diff options
Diffstat (limited to 'src/libpcp/src/p_instance.c')
-rw-r--r-- | src/libpcp/src/p_instance.c | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/src/libpcp/src/p_instance.c b/src/libpcp/src/p_instance.c new file mode 100644 index 0000000..3b5474d --- /dev/null +++ b/src/libpcp/src/p_instance.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2012-2013 Red Hat. + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + */ + +#include <ctype.h> +#include "pmapi.h" +#include "impl.h" +#include "internal.h" + +/* + * PDU for pm*InDom request (PDU_INSTANCE_REQ) + */ +typedef struct { + __pmPDUHdr hdr; + pmInDom indom; + __pmTimeval when; /* desired time */ + int inst; /* may be PM_IN_NULL */ + int namelen; /* chars in name[], may be 0 */ + char name[sizeof(int)]; /* may be missing */ +} instance_req_t; + +int +__pmSendInstanceReq(int fd, int from, const __pmTimeval *when, pmInDom indom, + int inst, const char *name) +{ + instance_req_t *pp; + int need; + int sts; + + need = sizeof(instance_req_t) - sizeof(int); + if (name != NULL) + need += PM_PDU_SIZE_BYTES(strlen(name)); + if ((pp = (instance_req_t *)__pmFindPDUBuf(sizeof(need))) == NULL) + return -oserror(); + pp->hdr.len = need; + pp->hdr.type = PDU_INSTANCE_REQ; + pp->hdr.from = from; + pp->when.tv_sec = htonl((__int32_t)when->tv_sec); + pp->when.tv_usec = htonl((__int32_t)when->tv_usec); + pp->indom = __htonpmInDom(indom); + pp->inst = htonl(inst); + if (name == NULL) + pp->namelen = 0; + else { + pp->namelen = (int)strlen(name); + memcpy((void *)pp->name, (void *)name, pp->namelen); +#ifdef PCP_DEBUG + if ((pp->namelen % sizeof(__pmPDU)) != 0) { + /* for Purify */ + int pad; + char *padp = pp->name + pp->namelen; + + for (pad = sizeof(__pmPDU) - 1; pad >= (pp->namelen % sizeof(__pmPDU)); pad--) + *padp++ = '~'; /* buffer end */ + } +#endif + pp->namelen = htonl(pp->namelen); + } + + sts = __pmXmitPDU(fd, (__pmPDU *)pp); + __pmUnpinPDUBuf(pp); + return sts; +} + +int +__pmDecodeInstanceReq(__pmPDU *pdubuf, __pmTimeval *when, pmInDom *indom, int *inst, char **name) +{ + instance_req_t *pp; + char *pdu_end; + int namelen; + + pp = (instance_req_t *)pdubuf; + pdu_end = (char *)pdubuf + pp->hdr.len; + + if (pdu_end - (char *)pp < sizeof(instance_req_t) - sizeof(pp->name)) + return PM_ERR_IPC; + + when->tv_sec = ntohl(pp->when.tv_sec); + when->tv_usec = ntohl(pp->when.tv_usec); + *indom = __ntohpmInDom(pp->indom); + *inst = ntohl(pp->inst); + namelen = ntohl(pp->namelen); + if (namelen > 0) { + if (namelen >= INT_MAX - 1 || namelen > pp->hdr.len) + return PM_ERR_IPC; + if (pdu_end - (char *)pp < sizeof(instance_req_t) - sizeof(pp->name) + namelen) + return PM_ERR_IPC; + if ((*name = (char *)malloc(namelen+1)) == NULL) + return -oserror(); + strncpy(*name, pp->name, namelen); + (*name)[namelen] = '\0'; + } + else if (namelen < 0) { + return PM_ERR_IPC; + } else { + *name = NULL; + } + return 0; +} + +/* + * PDU for pm*InDom result (PDU_INSTANCE) + */ +typedef struct { + int inst; /* internal instance id */ + int namelen; /* chars in name[], may be 0 */ + char name[sizeof(int)]; /* may be missing */ +} instlist_t; + +typedef struct { + __pmPDUHdr hdr; + pmInDom indom; + int numinst; /* no. of elts to follow */ + __pmPDU rest[1]; /* array of instlist_t */ +} instance_t; + +int +__pmSendInstance(int fd, int from, __pmInResult *result) +{ + instance_t *rp; + instlist_t *ip; + int need; + int i; + int j; + int sts; + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_INDOM) + __pmDumpInResult(stderr, result); +#endif + + need = sizeof(*rp) - sizeof(rp->rest); + /* instlist_t + name rounded up to a __pmPDU boundary */ + for (i = 0; i < result->numinst; i++) { + need += sizeof(*ip) - sizeof(ip->name); + if (result->namelist != NULL) + need += PM_PDU_SIZE_BYTES(strlen(result->namelist[i])); + } + + if ((rp = (instance_t *)__pmFindPDUBuf(need)) == NULL) + return -oserror(); + rp->hdr.len = need; + rp->hdr.type = PDU_INSTANCE; + rp->hdr.from = from; + rp->indom = __htonpmInDom(result->indom); + rp->numinst = htonl(result->numinst); + + for (i = j = 0; i < result->numinst; i++) { + ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)]; + if (result->instlist != NULL) + ip->inst = htonl(result->instlist[i]); + else + /* weird, but this is going to be ignored at the other end */ + ip->inst = htonl(PM_IN_NULL); + if (result->namelist != NULL) { + ip->namelen = (int)strlen(result->namelist[i]); + memcpy((void *)ip->name, (void *)result->namelist[i], ip->namelen); +#ifdef PCP_DEBUG + if ((ip->namelen % sizeof(__pmPDU)) != 0) { + /* for Purify */ + int pad; + char *padp = ip->name + ip->namelen; + for (pad = sizeof(__pmPDU) - 1; pad >= (ip->namelen % sizeof(__pmPDU)); pad--) + *padp++ = '~'; /* buffer end */ + } +#endif + j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen); + ip->namelen = htonl(ip->namelen); + } + else { + ip->namelen = 0; + j += sizeof(*ip) - sizeof(ip->name); + } + } + + sts = __pmXmitPDU(fd, (__pmPDU *)rp); + __pmUnpinPDUBuf(rp); + return sts; +} + +int +__pmDecodeInstance(__pmPDU *pdubuf, __pmInResult **result) +{ + int i; + int j; + instance_t *rp; + instlist_t *ip; + __pmInResult *res; + int sts; + char *p; + char *pdu_end; + int keep_instlist; + int keep_namelist; + + rp = (instance_t *)pdubuf; + pdu_end = (char *)pdubuf + rp->hdr.len; + + if (pdu_end - (char *)pdubuf < sizeof(instance_t) - sizeof(__pmPDU)) + return PM_ERR_IPC; + + if ((res = (__pmInResult *)malloc(sizeof(*res))) == NULL) + return -oserror(); + res->instlist = NULL; + res->namelist = NULL; + res->indom = __ntohpmInDom(rp->indom); + res->numinst = ntohl(rp->numinst); + + if (res->numinst >= (INT_MAX / sizeof(res->instlist[0])) || + res->numinst >= (INT_MAX / sizeof(res->namelist[0])) || + res->numinst >= rp->hdr.len) { + sts = PM_ERR_IPC; + goto badsts; + } + if ((res->instlist = (int *)malloc(res->numinst * sizeof(res->instlist[0]))) == NULL) { + sts = -oserror(); + goto badsts; + } + if ((res->namelist = (char **)malloc(res->numinst * sizeof(res->namelist[0]))) == NULL) { + sts = -oserror(); + goto badsts; + } + /* required for __pmFreeInResult() in the event of a later error */ + memset(res->namelist, 0, res->numinst * sizeof(res->namelist[0])); + + if (res->numinst == 1) + keep_instlist = keep_namelist = 0; + else + keep_instlist = keep_namelist = 1; + + for (i = j = 0; i < res->numinst; i++) { + ip = (instlist_t *)&rp->rest[j/sizeof(__pmPDU)]; + if (sizeof(instlist_t) - sizeof(ip->name) > (size_t)(pdu_end - (char *)ip)) { + sts = PM_ERR_IPC; + goto badsts; + } + + res->instlist[i] = ntohl(ip->inst); + if (res->instlist[i] != PM_IN_NULL) + keep_instlist = 1; + ip->namelen = ntohl(ip->namelen); + if (ip->namelen > 0) + keep_namelist = 1; + if (ip->namelen < 0) { + sts = PM_ERR_IPC; + goto badsts; + } + if (sizeof(instlist_t) - sizeof(int) + ip->namelen > (size_t)(pdu_end - (char *)ip)) { + sts = PM_ERR_IPC; + goto badsts; + } + if ((p = (char *)malloc(ip->namelen + 1)) == NULL) { + sts = -oserror(); + goto badsts; + } + memcpy((void *)p, (void *)ip->name, ip->namelen); + p[ip->namelen] = '\0'; + res->namelist[i] = p; + j += sizeof(*ip) - sizeof(ip->name) + PM_PDU_SIZE_BYTES(ip->namelen); + } + if (keep_instlist == 0) { + free(res->instlist); + res->instlist = NULL; + } + if (keep_namelist == 0) { + free(res->namelist[0]); + free(res->namelist); + res->namelist = NULL; + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_INDOM) + __pmDumpInResult(stderr, res); +#endif + *result = res; + return 0; + +badsts: + __pmFreeInResult(res); + return sts; +} |