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