]> git.ipfire.org Git - thirdparty/cups.git/blame - backend/socket.c
Mirror 1.1.x changes.
[thirdparty/cups.git] / backend / socket.c
CommitLineData
43e2fc22 1/*
2d417cb3 2 * "$Id: socket.c,v 1.17.2.16 2003/10/09 19:13:48 mike Exp $"
43e2fc22 3 *
e73c6c0a 4 * AppSocket backend for the Common UNIX Printing System (CUPS).
43e2fc22 5 *
1d9595ab 6 * Copyright 1997-2003 by Easy Software Products, all rights reserved.
43e2fc22 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
58ec2a95 17 * 44141 Airport View Drive, Suite 204
43e2fc22 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 *
dab1a4d8 24 * This file is subject to the Apple OS-Developed Software exception.
25 *
43e2fc22 26 * Contents:
27 *
decc1f36 28 * main() - Send a file to the printer or server.
43e2fc22 29 */
30
31/*
32 * Include necessary headers.
33 */
34
e73c6c0a 35#include <cups/cups.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <stdarg.h>
2d417cb3 39#include <cups/http-private.h>
e73c6c0a 40#include <cups/string.h>
41#include <errno.h>
42#include <sys/types.h>
43#include <sys/stat.h>
4ff40357 44#include <signal.h>
e73c6c0a 45
c3026ddc 46#ifdef WIN32
e73c6c0a 47# include <winsock.h>
48#else
267cf96a 49# include <unistd.h>
50# include <fcntl.h>
e73c6c0a 51# include <sys/socket.h>
52# include <netinet/in.h>
53# include <arpa/inet.h>
54# include <netdb.h>
c3026ddc 55#endif /* WIN32 */
e73c6c0a 56
57
58/*
59 * 'main()' - Send a file to the printer or server.
60 *
61 * Usage:
62 *
63 * printer-uri job-id user title copies options [file]
64 */
65
8b7032be 66int /* O - Exit status */
67main(int argc, /* I - Number of command-line arguments (6 or 7) */
68 char *argv[]) /* I - Command-line arguments */
e73c6c0a 69{
70 char method[255], /* Method in URI */
71 hostname[1024], /* Hostname */
72 username[255], /* Username info (not used) */
73 resource[1024]; /* Resource info (not used) */
267cf96a 74 int fp; /* Print file */
3f9cb6c6 75 int copies; /* Number of copies to print */
e73c6c0a 76 int port; /* Port number */
10f725af 77 int delay; /* Delay for retries... */
e73c6c0a 78 int fd; /* AppSocket */
79 int error; /* Error code (if any) */
80 struct sockaddr_in addr; /* Socket address */
81 struct hostent *hostaddr; /* Host address */
7c88bf41 82 int wbytes; /* Number of bytes written */
8b7032be 83 int nbytes; /* Number of bytes read */
84 size_t tbytes; /* Total number of bytes written */
7c88bf41 85 char buffer[8192], /* Output buffer */
86 *bufptr; /* Pointer into buffer */
e73c6c0a 87 struct timeval timeout; /* Timeout for select() */
88 fd_set input; /* Input set for select() */
4ff40357 89#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
90 struct sigaction action; /* Actions for POSIX signals */
91#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
e73c6c0a 92
93
4b23f3b3 94 /*
95 * Make sure status messages are not buffered...
96 */
97
98 setbuf(stderr, NULL);
99
98904cd6 100 /*
101 * Ignore SIGPIPE signals...
102 */
103
104#ifdef HAVE_SIGSET
105 sigset(SIGPIPE, SIG_IGN);
106#elif defined(HAVE_SIGACTION)
107 memset(&action, 0, sizeof(action));
108 action.sa_handler = SIG_IGN;
109 sigaction(SIGPIPE, &action, NULL);
110#else
111 signal(SIGPIPE, SIG_IGN);
112#endif /* HAVE_SIGSET */
113
4b23f3b3 114 /*
115 * Check command-line...
116 */
117
68edc300 118 if (argc == 1)
119 {
d4c438d4 120 puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\"");
68edc300 121 return (0);
122 }
123 else if (argc < 6 || argc > 7)
e73c6c0a 124 {
125 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
126 argv[0]);
127 return (1);
128 }
129
130 /*
131 * If we have 7 arguments, print the file named on the command-line.
132 * Otherwise, send stdin instead...
133 */
134
135 if (argc == 6)
3f9cb6c6 136 {
267cf96a 137 fp = 0;
3f9cb6c6 138 copies = 1;
139 }
e73c6c0a 140 else
141 {
142 /*
143 * Try to open the print file...
144 */
145
267cf96a 146 if ((fp = open(argv[6], O_RDONLY)) < 0)
e73c6c0a 147 {
decc1f36 148 perror("ERROR: unable to open print file");
e73c6c0a 149 return (1);
150 }
3f9cb6c6 151
152 copies = atoi(argv[4]);
e73c6c0a 153 }
154
155 /*
156 * Extract the hostname and port number from the URI...
157 */
158
159 httpSeparate(argv[0], method, username, hostname, &port, resource);
160
161 if (port == 0)
162 port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
163
164 /*
165 * Then try to connect to the remote host...
166 */
167
753453e4 168 if ((hostaddr = httpGetHostByName(hostname)) == NULL)
e73c6c0a 169 {
2a0ef17a 170 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s\n",
7e3ba0af 171 hostname, hstrerror(h_errno));
e73c6c0a 172 return (1);
173 }
174
175 fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n",
176 hostname, port);
177
178 memset(&addr, 0, sizeof(addr));
179 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
180 addr.sin_family = hostaddr->h_addrtype;
181 addr.sin_port = htons(port);
182
3f9cb6c6 183 while (copies > 0)
e73c6c0a 184 {
10f725af 185 for (delay = 5;;)
e73c6c0a 186 {
3f9cb6c6 187 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
e73c6c0a 188 {
2cc18dd2 189 perror("ERROR: Unable to create socket");
3f9cb6c6 190 return (1);
e73c6c0a 191 }
3f9cb6c6 192
193 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
e73c6c0a 194 {
3f9cb6c6 195 error = errno;
196 close(fd);
197 fd = -1;
198
4c2096b8 199 if (error == ECONNREFUSED || error == EHOSTDOWN ||
200 error == EHOSTUNREACH)
3f9cb6c6 201 {
10f725af 202 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in %d seconds...\n",
203 hostname, delay);
204 sleep(delay);
205
206 if (delay < 30)
207 delay += 5;
3f9cb6c6 208 }
209 else
210 {
10f725af 211 perror("ERROR: Unable to connect to printer (retrying in 30 seconds)");
2cc18dd2 212 sleep(30);
3f9cb6c6 213 }
e73c6c0a 214 }
3f9cb6c6 215 else
216 break;
e73c6c0a 217 }
e73c6c0a 218
4ff40357 219 /*
220 * Now that we are "connected" to the port, ignore SIGTERM so that we
221 * can finish out any page data the driver sends (e.g. to eject the
222 * current page...
223 */
224
225#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
226 sigset(SIGTERM, SIG_IGN);
227#elif defined(HAVE_SIGACTION)
228 memset(&action, 0, sizeof(action));
229
230 sigemptyset(&action.sa_mask);
231 action.sa_handler = SIG_IGN;
232 sigaction(SIGTERM, &action, NULL);
233#else
234 signal(SIGTERM, SIG_IGN);
235#endif /* HAVE_SIGSET */
236
e73c6c0a 237 /*
3f9cb6c6 238 * Finally, send the print file...
e73c6c0a 239 */
240
3f9cb6c6 241 copies --;
7c88bf41 242
267cf96a 243 if (fp != 0)
e73c6c0a 244 {
3f9cb6c6 245 fputs("PAGE: 1 1\n", stderr);
267cf96a 246 lseek(fp, 0, SEEK_SET);
e73c6c0a 247 }
e73c6c0a 248
3f9cb6c6 249 fputs("INFO: Connected to host, sending print job...\n", stderr);
e73c6c0a 250
3f9cb6c6 251 tbytes = 0;
267cf96a 252 while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0)
e73c6c0a 253 {
254 /*
3f9cb6c6 255 * Write the print data to the printer...
256 */
257
258 tbytes += nbytes;
259 bufptr = buffer;
260
261 while (nbytes > 0)
262 {
263 if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0)
264 {
265 perror("ERROR: Unable to send print file to printer");
266 break;
267 }
268
269 nbytes -= wbytes;
270 bufptr += wbytes;
271 }
272
0cd4970e 273 if (wbytes < 0)
274 break;
275
3f9cb6c6 276 /*
277 * Check for possible data coming back from the printer...
e73c6c0a 278 */
279
b5cb0608 280 timeout.tv_sec = 0;
3f9cb6c6 281 timeout.tv_usec = 0;
b5cb0608 282
3f9cb6c6 283 FD_ZERO(&input);
284 FD_SET(fd, &input);
285 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
286 {
287 /*
288 * Grab the data coming back and spit it out to stderr...
289 */
290
291 if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0)
8b7032be 292 fprintf(stderr, "INFO: Received %d bytes of back-channel data!\n",
293 nbytes);
3f9cb6c6 294 }
295 else if (argc > 6)
ba31b514 296 fprintf(stderr, "INFO: Sending print file, %lu bytes...\n",
297 (unsigned long)tbytes);
e73c6c0a 298 }
3f9cb6c6 299
b5cb0608 300 /*
301 * Shutdown the socket and wait for the other end to finish...
302 */
303
304 fputs("INFO: Print file sent, waiting for printer to finish...\n", stderr);
305
306 shutdown(fd, 1);
307
308 for (;;)
309 {
310 /*
311 * Wait a maximum of 90 seconds for backchannel data or a closed
312 * connection...
313 */
314
315 timeout.tv_sec = 90;
316 timeout.tv_usec = 0;
317
318 FD_ZERO(&input);
319 FD_SET(fd, &input);
320
321#ifdef __hpux
322 if (select(fd + 1, (int *)&input, NULL, NULL, &timeout) > 0)
323#else
324 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
325#endif /* __hpux */
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)
8b7032be 332 fprintf(stderr, "INFO: Received %d bytes of back-channel data!\n",
333 nbytes);
b5cb0608 334 else
335 break;
336 }
337 else
338 break;
339 }
340
3f9cb6c6 341 /*
342 * Close the socket connection...
343 */
344
345 close(fd);
e73c6c0a 346 }
347
348 /*
3f9cb6c6 349 * Close the input file and return...
e73c6c0a 350 */
351
267cf96a 352 if (fp != 0)
353 close(fp);
e73c6c0a 354
753453e4 355 fputs("INFO: Ready to print.\n", stderr);
b5cb0608 356
e73c6c0a 357 return (0);
358}
43e2fc22 359
360
361/*
2d417cb3 362 * End of "$Id: socket.c,v 1.17.2.16 2003/10/09 19:13:48 mike Exp $".
43e2fc22 363 */