lpsend.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. #ifdef plan9
  2. #include <u.h>
  3. #include <libc.h>
  4. #define stderr 2
  5. #define RDNETIMEOUT 60000
  6. #define WRNETIMEOUT 60000
  7. #else
  8. /* not for plan 9 */
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <time.h>
  12. #include <fcntl.h>
  13. #include <signal.h>
  14. #define create creat
  15. #define seek lseek
  16. #define fprint fprintf
  17. #define sprint sprintf
  18. #define exits exit
  19. #define ORDWR O_RDWR
  20. #define OTRUNC O_TRUNC
  21. #define ORCLOSE 0
  22. #define RDNETIMEOUT 60
  23. #define WRNETIMEOUT 60
  24. #endif
  25. #define MIN(a,b) ((a<b)?a:b)
  26. #define ACK(a) write(a, "", 1)
  27. #define NAK(a) write(a, "\001", 1)
  28. #define LPDAEMONLOG "/tmp/lpdaemonl"
  29. #define LNBFSZ 4096
  30. char lnbuf[LNBFSZ];
  31. int dbgstate = 0;
  32. char *dbgstrings[] = {
  33. "",
  34. "rcvack1",
  35. "send",
  36. "rcvack2",
  37. "response",
  38. "done"
  39. };
  40. #ifdef plan9
  41. void
  42. error(int level, char *s1, ...)
  43. {
  44. va_list ap;
  45. long thetime;
  46. char *chartime;
  47. char *args[8];
  48. int argno = 0;
  49. if (level == 0) {
  50. time(&thetime);
  51. chartime = ctime(thetime);
  52. fprint(stderr, "%.15s ", &(chartime[4]));
  53. }
  54. va_start(ap, s1);
  55. while(args[argno++] = va_arg(ap, char*))
  56. ;
  57. va_end(ap);
  58. fprint(stderr, s1, *args);
  59. }
  60. int
  61. alarmhandler(void *foo, char *note) {
  62. USED(foo);
  63. if(strcmp(note, "alarm")==0) {
  64. fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
  65. return(1);
  66. } else return(0);
  67. }
  68. #else
  69. void
  70. error(int level, char *s1, ...)
  71. {
  72. time_t thetime;
  73. char *chartime;
  74. if (level == 0) {
  75. time(&thetime);
  76. chartime = ctime(&thetime);
  77. fprintf(stderr, "%.15s ", &(chartime[4]));
  78. }
  79. fprintf(stderr, s1, &s1 + 1);
  80. }
  81. void
  82. alarmhandler() {
  83. fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
  84. }
  85. #endif
  86. /* get a line from inpfd using nonbuffered input. The line is truncated if it is too
  87. * long for the buffer. The result is left in lnbuf and the number of characters
  88. * read in is returned.
  89. */
  90. int
  91. readline(int inpfd)
  92. {
  93. register char *ap;
  94. register int i;
  95. ap = lnbuf;
  96. i = 0;
  97. do {
  98. if (read(inpfd, ap, 1) != 1) {
  99. error(0, "read error in readline, fd=%d\n", inpfd);
  100. break;
  101. }
  102. } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
  103. if (i == LNBFSZ - 2) {
  104. *ap = '\n';
  105. i++;
  106. }
  107. *ap = '\0';
  108. return(i);
  109. }
  110. #define RDSIZE 512
  111. char jobbuf[RDSIZE];
  112. int
  113. pass(int inpfd, int outfd, int bsize)
  114. {
  115. int bcnt = 0;
  116. int rv = 0;
  117. for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
  118. alarm(WRNETIMEOUT); /* to break hanging */
  119. if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
  120. error(0, "read error during pass, %d remaining\n", bcnt);
  121. break;
  122. } else if((write(outfd, jobbuf, rv)) != rv) {
  123. error(0, "write error during pass, %d remaining\n", bcnt);
  124. break;
  125. }
  126. }
  127. alarm(0);
  128. return(bcnt);
  129. }
  130. /* get whatever stdin has and put it into the temporary file.
  131. * return the file size.
  132. */
  133. int
  134. prereadfile(int inpfd)
  135. {
  136. int rv, bsize;
  137. bsize = 0;
  138. do {
  139. if((rv=read(0, jobbuf, RDSIZE))<0) {
  140. error(0, "read error while making temp file\n");
  141. exits("read error while making temp file");
  142. } else if((write(inpfd, jobbuf, rv)) != rv) {
  143. error(0, "write error while making temp file\n");
  144. exits("write error while making temp file");
  145. }
  146. bsize += rv;
  147. } while (rv!=0);
  148. return(bsize);
  149. }
  150. int
  151. tempfile(void)
  152. {
  153. static tindx = 0;
  154. char tmpf[20];
  155. int tmpfd;
  156. sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
  157. if((tmpfd=create(tmpf,
  158. #ifdef plan9
  159. ORDWR|OTRUNC,
  160. #endif
  161. 0666)) < 0) {
  162. error(0, "cannot create temp file %s\n", tmpf);
  163. exits("cannot create temp file");
  164. }
  165. close(tmpfd);
  166. if((tmpfd=open(tmpf, ORDWR
  167. #ifdef plan9
  168. |ORCLOSE|OTRUNC
  169. #endif
  170. )) < 0) {
  171. error(0, "cannot open temp file %s\n", tmpf);
  172. exits("cannot open temp file");
  173. }
  174. return(tmpfd);
  175. }
  176. int
  177. recvACK(int netfd)
  178. {
  179. int rv;
  180. *jobbuf = '\0';
  181. alarm(RDNETIMEOUT);
  182. if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
  183. error(0, "failed to receive ACK, ");
  184. if (*jobbuf == '\0')
  185. error(1, "read failed\n");
  186. else
  187. error(1, "received <0x%x> instead\n", *jobbuf);
  188. rv = 0;
  189. } else rv = 1;
  190. alarm(0);
  191. return(rv);
  192. }
  193. void
  194. main(int argc, char *argv[])
  195. {
  196. char *devdir;
  197. int i, rv, netfd, bsize;
  198. int datafd;
  199. #ifndef plan9
  200. void (*oldhandler)();
  201. #endif
  202. /* make connection */
  203. if (argc != 2) {
  204. fprint(stderr, "usage: %s network!destination!service\n", argv[0]);
  205. exits("incorrect number of arguments");
  206. }
  207. /* read options line from stdin into lnbuf */
  208. i = readline(0);
  209. /* read stdin into tempfile to get size */
  210. datafd = tempfile();
  211. bsize = prereadfile(datafd);
  212. /* network connection is opened after data is in to avoid timeout */
  213. if ((netfd=dial(argv[1], 0, 0, 0)) < 0) {
  214. fprint(stderr, "dialing %s\n", devdir);
  215. perror("dial");
  216. exits("can't dial");
  217. }
  218. /* write out the options we read above */
  219. if (write(netfd, lnbuf, i) != i) {
  220. error(0, "write error while sending options\n");
  221. exits("write error while sending options");
  222. }
  223. /* send the size of the file to be sent */
  224. sprint(lnbuf, "%d\n", bsize);
  225. i = strlen(lnbuf);
  226. if ((rv=write(netfd, lnbuf, i)) != i) {
  227. perror("write error while sending size");
  228. error(0, "write returned %d\n", rv);
  229. exits("write error while sending size");
  230. }
  231. if (seek(datafd, 0L, 0) < 0) {
  232. error(0, "error seeking temp file\n");
  233. exits("seek error");
  234. }
  235. /* mirror performance in readfile() in lpdaemon */
  236. #ifdef plan9
  237. atnotify(alarmhandler, 1);
  238. #else
  239. oldhandler = signal(SIGALRM, alarmhandler);
  240. #endif
  241. dbgstate = 1;
  242. if(!recvACK(netfd)) {
  243. error(0, "failed to receive ACK before sending data\n");
  244. exits("recv ack1 failed");
  245. }
  246. dbgstate = 2;
  247. if ((i=pass(datafd, netfd, bsize)) != 0) {
  248. NAK(netfd);
  249. error(0, "failed to send %d bytes\n", i);
  250. exits("send data failed");
  251. }
  252. ACK(netfd);
  253. dbgstate = 3;
  254. if(!recvACK(netfd)) {
  255. error(0, "failed to receive ACK after sending data\n");
  256. exits("recv ack2 failed");
  257. }
  258. /* get response, as from lp -q */
  259. dbgstate = 4;
  260. while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
  261. if((write(1, jobbuf, rv)) != rv) {
  262. error(0, "write error while sending to stdout\n");
  263. exits("write error while sending to stdout");
  264. }
  265. }
  266. dbgstate = 5;
  267. #ifdef plan9
  268. atnotify(alarmhandler, 0);
  269. /* close down network connections and go away */
  270. exits("");
  271. #else
  272. signal(SIGALRM, oldhandler);
  273. exit(0);
  274. #endif
  275. }