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