]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/socket.c
Load cups into easysw/current.
[thirdparty/cups.git] / backend / socket.c
CommitLineData
ef416fc2 1/*
bd7854cb 2 * "$Id: socket.c 5099 2006-02-13 02:46:10Z mike $"
ef416fc2 3 *
4 * AppSocket backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * main() - Send a file to the printer or server.
29 */
30
31/*
32 * Include necessary headers.
33 */
34
35#include <cups/backend.h>
36#include <cups/http-private.h>
37#include <cups/cups.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <stdarg.h>
41#include <cups/string.h>
42#include <errno.h>
43#include <sys/types.h>
44#include <sys/stat.h>
45#include <signal.h>
46
47#ifdef WIN32
48# include <winsock.h>
49#else
50# include <unistd.h>
51# include <fcntl.h>
52# include <sys/socket.h>
53# include <netinet/in.h>
54# include <arpa/inet.h>
55# include <netdb.h>
56#endif /* WIN32 */
57
58
59/*
60 * 'main()' - Send a file to the printer or server.
61 *
62 * Usage:
63 *
64 * printer-uri job-id user title copies options [file]
65 */
66
67int /* O - Exit status */
68main(int argc, /* I - Number of command-line arguments (6 or 7) */
69 char *argv[]) /* I - Command-line arguments */
70{
71 char method[255], /* Method in URI */
72 hostname[1024], /* Hostname */
73 username[255], /* Username info (not used) */
fa73b229 74 resource[1024], /* Resource info (not used) */
75 *options, /* Pointer to options */
76 name[255], /* Name of option */
77 value[255], /* Value of option */
78 *ptr; /* Pointer into name or value */
ef416fc2 79 int fp; /* Print file */
80 int copies; /* Number of copies to print */
fa73b229 81 int waiteof; /* Wait for end-of-file? */
ef416fc2 82 int port; /* Port number */
83 char portname[255]; /* Port name */
84 int delay; /* Delay for retries... */
85 int fd; /* AppSocket */
86 int error; /* Error code (if any) */
87 http_addrlist_t *addrlist; /* Address list */
88 int rbytes; /* Number of bytes read */
89 int wbytes; /* Number of bytes written */
90 int nbytes; /* Number of bytes read */
91 size_t tbytes; /* Total number of bytes written */
92 char buffer[8192], /* Output buffer */
93 *bufptr; /* Pointer into buffer */
94 struct timeval timeout; /* Timeout for select() */
95 fd_set input, /* Input set for select() */
96 output; /* Output set for select() */
97#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
98 struct sigaction action; /* Actions for POSIX signals */
99#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
100
101
102 /*
103 * Make sure status messages are not buffered...
104 */
105
106 setbuf(stderr, NULL);
107
108 /*
109 * Ignore SIGPIPE signals...
110 */
111
112#ifdef HAVE_SIGSET
113 sigset(SIGPIPE, SIG_IGN);
114#elif defined(HAVE_SIGACTION)
115 memset(&action, 0, sizeof(action));
116 action.sa_handler = SIG_IGN;
117 sigaction(SIGPIPE, &action, NULL);
118#else
119 signal(SIGPIPE, SIG_IGN);
120#endif /* HAVE_SIGSET */
121
122 /*
123 * Check command-line...
124 */
125
126 if (argc == 1)
127 {
128 puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\"");
129 return (CUPS_BACKEND_OK);
130 }
131 else if (argc < 6 || argc > 7)
132 {
133 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
134 argv[0]);
135 return (CUPS_BACKEND_FAILED);
136 }
137
138 /*
139 * If we have 7 arguments, print the file named on the command-line.
140 * Otherwise, send stdin instead...
141 */
142
143 if (argc == 6)
144 {
145 fp = 0;
146 copies = 1;
147 }
148 else
149 {
150 /*
151 * Try to open the print file...
152 */
153
154 if ((fp = open(argv[6], O_RDONLY)) < 0)
155 {
156 perror("ERROR: unable to open print file");
157 return (CUPS_BACKEND_FAILED);
158 }
159
160 copies = atoi(argv[4]);
161 }
162
163 /*
164 * Extract the hostname and port number from the URI...
165 */
166
a4d04587 167 httpSeparateURI(HTTP_URI_CODING_ALL, cupsBackendDeviceURI(argv),
168 method, sizeof(method), username, sizeof(username),
169 hostname, sizeof(hostname), &port,
ef416fc2 170 resource, sizeof(resource));
171
172 if (port == 0)
173 port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
174
fa73b229 175 /*
176 * Get options, if any...
177 */
178
179 waiteof = 1;
180
181 if ((options = strchr(resource, '?')) != NULL)
182 {
183 /*
184 * Yup, terminate the device name string and move to the first
185 * character of the options...
186 */
187
188 *options++ = '\0';
189
190 /*
191 * Parse options...
192 */
193
194 while (*options)
195 {
196 /*
197 * Get the name...
198 */
199
200 for (ptr = name; *options && *options != '=';)
201 if (ptr < (name + sizeof(name) - 1))
202 *ptr++ = *options++;
203 *ptr = '\0';
204
205 if (*options == '=')
206 {
207 /*
208 * Get the value...
209 */
210
211 options ++;
212
213 for (ptr = value; *options && *options != '+' && *options != '&';)
214 if (ptr < (value + sizeof(value) - 1))
215 *ptr++ = *options++;
216 *ptr = '\0';
217
218 if (*options == '+' || *options == '&')
219 options ++;
220 }
221 else
222 value[0] = '\0';
223
224 /*
225 * Process the option...
226 */
227
228 if (!strcasecmp(name, "waiteof"))
229 {
230 /*
231 * Set the wait-for-eof value...
232 */
233
234 waiteof = !value[0] || !strcasecmp(value, "on") ||
235 !strcasecmp(value, "yes") || !strcasecmp(value, "true");
236 }
237 }
238 }
239
ef416fc2 240 /*
241 * Then try to connect to the remote host...
242 */
243
244 sprintf(portname, "%d", port);
245
246 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
247 {
248 fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", hostname);
249 return (CUPS_BACKEND_STOP);
250 }
251
252 fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n",
253 hostname, port);
254
255 wbytes = 0;
256
257 while (copies > 0)
258 {
259 for (delay = 5;;)
260 {
261 if (!httpAddrConnect(addrlist, &fd))
262 {
263 error = errno;
264 fd = -1;
265
266 if (getenv("CLASS") != NULL)
267 {
268 /*
269 * If the CLASS environment variable is set, the job was submitted
270 * to a class and not to a specific queue. In this case, we want
271 * to abort immediately so that the job can be requeued on the next
272 * available printer in the class.
273 */
274
275 fprintf(stderr, "INFO: Unable to connect to \"%s\", queuing on next printer in class...\n",
276 hostname);
277
278 /*
279 * Sleep 5 seconds to keep the job from requeuing too rapidly...
280 */
281
282 sleep(5);
283
284 return (CUPS_BACKEND_FAILED);
285 }
286
287 if (error == ECONNREFUSED || error == EHOSTDOWN ||
288 error == EHOSTUNREACH)
289 {
290 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in %d seconds...\n",
291 hostname, delay);
292 sleep(delay);
293
294 if (delay < 30)
295 delay += 5;
296 }
297 else
298 {
299 perror("ERROR: Unable to connect to printer (retrying in 30 seconds)");
300 sleep(30);
301 }
302 }
303 else
304 break;
305 }
306
307 /*
308 * Now that we are "connected" to the port, ignore SIGTERM so that we
309 * can finish out any page data the driver sends (e.g. to eject the
310 * current page... Only ignore SIGTERM if we are printing data from
311 * stdin (otherwise you can't cancel raw jobs...)
312 */
313
314 if (argc < 7)
315 {
316#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
317 sigset(SIGTERM, SIG_IGN);
318#elif defined(HAVE_SIGACTION)
319 memset(&action, 0, sizeof(action));
320
321 sigemptyset(&action.sa_mask);
322 action.sa_handler = SIG_IGN;
323 sigaction(SIGTERM, &action, NULL);
324#else
325 signal(SIGTERM, SIG_IGN);
326#endif /* HAVE_SIGSET */
327 }
328
329 /*
330 * Finally, send the print file...
331 */
332
333 copies --;
334
335 if (fp != 0)
336 {
337 fputs("PAGE: 1 1\n", stderr);
338 lseek(fp, 0, SEEK_SET);
339 }
340
341 fputs("INFO: Connected to host, sending print job...\n", stderr);
342
343 tbytes = 0;
344 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
345 {
346 /*
347 * Write the print data to the printer...
348 */
349
350 tbytes += nbytes;
351 bufptr = buffer;
352
353 while (nbytes > 0)
354 {
355 /*
356 * See if we are ready to read or write...
357 */
358
359 do
360 {
361 FD_ZERO(&input);
362 FD_SET(fd, &input);
363 FD_ZERO(&output);
364 FD_SET(fd, &output);
365 }
366 while (select(fd + 1, &input, &output, NULL, NULL) < 0);
367
368 if (FD_ISSET(fd, &input))
369 {
370 /*
371 * Read backchannel data...
372 */
373
374 if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
375 {
376 fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
377 rbytes);
bd7854cb 378 cupsBackChannelWrite(resource, rbytes, 1.0);
ef416fc2 379 }
380 }
381
382 if (FD_ISSET(fd, &output))
383 {
384 /*
385 * Write print data...
386 */
387
388 if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0)
389 {
390 /*
391 * Check for retryable errors...
392 */
393
394 if (errno != EAGAIN && errno != EINTR)
395 {
396 perror("ERROR: Unable to send print file to printer");
397 break;
398 }
399 }
400 else
401 {
402 /*
403 * Update count and pointer...
404 */
405
406 nbytes -= wbytes;
407 bufptr += wbytes;
408 }
409 }
410 }
411
412 if (wbytes < 0)
413 break;
414
415 if (argc > 6)
416 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
417 (unsigned long)tbytes);
418 }
419
fa73b229 420 if (waiteof)
ef416fc2 421 {
422 /*
fa73b229 423 * Shutdown the socket and wait for the other end to finish...
ef416fc2 424 */
425
fa73b229 426 fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
ef416fc2 427
fa73b229 428 shutdown(fd, 1);
ef416fc2 429
fa73b229 430 for (;;)
ef416fc2 431 {
432 /*
fa73b229 433 * Wait a maximum of 90 seconds for backchannel data or a closed
434 * connection...
ef416fc2 435 */
436
fa73b229 437 timeout.tv_sec = 90;
438 timeout.tv_usec = 0;
439
440 FD_ZERO(&input);
441 FD_SET(fd, &input);
442
443 #ifdef __hpux
444 if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
445 #else
446 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
447 #endif /* __hpux */
ef416fc2 448 {
fa73b229 449 /*
450 * Grab the data coming back and spit it out to stderr...
451 */
452
453 if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0)
454 {
455 fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n",
456 rbytes);
bd7854cb 457 cupsBackChannelWrite(resource, rbytes, 1.0);
fa73b229 458 }
459 else
460 break;
461 }
ef416fc2 462 else
463 break;
464 }
ef416fc2 465 }
466
467 /*
468 * Close the socket connection...
469 */
470
471 close(fd);
472 }
473
474 httpAddrFreeList(addrlist);
475
476 /*
477 * Close the input file and return...
478 */
479
480 if (fp != 0)
481 close(fp);
482
483 if (wbytes >= 0)
484 fputs("INFO: Ready to print.\n", stderr);
485
486 return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK);
487}
488
489
490/*
bd7854cb 491 * End of "$Id: socket.c 5099 2006-02-13 02:46:10Z mike $".
ef416fc2 492 */