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