]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/socket.c
Backends now handle SIGTERM once a connection is established with a
[thirdparty/cups.git] / backend / socket.c
1 /*
2 * "$Id: socket.c,v 1.13 2000/04/27 21:31:38 mike Exp $"
3 *
4 * AppSocket backend for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2000 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 * Contents:
25 *
26 * main() - Send a file to the printer or server.
27 */
28
29 /*
30 * Include necessary headers.
31 */
32
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>
41 #include <signal.h>
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 */
70 int copies; /* Number of copies to print */
71 int port; /* Port number */
72 int fd; /* AppSocket */
73 int error; /* Error code (if any) */
74 struct sockaddr_in addr; /* Socket address */
75 struct hostent *hostaddr; /* Host address */
76 int wbytes; /* Number of bytes written */
77 size_t nbytes, /* Number of bytes read */
78 tbytes; /* Total number of bytes written */
79 char buffer[8192], /* Output buffer */
80 *bufptr; /* Pointer into buffer */
81 struct timeval timeout; /* Timeout for select() */
82 fd_set input; /* Input set for select() */
83 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
84 struct sigaction action; /* Actions for POSIX signals */
85 #endif /* HAVE_SIGACTION && !HAVE_SIGSET */
86
87
88 if (argc == 1)
89 {
90 puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\"");
91 return (0);
92 }
93 else if (argc < 6 || argc > 7)
94 {
95 fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
96 argv[0]);
97 return (1);
98 }
99
100 /*
101 * If we have 7 arguments, print the file named on the command-line.
102 * Otherwise, send stdin instead...
103 */
104
105 if (argc == 6)
106 {
107 fp = stdin;
108 copies = 1;
109 }
110 else
111 {
112 /*
113 * Try to open the print file...
114 */
115
116 if ((fp = fopen(argv[6], "rb")) == NULL)
117 {
118 perror("ERROR: unable to open print file");
119 return (1);
120 }
121
122 copies = atoi(argv[4]);
123 }
124
125 /*
126 * Extract the hostname and port number from the URI...
127 */
128
129 httpSeparate(argv[0], method, username, hostname, &port, resource);
130
131 if (port == 0)
132 port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
133
134 /*
135 * Then try to connect to the remote host...
136 */
137
138 if ((hostaddr = gethostbyname(hostname)) == NULL)
139 {
140 fprintf(stderr, "ERROR: Unable to locate printer \'%s\' - %s",
141 hostname, strerror(errno));
142 return (1);
143 }
144
145 fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n",
146 hostname, port);
147
148 memset(&addr, 0, sizeof(addr));
149 memcpy(&(addr.sin_addr), hostaddr->h_addr, hostaddr->h_length);
150 addr.sin_family = hostaddr->h_addrtype;
151 addr.sin_port = htons(port);
152
153 while (copies > 0)
154 {
155 for (;;)
156 {
157 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
158 {
159 perror("ERROR: Unable to create socket");
160 return (1);
161 }
162
163 if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
164 {
165 error = errno;
166 close(fd);
167 fd = -1;
168
169 if (error == ECONNREFUSED)
170 {
171 fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...\n",
172 hostname);
173 sleep(30);
174 }
175 else
176 {
177 perror("ERROR: Unable to connect to printer");
178 sleep(30);
179 }
180 }
181 else
182 break;
183 }
184
185 /*
186 * Now that we are "connected" to the port, ignore SIGTERM so that we
187 * can finish out any page data the driver sends (e.g. to eject the
188 * current page...
189 */
190
191 #ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
192 sigset(SIGTERM, SIG_IGN);
193 #elif defined(HAVE_SIGACTION)
194 memset(&action, 0, sizeof(action));
195
196 sigemptyset(&action.sa_mask);
197 action.sa_handler = SIG_IGN;
198 sigaction(SIGTERM, &action, NULL);
199 #else
200 signal(SIGTERM, SIG_IGN);
201 #endif /* HAVE_SIGSET */
202
203 /*
204 * Finally, send the print file...
205 */
206
207 copies --;
208
209 if (fp != stdin)
210 {
211 fputs("PAGE: 1 1\n", stderr);
212 rewind(fp);
213 }
214
215 fputs("INFO: Connected to host, sending print job...\n", stderr);
216
217 tbytes = 0;
218 while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0)
219 {
220 /*
221 * Write the print data to the printer...
222 */
223
224 tbytes += nbytes;
225 bufptr = buffer;
226
227 while (nbytes > 0)
228 {
229 if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0)
230 {
231 perror("ERROR: Unable to send print file to printer");
232 break;
233 }
234
235 nbytes -= wbytes;
236 bufptr += wbytes;
237 }
238
239 /*
240 * Check for possible data coming back from the printer...
241 */
242
243 timeout.tv_sec = 0;
244 timeout.tv_usec = 0;
245 FD_ZERO(&input);
246 FD_SET(fd, &input);
247 if (select(fd + 1, &input, NULL, NULL, &timeout) > 0)
248 {
249 /*
250 * Grab the data coming back and spit it out to stderr...
251 */
252
253 if ((nbytes = recv(fd, buffer, sizeof(buffer), 0)) > 0)
254 fprintf(stderr, "INFO: Received %u bytes of back-channel data!\n",
255 nbytes);
256 }
257 else if (argc > 6)
258 fprintf(stderr, "INFO: Sending print file, %u bytes...\n", tbytes);
259 }
260
261 /*
262 * Close the socket connection...
263 */
264
265 close(fd);
266 }
267
268 /*
269 * Close the input file and return...
270 */
271
272 if (fp != stdin)
273 fclose(fp);
274
275 return (0);
276 }
277
278
279 /*
280 * End of "$Id: socket.c,v 1.13 2000/04/27 21:31:38 mike Exp $".
281 */