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