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:
Event dead_error_condition: On this path, the condition "pr != NULL" cannot be true.
Also see events: [const][new_values][dead_error_begin]
387  	    if (pr != NULL) {
388  		/* clean up partial malloc's */
Event dead_error_begin: Execution cannot reach this statement "pr->numpmid = i;".
Also see events: [dead_error_condition][const][new_values]
389  		pr->numpmid = i;
390  		pmFreeResult(pr);
391  	    }
392  	    return sts;
393  	}