]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/network.c
Merge fixes from CUPS 1.4svn-r7555.
[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(resource, "._tcp") || strstr(hostname, "._tcp"))
201 {
202 #ifdef HAVE_DNSSD
203 DNSServiceRef ref; /* DNS-SD service reference */
204 char *full_name, /* Full (service) name */
205 *regtype, /* Pointer to type in hostname */
206 *domain; /* Pointer to domain in hostname */
207 static char resolved_uri[HTTP_MAX_URI];
208 /* Resolved device URI */
209
210 /*
211 * Separate the hostname into service name, registration type, and domain...
212 */
213
214 if (strstr(resource, "._tcp"))
215 full_name = resource + 1;
216 else
217 full_name = hostname;
218
219 regtype = strchr(full_name, '.');
220 *regtype++ = '\0';
221
222 domain = regtype + strlen(regtype) - 1;
223 if (domain > regtype && *domain == '.')
224 *domain = '\0';
225
226 for (domain = strchr(regtype, '.');
227 domain;
228 domain = strchr(domain + 1, '.'))
229 if (domain[1] != '_')
230 break;
231
232 if (domain)
233 *domain++ = '\0';
234
235 fprintf(stderr,
236 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
237 full_name, regtype, domain ? domain : "(null)");
238
239 if (DNSServiceResolve(&ref, 0, 0, full_name, regtype, domain,
240 resolve_callback,
241 resolved_uri) == kDNSServiceErr_NoError)
242 {
243 if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError)
244 uri = NULL;
245 else
246 uri = resolved_uri;
247
248 DNSServiceRefDeallocate(ref);
249 }
250 else
251 #endif /* HAVE_DNSSD */
252
253 uri = NULL;
254
255 if (!uri)
256 {
257 fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri);
258 exit(CUPS_BACKEND_STOP);
259 }
260 }
261
262 return (uri);
263 }
264
265
266 #ifdef HAVE_DNSSD
267 /*
268 * 'resolve_callback()' - Build a device URI for the given service name.
269 */
270
271 static void
272 resolve_callback(
273 DNSServiceRef sdRef, /* I - Service reference */
274 DNSServiceFlags flags, /* I - Results flags */
275 uint32_t interfaceIndex, /* I - Interface number */
276 DNSServiceErrorType errorCode, /* I - Error, if any */
277 const char *fullName, /* I - Full service name */
278 const char *hostTarget, /* I - Hostname */
279 uint16_t port, /* I - Port number */
280 uint16_t txtLen, /* I - Length of TXT record */
281 const unsigned char *txtRecord, /* I - TXT record data */
282 void *context) /* I - Pointer to URI buffer */
283 {
284 const char *scheme; /* URI scheme */
285 char rp[257]; /* Remote printer */
286 const void *value; /* Value from TXT record */
287 uint8_t valueLen; /* Length of value */
288
289
290 fprintf(stderr,
291 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
292 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
293 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
294 interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
295 txtRecord, context);
296
297 /*
298 * Figure out the scheme from the full name...
299 */
300
301 if (strstr(fullName, "._ipp"))
302 scheme = "ipp";
303 else if (strstr(fullName, "._printer."))
304 scheme = "lpd";
305 else if (strstr(fullName, "._pdl-datastream."))
306 scheme = "socket";
307 else
308 scheme = "riousbprint";
309
310 /*
311 * Extract the "remote printer" key from the TXT record...
312 */
313
314 if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
315 &valueLen)) != NULL)
316 {
317 /*
318 * Convert to resource by concatenating with a leading "/"...
319 */
320
321 rp[0] = '/';
322 memcpy(rp + 1, value, valueLen);
323 rp[valueLen + 1] = '\0';
324 }
325 else
326 rp[0] = '\0';
327
328 /*
329 * Assemble the final device URI...
330 */
331
332 httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme,
333 NULL, hostTarget, ntohs(port), rp);
334
335 fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context);
336 }
337 #endif /* HAVE_DNSSD */
338
339
340 /*
341 * End of "$Id$".
342 */