📄 tcp_wce.c
字号:
/* * Program: Winsock TCP/IP routines * * Author: Mark Crispin from Mike Seibel's Winsock code * Networks and Distributed Computing * Computing & Communications * University of Washington * Administration Building, AG-44 * Seattle, WA 98195 * Internet: MRC@CAC.Washington.EDU * * Date: 11 April 1989 * Last Edited: 17 October 2000 * * Copyright 2000 by the University of Washington * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appears in all copies and that both the * above copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Washington not be * used in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. This software is made * available "as is", and * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL, * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * *//* Private functions */long tcp_abort (SOCKET *sock);char *tcp_name (struct sockaddr_in *sin,long flag);/* Private data */int wsa_initted = 0; /* init ? */static int wsa_sock_open = 0; /* keep track of open sockets */static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */static long ttmo_read = 0; /* TCP timeouts, in seconds */static long ttmo_write = 0;static long allowreversedns = /* allow reverse DNS lookup */#ifdef DISABLE_REVERSE_DNS_LOOKUP NIL /* Not recommended, especially if using Kerberos authentication */#else T#endif ;/* TCP/IP manipulate parameters * Accepts: function code * function-dependent value * Returns: function-dependent return value */void *tcp_parameters (long function,void *value){ void *ret = NIL; switch ((int) function) { case SET_TIMEOUT: tmoh = (tcptimeout_t) value; case GET_TIMEOUT: ret = (void *) tmoh; break; case SET_READTIMEOUT: ttmo_read = (long) value; case GET_READTIMEOUT: ret = (void *) ttmo_read; break; case SET_WRITETIMEOUT: ttmo_write = (long) value; case GET_WRITETIMEOUT: ret = (void *) ttmo_write; break; } return ret;}/* TCP/IP open * Accepts: host name * contact service name * contact port number and optional silent flag * Returns: TCP/IP stream if success else NIL */TCPSTREAM *tcp_open (char *host,char *service,unsigned long port){ TCPSTREAM *stream = NIL; SOCKET sock; int i; char *s; struct sockaddr_in sin; struct hostent *he; char tmp[MAILTMPLEN]; char *hostname = NIL; blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); int silent = (port & NET_SILENT) ? T : NIL; port &= 0xffff; /* erase flags */ if (!wsa_initted++) { /* init Windows Sockets */ WSADATA wsock; int i = (int) WSAStartup (WSA_VERSION,&wsock); if (i) { /* failed */ wsa_initted = 0; /* in case we try again */ sprintf (tmp,"Unable to start Windows Sockets (%d)",i); mm_log (tmp,ERROR); return NIL; } } /* 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. */ sin.sin_family = AF_INET; /* family is always Internet */ /* 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 ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) { sprintf (tmp,"Bad format domain-literal: %.80s",host); mm_log (tmp,ERROR); return NIL; } else hostname = cpystr (host); } else { /* lookup host name */ if (bn) (*bn) (BLOCK_DNSLOOKUP,NIL); if ((he = gethostbyname (lcase (strcpy (tmp,host))))) { if (bn) (*bn) (BLOCK_NONE,NIL); /* copy host name */ hostname = cpystr (he->h_name); /* copy host addresses */ memcpy (&sin.sin_addr,he->h_addr,he->h_length); } else { if (bn) (*bn) (BLOCK_NONE,NIL); sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host); mm_log (tmp,ERROR); return NIL; } } /* copy port number in network format */ if (!(sin.sin_port = htons ((u_short) port))) fatal ("Bad port argument to tcp_open"); if (bn) (*bn) (BLOCK_TCPOPEN,NIL); /* get a TCP stream */ if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) { sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError()); mm_log (tmp,ERROR); fs_give ((void **) &hostname); return NIL; } wsa_sock_open++; /* now have a socket open */ /* open connection */ if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) == SOCKET_ERROR) { switch (WSAGetLastError ()) { /* analyze error */ case WSAECONNREFUSED: s = "Refused"; break; case WSAENOBUFS: s = "Insufficient system resources"; break; case WSAETIMEDOUT: s = "Timed out"; break; default: s = "Unknown error"; break; } sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hostname,port,s, WSAGetLastError ()); if (!silent) mm_log (tmp,ERROR); fs_give ((void **) &hostname); return (TCPSTREAM *) tcp_abort (&sock); } for (i = 65536; (i > 4096) && /* set receive buffer size to 64K */ setsockopt (sock,SOL_SOCKET,SO_RCVBUF,(void *) &i,sizeof(i)); i -= 1024); for (i = 65536; (i > 4096) && /* set send buffer size to 64K */ setsockopt (sock,SOL_SOCKET,SO_SNDBUF,(void *) &i,sizeof(i)); i -= 1024); if (bn) (*bn) (BLOCK_NONE,NIL); /* create TCP/IP stream */ stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, sizeof (TCPSTREAM)); stream->host = hostname; /* official host name */ stream->port = port; /* port number */ /* init socket */ stream->tcpsi = stream->tcpso = sock; stream->ictr = 0; /* init input counter */ return stream; /* return success */} /* TCP/IP authenticated open * Accepts: NETMBX specifier * service name * returned user name buffer * Returns: TCP/IP stream if success else NIL */TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf){ return NIL; /* always NIL on Windows */}/* TCP/IP receive line * Accepts: TCP/IP stream * Returns: text line string or NIL if failure */char *tcp_getline (TCPSTREAM *stream){ int n,m; char *st,*ret,*stp; char c = '\0'; char d; /* make sure have data */ if (!tcp_getdata (stream)) return NIL; st = stream->iptr; /* save start of string */ n = 0; /* init string count */ while (stream->ictr--) { /* look for end of line */ d = *stream->iptr++; /* slurp another character */ if ((c == '\015') && (d == '\012')) { ret = (char *) fs_get (n--); memcpy (ret,st,n); /* copy into a free storage string */ ret[n] = '\0'; /* tie off string with null */ return ret; } n++; /* count another character searched */ c = d; /* remember previous character */ } /* copy partial string from buffer */ memcpy ((ret = stp = (char *) fs_get (n)),st,n); /* get more data from the net */ if (!tcp_getdata (stream)) fs_give ((void **) &ret); /* special case of newline broken by buffer */ else if ((c == '\015') && (*stream->iptr == '\012')) { stream->iptr++; /* eat the line feed */ stream->ictr--; ret[n - 1] = '\0'; /* tie off string with null */ } /* else recurse to get remainder */ else if (st = tcp_getline (stream)) { ret = (char *) fs_get (n + 1 + (m = strlen (st))); memcpy (ret,stp,n); /* copy first part */ memcpy (ret + n,st,m); /* and second part */ fs_give ((void **) &stp); /* flush first part */ fs_give ((void **) &st); /* flush second part */ ret[n + m] = '\0'; /* tie off string with null */ } return ret;}/* TCP/IP receive buffer * Accepts: TCP/IP stream * size in bytes * buffer to read into * Returns: T if success, NIL otherwise */long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s){ unsigned long n; /* make sure socket still alive */ if (stream->tcpsi == INVALID_SOCKET) return NIL; /* can transfer bytes from buffer? */ if (n = min (size,stream->ictr)) { memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ s += n; /* update pointer */ stream->iptr +=n; size -= n; /* update # of bytes to do */ stream->ictr -=n; } if (size) { int i; fd_set fds; struct timeval tmo; time_t tc,t = time (0); blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); if (bn) (*bn) (BLOCK_TCPREAD,NIL); while (size > 0) { /* until request satisfied */ time_t tl = time (0); FD_ZERO (&fds); /* initialize selection vector */ FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */ tmo.tv_sec = ttmo_read; tmo.tv_usec = 0; /* block and read */ switch ((stream->tcpsi == stream->tcpso) ? select (stream->tcpsi+1,&fds,0,0, ttmo_read ? &tmo : (struct timeval *) 0) : 1) { case SOCKET_ERROR: /* error */ if (WSAGetLastError () != WSAEINTR) return tcp_abort (&stream->tcpsi); break; case 0: /* timeout */ tc = time (0); if (tmoh && ((*tmoh) (tc - t,tc - tl))) break; return tcp_abort (&stream->tcpsi); default: if (stream->tcpsi == stream->tcpso) while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) == SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR)); else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) && (errno == EINTR)); switch (i) { case SOCKET_ERROR: /* error */ case 0: /* no data read */ return tcp_abort (&stream->tcpsi); default: s += i; /* point at new place to write */ size -= i; /* reduce byte count */ } } } if (bn) (*bn) (BLOCK_NONE,NIL); } *s = '\0'; /* tie off string */ return T;}/* TCP/IP receive data * Accepts: TCP/IP stream * Returns: T if success, NIL otherwise */long tcp_getdata (TCPSTREAM *stream){ struct timeval tmo; int i; fd_set fds; time_t tc,t = time (0); blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); FD_ZERO (&fds); /* initialize selection vector */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -