1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <libintl.h>
33 #include <signal.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <syslog.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/file.h>
43 #include <netinet/in.h>
44 #include "netpr.h"
45
46 #define TIMEOUT 1
47
48 static int netpr_send_message(int, char *, ...);
49 static int xfer_cfAfile(int, char *, char *, uint);
50
51 int
bsd_print(int sockfd,caddr_t pa,np_bsdjob_t * bsdjob)52 bsd_print(int sockfd, caddr_t pa, np_bsdjob_t * bsdjob)
53 {
54 int filesize;
55 int xfer;
56 int net;
57
58 syslog(LOG_DEBUG, "bsd_print");
59
60 filesize = bsdjob->np_data->np_data_size;
61 syslog(LOG_DEBUG, "filesize is %d", filesize);
62
63
64 if (netpr_send_message(sockfd, "%c%s\n", XFER_REQUEST,
65 bsdjob->np_printer) != 0) {
66 return (NETWORK_ERROR_SEND_RESPONSE);
67 }
68
69 /*
70 * control file
71 */
72
73 if (bsdjob->np_print_order == CONTROL_FIRST) {
74 if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
75 bsdjob->np_cfAfilename,
76 bsdjob->np_cfAfilesize)) != 0) {
77 (void) fprintf(stderr,
78 gettext("Netpr: Error sending control file\n"));
79 syslog(LOG_DEBUG, "Error sending control file");
80 return (NETWORK_ERROR_UNKNOWN);
81
82 }
83 }
84
85 /* send msg - get ready for transfer */
86
87 if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_DATA, filesize,
88 bsdjob->np_data->np_dfAfilename)) != 0) {
89 return (NETWORK_ERROR_SEND_RESPONSE);
90 }
91
92 /*
93 * send the file
94 */
95
96 if ((xfer = xfer_file(sockfd, pa, filesize, bsdjob->np_timeout)) != 0) {
97 return (xfer);
98 }
99
100 /* send msg - done */
101 if ((net = netpr_send_message(sockfd, "", NULL)) != 0) {
102 (void) fprintf(stderr,
103 gettext("Netpr: network error transfering %s returns: %d\n"),
104 bsdjob->np_filename, net);
105 syslog(LOG_DEBUG,
106 "network error transfering %s returns: %d",
107 bsdjob->np_filename, net);
108 return (NETWORK_ERROR_WRITE_FAILED);
109 }
110
111 /*
112 * control file
113 */
114
115 if (bsdjob->np_print_order == DATA_FIRST) {
116 if ((xfer_cfAfile(sockfd, bsdjob->np_cfAfile,
117 bsdjob->np_cfAfilename,
118 bsdjob->np_cfAfilesize)) != 0) {
119
120 (void) fprintf(stderr,
121 gettext("Netpr: Error sending control file\n"));
122 syslog(LOG_DEBUG, "Error sending control file");
123 return (NETWORK_ERROR_UNKNOWN);
124 }
125 }
126
127 return (0);
128 }
129
130 int
xfer_file(int sockfd,caddr_t pa,int filesize,int seed)131 xfer_file(int sockfd, caddr_t pa, int filesize, int seed)
132 {
133 int ctr;
134 int timeout;
135 int nw;
136 int error_msg = 0;
137 int pause = 0;
138
139 syslog(LOG_DEBUG, "xfer_file");
140
141 /* send file */
142 ctr = filesize;
143 timeout = seed = seed ? seed : 10;
144
145 while (ctr > 0) {
146
147 syslog(LOG_DEBUG, "xfer_file: write while loop => ctr = %d", ctr);
148 syslog(LOG_DEBUG, "xfer_file: timeout = %d", timeout);
149
150 (void) signal(SIGALRM, null_sighandler);
151 (void) alarm(10);
152 nw = write(sockfd, pa, ctr);
153 syslog(LOG_DEBUG, "xfer_file: write while loop => nw = %d", nw);
154 (void) alarm(0);
155 if ((nw == 0) || (nw < 0)) {
156 if (timeout < (seed * 4)) {
157 (void) sleep(timeout);
158 timeout *= 2;
159 } else if (timeout == (seed * 4)) {
160 (void) sleep(timeout);
161 timeout *= 2;
162
163 /*
164 * Send message to user once
165 */
166 if (error_msg == 0) {
167 error_msg++;
168 tell_lptell(ERRORMSG,
169 gettext("Printer not accepting input;"
170 "possibly offline or out of paper."));
171 }
172
173 } else if (timeout > (seed * 4)) {
174 (void) sleep(timeout);
175 if (pause++ > 3)
176 timeout = (seed * 10);
177 }
178
179 } else {
180 ctr -= nw;
181 pa += nw;
182 if (error_msg) {
183 tell_lptell(OKMSG, "Current");
184 error_msg = 0;
185 pause = 0;
186 }
187 timeout = seed;
188 }
189 }
190
191 return (E_SUCCESS);
192 }
193
194 static int
xfer_cfAfile(int sockfd,char * cfAfile,char * cfAname,uint size)195 xfer_cfAfile(int sockfd, char * cfAfile, char * cfAname, uint size)
196 {
197 int ctr;
198 caddr_t pa;
199 int nw = 0;
200 int timeout;
201 int printererr;
202
203 syslog(LOG_DEBUG, "xfer_cfAfile");
204
205 if ((netpr_send_message(sockfd, "%c%d %s\n", XFER_CONTROL,
206 size, cfAname)) != 0) {
207 return (NETWORK_ERROR_MSG_FAILED);
208 }
209
210 /* send the control file */
211 pa = cfAfile;
212 ctr = size;
213 syslog(LOG_DEBUG, "xfer_cfAfile : cfAfile %s", pa);
214 syslog(LOG_DEBUG, "xfer_cfAfile : size %d", size);
215
216 /* send control file */
217 timeout = TIMEOUT;
218 printererr = 0;
219 while (ctr > 0) {
220 (void) signal(SIGALRM, null_sighandler);
221 (void) alarm(2);
222 nw = write(sockfd, pa, size);
223 (void) alarm(0);
224 if (nw <= 0) {
225 if (timeout < 16) {
226 (void) sleep(timeout);
227 timeout *= 2;
228 } else if (timeout == 16) {
229 /* talk with the printer and see what's happening */
230 /* send message back to caller */
231 (void) sleep(timeout);
232 timeout *= 2;
233 printererr = 1;
234
235 tell_lptell(ERRORMSG,
236 gettext("Printer not accepting input;"
237 "possibly offline or out of paper."));
238
239 } else if (timeout > 16) {
240 (void) sleep(timeout);
241 }
242 }
243 ctr -= nw;
244 pa += nw;
245 }
246
247 if (printererr == 1) {
248 (void) fprintf(stderr, gettext("Printer status ok\n"));
249 tell_lptell(OKMSG, "Current");
250 }
251
252
253 /* send msg - done */
254 if (netpr_send_message(sockfd, "", NULL) != 0) {
255 return (NETWORK_ERROR_MSG_FAILED);
256 }
257
258 return (0);
259 }
260
261 /*
262 * netpr_response() reads in a byte from the network printer
263 */
264 static int
netpr_response(int nd)265 netpr_response(int nd)
266 {
267 char c;
268 int msg_given = 0;
269 int firstloop = 0;
270
271 syslog(LOG_DEBUG, "netpr_response");
272
273 (void) signal(SIGALRM, null_sighandler);
274 (void) alarm(2);
275 while (1) {
276 errno = 0;
277 if ((read(nd, &c, 1) != 1)) {
278
279 if (firstloop == 0) {
280 (void) alarm(0);
281 firstloop++;
282 }
283
284 if (errno == EINTR) {
285 if (msg_given == 0) {
286 tell_lptell(ERRORMSG,
287 gettext("Printer not responding;"
288 "Either warming up or needs attention"));
289 msg_given++;
290 syslog(LOG_DEBUG,
291 "read hanging in netpr_response: %m");
292 }
293
294 } else {
295 syslog(LOG_DEBUG,
296 "read in netpr_response failed: %m");
297 return (NETWORK_READ_RESPONSE_FAILED);
298 }
299
300 } else {
301 if (c) {
302 syslog(LOG_DEBUG,
303 "Printer returned error: %m");
304 return (NETWORK_PRINTER_REFUSED_CONN);
305 } else {
306 if (msg_given)
307 tell_lptell(OKMSG, "Current");
308 return (0);
309 }
310 }
311 }
312
313 }
314
315 static int
netpr_send_message(int nd,char * fmt,...)316 netpr_send_message(int nd, char *fmt, ...)
317 {
318 char buf[BUFSIZ];
319 int ctr;
320 char * pa;
321 va_list ap;
322 int timeout = 1;
323 int nw;
324 int err_msg = 0;
325
326 syslog(LOG_DEBUG, "netpr_send_message");
327 va_start(ap, fmt);
328 (void) vsnprintf(buf, sizeof (buf), fmt, ap);
329 va_end(ap);
330
331 pa = buf;
332 ctr = (strlen(buf) != 0) ? strlen(buf) : 1;
333
334 syslog(LOG_DEBUG, "netpr_send_message : ctr = %d", ctr);
335 while (ctr > 0) {
336 (void) signal(SIGALRM, null_sighandler);
337 (void) alarm(2);
338 nw = write(nd, pa, ctr);
339 syslog(LOG_DEBUG, "netpr_send_message : nw = %d", nw);
340 (void) alarm(0);
341
342 if (nw <= 0) {
343 if (timeout < 16) {
344 (void) sleep(timeout);
345 timeout *= 2;
346 } else if (timeout == 16) {
347 (void) sleep(timeout);
348 timeout *= 2;
349 if (err_msg == 0) {
350 err_msg++;
351 tell_lptell(ERRORMSG,
352 gettext("Printer not accepting input;"
353 "possibly offline or out of paper."));
354 }
355 } else
356 (void) sleep(timeout);
357 } else {
358 ctr -= nw;
359 pa += nw;
360 if (err_msg)
361 tell_lptell(OKMSG, "Current");
362 }
363 }
364
365 return (netpr_response(nd));
366 }
367
368 /*
369 * null() is to be used as a signal handler that does nothing. It is used in
370 * place of SIG_IGN, because we want the signal to be delivered and
371 * interupt the current system call.
372 */
373 /*ARGSUSED*/
374 void
null_sighandler(int i)375 null_sighandler(int i)
376 {
377 }
378