summaryrefslogtreecommitdiff
path: root/sys/src/cmd/postscript/tcpostio
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/postscript/tcpostio
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/postscript/tcpostio')
-rwxr-xr-xsys/src/cmd/postscript/tcpostio/dial.c109
-rwxr-xr-xsys/src/cmd/postscript/tcpostio/mkfile16
-rwxr-xr-xsys/src/cmd/postscript/tcpostio/tcpostio.c534
3 files changed, 659 insertions, 0 deletions
diff --git a/sys/src/cmd/postscript/tcpostio/dial.c b/sys/src/cmd/postscript/tcpostio/dial.c
new file mode 100755
index 000000000..da885d9b6
--- /dev/null
+++ b/sys/src/cmd/postscript/tcpostio/dial.c
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/time.h>
+
+#define DIALTIMEOUT 30
+
+/* This is a dummy routine for non Plan9 systems.
+ * No attempt has been made to be clever, it's just
+ * supposed to work in this program.
+ */
+int dial_debug = 0;
+
+int
+dial(char *dest, char *local, char *dir, int *cfdp) {
+ int sockconn, lport;
+ struct hostent *hp; /* Pointer to host info */
+ struct sockaddr_in sin; /* Socket address, Internet style */
+ struct servent *sp = 0;
+ char *tdest, *netname, *hostname, *servname;
+ int sock_type;
+#ifndef plan9
+#define USED(x) if(x); else
+ int sockoption, sockoptsize;
+#endif
+
+ USED(dir);
+ USED(cfdp);
+ if ((tdest = malloc(strlen(dest)+1)) == NULL) {
+ if (dial_debug) fprintf(stderr, "dial: could not allocate memory\n");
+ return(-1);
+ }
+ strcpy(tdest, dest);
+
+ if ((netname = strtok(tdest, "!")) == NULL) {
+ fprintf(stderr, "dial: no network name\n");
+ return(-1);
+ }
+ if (strcmp(netname, "tcp") == 0) {
+ sock_type = SOCK_STREAM;
+ } else if (strcmp(netname, "udp") == 0) {
+ sock_type = SOCK_DGRAM;
+ } else {
+ fprintf(stderr, "dial: network protocol name `%s' is invalid; must be `tcp' or `udp'\n", netname);
+ return(-1);
+ }
+ if ((hostname = strtok(0, "!")) == NULL) {
+ fprintf(stderr, "dial: no host name or number\n");
+ return(-1);
+ }
+ if ((servname = strtok(0, "!")) == NULL) {
+ fprintf(stderr, "dial: no service name or number\n");
+ return(-1);
+ }
+ hp = gethostbyname(hostname);
+ if (hp == (struct hostent *)NULL) {
+ if (dial_debug) fprintf(stderr, "host `%s' unknown by local host\n", hostname);
+ return(-1);
+ }
+ if (!isdigit(servname[0]))
+ sp = getservbyname(servname, netname);
+ sin.sin_addr.s_addr = *(unsigned long*)hp->h_addr;
+ sin.sin_port = htons((sp==0)?atoi(servname):sp->s_port);
+ sin.sin_family = AF_INET;
+ if (local == NULL) {
+ if ((sockconn = socket(AF_INET, sock_type, 0)) < 0) {
+ if (dial_debug) perror("dial:socket():");
+ return(-1);
+ }
+ if (dial_debug) fprintf(stderr, "socket FD=%d\n", sockconn);
+ } else {
+ lport = atoi(local);
+ if ((lport < 512) || (lport >= 1024)) {
+ fprintf(stderr, "dial:invalid local port %d\n", lport);
+ return(-1);
+ }
+ if ((sockconn = rresvport(&lport)) < 0) {
+ if (dial_debug) perror("dial:rresvport():");
+ return(-1);
+ }
+ }
+ if (dial_debug) {
+ fprintf(stderr, "sin size=%d\n", sizeof(sin));
+ }
+ alarm(DIALTIMEOUT);
+ if ((connect(sockconn, (struct sockaddr *) &sin, sizeof(sin)) < 0)) {
+ if (dial_debug) perror("dial:connect():");
+ return(-1);
+ }
+ alarm(0);
+#ifndef plan9
+ sockoptsize = sizeof(sockoption);
+ if (getsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, &sockoptsize) < 0) {
+ if (dial_debug) perror("dial:getsockopt():");
+ return(-1);
+ }
+ if (sockoptsize == sizeof(sockoption) && !sockoption) {
+ if (setsockopt(sockconn, SOL_SOCKET, SO_KEEPALIVE, &sockoption, sockoptsize) < 0) {
+ if (dial_debug) perror("dial:getsockopt():");
+ return(-1);
+ }
+ }
+#endif
+ return(sockconn);
+}
diff --git a/sys/src/cmd/postscript/tcpostio/mkfile b/sys/src/cmd/postscript/tcpostio/mkfile
new file mode 100755
index 000000000..539f5907d
--- /dev/null
+++ b/sys/src/cmd/postscript/tcpostio/mkfile
@@ -0,0 +1,16 @@
+</$objtype/mkfile
+
+<../config
+
+TARG=tcpostio
+OFILES= tcpostio.$O\
+ dial.$O\
+
+BIN=$POSTBIN
+
+</sys/src/cmd/mkone
+CC=pcc
+CFLAGS=-Bw -c -D_BSD_EXTENSION -D_NET_EXTENSION -Dplan9
+
+syms:V:
+ vc $CFLAGS -a tcpostio.c > syms
diff --git a/sys/src/cmd/postscript/tcpostio/tcpostio.c b/sys/src/cmd/postscript/tcpostio/tcpostio.c
new file mode 100755
index 000000000..4f0fdc007
--- /dev/null
+++ b/sys/src/cmd/postscript/tcpostio/tcpostio.c
@@ -0,0 +1,534 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef plan9
+#include <bsd.h>
+#endif
+
+#include <string.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <sys/socket.h>
+
+extern int dial_debug;
+extern int dial(char*, char*, char*, int*);
+
+
+/* debug = 0 for no debugging */
+/* debug = 1 for readprinter debugging */
+/* debug = 2 for sendprinter debugging */
+/* debug = 3 for full debugging, its hard to read the messages */
+
+int debug = 0;
+#define READTIMEOUT 300
+#define RCVSELTIMEOUT 30
+#define SNDSELTIMEOUT 300
+
+void
+rdtmout(void) {
+ fprintf(stderr, "read timeout occurred, check printer\n");
+}
+
+int
+getline(int fd, char *buf, int len) {
+ char *bp, c;
+ int i = 0, n;
+
+ bp = buf;
+ while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) {
+ alarm(0);
+ if (*bp == '\r') continue;
+ i += n;
+
+ c = *bp++;
+ if (c == '\n' || c == '\004' || i >= len-1)
+ break;
+ }
+ alarm(0);
+ if (n < 0)
+ return(n);
+ *bp = '\0';
+ return(i);
+}
+
+typedef struct {
+ char *state; /* printer's current status */
+ int val; /* value returned by getstatus() */
+} Status;
+
+/* printer states */
+#define INITIALIZING 0
+#define IDLE 1
+#define BUSY 2
+#define WAITING 3
+#define PRINTING 4
+#define PRINTERERROR 5
+#define ERROR 6
+#define FLUSHING 7
+#define UNKNOWN 8
+
+/* protocol requests and program states */
+#define START 'S'
+unsigned char Start[] = { START };
+#define ID_LE 'L'
+unsigned char Id_le[] = { ID_LE };
+#define REQ_STAT 'T'
+unsigned char Req_stat[] = { REQ_STAT };
+#define SEND_DATA 'D'
+unsigned char Send_data[] = { SEND_DATA };
+#define SENT_DATA 'A'
+unsigned char Sent_data[] = { SENT_DATA };
+#define WAIT_FOR_EOJ 'W'
+unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ };
+#define END_OF_JOB 'E'
+unsigned char End_of_job[] = { END_OF_JOB };
+#define FATAL_ERROR 'F'
+unsigned char Fatal_error[] = { FATAL_ERROR };
+#define WAIT_FOR_IDLE 'I'
+unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE };
+#define OVER_AND_OUT 'O'
+unsigned char Over_and_out[] = { OVER_AND_OUT };
+
+Status statuslist[] = {
+ "initializing", INITIALIZING,
+ "idle", IDLE,
+ "busy", BUSY,
+ "waiting", WAITING,
+ "printing", PRINTING,
+ "printererror", PRINTERERROR,
+ "Error", ERROR,
+ "flushing", FLUSHING,
+ NULL, UNKNOWN
+};
+
+
+/* find returns a pointer to the location of string str2 in string str1,
+ * if it exists. Otherwise, it points to the end of str1.
+ */
+char *
+find(char *str1, char *str2) {
+ char *s1, *s2;
+
+ for (; *str1!='\0'; str1++) {
+ for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ;
+ if ( *s2 == '\0' )
+ break;
+ }
+
+ return(str1);
+}
+
+#define MESGSIZE 16384
+int blocksize = 1920; /* 19200/10, with 1 sec delay between transfers
+ * this keeps the queues from building up.
+ */
+char mesg[MESGSIZE]; /* exactly what came back on ttyi */
+
+int
+parsmesg(char *buf) {
+ static char sbuf[MESGSIZE];
+ char *s; /* start of printer messsage in mesg[] */
+ char *e; /* end of printer message in mesg[] */
+ char *key, *val; /* keyword/value strings in sbuf[] */
+ char *p; /* for converting to lower case etc. */
+ int i; /* where *key was found in statuslist[] */
+
+ if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') {
+ strcpy(sbuf, s+3); /* don't change mesg[] */
+ sbuf[e-(s+3)] = '\0'; /* ignore the trailing " ]%" */
+
+ for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :")) {
+ if (strcmp(key, "Error") == 0)
+ return(ERROR);
+ if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0)
+ key = val;
+
+ for (; *key == ' '; key++) ; /* skip any leading spaces */
+ for (p = key; *p; p++) /* convert to lower case */
+ if (*p == ':') {
+ *p = '\0';
+ break;
+ } else if (isupper(*p)) *p = tolower(*p);
+
+ for (i=0; statuslist[i].state != NULL; i++) {
+ if (strcmp(statuslist[i].state, key) == 0)
+ return(statuslist[i].val);
+ }
+ }
+ }
+ return(UNKNOWN);
+}
+
+char buf[MESGSIZE];
+fd_set readfds, writefds, exceptfds;
+struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 };
+struct timeval sndtimeout = { SNDSELTIMEOUT, 0 };
+
+int
+readprinter(int printerfd, int pipefd)
+{
+ unsigned char proto;
+ int progstate = START;
+ int print_wait_msg = 0;
+ int tocount = 0;
+ int c, printstat, lastprintstat, n, nfds;
+
+
+ nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
+ printstat = 0;
+ signal(SIGALRM, rdtmout);
+ do {
+
+reselect:
+ /* ask sending process to request printer status */
+ if (write(pipefd, Req_stat, 1) != 1) {
+ fprintf(stderr, "request status failed\n");
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ FD_ZERO(&readfds); /* lets be anal */
+ FD_SET(printerfd, &readfds);
+ FD_SET(pipefd, &readfds);
+ FD_ZERO(&exceptfds);
+ FD_SET(printerfd, &exceptfds);
+ FD_SET(pipefd, &exceptfds);
+ n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout);
+ if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n);
+ if (n == 0) {
+ /* a timeout occurred */
+ if (++tocount > 4) {
+ fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n");
+ tocount = 0;
+ }
+ goto reselect;
+ }
+ if (n > 0 && FD_ISSET(printerfd, &exceptfds)) {
+ /* printer problem */
+ fprintf(stderr, "printer exception\n");
+ if (write(pipefd, Fatal_error, 1) != 1) {
+ fprintf(stderr, "'fatal error' write to pipe failed\n");
+ }
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ if (n > 0 && FD_ISSET(pipefd, &exceptfds)) {
+ /* pipe problem */
+ fprintf(stderr, "pipe exception\n");
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ if (n > 0 && FD_ISSET(pipefd, &readfds)) {
+ /* protocol pipe wants to be read */
+ if (debug&0x1) fprintf(stderr, "pipe wants to be read\n");
+ if (read(pipefd, &proto, 1) != 1) {
+ fprintf(stderr, "read protocol pipe failed\n");
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto);
+ /* change state? */
+ switch (proto) {
+ case SENT_DATA:
+ break;
+ case WAIT_FOR_EOJ:
+ if (!print_wait_msg) {
+ print_wait_msg = 1;
+ fprintf(stderr, "waiting for end of job\n");
+ }
+ progstate = proto;
+ break;
+ default:
+ fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto);
+ break;
+ }
+ n--;
+ }
+ if (n > 0 && FD_ISSET(printerfd, &readfds)) {
+ /* printer wants to be read */
+ if (debug&0x1) fprintf(stderr, "printer wants to be read\n");
+ if ((c=getline(printerfd, buf, MESGSIZE)) < 0) {
+ fprintf(stderr, "read printer failed\n");
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ if (debug&0x1) fprintf(stderr, "%s\n", buf);
+ if (c==1 && *buf == '\004') {
+ if (progstate == WAIT_FOR_EOJ) {
+ if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate);
+ fprintf(stderr, "%%[ status: endofjob ]%%\n");
+/* progstate = WAIT_FOR_IDLE; */
+ progstate = OVER_AND_OUT;
+ if (write(pipefd, Over_and_out, 1) != 1) {
+ fprintf(stderr, "'fatal error' write to pipe failed\n");
+ }
+ continue;
+ } else {
+ if (printstat == ERROR) {
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ if (progstate != START && progstate != WAIT_FOR_IDLE)
+ fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate);
+
+ }
+ continue;
+ }
+
+ /* figure out if it was a status line */
+ lastprintstat = printstat;
+ printstat = parsmesg(buf);
+ if (printstat == UNKNOWN || printstat == ERROR
+ || lastprintstat != printstat) {
+ /* print whatever it is that was read */
+ fprintf(stderr, buf);
+ fflush(stderr);
+ if (printstat == UNKNOWN) {
+ printstat = lastprintstat;
+ continue;
+ }
+ }
+ switch (printstat) {
+ case UNKNOWN:
+ continue; /* shouldn't get here */
+ case FLUSHING:
+ case ERROR:
+ progstate = FATAL_ERROR;
+ /* ask sending process to die */
+ if (write(pipefd, Fatal_error, 1) != 1) {
+ fprintf(stderr, "Fatal_error mesg write to pipe failed\n");
+ }
+ continue;
+ case INITIALIZING:
+ case PRINTERERROR:
+ sleep(1);
+ break;
+ case IDLE:
+ if (progstate == WAIT_FOR_IDLE) {
+ progstate = OVER_AND_OUT;
+ if (write(pipefd, Over_and_out, 1) != 1) {
+ fprintf(stderr, "'fatal error' write to pipe failed\n");
+ }
+ continue;
+ }
+ progstate = SEND_DATA;
+
+ goto dowait;
+ case BUSY:
+ case WAITING:
+ default:
+ sleep(1);
+dowait:
+ switch (progstate) {
+ case WAIT_FOR_IDLE:
+ case WAIT_FOR_EOJ:
+ case START:
+ sleep(5);
+ break;
+
+ case SEND_DATA:
+ if (write(pipefd, Send_data, 1) != 1) {
+ fprintf(stderr, "send data write to pipe failed\n");
+ progstate = FATAL_ERROR;
+ continue;
+ }
+ break;
+ default:
+ fprintf(stderr, "unexpected program state %c\n", progstate);
+ exit(1);
+ }
+ break;
+ }
+ n--;
+ }
+ if (n > 0) {
+ fprintf(stderr, "more fds selected than requested!\n");
+ exit(1);
+ };
+ } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
+
+ if (progstate == FATAL_ERROR)
+ return(1);
+ else
+ return(0);
+}
+
+int
+sendfile(int infd, int printerfd, int pipefd)
+{
+ unsigned char proto;
+ int progstate = START;
+ int i, n, nfds;
+ int bytesread, bytesent = 0;
+
+ nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
+
+ if (write(printerfd, "\004", 1)!=1) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ }
+ do {
+ FD_ZERO(&readfds); /* lets be anal */
+ FD_SET(pipefd, &readfds);
+ n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout);
+ if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n);
+ if (n > 0 && FD_ISSET(pipefd, &readfds)) {
+ /* protocol pipe wants to be read */
+ if (read(pipefd, &proto, 1) != 1) {
+ fprintf(stderr, "read protocol pipe failed\n");
+ return(1);
+ }
+ /* change state? */
+ if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto);
+ switch (proto) {
+ case OVER_AND_OUT:
+ case END_OF_JOB:
+ progstate = proto;
+ break;
+ case SEND_DATA:
+ bytesread = 0;
+ do {
+ i = read(infd, &buf[bytesread], blocksize-bytesread);
+ if (debug&02) fprintf(stderr, "read %d bytes\n", i);
+ if (i > 0)
+ bytesread += i;
+ } while((i > 0) && (bytesread < blocksize));
+ if (i < 0) {
+ fprintf(stderr, "input file read error\n");
+ progstate = FATAL_ERROR;
+ break; /* from switch */
+ }
+ if (bytesread > 0) {
+ if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread);
+ if (write(printerfd, buf, bytesread)!=bytesread) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ } else if (write(pipefd, Sent_data, 1)!=1) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ } else {
+ bytesent += bytesread;
+ }
+ fprintf(stderr, "%d sent\n", bytesent);
+ fflush(stderr);
+
+ /* we have reached the end of the input file */
+ }
+ if (i == 0) {
+ if (progstate != WAIT_FOR_EOJ) {
+ if (write(printerfd, "\004", 1)!=1) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ } else if (write(pipefd, Wait_for_eoj, 1)!=1) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ } else {
+ progstate = WAIT_FOR_EOJ;
+ }
+ }
+ }
+ break;
+ case REQ_STAT:
+ if (write(printerfd, "\024", 1)!=1) {
+ fprintf(stderr, "write to printer failed\n");
+ progstate = FATAL_ERROR;
+ }
+ if (debug&02) fprintf(stderr, "^T");
+ break;
+ case FATAL_ERROR:
+ progstate = FATAL_ERROR;
+ }
+ } else if (n < 0) {
+ perror("sendfile:select:");
+ progstate = FATAL_ERROR;
+ } else if (n == 0) {
+ sleep(1);
+ fprintf(stderr, "sendfile timeout\n");
+ progstate = FATAL_ERROR;
+ }
+ } while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
+ if (write(printerfd, "\004", 1)!=1) {
+ perror("sendfile:write:");
+ progstate = FATAL_ERROR;
+ }
+
+ if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent);
+ if (progstate == FATAL_ERROR)
+ return(1);
+ else
+ return(0);
+}
+
+void main(int argc, char *argv[]) {
+ int c, usgflg=0, infd, printerfd;
+ int cpid;
+ int pipefd[2];
+ char *dialstr;
+ unsigned long rprv, sprv;
+
+ dialstr = 0;
+
+ while ((c = getopt(argc, argv, "b:d:")) != -1)
+ switch (c) {
+ case 'b':
+ blocksize = atoi(optarg)/10;
+ if (blocksize > MESGSIZE || blocksize < 1)
+ blocksize = MESGSIZE;
+ break;
+ case 'd':
+ debug = atoi(optarg);
+ dial_debug = debug;
+ break;
+ case '?':
+ fprintf(stderr, "unknown option %c\n", c);
+ usgflg++;
+ }
+ if (optind < argc)
+ dialstr = argv[optind++];
+ else {
+ usgflg++;
+ }
+ if (usgflg) {
+ fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n", argv[0]);
+ exit (2);
+ }
+ if (optind < argc) {
+ infd = open(argv[optind], 0);
+ if (infd < 0) {
+ fprintf(stderr, "cannot open %s\n", argv[optind]);
+ exit(1);
+ }
+ optind++;
+ } else
+ infd = 0;
+
+ if (debug & 02) fprintf(stderr, "blocksize=%d\n", blocksize);
+ if (debug) fprintf(stderr, "dialing address=%s\n", dialstr);
+ printerfd = dial(dialstr, 0, 0, 0);
+ if (printerfd < 0) exit(1);
+
+ fprintf(stderr, "printer startup\n");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) {
+ perror("socketpair");
+ exit(1);
+ }
+ switch(cpid = fork()){
+ case -1:
+ perror("fork error");
+ exit(1);
+ case 0:
+ close(pipefd[1]);
+ sprv = sendfile(infd, printerfd, pipefd[0]); /* child - to printer */
+ if (debug) fprintf(stderr, "to remote - exiting\n");
+ exit(sprv);
+ default:
+ close(pipefd[0]);
+ rprv = readprinter(printerfd, pipefd[1]); /* parent - from printer */
+ if (debug) fprintf(stderr, "from remote - exiting\n");
+ while(wait(&sprv) != cpid);
+ exit(rprv|sprv);
+ }
+}