]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/network.c
Merge changes from CUPS trunk, r7566.
[thirdparty/cups.git] / backend / network.c
1 /*
2 * "$Id$"
3 *
4 * Common network APIs for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 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 * backendResolveURI() - Get the device URI, resolving as needed.
22 * resolve_callback() - Build a device URI for the given service name.
23 */
24
25 /*
26 * Include necessary headers.
27 */
28
29 #include "backend-private.h"
30 #include <limits.h>
31 #ifdef __hpux
32 # include <sys/time.h>
33 #else
34 # include <sys/select.h>
35 #endif /* __hpux */
36 #ifdef HAVE_DNSSD
37 # include <dns_sd.h>
38 #endif /* HAVE_DNSSD */
39
40
41 /*
42 * Local functions...
43 */
44
45 #ifdef HAVE_DNSSD
46 static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
47 uint32_t interfaceIndex,
48 DNSServiceErrorType errorCode,
49 const char *fullName, const char *hostTarget,
50 uint16_t port, uint16_t txtLen,
51 const unsigned char *txtRecord, void *context);
52 #endif /* HAVE_DNSSD */
53
54
55 /*
56 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
57 */
58
59
60 void
61 backendCheckSideChannel(
62 int snmp_fd, /* I - SNMP socket */
63 http_addr_t *addr) /* I - Address of device */
64 {
65 fd_set input; /* Select input set */
66 struct timeval timeout; /* Select timeout */
67
68
69 FD_ZERO(&input);
70 FD_SET(CUPS_SC_FD, &input);
71
72 timeout.tv_sec = timeout.tv_usec = 0;
73
74 if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0)
75 backendNetworkSideCB(-1, -1, snmp_fd, addr, 0);
76 }
77
78
79 /*
80 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
81 */
82
83 void
84 backendNetworkSideCB(
85 int print_fd, /* I - Print file or -1 */
86 int device_fd, /* I - Device file or -1 */
87 int snmp_fd, /* I - SNMP socket */
88 http_addr_t *addr, /* I - Address of device */
89 int use_bc) /* I - Use back-channel data? */
90 {
91 cups_sc_command_t command; /* Request command */
92 cups_sc_status_t status; /* Request/response status */
93 char data[2048]; /* Request/response data */
94 int datalen; /* Request/response data size */
95 const char *device_id; /* 1284DEVICEID env var */
96
97
98 datalen = sizeof(data);
99
100 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
101 {
102 _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
103 return;
104 }
105
106 switch (command)
107 {
108 case CUPS_SC_CMD_DRAIN_OUTPUT :
109 /*
110 * Our sockets disable the Nagle algorithm and data is sent immediately.
111 */
112
113 if (device_fd < 0)
114 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
115 else if (backendDrainOutput(print_fd, device_fd))
116 status = CUPS_SC_STATUS_IO_ERROR;
117 else
118 status = CUPS_SC_STATUS_OK;
119
120 datalen = 0;
121 break;
122
123 case CUPS_SC_CMD_GET_BIDI :
124 data[0] = use_bc;
125 datalen = 1;
126 break;
127
128 case CUPS_SC_CMD_GET_DEVICE_ID :
129 if (snmp_fd >= 0)
130 {
131 cups_snmp_t packet; /* Packet from printer */
132 static const int ppmPrinterIEEE1284DeviceId[] =
133 { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
134
135 if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(),
136 CUPS_ASN1_GET_REQUEST, 1,
137 ppmPrinterIEEE1284DeviceId))
138 {
139 if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
140 packet.object_type == CUPS_ASN1_OCTET_STRING)
141 {
142 strlcpy(data, packet.object_value.string, sizeof(data));
143 datalen = (int)strlen(data);
144 break;
145 }
146 }
147 }
148
149 if ((device_id = getenv("1284DEVICEID")) != NULL)
150 {
151 strlcpy(data, device_id, sizeof(data));
152 datalen = (int)strlen(data);
153 break;
154 }
155
156 default :
157 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
158 datalen = 0;
159 break;
160 }
161
162 cupsSideChannelWrite(command, status, data, datalen, 1.0);
163 }
164
165
166 /*
167 * 'backendResolveURI()' - Get the device URI, resolving as needed.
168 */
169
170 const char * /* O - Device URI */
171 backendResolveURI(char **argv) /* I - Command-line arguments */
172 {
173 const char *uri; /* Device URI */
174 char scheme[32], /* URI components... */
175 userpass[256],
176 hostname[1024],
177 resource[1024];
178 int port;
179 http_uri_status_t status; /* URI decode status */
180
181 /*
182 * Get the device URI...
183 */
184
185 uri = cupsBackendDeviceURI(argv);
186
187 if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
188 sizeof(scheme), userpass, sizeof(userpass),
189 hostname, sizeof(hostname), &port,
190 resource, sizeof(resource))) < HTTP_URI_OK)
191 {
192 fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status);
193 exit (CUPS_BACKEND_STOP);
194 }
195
196 /*
197 * Resolve it as needed...
198 */
199
200 if (strstr(hostname, "._tcp"))
201 {
202 #ifdef HAVE_DNSSD
203 DNSServiceRef ref; /* DNS-SD service reference */
204 char *regtype, /* Pointer to type in hostname */
205 *domain; /* Pointer to domain in hostname */
206 static char resolved_uri[HTTP_MAX_URI];
207 /* Resolved device URI */
208
209 /*
210 * Separate the hostname into service name, registration type, and domain...
211 */
212
213 regtype = strchr(hostname, '.');
214 *regtype++ = '\0';
215
216 domain = regtype + strlen(regtype) - 1;
217 if (domain > regtype && *domain == '.')
218 *domain = '\0';
219
220 for (domain = strchr(regtype, '.');
221 domain;
222 domain = strchr(domain + 1, '.'))
223 if (domain[1] != '_')
224 break;
225
226 if (domain)
227 *domain++ = '\0';
228
229 fprintf(stderr,
230 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
231 hostname, regtype, domain ? domain : "(null)");
232
233 if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain,
234 resolve_callback,
235 resolved_uri) == kDNSServiceErr_NoError)
236 {
237 if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError)
238 uri = NULL;
239 else
240 uri = resolved_uri;
241
242 DNSServiceRefDeallocate(ref);
243 }
244 else
245 #endif /* HAVE_DNSSD */
246
247 uri = NULL;
248
249 if (!uri)
250 {
251 fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri);
252 exit(CUPS_BACKEND_STOP);
253 }
254 }
255
256 return (uri);
257 }
258
259
260 #ifdef HAVE_DNSSD
261 /*
262 * 'resolve_callback()' - Build a device URI for the given service name.
263 */
264
265 static void
266 resolve_callback(
267 DNSServiceRef sdRef, /* I - Service reference */
268 DNSServiceFlags flags, /* I - Results flags */
269 uint32_t interfaceIndex, /* I - Interface number */
270 DNSServiceErrorType errorCode, /* I - Error, if any */
271 const char *fullName, /* I - Full service name */
272 const char *hostTarget, /* I - Hostname */
273 uint16_t port, /* I - Port number */
274 uint16_t txtLen, /* I - Length of TXT record */
275 const unsigned char *txtRecord, /* I - TXT record data */
276 void *context) /* I - Pointer to URI buffer */
277 {
278 const char *scheme; /* URI scheme */
279 char rp[257]; /* Remote printer */
280 const void *value; /* Value from TXT record */
281 uint8_t valueLen; /* Length of value */
282
283
284 fprintf(stderr,
285 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
286 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
287 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
288 interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
289 txtRecord, context);
290
291 /*
292 * Figure out the scheme from the full name...
293 */
294
295 if (strstr(fullName, "._ipp"))
296 scheme = "ipp";
297 else if (strstr(fullName, "._printer."))
298 scheme = "lpd";
299 else if (strstr(fullName, "._pdl-datastream."))
300 scheme = "socket";
301 else
302 scheme = "riousbprint";
303
304 /*
305 * Extract the "remote printer" key from the TXT record...
306 */
307
308 if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
309 &valueLen)) != NULL)
310 {
311 /*
312 * Convert to resource by concatenating with a leading "/"...
313 */
314
315 rp[0] = '/';
316 memcpy(rp + 1, value, valueLen);
317 rp[valueLen + 1] = '\0';
318 }
319 else
320 rp[0] = '\0';
321
322 /*
323 * Assemble the final device URI...
324 */
325
326 httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme,
327 NULL, hostTarget, ntohs(port), rp);
328
329 fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context);
330 }
331 #endif /* HAVE_DNSSD */
332
333
334 /*
335 * End of "$Id$".
336 */