]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/network.c
Merge CUPS 1.4svn-r7524.
[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 */
20
21 /*
22 * Include necessary headers.
23 */
24
25 #include "backend-private.h"
26 #include <limits.h>
27 #ifdef __hpux
28 # include <sys/time.h>
29 #else
30 # include <sys/select.h>
31 #endif /* __hpux */
32 #ifdef HAVE_DNSSD
33 # include <dns_sd.h>
34 #endif /* HAVE_DNSSD */
35
36
37 /*
38 * Local functions...
39 */
40
41 #ifdef HAVE_DNSSD
42 static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
43 uint32_t interfaceIndex,
44 DNSServiceErrorType errorCode,
45 const char *fullName, const char *hostTarget,
46 uint16_t port, uint16_t txtLen,
47 const unsigned char *txtRecord, void *context);
48 #endif /* HAVE_DNSSD */
49
50
51 /*
52 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
53 */
54
55
56 void
57 backendCheckSideChannel(
58 int snmp_fd, /* I - SNMP socket */
59 http_addr_t *addr) /* I - Address of device */
60 {
61 fd_set input; /* Select input set */
62 struct timeval timeout; /* Select timeout */
63
64
65 FD_ZERO(&input);
66 FD_SET(CUPS_SC_FD, &input);
67
68 timeout.tv_sec = timeout.tv_usec = 0;
69
70 if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0)
71 backendNetworkSideCB(-1, -1, snmp_fd, addr, 0);
72 }
73
74
75 /*
76 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
77 */
78
79 void
80 backendNetworkSideCB(
81 int print_fd, /* I - Print file or -1 */
82 int device_fd, /* I - Device file or -1 */
83 int snmp_fd, /* I - SNMP socket */
84 http_addr_t *addr, /* I - Address of device */
85 int use_bc) /* I - Use back-channel data? */
86 {
87 cups_sc_command_t command; /* Request command */
88 cups_sc_status_t status; /* Request/response status */
89 char data[2048]; /* Request/response data */
90 int datalen; /* Request/response data size */
91 const char *device_id; /* 1284DEVICEID env var */
92
93
94 datalen = sizeof(data);
95
96 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
97 {
98 _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
99 return;
100 }
101
102 switch (command)
103 {
104 case CUPS_SC_CMD_DRAIN_OUTPUT :
105 /*
106 * Our sockets disable the Nagle algorithm and data is sent immediately.
107 */
108
109 if (device_fd < 0)
110 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
111 else if (backendDrainOutput(print_fd, device_fd))
112 status = CUPS_SC_STATUS_IO_ERROR;
113 else
114 status = CUPS_SC_STATUS_OK;
115
116 datalen = 0;
117 break;
118
119 case CUPS_SC_CMD_GET_BIDI :
120 data[0] = use_bc;
121 datalen = 1;
122 break;
123
124 case CUPS_SC_CMD_GET_DEVICE_ID :
125 if (snmp_fd >= 0)
126 {
127 cups_snmp_t packet; /* Packet from printer */
128 static const int ppmPrinterIEEE1284DeviceId[] =
129 { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
130
131 if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(),
132 CUPS_ASN1_GET_REQUEST, 1,
133 ppmPrinterIEEE1284DeviceId))
134 {
135 if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
136 packet.object_type == CUPS_ASN1_OCTET_STRING)
137 {
138 strlcpy(data, packet.object_value.string, sizeof(data));
139 datalen = (int)strlen(data);
140 break;
141 }
142 }
143 }
144
145 if ((device_id = getenv("1284DEVICEID")) != NULL)
146 {
147 strlcpy(data, device_id, sizeof(data));
148 datalen = (int)strlen(data);
149 break;
150 }
151
152 default :
153 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
154 datalen = 0;
155 break;
156 }
157
158 cupsSideChannelWrite(command, status, data, datalen, 1.0);
159 }
160
161
162 /*
163 * 'backendResolveURI()' - Get the device URI, resolving as needed.
164 */
165
166 const char * /* O - Device URI */
167 backendResolveURI(char **argv) /* I - Command-line arguments */
168 {
169 const char *uri; /* Device URI */
170 char scheme[32], /* URI components... */
171 userpass[256],
172 hostname[1024],
173 resource[1024];
174 int port;
175 http_uri_status_t status; /* URI decode status */
176
177 /*
178 * Get the device URI...
179 */
180
181 uri = cupsBackendDeviceURI(argv);
182
183 if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
184 sizeof(scheme), userpass, sizeof(userpass),
185 hostname, sizeof(hostname), &port,
186 resource, sizeof(resource))) < HTTP_URI_OK)
187 {
188 fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status);
189 exit (CUPS_BACKEND_STOP);
190 }
191
192 /*
193 * Resolve it as needed...
194 */
195
196 if (strstr(hostname, "._tcp"))
197 {
198 #ifdef HAVE_DNSSD
199 DNSServiceRef ref; /* DNS-SD service reference */
200 char *regtype, /* Pointer to type in hostname */
201 *domain; /* Pointer to domain in hostname */
202 static char resolved_uri[HTTP_MAX_URI];
203 /* Resolved device URI */
204
205 /*
206 * Separate the hostname into service name, registration type, and domain...
207 */
208
209 regtype = strchr(hostname, '.');
210 *regtype++ = '\0';
211
212 domain = regtype + strlen(regtype) - 1;
213 if (domain > regtype && *domain == '.')
214 *domain = '\0';
215
216 for (domain = strchr(regtype, '.');
217 domain;
218 domain = strchr(domain + 1, '.'))
219 if (domain[1] != '_')
220 break;
221
222 if (domain)
223 *domain++ = '\0';
224
225 fprintf(stderr,
226 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
227 hostname, regtype, domain ? domain : "(null)");
228
229 if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain,
230 resolve_callback,
231 resolved_uri) == kDNSServiceErr_NoError)
232 {
233 if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError)
234 uri = NULL;
235 else
236 uri = resolved_uri;
237
238 DNSServiceRefDeallocate(ref);
239 }
240 else
241 #endif /* HAVE_DNSSD */
242
243 uri = NULL;
244
245 if (!uri)
246 {
247 fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri);
248 exit(CUPS_BACKEND_STOP);
249 }
250 }
251
252 return (uri);
253 }
254
255
256 #ifdef HAVE_DNSSD
257 /*
258 * 'resolve_callback()' - Build a device URI for the given service name.
259 */
260
261 static void
262 resolve_callback(
263 DNSServiceRef sdRef, /* I - Service reference */
264 DNSServiceFlags flags, /* I - Results flags */
265 uint32_t interfaceIndex, /* I - Interface number */
266 DNSServiceErrorType errorCode, /* I - Error, if any */
267 const char *fullName, /* I - Full service name */
268 const char *hostTarget, /* I - Hostname */
269 uint16_t port, /* I - Port number */
270 uint16_t txtLen, /* I - Length of TXT record */
271 const unsigned char *txtRecord, /* I - TXT record data */
272 void *context) /* I - Pointer to URI buffer */
273 {
274 const char *scheme; /* URI scheme */
275 char rp[257]; /* Remote printer */
276 const void *value; /* Value from TXT record */
277 uint8_t valueLen; /* Length of value */
278
279
280 fprintf(stderr,
281 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
282 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
283 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
284 interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
285 txtRecord, context);
286
287 /*
288 * Figure out the scheme from the full name...
289 */
290
291 if (strstr(fullName, "._ipp"))
292 scheme = "ipp";
293 else if (strstr(fullName, "._printer."))
294 scheme = "lpd";
295 else if (strstr(fullName, "._pdl-datastream."))
296 scheme = "socket";
297 else
298 scheme = "riousbprint";
299
300 /*
301 * Extract the "remote printer" key from the TXT record...
302 */
303
304 if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
305 &valueLen)) != NULL)
306 {
307 /*
308 * Convert to resource by concatenating with a leading "/"...
309 */
310
311 rp[0] = '/';
312 memcpy(rp, value, valueLen);
313 rp[valueLen + 1] = '\0';
314 }
315 else
316 rp[0] = '\0';
317
318 /*
319 * Assemble the final device URI...
320 */
321
322 httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme,
323 NULL, hostTarget, ntohs(port), rp);
324
325 fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context);
326 }
327 #endif /* HAVE_DNSSD */
328
329
330 /*
331 * End of "$Id$".
332 */
333 /*
334 * "$Id$"
335 *
336 * Common network APIs for the Common UNIX Printing System (CUPS).
337 *
338 * Copyright 2007-2008 by Apple Inc.
339 * Copyright 2006-2007 by Easy Software Products, all rights reserved.
340 *
341 * These coded instructions, statements, and computer programs are the
342 * property of Apple Inc. and are protected by Federal copyright
343 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
344 * "LICENSE" which should have been included with this file. If this
345 * file is missing or damaged, see the license at "http://www.cups.org/".
346 *
347 * This file is subject to the Apple OS-Developed Software exception.
348 *
349 * Contents:
350 *
351 */
352
353 /*
354 * Include necessary headers.
355 */
356
357 #include "backend-private.h"
358 #include <limits.h>
359 #ifdef __hpux
360 # include <sys/time.h>
361 #else
362 # include <sys/select.h>
363 #endif /* __hpux */
364 #ifdef HAVE_DNSSD
365 # include <dns_sd.h>
366 #endif /* HAVE_DNSSD */
367
368
369 /*
370 * Local functions...
371 */
372
373 #ifdef HAVE_DNSSD
374 static void resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
375 uint32_t interfaceIndex,
376 DNSServiceErrorType errorCode,
377 const char *fullName, const char *hostTarget,
378 uint16_t port, uint16_t txtLen,
379 const unsigned char *txtRecord, void *context);
380 #endif /* HAVE_DNSSD */
381
382
383 /*
384 * 'backendCheckSideChannel()' - Check the side-channel for pending requests.
385 */
386
387
388 void
389 backendCheckSideChannel(
390 int snmp_fd, /* I - SNMP socket */
391 http_addr_t *addr) /* I - Address of device */
392 {
393 fd_set input; /* Select input set */
394 struct timeval timeout; /* Select timeout */
395
396
397 FD_ZERO(&input);
398 FD_SET(CUPS_SC_FD, &input);
399
400 timeout.tv_sec = timeout.tv_usec = 0;
401
402 if (select(CUPS_SC_FD + 1, &input, NULL, NULL, &timeout) > 0)
403 backendNetworkSideCB(-1, -1, snmp_fd, addr, 0);
404 }
405
406
407 /*
408 * 'backendNetworkSideCB()' - Handle common network side-channel commands.
409 */
410
411 void
412 backendNetworkSideCB(
413 int print_fd, /* I - Print file or -1 */
414 int device_fd, /* I - Device file or -1 */
415 int snmp_fd, /* I - SNMP socket */
416 http_addr_t *addr, /* I - Address of device */
417 int use_bc) /* I - Use back-channel data? */
418 {
419 cups_sc_command_t command; /* Request command */
420 cups_sc_status_t status; /* Request/response status */
421 char data[2048]; /* Request/response data */
422 int datalen; /* Request/response data size */
423 const char *device_id; /* 1284DEVICEID env var */
424
425
426 datalen = sizeof(data);
427
428 if (cupsSideChannelRead(&command, &status, data, &datalen, 1.0))
429 {
430 _cupsLangPuts(stderr, _("WARNING: Failed to read side-channel request!\n"));
431 return;
432 }
433
434 switch (command)
435 {
436 case CUPS_SC_CMD_DRAIN_OUTPUT :
437 /*
438 * Our sockets disable the Nagle algorithm and data is sent immediately.
439 */
440
441 if (device_fd < 0)
442 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
443 else if (backendDrainOutput(print_fd, device_fd))
444 status = CUPS_SC_STATUS_IO_ERROR;
445 else
446 status = CUPS_SC_STATUS_OK;
447
448 datalen = 0;
449 break;
450
451 case CUPS_SC_CMD_GET_BIDI :
452 data[0] = use_bc;
453 datalen = 1;
454 break;
455
456 case CUPS_SC_CMD_GET_DEVICE_ID :
457 if (snmp_fd >= 0)
458 {
459 cups_snmp_t packet; /* Packet from printer */
460 static const int ppmPrinterIEEE1284DeviceId[] =
461 { CUPS_OID_ppmPrinterIEEE1284DeviceId,1,-1 };
462
463 if (_cupsSNMPWrite(snmp_fd, addr, 1, _cupsSNMPDefaultCommunity(),
464 CUPS_ASN1_GET_REQUEST, 1,
465 ppmPrinterIEEE1284DeviceId))
466 {
467 if (_cupsSNMPRead(snmp_fd, &packet, 1.0) &&
468 packet.object_type == CUPS_ASN1_OCTET_STRING)
469 {
470 strlcpy(data, packet.object_value.string, sizeof(data));
471 datalen = (int)strlen(data);
472 break;
473 }
474 }
475 }
476
477 if ((device_id = getenv("1284DEVICEID")) != NULL)
478 {
479 strlcpy(data, device_id, sizeof(data));
480 datalen = (int)strlen(data);
481 break;
482 }
483
484 default :
485 status = CUPS_SC_STATUS_NOT_IMPLEMENTED;
486 datalen = 0;
487 break;
488 }
489
490 cupsSideChannelWrite(command, status, data, datalen, 1.0);
491 }
492
493
494 /*
495 * 'backendResolveURI()' - Get the device URI, resolving as needed.
496 */
497
498 const char * /* O - Device URI */
499 backendResolveURI(char **argv) /* I - Command-line arguments */
500 {
501 const char *uri; /* Device URI */
502 char scheme[32], /* URI components... */
503 userpass[256],
504 hostname[1024],
505 resource[1024];
506 int port;
507 http_uri_status_t status; /* URI decode status */
508
509 /*
510 * Get the device URI...
511 */
512
513 uri = cupsBackendDeviceURI(argv);
514
515 if ((status = httpSeparateURI(HTTP_URI_CODING_ALL, uri, scheme,
516 sizeof(scheme), userpass, sizeof(userpass),
517 hostname, sizeof(hostname), &port,
518 resource, sizeof(resource))) < HTTP_URI_OK)
519 {
520 fprintf(stderr, "ERROR: Bad device URI \"%s\" (%d)!\n", uri, status);
521 exit (CUPS_BACKEND_STOP);
522 }
523
524 /*
525 * Resolve it as needed...
526 */
527
528 if (strstr(hostname, "._tcp"))
529 {
530 #ifdef HAVE_DNSSD
531 DNSServiceRef ref; /* DNS-SD service reference */
532 char *regtype, /* Pointer to type in hostname */
533 *domain; /* Pointer to domain in hostname */
534 static char resolved_uri[HTTP_MAX_URI];
535 /* Resolved device URI */
536
537 /*
538 * Separate the hostname into service name, registration type, and domain...
539 */
540
541 regtype = strchr(hostname, '.');
542 *regtype++ = '\0';
543
544 domain = regtype + strlen(regtype) - 1;
545 if (domain > regtype && *domain == '.')
546 *domain = '\0';
547
548 for (domain = strchr(regtype, '.');
549 domain;
550 domain = strchr(domain + 1, '.'))
551 if (domain[1] != '_')
552 break;
553
554 if (domain)
555 *domain++ = '\0';
556
557 fprintf(stderr,
558 "DEBUG: Resolving service \"%s\", regtype \"%s\", domain \"%s\"\n",
559 hostname, regtype, domain ? domain : "(null)");
560
561 if (DNSServiceResolve(&ref, 0, 0, hostname, regtype, domain,
562 resolve_callback,
563 resolved_uri) == kDNSServiceErr_NoError)
564 {
565 if (DNSServiceProcessResult(ref) != kDNSServiceErr_NoError)
566 uri = NULL;
567 else
568 uri = resolved_uri;
569
570 DNSServiceRefDeallocate(ref);
571 }
572 else
573 #endif /* HAVE_DNSSD */
574
575 uri = NULL;
576
577 if (!uri)
578 {
579 fprintf(stderr, "ERROR: Unable to resolve DNS-SD service \"%s\"!\n", uri);
580 exit(CUPS_BACKEND_STOP);
581 }
582 }
583
584 return (uri);
585 }
586
587
588 #ifdef HAVE_DNSSD
589 /*
590 * 'resolve_callback()' - Build a device URI for the given service name.
591 */
592
593 static void
594 resolve_callback(
595 DNSServiceRef sdRef, /* I - Service reference */
596 DNSServiceFlags flags, /* I - Results flags */
597 uint32_t interfaceIndex, /* I - Interface number */
598 DNSServiceErrorType errorCode, /* I - Error, if any */
599 const char *fullName, /* I - Full service name */
600 const char *hostTarget, /* I - Hostname */
601 uint16_t port, /* I - Port number */
602 uint16_t txtLen, /* I - Length of TXT record */
603 const unsigned char *txtRecord, /* I - TXT record data */
604 void *context) /* I - Pointer to URI buffer */
605 {
606 const char *scheme; /* URI scheme */
607 char rp[257]; /* Remote printer */
608 const void *value; /* Value from TXT record */
609 uint8_t valueLen; /* Length of value */
610
611
612 fprintf(stderr,
613 "DEBUG2: resolve_callback(sdRef=%p, flags=%x, interfaceIndex=%u, "
614 "errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, "
615 "txtLen=%u, txtRecord=%p, context=%p)\n", sdRef, flags,
616 interfaceIndex, errorCode, fullName, hostTarget, port, txtLen,
617 txtRecord, context);
618
619 /*
620 * Figure out the scheme from the full name...
621 */
622
623 if (strstr(fullName, "._ipp"))
624 scheme = "ipp";
625 else if (strstr(fullName, "._printer."))
626 scheme = "lpd";
627 else if (strstr(fullName, "._pdl-datastream."))
628 scheme = "socket";
629 else
630 scheme = "riousbprint";
631
632 /*
633 * Extract the "remote printer" key from the TXT record...
634 */
635
636 if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, "rp",
637 &valueLen)) != NULL)
638 {
639 /*
640 * Convert to resource by concatenating with a leading "/"...
641 */
642
643 rp[0] = '/';
644 memcpy(rp, value, valueLen);
645 rp[valueLen + 1] = '\0';
646 }
647 else
648 rp[0] = '\0';
649
650 /*
651 * Assemble the final device URI...
652 */
653
654 httpAssembleURI(HTTP_URI_CODING_ALL, (char *)context, HTTP_MAX_URI, scheme,
655 NULL, hostTarget, ntohs(port), rp);
656
657 fprintf(stderr, "DEBUG: Resolved URI is \"%s\"...\n", (char *)context);
658 }
659 #endif /* HAVE_DNSSD */
660
661
662 /*
663 * End of "$Id$".
664 */