]>
Commit | Line | Data |
---|---|---|
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 | 66 | int /* O - Exit status */ |
67 | main(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 | */ |