/************************************************************************** * * File Name: blast.c * * Author: Warren Gish * Current address: * Department of Genetics * Washington University School of Medicine * St. Louis, MO * gish@watson.wustl.edu * * File Description: * experimental blast network service client for UNIX * * Necessary support libraries (see the INSTALL instructions): * ncbi.tar -- NCBI core library (only .h header files are needed) * gish.tar -- personal library of support functions * * Modification history: Jan. 5, 1995 - added "-p port" option Nov. 1993 - client now "escapes" white space in command line arguments, so complex -filter options can be specified by the user that will be properly interpreted by the server. Nov. 1990 - initial implementation while at the NCBI **************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifdef OS_UNIX_AIX #include #endif #if defined(OS_UNIX_SYSV) && defined(sun) #define sys_siglist _sys_siglist #else #ifndef OS_UNIX_LINUX extern char *sys_siglist[]; #endif #endif #include #include "blastsrv.h" #include extern int errno; extern char *sys_errlist[]; void fatalf VPROTO((char *format, ...)); char *module; char *theServer; int theSock; FILE *sockfp; int connected = FALSE; off_t seqlen; /* length of sequence transmitted */ int samechannel; int exitcode; unsigned waitconnect = WAITCONNECT; unsigned waitio = 300; char batch = FALSE; int blastport = BLASTPORT; char blastport_set; #define ENDSTR "': /* FASTA/Pearson format */ seqformat = FASTA_FMT; fastaformat = TRUE; break; case ';': /* Intelligenetics format */ seqformat = IG_FMT; igformat = TRUE; hadcomment = TRUE; do { if (vfgets(&title, &titlemax, &title, fp) == NULL) fatalf("null sequence"); bp = strpblk(title); } while (*bp == ';'); strcpy(title, bp); title = realloc(title, strlen(title)+2); /* Overlapping copy. Be safe! */ /* change by hr sorry mem_cpy(title+1, title, strlen(title)+1); */ memcpy(title+1, title, strlen(title)+1); title[0] = '>'; break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': seqformat = RAW_FMT; rawformat = TRUE; break; default: fatalf("Sorry, the query sequence file is not in any recognized format.\n"); } /* Does this look like IG format without any comment line(s)? */ if (rawformat && strlen(title) <= (size_t)10) { rawformat = FALSE; igformat = TRUE; seqformat = IG_FMT; } if (rawformat) { seq = title; seqmax = titlemax; title = ">ANONYMOUS"; titlemax = 0; } else { if (vfgets(&seq, &seqmax, &seq, fp) == NULL) fatalf("null sequence"); } if (titlemax > 79) title[79] = NULLB; bp = title + strlen(title) - 1; while (isspace(*bp)) *bp-- = NULLB; cp = seq; do { bp = strpblk(cp0 = cp); for (;;) { switch (ch = *bp++) { /* Accept files originating under MS-DOS, where EOF is Cntrl-Z */ case CNTRL('Z'): break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': ch = toupper(ch); /* Intentional fall-through */ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '*': case '-': if (cp - seq >= QUERYLEN_MAX) fatalf("query sequence is too long (> %d letters)", QUERYLEN_MAX); *cp++ = ch; continue; case '1': case '0': if (igformat) goto EndSeq; /* Intentional fall-through */ case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': case '(': case ')': case ',': case ' ': case '\t': continue; case NULLB: case '\n': case '\r': break; case ';': case '>': if (bp == cp0+1) { fprintf(stderr, "\n%s: ONLY THE FIRST QUERY SEQUENCE IN THE FILE WILL BE USED\n\n", module); if (!samechannel) printf( "\n%s: ONLY THE FIRST QUERY SEQUENCE IN THE FILE WILL BE USED\n\n", module); goto EndSeq; } /* Intentional fall-through */ default: if (isprint(ch)) fatalf("Invalid character in sequence: ``%c'' (code %d)", ch, ch); fatalf("Invalid character in sequence file, numeric value = %d", (int)ch); } break; } } while (vfgets(&seq, &seqmax, &cp, fp) != NULL); EndSeq: *cp = NULLB; seqlen = cp - seq; if (seqlen < QUERYLEN_MIN) fatalf("query sequence is too short (less than %d letters)", QUERYLEN_MIN); } callserver() { struct hostent *hp; struct servent *sp = NULL, sent; struct sockaddr_in sin; unsigned int inaddr; static int i = -1; if (!blastport_set) sp = getservbyname("blast", "tcp"); if (sp == NULL) { #ifndef RELIABLE if (!blastport_set) fatalf("tcp/blast: unknown network service"); #endif sp = &sent; sent.s_port = htons(blastport); } for (++i; (theServer = servers[i]) != NULL; ++i) { if (*theServer == NULLB) continue; printf("Trying %s... ", theServer); fflush(stdout); inaddr = inet_addr(theServer); if (inaddr != INADDR_NONE) memcpy((char *)&sin.sin_addr, (char *)&inaddr, sizeof(inaddr)); else { hp = gethostbyname(theServer); if (hp == NULL) { printf("address not found\n"); continue; } memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); } sin.sin_family = AF_INET; sin.sin_port = sp->s_port; theSock = socket(AF_INET, SOCK_STREAM, 0); if (theSock == -1) fatalf("socket: %s", sys_errlist[errno]); /* set socket for non-blocking i/o */ fcntl(theSock, F_SETFL, fcntl(theSock, F_GETFL)|FNDELAY); if (sockconnect(theSock, (struct sockaddr *)&sin, sizeof(sin)) == 0) break; while (close(theSock) == -1 && errno == EINTR) ; } if (theServer == NULL) fatalf("Sorry, no blast server is available. Try again later.\n"); printf("connected\n"); fflush(stdout); connected = TRUE; return 0; } int batchcmd() { if (!batch) return 0; serverwrite(">BATCH\r\n", sizeof(">BATCH\r\n")-1); return 0; } sendusername(username) char *username; { serverwrite(">USER ", sizeof(">USER ")-1); if (username == NULL) serverwrite("unknown", sizeof("unknown")-1); else serverwrite(username, strlen(username)); serverwrite(CRLF, 2); } sendargs(argc, argv) int argc; char **argv; { int i; /* Send the command-line arguments */ serverwrite(module, strlen(module)); serverwrite(" ", 1); for (i = 1; i < argc - 1; ++i) { send1arg(argv[i]); serverwrite(" ", 1); } send1arg(argv[i]); serverwrite(CRLF, 2); return 0; } int send1arg(thearg) CharPtr thearg; { register CharPtr cp, bp; register char ch; char buf[512]; if (thearg == NULL) return 0; /* Send one command line argument to the server, escaping any white space */ for (cp = thearg, bp = buf; *cp != NULLB; ++cp) { ch = *cp; if (isspace(ch) || ch == '\\') *bp++ = '\\'; *bp++ = ch; if (bp - buf > DIM(buf)-2) { serverwrite(buf, bp - buf); bp = buf; } } if (bp - buf != 0) serverwrite(buf, bp - buf); return 0; } int sendquery() { register char *cp = seq; register int i, j; serverwrite(title, strlen(title)); serverwrite(CRLF, 2); for (i=0; i seqlen) j = seqlen - i; serverwrite(cp, j); cp += j; serverwrite(CRLF, 2); } /* End of sequence signal is the character string "DOWN\r\n", NULL }; DFAPtr dp; int errscan PROTO((unsigned char *)); int getresults() { char buf[4097], buf2[4097], buf3[4097]; char totbuf[sizeof(buf)+sizeof(buf2)+sizeof(buf3)]; register char *cp = buf; register int rc; int j, retval = 0; char lastc = NULLB; char complete = 0; DFA_PatID pi; fflush(stdout); dp = dfa_new(0, UCHAR_MAX); dfa_begin(dp); for (j=0; j < DIM(pats)-1; ++j) { pi.i = j+1; dfa_add(dp, (unsigned char *)pats[j], strlen(pats[j]), pi); } if (dfa_close(dp) != dfaErrNone) fprintf(stderr, "\n*********** dfa_close error\n"); if ((rc = serverread(buf, sizeof(buf)-1)) <= 0) return -1; /* server sent no data at all */ buf[rc] = NULLB; if (write(1, buf, rc) != rc) fatalf("write error on stdout: %s", sys_errlist[errno]); if (errscan((unsigned char *)buf) != 0) retval = 1; buf[sizeof(buf)-1] = buf2[sizeof(buf2)-1] = buf3[sizeof(buf3)-1] = buf[0] = buf2[0] = buf3[0] = NULLB; for (;;) { if (cp == buf) cp = buf2; else if (cp == buf2) cp = buf3; else cp = buf; if ((rc = serverread(cp, sizeof(buf)-1)) <= 0) break; cp[rc] = NULLB; if (errscan((unsigned char *)cp) != 0) retval = 1; lastc = cp[rc-1]; if (lastc == ENDSTR[ENDSTR_SIZE-1] && rc >= ENDSTR_SIZE) { if (strcmp(&cp[rc-ENDSTR_SIZE], ENDSTR) == 0) { complete = 1; rc -= ENDSTR_SIZE; } } if (write(1, cp, rc) != rc) fatalf("write error on stdout: %s", sys_errlist[errno]); } if (lastc != '\n') putchar('\n'); serverclose(); if (cp == buf) { strcpy(totbuf, buf2); strcat(totbuf, buf3); } else if (cp == buf2) { strcpy(totbuf, buf3); strcat(totbuf, buf); } else { strcpy(totbuf, buf); strcat(totbuf, buf2); } cp = totbuf; while ((cp = str_chr(cp, 'E')) != NULL) { if (strncmp(cp, "EXIT CODE ", 10) == 0) { complete = 1; sscanf(cp, "%*s %*s %d", &exitcode); if (!samechannel) fprintf(stderr, "EXIT CODE %d\n", exitcode); break; } ++cp; } if (!complete && !retval) { cp = totbuf; while ((cp = str_chr(cp, '>')) != NULL) { if (strcmp(cp, ENDSTR) == 0) break; ++cp; } if (cp == NULL) { printf("\nFATAL: client: INCOMPLETE OUTPUT!\n"); printf("EXIT CODE 1\n"); if (!samechannel) { fprintf(stderr, "FATAL: client: INCOMPLETE OUTPUT!\n"); fprintf(stderr, "EXIT CODE 1\n"); } exitcode = 1; } } return retval; } void #ifndef VAR_ARGS fatalf(char *format, ...) #else /* VARARGS_AVAIL */ fatalf(format, va_alist) char *format; va_dcl #endif { va_list args; char buf[4096]; sendoob(theSock); serverclose(); if (samechannel) (void) fflush(stdout); #ifndef VAR_ARGS va_start(args, format); #else /* VARARGS_AVAIL */ va_start(args); #endif (void) vsprintf(buf, format, args); va_end(args); if (!samechannel) { (void) wrap(stderr, "FATAL: ", buf, -1, 78, 8); (void) fflush(stderr); } (void) fputc('\n', stdout); (void) wrap(stdout, "FATAL: ", buf, -1, 78, 8); (void) fputc('\n', stdout); (void) fflush(stdout); if (exitcode == 0) exitcode = 1; printf("EXIT CODE %d\n", exitcode); if (!samechannel) fprintf(stderr, "EXIT CODE %d\n", exitcode); exit(exitcode); } void sighandler(sig) int sig; { int s; signal(sig, SIG_DFL); if (theSock >= 0) { s = theSock; theSock = -1; sendoob(s); } switch (sig) { #ifdef SIGXCPU case SIGXCPU: #endif #ifdef SIGXFSZ case SIGXFSZ: #endif fatalf("%s", sys_siglist[sig]); /*NOTREACHED*/ default: break; } exit(1); } int sendoob(fd) int fd; { char oobmsg = NULLB; static char calledonce = 0; #if 0 int omask; omask = sigsetmask(0xffffffff); if (calledonce) { sigsetmask(omask); return 0; } sigsetmask(omask); #endif calledonce = 1; if (fd == -1) return -1; if (send(fd, &oobmsg, sizeof oobmsg, MSG_OOB) == -1) return -1; return 0; } char * strpblk(s) register char *s; { register char ch; while ((ch = *s) != NULLB && isspace(ch)) ++s; return s; } /* errscan -- search for warnings and fatalf error messages */ char *errprint(), *errprint1(); int errscan(s) register unsigned char *s; { register unsigned char ch; DFA_StatePtr S; static DFA_StatePtr S_save; DFA_AcceptPtr ap; DFA_PatlistPtr plp; static char *errstr, which = 0; char *cp; if (dfaerrno != dfaErrNone) return 0; if (errstr != NULL) { if (which) errstr = errprint1(s); else errstr = errprint(s); if (errstr != NULL) return 0; which = 0; } if (S_save == NULL) S_save = dp->state0->next['\n']; S = S_save; while ((ch = *s++) != NULLB) { S = S->next[ch]; if (DFA_ISACCEPTING(S)) { ap = (DFA_AcceptPtr)DFA_UNMUNGED(S); S = ap->retState; plp = &ap->pl; if (!samechannel) { cp = pats[plp->patID.i - 1] + 1; fputs(cp, stderr); } switch ((int)plp->patID.i) { case 1: /* WARNING */ case 2: /* FATAL */ errstr = errprint(s); if (errstr != NULL) return 0; break; case 3: /* Waiting on */ case 4: /* Still waiting */ case 5: /* Continuing */ which = 1; errstr = errprint1(s); break; case 6: /* DOWN */ S_save = NULL; return 1; default: break; } } } S_save = S; return 0; } char * errprint(s) char *s; { char *s0 = s; register char ch, lastch; if (samechannel) return NULL; ++s; while ((ch = *s++) != NULLB) { lastch = ch; if (lastch == '\n' && ((ch = *s) == '\n' || !isspace(ch))) { fwrite(s0, 1, s-s0, stderr); return NULL; /* End of message encountered */ } } fwrite(s0, 1, s-s0, stderr); fflush(stderr); return s; } char * errprint1(s) char *s; { char *s0 = s; register char ch; if (samechannel) return NULL; while ((ch = *s++) != NULLB) { if (ch == '\n') { fwrite(s0, s-s0, 1, stderr); return NULL; /* End of message encountered */ } } fwrite(s0, s-s0, 1, stderr); fflush(stderr); return s; } int serverread(buf, buflen) char *buf; int buflen; { int rc; if (theSock == -1) return -1; rc = sockread(theSock, buf, buflen); if (rc <= 0) { serverclose(); return -1; } return rc; } int serverwrite(buf, buflen) char *buf; int buflen; { int rc; if (theSock == -1) return -1; rc = sockwrite(theSock, buf, buflen); if (rc == -1) { serverclose(); } return rc; } int serverclose() { int s; if (theSock == -1) return -1; s = theSock; theSock = -1; close(s); connected = FALSE; return 0; } int sockread(fd, buf, buflen) int fd; char *buf; unsigned buflen; { int rc; if (fd < 0) return -1; while ((rc = READSOCKET(fd, buf, buflen)) < 0) { switch (errno) { case EINTR: continue; case EAGAIN: #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif if (sockselectr(fd) == 0) continue; return -1; case EBADF: #ifdef EBADMSG case EBADMSG: #endif return -1; default: fatalf("read error %d on socket connection to server: %s", errno, sys_errlist[errno]); } } return rc; } int sockselectr(fd) int fd; { fd_set rfds, xfds; struct timeval timeout; int cnt; FD_ZERO(&rfds); FD_SET(fd, &rfds); memcpy((char *)&xfds, (char *)&rfds, sizeof(xfds)); timeout.tv_usec = 0; timeout.tv_sec = waitio; while ((cnt = select(fd+1, &rfds, NULL, &xfds, &timeout)) == -1) { switch (errno) { case EINTR: continue; case EBADF: return -1; case EFAULT: case EINVAL: default: fatalf("select error %d: %s", sys_errlist[errno]); } } if (cnt == 0) fatalf("Connection timed out after %d seconds with no activity.", waitio); if (FD_ISSET(fd, &rfds)) return 0; return -1; } int sockwrite(fd, buf, nbyte) int fd; char *buf; unsigned nbyte; { int rc; while (nbyte > 0) { while ((rc = WRITESOCKET(fd, buf, nbyte)) <= 0) { if (rc == 0) return -1; switch (errno) { case EINTR: continue; case EAGAIN: #if EAGAIN != EWOULDBLOCK case EWOULDBLOCK: #endif if (sockselectw(fd) == 0) continue; return -1; case EBADF: return -1; case EFAULT: case EFBIG: case ERANGE: case EINVAL: case EPIPE: fatalf("Connection closed"); default: fatalf("unknown errno (%d) from write: %s", errno, sys_errlist[errno]); } } buf += rc; nbyte -= rc; } return 0; } int sockselectw(fd) int fd; { fd_set wfds, xfds; struct timeval timeout; int cnt; FD_ZERO(&wfds); FD_SET(fd, &wfds); memcpy((char *)&xfds, (char *)&wfds, sizeof(xfds)); timeout.tv_usec = 0; timeout.tv_sec = waitio; while ((cnt = select(fd+1, NULL, &wfds, &xfds, &timeout)) == -1) { switch (errno) { case EINTR: continue; case EBADF: return -1; case EFAULT: case EINVAL: fatalf("select: %s", sys_errlist[errno]); default: fatalf("select: unrecognized errno (%d): %s", errno, sys_errlist[errno]); } } if (cnt == 0) fatalf("Connection timed out after %d seconds with no activity.", waitio); if (FD_ISSET(fd, &wfds)) return 0; return -1; } char * servergets(buf, buflen) char *buf; int buflen; { if (theSock == -1) return NULL; if ((buf = sockgets(buf, buflen, theSock)) == NULL) { serverclose(); return NULL; } return buf; } char * sockgets(buf, buflen, fd) char *buf; int buflen; int fd; { char *buf0 = buf, ch; int rc; if (fd == -1) return NULL; if (buflen < 1) return buf; rc = 0; while (--buflen > 0 && (rc = sockread(fd, buf, 1)) == 0) { if (*buf++ == '\n') break; } if (rc != 0) return NULL; *buf = NULLB; return buf0; } int sockconnect(fd, hostaddr, hostaddrlen) int fd; struct sockaddr *hostaddr; int hostaddrlen; { fd_set wset; struct timeval timeout; int rc; while ((rc = connect(fd, hostaddr, hostaddrlen)) == -1) { switch (errno) { case EISCONN: rc = 0; break; case EINTR: continue; case EINPROGRESS: FD_ZERO(&wset); FD_SET(fd, &wset); timeout.tv_usec = 0; timeout.tv_sec = waitconnect; while ((rc=select(fd+1, NULL, &wset, NULL, &timeout)) == -1) { switch (errno) { case EINTR: continue; case EBADF: case EINVAL: default: fatalf("select error %d: %s", errno, sys_errlist[errno]); } } if (rc > 0) { rc = -1; break; } printf("no response.\n"); return -1; case ETIMEDOUT: printf("no response.\n"); return -1; case EINVAL: /* EINVAL branch taken when no one is listening */ case ECONNREFUSED: printf("connection refused.\n"); return -1; case ENETUNREACH: printf("network unreachable.\n"); return -1; case EADDRINUSE: printf("address in use.\n"); return -1; case EADDRNOTAVAIL: printf("address not available.\n"); return -1; case ENOTSOCK: case EAFNOSUPPORT: case EFAULT: case EALREADY: default: fatalf("connect error %d: %s", errno, sys_errlist[errno]); } if (rc != -1) break; } return 0; }