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 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 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 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 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 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 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 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