TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int family; int sock = -1; int ctr = 0; int silent = (port & NET_SILENT) ? T : NIL; int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr; char *s,*hostname,tmp[MAILTMPLEN]; void *adr; size_t adrlen; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); void *data,*next; port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sv->s_port); /* The domain literal form is used (rather than simply the dotted decimal as with other Unix programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[(strlen (tmp))-1] = '\0'; if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) { (*bn) (BLOCK_TCPOPEN,NIL); /* get an open socket for this system */ sock = tcp_socket_open (family,adr,adrlen,port,tmp,ctrp,hostname = host); (*bn) (BLOCK_NONE,NIL); fs_give ((void **) &adr); } else sprintf (tmp,"Bad format domain-literal: %.80s",host); } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ data = (*bn) (BLOCK_SENSITIVE,NIL); if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next))) sprintf (tmp,"No such host as %.80s",host); (*bn) (BLOCK_NONSENSITIVE,data); (*bn) (BLOCK_NONE,NIL); if (s) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); do { (*bn) (BLOCK_TCPOPEN,NIL); if (((sock = tcp_socket_open (family,s,adrlen,port,tmp,ctrp, hostname)) < 0) && (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) && !silent) mm_log (tmp,WARN); (*bn) (BLOCK_NONE,NIL); } while ((sock < 0) && s);/* repeat until success or no more addreses */ } } if (sock >= 0) { /* won */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init sockets */ stream->tcpsi = stream->tcpso = sock; /* stash in the snuck-in byte */ if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0]; /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } else if (!silent) mm_log (tmp,ERROR); return stream; /* return success */ }
TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) { TCPSTREAM *stream = NIL; void *adr; char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1],*r; int i,ti,pipei[2],pipeo[2]; size_t len; time_t now; struct timeval tmo; fd_set fds,efds; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); #ifdef SSHPATH /* ssh path defined yet? */ if (!sshpath) sshpath = cpystr (SSHPATH); #endif #ifdef RSHPATH /* rsh path defined yet? */ if (!rshpath) rshpath = cpystr (RSHPATH); #endif if (*service == '*') { /* want ssh? */ /* return immediately if ssh disabled */ if (!(sshpath && (ti = sshtimeout))) return NIL; /* ssh command prototype defined yet? */ if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); } /* want rsh? */ else if (rshpath && (ti = rshtimeout)) { /* rsh command prototype defined yet? */ if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); } else return NIL; /* rsh disabled */ /* look like domain literal? */ if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') { strcpy (host,mb->host+1); /* yes, copy without brackets */ host[i-1] = '\0'; /* validate domain literal */ if (adr = ip_stringtoaddr (host,&len,&i)) fs_give ((void **) &adr); else { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } } else strcpy (host,tcp_canonical (mb->host)); if (*service == '*') /* build ssh command */ sprintf (tmp,sshcommand,sshpath,host, mb->user[0] ? mb->user : myusername (),service + 1); else sprintf (tmp,rshcommand,rshpath,host, mb->user[0] ? mb->user : myusername (),service); if (tcpdebug) { char msg[MAILTMPLEN]; sprintf (msg,"Trying %.100s",tmp); mm_log (msg,TCPDEBUG); } /* parse command into argv */ for (i = 1,path = argv[0] = strtok_r (tmp," ",&r); (i < MAXARGV) && (argv[i] = strtok_r (NIL," ",&r)); i++); argv[i] = NIL; /* make sure argv tied off */ /* make command pipes */ if (pipe (pipei) < 0) return NIL; if ((pipei[0] >= FD_SETSIZE) || (pipei[1] >= FD_SETSIZE) || (pipe (pipeo) < 0)) { close (pipei[0]); close (pipei[1]); return NIL; } (*bn) (BLOCK_TCPOPEN,NIL); /* quell alarm up here for NeXT */ if ((pipeo[0] >= FD_SETSIZE) || (pipeo[1] >= FD_SETSIZE) || ((i = fork ()) < 0)) { /* make inferior process */ close (pipei[0]); close (pipei[1]); close (pipeo[0]); close (pipeo[1]); (*bn) (BLOCK_NONE,NIL); return NIL; } if (!i) { /* if child */ alarm (0); /* never have alarms in children */ if (!fork ()) { /* make grandchild so it's inherited by init */ int cf; /* don't alter parent vars in case vfork() */ int maxfd = max (20,max (max(pipei[0],pipei[1]),max(pipeo[0],pipeo[1]))); dup2 (pipei[1],1); /* parent's input is my output */ dup2 (pipei[1],2); /* parent's input is my error output too */ dup2 (pipeo[0],0); /* parent's output is my input */ /* close all unnecessary descriptors */ for (cf = 3; cf <= maxfd; cf++) close (cf); setpgrp (0,getpid ()); /* be our own process group */ _exit (execv (path,argv));/* now run it */ } _exit (1); /* child is done */ } grim_pid_reap (i,NIL); /* reap child; grandchild now owned by init */ close (pipei[1]); /* close child's side of the pipes */ close (pipeo[0]); /* create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); /* copy remote host name from argument */ stream->remotehost = cpystr (stream->host = cpystr (host)); stream->tcpsi = pipei[0]; /* init sockets */ stream->tcpso = pipeo[1]; stream->ictr = 0; /* init input counter */ stream->port = 0xffffffff; /* no port number */ ti += now = time (0); /* open timeout */ tmo.tv_usec = 0; /* initialize usec timeout */ FD_ZERO (&fds); /* initialize selection vector */ FD_ZERO (&efds); /* handle errors too */ FD_SET (stream->tcpsi,&fds); /* set bit in selection vector */ FD_SET (stream->tcpsi,&efds); /* set bit in error selection vector */ FD_SET (stream->tcpso,&efds); /* set bit in error selection vector */ do { /* block under timeout */ tmo.tv_sec = ti - now; i = select (max (stream->tcpsi,stream->tcpso)+1,&fds,NIL,&efds,&tmo); now = time (0); /* fake timeout if interrupt & time expired */ if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; } while ((i < 0) && (errno == EINTR)); if (i <= 0) { /* timeout or error? */ sprintf (tmp,i ? "error in %s to IMAP server" : "%s to IMAP server timed out",(*service == '*') ? "ssh" : "rsh"); mm_log (tmp,WARN); tcp_close (stream); /* punt stream */ stream = NIL; } (*bn) (BLOCK_NONE,NIL); /* return user name */ strcpy (usrbuf,mb->user[0] ? mb->user : myusername ()); return stream; /* return success */ }
TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) { TCPSTREAM *stream = NIL; int i,family; SOCKET sock = INVALID_SOCKET; int silent = (port & NET_SILENT) ? T : NIL; char *s,*hostname,tmp[MAILTMPLEN]; void *adr,*next; size_t adrlen; struct servent *sv = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; if (i = (int) WSAStartup (WINSOCK_VERSION,&wsock)) { wsa_initted = 0; /* in case we try again */ sprintf (tmp,"Unable to start Windows Sockets (%d)",i); mm_log (tmp,ERROR); return NIL; } } port &= 0xffff; /* erase flags */ /* lookup service */ if (service && (sv = getservbyname (service,"tcp"))) port = ntohs (sv->s_port); /* The domain literal form is used (rather than simply the dotted decimal as with other Windows programs) because it has to be a valid "host name" in mailsystem terminology. */ /* look like domain literal? */ if (host[0] == '[' && host[(strlen (host))-1] == ']') { strcpy (tmp,host+1); /* yes, copy number part */ tmp[strlen (tmp)-1] = '\0'; if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) { (*bn) (BLOCK_TCPOPEN,NIL); sock = tcp_socket_open (family,adr,adrlen,(unsigned short) port,tmp, hostname = host); (*bn) (BLOCK_NONE,NIL); fs_give ((void **) &adr); } else sprintf (tmp,"Bad format domain-literal: %.80s",host); } else { /* lookup host name */ if (tcpdebug) { sprintf (tmp,"DNS resolution %.80s",host); mm_log (tmp,TCPDEBUG); } (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */ if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next))) sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError (),host); (*bn) (BLOCK_NONE,NIL); if (s) { /* DNS resolution won? */ if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); wsa_sock_open++; /* prevent tcp_abort() from freeing in loop */ do { (*bn) (BLOCK_TCPOPEN,NIL); if (((sock = tcp_socket_open (family,s,adrlen,(unsigned short) port, tmp,hostname)) == INVALID_SOCKET) && (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) && !silent) mm_log (tmp,WARN); (*bn) (BLOCK_NONE,NIL); } while ((sock == INVALID_SOCKET) && s); wsa_sock_open--; /* undo protection */ } } if (sock == INVALID_SOCKET) { /* do possible cleanup action */ if (!silent) mm_log (tmp,ERROR); tcp_abort (&sock); } else { /* got a socket, create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->port = port; /* port number */ /* init socket */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ /* copy official host name */ stream->host = cpystr (hostname); if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); } return stream; /* return success */ }