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