Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
srohatgi01
GitHub Repository: srohatgi01/cups
Path: blob/master/backend/socket.c
1090 views
1
/*
2
* AppSocket backend for CUPS.
3
*
4
* Copyright © 2007-2018 by Apple Inc.
5
* Copyright © 1997-2007 by Easy Software Products, all rights reserved.
6
*
7
* Licensed under Apache License v2.0. See the file "LICENSE" for more
8
* information.
9
*/
10
11
/*
12
* Include necessary headers.
13
*/
14
15
#include <cups/http-private.h>
16
#include "backend-private.h"
17
#include <stdarg.h>
18
#include <sys/types.h>
19
#include <sys/stat.h>
20
21
#ifdef _WIN32
22
# include <winsock.h>
23
#else
24
# include <unistd.h>
25
# include <fcntl.h>
26
# include <sys/socket.h>
27
# include <netinet/in.h>
28
# include <arpa/inet.h>
29
# include <netdb.h>
30
#endif /* _WIN32 */
31
32
33
/*
34
* Local functions...
35
*/
36
37
static ssize_t wait_bc(int device_fd, int secs);
38
39
40
/*
41
* 'main()' - Send a file to the printer or server.
42
*
43
* Usage:
44
*
45
* printer-uri job-id user title copies options [file]
46
*/
47
48
int /* O - Exit status */
49
main(int argc, /* I - Number of command-line arguments (6 or 7) */
50
char *argv[]) /* I - Command-line arguments */
51
{
52
const char *device_uri; /* Device URI */
53
char scheme[255], /* Scheme in URI */
54
hostname[1024], /* Hostname */
55
username[255], /* Username info (not used) */
56
resource[1024], /* Resource info (not used) */
57
*options, /* Pointer to options */
58
*name, /* Name of option */
59
*value, /* Value of option */
60
sep; /* Option separator */
61
int print_fd; /* Print file */
62
int copies; /* Number of copies to print */
63
time_t start_time; /* Time of first connect */
64
int contimeout; /* Connection timeout */
65
int waiteof; /* Wait for end-of-file? */
66
int port; /* Port number */
67
int delay; /* Delay for retries... */
68
int device_fd; /* AppSocket */
69
int error; /* Error code (if any) */
70
http_addrlist_t *addrlist, /* Address list */
71
*addr; /* Connected address */
72
char addrname[256]; /* Address name */
73
int snmp_enabled = 1; /* Is SNMP enabled? */
74
int snmp_fd, /* SNMP socket */
75
start_count, /* Page count via SNMP at start */
76
page_count, /* Page count via SNMP */
77
have_supplies; /* Printer supports supply levels? */
78
ssize_t bytes = 0, /* Initial bytes read */
79
tbytes; /* Total number of bytes written */
80
char buffer[1024]; /* Initial print buffer */
81
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
82
struct sigaction action; /* Actions for POSIX signals */
83
#endif /* HAVE_SIGACTION && !HAVE_SIGSET */
84
85
86
/*
87
* Make sure status messages are not buffered...
88
*/
89
90
setbuf(stderr, NULL);
91
92
/*
93
* Ignore SIGPIPE signals...
94
*/
95
96
#ifdef HAVE_SIGSET
97
sigset(SIGPIPE, SIG_IGN);
98
#elif defined(HAVE_SIGACTION)
99
memset(&action, 0, sizeof(action));
100
action.sa_handler = SIG_IGN;
101
sigaction(SIGPIPE, &action, NULL);
102
#else
103
signal(SIGPIPE, SIG_IGN);
104
#endif /* HAVE_SIGSET */
105
106
/*
107
* Check command-line...
108
*/
109
110
if (argc == 1)
111
{
112
printf("network socket \"Unknown\" \"%s\"\n",
113
_cupsLangString(cupsLangDefault(), _("AppSocket/HP JetDirect")));
114
return (CUPS_BACKEND_OK);
115
}
116
else if (argc < 6 || argc > 7)
117
{
118
_cupsLangPrintf(stderr,
119
_("Usage: %s job-id user title copies options [file]"),
120
argv[0]);
121
return (CUPS_BACKEND_FAILED);
122
}
123
124
/*
125
* If we have 7 arguments, print the file named on the command-line.
126
* Otherwise, send stdin instead...
127
*/
128
129
if (argc == 6)
130
{
131
print_fd = 0;
132
copies = 1;
133
}
134
else
135
{
136
/*
137
* Try to open the print file...
138
*/
139
140
if ((print_fd = open(argv[6], O_RDONLY)) < 0)
141
{
142
_cupsLangPrintError("ERROR", _("Unable to open print file"));
143
return (CUPS_BACKEND_FAILED);
144
}
145
146
copies = atoi(argv[4]);
147
}
148
149
/*
150
* Extract the hostname and port number from the URI...
151
*/
152
153
while ((device_uri = cupsBackendDeviceURI(argv)) == NULL)
154
{
155
_cupsLangPrintFilter(stderr, "INFO", _("Unable to locate printer."));
156
sleep(10);
157
158
if (getenv("CLASS") != NULL)
159
return (CUPS_BACKEND_FAILED);
160
}
161
162
httpSeparateURI(HTTP_URI_CODING_ALL, device_uri, scheme, sizeof(scheme),
163
username, sizeof(username), hostname, sizeof(hostname), &port,
164
resource, sizeof(resource));
165
166
if (port == 0)
167
port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */
168
169
/*
170
* Get options, if any...
171
*/
172
173
waiteof = 1;
174
contimeout = 7 * 24 * 60 * 60;
175
176
if ((options = strchr(resource, '?')) != NULL)
177
{
178
/*
179
* Yup, terminate the device name string and move to the first
180
* character of the options...
181
*/
182
183
*options++ = '\0';
184
185
/*
186
* Parse options...
187
*/
188
189
while (*options)
190
{
191
/*
192
* Get the name...
193
*/
194
195
name = options;
196
197
while (*options && *options != '=' && *options != '+' && *options != '&')
198
options ++;
199
200
if ((sep = *options) != '\0')
201
*options++ = '\0';
202
203
if (sep == '=')
204
{
205
/*
206
* Get the value...
207
*/
208
209
value = options;
210
211
while (*options && *options != '+' && *options != '&')
212
options ++;
213
214
if (*options)
215
*options++ = '\0';
216
}
217
else
218
value = (char *)"";
219
220
/*
221
* Process the option...
222
*/
223
224
if (!_cups_strcasecmp(name, "waiteof"))
225
{
226
/*
227
* Set the wait-for-eof value...
228
*/
229
230
waiteof = !value[0] || !_cups_strcasecmp(value, "on") ||
231
!_cups_strcasecmp(value, "yes") || !_cups_strcasecmp(value, "true");
232
}
233
else if (!_cups_strcasecmp(name, "snmp"))
234
{
235
/*
236
* Enable/disable SNMP stuff...
237
*/
238
239
snmp_enabled = !value[0] || !_cups_strcasecmp(value, "on") ||
240
!_cups_strcasecmp(value, "yes") ||
241
!_cups_strcasecmp(value, "true");
242
}
243
else if (!_cups_strcasecmp(name, "contimeout"))
244
{
245
/*
246
* Set the connection timeout...
247
*/
248
249
if (atoi(value) > 0)
250
contimeout = atoi(value);
251
}
252
}
253
}
254
255
/*
256
* Then try finding the remote host...
257
*/
258
259
start_time = time(NULL);
260
261
addrlist = backendLookup(hostname, port, NULL);
262
263
/*
264
* See if the printer supports SNMP...
265
*/
266
267
if (snmp_enabled)
268
snmp_fd = _cupsSNMPOpen(addrlist->addr.addr.sa_family);
269
else
270
snmp_fd = -1;
271
272
if (snmp_fd >= 0)
273
have_supplies = !backendSNMPSupplies(snmp_fd, &(addrlist->addr),
274
&start_count, NULL);
275
else
276
have_supplies = start_count = 0;
277
278
/*
279
* Wait for data from the filter...
280
*/
281
282
if (print_fd == 0)
283
{
284
if (!backendWaitLoop(snmp_fd, &(addrlist->addr), 1, backendNetworkSideCB))
285
return (CUPS_BACKEND_OK);
286
else if ((bytes = read(0, buffer, sizeof(buffer))) <= 0)
287
return (CUPS_BACKEND_OK);
288
}
289
290
/*
291
* Connect to the printer...
292
*/
293
294
fprintf(stderr, "DEBUG: Connecting to %s:%d\n", hostname, port);
295
_cupsLangPrintFilter(stderr, "INFO", _("Connecting to printer."));
296
297
for (delay = 5;;)
298
{
299
if ((addr = httpAddrConnect(addrlist, &device_fd)) == NULL)
300
{
301
error = errno;
302
device_fd = -1;
303
304
if (getenv("CLASS") != NULL)
305
{
306
/*
307
* If the CLASS environment variable is set, the job was submitted
308
* to a class and not to a specific queue. In this case, we want
309
* to abort immediately so that the job can be requeued on the next
310
* available printer in the class.
311
*/
312
313
_cupsLangPrintFilter(stderr, "INFO",
314
_("Unable to contact printer, queuing on next "
315
"printer in class."));
316
317
/*
318
* Sleep 5 seconds to keep the job from requeuing too rapidly...
319
*/
320
321
sleep(5);
322
323
return (CUPS_BACKEND_FAILED);
324
}
325
326
fprintf(stderr, "DEBUG: Connection error: %s\n", strerror(error));
327
328
if (errno == ECONNREFUSED || errno == EHOSTDOWN || errno == EHOSTUNREACH || errno == ETIMEDOUT || errno == ENOTCONN)
329
{
330
if (contimeout && (time(NULL) - start_time) > contimeout)
331
{
332
_cupsLangPrintFilter(stderr, "ERROR",
333
_("The printer is not responding."));
334
return (CUPS_BACKEND_FAILED);
335
}
336
337
switch (error)
338
{
339
case EHOSTDOWN :
340
_cupsLangPrintFilter(stderr, "WARNING",
341
_("The printer may not exist or "
342
"is unavailable at this time."));
343
break;
344
345
case EHOSTUNREACH :
346
default :
347
_cupsLangPrintFilter(stderr, "WARNING",
348
_("The printer is unreachable at this "
349
"time."));
350
break;
351
352
case ECONNREFUSED :
353
_cupsLangPrintFilter(stderr, "WARNING",
354
_("The printer is in use."));
355
break;
356
}
357
358
sleep((unsigned)delay);
359
360
if (delay < 30)
361
delay += 5;
362
}
363
else
364
{
365
_cupsLangPrintFilter(stderr, "ERROR",
366
_("The printer is not responding."));
367
sleep(30);
368
}
369
}
370
else
371
break;
372
}
373
374
fputs("STATE: -connecting-to-device\n", stderr);
375
_cupsLangPrintFilter(stderr, "INFO", _("Connected to printer."));
376
377
fprintf(stderr, "DEBUG: Connected to %s:%d...\n",
378
httpAddrString(&(addr->addr), addrname, sizeof(addrname)),
379
httpAddrPort(&(addr->addr)));
380
381
/*
382
* Print everything...
383
*/
384
385
tbytes = 0;
386
387
if (bytes > 0)
388
tbytes += write(device_fd, buffer, (size_t)bytes);
389
390
while (copies > 0 && tbytes >= 0)
391
{
392
copies --;
393
394
if (print_fd != 0)
395
{
396
fputs("PAGE: 1 1\n", stderr);
397
lseek(print_fd, 0, SEEK_SET);
398
}
399
400
if ((bytes = backendRunLoop(print_fd, device_fd, snmp_fd, &(addrlist->addr), 1, 0, backendNetworkSideCB)) < 0)
401
tbytes = -1;
402
else
403
tbytes = bytes;
404
405
if (print_fd != 0 && tbytes >= 0)
406
_cupsLangPrintFilter(stderr, "INFO", _("Print file sent."));
407
}
408
409
fputs("STATE: +cups-waiting-for-job-completed\n", stderr);
410
411
if (waiteof && tbytes >= 0)
412
{
413
/*
414
* Shutdown the socket and wait for the other end to finish...
415
*/
416
417
_cupsLangPrintFilter(stderr, "INFO", _("Waiting for printer to finish."));
418
419
shutdown(device_fd, 1);
420
421
while (wait_bc(device_fd, 90) > 0);
422
}
423
424
/*
425
* Collect the final page count as needed...
426
*/
427
428
if (have_supplies &&
429
!backendSNMPSupplies(snmp_fd, &(addrlist->addr), &page_count, NULL) &&
430
page_count > start_count)
431
fprintf(stderr, "PAGE: total %d\n", page_count - start_count);
432
433
/*
434
* Close the socket connection...
435
*/
436
437
close(device_fd);
438
439
httpAddrFreeList(addrlist);
440
441
/*
442
* Close the input file and return...
443
*/
444
445
if (print_fd != 0)
446
close(print_fd);
447
448
return (tbytes >= 0 ? CUPS_BACKEND_OK : CUPS_BACKEND_FAILED);
449
}
450
451
452
/*
453
* 'wait_bc()' - Wait for back-channel data...
454
*/
455
456
static ssize_t /* O - # bytes read or -1 on error */
457
wait_bc(int device_fd, /* I - Socket */
458
int secs) /* I - Seconds to wait */
459
{
460
struct timeval timeout; /* Timeout for select() */
461
fd_set input; /* Input set for select() */
462
ssize_t bytes; /* Number of back-channel bytes read */
463
char buffer[1024]; /* Back-channel buffer */
464
465
466
/*
467
* Wait up to "secs" seconds for backchannel data...
468
*/
469
470
timeout.tv_sec = secs;
471
timeout.tv_usec = 0;
472
473
FD_ZERO(&input);
474
FD_SET(device_fd, &input);
475
476
if (select(device_fd + 1, &input, NULL, NULL, &timeout) > 0)
477
{
478
/*
479
* Grab the data coming back and spit it out to stderr...
480
*/
481
482
if ((bytes = read(device_fd, buffer, sizeof(buffer))) > 0)
483
{
484
fprintf(stderr, "DEBUG: Received %d bytes of back-channel data\n",
485
(int)bytes);
486
cupsBackChannelWrite(buffer, (size_t)bytes, 1.0);
487
}
488
489
return (bytes);
490
}
491
else
492
return (-1);
493
}
494
495