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