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