lpsend.c 5.9 KB

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