• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Common backend network APIs for CUPS.
3  *
4  * Copyright © 2007-2016 by Apple Inc.
5  * Copyright © 2006-2007 by Easy Software Products, all rights reserved.
6  *
7  * Licensed under Apache License v2.0.  See the file "LICENSE" for more
8  * information.
9  */
10 
11 /*
12  * Include necessary headers.
13  */
14 
15 #include "backend-private.h"
16 #include <limits.h>
17 #include <sys/select.h>
18 
19 
20 /*
21  * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
22  */
23 
24 void
backendCheckSideChannel(int snmp_fd,http_addr_t * addr)25 backendCheckSideChannel(
26     int         snmp_fd,		/* I - SNMP socket */
27     http_addr_t *addr)			/* I - Address of device */
28 {
29   fd_set	input;			/* Select input set */
30   struct timeval timeout;		/* Select timeout */
31 
32 
33   FD_ZERO(&input);
34   FD_SET(CUPS_SC_FD, &input);
35 
36   timeout.tv_sec = timeout.tv_usec = 0;
37 
38   if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0)
39     backendNetworkSideCB(-1, -1, snmp_fd, addr, 0);
40 }
41 
42 
43 /*
44  * 'backendLookup()' - Lookup the given host and log addresses.
45  */
46 
47 http_addrlist_t	*			/* O - List of addresses or NULL */
backendLookup(const char * hostname,int port,int * cancel)48 backendLookup(const char *hostname,	/* I - Hostname */
49               int        port,		/* I - Port number */
50 	      int        *cancel)	/* I - Variable to watch for job cancel */
51 {
52   char			portname[32],	/* Port number as string */
53 			addrname[256];	/* Address as string */
54   http_addrlist_t	*addrlist,	/* List of addresses */
55 			*current;	/* Current address */
56 
57 
58  /*
59   * Lookup the address for the named host...
60   */
61 
62   snprintf(portname, sizeof(portname), "%d", port);
63 
64   fputs("STATE: +connecting-to-device\n", stderr);
65   fprintf(stderr, "DEBUG: Looking up \"%s\"...\n", hostname);
66 
67   while ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
68   {
69     _cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer \"%s\"."), hostname);
70     sleep(10);
71 
72     if (getenv("CLASS") != NULL)
73     {
74       fputs("STATE: -connecting-to-device\n", stderr);
75       exit(CUPS_BACKEND_STOP);
76     }
77 
78     if (cancel && *cancel)
79     {
80       fputs("STATE: -connecting-to-device\n", stderr);
81       exit(CUPS_BACKEND_OK);
82     }
83   }
84 
85   fputs("STATE: -connecting-to-device\n", stderr);
86 
87  /*
88   * Log the addresses we got...
89   */
90 
91   for (current = addrlist; current; current = current->next)
92     fprintf(stderr, "DEBUG: %s=%s\n", hostname, httpAddrString(&current->addr, addrname, sizeof(addrname)));
93 
94  /*
95   * Return...
96   */
97 
98   return (addrlist);
99 }
100 
101 
102 /*
103  * 'backendNetworkSideCB()' - Handle common network side-channel commands.
104  */
105 
106 int					/* O - -1 on error, 0 on success */
backendNetworkSideCB(int print_fd,int device_fd,int snmp_fd,http_addr_t * addr,int use_bc)107 backendNetworkSideCB(
108     int         print_fd,		/* I - Print file or -1 */
109     int         device_fd,		/* I - Device file or -1 */
110     int         snmp_fd,		/* I - SNMP socket */
111     http_addr_t *addr,			/* I - Address of device */
112     int         use_bc)			/* I - Use back-channel data? */
113 {
114   cups_sc_command_t	command;	/* Request command */
115   cups_sc_status_t	status;		/* Request/response status */
116   char			data[65536];	/* Request/response data */
117   int			datalen;	/* Request/response data size */
118   const char		*device_id;	/* 1284DEVICEID env var */
119 
120 
121   datalen = sizeof(data);
122 
123   if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
124     return (-1);
125 
126   switch (command)
127   {
128     case CUPS_SC_CMD_DRAIN_OUTPUT :
129        /*
130         * Our sockets disable the Nagle algorithm and data is sent immediately.
131 	*/
132 
133         if (device_fd < 0)
134 	  status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
135 	else if (backendDrainOutput(print_fd, device_fd))
136 	  status = CUPS_SC_STATUS_IO_ERROR;
137 	else
138           status = CUPS_SC_STATUS_OK;
139 
140 	datalen = 0;
141         break;
142 
143     case CUPS_SC_CMD_GET_BIDI :
144 	status  = CUPS_SC_STATUS_OK;
145         data[0] = (char)use_bc;
146         datalen = 1;
147         break;
148 
149     case CUPS_SC_CMD_SNMP_GET :
150     case CUPS_SC_CMD_SNMP_GET_NEXT :
151         fprintf(stderr, "DEBUG: CUPS_SC_CMD_SNMP_%s: %d (%s)\n",
152 	        command == CUPS_SC_CMD_SNMP_GET ? "GET" : "GET_NEXT", datalen,
153 		data);
154 
155         if (datalen < 2)
156 	{
157 	  status  = CUPS_SC_STATUS_BAD_MESSAGE;
158 	  datalen = 0;
159 	  break;
160 	}
161 
162         if (snmp_fd >= 0)
163 	{
164 	  char		*dataptr;	/* Pointer into data */
165 	  cups_snmp_t	packet;		/* Packet from printer */
166           const char	*snmp_value;	/* CUPS_SNMP_VALUE env var */
167 
168           if ((snmp_value = getenv("CUPS_SNMP_VALUE")) != NULL)
169           {
170             const char	*snmp_count;	/* CUPS_SNMP_COUNT env var */
171             int		count;		/* Repetition count */
172 
173             if ((snmp_count = getenv("CUPS_SNMP_COUNT")) != NULL)
174             {
175               if ((count = atoi(snmp_count)) <= 0)
176                 count = 1;
177             }
178             else
179               count = 1;
180 
181 	    for (dataptr = data + strlen(data) + 1;
182 	         count > 0 && dataptr < (data + sizeof(data) - 1);
183 	         count --, dataptr += strlen(dataptr))
184 	      strlcpy(dataptr, snmp_value, sizeof(data) - (size_t)(dataptr - data));
185 
186 	    fprintf(stderr, "DEBUG: Returning %s %s\n", data,
187 	            data + strlen(data) + 1);
188 
189 	    status  = CUPS_SC_STATUS_OK;
190 	    datalen = (int)(dataptr - data);
191 	    break;
192           }
193 
194           if (!_cupsSNMPStringToOID(data, packet.object_name, CUPS_SNMP_MAX_OID))
195 	  {
196 	    status  = CUPS_SC_STATUS_BAD_MESSAGE;
197 	    datalen = 0;
198 	    break;
199 	  }
200 
201           status  = CUPS_SC_STATUS_IO_ERROR;
202 	  datalen = 0;
203 
204           if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
205 	                     _cupsSNMPDefaultCommunity(),
206 	                     command == CUPS_SC_CMD_SNMP_GET ?
207 			         CUPS_ASN1_GET_REQUEST :
208 				 CUPS_ASN1_GET_NEXT_REQUEST, 1,
209 			     packet.object_name))
210           {
211 	    if (_cupsSNMPRead(snmp_fd, &packet, 1.0))
212 	    {
213 	      size_t	i;		/* Looping var */
214 
215 
216               if (!_cupsSNMPOIDToString(packet.object_name, data, sizeof(data)))
217 	      {
218 	        fputs("DEBUG: Bad OID returned!\n", stderr);
219 	        break;
220 	      }
221 
222 	      datalen = (int)strlen(data) + 1;
223               dataptr = data + datalen;
224 
225 	      switch (packet.object_type)
226 	      {
227 	        case CUPS_ASN1_BOOLEAN :
228 		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d", packet.object_value.boolean);
229 	            datalen += (int)strlen(dataptr);
230 		    break;
231 
232 	        case CUPS_ASN1_INTEGER :
233 		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%d",
234 		             packet.object_value.integer);
235 	            datalen += (int)strlen(dataptr);
236 		    break;
237 
238 	        case CUPS_ASN1_BIT_STRING :
239 	        case CUPS_ASN1_OCTET_STRING :
240 		    if (packet.object_value.string.num_bytes < (sizeof(data) - (size_t)(dataptr - data)))
241 		      i = packet.object_value.string.num_bytes;
242 		    else
243 		      i = sizeof(data) - (size_t)(dataptr - data);
244 
245 		    memcpy(dataptr, packet.object_value.string.bytes, i);
246 
247                     datalen += (int)i;
248 		    break;
249 
250 	        case CUPS_ASN1_OID :
251 		    _cupsSNMPOIDToString(packet.object_value.oid, dataptr,
252 		                         sizeof(data) - (size_t)(dataptr - data));
253 	            datalen += (int)strlen(dataptr);
254 		    break;
255 
256                 case CUPS_ASN1_HEX_STRING :
257 		    for (i = 0;
258 		         i < packet.object_value.string.num_bytes &&
259 			     dataptr < (data + sizeof(data) - 3);
260 			 i ++, dataptr += 2)
261 		      sprintf(dataptr, "%02X", packet.object_value.string.bytes[i]);
262 	            datalen += (int)strlen(dataptr);
263 		    break;
264 
265                 case CUPS_ASN1_COUNTER :
266 		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.counter);
267 	            datalen += (int)strlen(dataptr);
268 		    break;
269 
270                 case CUPS_ASN1_GAUGE :
271 		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.gauge);
272 	            datalen += (int)strlen(dataptr);
273 		    break;
274 
275                 case CUPS_ASN1_TIMETICKS :
276 		    snprintf(dataptr, sizeof(data) - (size_t)(dataptr - data), "%u", packet.object_value.timeticks);
277 	            datalen += (int)strlen(dataptr);
278 		    break;
279 
280                 default :
281 	            fprintf(stderr, "DEBUG: Unknown OID value type %02X.\n", packet.object_type);
282 
283 		case CUPS_ASN1_NULL_VALUE :
284 		    dataptr[0] = '\0';
285 		    break;
286               }
287 
288 	      fprintf(stderr, "DEBUG: Returning %s %s\n", data, data + datalen);
289 
290 	      status = CUPS_SC_STATUS_OK;
291 	    }
292 	    else
293 	      fputs("DEBUG: SNMP read error...\n", stderr);
294 	  }
295 	  else
296 	    fputs("DEBUG: SNMP write error...\n", stderr);
297 	  break;
298         }
299 
300         status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
301 	datalen = 0;
302 	break;
303 
304     case CUPS_SC_CMD_GET_CONNECTED :
305 	status  = CUPS_SC_STATUS_OK;
306         data[0] = device_fd != -1;
307         datalen = 1;
308         break;
309 
310     case CUPS_SC_CMD_GET_DEVICE_ID :
311         if (snmp_fd >= 0)
312 	{
313 	  cups_snmp_t	packet;		/* Packet from printer */
314 	  static const int ppmPrinterIEEE1284DeviceId[] =
315 	  		{ CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
316 
317 
318           status  = CUPS_SC_STATUS_IO_ERROR;
319 	  datalen = 0;
320 
321           if (_cupsSNMPWrite(snmp_fd, addr, CUPS_SNMP_VERSION_1,
322 	                     _cupsSNMPDefaultCommunity(),
323 	                     CUPS_ASN1_GET_REQUEST, 1,
324 			     ppmPrinterIEEE1284DeviceId))
325           {
326 	    if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
327 	        packet.object_type == CUPS_ASN1_OCTET_STRING)
328 	    {
329 	      strlcpy(data, (char *)packet.object_value.string.bytes,
330 	              sizeof(data));
331 	      datalen = (int)strlen(data);
332 	      status  = CUPS_SC_STATUS_OK;
333 	    }
334 	  }
335 
336 	  break;
337         }
338 
339 	if ((device_id = getenv("1284DEVICEID")) != NULL)
340 	{
341 	  strlcpy(data, device_id, sizeof(data));
342 	  datalen = (int)strlen(data);
343 	  status  = CUPS_SC_STATUS_OK;
344 	  break;
345 	}
346 
347     default :
348         status  = CUPS_SC_STATUS_NOT_IMPLEMENTED;
349 	datalen = 0;
350 	break;
351   }
352 
353   return (cupsSideChannelWrite(command, status, data, datalen, 1.0));
354 }
355