lpsend.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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 rv, bcnt;
  118. for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
  119. alarm(WRNETIMEOUT); /* to break hanging */
  120. if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
  121. error(0, "read error during pass, %d remaining\n", bcnt);
  122. break;
  123. } else if((write(outfd, jobbuf, rv)) != rv) {
  124. error(0, "write error during pass, %d remaining\n", bcnt);
  125. break;
  126. }
  127. }
  128. alarm(0);
  129. return(bcnt);
  130. }
  131. /* get whatever stdin has and put it into the temporary file.
  132. * return the file size.
  133. */
  134. int
  135. prereadfile(int inpfd)
  136. {
  137. int rv, bsize;
  138. bsize = 0;
  139. do {
  140. if((rv=read(0, jobbuf, RDSIZE))<0) {
  141. error(0, "read error while making temp file\n");
  142. exits("read error while making temp file");
  143. } else if((write(inpfd, jobbuf, rv)) != rv) {
  144. error(0, "write error while making temp file\n");
  145. exits("write error while making temp file");
  146. }
  147. bsize += rv;
  148. } while (rv!=0);
  149. return(bsize);
  150. }
  151. int
  152. tempfile(void)
  153. {
  154. static tindx = 0;
  155. char tmpf[20];
  156. int tmpfd;
  157. sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
  158. if((tmpfd=create(tmpf,
  159. #ifdef plan9
  160. ORDWR|OTRUNC,
  161. #endif
  162. 0666)) < 0) {
  163. error(0, "cannot create temp file %s\n", tmpf);
  164. exits("cannot create temp file");
  165. }
  166. close(tmpfd);
  167. if((tmpfd=open(tmpf, ORDWR
  168. #ifdef plan9
  169. |ORCLOSE|OTRUNC
  170. #endif
  171. )) < 0) {
  172. error(0, "cannot open temp file %s\n", tmpf);
  173. exits("cannot open temp file");
  174. }
  175. return(tmpfd);
  176. }
  177. int
  178. recvACK(int netfd)
  179. {
  180. int rv;
  181. *jobbuf = '\0';
  182. alarm(RDNETIMEOUT);
  183. if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
  184. error(0, "failed to receive ACK, ");
  185. if (*jobbuf == '\0')
  186. error(1, "read failed\n");
  187. else
  188. error(1, "received <%#x> instead\n", (uchar)*jobbuf);
  189. rv = 0;
  190. } else rv = 1;
  191. alarm(0);
  192. return(rv);
  193. }
  194. void
  195. main(int argc, char *argv[])
  196. {
  197. int i, rv, netfd, bsize, datafd;
  198. #ifndef plan9
  199. void (*oldhandler)();
  200. #endif
  201. /* make connection */
  202. if (argc != 2) {
  203. fprint(stderr, "usage: %s network!destination!service\n",
  204. argv[0]);
  205. exits("usage");
  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 ");
  215. perror(argv[1]);
  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 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 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. }