]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/socket.c
Clean up compiler warnings reported in build farm logs.
[thirdparty/cups.git] / backend / socket.c
1 /*
2 * "$Id: socket.c,v 1.37 2003/04/10 12:57:40 mike Exp $"
3 *
4 * AppSocket backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2003 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-3111 USA
19 *
20 * Voice: (301) 373-9603
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/cups.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <cups/string.h>
40 #include <errno.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <signal.h>
44
45 #ifdef WIN32
46 # include <winsock.h>
47 #else
48 # include <unistd.h>
49 # include <fcntl.h>
50 # include <sys/socket.h>
51 # include <netinet/in.h>
52 # include <arpa/inet.h>
53 # include <netdb.h>
54 #endif /* WIN32 */
55
56
57 /*
58 * Some OS's don't have hstrerror(), most notably Solaris...
59 */
60
61 #ifndef HAVE_HSTRERROR
62 # define hstrerror cups_hstrerror
63
64 const char * /* O - Error string */
65 cups_hstrerror(int error) /* I - Error number */
66 {
67 static const char * const errors[] =
68 {
69 "OK",
70 "Host not found.",
71 "Try again.",
72 "Unrecoverable lookup error.",
73 "No data associated with name."
74 };
75
76
77 if (error < 0 || error > 4)
78 return ("Unknown hostname lookup error.");
79 else
80 return (errors[error]);
81 }
82 #elif defined(_AIX)
83 /*
84 * AIX doesn't provide a prototype but does provide the function...
85 */
86 extern const char *hstrerror(int);
87 #endif /* !HAVE_HSTRERROR */
88
89
90 /*
91 * Local functions...
92 */
93
94 void print_backchannel(const unsigned char *buffer, int nbytes);
95
96
97 /*
98 * 'main()' - Send a file to the printer or server.
99 *
100 * Usage:
101 *
102 * printer-uri job-id user title copies options [file]
103 */
104
105 int /* O - Exit status */
106 main(int argc, /* I - Number of command-line arguments (6 or 7) */
107 char *argv[]) /* I - Command-line arguments */
108 {
109 char method[255], /* Method in URI */
110 hostname[1024], /* Hostname */
111 username[255], /* Username info (not used) */
112 resource[1024]; /* Resource info (not used) */
113 int fp; /* Print file */
114 int copies; /* Number of copies to print */
115 int port; /* Port number */
116 int delay; /* Delay for retries... */
117 int fd; /* AppSocket */
118 int error; /* Error code (if any) */
119 struct sockaddr_in addr; /* Socket address */
120 struct hostent *hostaddr; /* Host address */
121 int wbytes; /* Number of bytes written */
122 int nbytes; /* Number of bytes read */
123 size_t tbytes; /* Total number of bytes written */
124 char buffer[8192], /* Output buffer */
125 *bufptr; /* Pointer into buffer */
126 struct timeval timeout; /* Timeout for select() */
127 fd_set input; /* Input set for select() */
128 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
129 struct sigaction action; /* Actions for POSIX signals */
130 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
131
132
133 /*
134 * Make sure status messages are not buffered...
135 */
136
137 setbuf(stderr, NULL);
138
139 /*
140 * Ignore SIGPIPE signals...
141 */
142
143 #ifdef HAVE_SIGSET
144 sigset(SIGPIPE, SIG_IGN);
145 #elif defined(HAVE_SIGACTION)
146 memset(&action, 0, sizeof(action));
147 action.sa_handler = SIG_IGN;
148 sigaction(SIGPIPE, &action, NULL);
149 #else
150 signal(SIGPIPE, SIG_IGN);
151 #endif /* HAVE_SIGSET */
152
153 /*
154 * Check command-line...
155 */
156
157 if (argc == 1)
158 {
159 puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\"");
160 return (0);
161 }
162 else if (argc < 6 || argc > 7)
163 {
164 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
165 argv[0]);
166 return (1);
167 }
168
169 /*
170 * If we have 7 arguments, print the file named on the command-line.
171 * Otherwise, send stdin instead...
172 */
173
174 if (argc == 6)
175 {
176 fp = 0;
177 copies = 1;
178 }
179 else
180 {
181 /*
182 * Try to open the print file...
183 */
184
185 if ((fp = open(argv[6], O_RDONLY)) < 0)
186 {
187 perror("ERROR: unable to open print file");
188 return (1);
189 }
190
191 copies = atoi(argv[4]);
192 }
193
194 /*
195 * Extract the hostname and port number from the URI...
196 */
197
198 httpSeparate(argv[0], method, username, hostname, &port, resource);
199
200 if (port == 0)
201 port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
202
203 /*
204 * Then try to connect to the remote host...
205 */
206
207 if ((hostaddr = httpGetHostByName(hostname)) == NULL)
208 {
209 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
210 hostname, hstrerror(h_errno));
211 return (1);
212 }
213
214 fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n",
215 hostname, port);
216
217 memset(&addr, 0, sizeof(addr));
218 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
219 addr.sin_family = hostaddr->h_addrtype;
220 addr.sin_port = htons(port);
221
222 while (copies > 0)
223 {
224 for (delay = 5;;)
225 {
226 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
227 {
228 perror("ERROR: Unable to create socket");
229 return (1);
230 }
231
232 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
233 {
234 error = errno;
235 close(fd);
236 fd = -1;
237
238 if (error == ECONNREFUSED || error == EHOSTDOWN ||
239 error == EHOSTUNREACH)
240 {
241 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in %d seconds...\n",
242 hostname, delay);
243 sleep(delay);
244
245 if (delay < 30)
246 delay += 5;
247 }
248 else
249 {
250 perror("ERROR: Unable to connect to printer (retrying in 30 seconds)");
251 sleep(30);
252 }
253 }
254 else
255 break;
256 }
257
258 /*
259 * Now that we are "connected" to the port, ignore SIGTERM so that we
260 * can finish out any page data the driver sends (e.g. to eject the
261 * current page... Only ignore SIGTERM if we are printing data from
262 * stdin (otherwise you can't cancel raw jobs...)
263 */
264
265 if (argc < 7)
266 {
267 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
268 sigset(SIGTERM, SIG_IGN);
269 #elif defined(HAVE_SIGACTION)
270 memset(&action, 0, sizeof(action));
271
272 sigemptyset(&action.sa_mask);
273 action.sa_handler = SIG_IGN;
274 sigaction(SIGTERM, &action, NULL);
275 #else
276 signal(SIGTERM, SIG_IGN);
277 #endif /* HAVE_SIGSET */
278 }
279
280 /*
281 * Finally, send the print file...
282 */
283
284 copies --;
285
286 if (fp != 0)
287 {
288 fputs("PAGE: 1 1\n", stderr);
289 lseek(fp, 0, SEEK_SET);
290 }
291
292 fputs("INFO: Connected to host, sending print job...\n", stderr);
293
294 tbytes = 0;
295 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
296 {
297 /*
298 * Write the print data to the printer...
299 */
300
301 tbytes += nbytes;
302 bufptr = buffer;
303
304 while (nbytes > 0)
305 {
306 if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0)
307 {
308 perror("ERROR: Unable to send print file to printer");
309 break;
310 }
311
312 nbytes -= wbytes;
313 bufptr += wbytes;
314 }
315
316 /*
317 * Check for possible data coming back from the printer...
318 */
319
320 timeout.tv_sec = 0;
321 timeout.tv_usec = 0;
322
323 FD_ZERO(&input);
324 FD_SET(fd, &input);
325 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
326 {
327 /*
328 * Grab the data coming back and spit it out to stderr...
329 */
330
331 if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0)
332 {
333 fprintf(stderr, "INFO: Received %d bytes of back-channel data!\n",
334 nbytes);
335 print_backchannel((unsigned char *)buffer, nbytes);
336 }
337 }
338 else if (argc > 6)
339 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
340 (unsigned long)tbytes);
341 }
342
343 /*
344 * Shutdown the socket and wait for the other end to finish...
345 */
346
347 fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
348
349 shutdown(fd, 1);
350
351 for (;;)
352 {
353 /*
354 * Wait a maximum of 90 seconds for backchannel data or a closed
355 * connection...
356 */
357
358 timeout.tv_sec = 90;
359 timeout.tv_usec = 0;
360
361 FD_ZERO(&input);
362 FD_SET(fd, &input);
363
364 #ifdef __hpux
365 if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
366 #else
367 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
368 #endif /* __hpux */
369 {
370 /*
371 * Grab the data coming back and spit it out to stderr...
372 */
373
374 if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0)
375 {
376 fprintf(stderr, "INFO: Received %d bytes of back-channel data!\n",
377 nbytes);
378 print_backchannel((unsigned char *)buffer, nbytes);
379 }
380 else
381 break;
382 }
383 else
384 break;
385 }
386
387 /*
388 * Close the socket connection...
389 */
390
391 close(fd);
392 }
393
394 /*
395 * Close the input file and return...
396 */
397
398 if (fp != 0)
399 close(fp);
400
401 fputs("INFO: Ready to print.\n", stderr);
402
403 return (0);
404 }
405
406
407 /*
408 * 'print_backchannel()' - Print the contents of a back-channel buffer.
409 */
410
411 void
412 print_backchannel(const unsigned char *buffer, /* I - Data buffer */
413 int nbytes) /* I - Number of bytes */
414 {
415 char line[255], /* Formatted line */
416 *lineptr; /* Pointer into line */
417
418
419 for (lineptr = line; nbytes > 0; buffer ++, nbytes --)
420 {
421 if (*buffer < 0x20 || *buffer >= 0x7f)
422 {
423 snprintf(lineptr, sizeof(line) - (lineptr - line), "<%02X>", *buffer);
424 lineptr += strlen(lineptr);
425 }
426 else
427 *lineptr++ = *buffer;
428
429 if ((lineptr - line) > 72)
430 {
431 *lineptr = '\0';
432 fprintf(stderr, "DEBUG: DATA: %s\n", line);
433 lineptr = line;
434 }
435 }
436
437 if (lineptr > line)
438 {
439 *lineptr = '\0';
440 fprintf(stderr, "DEBUG: DATA: %s\n", line);
441 }
442 }
443
444
445 /*
446 * End of "$Id: socket.c,v 1.37 2003/04/10 12:57:40 mike Exp $".
447 */