imapext-2007

view src/osdep/amiga/tcp_ami.c @ 0:ada5e610ab86

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

UW-IMAP'd extensions by yuuji