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: Waterloo 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
|
yuuji@0
|
30 /* Global data */
|
yuuji@0
|
31
|
yuuji@0
|
32 short sock_initted = 0; /* global so others using net can see it */
|
yuuji@0
|
33
|
yuuji@0
|
34 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
|
yuuji@0
|
35 long *contd);
|
yuuji@0
|
36
|
yuuji@0
|
37 /* TCP/IP manipulate parameters
|
yuuji@0
|
38 * Accepts: function code
|
yuuji@0
|
39 * function-dependent value
|
yuuji@0
|
40 * Returns: function-dependent return value
|
yuuji@0
|
41 */
|
yuuji@0
|
42
|
yuuji@0
|
43 void *tcp_parameters (long function,void *value)
|
yuuji@0
|
44 {
|
yuuji@0
|
45 return NIL;
|
yuuji@0
|
46 }
|
yuuji@0
|
47
|
yuuji@0
|
48 /* TCP/IP open
|
yuuji@0
|
49 * Accepts: host name
|
yuuji@0
|
50 * contact service name
|
yuuji@0
|
51 * contact port number
|
yuuji@0
|
52 * Returns: TCP/IP stream if success else NIL
|
yuuji@0
|
53 */
|
yuuji@0
|
54
|
yuuji@0
|
55 TCPSTREAM *TCP_open (char *host,char *service,unsigned long port)
|
yuuji@0
|
56 {
|
yuuji@0
|
57 TCPSTREAM *stream = NIL;
|
yuuji@0
|
58 tcp_Socket *sock;
|
yuuji@0
|
59 char *s,tmp[MAILTMPLEN];
|
yuuji@0
|
60 unsigned long adr,i,j,k,l;
|
yuuji@0
|
61 port &= 0xffff; /* erase flags */
|
yuuji@0
|
62 /* initialize if first time here */
|
yuuji@0
|
63 if (!sock_initted++) sock_init();
|
yuuji@0
|
64 /* The domain literal form is used (rather than simply the dotted decimal
|
yuuji@0
|
65 as with other Unix programs) because it has to be a valid "host name"
|
yuuji@0
|
66 in mailsystem terminology. */
|
yuuji@0
|
67 /* look like domain literal? */
|
yuuji@0
|
68 if (host[0] == '[' && host[strlen (host)-1] == ']') {
|
yuuji@0
|
69 if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
70 ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
71 ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
72 ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s)
|
yuuji@0
|
73 adr = (i << 24) + (j << 16) + (k << 8) + l;
|
yuuji@0
|
74 else {
|
yuuji@0
|
75 sprintf (tmp,"Bad format domain-literal: %.80s",host);
|
yuuji@0
|
76 mm_log (tmp,ERROR);
|
yuuji@0
|
77 return NIL;
|
yuuji@0
|
78 }
|
yuuji@0
|
79 }
|
yuuji@0
|
80 else { /* lookup host name */
|
yuuji@0
|
81 if (!(adr = resolve (host))) {
|
yuuji@0
|
82 sprintf (tmp,"Host not found: %s",host);
|
yuuji@0
|
83 mm_log (tmp,ERROR);
|
yuuji@0
|
84 return NIL;
|
yuuji@0
|
85 }
|
yuuji@0
|
86 }
|
yuuji@0
|
87
|
yuuji@0
|
88 /* OK to instantiate socket now */
|
yuuji@0
|
89 sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket));
|
yuuji@0
|
90 /* open connection */
|
yuuji@0
|
91 if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) {
|
yuuji@0
|
92 sprintf (tmp,"Can't connect to %.80s,%ld",host,port);
|
yuuji@0
|
93 mm_log (tmp,ERROR);
|
yuuji@0
|
94 fs_give ((void **) &sock);
|
yuuji@0
|
95 return NIL;
|
yuuji@0
|
96 }
|
yuuji@0
|
97 /* create TCP/IP stream */
|
yuuji@0
|
98 stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
|
yuuji@0
|
99 stream->host = cpystr (host); /* official host name */
|
yuuji@0
|
100 stream->localhost = cpystr (mylocalhost ());
|
yuuji@0
|
101 stream->port = port; /* port number */
|
yuuji@0
|
102 stream->tcps = sock; /* init socket */
|
yuuji@0
|
103 stream->ictr = 0; /* init input counter */
|
yuuji@0
|
104 return stream; /* return success */
|
yuuji@0
|
105 }
|
yuuji@0
|
106
|
yuuji@0
|
107 /* TCP/IP authenticated open
|
yuuji@0
|
108 * Accepts: NETMBX specifier
|
yuuji@0
|
109 * service name
|
yuuji@0
|
110 * returned user name buffer
|
yuuji@0
|
111 * Returns: TCP/IP stream if success else NIL
|
yuuji@0
|
112 */
|
yuuji@0
|
113
|
yuuji@0
|
114 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
|
yuuji@0
|
115 {
|
yuuji@0
|
116 return NIL; /* always NIL on DOS */
|
yuuji@0
|
117 }
|
yuuji@0
|
118
|
yuuji@0
|
119 /* TCP receive line
|
yuuji@0
|
120 * Accepts: TCP stream
|
yuuji@0
|
121 * Returns: text line string or NIL if failure
|
yuuji@0
|
122 */
|
yuuji@0
|
123
|
yuuji@0
|
124 char *tcp_getline (TCPSTREAM *stream)
|
yuuji@0
|
125 {
|
yuuji@0
|
126 unsigned long n,contd;
|
yuuji@0
|
127 char *ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
128 if (ret && contd) { /* got a line needing continuation? */
|
yuuji@0
|
129 STRINGLIST *stl = mail_newstringlist ();
|
yuuji@0
|
130 STRINGLIST *stc = stl;
|
yuuji@0
|
131 do { /* collect additional lines */
|
yuuji@0
|
132 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
133 stc->text.size = n;
|
yuuji@0
|
134 stc = stc->next = mail_newstringlist ();
|
yuuji@0
|
135 ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
136 } while (ret && contd);
|
yuuji@0
|
137 if (ret) { /* stash final part of line on list */
|
yuuji@0
|
138 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
139 stc->text.size = n;
|
yuuji@0
|
140 /* determine how large a buffer we need */
|
yuuji@0
|
141 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
|
yuuji@0
|
142 ret = fs_get (n + 1); /* copy parts into buffer */
|
yuuji@0
|
143 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
|
yuuji@0
|
144 memcpy (ret + n,stc->text.data,stc->text.size);
|
yuuji@0
|
145 ret[n] = '\0';
|
yuuji@0
|
146 }
|
yuuji@0
|
147 mail_free_stringlist (&stl);/* either way, done with list */
|
yuuji@0
|
148 }
|
yuuji@0
|
149 return ret;
|
yuuji@0
|
150 }
|
yuuji@0
|
151
|
yuuji@0
|
152 /* TCP receive line or partial line
|
yuuji@0
|
153 * Accepts: TCP stream
|
yuuji@0
|
154 * pointer to return size
|
yuuji@0
|
155 * pointer to return continuation flag
|
yuuji@0
|
156 * Returns: text line string, size and continuation flag, or NIL if failure
|
yuuji@0
|
157 */
|
yuuji@0
|
158
|
yuuji@0
|
159 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
|
yuuji@0
|
160 long *contd)
|
yuuji@0
|
161 {
|
yuuji@0
|
162 unsigned long n;
|
yuuji@0
|
163 char *s,*ret,c,d;
|
yuuji@0
|
164 *contd = NIL; /* assume no continuation */
|
yuuji@0
|
165 /* make sure have data */
|
yuuji@0
|
166 if (!tcp_getdata (stream)) return NIL;
|
yuuji@0
|
167 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
|
yuuji@0
|
168 d = *stream->iptr++; /* slurp another character */
|
yuuji@0
|
169 if ((c == '\015') && (d == '\012')) {
|
yuuji@0
|
170 ret = (char *) fs_get (n--);
|
yuuji@0
|
171 memcpy (ret,s,*size = n); /* copy into a free storage string */
|
yuuji@0
|
172 ret[n] = '\0'; /* tie off string with null */
|
yuuji@0
|
173 return ret;
|
yuuji@0
|
174 }
|
yuuji@0
|
175 }
|
yuuji@0
|
176 /* copy partial string from buffer */
|
yuuji@0
|
177 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
|
yuuji@0
|
178 /* get more data from the net */
|
yuuji@0
|
179 if (!tcp_getdata (stream)) fs_give ((void **) &ret);
|
yuuji@0
|
180 /* special case of newline broken by buffer */
|
yuuji@0
|
181 else if ((c == '\015') && (*stream->iptr == '\012')) {
|
yuuji@0
|
182 stream->iptr++; /* eat the line feed */
|
yuuji@0
|
183 stream->ictr--;
|
yuuji@0
|
184 ret[*size = --n] = '\0'; /* tie off string with null */
|
yuuji@0
|
185 }
|
yuuji@0
|
186 else *contd = LONGT; /* continuation needed */
|
yuuji@0
|
187 return ret;
|
yuuji@0
|
188 }
|
yuuji@0
|
189
|
yuuji@0
|
190 /* TCP/IP receive buffer
|
yuuji@0
|
191 * Accepts: TCP/IP stream
|
yuuji@0
|
192 * size in bytes
|
yuuji@0
|
193 * buffer to read into
|
yuuji@0
|
194 * Returns: T if success, NIL otherwise
|
yuuji@0
|
195 */
|
yuuji@0
|
196
|
yuuji@0
|
197 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
|
yuuji@0
|
198 {
|
yuuji@0
|
199 unsigned long n;
|
yuuji@0
|
200 char *bufptr = buffer;
|
yuuji@0
|
201 while (size > 0) { /* until request satisfied */
|
yuuji@0
|
202 if (!tcp_getdata (stream)) return NIL;
|
yuuji@0
|
203 n = min (size,stream->ictr);/* number of bytes to transfer */
|
yuuji@0
|
204 /* do the copy */
|
yuuji@0
|
205 memcpy (bufptr,stream->iptr,(size_t) n);
|
yuuji@0
|
206 bufptr += n; /* update pointer */
|
yuuji@0
|
207 stream->iptr +=n;
|
yuuji@0
|
208 size -= n; /* update # of bytes to do */
|
yuuji@0
|
209 stream->ictr -=n;
|
yuuji@0
|
210 }
|
yuuji@0
|
211 bufptr[0] = '\0'; /* tie off string */
|
yuuji@0
|
212 return T;
|
yuuji@0
|
213 }
|
yuuji@0
|
214
|
yuuji@0
|
215
|
yuuji@0
|
216 /* TCP/IP receive data
|
yuuji@0
|
217 * Accepts: TCP/IP stream
|
yuuji@0
|
218 * Returns: T if success, NIL otherwise
|
yuuji@0
|
219 */
|
yuuji@0
|
220
|
yuuji@0
|
221 long tcp_getdata (TCPSTREAM *stream)
|
yuuji@0
|
222 {
|
yuuji@0
|
223 int status;
|
yuuji@0
|
224 if (!stream->tcps) return NIL;/* no-no nuked socket */
|
yuuji@0
|
225 while (stream->ictr < 1) { /* if buffer empty, block for input and read */
|
yuuji@0
|
226 if (!_ip_delay1 (stream->tcps,600,NULL,&status))
|
yuuji@0
|
227 stream->ictr = sock_fastread (stream->tcps,
|
yuuji@0
|
228 stream->iptr = stream->ibuf,BUFLEN);
|
yuuji@0
|
229 else if (status == 1) { /* nuke the socket if closed */
|
yuuji@0
|
230 sock_close (stream->tcps);
|
yuuji@0
|
231 fs_give ((void **) &stream->tcps);
|
yuuji@0
|
232 return NIL;
|
yuuji@0
|
233 }
|
yuuji@0
|
234 }
|
yuuji@0
|
235 return T;
|
yuuji@0
|
236 }
|
yuuji@0
|
237
|
yuuji@0
|
238 /* TCP/IP send string as record
|
yuuji@0
|
239 * Accepts: TCP/IP stream
|
yuuji@0
|
240 * Returns: T if success else NIL
|
yuuji@0
|
241 */
|
yuuji@0
|
242
|
yuuji@0
|
243 long tcp_soutr (TCPSTREAM *stream,char *string)
|
yuuji@0
|
244 {
|
yuuji@0
|
245 /* output the cruft */
|
yuuji@0
|
246 sock_puts (stream->tcps,string);
|
yuuji@0
|
247 return T; /* all done */
|
yuuji@0
|
248 }
|
yuuji@0
|
249
|
yuuji@0
|
250
|
yuuji@0
|
251 /* TCP/IP send string
|
yuuji@0
|
252 * Accepts: TCP/IP stream
|
yuuji@0
|
253 * string pointer
|
yuuji@0
|
254 * byte count
|
yuuji@0
|
255 * Returns: T if success else NIL
|
yuuji@0
|
256 */
|
yuuji@0
|
257
|
yuuji@0
|
258 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
|
yuuji@0
|
259 {
|
yuuji@0
|
260 sock_write (stream->tcps,string,(int) size);
|
yuuji@0
|
261 return T;
|
yuuji@0
|
262 }
|
yuuji@0
|
263
|
yuuji@0
|
264
|
yuuji@0
|
265 /* TCP/IP close
|
yuuji@0
|
266 * Accepts: TCP/IP stream
|
yuuji@0
|
267 */
|
yuuji@0
|
268
|
yuuji@0
|
269 void tcp_close (TCPSTREAM *stream)
|
yuuji@0
|
270 {
|
yuuji@0
|
271 if (stream->tcps){ /* nuke the socket */
|
yuuji@0
|
272 sock_close (stream->tcps);
|
yuuji@0
|
273 _ip_delay2 (stream->tcps,0,NULL,NULL);
|
yuuji@0
|
274 }
|
yuuji@0
|
275 fs_give ((void **) &stream->tcps);
|
yuuji@0
|
276 /* flush host names */
|
yuuji@0
|
277 fs_give ((void **) &stream->host);
|
yuuji@0
|
278 fs_give ((void **) &stream->localhost);
|
yuuji@0
|
279 fs_give ((void **) &stream); /* flush the stream */
|
yuuji@0
|
280 }
|
yuuji@0
|
281
|
yuuji@0
|
282 /* TCP/IP get host name
|
yuuji@0
|
283 * Accepts: TCP/IP stream
|
yuuji@0
|
284 * Returns: host name for this stream
|
yuuji@0
|
285 */
|
yuuji@0
|
286
|
yuuji@0
|
287 char *tcp_host (TCPSTREAM *stream)
|
yuuji@0
|
288 {
|
yuuji@0
|
289 return stream->host; /* return host name */
|
yuuji@0
|
290 }
|
yuuji@0
|
291
|
yuuji@0
|
292
|
yuuji@0
|
293 /* TCP/IP get remote host name
|
yuuji@0
|
294 * Accepts: TCP/IP stream
|
yuuji@0
|
295 * Returns: host name for this stream
|
yuuji@0
|
296 */
|
yuuji@0
|
297
|
yuuji@0
|
298 char *tcp_remotehost (TCPSTREAM *stream)
|
yuuji@0
|
299 {
|
yuuji@0
|
300 return stream->host; /* return host name */
|
yuuji@0
|
301 }
|
yuuji@0
|
302
|
yuuji@0
|
303
|
yuuji@0
|
304 /* TCP/IP return port for this stream
|
yuuji@0
|
305 * Accepts: TCP/IP stream
|
yuuji@0
|
306 * Returns: port number for this stream
|
yuuji@0
|
307 */
|
yuuji@0
|
308
|
yuuji@0
|
309 unsigned long tcp_port (TCPSTREAM *stream)
|
yuuji@0
|
310 {
|
yuuji@0
|
311 return stream->port; /* return port number */
|
yuuji@0
|
312 }
|
yuuji@0
|
313
|
yuuji@0
|
314
|
yuuji@0
|
315 /* TCP/IP get local host name
|
yuuji@0
|
316 * Accepts: TCP/IP stream
|
yuuji@0
|
317 * Returns: local host name
|
yuuji@0
|
318 */
|
yuuji@0
|
319
|
yuuji@0
|
320 char *tcp_localhost (TCPSTREAM *stream)
|
yuuji@0
|
321 {
|
yuuji@0
|
322 return stream->localhost; /* return local host name */
|
yuuji@0
|
323 }
|
yuuji@0
|
324
|
yuuji@0
|
325
|
yuuji@0
|
326 /* TCP/IP return canonical form of host name
|
yuuji@0
|
327 * Accepts: host name
|
yuuji@0
|
328 * Returns: canonical form of host name
|
yuuji@0
|
329 */
|
yuuji@0
|
330
|
yuuji@0
|
331 char *tcp_canonical (char *name)
|
yuuji@0
|
332 {
|
yuuji@0
|
333 return name;
|
yuuji@0
|
334 }
|
yuuji@0
|
335
|
yuuji@0
|
336
|
yuuji@0
|
337 /* TCP/IP get client host name (server calls only)
|
yuuji@0
|
338 * Returns: client host name
|
yuuji@0
|
339 */
|
yuuji@0
|
340
|
yuuji@0
|
341 char *tcp_clienthost ()
|
yuuji@0
|
342 {
|
yuuji@0
|
343 return "UNKNOWN";
|
yuuji@0
|
344 }
|