1 /*
2 * Copyright (c) 1995-2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; either version 2.1 of the License, or
7 * (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
13 */
14
15 #include <ctype.h>
16 #include "pmapi.h"
17 #include "impl.h"
18
19 /*
20 * PDU for pmResult (PDU_RESULT)
21 */
22
23 typedef struct {
24 pmID pmid;
25 int numval; /* no. of vlist els to follow, or error */
26 int valfmt; /* insitu or pointer */
27 __pmValue_PDU vlist[1]; /* zero or more */
28 } vlist_t;
29
30 typedef struct {
31 __pmPDUHdr hdr;
32 __pmTimeval timestamp; /* when returned */
33 int numpmid; /* no. of PMIDs to follow */
34 __pmPDU data[1]; /* zero or more */
35 } result_t;
36
37 int
38 __pmEncodeResult(int targetfd, const pmResult *result, __pmPDU **pdubuf)
39 {
40 int i;
41 int j;
42 size_t need; /* bytes for the PDU */
43 size_t vneed; /* additional bytes for the pmValueBlocks on the end */
44 __pmPDU *_pdubuf;
45 __pmPDU *vbp;
46 result_t *pp;
47 vlist_t *vlp;
48
49 /* to start with, need space for result_t with no data (__pmPDU) */
50 need = sizeof(result_t) - sizeof(__pmPDU);
51 vneed = 0;
52 /* now add space for each vlist_t (data in result_t) */
53 for (i = 0; i < result->numpmid; i++) {
54 pmValueSet *vsp = result->vset[i];
55 /* need space for PMID and count of values (defer valfmt until
56 * we know numval > 0, which means there should be a valfmt)
57 */
58 need += sizeof(pmID) + sizeof(int);
59 for (j = 0; j < vsp->numval; j++) {
60 /* plus value, instance pair */
61 need += sizeof(__pmValue_PDU);
62 if (vsp->valfmt != PM_VAL_INSITU) {
63 /* plus pmValueBlock */
64 vneed += PM_PDU_SIZE_BYTES(vsp->vlist[j].value.pval->vlen);
65 }
66 }
67 if (j)
68 /* optional value format, if any values present */
69 need += sizeof(int);
70 }
71 if ((_pdubuf = __pmFindPDUBuf((int)(need+vneed))) == NULL)
72 return -oserror();
73 pp = (result_t *)_pdubuf;
74 pp->hdr.len = (int)(need+vneed);
75 pp->hdr.type = PDU_RESULT;
76 pp->timestamp.tv_sec = htonl((__int32_t)(result->timestamp.tv_sec));
77 pp->timestamp.tv_usec = htonl((__int32_t)(result->timestamp.tv_usec));
78 pp->numpmid = htonl(result->numpmid);
79 vlp = (vlist_t *)pp->data;
80 /*
81 * Note: vbp, and hence offset in sent PDU is in units of __pmPDU
82 */
83 vbp = _pdubuf + need/sizeof(__pmPDU);
84 for (i = 0; i < result->numpmid; i++) {
85 pmValueSet *vsp = result->vset[i];
86 vlp->pmid = __htonpmID(vsp->pmid);
87 if (vsp->numval > 0)
88 vlp->valfmt = htonl(vsp->valfmt);
89 for (j = 0; j < vsp->numval; j++) {
90 vlp->vlist[j].inst = htonl(vsp->vlist[j].inst);
91 if (vsp->valfmt == PM_VAL_INSITU)
92 vlp->vlist[j].value.lval = htonl(vsp->vlist[j].value.lval);
93 else {
94 /*
95 * pmValueBlocks are harder!
96 * -- need to copy the len field (len) + len bytes (vbuf)
97 */
98 int nb;
99 nb = vsp->vlist[j].value.pval->vlen;
100 memcpy((void *)vbp, (void *)vsp->vlist[j].value.pval, nb);
101 #ifdef PCP_DEBUG
102 if ((nb % sizeof(__pmPDU)) != 0) {
103 /* for Purify */
104 int pad;
105 char *padp = (char *)vbp + nb;
106 for (pad = sizeof(__pmPDU) - 1; pad >= (nb % sizeof(__pmPDU)); pad--)
107 *padp++ = '~'; /* buffer end */
108 }
109 #endif
110 __htonpmValueBlock((pmValueBlock *)vbp);
111 /* point to the value block at the end of the PDU */
112 vlp->vlist[j].value.lval = htonl((int)(vbp - _pdubuf));
113 vbp += PM_PDU_SIZE(nb);
114 }
115 }
116 vlp->numval = htonl(vsp->numval);
117 if (j > 0)
118 vlp = (vlist_t *)((__psint_t)vlp + sizeof(*vlp) + (j-1)*sizeof(vlp->vlist[0]));
119 else
120 vlp = (vlist_t *)((__psint_t)vlp + sizeof(vlp->pmid) + sizeof(vlp->numval));
121 }
122 *pdubuf = _pdubuf;
123 return 0;
124 }
125
126 int
127 __pmSendResult(int fd, int from, const pmResult *result)
128 {
129 int sts;
130 __pmPDU *pdubuf;
131 result_t *pp;
132
133 #ifdef PCP_DEBUG
134 if (pmDebug & DBG_TRACE_PDU)
135 __pmDumpResult(stderr, result);
136 #endif
137 if ((sts = __pmEncodeResult(fd, result, &pdubuf)) < 0)
138 return sts;
139 pp = (result_t *)pdubuf;
140 pp->hdr.from = from;
141 return __pmXmitPDU(fd, pdubuf);
142 }
143
144 int
145 __pmDecodeResult(__pmPDU *pdubuf, pmResult **result)
146 {
147 int numpmid; /* number of metrics */
148 int sts; /* function status */
149 int i = 0; /* range of metrics */
150 int j; /* range over values */
151 int version;
152 result_t *pp;
153 vlist_t *vlp;
154 pmResult *pr = NULL;
155 #if defined(HAVE_64BIT_PTR)
156 char *newbuf;
157 int valfmt;
158 int numval;
159 #ifdef DESPERATE
160 pmID pmid;
161 #endif
162 /*
163 * Note: all sizes are in units of bytes ... beware that pp->data is in
164 * units of __pmPDU
165 */
166 int vsize; /* size of vlist_t's in PDU buffer */
167 int nvsize; /* size of pmValue's after decode */
168 int offset; /* differences in sizes */
169 int vbsize; /* size of pmValueBlocks */
170 pmValueSet *nvsp;
171 #elif defined(HAVE_32BIT_PTR)
172 pmValueSet *vsp; /* vlist_t == pmValueSet */
173 #else
174 Bozo - unexpected sizeof pointer!!
175 #endif
176
177 if ((sts = version = __pmLastVersionIPC()) < 0)
178 return sts;
179
180 pp = (result_t *)pdubuf;
181 numpmid = ntohl(pp->numpmid);
|
Event const: |
After this line, the value of "pr" is equal to 0. |
|
Event new_values: |
Noticing condition "(pr = (pmResult *)malloc(sizeof (pmResult) /*32*/ + (numpmid - 1) * sizeof (pmValueSet *) /*8*/)) == NULL". |
| Also see events: |
[dead_error_condition][dead_error_begin] |
182 if ((pr = (pmResult *)malloc(sizeof(pmResult) +
183 (numpmid - 1) * sizeof(pmValueSet *))) == NULL) {
184 sts = -oserror();
185 goto badsts;
186 }
187 pr->numpmid = numpmid;
188 pr->timestamp.tv_sec = ntohl(pp->timestamp.tv_sec);
189 pr->timestamp.tv_usec = ntohl(pp->timestamp.tv_usec);
190
191 #if defined(HAVE_64BIT_PTR)
192 nvsize = vsize = vbsize = 0;
193 for (i = 0; i < numpmid; i++) {
194 vlp = (vlist_t *)&pp->data[vsize/sizeof(__pmPDU)];
195 vsize += sizeof(vlp->pmid) + sizeof(vlp->numval);
196 numval = ntohl(vlp->numval);
197 valfmt = ntohl(vlp->valfmt);
198 #ifdef DESPERATE
199 pmid = __ntohpmID(vlp->pmid);
200 fprintf(stderr, "vlist[%d] pmid: %s numval: %d",
201 i, pmIDStr(pmid), numval);
202 #endif
203 nvsize += sizeof(pmValueSet);
204 if (numval > 0) {
205 vsize += sizeof(vlp->valfmt) + numval * sizeof(__pmValue_PDU);
206 nvsize += (numval - 1) * sizeof(pmValue);
207 #ifdef DESPERATE
208 fprintf(stderr, " valfmt: %s",
209 valfmt == PM_VAL_INSITU ? "insitu" : "ptr");
210 #endif
211 if (valfmt != PM_VAL_INSITU) {
212 for (j = 0; j < numval; j++) {
213 int index = ntohl(vlp->vlist[j].value.pval);
214 pmValueBlock *pduvbp = (pmValueBlock *)&pdubuf[index];
215
216 __ntohpmValueBlock(pduvbp);
217 vbsize += PM_PDU_SIZE_BYTES(pduvbp->vlen);
218 #ifdef DESPERATE
219 fprintf(stderr, " len: %d type: %d",
220 pduvbp->vlen - PM_VAL_HDR_SIZE, pduvbp->vtype);
221 #endif
222 }
223 }
224 }
225 #ifdef DESPERATE
226 fputc('\n', stderr);
227 #endif
228 }
229 #ifdef DESPERATE
230 fprintf(stderr, "vsize: %d nvsize: %d vbsize: %d\n", vsize, nvsize, vbsize);
231 #endif
232
233 /* pin the original pdubuf so we don't just allocate that again */
234 __pmPinPDUBuf(pdubuf);
235 if ((newbuf = (char *)__pmFindPDUBuf((int)nvsize + vbsize)) == NULL) {
236 free(pr);
237 __pmUnpinPDUBuf(pdubuf);
238 return -oserror();
239 }
240
241 /*
242 * At this point, we have the following set up ...
243 *
244 * From the original PDU buffer ...
245 * :-----:---------:-----------:----------------:--------------------:
246 * : Hdr : numpmid : timestamp : ... vlists ... : .. pmValueBocks .. :
247 * :-----:---------:-----------:----------------:--------------------:
248 * <--- vsize ---> <--- vbsize --->
249 * bytes bytes
250 *
251 * and in the new PDU buffer we are going to build ...
252 * :---------------------:--------------------:
253 * : ... pmValueSets ... : .. pmValueBocks .. :
254 * :---------------------:--------------------:
255 * <--- nvsize ---> <--- vbsize --->
256 * bytes bytes
257 */
258
259 if (vbsize) {
260 /* pmValueBlocks (if any) are copied across "as is" */
261 memcpy((void *)&newbuf[nvsize], (void *)&pp->data[vsize/sizeof(__pmPDU)], vbsize);
262 }
263
264 /*
265 * offset is a bit tricky ... _add_ the expansion due to the
266 * different sizes of the vlist_t and pmValueSet, and _subtract_
267 * the PDU header and pmResult fields ...
268 */
269 offset = nvsize - vsize
270 - (int)sizeof(pp->hdr) - (int)sizeof(pp->timestamp)
271 - (int)sizeof(pp->numpmid);
272 nvsize = vsize = 0;
273 for (i = 0; i < numpmid; i++) {
274 vlp = (vlist_t *)&pp->data[vsize/sizeof(__pmPDU)];
275 nvsp = (pmValueSet *)&newbuf[nvsize];
276 pr->vset[i] = nvsp;
277 nvsp->pmid = __ntohpmID(vlp->pmid);
278 nvsp->numval = ntohl(vlp->numval);
279 #ifdef DESPERATE
280 fprintf(stderr, "new vlist[%d] pmid: %s numval: %d",
281 i, pmIDStr(nvsp->pmid), nvsp->numval);
282 #endif
283
284 vsize += sizeof(nvsp->pmid) + sizeof(nvsp->numval);
285 nvsize += sizeof(pmValueSet);
286 if (nvsp->numval > 0) {
287 nvsp->valfmt = ntohl(vlp->valfmt);
288 #ifdef DESPERATE
289 fprintf(stderr, " valfmt: %s",
290 nvsp->valfmt == PM_VAL_INSITU ? "insitu" : "ptr");
291 #endif
292 vsize += sizeof(nvsp->valfmt) + nvsp->numval * sizeof(__pmValue_PDU);
293 nvsize += (nvsp->numval - 1) * sizeof(pmValue);
294 for (j = 0; j < nvsp->numval; j++) {
295 __pmValue_PDU *vp = &vlp->vlist[j];
296 pmValue *nvp = &nvsp->vlist[j];
297
298 nvp->inst = ntohl(vp->inst);
299 if (nvsp->valfmt == PM_VAL_INSITU) {
300 nvp->value.lval = ntohl(vp->value.lval);
301 #ifdef DESPERATE
302 fprintf(stderr, " value: %d", nvp->value.lval);
303 #endif
304 }
305 else {
306 /*
307 * in the input PDU buffer, pval is an index to the
308 * start of the pmValueBlock, in units of __pmPDU
309 */
310 nvp->value.pval = (pmValueBlock *)&newbuf[sizeof(__pmPDU) * ntohl(vp->value.pval) + offset];
311 #ifdef DESPERATE
312 {
313 int k, len;
314 len = nvp->value.pval->vlen - PM_VAL_HDR_SIZE;
315 fprintf(stderr, " len: %d type: %dvalue: 0x", len,
316 nvp->value.pval->vtype;
317 for (k = 0; k < len; k++)
318 fprintf(stderr, "%02x", nvp->value.pval->vbuf[k]);
319 }
320 #endif
321 }
322 }
323 }
324 else if (nvsp->numval < 0 && version == PDU_VERSION1) {
325 nvsp->numval = XLATE_ERR_1TO2(nvsp->numval);
326 }
327 #ifdef DESPERATE
328 fputc('\n', stderr);
329 #endif
330 }
331
332 __pmUnpinPDUBuf(pdubuf); /* release it now that data copied */
333 if (numpmid)
334 __pmPinPDUBuf(newbuf); /* pin the new buffer containing data */
335
336 #elif defined(HAVE_32BIT_PTR)
337
338 pr->timestamp.tv_sec = ntohl(pp->timestamp.tv_sec);
339 pr->timestamp.tv_usec = ntohl(pp->timestamp.tv_usec);
340 vlp = (vlist_t *)pp->data;
341 /*
342 * Now fix up any pointers in pmValueBlocks (currently offsets into
343 * the PDU buffer) by adding the base address of the PDU buffer.
344 */
345 for (i = 0; i < numpmid; i++) {
346 vsp = pr->vset[i] = (pmValueSet *)vlp;
347 #ifndef HAVE_NETWORK_BYTEORDER
348 vsp->pmid = __ntohpmID(vsp->pmid);
349 vsp->numval = ntohl(vsp->numval);
350 if (vsp->numval > 0) {
351 vsp->valfmt = ntohl(vsp->valfmt);
352 for (j = 0; j < vsp->numval; j++) {
353 vsp->vlist[j].inst = ntohl(vsp->vlist[j].inst);
354 if (vsp->valfmt == PM_VAL_INSITU)
355 vsp->vlist[j].value.lval = ntohl(vsp->vlist[j].value.lval);
356 }
357 }
358 #endif
359 if (vsp->numval > 0) {
360 if (vsp->valfmt != PM_VAL_INSITU) {
361 /* salvage pmValueBlocks from end of PDU */
362 for (j = 0; j < vsp->numval; j++) {
363 vsp->vlist[j].value.pval = (pmValueBlock *)&pdubuf[ntohl(vsp->vlist[j].value.lval)];
364 __ntohpmValueBlock(vsp->vlist[j].value.pval);
365 }
366 }
367 vlp = (vlist_t *)((__psint_t)vlp + sizeof(*vlp) + (vsp->numval-1)*sizeof(vlp->vlist[0]));
368 }
369 else {
370 if (vsp->numval < 0 && version == PDU_VERSION1)
371 vsp->numval = XLATE_ERR_1TO2(vsp->numval);
372 vlp = (vlist_t *)((__psint_t)vlp + sizeof(vlp->pmid) + sizeof(vlp->numval));
373 }
374 }
375 if (numpmid)
376 __pmPinPDUBuf(pdubuf);
377 #endif
378
379 #ifdef PCP_DEBUG
380 if (pmDebug & DBG_TRACE_PDU)
381 __pmDumpResult(stderr, pr);
382 #endif
383 *result = pr;
384 return 0;
385
386 badsts:
387 if (pr != NULL) {
388 /* clean up partial malloc's */
389 pr->numpmid = i;
390 pmFreeResult(pr);
391 }
392 return sts;
393 }