imapext-2007

annotate src/osdep/wce/tcp_wce.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2008 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: Winsock TCP/IP routines
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin from Mike Seibel's Winsock code
yuuji@0 18 * Networks and Distributed Computing
yuuji@0 19 * Computing & Communications
yuuji@0 20 * University of Washington
yuuji@0 21 * Administration Building, AG-44
yuuji@0 22 * Seattle, WA 98195
yuuji@0 23 * Internet: MRC@CAC.Washington.EDU
yuuji@0 24 *
yuuji@0 25 * Date: 11 April 1989
yuuji@0 26 * Last Edited: 13 January 2008
yuuji@0 27 */
yuuji@0 28
yuuji@0 29
yuuji@0 30 #define TCPMAXSEND 32768
yuuji@0 31
yuuji@0 32 /* Private functions */
yuuji@0 33
yuuji@0 34 int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
yuuji@0 35 unsigned long port);
yuuji@0 36 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
yuuji@0 37 long *contd);
yuuji@0 38 long tcp_abort (TCPSTREAM *stream);
yuuji@0 39 long tcp_close_socket (SOCKET *sock);
yuuji@0 40 char *tcp_name (struct sockaddr_in *sin,long flag);
yuuji@0 41 char *tcp_name_valid (char *s);
yuuji@0 42
yuuji@0 43
yuuji@0 44 /* Private data */
yuuji@0 45
yuuji@0 46 int wsa_initted = 0; /* init ? */
yuuji@0 47 static int wsa_sock_open = 0; /* keep track of open sockets */
yuuji@0 48 static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
yuuji@0 49 static long ttmo_read = 0; /* TCP timeouts, in seconds */
yuuji@0 50 static long ttmo_write = 0;
yuuji@0 51 static long allowreversedns = T;/* allow reverse DNS lookup */
yuuji@0 52 static long tcpdebug = NIL; /* extra TCP debugging telemetry */
yuuji@0 53
yuuji@0 54 /* TCP/IP manipulate parameters
yuuji@0 55 * Accepts: function code
yuuji@0 56 * function-dependent value
yuuji@0 57 * Returns: function-dependent return value
yuuji@0 58 */
yuuji@0 59
yuuji@0 60 void *tcp_parameters (long function,void *value)
yuuji@0 61 {
yuuji@0 62 void *ret = NIL;
yuuji@0 63 switch ((int) function) {
yuuji@0 64 case SET_TIMEOUT:
yuuji@0 65 tmoh = (tcptimeout_t) value;
yuuji@0 66 case GET_TIMEOUT:
yuuji@0 67 ret = (void *) tmoh;
yuuji@0 68 break;
yuuji@0 69 case SET_READTIMEOUT:
yuuji@0 70 ttmo_read = (long) value;
yuuji@0 71 case GET_READTIMEOUT:
yuuji@0 72 ret = (void *) ttmo_read;
yuuji@0 73 break;
yuuji@0 74 case SET_WRITETIMEOUT:
yuuji@0 75 ttmo_write = (long) value;
yuuji@0 76 case GET_WRITETIMEOUT:
yuuji@0 77 ret = (void *) ttmo_write;
yuuji@0 78 break;
yuuji@0 79 case SET_ALLOWREVERSEDNS:
yuuji@0 80 allowreversedns = (long) value;
yuuji@0 81 case GET_ALLOWREVERSEDNS:
yuuji@0 82 ret = (void *) allowreversedns;
yuuji@0 83 break;
yuuji@0 84 case SET_TCPDEBUG:
yuuji@0 85 tcpdebug = (long) value;
yuuji@0 86 case GET_TCPDEBUG:
yuuji@0 87 ret = (void *) tcpdebug;
yuuji@0 88 break;
yuuji@0 89 }
yuuji@0 90 return ret;
yuuji@0 91 }
yuuji@0 92
yuuji@0 93 /* TCP/IP open
yuuji@0 94 * Accepts: host name
yuuji@0 95 * contact service name
yuuji@0 96 * contact port number and optional silent flag
yuuji@0 97 * Returns: TCP/IP stream if success else NIL
yuuji@0 98 */
yuuji@0 99
yuuji@0 100 TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
yuuji@0 101 {
yuuji@0 102 TCPSTREAM *stream = NIL;
yuuji@0 103 int i;
yuuji@0 104 SOCKET sock = INVALID_SOCKET;
yuuji@0 105 int silent = (port & NET_SILENT) ? T : NIL;
yuuji@0 106 char *s;
yuuji@0 107 struct sockaddr_in sin;
yuuji@0 108 struct hostent *he;
yuuji@0 109 char hostname[MAILTMPLEN];
yuuji@0 110 char tmp[MAILTMPLEN];
yuuji@0 111 struct servent *sv = NIL;
yuuji@0 112 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 113 if (!wsa_initted++) { /* init Windows Sockets */
yuuji@0 114 WSADATA wsock;
yuuji@0 115 if (i = (int) WSAStartup (WSA_VERSION,&wsock)) {
yuuji@0 116 wsa_initted = 0; /* in case we try again */
yuuji@0 117 sprintf (tmp,"Unable to start Windows Sockets (%d)",i);
yuuji@0 118 mm_log (tmp,ERROR);
yuuji@0 119 return NIL;
yuuji@0 120 }
yuuji@0 121 }
yuuji@0 122 port &= 0xffff; /* erase flags */
yuuji@0 123 /* lookup service */
yuuji@0 124 if (service && (sv = getservbyname (service,"tcp")))
yuuji@0 125 port = ntohs (sin.sin_port = sv->s_port);
yuuji@0 126 /* copy port number in network format */
yuuji@0 127 else sin.sin_port = htons ((u_short) port);
yuuji@0 128 /* The domain literal form is used (rather than simply the dotted decimal
yuuji@0 129 as with other Windows programs) because it has to be a valid "host name"
yuuji@0 130 in mailsystem terminology. */
yuuji@0 131 sin.sin_family = AF_INET; /* family is always Internet */
yuuji@0 132 /* look like domain literal? */
yuuji@0 133 if (host[0] == '[' && host[(strlen (host))-1] == ']') {
yuuji@0 134 strcpy (tmp,host+1); /* yes, copy number part */
yuuji@0 135 tmp[strlen (tmp)-1] = '\0';
yuuji@0 136 if ((sin.sin_addr.s_addr = inet_addr (tmp)) == INADDR_NONE) {
yuuji@0 137 sprintf (tmp,"Bad format domain-literal: %.80s",host);
yuuji@0 138 mm_log (tmp,ERROR);
yuuji@0 139 return NIL;
yuuji@0 140 }
yuuji@0 141 else {
yuuji@0 142 sin.sin_family = AF_INET; /* family is always Internet */
yuuji@0 143 strcpy (hostname,host);
yuuji@0 144 (*bn) (BLOCK_TCPOPEN,NIL);
yuuji@0 145 sock = tcp_socket_open (&sin,tmp,hostname,port);
yuuji@0 146 (*bn) (BLOCK_NONE,NIL);
yuuji@0 147 }
yuuji@0 148 }
yuuji@0 149
yuuji@0 150 else { /* lookup host name */
yuuji@0 151 if (tcpdebug) {
yuuji@0 152 sprintf (tmp,"DNS resolution %.80s",host);
yuuji@0 153 mm_log (tmp,TCPDEBUG);
yuuji@0 154 }
yuuji@0 155 (*bn) (BLOCK_DNSLOOKUP,NIL);/* look up name */
yuuji@0 156 if (!(he = gethostbyname (lcase (strcpy (tmp,host)))))
yuuji@0 157 sprintf (tmp,"Host not found (#%d): %s",WSAGetLastError(),host);
yuuji@0 158 (*bn) (BLOCK_NONE,NIL);
yuuji@0 159 if (he) { /* DNS resolution won? */
yuuji@0 160 if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG);
yuuji@0 161 /* copy address type */
yuuji@0 162 sin.sin_family = he->h_addrtype;
yuuji@0 163 /* copy host name */
yuuji@0 164 strcpy (hostname,he->h_name);
yuuji@0 165 wsa_sock_open++; /* prevent tcp_close_socket() from freeing in
yuuji@0 166 loop */
yuuji@0 167 for (i = 0; (sock == INVALID_SOCKET) && (s = he->h_addr_list[i]); i++) {
yuuji@0 168 if (i && !silent) mm_log (tmp,WARN);
yuuji@0 169 memcpy (&sin.sin_addr,s,he->h_length);
yuuji@0 170 (*bn) (BLOCK_TCPOPEN,NIL);
yuuji@0 171 sock = tcp_socket_open (&sin,tmp,hostname,port);
yuuji@0 172 (*bn) (BLOCK_NONE,NIL);
yuuji@0 173 }
yuuji@0 174 wsa_sock_open--; /* undo protection */
yuuji@0 175 }
yuuji@0 176 }
yuuji@0 177 if (sock == INVALID_SOCKET) { /* error? */
yuuji@0 178 if (!silent) mm_log (tmp,ERROR);
yuuji@0 179 tcp_close_socket (&sock); /* do possible cleanup action */
yuuji@0 180 }
yuuji@0 181 else { /* got a socket, create TCP/IP stream */
yuuji@0 182 stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0,
yuuji@0 183 sizeof (TCPSTREAM));
yuuji@0 184 stream->port = port; /* port number */
yuuji@0 185 /* init socket */
yuuji@0 186 stream->tcpsi = stream->tcpso = sock;
yuuji@0 187 stream->ictr = 0; /* init input counter */
yuuji@0 188 /* copy official host name */
yuuji@0 189 stream->host = cpystr (hostname);
yuuji@0 190 if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG);
yuuji@0 191 }
yuuji@0 192 return stream; /* return success */
yuuji@0 193 }
yuuji@0 194
yuuji@0 195 /* Open a TCP socket
yuuji@0 196 * Accepts: Internet socket address block
yuuji@0 197 * scratch buffer
yuuji@0 198 * host name for error message
yuuji@0 199 * port number for error message
yuuji@0 200 * Returns: socket if success, else -1 with error string in scratch buffer
yuuji@0 201 */
yuuji@0 202
yuuji@0 203 int tcp_socket_open (struct sockaddr_in *sin,char *tmp,char *hst,
yuuji@0 204 unsigned long port)
yuuji@0 205 {
yuuji@0 206 int sock;
yuuji@0 207 char *s;
yuuji@0 208 sprintf (tmp,"Trying IP address [%s]",inet_ntoa (sin->sin_addr));
yuuji@0 209 mm_log (tmp,NIL);
yuuji@0 210 /* get a TCP stream */
yuuji@0 211 if ((sock = socket (sin->sin_family,SOCK_STREAM,0)) == INVALID_SOCKET) {
yuuji@0 212 sprintf (tmp,"Unable to create TCP socket (%d)",WSAGetLastError());
yuuji@0 213 return -1;
yuuji@0 214 }
yuuji@0 215 wsa_sock_open++; /* count this socket as open */
yuuji@0 216 /* open connection */
yuuji@0 217 if (connect (sock,(struct sockaddr *) sin,sizeof (struct sockaddr_in)) ==
yuuji@0 218 SOCKET_ERROR) {
yuuji@0 219 switch (WSAGetLastError ()){/* analyze error */
yuuji@0 220 case WSAECONNREFUSED:
yuuji@0 221 s = "Refused";
yuuji@0 222 break;
yuuji@0 223 case WSAENOBUFS:
yuuji@0 224 s = "Insufficient system resources";
yuuji@0 225 break;
yuuji@0 226 case WSAETIMEDOUT:
yuuji@0 227 s = "Timed out";
yuuji@0 228 break;
yuuji@0 229 case WSAEHOSTUNREACH:
yuuji@0 230 s = "Host unreachable";
yuuji@0 231 break;
yuuji@0 232 default:
yuuji@0 233 s = "Unknown error";
yuuji@0 234 break;
yuuji@0 235 }
yuuji@0 236 sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",hst,port,s,
yuuji@0 237 WSAGetLastError ());
yuuji@0 238 tcp_close_socket (&sock); /* flush socket */
yuuji@0 239 sock = INVALID_SOCKET;
yuuji@0 240 }
yuuji@0 241 return sock; /* return the socket */
yuuji@0 242 }
yuuji@0 243
yuuji@0 244 /* TCP/IP authenticated open
yuuji@0 245 * Accepts: NETMBX specifier
yuuji@0 246 * service name
yuuji@0 247 * returned user name buffer
yuuji@0 248 * Returns: TCP/IP stream if success else NIL
yuuji@0 249 */
yuuji@0 250
yuuji@0 251 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
yuuji@0 252 {
yuuji@0 253 return NIL; /* always NIL on Windows */
yuuji@0 254 }
yuuji@0 255
yuuji@0 256 /* TCP receive line
yuuji@0 257 * Accepts: TCP stream
yuuji@0 258 * Returns: text line string or NIL if failure
yuuji@0 259 */
yuuji@0 260
yuuji@0 261 char *tcp_getline (TCPSTREAM *stream)
yuuji@0 262 {
yuuji@0 263 unsigned long n,contd;
yuuji@0 264 char *ret = tcp_getline_work (stream,&n,&contd);
yuuji@0 265 if (ret && contd) { /* got a line needing continuation? */
yuuji@0 266 STRINGLIST *stl = mail_newstringlist ();
yuuji@0 267 STRINGLIST *stc = stl;
yuuji@0 268 do { /* collect additional lines */
yuuji@0 269 stc->text.data = (unsigned char *) ret;
yuuji@0 270 stc->text.size = n;
yuuji@0 271 stc = stc->next = mail_newstringlist ();
yuuji@0 272 ret = tcp_getline_work (stream,&n,&contd);
yuuji@0 273 } while (ret && contd);
yuuji@0 274 if (ret) { /* stash final part of line on list */
yuuji@0 275 stc->text.data = (unsigned char *) ret;
yuuji@0 276 stc->text.size = n;
yuuji@0 277 /* determine how large a buffer we need */
yuuji@0 278 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
yuuji@0 279 ret = fs_get (n + 1); /* copy parts into buffer */
yuuji@0 280 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
yuuji@0 281 memcpy (ret + n,stc->text.data,stc->text.size);
yuuji@0 282 ret[n] = '\0';
yuuji@0 283 }
yuuji@0 284 mail_free_stringlist (&stl);/* either way, done with list */
yuuji@0 285 }
yuuji@0 286 return ret;
yuuji@0 287 }
yuuji@0 288
yuuji@0 289 /* TCP receive line or partial line
yuuji@0 290 * Accepts: TCP stream
yuuji@0 291 * pointer to return size
yuuji@0 292 * pointer to return continuation flag
yuuji@0 293 * Returns: text line string, size and continuation flag, or NIL if failure
yuuji@0 294 */
yuuji@0 295
yuuji@0 296 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
yuuji@0 297 long *contd)
yuuji@0 298 {
yuuji@0 299 unsigned long n;
yuuji@0 300 char *s,*ret,c,d;
yuuji@0 301 *contd = NIL; /* assume no continuation */
yuuji@0 302 /* make sure have data */
yuuji@0 303 if (!tcp_getdata (stream)) return NIL;
yuuji@0 304 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
yuuji@0 305 d = *stream->iptr++; /* slurp another character */
yuuji@0 306 if ((c == '\015') && (d == '\012')) {
yuuji@0 307 ret = (char *) fs_get (n--);
yuuji@0 308 memcpy (ret,s,*size = n); /* copy into a free storage string */
yuuji@0 309 ret[n] = '\0'; /* tie off string with null */
yuuji@0 310 return ret;
yuuji@0 311 }
yuuji@0 312 }
yuuji@0 313 /* copy partial string from buffer */
yuuji@0 314 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
yuuji@0 315 /* get more data from the net */
yuuji@0 316 if (!tcp_getdata (stream)) fs_give ((void **) &ret);
yuuji@0 317 /* special case of newline broken by buffer */
yuuji@0 318 else if ((c == '\015') && (*stream->iptr == '\012')) {
yuuji@0 319 stream->iptr++; /* eat the line feed */
yuuji@0 320 stream->ictr--;
yuuji@0 321 ret[*size = --n] = '\0'; /* tie off string with null */
yuuji@0 322 }
yuuji@0 323 else *contd = LONGT; /* continuation needed */
yuuji@0 324 return ret;
yuuji@0 325 }
yuuji@0 326
yuuji@0 327 /* TCP/IP receive buffer
yuuji@0 328 * Accepts: TCP/IP stream
yuuji@0 329 * size in bytes
yuuji@0 330 * buffer to read into
yuuji@0 331 * Returns: T if success, NIL otherwise
yuuji@0 332 */
yuuji@0 333
yuuji@0 334 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s)
yuuji@0 335 {
yuuji@0 336 unsigned long n;
yuuji@0 337 /* make sure socket still alive */
yuuji@0 338 if (stream->tcpsi == INVALID_SOCKET) return NIL;
yuuji@0 339 /* can transfer bytes from buffer? */
yuuji@0 340 if (n = min (size,stream->ictr)) {
yuuji@0 341 memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */
yuuji@0 342 s += n; /* update pointer */
yuuji@0 343 stream->iptr +=n;
yuuji@0 344 size -= n; /* update # of bytes to do */
yuuji@0 345 stream->ictr -=n;
yuuji@0 346 }
yuuji@0 347 if (size) {
yuuji@0 348 int i;
yuuji@0 349 fd_set fds;
yuuji@0 350 struct timeval tmo;
yuuji@0 351 time_t tc,t = time (0);
yuuji@0 352 blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 353 (*bn) (BLOCK_TCPREAD,NIL);
yuuji@0 354 while (size > 0) { /* until request satisfied */
yuuji@0 355 time_t tl = time (0);
yuuji@0 356 if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG);
yuuji@0 357 FD_ZERO (&fds); /* initialize selection vector */
yuuji@0 358 FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
yuuji@0 359 tmo.tv_sec = ttmo_read;
yuuji@0 360 tmo.tv_usec = 0;
yuuji@0 361 /* block and read */
yuuji@0 362 switch ((stream->tcpsi == stream->tcpso) ?
yuuji@0 363 select (stream->tcpsi+1,&fds,0,0,
yuuji@0 364 ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
yuuji@0 365 case SOCKET_ERROR: /* error */
yuuji@0 366 if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
yuuji@0 367 break;
yuuji@0 368 case 0: /* timeout */
yuuji@0 369 tc = time (0);
yuuji@0 370 if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
yuuji@0 371 return tcp_abort (stream);
yuuji@0 372 default:
yuuji@0 373 if (stream->tcpsi == stream->tcpso)
yuuji@0 374 while (((i = recv (stream->tcpsi,s,(int) min (maxposint,size),0)) ==
yuuji@0 375 SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
yuuji@0 376 else while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) <
yuuji@0 377 0) && (errno == EINTR));
yuuji@0 378 switch (i) {
yuuji@0 379 case SOCKET_ERROR: /* error */
yuuji@0 380 case 0: /* no data read */
yuuji@0 381 return tcp_abort (stream);
yuuji@0 382 default:
yuuji@0 383 s += i; /* point at new place to write */
yuuji@0 384 size -= i; /* reduce byte count */
yuuji@0 385 if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG);
yuuji@0 386 }
yuuji@0 387 }
yuuji@0 388 }
yuuji@0 389 (*bn) (BLOCK_NONE,NIL);
yuuji@0 390 }
yuuji@0 391 *s = '\0'; /* tie off string */
yuuji@0 392 return T;
yuuji@0 393 }
yuuji@0 394
yuuji@0 395 /* TCP/IP receive data
yuuji@0 396 * Accepts: TCP/IP stream
yuuji@0 397 * Returns: T if success, NIL otherwise
yuuji@0 398 */
yuuji@0 399
yuuji@0 400 long tcp_getdata (TCPSTREAM *stream)
yuuji@0 401 {
yuuji@0 402 struct timeval tmo;
yuuji@0 403 int i;
yuuji@0 404 fd_set fds;
yuuji@0 405 time_t tc,t = time (0);
yuuji@0 406 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 407 FD_ZERO (&fds); /* initialize selection vector */
yuuji@0 408 if (stream->tcpsi == INVALID_SOCKET) return NIL;
yuuji@0 409 (*bn) (BLOCK_TCPREAD,NIL);
yuuji@0 410 tmo.tv_sec = ttmo_read;
yuuji@0 411 tmo.tv_usec = 0;
yuuji@0 412 while (stream->ictr < 1) { /* if nothing in the buffer */
yuuji@0 413 time_t tl = time (0);
yuuji@0 414 if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG);
yuuji@0 415 FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
yuuji@0 416 /* block and read */
yuuji@0 417 switch ((stream->tcpsi == stream->tcpso) ?
yuuji@0 418 select (stream->tcpsi+1,&fds,0,0,
yuuji@0 419 ttmo_read ? &tmo : (struct timeval *) 0) : 1) {
yuuji@0 420 case SOCKET_ERROR: /* error */
yuuji@0 421 if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
yuuji@0 422 break;
yuuji@0 423 case 0: /* timeout */
yuuji@0 424 tc = time (0);
yuuji@0 425 if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
yuuji@0 426 return tcp_abort (stream);
yuuji@0 427 default:
yuuji@0 428 if (stream->tcpsi == stream->tcpso)
yuuji@0 429 while (((i = recv (stream->tcpsi,stream->ibuf,BUFLEN,0)) ==
yuuji@0 430 SOCKET_ERROR) && (WSAGetLastError () == WSAEINTR));
yuuji@0 431 else while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
yuuji@0 432 (errno == EINTR));
yuuji@0 433 switch (i) {
yuuji@0 434 case SOCKET_ERROR: /* error */
yuuji@0 435 case 0: /* no data read */
yuuji@0 436 return tcp_abort (stream);
yuuji@0 437 default:
yuuji@0 438 stream->ictr = i; /* set new byte count */
yuuji@0 439 /* point at TCP buffer */
yuuji@0 440 stream->iptr = stream->ibuf;
yuuji@0 441 if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG);
yuuji@0 442 }
yuuji@0 443 }
yuuji@0 444 }
yuuji@0 445 (*bn) (BLOCK_NONE,NIL);
yuuji@0 446 return T;
yuuji@0 447 }
yuuji@0 448
yuuji@0 449 /* TCP/IP send string as record
yuuji@0 450 * Accepts: TCP/IP stream
yuuji@0 451 * string pointer
yuuji@0 452 * Returns: T if success else NIL
yuuji@0 453 */
yuuji@0 454
yuuji@0 455 long tcp_soutr (TCPSTREAM *stream,char *string)
yuuji@0 456 {
yuuji@0 457 return tcp_sout (stream,string,(unsigned long) strlen (string));
yuuji@0 458 }
yuuji@0 459
yuuji@0 460
yuuji@0 461 /* TCP/IP send string
yuuji@0 462 * Accepts: TCP/IP stream
yuuji@0 463 * string pointer
yuuji@0 464 * byte count
yuuji@0 465 * Returns: T if success else NIL
yuuji@0 466 */
yuuji@0 467
yuuji@0 468 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
yuuji@0 469 {
yuuji@0 470 int i;
yuuji@0 471 struct timeval tmo;
yuuji@0 472 fd_set fds;
yuuji@0 473 time_t tc,t = time (0);
yuuji@0 474 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 475 tmo.tv_sec = ttmo_write;
yuuji@0 476 tmo.tv_usec = 0;
yuuji@0 477 FD_ZERO (&fds); /* initialize selection vector */
yuuji@0 478 if (stream->tcpso == INVALID_SOCKET) return NIL;
yuuji@0 479 (*bn) (BLOCK_TCPWRITE,NIL);
yuuji@0 480 while (size > 0) { /* until request satisfied */
yuuji@0 481 time_t tl = time (0);
yuuji@0 482 if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG);
yuuji@0 483 FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
yuuji@0 484 /* block and write */
yuuji@0 485 switch ((stream->tcpsi == stream->tcpso) ?
yuuji@0 486 select (stream->tcpso+1,NULL,&fds,NULL,
yuuji@0 487 tmo.tv_sec ? &tmo : (struct timeval *) 0) : 1) {
yuuji@0 488 case SOCKET_ERROR: /* error */
yuuji@0 489 if (WSAGetLastError () != WSAEINTR) return tcp_abort (stream);
yuuji@0 490 break;
yuuji@0 491 case 0: /* timeout */
yuuji@0 492 tc = time (0);
yuuji@0 493 if (tmoh && ((*tmoh) (tc - t,tc - tl))) break;
yuuji@0 494 return tcp_abort (stream);
yuuji@0 495 default:
yuuji@0 496 if (stream->tcpsi == stream->tcpso)
yuuji@0 497 while (((i = send (stream->tcpso,string,
yuuji@0 498 (int) min (size,TCPMAXSEND),0)) == SOCKET_ERROR) &&
yuuji@0 499 (WSAGetLastError () == WSAEINTR));
yuuji@0 500 else while (((i = write (stream->tcpso,string,
yuuji@0 501 min (size,TCPMAXSEND))) < 0) &&
yuuji@0 502 (errno == EINTR));
yuuji@0 503 if (i == SOCKET_ERROR) return tcp_abort (stream);
yuuji@0 504 size -= i; /* count this size */
yuuji@0 505 if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG);
yuuji@0 506 string += i;
yuuji@0 507 }
yuuji@0 508 }
yuuji@0 509 (*bn) (BLOCK_NONE,NIL);
yuuji@0 510 return T; /* all done */
yuuji@0 511 }
yuuji@0 512
yuuji@0 513
yuuji@0 514 /* TCP/IP close
yuuji@0 515 * Accepts: TCP/IP stream
yuuji@0 516 */
yuuji@0 517
yuuji@0 518 void tcp_close (TCPSTREAM *stream)
yuuji@0 519 {
yuuji@0 520 tcp_abort (stream); /* nuke the sockets */
yuuji@0 521 /* flush host names */
yuuji@0 522 if (stream->host) fs_give ((void **) &stream->host);
yuuji@0 523 if (stream->remotehost) fs_give ((void **) &stream->remotehost);
yuuji@0 524 if (stream->localhost) fs_give ((void **) &stream->localhost);
yuuji@0 525 fs_give ((void **) &stream); /* flush the stream */
yuuji@0 526 }
yuuji@0 527
yuuji@0 528
yuuji@0 529 /* TCP/IP abort sockets
yuuji@0 530 * Accepts: TCP/IP stream
yuuji@0 531 * Returns: NIL, always
yuuji@0 532 */
yuuji@0 533
yuuji@0 534 long tcp_abort (TCPSTREAM *stream)
yuuji@0 535 {
yuuji@0 536 if (stream->tcpsi != stream->tcpso) tcp_close_socket (&stream->tcpso);
yuuji@0 537 else stream->tcpso = INVALID_SOCKET;
yuuji@0 538 return tcp_close_socket (&stream->tcpsi);
yuuji@0 539 }
yuuji@0 540
yuuji@0 541
yuuji@0 542 /* TCP/IP abort stream
yuuji@0 543 * Accepts: WinSock socket
yuuji@0 544 * Returns: NIL, always
yuuji@0 545 */
yuuji@0 546
yuuji@0 547 long tcp_close_socket (SOCKET *sock)
yuuji@0 548 {
yuuji@0 549 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 550 /* something to close? */
yuuji@0 551 if (sock && (*sock != INVALID_SOCKET)) {
yuuji@0 552 (*bn) (BLOCK_TCPCLOSE,NIL);
yuuji@0 553 closesocket (*sock); /* WinSock socket close */
yuuji@0 554 *sock = INVALID_SOCKET;
yuuji@0 555 (*bn) (BLOCK_NONE,NIL);
yuuji@0 556 wsa_sock_open--; /* drop this socket */
yuuji@0 557 }
yuuji@0 558 /* no more open streams? */
yuuji@0 559 if (wsa_initted && !wsa_sock_open) {
yuuji@0 560 mm_log ("Winsock cleanup",NIL);
yuuji@0 561 wsa_initted = 0; /* no more sockets, so... */
yuuji@0 562 WSACleanup (); /* free up resources until needed */
yuuji@0 563 }
yuuji@0 564 return NIL;
yuuji@0 565 }
yuuji@0 566
yuuji@0 567 /* TCP/IP get host name
yuuji@0 568 * Accepts: TCP/IP stream
yuuji@0 569 * Returns: host name for this stream
yuuji@0 570 */
yuuji@0 571
yuuji@0 572 char *tcp_host (TCPSTREAM *stream)
yuuji@0 573 {
yuuji@0 574 return stream->host; /* use tcp_remotehost() if want guarantees */
yuuji@0 575 }
yuuji@0 576
yuuji@0 577
yuuji@0 578 /* TCP/IP get remote host name
yuuji@0 579 * Accepts: TCP/IP stream
yuuji@0 580 * Returns: host name for this stream
yuuji@0 581 */
yuuji@0 582
yuuji@0 583 char *tcp_remotehost (TCPSTREAM *stream)
yuuji@0 584 {
yuuji@0 585 if (!stream->remotehost) {
yuuji@0 586 struct sockaddr_in sin;
yuuji@0 587 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 588 stream->remotehost = /* get socket's peer name */
yuuji@0 589 ((getpeername (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
yuuji@0 590 SOCKET_ERROR) || (sinlen <= 0)) ?
yuuji@0 591 cpystr (stream->host) : tcp_name (&sin,NIL);
yuuji@0 592 }
yuuji@0 593 return stream->remotehost;
yuuji@0 594 }
yuuji@0 595
yuuji@0 596
yuuji@0 597 /* TCP/IP return port for this stream
yuuji@0 598 * Accepts: TCP/IP stream
yuuji@0 599 * Returns: port number for this stream
yuuji@0 600 */
yuuji@0 601
yuuji@0 602 unsigned long tcp_port (TCPSTREAM *stream)
yuuji@0 603 {
yuuji@0 604 return stream->port; /* return port number */
yuuji@0 605 }
yuuji@0 606
yuuji@0 607
yuuji@0 608 /* TCP/IP get local host name
yuuji@0 609 * Accepts: TCP/IP stream
yuuji@0 610 * Returns: local host name
yuuji@0 611 */
yuuji@0 612
yuuji@0 613 char *tcp_localhost (TCPSTREAM *stream)
yuuji@0 614 {
yuuji@0 615 if (!stream->localhost) {
yuuji@0 616 struct sockaddr_in sin;
yuuji@0 617 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 618 stream->localhost = /* get socket's name */
yuuji@0 619 ((stream->port & 0xffff000) ||
yuuji@0 620 ((getsockname (stream->tcpsi,(struct sockaddr *) &sin,&sinlen) ==
yuuji@0 621 SOCKET_ERROR) || (sinlen <= 0))) ?
yuuji@0 622 cpystr (mylocalhost ()) : tcp_name (&sin,NIL);
yuuji@0 623 }
yuuji@0 624 return stream->localhost; /* return local host name */
yuuji@0 625 }
yuuji@0 626
yuuji@0 627 /* TCP/IP get client host address (server calls only)
yuuji@0 628 * Returns: client host address
yuuji@0 629 */
yuuji@0 630
yuuji@0 631 char *tcp_clientaddr ()
yuuji@0 632 {
yuuji@0 633 if (!myClientAddr) {
yuuji@0 634 struct sockaddr_in sin;
yuuji@0 635 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 636 myClientAddr = /* get stdin's peer name */
yuuji@0 637 ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
yuuji@0 638 (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
yuuji@0 639 }
yuuji@0 640 return myClientAddr;
yuuji@0 641 }
yuuji@0 642
yuuji@0 643
yuuji@0 644 /* TCP/IP get client host name (server calls only)
yuuji@0 645 * Returns: client host name
yuuji@0 646 */
yuuji@0 647
yuuji@0 648 char *tcp_clienthost ()
yuuji@0 649 {
yuuji@0 650 if (!myClientHost) {
yuuji@0 651 struct sockaddr_in sin;
yuuji@0 652 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 653 myClientHost = /* get stdin's peer name */
yuuji@0 654 ((getpeername (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
yuuji@0 655 (sinlen <= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin,T);
yuuji@0 656 }
yuuji@0 657 return myClientHost;
yuuji@0 658 }
yuuji@0 659
yuuji@0 660 /* TCP/IP get server host address (server calls only)
yuuji@0 661 * Returns: server host address
yuuji@0 662 */
yuuji@0 663
yuuji@0 664 char *tcp_serveraddr ()
yuuji@0 665 {
yuuji@0 666 if (!myServerAddr) {
yuuji@0 667 struct sockaddr_in sin;
yuuji@0 668 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 669 myServerAddr = /* get stdin's peer name */
yuuji@0 670 ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
yuuji@0 671 (sinlen <= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin.sin_addr));
yuuji@0 672 }
yuuji@0 673 return myServerAddr;
yuuji@0 674 }
yuuji@0 675
yuuji@0 676
yuuji@0 677 /* TCP/IP get server host name (server calls only)
yuuji@0 678 * Returns: server host name
yuuji@0 679 */
yuuji@0 680
yuuji@0 681 static long myServerPort = -1;
yuuji@0 682
yuuji@0 683 char *tcp_serverhost ()
yuuji@0 684 {
yuuji@0 685 if (!myServerHost) {
yuuji@0 686 struct sockaddr_in sin;
yuuji@0 687 int sinlen = sizeof (struct sockaddr_in);
yuuji@0 688 if (!wsa_initted++) { /* init Windows Sockets */
yuuji@0 689 WSADATA wsock;
yuuji@0 690 if (WSAStartup (WSA_VERSION,&wsock)) {
yuuji@0 691 wsa_initted = 0;
yuuji@0 692 return "random-pc"; /* try again later? */
yuuji@0 693 }
yuuji@0 694 }
yuuji@0 695 /* get stdin's name */
yuuji@0 696 if ((getsockname (0,(struct sockaddr *) &sin,&sinlen) == SOCKET_ERROR) ||
yuuji@0 697 (sinlen <= 0)) myServerHost = cpystr (mylocalhost ());
yuuji@0 698 else {
yuuji@0 699 myServerHost = tcp_name (&sin,NIL);
yuuji@0 700 myServerPort = ntohs (sin.sin_port);
yuuji@0 701 }
yuuji@0 702 }
yuuji@0 703 return myServerHost;
yuuji@0 704 }
yuuji@0 705
yuuji@0 706
yuuji@0 707 /* TCP/IP get server port number (server calls only)
yuuji@0 708 * Returns: server port number
yuuji@0 709 */
yuuji@0 710
yuuji@0 711 long tcp_serverport ()
yuuji@0 712 {
yuuji@0 713 if (!myServerHost) tcp_serverhost ();
yuuji@0 714 return myServerPort;
yuuji@0 715 }
yuuji@0 716
yuuji@0 717 /* TCP/IP return canonical form of host name
yuuji@0 718 * Accepts: host name
yuuji@0 719 * Returns: canonical form of host name
yuuji@0 720 */
yuuji@0 721
yuuji@0 722 char *tcp_canonical (char *name)
yuuji@0 723 {
yuuji@0 724 char *ret,host[MAILTMPLEN];
yuuji@0 725 struct hostent *he;
yuuji@0 726 blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 727 /* look like domain literal? */
yuuji@0 728 if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
yuuji@0 729 (*bn) (BLOCK_DNSLOOKUP,NIL);
yuuji@0 730 if (tcpdebug) {
yuuji@0 731 sprintf (host,"DNS canonicalization %.80s",name);
yuuji@0 732 mm_log (host,TCPDEBUG);
yuuji@0 733 }
yuuji@0 734 /* note that NT requires lowercase! */
yuuji@0 735 ret = (he = gethostbyname (lcase (strcpy (host,name)))) ? he->h_name : name;
yuuji@0 736 (*bn) (BLOCK_NONE,NIL);
yuuji@0 737 if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG);
yuuji@0 738 return ret;
yuuji@0 739 }
yuuji@0 740
yuuji@0 741
yuuji@0 742 /* TCP/IP return name from socket
yuuji@0 743 * Accepts: socket
yuuji@0 744 * verbose flag
yuuji@0 745 * Returns: cpystr name
yuuji@0 746 */
yuuji@0 747
yuuji@0 748 char *tcp_name (struct sockaddr_in *sin,long flag)
yuuji@0 749 {
yuuji@0 750 char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN];
yuuji@0 751 sprintf (ret = adr,"[%.80s]",inet_ntoa (sin->sin_addr));
yuuji@0 752 if (allowreversedns) {
yuuji@0 753 struct hostent *he;
yuuji@0 754 blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL);
yuuji@0 755 void *data;
yuuji@0 756 if (tcpdebug) {
yuuji@0 757 sprintf (tmp,"Reverse DNS resolution %s",adr);
yuuji@0 758 mm_log (tmp,TCPDEBUG);
yuuji@0 759 }
yuuji@0 760 (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */
yuuji@0 761 data = (*bn) (BLOCK_SENSITIVE,NIL);
yuuji@0 762 /* translate address to name */
yuuji@0 763 if (t = tcp_name_valid ((he = gethostbyaddr ((char *) &sin->sin_addr,
yuuji@0 764 sizeof (struct in_addr),
yuuji@0 765 sin->sin_family)) ?
yuuji@0 766 (char *) he->h_name : NIL)) {
yuuji@0 767 /* produce verbose form if needed */
yuuji@0 768 if (flag) sprintf (ret = tmp,"%s %s",t,adr);
yuuji@0 769 else ret = t;
yuuji@0 770 }
yuuji@0 771 (*bn) (BLOCK_NONSENSITIVE,data);
yuuji@0 772 (*bn) (BLOCK_NONE,NIL); /* alarms OK now */
yuuji@0 773 if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG);
yuuji@0 774 }
yuuji@0 775 return cpystr (ret);
yuuji@0 776 }
yuuji@0 777
yuuji@0 778 /* Return my local host name
yuuji@0 779 * Returns: my local host name
yuuji@0 780 */
yuuji@0 781
yuuji@0 782 char *mylocalhost (void)
yuuji@0 783 {
yuuji@0 784 if (!myLocalHost) {
yuuji@0 785 char tmp[MAILTMPLEN];
yuuji@0 786 if (!wsa_initted++) { /* init Windows Sockets */
yuuji@0 787 WSADATA wsock;
yuuji@0 788 if (WSAStartup (WSA_VERSION,&wsock)) {
yuuji@0 789 wsa_initted = 0;
yuuji@0 790 return "random-pc"; /* try again later? */
yuuji@0 791 }
yuuji@0 792 }
yuuji@0 793 myLocalHost = cpystr ((gethostname (tmp,MAILTMPLEN-1) == SOCKET_ERROR) ?
yuuji@0 794 "random-pc" : tcp_canonical (tmp));
yuuji@0 795 }
yuuji@0 796 return myLocalHost;
yuuji@0 797 }
yuuji@0 798
yuuji@0 799
yuuji@0 800 /* Validate name
yuuji@0 801 * Accepts: domain name
yuuji@0 802 * Returns: T if valid, NIL otherwise
yuuji@0 803 */
yuuji@0 804
yuuji@0 805 char *tcp_name_valid (char *s)
yuuji@0 806 {
yuuji@0 807 int c;
yuuji@0 808 char *ret,*tail;
yuuji@0 809 /* must be non-empty and not too long */
yuuji@0 810 if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) {
yuuji@0 811 /* must be alnum, dot, or hyphen */
yuuji@0 812 while ((c = *s++) && (s <= tail) &&
yuuji@0 813 (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) ||
yuuji@0 814 ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.')));
yuuji@0 815 if (c) ret = NIL;
yuuji@0 816 }
yuuji@0 817 return ret;
yuuji@0 818 }

UW-IMAP'd extensions by yuuji