lpsend.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. va_end(ap);
  57. fprint(stderr, s1, *args);
  58. return;
  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. return;
  81. }
  82. void
  83. alarmhandler() {
  84. fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
  85. }
  86. #endif
  87. /* get a line from inpfd using nonbuffered input. The line is truncated if it is too
  88. * long for the buffer. The result is left in lnbuf and the number of characters
  89. * read in is returned.
  90. */
  91. int
  92. readline(int inpfd)
  93. {
  94. register char *ap;
  95. register int i;
  96. ap = lnbuf;
  97. i = 0;
  98. do {
  99. if (read(inpfd, ap, 1) != 1) {
  100. error(0, "read error in readline, fd=%d\n", inpfd);
  101. break;
  102. }
  103. } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
  104. if (i == LNBFSZ - 2) {
  105. *ap = '\n';
  106. i++;
  107. }
  108. *ap = '\0';
  109. return(i);
  110. }
  111. #define RDSIZE 512
  112. char jobbuf[RDSIZE];
  113. int
  114. pass(int inpfd, int outfd, int bsize)
  115. {
  116. int bcnt = 0;
  117. int rv = 0;
  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 <0x%x> instead\n", *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. char *devdir;
  198. int i, rv, netfd, bsize;
  199. int 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", argv[0]);
  206. exits("incorrect number of arguments");
  207. }
  208. /* read options line from stdin into lnbuf */
  209. i = readline(0);
  210. /* read stdin into tempfile to get size */
  211. datafd = tempfile();
  212. bsize = prereadfile(datafd);
  213. /* network connection is opened after data is in to avoid timeout */
  214. if ((netfd=dial(argv[1], 0, 0, 0)) < 0) {
  215. fprint(stderr, "dialing %s\n", devdir);
  216. perror("dial");
  217. exits("can't dial");
  218. }
  219. /* write out the options we read above */
  220. if (write(netfd, lnbuf, i) != i) {
  221. error(0, "write error while sending options\n");
  222. exits("write error while sending options");
  223. }
  224. /* send the size of the file to be sent */
  225. sprint(lnbuf, "%d\n", bsize);
  226. i = strlen(lnbuf);
  227. if ((rv=write(netfd, lnbuf, i)) != i) {
  228. perror("write error while sending size");
  229. error(0, "write returned %d\n", rv);
  230. exits("write error while sending size");
  231. }
  232. if (seek(datafd, 0L, 0) < 0) {
  233. error(0, "error seeking temp file\n");
  234. exits("seek error");
  235. }
  236. /* mirror performance in readfile() in lpdaemon */
  237. #ifdef plan9
  238. atnotify(alarmhandler, 1);
  239. #else
  240. oldhandler = signal(SIGALRM, alarmhandler);
  241. #endif
  242. dbgstate = 1;
  243. if(!recvACK(netfd)) {
  244. error(0, "failed to receive ACK before sending data\n");
  245. exits("recv ack1 failed");
  246. }
  247. dbgstate = 2;
  248. if ((i=pass(datafd, netfd, bsize)) != 0) {
  249. NAK(netfd);
  250. error(0, "failed to send %d bytes\n", i);
  251. exits("send data failed");
  252. }
  253. ACK(netfd);
  254. dbgstate = 3;
  255. if(!recvACK(netfd)) {
  256. error(0, "failed to receive ACK after sending data\n");
  257. exits("recv ack2 failed");
  258. }
  259. /* get response, as from lp -q */
  260. dbgstate = 4;
  261. while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
  262. if((write(1, jobbuf, rv)) != rv) {
  263. error(0, "write error while sending to stdout\n");
  264. exits("write error while sending to stdout");
  265. }
  266. }
  267. dbgstate = 5;
  268. #ifdef plan9
  269. atnotify(alarmhandler, 0);
  270. /* close down network connections and go away */
  271. exits("");
  272. #else
  273. signal(SIGALRM, oldhandler);
  274. exit(0);
  275. #endif
  276. }