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