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