1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 */
27
28 /* $Id: write.c 146 2006-03-24 00:26:54Z njacobs $ */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
35 #include <inttypes.h>
36
37 #include <papi.h>
38 #include <ipp.h>
39
40 static int8_t
papi_attribute_to_ipp_type(papi_attribute_value_type_t type)41 papi_attribute_to_ipp_type(papi_attribute_value_type_t type)
42 {
43 switch (type) {
44 case PAPI_INTEGER:
45 return (VTAG_INTEGER);
46 case PAPI_BOOLEAN:
47 return (VTAG_BOOLEAN);
48 case PAPI_RANGE:
49 return (VTAG_RANGE_OF_INTEGER);
50 case PAPI_RESOLUTION:
51 return (VTAG_RESOLUTION);
52 case PAPI_DATETIME:
53 return (VTAG_DATE_TIME);
54 case PAPI_STRING:
55 return (VTAG_TEXT_WITHOUT_LANGUAGE);
56 }
57
58 return (0);
59 }
60
61 static papi_status_t
papi_ipp_type_match(papi_attribute_value_type_t papi,int8_t ipp)62 papi_ipp_type_match(papi_attribute_value_type_t papi, int8_t ipp)
63 {
64 switch (papi) {
65 case PAPI_STRING:
66 switch (ipp) {
67 case VTAG_URI:
68 case VTAG_OCTET_STRING:
69 case VTAG_TEXT_WITHOUT_LANGUAGE:
70 case VTAG_URI_SCHEME:
71 case VTAG_CHARSET:
72 case VTAG_NATURAL_LANGUAGE:
73 case VTAG_MIME_MEDIA_TYPE:
74 case VTAG_NAME_WITHOUT_LANGUAGE:
75 case VTAG_KEYWORD:
76 break;
77 default:
78 return (PAPI_CONFLICT);
79 }
80 break;
81 case PAPI_INTEGER:
82 switch (ipp) {
83 case VTAG_ENUM:
84 case VTAG_INTEGER:
85 break;
86 default:
87 return (PAPI_CONFLICT);
88 }
89 break;
90 case PAPI_BOOLEAN:
91 if (ipp != VTAG_BOOLEAN)
92 return (PAPI_CONFLICT);
93 break;
94 case PAPI_RANGE:
95 if (ipp != VTAG_RANGE_OF_INTEGER)
96 return (PAPI_CONFLICT);
97 break;
98 case PAPI_RESOLUTION:
99 if (ipp != VTAG_RESOLUTION)
100 return (PAPI_CONFLICT);
101 break;
102 case PAPI_DATETIME:
103 if (ipp != VTAG_DATE_TIME)
104 return (PAPI_CONFLICT);
105 break;
106 case PAPI_COLLECTION:
107 /* don't need to match */
108 break;
109 }
110
111 return (PAPI_OK);
112 }
113
114 static papi_status_t
ipp_write_attribute(ipp_writer_t iwrite,void * fd,papi_attribute_t * attribute)115 ipp_write_attribute(ipp_writer_t iwrite, void *fd, papi_attribute_t *attribute)
116 {
117 papi_status_t status;
118 papi_attribute_value_t **values;
119 int8_t type;
120 int i;
121 char *name;
122
123 name = attribute->name;
124 values = attribute->values;
125
126 if ((type = name_to_ipp_type(name)) == 0)
127 type = papi_attribute_to_ipp_type(attribute->type);
128
129 /* The types don't match, so don't send the attribute */
130 if ((status = papi_ipp_type_match(attribute->type, type)) != PAPI_OK)
131 return (status);
132
133 if (values == NULL) {
134 uint16_t length;
135
136 type = VTAG_UNSUPPORTED;
137 if (iwrite(fd, &type, 1) != 1)
138 return (PAPI_DEVICE_ERROR);
139
140 if (name != NULL) { /* first value gets named */
141 length = (uint16_t)htons(strlen(name));
142
143 if (iwrite(fd, &length, 2) != 2)
144 return (PAPI_DEVICE_ERROR);
145 if (iwrite(fd, name, strlen(name)) != strlen(name))
146 return (PAPI_DEVICE_ERROR);
147 }
148
149 length = (uint16_t)htons(0);
150 if (iwrite(fd, &length, 2) != 2)
151 return (PAPI_DEVICE_ERROR);
152
153 return (PAPI_OK);
154 }
155
156
157
158 for (i = 0; values[i] != NULL; i++) {
159 papi_attribute_value_t *value = values[i];
160 uint16_t length = 0;
161
162 if (iwrite(fd, &type, 1) != 1)
163 return (PAPI_DEVICE_ERROR);
164
165 if (name != NULL) { /* first value gets named */
166 length = (uint16_t)htons(strlen(name));
167
168 if (iwrite(fd, &length, 2) != 2)
169 return (PAPI_DEVICE_ERROR);
170 if (iwrite(fd, name, strlen(name)) != strlen(name))
171 return (PAPI_DEVICE_ERROR);
172 name = NULL;
173 } else {
174 length = (uint16_t)htons(0);
175
176 if (iwrite(fd, &length, 2) != 2)
177 return (PAPI_DEVICE_ERROR);
178 }
179
180 switch (attribute->type) {
181 case PAPI_STRING: {
182 char *v = (char *)value->string;
183
184 if (v != NULL) {
185 size_t str_length = strlen(v);
186
187 /*
188 * if the length is more than 16 bits can
189 * express, send what can be represented
190 * in 16 bits. IPP "strings" can only be
191 * that large.
192 */
193 if (str_length > 0xFFFF)
194 str_length = 0xFFFF;
195
196 length = (uint16_t)htons(str_length);
197 if (iwrite(fd, &length, 2) != 2)
198 return (PAPI_DEVICE_ERROR);
199 if (iwrite(fd, v, str_length) != str_length)
200 return (PAPI_DEVICE_ERROR);
201 } else
202 if (iwrite(fd, &length, 2) != 2)
203 return (PAPI_DEVICE_ERROR);
204 }
205 break;
206 case PAPI_BOOLEAN: {
207 int8_t v = (int8_t)value->boolean;
208
209 length = (uint16_t)htons(1);
210 if (iwrite(fd, &length, 2) != 2)
211 return (PAPI_DEVICE_ERROR);
212 if (iwrite(fd, &v, 1) != 1)
213 return (PAPI_DEVICE_ERROR);
214 }
215 break;
216 case PAPI_INTEGER: {
217 int32_t v = (int32_t)value->integer;
218
219 length = (uint16_t)htons(4);
220 v = (int32_t)htonl(v);
221 if (iwrite(fd, &length, 2) != 2)
222 return (PAPI_DEVICE_ERROR);
223 if (iwrite(fd, &v, 4) != 4)
224 return (PAPI_DEVICE_ERROR);
225 }
226 break;
227 case PAPI_RANGE: {
228 int32_t min = (int32_t)htonl((int)(value->range).lower),
229 max = (int32_t)htonl((int)(value->range).upper);
230
231 length = (uint16_t)htons(8);
232 if (iwrite(fd, &length, 2) != 2)
233 return (PAPI_DEVICE_ERROR);
234 if (iwrite(fd, &min, 4) != 4)
235 return (PAPI_DEVICE_ERROR);
236 if (iwrite(fd, &max, 4) != 4)
237 return (PAPI_DEVICE_ERROR);
238 }
239 break;
240 case PAPI_RESOLUTION: {
241 int32_t x = (int)(value->resolution).xres,
242 y = (int)(value->resolution).yres;
243 int8_t units = (int8_t)(value->resolution).units;
244
245 length = (uint16_t)htons(9);
246 x = (int32_t)htonl(x);
247 y = (int32_t)htonl(y);
248
249 if (iwrite(fd, &length, 2) != 2)
250 return (PAPI_DEVICE_ERROR);
251 if (iwrite(fd, &x, 4) != 4)
252 return (PAPI_DEVICE_ERROR);
253 if (iwrite(fd, &y, 4) != 4)
254 return (PAPI_DEVICE_ERROR);
255 if (iwrite(fd, &units, 1) != 1)
256 return (PAPI_DEVICE_ERROR);
257 }
258 break;
259 case PAPI_DATETIME: {
260 struct tm *v = gmtime(&value->datetime);
261 int8_t c;
262 uint16_t s;
263
264 length = (uint16_t)htons(11);
265 if (iwrite(fd, &length, 2) != 2)
266 return (PAPI_DEVICE_ERROR);
267 s = (uint16_t)htons(v->tm_year + 1900);
268 if (iwrite(fd, &s, 2) != 2)
269 return (PAPI_DEVICE_ERROR);
270 c = v->tm_mon + 1;
271 if (iwrite(fd, &c, 1) != 1)
272 return (PAPI_DEVICE_ERROR);
273 c = v->tm_mday;
274 if (iwrite(fd, &c, 1) != 1)
275 return (PAPI_DEVICE_ERROR);
276 c = v->tm_hour;
277 if (iwrite(fd, &c, 1) != 1)
278 return (PAPI_DEVICE_ERROR);
279 c = v->tm_min;
280 if (iwrite(fd, &c, 1) != 1)
281 return (PAPI_DEVICE_ERROR);
282 c = v->tm_sec;
283 if (iwrite(fd, &c, 1) != 1)
284 return (PAPI_DEVICE_ERROR);
285 c = /* v->deciseconds */ 0;
286 if (iwrite(fd, &c, 1) != 1)
287 return (PAPI_DEVICE_ERROR);
288 c = /* v->utc_dir */ 0;
289 if (iwrite(fd, &c, 1) != 1)
290 return (PAPI_DEVICE_ERROR);
291 c = /* v->utc_hours */ 0;
292 if (iwrite(fd, &c, 1) != 1)
293 return (PAPI_DEVICE_ERROR);
294 c = /* v->utc_minutes */ 0;
295 if (iwrite(fd, &c, 1) != 1)
296 return (PAPI_DEVICE_ERROR);
297 }
298 break;
299 default: {
300 /*
301 * If there is a value, it is not one of our
302 * types, so we couldn't use it anyway. We assume
303 * that it was an OOB type with no value
304 */
305 length = (uint16_t)htons(0);
306 if (iwrite(fd, &length, 2) != 2)
307 return (PAPI_DEVICE_ERROR);
308 }
309 break;
310 }
311 }
312
313 return (PAPI_OK);
314 }
315
316 static papi_status_t
ipp_write_attribute_group(ipp_writer_t iwrite,void * fd,int8_t type,papi_attribute_t ** attributes)317 ipp_write_attribute_group(ipp_writer_t iwrite, void *fd, int8_t type,
318 papi_attribute_t **attributes)
319 {
320 papi_status_t result = PAPI_OK;
321 int i;
322
323 /* write group tag */
324 if (iwrite(fd, &type, 1) != 1)
325 return (PAPI_DEVICE_ERROR);
326
327 /* write values */
328 for (i = 0; ((attributes[i] != NULL) && (result == PAPI_OK)); i++)
329 result = ipp_write_attribute(iwrite, fd, attributes[i]);
330
331 return (result);
332 }
333
334 static papi_status_t
ipp_write_attribute_groups(ipp_writer_t iwrite,void * fd,papi_attribute_t ** groups)335 ipp_write_attribute_groups(ipp_writer_t iwrite, void *fd,
336 papi_attribute_t **groups)
337 {
338 papi_status_t result = PAPI_OK;
339 int8_t c;
340
341 for (c = DTAG_MIN; c <= DTAG_MAX; c++) {
342 papi_status_t status;
343 papi_attribute_t **group = NULL;
344 void *iter = NULL;
345 char name[32];
346
347 (void) ipp_tag_string(c, name, sizeof (name));
348 for (status = papiAttributeListGetCollection(groups, &iter,
349 name, &group);
350 ((status == PAPI_OK) && (result == PAPI_OK));
351 status = papiAttributeListGetCollection(groups, &iter,
352 NULL, &group))
353 result = ipp_write_attribute_group(iwrite, fd,
354 c, group);
355 }
356
357 c = DTAG_END_OF_ATTRIBUTES;
358 if (iwrite(fd, &c, 1) != 1)
359 result = PAPI_DEVICE_ERROR;
360
361 return (result);
362 }
363
364 static papi_status_t
ipp_write_message_header(ipp_writer_t iwrite,void * fd,papi_attribute_t ** message)365 ipp_write_message_header(ipp_writer_t iwrite, void *fd,
366 papi_attribute_t **message)
367 {
368 int tmp;
369 int8_t c;
370 uint16_t s;
371 int32_t i;
372
373 /* write the version */
374 papiAttributeListGetInteger(message, NULL, "version-major", &tmp);
375 c = tmp;
376 if (iwrite(fd, &c, 1) != 1)
377 return (PAPI_DEVICE_ERROR);
378
379 papiAttributeListGetInteger(message, NULL, "version-minor", &tmp);
380 c = tmp;
381 if (iwrite(fd, &c, 1) != 1)
382 return (PAPI_DEVICE_ERROR);
383
384 /* write the request/status code */
385 papiAttributeListGetInteger(message, NULL, "status-code", &tmp);
386 papiAttributeListGetInteger(message, NULL, "operation-id", &tmp);
387 s = (uint16_t)htons(tmp);
388 if (iwrite(fd, &s, 2) != 2)
389 return (PAPI_DEVICE_ERROR);
390
391 /* write the request id */
392 papiAttributeListGetInteger(message, NULL, "request-id", &tmp);
393 i = (uint32_t)htonl(tmp);
394 if (iwrite(fd, &i, 4) != 4)
395 return (PAPI_DEVICE_ERROR);
396
397 return (PAPI_OK);
398 }
399
400 papi_status_t
ipp_write_message(ipp_writer_t iwrite,void * fd,papi_attribute_t ** message)401 ipp_write_message(ipp_writer_t iwrite, void *fd, papi_attribute_t **message)
402 {
403 papi_status_t result;
404
405 if ((iwrite == NULL) || (fd == NULL) || (message == NULL))
406 return (PAPI_BAD_ARGUMENT);
407
408 result = ipp_write_message_header(iwrite, fd, message);
409 if (result == PAPI_OK)
410 result = ipp_write_attribute_groups(iwrite, fd, message);
411
412 return (result);
413 }
414