tcpostio.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. #define _BSD_EXTENSION
  2. #define _NET_EXTENSION
  3. #define _POSIX_SOURCE
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. #include <signal.h>
  11. #include <errno.h>
  12. #include <select.h>
  13. #include <sys/types.h>
  14. #include <sys/time.h>
  15. #include <sys/socket.h>
  16. #include <sys/wait.h>
  17. extern int dial_debug;
  18. extern int dial(char*, char*, char*, int*);
  19. /* debug = 0 for no debugging */
  20. /* debug = 1 for readprinter debugging */
  21. /* debug = 2 for sendprinter debugging */
  22. /* debug = 3 for full debugging, its hard to read the messages */
  23. int debug = 0;
  24. #define READTIMEOUT 300
  25. #define RCVSELTIMEOUT 30
  26. #define SNDSELTIMEOUT 300
  27. void
  28. rdtmout(void) {
  29. fprintf(stderr, "read timeout occurred, check printer\n");
  30. }
  31. int
  32. getline(int fd, char *buf, int len) {
  33. char *bp, c;
  34. int i = 0, n;
  35. bp = buf;
  36. while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) {
  37. alarm(0);
  38. if (*bp == '\r') continue;
  39. i += n;
  40. c = *bp++;
  41. if (c == '\n' || c == '\004' || i >= len-1)
  42. break;
  43. }
  44. alarm(0);
  45. if (n < 0)
  46. return(n);
  47. *bp = '\0';
  48. return(i);
  49. }
  50. typedef struct {
  51. char *state; /* printer's current status */
  52. int val; /* value returned by getstatus() */
  53. } Status;
  54. /* printer states */
  55. #define INITIALIZING 0
  56. #define IDLE 1
  57. #define BUSY 2
  58. #define WAITING 3
  59. #define PRINTING 4
  60. #define PRINTERERROR 5
  61. #define ERROR 6
  62. #define FLUSHING 7
  63. #define UNKNOWN 8
  64. /* protocol requests and program states */
  65. #define START 'S'
  66. unsigned char Start[] = { START };
  67. #define ID_LE 'L'
  68. unsigned char Id_le[] = { ID_LE };
  69. #define REQ_STAT 'T'
  70. unsigned char Req_stat[] = { REQ_STAT };
  71. #define SEND_DATA 'D'
  72. unsigned char Send_data[] = { SEND_DATA };
  73. #define SENT_DATA 'A'
  74. unsigned char Sent_data[] = { SENT_DATA };
  75. #define WAIT_FOR_EOJ 'W'
  76. unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ };
  77. #define END_OF_JOB 'E'
  78. unsigned char End_of_job[] = { END_OF_JOB };
  79. #define FATAL_ERROR 'F'
  80. unsigned char Fatal_error[] = { FATAL_ERROR };
  81. #define WAIT_FOR_IDLE 'I'
  82. unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE };
  83. #define OVER_AND_OUT 'O'
  84. unsigned char Over_and_out[] = { OVER_AND_OUT };
  85. Status statuslist[] = {
  86. "initializing", INITIALIZING,
  87. "idle", IDLE,
  88. "busy", BUSY,
  89. "waiting", WAITING,
  90. "printing", PRINTING,
  91. "printererror", PRINTERERROR,
  92. "Error", ERROR,
  93. "flushing", FLUSHING,
  94. NULL, UNKNOWN
  95. };
  96. /* find returns a pointer to the location of string str2 in string str1,
  97. * if it exists. Otherwise, it points to the end of str1.
  98. */
  99. char *
  100. find(char *str1, char *str2) {
  101. char *s1, *s2;
  102. for (; *str1!='\0'; str1++) {
  103. for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ;
  104. if ( *s2 == '\0' )
  105. break;
  106. }
  107. return(str1);
  108. }
  109. #define MESGSIZE 16384
  110. int blocksize = 1920; /* 19200/10, with 1 sec delay between transfers
  111. * this keeps the queues from building up.
  112. */
  113. char mesg[MESGSIZE]; /* exactly what came back on ttyi */
  114. int
  115. parsmesg(char *buf) {
  116. static char sbuf[MESGSIZE];
  117. char *s; /* start of printer messsage in mesg[] */
  118. char *e; /* end of printer message in mesg[] */
  119. char *key, *val; /* keyword/value strings in sbuf[] */
  120. char *p; /* for converting to lower case etc. */
  121. int i; /* where *key was found in statuslist[] */
  122. if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') {
  123. strcpy(sbuf, s+3); /* don't change mesg[] */
  124. sbuf[e-(s+3)] = '\0'; /* ignore the trailing " ]%" */
  125. for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :")) {
  126. if (strcmp(key, "Error") == 0)
  127. return(ERROR);
  128. if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0)
  129. key = val;
  130. for (; *key == ' '; key++) ; /* skip any leading spaces */
  131. for (p = key; *p; p++) /* convert to lower case */
  132. if (*p == ':') {
  133. *p = '\0';
  134. break;
  135. } else if (isupper(*p)) *p = tolower(*p);
  136. for (i=0; statuslist[i].state != NULL; i++) {
  137. if (strcmp(statuslist[i].state, key) == 0)
  138. return(statuslist[i].val);
  139. }
  140. }
  141. }
  142. return(UNKNOWN);
  143. }
  144. char buf[MESGSIZE];
  145. fd_set readfds, writefds, exceptfds;
  146. struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 };
  147. struct timeval sndtimeout = { SNDSELTIMEOUT, 0 };
  148. int
  149. readprinter(int printerfd, int pipefd)
  150. {
  151. unsigned char proto;
  152. int progstate = START;
  153. int print_wait_msg = 0;
  154. int tocount = 0;
  155. int c, printstat, lastprintstat, n, nfds;
  156. nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
  157. printstat = 0;
  158. signal(SIGALRM, rdtmout);
  159. do {
  160. reselect:
  161. /* ask sending process to request printer status */
  162. if (write(pipefd, Req_stat, 1) != 1) {
  163. fprintf(stderr, "request status failed\n");
  164. progstate = FATAL_ERROR;
  165. continue;
  166. }
  167. FD_ZERO(&readfds); /* lets be anal */
  168. FD_SET(printerfd, &readfds);
  169. FD_SET(pipefd, &readfds);
  170. FD_ZERO(&exceptfds);
  171. FD_SET(printerfd, &exceptfds);
  172. FD_SET(pipefd, &exceptfds);
  173. n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout);
  174. if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n);
  175. if (n == 0) {
  176. /* a timeout occurred */
  177. if (++tocount > 4) {
  178. fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n");
  179. tocount = 0;
  180. }
  181. goto reselect;
  182. }
  183. if (n > 0 && FD_ISSET(printerfd, &exceptfds)) {
  184. /* printer problem */
  185. fprintf(stderr, "printer exception\n");
  186. if (write(pipefd, Fatal_error, 1) != 1) {
  187. fprintf(stderr, "'fatal error' write to pipe failed\n");
  188. }
  189. progstate = FATAL_ERROR;
  190. continue;
  191. }
  192. if (n > 0 && FD_ISSET(pipefd, &exceptfds)) {
  193. /* pipe problem */
  194. fprintf(stderr, "pipe exception\n");
  195. progstate = FATAL_ERROR;
  196. continue;
  197. }
  198. if (n > 0 && FD_ISSET(pipefd, &readfds)) {
  199. /* protocol pipe wants to be read */
  200. if (debug&0x1) fprintf(stderr, "pipe wants to be read\n");
  201. if (read(pipefd, &proto, 1) != 1) {
  202. fprintf(stderr, "read protocol pipe failed\n");
  203. progstate = FATAL_ERROR;
  204. continue;
  205. }
  206. if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto);
  207. /* change state? */
  208. switch (proto) {
  209. case SENT_DATA:
  210. break;
  211. case WAIT_FOR_EOJ:
  212. if (!print_wait_msg) {
  213. print_wait_msg = 1;
  214. fprintf(stderr, "waiting for end of job\n");
  215. }
  216. progstate = proto;
  217. break;
  218. default:
  219. fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto);
  220. break;
  221. }
  222. n--;
  223. }
  224. if (n > 0 && FD_ISSET(printerfd, &readfds)) {
  225. /* printer wants to be read */
  226. if (debug&0x1) fprintf(stderr, "printer wants to be read\n");
  227. if ((c=getline(printerfd, buf, MESGSIZE)) < 0) {
  228. fprintf(stderr, "read printer failed\n");
  229. progstate = FATAL_ERROR;
  230. continue;
  231. }
  232. if (debug&0x1) fprintf(stderr, "%s\n", buf);
  233. if (c==1 && *buf == '\004') {
  234. if (progstate == WAIT_FOR_EOJ) {
  235. if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate);
  236. fprintf(stderr, "%%[ status: endofjob ]%%\n");
  237. /* progstate = WAIT_FOR_IDLE; */
  238. progstate = OVER_AND_OUT;
  239. if (write(pipefd, Over_and_out, 1) != 1) {
  240. fprintf(stderr, "'fatal error' write to pipe failed\n");
  241. }
  242. continue;
  243. } else {
  244. if (printstat == ERROR) {
  245. progstate = FATAL_ERROR;
  246. continue;
  247. }
  248. if (progstate != START && progstate != WAIT_FOR_IDLE)
  249. fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate);
  250. }
  251. continue;
  252. }
  253. /* figure out if it was a status line */
  254. lastprintstat = printstat;
  255. printstat = parsmesg(buf);
  256. if (printstat == UNKNOWN || printstat == ERROR
  257. || lastprintstat != printstat) {
  258. /* print whatever it is that was read */
  259. fprintf(stderr, buf);
  260. fflush(stderr);
  261. if (printstat == UNKNOWN) {
  262. printstat = lastprintstat;
  263. continue;
  264. }
  265. }
  266. switch (printstat) {
  267. case UNKNOWN:
  268. continue; /* shouldn't get here */
  269. case FLUSHING:
  270. case ERROR:
  271. progstate = FATAL_ERROR;
  272. /* ask sending process to die */
  273. if (write(pipefd, Fatal_error, 1) != 1) {
  274. fprintf(stderr, "Fatal_error mesg write to pipe failed\n");
  275. }
  276. continue;
  277. case INITIALIZING:
  278. case PRINTERERROR:
  279. sleep(1);
  280. break;
  281. case IDLE:
  282. if (progstate == WAIT_FOR_IDLE) {
  283. progstate = OVER_AND_OUT;
  284. if (write(pipefd, Over_and_out, 1) != 1) {
  285. fprintf(stderr, "'fatal error' write to pipe failed\n");
  286. }
  287. continue;
  288. }
  289. progstate = SEND_DATA;
  290. goto dowait;
  291. case BUSY:
  292. case WAITING:
  293. default:
  294. sleep(1);
  295. dowait:
  296. switch (progstate) {
  297. case WAIT_FOR_IDLE:
  298. case WAIT_FOR_EOJ:
  299. case START:
  300. sleep(5);
  301. break;
  302. case SEND_DATA:
  303. if (write(pipefd, Send_data, 1) != 1) {
  304. fprintf(stderr, "send data write to pipe failed\n");
  305. progstate = FATAL_ERROR;
  306. continue;
  307. }
  308. break;
  309. default:
  310. fprintf(stderr, "unexpected program state %c\n", progstate);
  311. exit(1);
  312. }
  313. break;
  314. }
  315. n--;
  316. }
  317. if (n > 0) {
  318. fprintf(stderr, "more fds selected than requested!\n");
  319. exit(1);
  320. };
  321. } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
  322. if (progstate == FATAL_ERROR)
  323. return(1);
  324. else
  325. return(0);
  326. }
  327. int
  328. sendfile(int infd, int printerfd, int pipefd)
  329. {
  330. unsigned char proto;
  331. int progstate = START;
  332. int i, n, nfds;
  333. int bytesread, bytesent = 0;
  334. nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
  335. if (write(printerfd, "\004", 1)!=1) {
  336. perror("sendfile:write:");
  337. progstate = FATAL_ERROR;
  338. }
  339. do {
  340. FD_ZERO(&readfds); /* lets be anal */
  341. FD_SET(pipefd, &readfds);
  342. n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout);
  343. if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n);
  344. if (n > 0 && FD_ISSET(pipefd, &readfds)) {
  345. /* protocol pipe wants to be read */
  346. if (read(pipefd, &proto, 1) != 1) {
  347. fprintf(stderr, "read protocol pipe failed\n");
  348. return(1);
  349. }
  350. /* change state? */
  351. if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto);
  352. switch (proto) {
  353. case OVER_AND_OUT:
  354. case END_OF_JOB:
  355. progstate = proto;
  356. break;
  357. case SEND_DATA:
  358. bytesread = 0;
  359. do {
  360. i = read(infd, &buf[bytesread], blocksize-bytesread);
  361. if (debug&02) fprintf(stderr, "read %d bytes\n", i);
  362. if (i > 0)
  363. bytesread += i;
  364. } while((i > 0) && (bytesread < blocksize));
  365. if (i < 0) {
  366. fprintf(stderr, "input file read error\n");
  367. progstate = FATAL_ERROR;
  368. break; /* from switch */
  369. }
  370. if (bytesread > 0) {
  371. if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread);
  372. if (write(printerfd, buf, bytesread)!=bytesread) {
  373. perror("sendfile:write:");
  374. progstate = FATAL_ERROR;
  375. } else if (write(pipefd, Sent_data, 1)!=1) {
  376. perror("sendfile:write:");
  377. progstate = FATAL_ERROR;
  378. } else {
  379. bytesent += bytesread;
  380. }
  381. fprintf(stderr, "%d sent\n", bytesent);
  382. fflush(stderr);
  383. /* we have reached the end of the input file */
  384. }
  385. if (i == 0) {
  386. if (progstate != WAIT_FOR_EOJ) {
  387. if (write(printerfd, "\004", 1)!=1) {
  388. perror("sendfile:write:");
  389. progstate = FATAL_ERROR;
  390. } else if (write(pipefd, Wait_for_eoj, 1)!=1) {
  391. perror("sendfile:write:");
  392. progstate = FATAL_ERROR;
  393. } else {
  394. progstate = WAIT_FOR_EOJ;
  395. }
  396. }
  397. }
  398. break;
  399. case REQ_STAT:
  400. if (write(printerfd, "\024", 1)!=1) {
  401. fprintf(stderr, "write to printer failed\n");
  402. progstate = FATAL_ERROR;
  403. }
  404. if (debug&02) fprintf(stderr, "^T");
  405. break;
  406. case FATAL_ERROR:
  407. progstate = FATAL_ERROR;
  408. }
  409. } else if (n < 0) {
  410. perror("sendfile:select:");
  411. progstate = FATAL_ERROR;
  412. } else if (n == 0) {
  413. sleep(1);
  414. fprintf(stderr, "sendfile timeout\n");
  415. progstate = FATAL_ERROR;
  416. }
  417. } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
  418. if (write(printerfd, "\004", 1)!=1) {
  419. perror("sendfile:write:");
  420. progstate = FATAL_ERROR;
  421. }
  422. if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent);
  423. if (progstate == FATAL_ERROR)
  424. return(1);
  425. else
  426. return(0);
  427. }
  428. void main(int argc, char *argv[]) {
  429. int c, usgflg=0, infd, printerfd;
  430. int cpid, sprv;
  431. int pipefd[2];
  432. char *dialstr;
  433. unsigned long rprv;
  434. dialstr = 0;
  435. while ((c = getopt(argc, argv, "b:d:")) != -1)
  436. switch (c) {
  437. case 'b':
  438. blocksize = atoi(optarg)/10;
  439. if (blocksize > MESGSIZE || blocksize < 1)
  440. blocksize = MESGSIZE;
  441. break;
  442. case 'd':
  443. debug = atoi(optarg);
  444. dial_debug = debug;
  445. break;
  446. case '?':
  447. fprintf(stderr, "unknown option %c\n", c);
  448. usgflg++;
  449. break;
  450. }
  451. if (optind < argc)
  452. dialstr = argv[optind++];
  453. else
  454. usgflg++;
  455. if (usgflg) {
  456. fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n",
  457. argv[0]);
  458. exit (2);
  459. }
  460. if (optind < argc) {
  461. infd = open(argv[optind], 0);
  462. if (infd < 0) {
  463. fprintf(stderr, "cannot open %s\n", argv[optind]);
  464. exit(1);
  465. }
  466. optind++;
  467. } else
  468. infd = 0;
  469. if (debug & 02)
  470. fprintf(stderr, "blocksize=%d\n", blocksize);
  471. if (debug)
  472. fprintf(stderr, "dialing address=%s\n", dialstr);
  473. printerfd = dial(dialstr, 0, 0, 0);
  474. if (printerfd < 0)
  475. exit(1);
  476. fprintf(stderr, "printer startup\n");
  477. if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) {
  478. perror("socketpair");
  479. exit(1);
  480. }
  481. switch(cpid = fork()){
  482. case -1:
  483. perror("fork error");
  484. exit(1);
  485. case 0: /* child - to printer */
  486. close(pipefd[1]);
  487. sprv = sendfile(infd, printerfd, pipefd[0]);
  488. if (debug)
  489. fprintf(stderr, "to remote - exiting\n");
  490. exit(sprv);
  491. default: /* parent - from printer */
  492. close(pipefd[0]);
  493. rprv = readprinter(printerfd, pipefd[1]);
  494. if (debug)
  495. fprintf(stderr, "from remote - exiting\n");
  496. while(wait(&sprv) != cpid)
  497. ;
  498. exit(rprv|sprv);
  499. }
  500. }