xref: /illumos-gate/usr/src/cmd/lp/model/netpr/net.c (revision edd580643f2cf1434e252cd7779e83182ea84945)
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
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
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
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
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
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
375 null_sighandler(int i)
376 {
377 }
378