1355b4669Sjacobs /*
2355b4669Sjacobs  * CDDL HEADER START
3355b4669Sjacobs  *
4355b4669Sjacobs  * The contents of this file are subject to the terms of the
5355b4669Sjacobs  * Common Development and Distribution License (the "License").
6355b4669Sjacobs  * You may not use this file except in compliance with the License.
7355b4669Sjacobs  *
8355b4669Sjacobs  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9355b4669Sjacobs  * or http://www.opensolaris.org/os/licensing.
10355b4669Sjacobs  * See the License for the specific language governing permissions
11355b4669Sjacobs  * and limitations under the License.
12355b4669Sjacobs  *
13355b4669Sjacobs  * When distributing Covered Code, include this CDDL HEADER in each
14355b4669Sjacobs  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15355b4669Sjacobs  * If applicable, add the following below this CDDL HEADER, with the
16355b4669Sjacobs  * fields enclosed by brackets "[]" replaced with your own identifying
17355b4669Sjacobs  * information: Portions Copyright [yyyy] [name of copyright owner]
18355b4669Sjacobs  *
19355b4669Sjacobs  * CDDL HEADER END
20355b4669Sjacobs  */
21355b4669Sjacobs 
22355b4669Sjacobs /*
23*c40965e4Sjacobs  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24355b4669Sjacobs  * Use is subject to license terms.
25355b4669Sjacobs  *
26355b4669Sjacobs  */
27355b4669Sjacobs 
28355b4669Sjacobs /* $Id: read.c 146 2006-03-24 00:26:54Z njacobs $ */
29355b4669Sjacobs 
30355b4669Sjacobs #pragma ident	"%Z%%M%	%I%	%E% SMI"
31355b4669Sjacobs 
32355b4669Sjacobs #include <stdio.h>
33355b4669Sjacobs #include <stdlib.h>
34355b4669Sjacobs #include <alloca.h>
35355b4669Sjacobs #include <string.h>
36355b4669Sjacobs #include <stdarg.h>
37355b4669Sjacobs #include <sys/types.h>
38355b4669Sjacobs #include <netinet/in.h>
39355b4669Sjacobs #include <inttypes.h>
40355b4669Sjacobs 
41355b4669Sjacobs #include <papi.h>
42355b4669Sjacobs #include <ipp.h>
43355b4669Sjacobs 
44355b4669Sjacobs 
45355b4669Sjacobs #define	_ipp_tag_string(id) ipp_tag_string((id), buf, sizeof (buf))
46355b4669Sjacobs 
47355b4669Sjacobs static papi_status_t
48355b4669Sjacobs read_name_with_language(ipp_reader_t iread, void *fd,
49355b4669Sjacobs 			papi_attribute_t ***message)
50355b4669Sjacobs {
51355b4669Sjacobs 	char *string;
52355b4669Sjacobs 	uint16_t size;
53355b4669Sjacobs 
54355b4669Sjacobs 	/* read the language */
55355b4669Sjacobs 	if (iread(fd, &size, 2) != 2) {
56355b4669Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
57355b4669Sjacobs 				"read failed: lang len\n");
58355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
59355b4669Sjacobs 	}
60355b4669Sjacobs 	size = (uint16_t)ntohs(size);
61355b4669Sjacobs 
62355b4669Sjacobs 	if ((string = alloca(size + 1)) == NULL) {
63355b4669Sjacobs 		ipp_set_status(message, PAPI_TEMPORARY_ERROR,
64355b4669Sjacobs 				"Memory allocation failed");
65355b4669Sjacobs 		return (PAPI_TEMPORARY_ERROR);
66355b4669Sjacobs 	}
67355b4669Sjacobs 	if (iread(fd, string, size) != size) {
68355b4669Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
69355b4669Sjacobs 				"read failed: lang\n");
70355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
71355b4669Sjacobs 	}
72355b4669Sjacobs 
73355b4669Sjacobs 	/* read the text */
74355b4669Sjacobs 	if (iread(fd, &size, 2) != 2) {
75355b4669Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
76355b4669Sjacobs 				"read failed: text len\n");
77355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
78355b4669Sjacobs 	}
79355b4669Sjacobs 	size = (uint16_t)ntohs(size);
80355b4669Sjacobs 
81355b4669Sjacobs 	if ((string = alloca(size + 1)) == NULL) {
82355b4669Sjacobs 		ipp_set_status(message, PAPI_TEMPORARY_ERROR,
83355b4669Sjacobs 				"Memory allocation failed");
84355b4669Sjacobs 		return (PAPI_TEMPORARY_ERROR);
85355b4669Sjacobs 	}
86355b4669Sjacobs 	if (iread(fd, string, size) != size) {
87355b4669Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
88355b4669Sjacobs 				"read failed: text\n");
89355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
90355b4669Sjacobs 	}
91355b4669Sjacobs 
92355b4669Sjacobs 	return (PAPI_OK);
93355b4669Sjacobs }
94355b4669Sjacobs 
95355b4669Sjacobs 
96355b4669Sjacobs static struct {
97355b4669Sjacobs 	int8_t	ipp_type;
98355b4669Sjacobs 	int8_t	size;
99355b4669Sjacobs } type_info[] = {
100355b4669Sjacobs 	{ VTAG_INTEGER,			4 },
101355b4669Sjacobs 	{ VTAG_ENUM,			4 },
102355b4669Sjacobs 	{ VTAG_BOOLEAN,			1 },
103355b4669Sjacobs 	{ VTAG_RANGE_OF_INTEGER,	8 },
104355b4669Sjacobs 	{ VTAG_RESOLUTION,		9 },
105355b4669Sjacobs 	{ VTAG_DATE_TIME,		11 },
106355b4669Sjacobs 	{ DTAG_MIN,			0 }
107355b4669Sjacobs };
108355b4669Sjacobs 
109355b4669Sjacobs /* verify that the IPP type and size are compatible */
110355b4669Sjacobs static int
111355b4669Sjacobs validate_length(int8_t type, int8_t size)
112355b4669Sjacobs {
113355b4669Sjacobs 	int i;
114355b4669Sjacobs 
115355b4669Sjacobs 	for (i = 0; type_info[i].ipp_type != DTAG_MIN; i++)
116355b4669Sjacobs 		if (type_info[i].ipp_type == type)
117355b4669Sjacobs 			return ((type_info[i].size == size) ? 0 : -1);
118355b4669Sjacobs 	return (0);
119355b4669Sjacobs }
120355b4669Sjacobs 
121355b4669Sjacobs /* convert tyep IPP type to a type that is marginally compatible */
122355b4669Sjacobs static int8_t
123355b4669Sjacobs base_type(int8_t i)
124355b4669Sjacobs {
125355b4669Sjacobs 	switch (i) {
126355b4669Sjacobs 	case VTAG_ENUM:
127355b4669Sjacobs 	case VTAG_INTEGER:
128355b4669Sjacobs 		return (VTAG_INTEGER);
129355b4669Sjacobs 	case VTAG_URI:
130355b4669Sjacobs 	case VTAG_OCTET_STRING:
131355b4669Sjacobs 	case VTAG_TEXT_WITHOUT_LANGUAGE:
132355b4669Sjacobs 	case VTAG_URI_SCHEME:
133355b4669Sjacobs 	case VTAG_CHARSET:
134355b4669Sjacobs 	case VTAG_NATURAL_LANGUAGE:
135355b4669Sjacobs 	case VTAG_MIME_MEDIA_TYPE:
136355b4669Sjacobs 	case VTAG_NAME_WITHOUT_LANGUAGE:
137355b4669Sjacobs 	case VTAG_KEYWORD:
138355b4669Sjacobs 		return (VTAG_TEXT_WITHOUT_LANGUAGE);
139355b4669Sjacobs 	case VTAG_BOOLEAN:
140355b4669Sjacobs 	case VTAG_RANGE_OF_INTEGER:
141355b4669Sjacobs 	case VTAG_DATE_TIME:
142355b4669Sjacobs 	case VTAG_RESOLUTION:
143355b4669Sjacobs 	default:
144355b4669Sjacobs 		return (i);
145355b4669Sjacobs 	}
146355b4669Sjacobs }
147355b4669Sjacobs 
148355b4669Sjacobs /* verify that the IPP type is correct for the named attribute */
149355b4669Sjacobs static papi_status_t
150355b4669Sjacobs validate_type(char *name, int8_t type)
151355b4669Sjacobs {
152355b4669Sjacobs 	int8_t t = name_to_ipp_type(name);
153355b4669Sjacobs 
154355b4669Sjacobs 	if (t == 0)		/* The attribute is not defined in the RFC */
155355b4669Sjacobs 		return (PAPI_NOT_FOUND);
156355b4669Sjacobs 	else if (t == type)	/* The supplied type matched the RFC type */
157355b4669Sjacobs 		return (PAPI_OK);
158355b4669Sjacobs 	else {			/* The supplied type doesn't match the RFC */
159355b4669Sjacobs 		if (base_type(t) == base_type(type))
160355b4669Sjacobs 			return (PAPI_OK);
161355b4669Sjacobs 
162355b4669Sjacobs 		return (PAPI_CONFLICT);
163355b4669Sjacobs 	}
164355b4669Sjacobs }
165355b4669Sjacobs 
166355b4669Sjacobs /* verify that the IPP value is within specification for the named attribute */
167355b4669Sjacobs static int
168355b4669Sjacobs validate_value(papi_attribute_t ***message, char *name, int8_t type, ...)
169355b4669Sjacobs {
170355b4669Sjacobs #define	within(a, b, c)	((b >= a) && (b <= c))
171355b4669Sjacobs 	va_list ap;
172355b4669Sjacobs 	int rc = -1;
173355b4669Sjacobs 	int min = min_val_len(type, name),
174355b4669Sjacobs 	    max = max_val_len(type, name);
175355b4669Sjacobs 	char buf[64];	/* For _ipp_<...>_string() */
176355b4669Sjacobs 
177355b4669Sjacobs 	va_start(ap, type);
178355b4669Sjacobs 	switch (type) {
179355b4669Sjacobs 	case VTAG_ENUM:
180355b4669Sjacobs 	case VTAG_INTEGER: {
181355b4669Sjacobs 		int32_t i = (int32_t)va_arg(ap, int32_t);
182355b4669Sjacobs 
183355b4669Sjacobs 		if (within(min, i, max))
184355b4669Sjacobs 			rc = 0;
185355b4669Sjacobs 		else
186355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
187355b4669Sjacobs 				"%s(%s): %d: out of range (%d - %d)", name,
188355b4669Sjacobs 				_ipp_tag_string(type), i, min, max);
189355b4669Sjacobs 		}
190355b4669Sjacobs 		break;
191355b4669Sjacobs 	case VTAG_BOOLEAN: {
192355b4669Sjacobs 		int8_t v = (int8_t)va_arg(ap, int);
193355b4669Sjacobs 
194355b4669Sjacobs 		if (within(0, v, 1))
195355b4669Sjacobs 			rc = 0;
196355b4669Sjacobs 		else
197355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
198355b4669Sjacobs 				"%s(%s): %d: out of range (0 - 1)", name,
199355b4669Sjacobs 				_ipp_tag_string(type), v);
200355b4669Sjacobs 		}
201355b4669Sjacobs 		break;
202355b4669Sjacobs 	case VTAG_RANGE_OF_INTEGER: {
203355b4669Sjacobs 		int32_t lower = (int32_t)va_arg(ap, int32_t);
204355b4669Sjacobs 		int32_t upper = (int32_t)va_arg(ap, int32_t);
205355b4669Sjacobs 
206355b4669Sjacobs 		if (within(min, lower, max) &&
207355b4669Sjacobs 		    within(min, upper, max))
208355b4669Sjacobs 			rc = 0;
209355b4669Sjacobs 		else
210355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
211355b4669Sjacobs 				"%s(%s): %d - %d: out of range (%d - %d)", name,
212355b4669Sjacobs 				_ipp_tag_string(type), lower, upper, min, max);
213355b4669Sjacobs 		}
214355b4669Sjacobs 		break;
215355b4669Sjacobs 	case VTAG_URI:
216355b4669Sjacobs 	case VTAG_OCTET_STRING:
217355b4669Sjacobs 	case VTAG_TEXT_WITHOUT_LANGUAGE:
218355b4669Sjacobs 	case VTAG_URI_SCHEME:
219355b4669Sjacobs 	case VTAG_CHARSET:
220355b4669Sjacobs 	case VTAG_NATURAL_LANGUAGE:
221355b4669Sjacobs 	case VTAG_MIME_MEDIA_TYPE:
222355b4669Sjacobs 	case VTAG_NAME_WITHOUT_LANGUAGE: {
223355b4669Sjacobs 		char *v = (char *)va_arg(ap, char *);
224355b4669Sjacobs 
225355b4669Sjacobs 		if (strlen(v) < max)
226355b4669Sjacobs 			rc = 0;
227355b4669Sjacobs 		else
228355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
229355b4669Sjacobs 				"%s(%s): %s: too long (max length: %d)", name,
230355b4669Sjacobs 				_ipp_tag_string(type), v, max);
231355b4669Sjacobs 		}
232355b4669Sjacobs 		break;
233355b4669Sjacobs 	case VTAG_KEYWORD: {
234355b4669Sjacobs 		char *v = (char *)va_arg(ap, char *);
235355b4669Sjacobs 
236355b4669Sjacobs 		if (strlen(v) >= max)
237355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
238355b4669Sjacobs 				"%s(%s): %s: too long (max length: %d)", name,
239355b4669Sjacobs 				_ipp_tag_string(type), v, max);
240355b4669Sjacobs 		else if (is_keyword(v) == 0)
241355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_ARGUMENT,
242355b4669Sjacobs 				"%s(%s): %s: invalid keyword", name,
243355b4669Sjacobs 				_ipp_tag_string(type), v);
244355b4669Sjacobs 		else
245355b4669Sjacobs 			rc = 0;
246355b4669Sjacobs 		}
247355b4669Sjacobs 		break;
248355b4669Sjacobs 	case VTAG_DATE_TIME:
249355b4669Sjacobs 	case VTAG_RESOLUTION:
250355b4669Sjacobs 	default:
251355b4669Sjacobs 		rc = 0;
252355b4669Sjacobs 	}
253355b4669Sjacobs 	va_end(ap);
254355b4669Sjacobs 
255355b4669Sjacobs 	return (rc);
256355b4669Sjacobs #undef within
257355b4669Sjacobs }
258355b4669Sjacobs 
259355b4669Sjacobs /*
260355b4669Sjacobs  * read_attr_group() reads in enough of the message data to parse an entire
261355b4669Sjacobs  * attribute group.  Since to determine that the group is finished you have to
262355b4669Sjacobs  * read the character that determines the type of the next group, this function
263355b4669Sjacobs  * must return that character, in order that our caller knows how to call us for
264355b4669Sjacobs  * the next group.  Thus type is used both as an input parameter (the type of
265355b4669Sjacobs  * attribute group to read in) and an output parameter (the type of the next
266355b4669Sjacobs  * attribute group).
267355b4669Sjacobs  */
268355b4669Sjacobs 
269355b4669Sjacobs static papi_status_t
270355b4669Sjacobs ipp_read_attribute_group(ipp_reader_t iread, void *fd, int8_t *type,
271355b4669Sjacobs 			papi_attribute_t ***message)
272355b4669Sjacobs {
273355b4669Sjacobs 	int8_t value_tag;
274355b4669Sjacobs 	uint16_t name_length, value_length;
275355b4669Sjacobs 	papi_attribute_t **attributes = NULL;
276355b4669Sjacobs 	char *name = NULL;
277355b4669Sjacobs 	int i;
278355b4669Sjacobs 	char buf[64];	/* For _ipp_<...>_string() */
279355b4669Sjacobs 
280355b4669Sjacobs 	/*
281355b4669Sjacobs 	 * RFC2910 3.3 says we need to handle `An expected but missing
282355b4669Sjacobs 	 * "begin-attribute-group-tag" field.  How?
283355b4669Sjacobs 	 */
284355b4669Sjacobs 	if (*type > DTAG_MAX)  {
285355b4669Sjacobs 		/* Scream bloody murder, or assign a new type? */
286355b4669Sjacobs 		ipp_set_status(message, PAPI_BAD_REQUEST,
287355b4669Sjacobs 			"Bad attribute group tag 0x%.2hx (%s)",
288355b4669Sjacobs 			*type, _ipp_tag_string(*type));
289355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
290355b4669Sjacobs 	}
291355b4669Sjacobs 
292355b4669Sjacobs 	/* This loops through *values* not *attributes*! */
293355b4669Sjacobs 	for (i = 0; ; i++) {
294355b4669Sjacobs 		papi_status_t valid = PAPI_OK;
295355b4669Sjacobs 		if (iread(fd, &value_tag, 1) != 1) {
296355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
297355b4669Sjacobs 				"bad read: value tag\n");
298355b4669Sjacobs 			return (PAPI_BAD_REQUEST);
299355b4669Sjacobs 		}
300355b4669Sjacobs 		/* are we done with this group ? */
301355b4669Sjacobs 		if (value_tag <= DTAG_MAX)
302355b4669Sjacobs 			break;
303355b4669Sjacobs 
304355b4669Sjacobs 		if (iread(fd, &name_length, 2) != 2) {
305355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
306355b4669Sjacobs 				"bad read: name length\n");
307355b4669Sjacobs 			return (PAPI_BAD_REQUEST);
308355b4669Sjacobs 		}
309355b4669Sjacobs 		name_length = (uint16_t)ntohs(name_length);
310355b4669Sjacobs 
311355b4669Sjacobs 		/* Not just another value for the previous attribute */
312355b4669Sjacobs 		if (name_length != 0) {
313355b4669Sjacobs 			if ((name = alloca(name_length + 1)) == NULL) {
314355b4669Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
315355b4669Sjacobs 					"alloca(): failed\n");
316355b4669Sjacobs 				return (PAPI_TEMPORARY_ERROR);
317355b4669Sjacobs 			}
318355b4669Sjacobs 			(void) memset(name, 0, name_length + 1);
319355b4669Sjacobs 
320355b4669Sjacobs 			if (iread(fd, name, name_length) != name_length) {
321355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
322355b4669Sjacobs 					"bad read: name\n");
323355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
324355b4669Sjacobs 			}
325355b4669Sjacobs 		}
326355b4669Sjacobs 
327355b4669Sjacobs 		valid = validate_type(name, value_tag);
328355b4669Sjacobs 		if ((valid != PAPI_OK) && (valid != PAPI_NOT_FOUND))
329355b4669Sjacobs 			ipp_set_status(message, valid, "%s(%s): %s", name,
330355b4669Sjacobs 				_ipp_tag_string(value_tag),
331355b4669Sjacobs 				papiStatusString(valid));
332355b4669Sjacobs 
333355b4669Sjacobs 		if (iread(fd, &value_length, 2) != 2) {
334355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
335355b4669Sjacobs 				"bad read: value length\n");
336355b4669Sjacobs 			return (PAPI_BAD_REQUEST);
337355b4669Sjacobs 		}
338355b4669Sjacobs 		value_length = (uint16_t)ntohs(value_length);
339355b4669Sjacobs 
340355b4669Sjacobs 		if (validate_length(value_tag, value_length) < 0) {
341355b4669Sjacobs 			ipp_set_status(message, PAPI_BAD_REQUEST,
342355b4669Sjacobs 				"Bad value length (%d) for type %s",
343355b4669Sjacobs 				value_length, _ipp_tag_string(value_tag));
344355b4669Sjacobs 			return (PAPI_BAD_REQUEST);
345355b4669Sjacobs 		}
346355b4669Sjacobs 
347355b4669Sjacobs 		switch (value_tag) {
348355b4669Sjacobs 		case VTAG_INTEGER:
349355b4669Sjacobs 		case VTAG_ENUM: {
350355b4669Sjacobs 			int32_t v;
351355b4669Sjacobs 
352355b4669Sjacobs 			if (iread(fd, &v, value_length) != value_length) {
353355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
354355b4669Sjacobs 					"bad read: int/enum\n");
355355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
356355b4669Sjacobs 			}
357355b4669Sjacobs 			v = (int32_t)ntohl(v);
358355b4669Sjacobs 			(void) validate_value(message, name, value_tag, v);
359355b4669Sjacobs 			papiAttributeListAddInteger(&attributes,
360355b4669Sjacobs 						PAPI_ATTR_APPEND, name, v);
361355b4669Sjacobs 
362355b4669Sjacobs 			}
363355b4669Sjacobs 			break;
364355b4669Sjacobs 		case VTAG_BOOLEAN: {
365355b4669Sjacobs 			int8_t v;
366355b4669Sjacobs 
367355b4669Sjacobs 			if (iread(fd, &v, value_length) != value_length) {
368355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
369355b4669Sjacobs 					"bad read: boolean\n");
370355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
371355b4669Sjacobs 			}
372355b4669Sjacobs 			(void) validate_value(message, name, value_tag, v);
373355b4669Sjacobs 			papiAttributeListAddBoolean(&attributes,
374355b4669Sjacobs 						PAPI_ATTR_APPEND, name, v);
375355b4669Sjacobs 			}
376355b4669Sjacobs 			break;
377355b4669Sjacobs 		case VTAG_RANGE_OF_INTEGER: {
378355b4669Sjacobs 			int32_t min, max;
379355b4669Sjacobs 
380355b4669Sjacobs 			if (iread(fd, &min, 4) != 4) {
381355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
382355b4669Sjacobs 					"bad read: min\n");
383355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
384355b4669Sjacobs 			}
385355b4669Sjacobs 			if (iread(fd, &max, 4) != 4) {
386355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
387355b4669Sjacobs 					"bad read: max\n");
388355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
389355b4669Sjacobs 			}
390355b4669Sjacobs 			min = (int32_t)ntohl(min);
391355b4669Sjacobs 			max = (int32_t)ntohl(max);
392355b4669Sjacobs 			(void) validate_value(message, name, value_tag,
393355b4669Sjacobs 					min, max);
394355b4669Sjacobs 			papiAttributeListAddRange(&attributes, PAPI_ATTR_APPEND,
395355b4669Sjacobs 						name, min, max);
396355b4669Sjacobs 			}
397355b4669Sjacobs 			break;
398355b4669Sjacobs 		case VTAG_RESOLUTION: {
399355b4669Sjacobs 			int32_t x, y;
400355b4669Sjacobs 			int8_t units;
401355b4669Sjacobs 
402355b4669Sjacobs 			if (iread(fd, &x, 4) != 4) {
403355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
404355b4669Sjacobs 					"bad read: x\n");
405355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
406355b4669Sjacobs 			}
407355b4669Sjacobs 			if (iread(fd, &y, 4) != 4) {
408355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
409355b4669Sjacobs 					"bad read: y\n");
410355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
411355b4669Sjacobs 			}
412355b4669Sjacobs 			if (iread(fd, &units, 1) != 1) {
413355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
414355b4669Sjacobs 					"bad read: units\n");
415355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
416355b4669Sjacobs 			}
417355b4669Sjacobs 			x = (int32_t)ntohl(x);
418355b4669Sjacobs 			y = (int32_t)ntohl(y);
419355b4669Sjacobs 			papiAttributeListAddResolution(&attributes,
420355b4669Sjacobs 						PAPI_ATTR_APPEND, name, x, y,
421355b4669Sjacobs 						(papi_resolution_unit_t)units);
422355b4669Sjacobs 			}
423355b4669Sjacobs 			break;
424355b4669Sjacobs 		case VTAG_DATE_TIME: {
425355b4669Sjacobs 			struct tm tm;
426355b4669Sjacobs 			time_t v;
427355b4669Sjacobs 			int8_t c;
428355b4669Sjacobs 			uint16_t s;
429355b4669Sjacobs 
430355b4669Sjacobs 			(void) memset(&tm, 0, sizeof (tm));
431355b4669Sjacobs 			if (iread(fd, &s, 2) != 2) {
432355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
433355b4669Sjacobs 					"bad read: year\n");
434355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
435355b4669Sjacobs 			}
436355b4669Sjacobs 			tm.tm_year = (uint16_t)ntohs(s) - 1900;
437355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
438355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
439355b4669Sjacobs 					"bad read: month\n");
440355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
441355b4669Sjacobs 			}
442355b4669Sjacobs 			tm.tm_mon = c - 1;
443355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
444355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
445355b4669Sjacobs 					"bad read: day\n");
446355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
447355b4669Sjacobs 			}
448355b4669Sjacobs 			tm.tm_mday = c;
449355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
450355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
451355b4669Sjacobs 					"bad read: hour\n");
452355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
453355b4669Sjacobs 			}
454355b4669Sjacobs 			tm.tm_hour = c;
455355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
456355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
457355b4669Sjacobs 					"bad read: minutes\n");
458355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
459355b4669Sjacobs 			}
460355b4669Sjacobs 			tm.tm_min = c;
461355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
462355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
463355b4669Sjacobs 					"bad read: seconds\n");
464355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
465355b4669Sjacobs 			}
466355b4669Sjacobs 			tm.tm_sec = c;
467355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
468355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
469355b4669Sjacobs 					"bad read: decisec\n");
470355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
471355b4669Sjacobs 			}
472355b4669Sjacobs 			/* tm.deciseconds = c; */
473355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
474355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
475355b4669Sjacobs 					"bad read: utc_dir\n");
476355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
477355b4669Sjacobs 			}
478355b4669Sjacobs 			/* tm.utc_dir = c; */
479355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
480355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
481355b4669Sjacobs 					"bad read: utc_hour\n");
482355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
483355b4669Sjacobs 			}
484355b4669Sjacobs 			/* tm.utc_hours = c; */
485355b4669Sjacobs 			if (iread(fd, &c, 1) != 1) {
486355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
487355b4669Sjacobs 					"bad read: utc_min\n");
488355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
489355b4669Sjacobs 			}
490355b4669Sjacobs 			/* tm.utc_minutes = c; */
491355b4669Sjacobs 
492355b4669Sjacobs 			v = mktime(&tm);
493355b4669Sjacobs 
494355b4669Sjacobs 			(void) validate_value(message, name, value_tag, v);
495355b4669Sjacobs 			papiAttributeListAddDatetime(&attributes,
496355b4669Sjacobs 						PAPI_ATTR_APPEND, name, v);
497355b4669Sjacobs 			}
498355b4669Sjacobs 			break;
499355b4669Sjacobs 		case VTAG_NAME_WITH_LANGUAGE:
500355b4669Sjacobs 		case VTAG_TEXT_WITH_LANGUAGE:
501355b4669Sjacobs 			/*
502355b4669Sjacobs 			 * we are dropping this because we don't support
503355b4669Sjacobs 			 * name with language at this time.
504355b4669Sjacobs 			 */
505355b4669Sjacobs 			(void) read_name_with_language(iread, fd, message);
506355b4669Sjacobs 			break;
507355b4669Sjacobs 		case VTAG_NAME_WITHOUT_LANGUAGE:
508355b4669Sjacobs 		case VTAG_TEXT_WITHOUT_LANGUAGE:
509355b4669Sjacobs 		case VTAG_URI:
510355b4669Sjacobs 		case VTAG_KEYWORD:
511355b4669Sjacobs 		case VTAG_CHARSET: {
512355b4669Sjacobs 			char *v;
513355b4669Sjacobs 
514355b4669Sjacobs 			if ((v = calloc(1, value_length + 1)) == NULL) {
515355b4669Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
516355b4669Sjacobs 					"calloc(): failed\n");
517355b4669Sjacobs 				return (PAPI_TEMPORARY_ERROR);
518355b4669Sjacobs 			}
519355b4669Sjacobs #ifdef NOTDEF
520355b4669Sjacobs 			if (iread(fd, v, value_length) != value_length) {
521355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
522355b4669Sjacobs 					"bad read: stringy\n");
523355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
524355b4669Sjacobs 			}
525355b4669Sjacobs #else
526355b4669Sjacobs 			{
527355b4669Sjacobs 			int rc, i = value_length;
528355b4669Sjacobs 			char *p = v;
529355b4669Sjacobs 
530355b4669Sjacobs 			while ((rc = iread(fd, p, i)) != i) {
531355b4669Sjacobs 				if (rc <= 0) {
532355b4669Sjacobs 					ipp_set_status(message,
533355b4669Sjacobs 						PAPI_BAD_REQUEST,
534355b4669Sjacobs 						"bad read: stringy\n");
535355b4669Sjacobs 					return (PAPI_BAD_REQUEST);
536355b4669Sjacobs 				}
537355b4669Sjacobs 				i -= rc;
538355b4669Sjacobs 				p += rc;
539355b4669Sjacobs 			}
540355b4669Sjacobs 			}
541355b4669Sjacobs #endif
542355b4669Sjacobs 			(void) validate_value(message, name, value_tag, v);
543355b4669Sjacobs 			papiAttributeListAddString(&attributes,
544355b4669Sjacobs 						PAPI_ATTR_APPEND, name, v);
545355b4669Sjacobs 			}
546355b4669Sjacobs 			break;
547355b4669Sjacobs 		case VTAG_UNKNOWN:
548355b4669Sjacobs 		case VTAG_NOVALUE:
549355b4669Sjacobs 		case VTAG_UNSUPPORTED:
550355b4669Sjacobs 			papiAttributeListAddValue(&attributes, PAPI_ATTR_EXCL,
551355b4669Sjacobs 					name, PAPI_COLLECTION, NULL);
552355b4669Sjacobs 			break;
553355b4669Sjacobs 		default: {
554355b4669Sjacobs 			char *v;
555355b4669Sjacobs 
556355b4669Sjacobs 			if ((v = calloc(1, value_length + 1)) == NULL) {
557355b4669Sjacobs 				ipp_set_status(message, PAPI_TEMPORARY_ERROR,
558355b4669Sjacobs 					"calloc(): failed\n");
559355b4669Sjacobs 				return (PAPI_TEMPORARY_ERROR);
560355b4669Sjacobs 			}
561355b4669Sjacobs 			if (iread(fd, v, value_length) != value_length) {
562355b4669Sjacobs 				ipp_set_status(message, PAPI_BAD_REQUEST,
563355b4669Sjacobs 					"bad read: other\n");
564355b4669Sjacobs 				return (PAPI_BAD_REQUEST);
565355b4669Sjacobs 			}
566355b4669Sjacobs 			papiAttributeListAddString(&attributes,
567355b4669Sjacobs 						PAPI_ATTR_APPEND, name, v);
568355b4669Sjacobs 			}
569355b4669Sjacobs 			break;
570355b4669Sjacobs 		}
571355b4669Sjacobs 	}
572355b4669Sjacobs 
573355b4669Sjacobs 	if (attributes != NULL) {
574355b4669Sjacobs 		char name[32];
575355b4669Sjacobs 
576355b4669Sjacobs 		(void) ipp_tag_string(*type, name, sizeof (name));
577355b4669Sjacobs 		papiAttributeListAddCollection(message, PAPI_ATTR_APPEND, name,
578355b4669Sjacobs 					attributes);
579355b4669Sjacobs 	}
580355b4669Sjacobs 
581355b4669Sjacobs 	*type = value_tag;
582355b4669Sjacobs 
583355b4669Sjacobs 	return (PAPI_OK);
584355b4669Sjacobs }
585355b4669Sjacobs 
586355b4669Sjacobs 
587355b4669Sjacobs static papi_status_t
588355b4669Sjacobs ipp_read_header(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
589355b4669Sjacobs 		char type)
590355b4669Sjacobs {
591355b4669Sjacobs 	char *attr_name = "status-code";	/* default to a response */
592355b4669Sjacobs 	char buf[8];
593355b4669Sjacobs 	int8_t c;
594355b4669Sjacobs 	uint16_t s;
595355b4669Sjacobs 	int32_t i;
596355b4669Sjacobs 
597355b4669Sjacobs 	if ((iread == NULL) || (fd == NULL) || (message == NULL))
598355b4669Sjacobs 		return (PAPI_BAD_ARGUMENT);
599355b4669Sjacobs 
600355b4669Sjacobs 	/*
601355b4669Sjacobs 	 * Apache 1.X uses the buffer supplied to it's read call to read in
602355b4669Sjacobs 	 * the chunk size when chunking is used.  This causes problems
603355b4669Sjacobs 	 * reading the header a piece at a time, because we don't have
604355b4669Sjacobs 	 * enough room to read in the chunk size prior to reading the
605355b4669Sjacobs 	 * chunk.
606355b4669Sjacobs 	 */
607355b4669Sjacobs 
608355b4669Sjacobs 	if (iread(fd, buf, 8) != 8)
609355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
610355b4669Sjacobs 
611355b4669Sjacobs 	c = buf[0];
612355b4669Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
613355b4669Sjacobs 				"version-major", c);
614355b4669Sjacobs 
615355b4669Sjacobs 	c = buf[1];
616355b4669Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
617355b4669Sjacobs 				"version-minor", c);
618355b4669Sjacobs 
619355b4669Sjacobs 	memcpy(&s, &buf[2], 2);
620355b4669Sjacobs 	s = (uint16_t)ntohs(s);
621355b4669Sjacobs 	if (type == IPP_TYPE_REQUEST)
622355b4669Sjacobs 		attr_name = "operation-id";
623355b4669Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
624355b4669Sjacobs 				attr_name, s);
625355b4669Sjacobs 
626*c40965e4Sjacobs 	memcpy(&i, &buf[4], 4);
627355b4669Sjacobs 	i = (uint32_t)ntohl(i);
628355b4669Sjacobs 	(void) papiAttributeListAddInteger(message, PAPI_ATTR_REPLACE,
629355b4669Sjacobs 				"request-id", i);
630355b4669Sjacobs 
631355b4669Sjacobs 	return (PAPI_OK);
632355b4669Sjacobs }
633355b4669Sjacobs 
634355b4669Sjacobs static papi_status_t
635355b4669Sjacobs ipp_read_attribute_groups(ipp_reader_t iread, void *fd,
636355b4669Sjacobs 			papi_attribute_t ***message)
637355b4669Sjacobs {
638355b4669Sjacobs 	papi_status_t result = PAPI_OK;
639355b4669Sjacobs 	int8_t tag;
640355b4669Sjacobs 
641355b4669Sjacobs 	/* start reading the attribute groups */
642355b4669Sjacobs 	if (iread(fd, &tag, 1) != 1)	/* prime the pump */
643355b4669Sjacobs 		return (PAPI_BAD_REQUEST);
644355b4669Sjacobs 
645355b4669Sjacobs 	while ((tag != DTAG_END_OF_ATTRIBUTES) && (result == PAPI_OK)) {
646355b4669Sjacobs 		result = ipp_read_attribute_group(iread, fd, &tag, message);
647355b4669Sjacobs 	}
648355b4669Sjacobs 
649355b4669Sjacobs 	return (result);
650355b4669Sjacobs }
651355b4669Sjacobs 
652355b4669Sjacobs papi_status_t
653355b4669Sjacobs ipp_read_message(ipp_reader_t iread, void *fd, papi_attribute_t ***message,
654355b4669Sjacobs 		char type)
655355b4669Sjacobs {
656355b4669Sjacobs 	papi_status_t result = PAPI_OK;
657355b4669Sjacobs 
658355b4669Sjacobs 	if ((iread == NULL) || (fd == NULL) || (message == NULL))
659355b4669Sjacobs 		return (PAPI_BAD_ARGUMENT);
660355b4669Sjacobs 
661355b4669Sjacobs 	result = ipp_read_header(iread, fd, message, type);
662355b4669Sjacobs 	if (result == PAPI_OK)
663355b4669Sjacobs 		result = ipp_read_attribute_groups(iread, fd, message);
664355b4669Sjacobs 
665355b4669Sjacobs 	return (result);
666355b4669Sjacobs }
667