Home | History | Annotate | Download | only in netpr
      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