1 /*
2 * Copyright (c) 1995-2002,2004,2006,2008 Silicon Graphics, Inc. All Rights Reserved.
3 * Copyright (c) 2007-2008 Aconex. All Rights Reserved.
4 *
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; either version 2.1 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 * License for more details.
14 */
15
16 #include "pmapi.h"
17 #include "impl.h"
18
19 #define PM_CONTEXT_UNDEF -1 /* current context is undefined */
20
21 static __pmContext *contexts; /* array of contexts */
22 static int contexts_len; /* number of contexts */
23 static int curcontext = PM_CONTEXT_UNDEF; /* current context */
24
25 static int n_backoff;
26 static int def_backoff[] = {5, 10, 20, 40, 80};
27 static int *backoff;
28
29 static void
30 waitawhile(__pmPMCDCtl *ctl)
31 {
32 /*
33 * after failure, compute delay before trying again ...
34 */
35 if (n_backoff == 0) {
36 char *q;
37 /* first time ... try for PMCD_RECONNECT_TIMEOUT from env */
38 if ((q = getenv("PMCD_RECONNECT_TIMEOUT")) != NULL) {
39 char *pend;
40 char *p;
41 int val;
42
43 for (p = q; *p != '\0'; ) {
44 val = (int)strtol(p, &pend, 10);
45 if (val <= 0 || (*pend != ',' && *pend != '\0')) {
46 __pmNotifyErr(LOG_WARNING,
47 "pmReconnectContext: ignored bad PMCD_RECONNECT_TIMEOUT = '%s'\n",
48 q);
49 n_backoff = 0;
50 if (backoff != NULL)
51 free(backoff);
52 break;
53 }
54 if ((backoff = (int *)realloc(backoff, (n_backoff+1) * sizeof(backoff[0]))) == NULL) {
55 __pmNoMem("pmReconnectContext", (n_backoff+1) * sizeof(backoff[0]), PM_FATAL_ERR);
56 }
57 backoff[n_backoff++] = val;
58 if (*pend == '\0')
59 break;
60 p = &pend[1];
61 }
62 }
63 if (n_backoff == 0) {
64 /* use default */
65 n_backoff = 5;
66 backoff = def_backoff;
67 }
68 }
69 if (ctl->pc_timeout == 0)
70 ctl->pc_timeout = 1;
71 else if (ctl->pc_timeout < n_backoff)
72 ctl->pc_timeout++;
73 ctl->pc_again = time(NULL) + backoff[ctl->pc_timeout-1];
74 }
75
76 __pmContext *
77 __pmHandleToPtr(int handle)
78 {
79 if (handle < 0 || handle >= contexts_len ||
80 contexts[handle].c_type == PM_CONTEXT_FREE)
81 return NULL;
82 else
83 return &contexts[handle];
84 }
85
86 int
87 __pmPtrToHandle(__pmContext *ctxp)
88 {
89 return ctxp - contexts;
90 }
91
92 const char *
93 pmGetContextHostName (int ctxid)
94 {
95 __pmContext * ctx;
96
97 if ( (ctx = __pmHandleToPtr(ctxid)) != NULL) {
98 switch (ctx->c_type) {
99 case PM_CONTEXT_HOST:
100 return (ctx->c_pmcd->pc_hosts[0].name);
101
102 case PM_CONTEXT_ARCHIVE:
103 return (ctx->c_archctl->ac_log->l_label.ill_hostname);
104 }
105 }
106
107 return ("");
108 }
109
110 int
111 pmWhichContext(void)
112 {
113 /*
114 * return curcontext, provided it is defined
115 */
116 int sts;
117
118 if (curcontext > PM_CONTEXT_UNDEF)
119 sts = curcontext;
120 else
121 sts = PM_ERR_NOCONTEXT;
122
123 #ifdef PCP_DEBUG
124 if (pmDebug & DBG_TRACE_CONTEXT)
125 fprintf(stderr, "pmWhichContext() -> %d, cur=%d\n",
126 sts, curcontext);
127 #endif
128 return sts;
129 }
130
131 static int
132 __pmConvertTimeout (int timeo)
133 {
134 int tout_msec;
135 const struct timeval *tv;
136
137 switch (timeo) {
138 case TIMEOUT_NEVER:
139 tout_msec = -1;
140 break;
141 case TIMEOUT_DEFAULT:
142 tv = __pmDefaultRequestTimeout();
143
144 tout_msec = tv->tv_sec *1000 + tv->tv_usec / 1000;
145 break;
146
147 default:
148 tout_msec = timeo * 1000;
149 break;
150 }
151
152 return tout_msec;
153 }
154
155 int
156 pmNewContext(int type, const char *name)
157 {
158 __pmContext *new = NULL;
159 __pmContext *list;
160 int i;
161 int sts;
162 int old_curcontext = curcontext;
163 int old_contexts_len = contexts_len;
164
165 /* See if we can reuse a free context */
166 for (i = 0; i < contexts_len; i++) {
167 if (contexts[i].c_type == PM_CONTEXT_FREE) {
168 curcontext = i;
169 new = &contexts[curcontext];
170 goto INIT_CONTEXT;
171 }
172 }
173
174 /* Create a new one */
175 if (contexts == NULL)
176 list = (__pmContext *)malloc(sizeof(__pmContext));
177 else
178 list = (__pmContext *)realloc((void *)contexts, (1+contexts_len) * sizeof(__pmContext));
179
180 if (list == NULL) {
181 /* fail : nothing changed */
182 sts = -oserror();
183 goto FAILED;
184 }
185
186 contexts = list;
187 curcontext = contexts_len++;
188 new = &contexts[curcontext];
189
190 INIT_CONTEXT:
191 /*
192 * Set up the default state
193 */
194 memset(new, 0, sizeof(__pmContext));
195 new->c_type = (type & PM_CONTEXT_TYPEMASK);
196 if ((new->c_instprof = (__pmProfile *)malloc(sizeof(__pmProfile))) == NULL) {
197 /*
198 * fail : nothing changed -- actually list is changed, but restoring
199 * contexts_len should make it ok next time through
200 */
201 sts = -oserror();
202 goto FAILED;
203 }
204 memset(new->c_instprof, 0, sizeof(__pmProfile));
205 new->c_instprof->state = PM_PROFILE_INCLUDE; /* default global state */
206 new->c_sent = 0; /* profile not sent */
207 new->c_origin.tv_sec = new->c_origin.tv_usec = 0; /* default time */
208
209 if (new->c_type == PM_CONTEXT_HOST) {
210 pmHostSpec *hosts;
211 int nhosts;
212 char *errmsg;
213
214 /* deconstruct a host[:port@proxy:port] specification */
215 sts = __pmParseHostSpec(name, &hosts, &nhosts, &errmsg);
|
At conditional (1): "sts < 0": Taking true branch.
|
216 if (sts < 0) {
|
Event noescape: |
Variable "errmsg" is not freed or pointed-to in function "pmprintf". |
| Also see events: |
[alloc_arg][leaked_storage] |
217 pmprintf("pmNewContext: bad host specification\n%s", errmsg);
218 pmflush();
|
Event leaked_storage: |
Variable "errmsg" going out of scope leaks the storage it points to. |
| Also see events: |
[alloc_arg][noescape] |
219 goto FAILED;
220 }
221
222 if ((type & PM_CTXFLAG_EXCLUSIVE) == 0 && nhosts == 1) {
223 for (i = 0; i < contexts_len; i++) {
224 if (i == curcontext)
225 continue;
226 if (contexts[i].c_type == PM_CONTEXT_HOST &&
227 (contexts[i].c_pmcd->pc_curpdu == 0) &&
228 strcmp(contexts[i].c_pmcd->pc_hosts[0].name,
229 hosts[0].name) == 0) {
230 new->c_pmcd = contexts[i].c_pmcd;
231 /*new->c_pduinfo = contexts[i].c_pduinfo;*/
232 }
233 }
234 }
235 if (new->c_pmcd == NULL) {
236 pmcd_ctl_state_t inistate;
237 /*
238 * Try to establish the connection.
239 * If this fails, restore the original current context
240 * and return an error.
241 */
242 if (type & PM_CTXFLAG_SHALLOW) {
243 sts = __pmCreateSocket();
244 inistate = PC_FETAL;
245 } else {
246 sts = __pmConnectPMCD(hosts, nhosts);
247 inistate = PC_READY;
248 }
249
250 if (sts < 0) {
251 __pmFreeHostSpec(hosts, nhosts);
252 goto FAILED;
253 }
254
255 new->c_pmcd = (__pmPMCDCtl *)calloc(1,sizeof(__pmPMCDCtl));
256 if (new->c_pmcd == NULL) {
257 sts = -oserror();
258 __pmCloseSocket(sts);
259 __pmFreeHostSpec(hosts, nhosts);
260 goto FAILED;
261 }
262 new->c_pmcd->pc_fd = sts;
263 new->c_pmcd->pc_state = inistate;
264 new->c_pmcd->pc_hosts = hosts;
265 new->c_pmcd->pc_nhosts = nhosts;
266 new->c_pmcd->pc_tout_sec = __pmConvertTimeout(TIMEOUT_DEFAULT) / 1000;
267 }
268 else {
269 /* duplicate of an existing context, don't need the __pmHostSpec */
270 __pmFreeHostSpec(hosts, nhosts);
271 }
272 new->c_pmcd->pc_refcnt++;
273 }
274 else if (new->c_type == PM_CONTEXT_LOCAL) {
275 if (!(type & PM_CTXFLAG_SHALLOW) && (sts = __pmConnectLocal()) != 0)
276 goto FAILED;
277 }
278 else if (new->c_type == PM_CONTEXT_ARCHIVE) {
279 if ((new->c_archctl = (__pmArchCtl *)malloc(sizeof(__pmArchCtl))) == NULL) {
280 sts = -oserror();
281 goto FAILED;
282 }
283 new->c_archctl->ac_log = NULL;
284 for (i = 0; i < contexts_len; i++) {
285 if (i == curcontext)
286 continue;
287 if (contexts[i].c_type == PM_CONTEXT_ARCHIVE &&
288 strcmp(name, contexts[i].c_archctl->ac_log->l_name) == 0) {
289 new->c_archctl->ac_log = contexts[i].c_archctl->ac_log;
290 }
291 }
292 if (new->c_archctl->ac_log == NULL) {
293 if ((new->c_archctl->ac_log = (__pmLogCtl *)malloc(sizeof(__pmLogCtl))) == NULL) {
294 free(new->c_archctl);
295 sts = -oserror();
296 goto FAILED;
297 }
298 if ((sts = __pmLogOpen(name, new)) < 0) {
299 free(new->c_archctl->ac_log);
300 free(new->c_archctl);
301 goto FAILED;
302 }
303 }
304 else {
305 /* archive already open, set default starting state as per __pmLogOpen */
306 new->c_origin.tv_sec = (__int32_t)new->c_archctl->ac_log->l_label.ill_start.tv_sec;
307 new->c_origin.tv_usec = (__int32_t)new->c_archctl->ac_log->l_label.ill_start.tv_usec;
308 new->c_mode = (new->c_mode & 0xffff0000) | PM_MODE_FORW;
309 }
310
311 /* start after header + label record + trailer */
312 new->c_archctl->ac_offset = sizeof(__pmLogLabel) + 2*sizeof(int);
313 new->c_archctl->ac_vol = new->c_archctl->ac_log->l_curvol;
314 new->c_archctl->ac_serial = 0; /* not serial access, yet */
315 new->c_archctl->ac_pmid_hc.nodes = 0; /* empty hash list */
316 new->c_archctl->ac_pmid_hc.hsize = 0;
317
318 new->c_archctl->ac_log->l_refcnt++;
319 }
320 else {
321 /* bad type */
322 #ifdef PCP_DEBUG
323 if (pmDebug & DBG_TRACE_CONTEXT) {
324 fprintf(stderr, "pmNewContext(%d, %s): illegal type\n",
325 type, name);
326 }
327 #endif
328 return PM_ERR_NOCONTEXT;
329 }
330
331 /* bind defined metrics if any ... */
332 __dmopencontext(new);
333
334 /* return the handle to the new (current) context */
335 #ifdef PCP_DEBUG
336 if (pmDebug & DBG_TRACE_CONTEXT) {
337 fprintf(stderr, "pmNewContext(%d, %s) -> %d\n", type, name, curcontext);
338 __pmDumpContext(stderr, curcontext, PM_INDOM_NULL);
339 }
340 #endif
341 return curcontext;
342
343 FAILED:
344 if (new != NULL) {
345 new->c_type = PM_CONTEXT_FREE;
346 if (new->c_instprof != NULL)
347 free(new->c_instprof);
348 }
349 curcontext = old_curcontext;
350 contexts_len = old_contexts_len;
351 #ifdef PCP_DEBUG
352 if (pmDebug & DBG_TRACE_CONTEXT)
353 fprintf(stderr, "pmNewContext(%d, %s) -> %d, curcontext=%d\n",
354 type, name, sts, curcontext);
355 #endif
356 return sts;
357 }
358
359
360 int
361 pmReconnectContext(int handle)
362 {
363 __pmContext *ctxp;
364 __pmPMCDCtl *ctl;
365 int sts;
366
367 if (handle < 0 || handle >= contexts_len ||
368 contexts[handle].c_type == PM_CONTEXT_FREE) {
369 #ifdef PCP_DEBUG
370 if (pmDebug & DBG_TRACE_CONTEXT)
371 fprintf(stderr, "pmReconnectContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT);
372 #endif
373 return PM_ERR_NOCONTEXT;
374 }
375
376 ctxp = &contexts[handle];
377 ctl = ctxp->c_pmcd;
378 if (ctxp->c_type == PM_CONTEXT_HOST) {
379 if (ctl->pc_timeout && time(NULL) < ctl->pc_again) {
380 /* too soon to try again */
381 #ifdef PCP_DEBUG
382 if (pmDebug & DBG_TRACE_CONTEXT)
383 fprintf(stderr, "pmReconnectContext(%d) -> %d, too soon (need wait another %d secs)\n",
384 handle, (int)-ETIMEDOUT, (int)(ctl->pc_again - time(NULL)));
385 #endif
386 return -ETIMEDOUT;
387 }
388
389 if (ctl->pc_fd >= 0) {
390 /* don't care if this fails */
391 __pmCloseSocket(ctl->pc_fd);
392 ctl->pc_fd = -1;
393 }
394
395 if ((sts = __pmConnectPMCD(ctl->pc_hosts, ctl->pc_nhosts)) >= 0) {
396 ctl->pc_fd = sts;
397 ctxp->c_sent = 0;
398 }
399
400 if (sts < 0) {
401 waitawhile(ctl);
402 #ifdef PCP_DEBUG
403 if (pmDebug & DBG_TRACE_CONTEXT)
404 fprintf(stderr, "pmReconnectContext(%d), failed (wait %d secs before next attempt)\n",
405 handle, (int)(ctl->pc_again - time(NULL)));
406 #endif
407 return -ETIMEDOUT;
408 }
409 else {
410 int i;
411 /*
412 * mark profile as not sent for all contexts sharing this
413 * socket
414 */
415 for (i = 0; i < contexts_len; i++) {
416 if (contexts[i].c_type != PM_CONTEXT_FREE && contexts[i].c_pmcd == ctl) {
417 contexts[i].c_sent = 0;
418 }
419 }
420 #ifdef PCP_DEBUG
421 if (pmDebug & DBG_TRACE_CONTEXT)
422 fprintf(stderr, "pmReconnectContext(%d), done\n", handle);
423 #endif
424 ctl->pc_timeout = 0;
425 }
426 }
427 else {
428 /*
429 * assume PM_CONTEXT_ARCHIVE or PM_CONTEXT_LOCAL reconnect,
430 * this is a NOP in either case.
431 */
432 ;
433 }
434
435 /*
436 * clear any derived metrics and re-bind
437 */
438 __dmclosecontext(ctxp);
439 __dmopencontext(ctxp);
440
441 #ifdef PCP_DEBUG
442 if (pmDebug & DBG_TRACE_CONTEXT)
443 fprintf(stderr, "pmReconnectContext(%d) -> %d\n", handle, handle);
444 #endif
445 return handle;
446 }
447
448 int
449 pmDupContext(void)
450 {
451 int sts;
452 int old, new = -1;
453 char hostspec[4096], *h;
454 __pmContext *newcon, *oldcon;
455 __pmInDomProfile *q, *p, *p_end;
456 __pmProfile *save;
457 void *save_dm;
458
459 if ((old = pmWhichContext()) < 0) {
460 sts = old;
461 goto done;
462 }
463 oldcon = &contexts[old];
464 if (oldcon->c_type == PM_CONTEXT_HOST) {
465 h = &hostspec[0];
466 __pmUnparseHostSpec(oldcon->c_pmcd->pc_hosts,
467 oldcon->c_pmcd->pc_nhosts, &h, sizeof(hostspec));
468 new = pmNewContext(oldcon->c_type, hostspec);
469 }
470 else if (oldcon->c_type == PM_CONTEXT_LOCAL)
471 new = pmNewContext(oldcon->c_type, NULL);
472 else
473 /* assume PM_CONTEXT_ARCHIVE */
474 new = pmNewContext(oldcon->c_type, oldcon->c_archctl->ac_log->l_name);
475 if (new < 0) {
476 /* failed to connect or out of memory */
477 sts = new;
478 goto done;
479 }
480 oldcon = &contexts[old]; /* contexts[] may have been relocated */
481 newcon = &contexts[new];
482 save = newcon->c_instprof; /* need this later */
483 save_dm = newcon->c_dm; /* need this later */
484 if (newcon->c_archctl != NULL)
485 free(newcon->c_archctl); /* will allocate a new one below */
486 *newcon = *oldcon; /* struct copy */
487 newcon->c_instprof = save; /* restore saved instprof from pmNewContext */
488 newcon->c_dm = save_dm; /* restore saved derived metrics control also */
489
490 /* clone the per-domain profiles (if any) */
491 if (oldcon->c_instprof->profile_len > 0) {
492 newcon->c_instprof->profile = (__pmInDomProfile *)malloc(
493 oldcon->c_instprof->profile_len * sizeof(__pmInDomProfile));
494 if (newcon->c_instprof->profile == NULL) {
495 sts = -oserror();
496 goto done;
497 }
498 memcpy(newcon->c_instprof->profile, oldcon->c_instprof->profile,
499 oldcon->c_instprof->profile_len * sizeof(__pmInDomProfile));
500 p = oldcon->c_instprof->profile;
501 p_end = p + oldcon->c_instprof->profile_len;
502 q = newcon->c_instprof->profile;
503 for (; p < p_end; p++, q++) {
504 if (p->instances) {
505 q->instances = (int *)malloc(p->instances_len * sizeof(int));
506 if (q->instances == NULL) {
507 sts = -oserror();
508 goto done;
509 }
510 memcpy(q->instances, p->instances,
511 p->instances_len * sizeof(int));
512 }
513 }
514 }
515
516 /*
517 * The call to pmNewContext (above) should have connected to the pmcd.
518 * Make sure the new profile will be sent before the next fetch.
519 */
520 newcon->c_sent = 0;
521
522 /* clone the archive control struct, if any */
523 if (oldcon->c_archctl != NULL) {
524 if ((newcon->c_archctl = (__pmArchCtl *)malloc(sizeof(__pmArchCtl))) == NULL) {
525 sts = -oserror();
526 goto done;
527 }
528 *newcon->c_archctl = *oldcon->c_archctl; /* struct assignment */
529 }
530
531 sts = new;
532
533 done:
534 /* return an error code, or the handle for the new context */
535 if (sts < 0 && new >= 0)
536 contexts[new].c_type = PM_CONTEXT_FREE;
537 #ifdef PCP_DEBUG
538 if (pmDebug & DBG_TRACE_CONTEXT) {
539 fprintf(stderr, "pmDupContext() -> %d\n", sts);
540 if (sts >= 0)
541 __pmDumpContext(stderr, sts, PM_INDOM_NULL);
542 }
543 #endif
544 return sts;
545 }
546
547 int
548 pmUseContext(int handle)
549 {
550 if (handle < 0 || handle >= contexts_len ||
551 contexts[handle].c_type == PM_CONTEXT_FREE) {
552 #ifdef PCP_DEBUG
553 if (pmDebug & DBG_TRACE_CONTEXT)
554 fprintf(stderr, "pmUseContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT);
555 #endif
556 return PM_ERR_NOCONTEXT;
557 }
558
559 #ifdef PCP_DEBUG
560 if (pmDebug & DBG_TRACE_CONTEXT)
561 fprintf(stderr, "pmUseContext(%d) -> 0\n", handle);
562 #endif
563 curcontext = handle;
564 return 0;
565 }
566
567 int
568 pmDestroyContext(int handle)
569 {
570 __pmContext *ctxp;
571 struct linger dolinger = {0, 1};
572
573 if (handle < 0 || handle >= contexts_len ||
574 contexts[handle].c_type == PM_CONTEXT_FREE) {
575 #ifdef PCP_DEBUG
576 if (pmDebug & DBG_TRACE_CONTEXT)
577 fprintf(stderr, "pmDestroyContext(%d) -> %d\n", handle, PM_ERR_NOCONTEXT);
578 #endif
579 return PM_ERR_NOCONTEXT;
580 }
581
582 ctxp = &contexts[handle];
583 if (ctxp->c_pmcd != NULL) {
584 if (--ctxp->c_pmcd->pc_refcnt == 0) {
585 if (ctxp->c_pmcd->pc_fd >= 0) {
586 /* before close, unsent data should be flushed */
587 setsockopt(ctxp->c_pmcd->pc_fd, SOL_SOCKET,
588 SO_LINGER, (char *) &dolinger, (mysocklen_t)sizeof(dolinger));
589 __pmCloseSocket(ctxp->c_pmcd->pc_fd);
590 }
591 __pmFreeHostSpec(ctxp->c_pmcd->pc_hosts, ctxp->c_pmcd->pc_nhosts);
592 free(ctxp->c_pmcd);
593 }
594 }
595 if (ctxp->c_archctl != NULL) {
596 if (--ctxp->c_archctl->ac_log->l_refcnt == 0) {
597 __pmLogClose(ctxp->c_archctl->ac_log);
598 free(ctxp->c_archctl->ac_log);
599 }
600 free(ctxp->c_archctl);
601 }
602 ctxp->c_type = PM_CONTEXT_FREE;
603
604 if (handle == curcontext)
605 /* we have no choice */
606 curcontext = PM_CONTEXT_UNDEF;
607
608 __pmFreeProfile(ctxp->c_instprof);
609 __dmclosecontext(ctxp);
610 #ifdef PCP_DEBUG
611 if (pmDebug & DBG_TRACE_CONTEXT)
612 fprintf(stderr, "pmDestroyContext(%d) -> 0, curcontext=%d\n",
613 handle, curcontext);
614 #endif
615
616 return 0;
617 }
618
619 static char *_mode[] = { "LIVE", "INTERP", "FORW", "BACK" };
620
621 /*
622 * dump context(s); context == -1 for all contexts, indom == PM_INDOM_NULL
623 * for all instance domains.
624 */
625 void
626 __pmDumpContext(FILE *f, int context, pmInDom indom)
627 {
628 int i;
629 __pmContext *con;
630
631 fprintf(f, "Dump Contexts: current context = %d\n", curcontext);
632 if (curcontext < 0)
633 return;
634
635 if (indom != PM_INDOM_NULL) {
636 fprintf(f, "Dump restricted to indom=%d [%s]\n",
637 indom, pmInDomStr(indom));
638 }
639
640 for (con=contexts, i=0; i < contexts_len; i++, con++) {
641 if (context == -1 || context == i) {
642 fprintf(f, "Context[%d]", i);
643 if (con->c_type == PM_CONTEXT_HOST) {
644 fprintf(f, " host %s:", con->c_pmcd->pc_hosts[0].name);
645 fprintf(f, " pmcd=%s profile=%s fd=%d refcnt=%d",
646 (con->c_pmcd->pc_fd < 0) ? "NOT CONNECTED" : "CONNECTED",
647 con->c_sent ? "SENT" : "NOT_SENT",
648 con->c_pmcd->pc_fd,
649 con->c_pmcd->pc_refcnt);
650 }
651 else if (con->c_type == PM_CONTEXT_LOCAL) {
652 fprintf(f, " standalone:");
653 fprintf(f, " profile=%s\n",
654 con->c_sent ? "SENT" : "NOT_SENT");
655 }
656 else {
657 fprintf(f, " log %s:", con->c_archctl->ac_log->l_name);
658 fprintf(f, " mode=%s", _mode[con->c_mode & __PM_MODE_MASK]);
659 fprintf(f, " profile=%s tifd=%d mdfd=%d mfd=%d\nrefcnt=%d vol=%d",
660 con->c_sent ? "SENT" : "NOT_SENT",
661 con->c_archctl->ac_log->l_tifp == NULL ? -1 : fileno(con->c_archctl->ac_log->l_tifp),
662 fileno(con->c_archctl->ac_log->l_mdfp),
663 fileno(con->c_archctl->ac_log->l_mfp),
664 con->c_archctl->ac_log->l_refcnt,
665 con->c_archctl->ac_log->l_curvol);
666 fprintf(f, " offset=%ld (vol=%d) serial=%d",
667 (long)con->c_archctl->ac_offset,
668 con->c_archctl->ac_vol,
669 con->c_archctl->ac_serial);
670 }
671 if (con->c_type != PM_CONTEXT_LOCAL) {
672 fprintf(f, " origin=%d.%06d",
673 con->c_origin.tv_sec, con->c_origin.tv_usec);
674 fprintf(f, " delta=%d\n", con->c_delta);
675 }
676 __pmDumpProfile(f, indom, con->c_instprof);
677 }
678 }
679 }
680
681 int
682 __pmGetHostContextByID (int ctxid, __pmContext **cp)
683 {
684 __pmContext *ctxp = __pmHandleToPtr(ctxid);
685
686 if (ctxp == NULL) {
687 return (PM_ERR_NOCONTEXT);
688 } else if (ctxp->c_type != PM_CONTEXT_HOST) {
689 return (PM_ERR_NOTHOST);
690 } else if ((ctxp->c_pmcd->pc_fd < 0) ||
691 (ctxp->c_pmcd->pc_state != PC_READY)) {
692 return (PM_ERR_NOTCONN);
693 }
694
695 *cp = ctxp;
696
697 return (0);
698 }
699
700 #ifdef ASYNC_API
701 int
702 __pmGetBusyHostContextByID (int ctxid, __pmContext **cp, int pdu)
703 {
704 int n;
705
706 if ((n = __pmGetHostContextByID (ctxid, cp)) >= 0) {
707 if ((*cp)->c_pmcd->pc_curpdu != pdu) {
708 *cp = NULL;
709 n = PM_ERR_CTXBUSY;
710 }
711 }
712 return (n);
713 }
714
715 int
716 pmGetContextFD (int ctxid)
717 {
718 __pmContext *ctxp = __pmHandleToPtr(ctxid);
719
720 if (ctxp == NULL) {
721 return (PM_ERR_NOCONTEXT);
722 } else if (ctxp->c_type != PM_CONTEXT_HOST) {
723 return (PM_ERR_NOTHOST);
724 } else if (ctxp->c_pmcd->pc_fd < 0) {
725 return (PM_ERR_NOTCONN);
726 }
727 return (ctxp->c_pmcd->pc_fd);
728 }
729
730 int
731 pmGetContextTimeout (int ctxid, int *tout_msec)
732 {
733 __pmContext *ctxp = __pmHandleToPtr(ctxid);
734
735 if (ctxp == NULL) {
736 return (PM_ERR_NOCONTEXT);
737 } else if (ctxp->c_type != PM_CONTEXT_HOST) {
738 return (PM_ERR_NOTHOST);
739 } else if (tout_msec == NULL) {
740 return (-EINVAL);
741 }
742
743 *tout_msec = __pmConvertTimeout(ctxp->c_pmcd->pc_tout_sec);
744
745 return (0);
746 }
747
748 int
749 pmContextConnectTo (int ctxid, const struct sockaddr *addr)
750 {
751 int f;
752 pmHostSpec *pmcd;
753 __pmPMCDCtl *pc;
754 __pmContext *ctxp = __pmHandleToPtr(ctxid);
755
756 if (ctxp == NULL) {
757 return (PM_ERR_NOCONTEXT);
758 } else if (ctxp->c_type != PM_CONTEXT_HOST) {
759 return (PM_ERR_NOTHOST);
760 } else if (ctxp->c_pmcd->pc_fd < 0) {
761 return (PM_ERR_NOTCONN);
762 } else if (ctxp->c_pmcd->pc_state != PC_FETAL) {
763 return (PM_ERR_ISCONN);
764 }
765
766 pc = ctxp->c_pmcd;
767 pmcd = &pc->pc_hosts[0];
768 memcpy(&pc->pc_addr, addr, sizeof (pc->pc_addr));
769 if (pmcd->nports < 1)
770 __pmConnectGetPorts(pmcd);
771
772 if ((f =__pmConnectTo(pc->pc_fd, addr, pmcd->ports[0])) >= 0) {
773 const struct timeval *tv = __pmConnectTimeout();
774
775 pc->pc_fdflags = f;
776 pc->pc_state = PC_CONN_INPROGRESS;
777 pc->pc_tout_sec = tv->tv_sec;
778 return (0);
779 }
780
781 __pmCloseSocket(pc->pc_fd);
782 pc->pc_fd = -1;
783
784 return (f);
785 }
786
787 int
788 pmContextConnectChangeState (int ctxid)
789 {
790 int f;
791 __pmContext *ctxp = __pmHandleToPtr(ctxid);
792 __pmPMCDCtl *pc;
793
794 if (ctxp == NULL) {
795 return (PM_ERR_NOCONTEXT);
796 } else if (ctxp->c_type != PM_CONTEXT_HOST) {
797 return (PM_ERR_NOTHOST);
798 } else if (ctxp->c_pmcd->pc_fd < 0) {
799 return (PM_ERR_NOTCONN);
800 }
801
802 /* The assumption is that if pc_fd is less then 0 then state does
803 * not matter */
804 pc = ctxp->c_pmcd;
805 switch (pc->pc_state) {
806 case PC_CONN_INPROGRESS:
807 if (((f = __pmConnectCheckError (pc->pc_fd)) == 0) &&
808 ((f = __pmConnectRestoreFlags (pc->pc_fd,
809 pc->pc_fdflags)) == pc->pc_fd)) {
810 pc->pc_tout_sec = TIMEOUT_DEFAULT;
811 pc->pc_state = PC_WAIT_FOR_PMCD;
812 f = 0;
813 } else if (pc->pc_hosts[0].nports > 1) {
814 int fd;
815 __pmCloseSocket(pc->pc_fd);
816
817 if ((fd = __pmCreateSocket()) >= 0) {
818 if (fd != pc->pc_fd) {
819 if ((f = dup2(fd, pc->pc_fd)) == pc->pc_fd) {
820 __pmSetVersionIPC(pc->pc_fd, __pmVersionIPC(fd));
821 __pmSetSocketIPC(pc->pc_fd);
822 __pmCloseSocket(fd);
823 } else {
824 fd = -oserror();
825 }
826 }
827
828 if (fd > 0) {
829 __pmDropHostPort(pc->pc_hosts);
830 pc->pc_state = PC_FETAL;
831
832 if ((f = __pmConnectTo(pc->pc_fd, &pc->pc_addr,
833 pc->pc_hosts[0].ports[0])) >= 0) {
834 pc->pc_fdflags = f;
835 pc->pc_state = PC_CONN_INPROGRESS;
836 f = 0;
837 }
838 } else {
839 f = fd;
840 }
841 } else {
842 f = fd;
843 }
844 } else if (f > 0) {
845 f = __pmMapErrno(-f);
846 }
847 break;
848
849 case PC_WAIT_FOR_PMCD:
850 if ((f = __pmConnectHandshake(pc->pc_fd)) >= 0) {
851 pc->pc_state = PC_READY;
852 f = 0;
853 }
854 break;
855
856 case PC_READY:
857 f = PM_ERR_ISCONN;
858 break;
859
860 case PC_FETAL:
861 f = PM_ERR_NOTCONN;
862 break;
863
864 default:
865 f = -EINVAL;
866 break;
867 }
868
869 if (f) {
870 __pmCloseSocket(pc->pc_fd);
871 pc->pc_fd = -1;
872 } else if (pc->pc_state != PC_READY) {
873 f = PM_ERR_AGAIN;
874 }
875
876 return (f);
877 }
878
879
880 void
881 pmContextUndef(void)
882 {
883 curcontext = PM_CONTEXT_UNDEF;
884 }
885 #endif /*ASYNC_API*/