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