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