SessionClose)dOpenHpiClientParam( SAHPI_IN SaHpiSessionIdT SessionId ) { CheckSession(); PreMarshal( eFsaHpiSessionClose ); request_header.m_len = HpiMarshalRequest1( hm, request, &SessionId ); Send(); int mr = HpiDemarshalReply0( reply_header.m_flags & dMhEndianBit, hm, reply, &err ); PostMarshal(); if ( err == SA_OK ) { config->m_num_sessions--; assert( config->m_num_sessions >= 0 ); if ( config->m_num_sessions < 0 ) config->m_num_sessions = 0; if ( config->m_num_sessions == 0 ) CleanupClient( config ); } return err; }
static void CheckNewClient(__pmFdSet * fdset, int rfd, int family) { ClientInfo *cp; if (__pmFD_ISSET(rfd, fdset)) { if ((cp = AcceptNewClient(rfd)) == NULL) /* failed to negotiate, already cleaned up */ return; /* establish a new connection to pmcd */ if ((cp->pmcd_fd = __pmAuxConnectPMCDPort(cp->pmcd_hostname, cp->pmcd_port)) < 0) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " oops!\n" "__pmAuxConnectPMCDPort(%s,%d) failed: %s\n", cp->pmcd_hostname, cp->pmcd_port, pmErrStr(-oserror())); #endif CleanupClient(cp, -oserror()); } else { if (cp->pmcd_fd > maxSockFd) maxSockFd = cp->pmcd_fd; __pmFD_SET(cp->pmcd_fd, &sockFds); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_CONTEXT) /* append to message started in AcceptNewClient() */ fprintf(stderr, " fd=%d\n", cp->pmcd_fd); #endif } } }
SessionOpen)dOpenHpiClientParam( SAHPI_IN SaHpiDomainIdT DomainId, SAHPI_OUT SaHpiSessionIdT *SessionId, SAHPI_IN void *SecurityParams ) { if ( config->m_initialize == 0 ) return SA_ERR_HPI_UNINITIALIZED; if ( SessionId == 0 || SecurityParams != 0 ) return SA_ERR_HPI_INVALID_PARAMS; if ( config->m_num_sessions == 0 ) { if ( !InitClient( config ) ) return SA_ERR_HPI_INITIALIZING; } config->m_num_sessions++; PreMarshal( eFsaHpiSessionOpen ); request_header.m_len = HpiMarshalRequest1( hm, request, &DomainId ); Send(); int mr = HpiDemarshalReply1( reply_header.m_flags & dMhEndianBit, hm, reply, &err, SessionId ); PostMarshal(); if ( err != SA_OK ) { config->m_num_sessions--; assert( config->m_num_sessions >= 0 ); if ( config->m_num_sessions < 0 ) config->m_num_sessions = 0; if ( config->m_num_sessions == 0 ) CleanupClient( config ); } return err; }
int DoFetch(ClientInfo *cip, __pmPDU* pb) { int i, j; int sts; int ctxnum; __pmTimeval when; int nPmids; pmID *pmidList; static pmResult *endResult = NULL; static int maxnpmids = 0; /* sizes endResult */ DomPmidList *dList; /* NOTE: NOT indexed by agent index */ static int nDoms = 0; static pmResult **results = NULL; static int *resIndex = NULL; __pmFdSet waitFds; __pmFdSet readyFds; int nWait; int maxFd; struct timeval timeout; if (nAgents > nDoms) { if (results != NULL) free(results); if (resIndex != NULL) free(resIndex); results = (pmResult **)malloc((nAgents + 1) * sizeof (pmResult *)); resIndex = (int *)malloc((nAgents + 1) * sizeof(int)); if (results == NULL || resIndex == NULL) { __pmNoMem("DoFetch.results", (nAgents + 1) * sizeof (pmResult *) + (nAgents + 1) * sizeof(int), PM_FATAL_ERR); } nDoms = nAgents; } memset(results, 0, (nAgents + 1) * sizeof(results[0])); sts = __pmDecodeFetch(pb, &ctxnum, &when, &nPmids, &pmidList); if (sts < 0) return sts; /* Check that a profile has been received from the specified context */ if (ctxnum < 0 || ctxnum >= cip->szProfile || cip->profile[ctxnum] == NULL) { __pmUnpinPDUBuf(pb); if (ctxnum < 0 || ctxnum >= cip->szProfile) __pmNotifyErr(LOG_ERR, "DoFetch: bad ctxnum=%d\n", ctxnum); else __pmNotifyErr(LOG_ERR, "DoFetch: no profile for ctxnum=%d\n", ctxnum); return PM_ERR_NOPROFILE; } if (nPmids > maxnpmids) { int need; if (endResult != NULL) free(endResult); need = (int)sizeof(pmResult) + (nPmids - 1) * (int)sizeof(pmValueSet *); if ((endResult = (pmResult *)malloc(need)) == NULL) { __pmNoMem("DoFetch.endResult", need, PM_FATAL_ERR); } maxnpmids = nPmids; } dList = SplitPmidList(nPmids, pmidList); /* For each domain in the split pmidList, dispatch the per-domain subset * of pmIDs to the appropriate agent. For DSO agents, the pmResult will * come back immediately. If a request cannot be sent to an agent, a * suitable pmResult (containing metric not available values) will be * returned. */ __pmFD_ZERO(&waitFds); nWait = 0; maxFd = -1; for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; results[j] = SendFetch(&dList[i], &agent[j], cip, ctxnum); if (results[j] == NULL) { /* Wait for agent's response */ int fd = agent[j].outFd; agent[j].status.busy = 1; __pmFD_SET(fd, &waitFds); if (fd > maxFd) maxFd = fd; nWait++; } } /* Construct pmResult for bad-pmID list */ if (dList[i].listSize != 0) results[nAgents] = MakeBadResult(dList[i].listSize, dList[i].list, PM_ERR_NOAGENT); /* Wait for results to roll in from agents */ while (nWait > 0) { __pmFD_COPY(&readyFds, &waitFds); if (nWait > 1) { timeout.tv_sec = _pmcd_timeout; timeout.tv_usec = 0; retry: setoserror(0); sts = __pmSelectRead(maxFd+1, &readyFds, &timeout); if (sts == 0) { __pmNotifyErr(LOG_INFO, "DoFetch: select timeout"); /* Timeout, terminate agents with undelivered results */ for (i = 0; i < nAgents; i++) { if (agent[i].status.busy) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, PM_ERR_NOAGENT); pmcd_trace(TR_RECV_TIMEOUT, agent[i].outFd, PDU_RESULT, 0); CleanupAgent(&agent[i], AT_COMM, agent[i].inFd); } } break; } else if (sts < 0) { if (neterror() == EINTR) goto retry; /* this is not expected to happen! */ __pmNotifyErr(LOG_ERR, "DoFetch: fatal select failure: %s\n", netstrerror()); Shutdown(); exit(1); } } /* Read results from agents that have them ready */ for (i = 0; i < nAgents; i++) { AgentInfo *ap = &agent[i]; int pinpdu; if (!ap->status.busy || !__pmFD_ISSET(ap->outFd, &readyFds)) continue; ap->status.busy = 0; __pmFD_CLR(ap->outFd, &waitFds); nWait--; pinpdu = sts = __pmGetPDU(ap->outFd, ANY_SIZE, _pmcd_timeout, &pb); if (sts > 0) pmcd_trace(TR_RECV_PDU, ap->outFd, sts, (int)((__psint_t)pb & 0xffffffff)); if (sts == PDU_RESULT) { if ((sts = __pmDecodeResult(pb, &results[i])) >= 0) if (results[i]->numpmid != aFreq[i]) { pmFreeResult(results[i]); sts = PM_ERR_IPC; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) __pmNotifyErr(LOG_ERR, "DoFetch: \"%s\" agent given %d pmIDs, returned %d\n", ap->pmDomainLabel, aFreq[i], results[i]->numpmid); #endif } } else { if (sts == PDU_ERROR) { int s; if ((s = __pmDecodeError(pb, &sts)) < 0) sts = s; else if (sts >= 0) sts = PM_ERR_GENERIC; pmcd_trace(TR_RECV_ERR, ap->outFd, PDU_RESULT, sts); } else if (sts >= 0) { pmcd_trace(TR_WRONG_PDU, ap->outFd, PDU_RESULT, sts); sts = PM_ERR_IPC; } } if (pinpdu > 0) __pmUnpinPDUBuf(pb); if (sts < 0) { /* Find entry in dList for this agent */ for (j = 0; dList[j].domain != -1; j++) if (dList[j].domain == agent[i].pmDomainId) break; results[i] = MakeBadResult(dList[j].listSize, dList[j].list, sts); if (sts == PM_ERR_PMDANOTREADY) { /* the agent is indicating it can't handle PDUs for now */ int k; extern int CheckError(AgentInfo *ap, int sts); for (k = 0; k < dList[j].listSize; k++) results[i]->vset[k]->numval = PM_ERR_AGAIN; sts = CheckError(&agent[i], sts); } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { fprintf(stderr, "RESULT error from \"%s\" agent : %s\n", ap->pmDomainLabel, pmErrStr(sts)); } #endif if (sts == PM_ERR_IPC || sts == PM_ERR_TIMEOUT) CleanupAgent(ap, AT_COMM, ap->outFd); } } } endResult->numpmid = nPmids; __pmtimevalNow(&endResult->timestamp); /* The order of the pmIDs in the per-domain results is the same as in the * original request, but on a per-domain basis. resIndex is an array of * indices (one per agent) of the next metric to be retrieved from each * per-domain result's vset. */ memset(resIndex, 0, (nAgents + 1) * sizeof(resIndex[0])); for (i = 0; i < nPmids; i++) { j = mapdom[((__pmID_int *)&pmidList[i])->domain]; endResult->vset[i] = results[j]->vset[resIndex[j]++]; } pmcd_trace(TR_XMIT_PDU, cip->fd, PDU_RESULT, endResult->numpmid); sts = 0; if (cip->status.changes) { /* notify client of PMCD state change */ sts = __pmSendError(cip->fd, FROM_ANON, (int)cip->status.changes); if (sts > 0) sts = 0; cip->status.changes = 0; } if (sts == 0) sts = __pmSendResult(cip->fd, FROM_ANON, endResult); if (sts < 0) { pmcd_trace(TR_XMIT_ERR, cip->fd, PDU_RESULT, sts); CleanupClient(cip, sts); } /* * pmFreeResult() all the accumulated results. */ for (i = 0; dList[i].domain != -1; i++) { j = mapdom[dList[i].domain]; if (agent[j].ipcType == AGENT_DSO && agent[j].status.connected && !agent[j].status.madeDsoResult) /* Living DSO's manage their own pmResult skeleton unless * MakeBadResult was called to create the result. The value sets * within the skeleton need to be freed though! */ __pmFreeResultValues(results[j]); else /* For others it is dynamically allocated in __pmDecodeResult or * MakeBadResult */ pmFreeResult(results[j]); } if (results[nAgents] != NULL) pmFreeResult(results[nAgents]); __pmUnpinPDUBuf(pmidList); return 0; }
/* Determine which clients (if any) have sent data to the server and handle it * as required. */ void HandleInput(__pmFdSet *fdsPtr) { int i, sts; __pmPDU *pb; ClientInfo *cp; /* input from clients */ for (i = 0; i < nClients; i++) { if (!client[i].status.connected || !__pmFD_ISSET(client[i].fd, fdsPtr)) continue; cp = &client[i]; sts = __pmGetPDU(cp->fd, LIMIT_SIZE, 0, &pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } /* We *must* see a credentials PDU as the first PDU */ if (!cp->status.allowed) { sts = VerifyClient(cp, pb); __pmUnpinPDUBuf(pb); if (sts < 0) { CleanupClient(cp, sts); continue; } cp->status.allowed = 1; continue; } sts = __pmXmitPDU(cp->pmcd_fd, pb); __pmUnpinPDUBuf(pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } } /* input from pmcds */ for (i = 0; i < nClients; i++) { if (!client[i].status.connected || !__pmFD_ISSET(client[i].pmcd_fd, fdsPtr)) continue; cp = &client[i]; sts = __pmGetPDU(cp->pmcd_fd, ANY_SIZE, 0, &pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } sts = __pmXmitPDU(cp->fd, pb); __pmUnpinPDUBuf(pb); if (sts <= 0) { CleanupClient(cp, sts); continue; } } }
static void CheckNewClient(__pmFdSet * fdset, int rfd, int family) { int s, sts, accepted = 1; __uint32_t challenge; ClientInfo *cp; if (__pmFD_ISSET(rfd, fdset)) { if ((cp = AcceptNewClient(rfd)) == NULL) return; /* Accept failed and no client added */ sts = __pmAccAddClient(cp->addr, &cp->denyOps); #if defined(HAVE_STRUCT_SOCKADDR_UN) if (sts >= 0 && family == AF_UNIX) { if ((sts = __pmServerSetLocalCreds(cp->fd, &cp->attrs)) < 0) { __pmNotifyErr(LOG_ERR, "ClientLoop: error extracting local credentials: %s", pmErrStr(sts)); } } #endif if (sts >= 0) { memset(&cp->pduInfo, 0, sizeof(cp->pduInfo)); cp->pduInfo.version = PDU_VERSION; cp->pduInfo.licensed = 1; if (__pmServerHasFeature(PM_SERVER_FEATURE_SECURE)) cp->pduInfo.features |= (PDU_FLAG_SECURE | PDU_FLAG_SECURE_ACK); if (__pmServerHasFeature(PM_SERVER_FEATURE_COMPRESS)) cp->pduInfo.features |= PDU_FLAG_COMPRESS; if (__pmServerHasFeature(PM_SERVER_FEATURE_AUTH)) /*optional*/ cp->pduInfo.features |= PDU_FLAG_AUTH; if (__pmServerHasFeature(PM_SERVER_FEATURE_CREDS_REQD)) /*required*/ cp->pduInfo.features |= PDU_FLAG_CREDS_REQD; if (__pmServerHasFeature(PM_SERVER_FEATURE_CONTAINERS)) cp->pduInfo.features |= PDU_FLAG_CONTAINER; challenge = *(__uint32_t *)(&cp->pduInfo); sts = 0; } else { challenge = 0; accepted = 0; } pmcd_trace(TR_XMIT_PDU, cp->fd, PDU_ERROR, sts); /* reset (no meaning, use fd table to version) */ cp->pduInfo.version = UNKNOWN_VERSION; s = __pmSendXtendError(cp->fd, FROM_ANON, sts, htonl(challenge)); if (s < 0) { __pmNotifyErr(LOG_ERR, "ClientLoop: error sending Conn ACK PDU to new client %s\n", pmErrStr(s)); if (sts >= 0) /* * prefer earlier failure status if any, else * use the one from __pmSendXtendError() */ sts = s; accepted = 0; } if (!accepted) CleanupClient(cp, sts); } }
/* * Determine which clients (if any) have sent data to the server and handle it * as required. */ void HandleClientInput(__pmFdSet *fdsPtr) { int sts; int i; __pmPDU *pb; __pmPDUHdr *php; ClientInfo *cp; for (i = 0; i < nClients; i++) { int pinpdu; if (!client[i].status.connected || !__pmFD_ISSET(client[i].fd, fdsPtr)) continue; cp = &client[i]; this_client_id = i; pinpdu = sts = __pmGetPDU(cp->fd, LIMIT_SIZE, _pmcd_timeout, &pb); if (sts > 0) { pmcd_trace(TR_RECV_PDU, cp->fd, sts, (int)((__psint_t)pb & 0xffffffff)); } else { CleanupClient(cp, sts); continue; } php = (__pmPDUHdr *)pb; if (__pmVersionIPC(cp->fd) == UNKNOWN_VERSION && php->type != PDU_CREDS) { /* old V1 client protocol, no longer supported */ sts = PM_ERR_IPC; CleanupClient(cp, sts); __pmUnpinPDUBuf(pb); continue; } if (pmDebug & DBG_TRACE_APPL0) ShowClients(stderr); switch (php->type) { case PDU_PROFILE: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoProfile(cp, pb); break; case PDU_FETCH: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoFetch(cp, pb); break; case PDU_INSTANCE_REQ: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoInstance(cp, pb); break; case PDU_DESC_REQ: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoDesc(cp, pb); break; case PDU_TEXT_REQ: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoText(cp, pb); break; case PDU_RESULT: sts = (cp->denyOps & PMCD_OP_STORE) ? PM_ERR_PERMISSION : DoStore(cp, pb); break; case PDU_PMNS_IDS: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoPMNSIDs(cp, pb); break; case PDU_PMNS_NAMES: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoPMNSNames(cp, pb); break; case PDU_PMNS_CHILD: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoPMNSChild(cp, pb); break; case PDU_PMNS_TRAVERSE: sts = (cp->denyOps & PMCD_OP_FETCH) ? PM_ERR_PERMISSION : DoPMNSTraverse(cp, pb); break; case PDU_CREDS: sts = DoCreds(cp, pb); break; default: sts = PM_ERR_IPC; } if (sts < 0) { if (pmDebug & DBG_TRACE_APPL0) fprintf(stderr, "PDU: %s client[%d]: %s\n", __pmPDUTypeStr(php->type), i, pmErrStr(sts)); /* Make sure client still alive before sending. */ if (cp->status.connected) { pmcd_trace(TR_XMIT_PDU, cp->fd, PDU_ERROR, sts); sts = __pmSendError(cp->fd, FROM_ANON, sts); if (sts < 0) __pmNotifyErr(LOG_ERR, "HandleClientInput: " "error sending Error PDU to client[%d] %s\n", i, pmErrStr(sts)); } } if (pinpdu > 0) __pmUnpinPDUBuf(pb); } }