1 /* ========================================================================
2 * Copyright 2008-2010 Mark Crispin
3 * ========================================================================
7 * Program: Winsock TCP/IP routines
9 * Author: Mark Crispin from Mike Seibel's Winsock code
12 * Last Edited: 3 April 2010
14 * Previous versions of this file were:
16 * Copyright 1988-2008 University of Washington
18 * Licensed under the Apache License, Version 2.0 (the "License");
19 * you may not use this file except in compliance with the License.
20 * You may obtain a copy of the License at
22 * http://www.apache.org/licenses/LICENSE-2.0
26 #define TCPMAXSEND 32768
28 /* Private functions */
30 int tcp_socket_open (struct sockaddr_in
*sin
,char *tmp
,char *hst
,
32 static char *tcp_getline_work (TCPSTREAM
*stream
,unsigned long *size
,
34 long tcp_abort (TCPSTREAM
*stream
);
35 long tcp_close_socket (SOCKET
*sock
);
36 char *tcp_name (struct sockaddr_in
*sin
,long flag
);
37 char *tcp_name_valid (char *s
);
42 int wsa_initted
= 0; /* init ? */
43 static int wsa_sock_open
= 0; /* keep track of open sockets */
44 static tcptimeout_t tmoh
= NIL
; /* TCP timeout handler routine */
45 static long ttmo_read
= 0; /* TCP timeouts, in seconds */
46 static long ttmo_write
= 0;
47 static long allowreversedns
= T
;/* allow reverse DNS lookup */
48 static long tcpdebug
= NIL
; /* extra TCP debugging telemetry */
50 /* TCP/IP manipulate parameters
51 * Accepts: function code
52 * function-dependent value
53 * Returns: function-dependent return value
56 void *tcp_parameters (long function
,void *value
)
59 switch ((int) function
) {
61 tmoh
= (tcptimeout_t
) value
;
66 ttmo_read
= (long) value
;
68 ret
= (void *) ttmo_read
;
70 case SET_WRITETIMEOUT
:
71 ttmo_write
= (long) value
;
72 case GET_WRITETIMEOUT
:
73 ret
= (void *) ttmo_write
;
75 case SET_ALLOWREVERSEDNS
:
76 allowreversedns
= (long) value
;
77 case GET_ALLOWREVERSEDNS
:
78 ret
= (void *) allowreversedns
;
81 tcpdebug
= (long) value
;
83 ret
= (void *) tcpdebug
;
91 * contact service name
92 * contact port number and optional silent flag
93 * Returns: TCP/IP stream if success else NIL
96 TCPSTREAM
*tcp_open (char *host
,char *service
,unsigned long port
)
98 TCPSTREAM
*stream
= NIL
;
100 SOCKET sock
= INVALID_SOCKET
;
101 int silent
= (port
& NET_SILENT
) ? T
: NIL
;
103 struct sockaddr_in sin
;
105 char hostname
[MAILTMPLEN
];
106 char tmp
[MAILTMPLEN
];
107 struct servent
*sv
= NIL
;
108 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
109 if (!wsa_initted
++) { /* init Windows Sockets */
111 if (i
= (int) WSAStartup (WSA_VERSION
,&wsock
)) {
112 wsa_initted
= 0; /* in case we try again */
113 sprintf (tmp
,"Unable to start Windows Sockets (%d)",i
);
118 port
&= 0xffff; /* erase flags */
120 if (service
&& (sv
= getservbyname (service
,"tcp")))
121 port
= ntohs (sin
.sin_port
= sv
->s_port
);
122 /* copy port number in network format */
123 else sin
.sin_port
= htons ((u_short
) port
);
124 /* The domain literal form is used (rather than simply the dotted decimal
125 as with other Windows programs) because it has to be a valid "host name"
126 in mailsystem terminology. */
127 sin
.sin_family
= AF_INET
; /* family is always Internet */
128 /* look like domain literal? */
129 if (host
[0] == '[' && host
[(strlen (host
))-1] == ']') {
130 strcpy (tmp
,host
+1); /* yes, copy number part */
131 tmp
[strlen (tmp
)-1] = '\0';
132 if ((sin
.sin_addr
.s_addr
= inet_addr (tmp
)) == INADDR_NONE
) {
133 sprintf (tmp
,"Bad format domain-literal: %.80s",host
);
138 sin
.sin_family
= AF_INET
; /* family is always Internet */
139 strcpy (hostname
,host
);
140 (*bn
) (BLOCK_TCPOPEN
,NIL
);
141 sock
= tcp_socket_open (&sin
,tmp
,hostname
,port
);
142 (*bn
) (BLOCK_NONE
,NIL
);
146 else { /* lookup host name */
148 sprintf (tmp
,"DNS resolution %.80s",host
);
149 mm_log (tmp
,TCPDEBUG
);
151 (*bn
) (BLOCK_DNSLOOKUP
,NIL
);/* look up name */
152 if (!(he
= gethostbyname (lcase (strcpy (tmp
,host
)))))
153 sprintf (tmp
,"Host not found (#%d): %s",WSAGetLastError(),host
);
154 (*bn
) (BLOCK_NONE
,NIL
);
155 if (he
) { /* DNS resolution won? */
156 if (tcpdebug
) mm_log ("DNS resolution done",TCPDEBUG
);
157 /* copy address type */
158 sin
.sin_family
= he
->h_addrtype
;
160 strcpy (hostname
,he
->h_name
);
161 wsa_sock_open
++; /* prevent tcp_close_socket() from freeing in
163 for (i
= 0; (sock
== INVALID_SOCKET
) && (s
= he
->h_addr_list
[i
]); i
++) {
164 if (i
&& !silent
) mm_log (tmp
,WARN
);
165 memcpy (&sin
.sin_addr
,s
,he
->h_length
);
166 (*bn
) (BLOCK_TCPOPEN
,NIL
);
167 sock
= tcp_socket_open (&sin
,tmp
,hostname
,port
);
168 (*bn
) (BLOCK_NONE
,NIL
);
170 wsa_sock_open
--; /* undo protection */
173 if (sock
== INVALID_SOCKET
) { /* error? */
174 if (!silent
) mm_log (tmp
,ERROR
);
175 tcp_close_socket (&sock
); /* do possible cleanup action */
177 else { /* got a socket, create TCP/IP stream */
178 stream
= (TCPSTREAM
*) memset (fs_get (sizeof (TCPSTREAM
)),0,
180 stream
->port
= port
; /* port number */
182 stream
->tcpsi
= stream
->tcpso
= sock
;
183 stream
->ictr
= 0; /* init input counter */
184 /* copy official host name */
185 stream
->host
= cpystr (hostname
);
186 if (tcpdebug
) mm_log ("Stream open and ready for read",TCPDEBUG
);
188 return stream
; /* return success */
192 * Accepts: Internet socket address block
194 * host name for error message
195 * port number for error message
196 * Returns: socket if success, else -1 with error string in scratch buffer
199 int tcp_socket_open (struct sockaddr_in
*sin
,char *tmp
,char *hst
,
204 sprintf (tmp
,"Trying IP address [%s]",inet_ntoa (sin
->sin_addr
));
206 /* get a TCP stream */
207 if ((sock
= socket (sin
->sin_family
,SOCK_STREAM
,0)) == INVALID_SOCKET
) {
208 sprintf (tmp
,"Unable to create TCP socket (%d)",WSAGetLastError());
211 wsa_sock_open
++; /* count this socket as open */
212 /* open connection */
213 if (connect (sock
,(struct sockaddr
*) sin
,sizeof (struct sockaddr_in
)) ==
215 switch (WSAGetLastError ()){/* analyze error */
216 case WSAECONNREFUSED
:
220 s
= "Insufficient system resources";
225 case WSAEHOSTUNREACH
:
226 s
= "Host unreachable";
232 sprintf (tmp
,"Can't connect to %.80s,%ld: %s (%d)",hst
,port
,s
,
234 tcp_close_socket (&sock
); /* flush socket */
235 sock
= INVALID_SOCKET
;
237 return sock
; /* return the socket */
240 /* TCP/IP authenticated open
241 * Accepts: NETMBX specifier
243 * returned user name buffer
244 * Returns: TCP/IP stream if success else NIL
247 TCPSTREAM
*tcp_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
249 return NIL
; /* always NIL on Windows */
253 * Accepts: TCP stream
254 * Returns: text line string or NIL if failure
257 char *tcp_getline (TCPSTREAM
*stream
)
259 unsigned long n
,contd
;
260 char *ret
= tcp_getline_work (stream
,&n
,&contd
);
261 if (ret
&& contd
) { /* got a line needing continuation? */
262 STRINGLIST
*stl
= mail_newstringlist ();
263 STRINGLIST
*stc
= stl
;
264 do { /* collect additional lines */
265 stc
->text
.data
= (unsigned char *) ret
;
267 stc
= stc
->next
= mail_newstringlist ();
268 ret
= tcp_getline_work (stream
,&n
,&contd
);
269 } while (ret
&& contd
);
270 if (ret
) { /* stash final part of line on list */
271 stc
->text
.data
= (unsigned char *) ret
;
273 /* determine how large a buffer we need */
274 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
275 ret
= fs_get (n
+ 1); /* copy parts into buffer */
276 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
277 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
280 mail_free_stringlist (&stl
);/* either way, done with list */
285 /* TCP receive line or partial line
286 * Accepts: TCP stream
287 * pointer to return size
288 * pointer to return continuation flag
289 * Returns: text line string, size and continuation flag, or NIL if failure
292 static char *tcp_getline_work (TCPSTREAM
*stream
,unsigned long *size
,
297 *contd
= NIL
; /* assume no continuation */
298 /* make sure have data */
299 if (!tcp_getdata (stream
)) return NIL
;
300 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
301 d
= *stream
->iptr
++; /* slurp another character */
302 if ((c
== '\015') && (d
== '\012')) {
303 ret
= (char *) fs_get (n
--);
304 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
305 ret
[n
] = '\0'; /* tie off string with null */
309 /* copy partial string from buffer */
310 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
311 /* get more data from the net */
312 if (!tcp_getdata (stream
)) fs_give ((void **) &ret
);
313 /* special case of newline broken by buffer */
314 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
315 stream
->iptr
++; /* eat the line feed */
317 ret
[*size
= --n
] = '\0'; /* tie off string with null */
319 else *contd
= LONGT
; /* continuation needed */
323 /* TCP/IP receive buffer
324 * Accepts: TCP/IP stream
326 * buffer to read into
327 * Returns: T if success, NIL otherwise
330 long tcp_getbuffer (TCPSTREAM
*stream
,unsigned long size
,char *s
)
333 /* make sure socket still alive */
334 if (stream
->tcpsi
== INVALID_SOCKET
) return NIL
;
335 /* can transfer bytes from buffer? */
336 if (n
= min (size
,stream
->ictr
)) {
337 memcpy (s
,stream
->iptr
,n
); /* yes, slurp as much as we can from it */
338 s
+= n
; /* update pointer */
340 size
-= n
; /* update # of bytes to do */
347 time_t tc
,t
= time (0);
348 blocknotify_t bn
=(blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
349 (*bn
) (BLOCK_TCPREAD
,NIL
);
350 while (size
> 0) { /* until request satisfied */
351 time_t tl
= time (0);
352 if (tcpdebug
) mm_log ("Reading TCP buffer",TCPDEBUG
);
353 FD_ZERO (&fds
); /* initialize selection vector */
354 FD_SET (stream
->tcpsi
,&fds
);/* set bit in selection vector */
355 tmo
.tv_sec
= ttmo_read
;
358 switch ((stream
->tcpsi
== stream
->tcpso
) ?
359 select (stream
->tcpsi
+1,&fds
,0,0,
360 ttmo_read
? &tmo
: (struct timeval
*) 0) : 1) {
361 case SOCKET_ERROR
: /* error */
362 if (WSAGetLastError () != WSAEINTR
) return tcp_abort (stream
);
364 case 0: /* timeout */
366 if (tmoh
&& ((*tmoh
) (tc
- t
,tc
- tl
))) break;
367 return tcp_abort (stream
);
369 if (stream
->tcpsi
== stream
->tcpso
)
370 while (((i
= recv (stream
->tcpsi
,s
,(int) min (maxposint
,size
),0)) ==
371 SOCKET_ERROR
) && (WSAGetLastError () == WSAEINTR
));
372 else while (((i
= read (stream
->tcpsi
,s
,(int) min (maxposint
,size
))) <
373 0) && (errno
== EINTR
));
375 case SOCKET_ERROR
: /* error */
376 case 0: /* no data read */
377 return tcp_abort (stream
);
379 s
+= i
; /* point at new place to write */
380 size
-= i
; /* reduce byte count */
381 if (tcpdebug
) mm_log ("Successfully read TCP buffer",TCPDEBUG
);
385 (*bn
) (BLOCK_NONE
,NIL
);
387 *s
= '\0'; /* tie off string */
391 /* TCP/IP receive data
392 * Accepts: TCP/IP stream
393 * Returns: T if success, NIL otherwise
396 long tcp_getdata (TCPSTREAM
*stream
)
401 time_t tc
,t
= time (0);
402 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
403 FD_ZERO (&fds
); /* initialize selection vector */
404 if (stream
->tcpsi
== INVALID_SOCKET
) return NIL
;
405 (*bn
) (BLOCK_TCPREAD
,NIL
);
406 tmo
.tv_sec
= ttmo_read
;
408 while (stream
->ictr
< 1) { /* if nothing in the buffer */
409 time_t tl
= time (0);
410 if (tcpdebug
) mm_log ("Reading TCP data",TCPDEBUG
);
411 FD_SET (stream
->tcpsi
,&fds
);/* set bit in selection vector */
413 switch ((stream
->tcpsi
== stream
->tcpso
) ?
414 select (stream
->tcpsi
+1,&fds
,0,0,
415 ttmo_read
? &tmo
: (struct timeval
*) 0) : 1) {
416 case SOCKET_ERROR
: /* error */
417 if (WSAGetLastError () != WSAEINTR
) return tcp_abort (stream
);
419 case 0: /* timeout */
421 if (tmoh
&& ((*tmoh
) (tc
- t
,tc
- tl
))) break;
422 return tcp_abort (stream
);
424 if (stream
->tcpsi
== stream
->tcpso
)
425 while (((i
= recv (stream
->tcpsi
,stream
->ibuf
,BUFLEN
,0)) ==
426 SOCKET_ERROR
) && (WSAGetLastError () == WSAEINTR
));
427 else while (((i
= read (stream
->tcpsi
,stream
->ibuf
,BUFLEN
)) < 0) &&
430 case SOCKET_ERROR
: /* error */
431 case 0: /* no data read */
432 return tcp_abort (stream
);
434 stream
->ictr
= i
; /* set new byte count */
435 /* point at TCP buffer */
436 stream
->iptr
= stream
->ibuf
;
437 if (tcpdebug
) mm_log ("Successfully read TCP data",TCPDEBUG
);
441 (*bn
) (BLOCK_NONE
,NIL
);
445 /* TCP/IP send string as record
446 * Accepts: TCP/IP stream
448 * Returns: T if success else NIL
451 long tcp_soutr (TCPSTREAM
*stream
,char *string
)
453 return tcp_sout (stream
,string
,(unsigned long) strlen (string
));
457 /* TCP/IP send string
458 * Accepts: TCP/IP stream
461 * Returns: T if success else NIL
464 long tcp_sout (TCPSTREAM
*stream
,char *string
,unsigned long size
)
469 time_t tc
,t
= time (0);
470 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
471 tmo
.tv_sec
= ttmo_write
;
473 FD_ZERO (&fds
); /* initialize selection vector */
474 if (stream
->tcpso
== INVALID_SOCKET
) return NIL
;
475 (*bn
) (BLOCK_TCPWRITE
,NIL
);
476 while (size
> 0) { /* until request satisfied */
477 time_t tl
= time (0);
478 if (tcpdebug
) mm_log ("Writing to TCP",TCPDEBUG
);
479 FD_SET (stream
->tcpso
,&fds
);/* set bit in selection vector */
480 /* block and write */
481 switch ((stream
->tcpsi
== stream
->tcpso
) ?
482 select (stream
->tcpso
+1,NULL
,&fds
,NULL
,
483 tmo
.tv_sec
? &tmo
: (struct timeval
*) 0) : 1) {
484 case SOCKET_ERROR
: /* error */
485 if (WSAGetLastError () != WSAEINTR
) return tcp_abort (stream
);
487 case 0: /* timeout */
489 if (tmoh
&& ((*tmoh
) (tc
- t
,tc
- tl
))) break;
490 return tcp_abort (stream
);
492 if (stream
->tcpsi
== stream
->tcpso
)
493 while (((i
= send (stream
->tcpso
,string
,
494 (int) min (size
,TCPMAXSEND
),0)) == SOCKET_ERROR
) &&
495 (WSAGetLastError () == WSAEINTR
));
496 else while (((i
= write (stream
->tcpso
,string
,
497 min (size
,TCPMAXSEND
))) < 0) &&
499 if (i
== SOCKET_ERROR
) return tcp_abort (stream
);
500 size
-= i
; /* count this size */
501 if (tcpdebug
) mm_log ("successfully wrote to TCP",TCPDEBUG
);
505 (*bn
) (BLOCK_NONE
,NIL
);
506 return T
; /* all done */
511 * Accepts: TCP/IP stream
514 void tcp_close (TCPSTREAM
*stream
)
516 tcp_abort (stream
); /* nuke the sockets */
517 /* flush host names */
518 if (stream
->host
) fs_give ((void **) &stream
->host
);
519 if (stream
->remotehost
) fs_give ((void **) &stream
->remotehost
);
520 if (stream
->localhost
) fs_give ((void **) &stream
->localhost
);
521 fs_give ((void **) &stream
); /* flush the stream */
525 /* TCP/IP abort sockets
526 * Accepts: TCP/IP stream
527 * Returns: NIL, always
530 long tcp_abort (TCPSTREAM
*stream
)
532 if (stream
->tcpsi
!= stream
->tcpso
) tcp_close_socket (&stream
->tcpso
);
533 else stream
->tcpso
= INVALID_SOCKET
;
534 return tcp_close_socket (&stream
->tcpsi
);
538 /* TCP/IP abort stream
539 * Accepts: WinSock socket
540 * Returns: NIL, always
543 long tcp_close_socket (SOCKET
*sock
)
545 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
546 /* something to close? */
547 if (sock
&& (*sock
!= INVALID_SOCKET
)) {
548 (*bn
) (BLOCK_TCPCLOSE
,NIL
);
549 closesocket (*sock
); /* WinSock socket close */
550 *sock
= INVALID_SOCKET
;
551 (*bn
) (BLOCK_NONE
,NIL
);
552 wsa_sock_open
--; /* drop this socket */
554 /* no more open streams? */
555 if (wsa_initted
&& !wsa_sock_open
) {
556 mm_log ("Winsock cleanup",NIL
);
557 wsa_initted
= 0; /* no more sockets, so... */
558 WSACleanup (); /* free up resources until needed */
563 /* TCP/IP get host name
564 * Accepts: TCP/IP stream
565 * Returns: host name for this stream
568 char *tcp_host (TCPSTREAM
*stream
)
570 return stream
->host
; /* use tcp_remotehost() if want guarantees */
574 /* TCP/IP get remote host name
575 * Accepts: TCP/IP stream
576 * Returns: host name for this stream
579 char *tcp_remotehost (TCPSTREAM
*stream
)
581 if (!stream
->remotehost
) {
582 struct sockaddr_in sin
;
583 int sinlen
= sizeof (struct sockaddr_in
);
584 stream
->remotehost
= /* get socket's peer name */
585 ((getpeername (stream
->tcpsi
,(struct sockaddr
*) &sin
,&sinlen
) ==
586 SOCKET_ERROR
) || (sinlen
<= 0)) ?
587 cpystr (stream
->host
) : tcp_name (&sin
,NIL
);
589 return stream
->remotehost
;
593 /* TCP/IP return port for this stream
594 * Accepts: TCP/IP stream
595 * Returns: port number for this stream
598 unsigned long tcp_port (TCPSTREAM
*stream
)
600 return stream
->port
; /* return port number */
604 /* TCP/IP get local host name
605 * Accepts: TCP/IP stream
606 * Returns: local host name
609 char *tcp_localhost (TCPSTREAM
*stream
)
611 if (!stream
->localhost
) {
612 struct sockaddr_in sin
;
613 int sinlen
= sizeof (struct sockaddr_in
);
614 stream
->localhost
= /* get socket's name */
615 ((stream
->port
& 0xffff000) ||
616 ((getsockname (stream
->tcpsi
,(struct sockaddr
*) &sin
,&sinlen
) ==
617 SOCKET_ERROR
) || (sinlen
<= 0))) ?
618 cpystr (mylocalhost ()) : tcp_name (&sin
,NIL
);
620 return stream
->localhost
; /* return local host name */
623 /* TCP/IP get client host address (server calls only)
624 * Returns: client host address
627 char *tcp_clientaddr ()
630 struct sockaddr_in sin
;
631 int sinlen
= sizeof (struct sockaddr_in
);
632 myClientAddr
= /* get stdin's peer name */
633 ((getpeername (0,(struct sockaddr
*) &sin
,&sinlen
) == SOCKET_ERROR
) ||
634 (sinlen
<= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin
.sin_addr
));
640 /* TCP/IP get client host name (server calls only)
641 * Returns: client host name
644 char *tcp_clienthost ()
647 struct sockaddr_in sin
;
648 int sinlen
= sizeof (struct sockaddr_in
);
649 myClientHost
= /* get stdin's peer name */
650 ((getpeername (0,(struct sockaddr
*) &sin
,&sinlen
) == SOCKET_ERROR
) ||
651 (sinlen
<= 0)) ? cpystr ("UNKNOWN") : tcp_name (&sin
,T
);
656 /* TCP/IP get server host address (server calls only)
657 * Returns: server host address
660 char *tcp_serveraddr ()
663 struct sockaddr_in sin
;
664 int sinlen
= sizeof (struct sockaddr_in
);
665 myServerAddr
= /* get stdin's peer name */
666 ((getsockname (0,(struct sockaddr
*) &sin
,&sinlen
) == SOCKET_ERROR
) ||
667 (sinlen
<= 0)) ? cpystr ("UNKNOWN") : cpystr (inet_ntoa (sin
.sin_addr
));
673 /* TCP/IP get server host name (server calls only)
674 * Returns: server host name
677 static long myServerPort
= -1;
679 char *tcp_serverhost ()
682 struct sockaddr_in sin
;
683 int sinlen
= sizeof (struct sockaddr_in
);
684 if (!wsa_initted
++) { /* init Windows Sockets */
686 if (WSAStartup (WSA_VERSION
,&wsock
)) {
688 return "random-pc"; /* try again later? */
691 /* get stdin's name */
692 if ((getsockname (0,(struct sockaddr
*) &sin
,&sinlen
) == SOCKET_ERROR
) ||
693 (sinlen
<= 0)) myServerHost
= cpystr (mylocalhost ());
695 myServerHost
= tcp_name (&sin
,NIL
);
696 myServerPort
= ntohs (sin
.sin_port
);
703 /* TCP/IP get server port number (server calls only)
704 * Returns: server port number
707 long tcp_serverport ()
709 if (!myServerHost
) tcp_serverhost ();
713 /* TCP/IP return canonical form of host name
715 * Returns: canonical form of host name
718 char *tcp_canonical (char *name
)
720 char *ret
,host
[MAILTMPLEN
];
722 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
723 /* look like domain literal? */
724 if (name
[0] == '[' && name
[strlen (name
) - 1] == ']') return name
;
725 (*bn
) (BLOCK_DNSLOOKUP
,NIL
);
727 sprintf (host
,"DNS canonicalization %.80s",name
);
728 mm_log (host
,TCPDEBUG
);
730 /* note that NT requires lowercase! */
731 ret
= (he
= gethostbyname (lcase (strcpy (host
,name
)))) ? he
->h_name
: name
;
732 (*bn
) (BLOCK_NONE
,NIL
);
733 if (tcpdebug
) mm_log ("DNS canonicalization done",TCPDEBUG
);
738 /* TCP/IP return name from socket
741 * Returns: cpystr name
744 char *tcp_name (struct sockaddr_in
*sin
,long flag
)
746 char *ret
,*t
,adr
[MAILTMPLEN
],tmp
[MAILTMPLEN
];
747 sprintf (ret
= adr
,"[%.80s]",inet_ntoa (sin
->sin_addr
));
748 if (allowreversedns
) {
750 blocknotify_t bn
= (blocknotify_t
)mail_parameters(NIL
,GET_BLOCKNOTIFY
,NIL
);
753 sprintf (tmp
,"Reverse DNS resolution %s",adr
);
754 mm_log (tmp
,TCPDEBUG
);
756 (*bn
) (BLOCK_DNSLOOKUP
,NIL
);/* quell alarms */
757 data
= (*bn
) (BLOCK_SENSITIVE
,NIL
);
758 /* translate address to name */
759 if (t
= tcp_name_valid ((he
= gethostbyaddr ((char *) &sin
->sin_addr
,
760 sizeof (struct in_addr
),
762 (char *) he
->h_name
: NIL
)) {
763 /* produce verbose form if needed */
764 if (flag
) sprintf (ret
= tmp
,"%s %s",t
,adr
);
767 (*bn
) (BLOCK_NONSENSITIVE
,data
);
768 (*bn
) (BLOCK_NONE
,NIL
); /* alarms OK now */
769 if (tcpdebug
) mm_log ("Reverse DNS resolution done",TCPDEBUG
);
774 /* Return my local host name
775 * Returns: my local host name
778 char *mylocalhost (void)
781 char tmp
[MAILTMPLEN
];
782 if (!wsa_initted
++) { /* init Windows Sockets */
784 if (WSAStartup (WSA_VERSION
,&wsock
))
787 if (wsa_initted
&& gethostname (tmp
,MAILTMPLEN
-1) != SOCKET_ERROR
)
788 myLocalHost
= tcp_canonical (tmp
));
790 return myLocalHost
? myLocalHost
: "random-pc";
795 * Accepts: domain name
796 * Returns: T if valid, NIL otherwise
799 char *tcp_name_valid (char *s
)
803 /* must be non-empty and not too long */
804 if ((ret
= (s
&& *s
) ? s
: NIL
) && (tail
= ret
+ NETMAXHOST
)) {
805 /* must be alnum, dot, or hyphen */
806 while ((c
= *s
++) && (s
<= tail
) &&
807 (((c
>= 'A') && (c
<= 'Z')) || ((c
>= 'a') && (c
<= 'z')) ||
808 ((c
>= '0') && (c
<= '9')) || (c
== '-') || (c
== '.')));