imapext-2007

annotate src/osdep/dos/tcp_dos.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: MS-DOS TCP/IP routines
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
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 static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
yuuji@0 30 static long ttmo_read = 0; /* TCP timeouts, in seconds */
yuuji@0 31 static long ttmo_write = 0;
yuuji@0 32
yuuji@0 33 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
yuuji@0 34 long *contd);
yuuji@0 35
yuuji@0 36 /* TCP/IP manipulate parameters
yuuji@0 37 * Accepts: function code
yuuji@0 38 * function-dependent value
yuuji@0 39 * Returns: function-dependent return value
yuuji@0 40 */
yuuji@0 41
yuuji@0 42 void *tcp_parameters (long function,void *value)
yuuji@0 43 {
yuuji@0 44 void *ret = NIL;
yuuji@0 45 switch ((int) function) {
yuuji@0 46 case SET_TIMEOUT:
yuuji@0 47 tmoh = (tcptimeout_t) value;
yuuji@0 48 case GET_TIMEOUT:
yuuji@0 49 ret = (void *) tmoh;
yuuji@0 50 break;
yuuji@0 51 case SET_READTIMEOUT:
yuuji@0 52 ttmo_read = (long) value;
yuuji@0 53 case GET_READTIMEOUT:
yuuji@0 54 ret = (void *) ttmo_read;
yuuji@0 55 break;
yuuji@0 56 case SET_WRITETIMEOUT:
yuuji@0 57 ttmo_write = (long) value;
yuuji@0 58 case GET_WRITETIMEOUT:
yuuji@0 59 ret = (void *) ttmo_write;
yuuji@0 60 break;
yuuji@0 61 }
yuuji@0 62 return ret;
yuuji@0 63 }
yuuji@0 64
yuuji@0 65 /* TCP/IP open
yuuji@0 66 * Accepts: host name
yuuji@0 67 * contact service name
yuuji@0 68 * contact port number
yuuji@0 69 * Returns: TCP/IP stream if success else NIL
yuuji@0 70 */
yuuji@0 71
yuuji@0 72 TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
yuuji@0 73 {
yuuji@0 74 TCPSTREAM *stream = NIL;
yuuji@0 75 struct sockaddr_in sin;
yuuji@0 76 int sock;
yuuji@0 77 char *s,tmp[MAILTMPLEN];
yuuji@0 78 port &= 0xffff; /* erase flags */
yuuji@0 79 /* The domain literal form is used (rather than simply the dotted decimal
yuuji@0 80 as with other Unix programs) because it has to be a valid "host name"
yuuji@0 81 in mailsystem terminology. */
yuuji@0 82 sin.sin_family = AF_INET; /* family is always Internet */
yuuji@0 83 /* look like domain literal? */
yuuji@0 84 if (host[0] == '[' && host[(strlen (host))-1] == ']') {
yuuji@0 85 strcpy (tmp,host+1); /* yes, copy number part */
yuuji@0 86 tmp[strlen (tmp)-1] = '\0';
yuuji@0 87 if ((sin.sin_addr.s_addr = inet_addr (tmp)) == -1) {
yuuji@0 88 sprintf (tmp,"Bad format domain-literal: %.80s",host);
yuuji@0 89 mm_log (tmp,ERROR);
yuuji@0 90 return NIL;
yuuji@0 91 }
yuuji@0 92 }
yuuji@0 93 /* look up host name */
yuuji@0 94 else if (!lookuphost (&host,&sin)) {
yuuji@0 95 sprintf (tmp,"Host not found: %s",host);
yuuji@0 96 mm_log (tmp,ERROR);
yuuji@0 97 return NIL;
yuuji@0 98 }
yuuji@0 99
yuuji@0 100 /* copy port number in network format */
yuuji@0 101 if (!(sin.sin_port = htons (port))) fatal ("Bad port argument to tcp_open");
yuuji@0 102 /* get a TCP stream */
yuuji@0 103 if ((sock = socket (sin.sin_family,SOCK_STREAM,0)) < 0) {
yuuji@0 104 sprintf (tmp,"Unable to create TCP socket (%d)",errno);
yuuji@0 105 mm_log (tmp,ERROR);
yuuji@0 106 fs_give ((void **) &host);
yuuji@0 107 return NIL;
yuuji@0 108 }
yuuji@0 109 #if 0
yuuji@0 110 /* needed? */
yuuji@0 111 else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
yuuji@0 112 sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
yuuji@0 113 sock,FD_SETSIZE);
yuuji@0 114 close (sock);
yuuji@0 115 errno = ENOBUFS; /* just in case */
yuuji@0 116 return NIL;
yuuji@0 117 }
yuuji@0 118 #endif
yuuji@0 119 /* open connection */
yuuji@0 120 if (connect (sock,(struct sockaddr *) &sin,sizeof (sin)) < 0) {
yuuji@0 121 switch (errno) { /* analyze error */
yuuji@0 122 case ECONNREFUSED:
yuuji@0 123 s = "Refused";
yuuji@0 124 break;
yuuji@0 125 case ENOBUFS:
yuuji@0 126 s = "Insufficient system resources";
yuuji@0 127 break;
yuuji@0 128 case ETIMEDOUT:
yuuji@0 129 s = "Timed out";
yuuji@0 130 break;
yuuji@0 131 default:
yuuji@0 132 s = "Unknown error";
yuuji@0 133 break;
yuuji@0 134 }
yuuji@0 135 sprintf (tmp,"Can't connect to %.80s,%ld: %s (%d)",host,port,s,errno);
yuuji@0 136 mm_log (tmp,ERROR);
yuuji@0 137 close (sock);
yuuji@0 138 fs_give ((void **) &host);
yuuji@0 139 return NIL;
yuuji@0 140 }
yuuji@0 141 /* create TCP/IP stream */
yuuji@0 142 stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
yuuji@0 143 stream->host = host; /* official host name */
yuuji@0 144 stream->localhost = cpystr (mylocalhost ());
yuuji@0 145 stream->port = port; /* port number */
yuuji@0 146 stream->tcps = sock; /* init socket */
yuuji@0 147 stream->ictr = 0; /* init input counter */
yuuji@0 148 return stream; /* return success */
yuuji@0 149 }
yuuji@0 150
yuuji@0 151 /* TCP/IP authenticated open
yuuji@0 152 * Accepts: NETMBX specifier
yuuji@0 153 * service name
yuuji@0 154 * returned user name buffer
yuuji@0 155 * Returns: TCP/IP stream if success else NIL
yuuji@0 156 */
yuuji@0 157
yuuji@0 158 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
yuuji@0 159 {
yuuji@0 160 return NIL; /* always NIL on DOS */
yuuji@0 161 }
yuuji@0 162
yuuji@0 163 /* TCP receive line
yuuji@0 164 * Accepts: TCP stream
yuuji@0 165 * Returns: text line string or NIL if failure
yuuji@0 166 */
yuuji@0 167
yuuji@0 168 char *tcp_getline (TCPSTREAM *stream)
yuuji@0 169 {
yuuji@0 170 unsigned long n,contd;
yuuji@0 171 char *ret = tcp_getline_work (stream,&n,&contd);
yuuji@0 172 if (ret && contd) { /* got a line needing continuation? */
yuuji@0 173 STRINGLIST *stl = mail_newstringlist ();
yuuji@0 174 STRINGLIST *stc = stl;
yuuji@0 175 do { /* collect additional lines */
yuuji@0 176 stc->text.data = (unsigned char *) ret;
yuuji@0 177 stc->text.size = n;
yuuji@0 178 stc = stc->next = mail_newstringlist ();
yuuji@0 179 ret = tcp_getline_work (stream,&n,&contd);
yuuji@0 180 } while (ret && contd);
yuuji@0 181 if (ret) { /* stash final part of line on list */
yuuji@0 182 stc->text.data = (unsigned char *) ret;
yuuji@0 183 stc->text.size = n;
yuuji@0 184 /* determine how large a buffer we need */
yuuji@0 185 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
yuuji@0 186 ret = fs_get (n + 1); /* copy parts into buffer */
yuuji@0 187 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
yuuji@0 188 memcpy (ret + n,stc->text.data,stc->text.size);
yuuji@0 189 ret[n] = '\0';
yuuji@0 190 }
yuuji@0 191 mail_free_stringlist (&stl);/* either way, done with list */
yuuji@0 192 }
yuuji@0 193 return ret;
yuuji@0 194 }
yuuji@0 195
yuuji@0 196 /* TCP receive line or partial line
yuuji@0 197 * Accepts: TCP stream
yuuji@0 198 * pointer to return size
yuuji@0 199 * pointer to return continuation flag
yuuji@0 200 * Returns: text line string, size and continuation flag, or NIL if failure
yuuji@0 201 */
yuuji@0 202
yuuji@0 203 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
yuuji@0 204 long *contd)
yuuji@0 205 {
yuuji@0 206 unsigned long n;
yuuji@0 207 char *s,*ret,c,d;
yuuji@0 208 *contd = NIL; /* assume no continuation */
yuuji@0 209 /* make sure have data */
yuuji@0 210 if (!tcp_getdata (stream)) return NIL;
yuuji@0 211 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
yuuji@0 212 d = *stream->iptr++; /* slurp another character */
yuuji@0 213 if ((c == '\015') && (d == '\012')) {
yuuji@0 214 ret = (char *) fs_get (n--);
yuuji@0 215 memcpy (ret,s,*size = n); /* copy into a free storage string */
yuuji@0 216 ret[n] = '\0'; /* tie off string with null */
yuuji@0 217 return ret;
yuuji@0 218 }
yuuji@0 219 }
yuuji@0 220 /* copy partial string from buffer */
yuuji@0 221 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
yuuji@0 222 /* get more data from the net */
yuuji@0 223 if (!tcp_getdata (stream)) fs_give ((void **) &ret);
yuuji@0 224 /* special case of newline broken by buffer */
yuuji@0 225 else if ((c == '\015') && (*stream->iptr == '\012')) {
yuuji@0 226 stream->iptr++; /* eat the line feed */
yuuji@0 227 stream->ictr--;
yuuji@0 228 ret[*size = --n] = '\0'; /* tie off string with null */
yuuji@0 229 }
yuuji@0 230 else *contd = LONGT; /* continuation needed */
yuuji@0 231 return ret;
yuuji@0 232 }
yuuji@0 233
yuuji@0 234 /* TCP/IP receive buffer
yuuji@0 235 * Accepts: TCP/IP stream
yuuji@0 236 * size in bytes
yuuji@0 237 * buffer to read into
yuuji@0 238 * Returns: T if success, NIL otherwise
yuuji@0 239 */
yuuji@0 240
yuuji@0 241 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
yuuji@0 242 {
yuuji@0 243 unsigned long n;
yuuji@0 244 char *bufptr = buffer;
yuuji@0 245 while (size > 0) { /* until request satisfied */
yuuji@0 246 if (!tcp_getdata (stream)) return NIL;
yuuji@0 247 n = min (size,stream->ictr);/* number of bytes to transfer */
yuuji@0 248 /* do the copy */
yuuji@0 249 memcpy (bufptr,stream->iptr,n);
yuuji@0 250 bufptr += n; /* update pointer */
yuuji@0 251 stream->iptr +=n;
yuuji@0 252 size -= n; /* update # of bytes to do */
yuuji@0 253 stream->ictr -=n;
yuuji@0 254 }
yuuji@0 255 bufptr[0] = '\0'; /* tie off string */
yuuji@0 256 return T;
yuuji@0 257 }
yuuji@0 258
yuuji@0 259 /* TCP/IP receive data
yuuji@0 260 * Accepts: TCP/IP stream
yuuji@0 261 * Returns: T if success, NIL otherwise
yuuji@0 262 */
yuuji@0 263
yuuji@0 264 long tcp_getdata (TCPSTREAM *stream)
yuuji@0 265 {
yuuji@0 266 int i;
yuuji@0 267 fd_set fds,efds;
yuuji@0 268 struct timeval tmo;
yuuji@0 269 time_t t = time (0);
yuuji@0 270 if (stream->tcps < 0) return NIL;
yuuji@0 271 while (stream->ictr < 1) { /* if nothing in the buffer */
yuuji@0 272 time_t tl = time (0); /* start of request */
yuuji@0 273 tmo.tv_sec = ttmo_read; /* read timeout */
yuuji@0 274 tmo.tv_usec = 0;
yuuji@0 275 FD_ZERO (&fds); /* initialize selection vector */
yuuji@0 276 FD_ZERO (&efds); /* handle errors too */
yuuji@0 277 FD_SET (stream->tcps,&fds);/* set bit in selection vector */
yuuji@0 278 FD_SET(stream->tcps,&efds);/* set bit in error selection vector */
yuuji@0 279 errno = NIL; /* block and read */
yuuji@0 280 while (((i = select (stream->tcps+1,&fds,0,&efds,ttmo_read ? &tmo : 0))<0)
yuuji@0 281 && (errno == EINTR));
yuuji@0 282 if (!i) { /* timeout? */
yuuji@0 283 time_t tc = time (0);
yuuji@0 284 if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
yuuji@0 285 else return tcp_abort (stream);
yuuji@0 286 }
yuuji@0 287 else if (i < 0) return tcp_abort (stream);
yuuji@0 288 while (((i = read (stream->tcps,stream->ibuf,BUFLEN)) < 0) &&
yuuji@0 289 (errno == EINTR));
yuuji@0 290 if (i < 1) return tcp_abort (stream);
yuuji@0 291 stream->iptr = stream->ibuf;/* point at TCP buffer */
yuuji@0 292 stream->ictr = i; /* set new byte count */
yuuji@0 293 }
yuuji@0 294 return T;
yuuji@0 295 }
yuuji@0 296
yuuji@0 297 /* TCP/IP send string as record
yuuji@0 298 * Accepts: TCP/IP stream
yuuji@0 299 * string pointer
yuuji@0 300 * Returns: T if success else NIL
yuuji@0 301 */
yuuji@0 302
yuuji@0 303 long tcp_soutr (TCPSTREAM *stream,char *string)
yuuji@0 304 {
yuuji@0 305 return tcp_sout (stream,string,(unsigned long) strlen (string));
yuuji@0 306 }
yuuji@0 307
yuuji@0 308
yuuji@0 309 /* TCP/IP send string
yuuji@0 310 * Accepts: TCP/IP stream
yuuji@0 311 * string pointer
yuuji@0 312 * byte count
yuuji@0 313 * Returns: T if success else NIL
yuuji@0 314 */
yuuji@0 315
yuuji@0 316 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
yuuji@0 317 {
yuuji@0 318 int i;
yuuji@0 319 fd_set fds;
yuuji@0 320 struct timeval tmo;
yuuji@0 321 time_t t = time (0);
yuuji@0 322 if (stream->tcps < 0) return NIL;
yuuji@0 323 while (size > 0) { /* until request satisfied */
yuuji@0 324 time_t tl = time (0); /* start of request */
yuuji@0 325 tmo.tv_sec = ttmo_write; /* write timeout */
yuuji@0 326 tmo.tv_usec = 0;
yuuji@0 327 FD_ZERO (&fds); /* initialize selection vector */
yuuji@0 328 FD_SET (stream->tcps,&fds);/* set bit in selection vector */
yuuji@0 329 errno = NIL; /* block and write */
yuuji@0 330 while (((i = select (stream->tcps+1,0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
yuuji@0 331 && (errno == EINTR));
yuuji@0 332 if (!i) { /* timeout? */
yuuji@0 333 time_t tc = time (0);
yuuji@0 334 if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
yuuji@0 335 else return tcp_abort (stream);
yuuji@0 336 }
yuuji@0 337 else if (i < 0) return tcp_abort (stream);
yuuji@0 338 while (((i = write (stream->tcps,string,size)) < 0) && (errno == EINTR));
yuuji@0 339 if (i < 0) return tcp_abort (stream);
yuuji@0 340 size -= i; /* how much we sent */
yuuji@0 341 string += i;
yuuji@0 342 }
yuuji@0 343 return T; /* all done */
yuuji@0 344 }
yuuji@0 345
yuuji@0 346 /* TCP/IP close
yuuji@0 347 * Accepts: TCP/IP stream
yuuji@0 348 */
yuuji@0 349
yuuji@0 350 void tcp_close (TCPSTREAM *stream)
yuuji@0 351 {
yuuji@0 352 tcp_abort (stream); /* nuke the socket */
yuuji@0 353 /* flush host names */
yuuji@0 354 fs_give ((void **) &stream->host);
yuuji@0 355 fs_give ((void **) &stream->localhost);
yuuji@0 356 fs_give ((void **) &stream); /* flush the stream */
yuuji@0 357 }
yuuji@0 358
yuuji@0 359
yuuji@0 360 /* TCP/IP abort stream
yuuji@0 361 * Accepts: TCP/IP stream
yuuji@0 362 * Returns: NIL always
yuuji@0 363 */
yuuji@0 364
yuuji@0 365 long tcp_abort (TCPSTREAM *stream)
yuuji@0 366 {
yuuji@0 367 if (stream->tcps >= 0) close (stream->tcps);
yuuji@0 368 stream->tcps = -1;
yuuji@0 369 return NIL;
yuuji@0 370 }
yuuji@0 371
yuuji@0 372 /* TCP/IP get host name
yuuji@0 373 * Accepts: TCP/IP stream
yuuji@0 374 * Returns: host name for this stream
yuuji@0 375 */
yuuji@0 376
yuuji@0 377 char *tcp_host (TCPSTREAM *stream)
yuuji@0 378 {
yuuji@0 379 return stream->host; /* return host name */
yuuji@0 380 }
yuuji@0 381
yuuji@0 382
yuuji@0 383 /* TCP/IP get remote host name
yuuji@0 384 * Accepts: TCP/IP stream
yuuji@0 385 * Returns: host name for this stream
yuuji@0 386 */
yuuji@0 387
yuuji@0 388 char *tcp_remotehost (TCPSTREAM *stream)
yuuji@0 389 {
yuuji@0 390 return stream->host; /* all we can do for now */
yuuji@0 391 }
yuuji@0 392
yuuji@0 393
yuuji@0 394 /* TCP/IP return port for this stream
yuuji@0 395 * Accepts: TCP/IP stream
yuuji@0 396 * Returns: port number for this stream
yuuji@0 397 */
yuuji@0 398
yuuji@0 399 unsigned long tcp_port (TCPSTREAM *stream)
yuuji@0 400 {
yuuji@0 401 return stream->port; /* return port number */
yuuji@0 402 }
yuuji@0 403
yuuji@0 404
yuuji@0 405 /* TCP/IP get local host name
yuuji@0 406 * Accepts: TCP/IP stream
yuuji@0 407 * Returns: local host name
yuuji@0 408 */
yuuji@0 409
yuuji@0 410 char *tcp_localhost (TCPSTREAM *stream)
yuuji@0 411 {
yuuji@0 412 return stream->localhost; /* return local host name */
yuuji@0 413 }
yuuji@0 414
yuuji@0 415
yuuji@0 416 /* TCP/IP return canonical form of host name
yuuji@0 417 * Accepts: host name
yuuji@0 418 * Returns: canonical form of host name
yuuji@0 419 */
yuuji@0 420
yuuji@0 421 char *tcp_canonical (char *name)
yuuji@0 422 {
yuuji@0 423 return name;
yuuji@0 424 }
yuuji@0 425
yuuji@0 426
yuuji@0 427 /* TCP/IP get client host name (server calls only)
yuuji@0 428 * Returns: client host name
yuuji@0 429 */
yuuji@0 430
yuuji@0 431 char *tcp_clienthost ()
yuuji@0 432 {
yuuji@0 433 return "UNKNOWN";
yuuji@0 434 }

UW-IMAP'd extensions by yuuji