1/* 2 * "$Id: network.c 12131 2014-08-28 23:38:16Z msweet $" 3 * 4 * Common backend network APIs for CUPS. 5 * 6 * Copyright 2007-2014 by Apple Inc. 7 * Copyright 2006-2007 by Easy Software Products, all rights reserved. 8 * 9 * These coded instructions, statements, and computer programs are the 10 * property of Apple Inc. and are protected by Federal copyright 11 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 12 * "LICENSE" which should have been included with this file. If this 13 * file is missing or damaged, see the license at "http://www.cups.org/". 14 * 15 * This file is subject to the Apple OS-Developed Software exception. 16 */ 17 18/* 19 * Include necessary headers. 20 */ 21 22#include "backend-private.h" 23#include <limits.h> 24#include <sys/select.h> 25 26 27/* 28 * 'backendCheckSideChannel()' - Check the side-channel for pending requests. 29 */ 30 31 32void 33backendCheckSideChannel( 34 int snmp_fd, /* I - SNMP socket */ 35 http_addr_t *addr) /* I - Address of device */ 36{ 37 fd_set input; /* Select input set */ 38 struct timeval timeout; /* Select timeout */ 39 40 41 FD_ZERO(&input); 42 FD_SET(CUPS_SC_FD, &input); 43 44 timeout.tv_sec = timeout.tv_usec = 0; 45 46 if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0) 47 backendNetworkSideCB(-1, -1, snmp_fd, addr, 0); 48} 49 50 51/* 52 * 'backendNetworkSideCB()' - Handle common network side-channel commands. 53 */ 54 55int /* O - -1 on error, 0 on success */ 56backendNetworkSideCB( 57 int print_fd, /* I - Print file or -1 */ 58 int device_fd, /* I - Device file or -1 */ 59 int snmp_fd, /* I - SNMP socket */ 60 http_addr_t *addr, /* I - Address of device */ 61 int use_bc) /* I - Use back-channel data? */ 62{ 63 cups_sc_command_t command; /* Request command */ 64 cups_sc_status_t status; /* Request/response status */ 65 char data[65536]; /* Request/response data */ 66 int datalen; /* Request/response data size */ 67 const char *device_id; /* 1284DEVICEID env var */ 68 69 70 datalen = sizeof(data); 71 72 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0)) 73 return (-1); 74 75 switch (command) 76 { 77 case CUPS_SC_CMD_DRAIN_OUTPUT : 78 /* 79 * Our sockets disable the Nagle algorithm and data is sent immediately. 80 */ 81 82 if (device_fd < 0) 83 status = CUPS_SC_STATUS_NOT_IMPLEMENTED; 84 else if (backendDrainOutput(print_fd, device_fd)) 85 status = CUPS_SC_STATUS_IO_ERROR; 86 else 87 status = CUPS_SC_STATUS_OK; 88 89 datalen = 0; 90 break; 91 92 case CUPS_SC_CMD_GET_BIDI : 93 status = CUPS_SC_STATUS_OK; 94 data[0] = (char)use_bc; 95 datalen = 1; 96 break; 97 98 case CUPS_SC_CMD_SNMP_GET : 99 case CUPS_SC_CMD_SNMP_GET_NEXT : 100 fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n", 101 command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen, 102 data); 103 104 if (datalen < 2) 105 { 106 status = CUPS_SC_STATUS_BAD_MESSAGE; 107 datalen = 0; 108 break; 109 } 110 111 if (snmp_fd >= 0) 112 { 113 char *dataptr; /* Pointer into data */ 114 cups_snmp_t packet; /* Packet from printer */ 115 const char *snmp_value; /* CUPS_SNMP_VALUE env var */ 116 117 if ((snmp_value = getenv("CUPS_SNMP_VALUE")) != NULL) 118 { 119 const char *snmp_count; /* CUPS_SNMP_COUNT env var */ 120 int count; /* Repetition count */ 121 122 if ((snmp_count = getenv("CUPS_SNMP_COUNT")) != NULL) 123 { 124 if ((count = atoi(snmp_count)) <= 0) 125 count = 1; 126 } 127 else 128 count = 1; 129 130 for (dataptr = data + strlen(data) + 1; 131 count > 0 && dataptr < (data + sizeof(data) - 1); 132 count --, dataptr += strlen(dataptr)) 133 strlcpy(dataptr, snmp_value, sizeof(data) - (size_t)(dataptr - data)); 134 135 fprintf(stderr, "DEBUG: Returning %s %s\n", data, 136 data + strlen(data) + 1); 137 138 status = CUPS_SC_STATUS_OK; 139 datalen = (int)(dataptr - data); 140 break; 141 } 142 143 if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID)) 144 { 145 status = CUPS_SC_STATUS_BAD_MESSAGE; 146 datalen = 0; 147 break; 148 } 149 150 status = CUPS_SC_STATUS_IO_ERROR; 151 datalen = 0; 152 153 if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, 154 _cupsSNMPDefaultCommunity(), 155 command == CUPS_SC_CMD_SNMP_GET ? 156 CUPS_ASN1_GET_REQUEST : 157 CUPS_ASN1_GET_NEXT_REQUEST, 1, 158 packet.object_name)) 159 { 160 if (_cupsSNMPRead(snmp_fd, &packet, 1.0)) 161 { 162 size_t i; /* Looping var */ 163 164 165 if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data))) 166 { 167 fputs("DEBUG: Bad OID returned!\n", stderr); 168 break; 169 } 170 171 datalen = (int)strlen(data) + 1; 172 dataptr = data + datalen; 173 174 switch (packet.object_type) 175 { 176 case CUPS_ASN1_BOOLEAN : 177 snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", packet.object_value.boolean); 178 datalen += (int)strlen(dataptr); 179 break; 180 181 case CUPS_ASN1_INTEGER : 182 snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", 183 packet.object_value.integer); 184 datalen += (int)strlen(dataptr); 185 break; 186 187 case CUPS_ASN1_BIT_STRING : 188 case CUPS_ASN1_OCTET_STRING : 189 if (packet.object_value.string.num_bytes < (sizeof(data) - (size_t)(dataptr - data))) 190 i = packet.object_value.string.num_bytes; 191 else 192 i = sizeof(data) - (size_t)(dataptr - data); 193 194 memcpy(dataptr, packet.object_value.string.bytes, i); 195 196 datalen += (int)i; 197 break; 198 199 case CUPS_ASN1_OID : 200 _cupsSNMPOIDToString(packet.object_value.oid, dataptr, 201 sizeof(data) - (size_t)(dataptr - data)); 202 datalen += (int)strlen(dataptr); 203 break; 204 205 case CUPS_ASN1_HEX_STRING : 206 for (i = 0; 207 i < packet.object_value.string.num_bytes && 208 dataptr < (data + sizeof(data) - 3); 209 i ++, dataptr += 2) 210 sprintf(dataptr, "%02X", packet.object_value.string.bytes[i]); 211 datalen += (int)strlen(dataptr); 212 break; 213 214 case CUPS_ASN1_COUNTER : 215 snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.counter); 216 datalen += (int)strlen(dataptr); 217 break; 218 219 case CUPS_ASN1_GAUGE : 220 snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.gauge); 221 datalen += (int)strlen(dataptr); 222 break; 223 224 case CUPS_ASN1_TIMETICKS : 225 snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.timeticks); 226 datalen += (int)strlen(dataptr); 227 break; 228 229 default : 230 fprintf(stderr, "DEBUG: Unknown OID value type %02X.\n", packet.object_type); 231 232 case CUPS_ASN1_NULL_VALUE : 233 dataptr[0] = '\0'; 234 break; 235 } 236 237 fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen); 238 239 status = CUPS_SC_STATUS_OK; 240 } 241 else 242 fputs("DEBUG: SNMP read error...\n", stderr); 243 } 244 else 245 fputs("DEBUG: SNMP write error...\n", stderr); 246 break; 247 } 248 249 status = CUPS_SC_STATUS_NOT_IMPLEMENTED; 250 datalen = 0; 251 break; 252 253 case CUPS_SC_CMD_GET_CONNECTED : 254 status = CUPS_SC_STATUS_OK; 255 data[0] = device_fd != -1; 256 datalen = 1; 257 break; 258 259 case CUPS_SC_CMD_GET_DEVICE_ID : 260 if (snmp_fd >= 0) 261 { 262 cups_snmp_t packet; /* Packet from printer */ 263 static const int ppmPrinterIEEE1284DeviceId[] = 264 { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 }; 265 266 267 status = CUPS_SC_STATUS_IO_ERROR; 268 datalen = 0; 269 270 if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1, 271 _cupsSNMPDefaultCommunity(), 272 CUPS_ASN1_GET_REQUEST, 1, 273 ppmPrinterIEEE1284DeviceId)) 274 { 275 if (_cupsSNMPRead(snmp_fd, &packet, 1.0) && 276 packet.object_type == CUPS_ASN1_OCTET_STRING) 277 { 278 strlcpy(data, (char *)packet.object_value.string.bytes, 279 sizeof(data)); 280 datalen = (int)strlen(data); 281 status = CUPS_SC_STATUS_OK; 282 } 283 } 284 285 break; 286 } 287 288 if ((device_id = getenv("1284DEVICEID")) != NULL) 289 { 290 strlcpy(data, device_id, sizeof(data)); 291 datalen = (int)strlen(data); 292 status = CUPS_SC_STATUS_OK; 293 break; 294 } 295 296 default : 297 status = CUPS_SC_STATUS_NOT_IMPLEMENTED; 298 datalen = 0; 299 break; 300 } 301 302 return (cupsSideChannelWrite(command, status, data, datalen, 1.0)); 303} 304 305 306/* 307 * End of "$Id: network.c 12131 2014-08-28 23:38:16Z msweet $". 308 */ 309