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: TOPS-20 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
|
yuuji@0
|
30 /* Dedication:
|
yuuji@0
|
31 * This file is dedicated with affection to the TOPS-20 operating system, which
|
yuuji@0
|
32 * set standards for user and programmer friendliness that have still not been
|
yuuji@0
|
33 * equaled by more `modern' operating systems.
|
yuuji@0
|
34 * Wasureru mon ka!!!!
|
yuuji@0
|
35 */
|
yuuji@0
|
36
|
yuuji@0
|
37 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
|
yuuji@0
|
38 long *contd);
|
yuuji@0
|
39
|
yuuji@0
|
40 /* TCP/IP manipulate parameters
|
yuuji@0
|
41 * Accepts: function code
|
yuuji@0
|
42 * function-dependent value
|
yuuji@0
|
43 * Returns: function-dependent return value
|
yuuji@0
|
44 */
|
yuuji@0
|
45
|
yuuji@0
|
46 void *tcp_parameters (long function,void *value)
|
yuuji@0
|
47 {
|
yuuji@0
|
48 return NIL;
|
yuuji@0
|
49 }
|
yuuji@0
|
50
|
yuuji@0
|
51 /* TCP/IP open
|
yuuji@0
|
52 * Accepts: host name
|
yuuji@0
|
53 * contact service name
|
yuuji@0
|
54 * contact port number
|
yuuji@0
|
55 * Returns: TCP stream if success else NIL
|
yuuji@0
|
56 */
|
yuuji@0
|
57
|
yuuji@0
|
58 TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
|
yuuji@0
|
59 {
|
yuuji@0
|
60 char *s,tmp[MAILTMPLEN];
|
yuuji@0
|
61 TCPSTREAM *stream = NIL;
|
yuuji@0
|
62 int argblk[5],jfn;
|
yuuji@0
|
63 unsigned long i,j,k,l;
|
yuuji@0
|
64 char file[MAILTMPLEN];
|
yuuji@0
|
65 port &= 0xffff; /* erase flags */
|
yuuji@0
|
66 /* domain literal? */
|
yuuji@0
|
67 if (host[0] == '[' && host[strlen (host)-1] == ']') {
|
yuuji@0
|
68 if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
69 ((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
70 ((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
|
yuuji@0
|
71 ((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s) {
|
yuuji@0
|
72 argblk[3] = (i << 24) + (j << 16) + (k << 8) + l;
|
yuuji@0
|
73 sprintf (tmp,"[%lu.%lu.%lu.%lu]",i,j,k,l);
|
yuuji@0
|
74 }
|
yuuji@0
|
75 else {
|
yuuji@0
|
76 sprintf (tmp,"Bad format domain-literal: %.80s",host);
|
yuuji@0
|
77 mm_log (tmp,ERROR);
|
yuuji@0
|
78 return NIL;
|
yuuji@0
|
79 }
|
yuuji@0
|
80 }
|
yuuji@0
|
81 else { /* host name */
|
yuuji@0
|
82 argblk[1] = _GTHPN; /* get IP address and primary name */
|
yuuji@0
|
83 argblk[2] = (int) (host-1); /* pointer to host */
|
yuuji@0
|
84 argblk[4] = (int) (tmp-1);
|
yuuji@0
|
85 if (!jsys (GTHST,argblk)) { /* first try DEC's domain way */
|
yuuji@0
|
86 argblk[1] = _GTHPN; /* get IP address and primary name */
|
yuuji@0
|
87 argblk[2] = (int) (host-1);
|
yuuji@0
|
88 argblk[4] = (int) (tmp-1);
|
yuuji@0
|
89 if (!jsys (GTDOM,argblk)){/* try the CHIVES domain way */
|
yuuji@0
|
90 argblk[1] = _GTHSN; /* failed, do the host table then */
|
yuuji@0
|
91 if (!jsys (GTHST,argblk)) {
|
yuuji@0
|
92 sprintf (tmp,"No such host as %s",host);
|
yuuji@0
|
93 mm_log (tmp,ERROR);
|
yuuji@0
|
94 return NIL;
|
yuuji@0
|
95 }
|
yuuji@0
|
96 argblk[1] = _GTHNS; /* convert number to string */
|
yuuji@0
|
97 argblk[2] = (int) (tmp-1);
|
yuuji@0
|
98 /* get the official name */
|
yuuji@0
|
99 if (!jsys (GTHST,argblk)) strcpy (tmp,host);
|
yuuji@0
|
100 }
|
yuuji@0
|
101 }
|
yuuji@0
|
102 }
|
yuuji@0
|
103
|
yuuji@0
|
104 sprintf (file,"TCP:.%o-%d;PERSIST:30;CONNECTION:ACTIVE",argblk[3],port);
|
yuuji@0
|
105 argblk[1] = GJ_SHT; /* short form GTJFN% */
|
yuuji@0
|
106 argblk[2] = (int) (file-1); /* pointer to file name */
|
yuuji@0
|
107 /* get JFN for TCP: file */
|
yuuji@0
|
108 if (!jsys (GTJFN,argblk)) fatal ("Unable to create TCP JFN");
|
yuuji@0
|
109 jfn = argblk[1]; /* note JFN for later */
|
yuuji@0
|
110 /* want 8-bit bidirectional I/O */
|
yuuji@0
|
111 argblk[2] = OF_RD|OF_WR|(FLD (8,monsym("OF%BSZ")));
|
yuuji@0
|
112 if (!jsys (OPENF,argblk)) {
|
yuuji@0
|
113 sprintf (file,"Can't connect to %s,%d server",tmp,port);
|
yuuji@0
|
114 mm_log (file,ERROR);
|
yuuji@0
|
115 return NIL;
|
yuuji@0
|
116 }
|
yuuji@0
|
117 /* create TCP/IP stream */
|
yuuji@0
|
118 stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
|
yuuji@0
|
119 stream->host = cpystr (tmp); /* copy official host name */
|
yuuji@0
|
120 argblk[1] = _GTHNS; /* convert number to string */
|
yuuji@0
|
121 argblk[2] = (int) (tmp-1);
|
yuuji@0
|
122 argblk[3] = -1; /* want local host */
|
yuuji@0
|
123 if (!jsys (GTHST,argblk)) strcpy (tmp,"LOCAL");
|
yuuji@0
|
124 stream->localhost = cpystr (tmp);
|
yuuji@0
|
125 stream->port = port; /* save port number */
|
yuuji@0
|
126 stream->jfn = jfn; /* init JFN */
|
yuuji@0
|
127 return stream;
|
yuuji@0
|
128 }
|
yuuji@0
|
129
|
yuuji@0
|
130 /* TCP/IP authenticated open
|
yuuji@0
|
131 * Accepts: NETMBX specifier
|
yuuji@0
|
132 * service name
|
yuuji@0
|
133 * returned user name buffer
|
yuuji@0
|
134 * Returns: TCP/IP stream if success else NIL
|
yuuji@0
|
135 */
|
yuuji@0
|
136
|
yuuji@0
|
137 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
|
yuuji@0
|
138 {
|
yuuji@0
|
139 return NIL;
|
yuuji@0
|
140 }
|
yuuji@0
|
141
|
yuuji@0
|
142 /* TCP receive line
|
yuuji@0
|
143 * Accepts: TCP stream
|
yuuji@0
|
144 * Returns: text line string or NIL if failure
|
yuuji@0
|
145 */
|
yuuji@0
|
146
|
yuuji@0
|
147 char *tcp_getline (TCPSTREAM *stream)
|
yuuji@0
|
148 {
|
yuuji@0
|
149 unsigned long n,contd;
|
yuuji@0
|
150 char *ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
151 if (ret && contd) { /* got a line needing continuation? */
|
yuuji@0
|
152 STRINGLIST *stl = mail_newstringlist ();
|
yuuji@0
|
153 STRINGLIST *stc = stl;
|
yuuji@0
|
154 do { /* collect additional lines */
|
yuuji@0
|
155 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
156 stc->text.size = n;
|
yuuji@0
|
157 stc = stc->next = mail_newstringlist ();
|
yuuji@0
|
158 ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
159 } while (ret && contd);
|
yuuji@0
|
160 if (ret) { /* stash final part of line on list */
|
yuuji@0
|
161 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
162 stc->text.size = n;
|
yuuji@0
|
163 /* determine how large a buffer we need */
|
yuuji@0
|
164 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
|
yuuji@0
|
165 ret = fs_get (n + 1); /* copy parts into buffer */
|
yuuji@0
|
166 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
|
yuuji@0
|
167 memcpy (ret + n,stc->text.data,stc->text.size);
|
yuuji@0
|
168 ret[n] = '\0';
|
yuuji@0
|
169 }
|
yuuji@0
|
170 mail_free_stringlist (&stl);/* either way, done with list */
|
yuuji@0
|
171 }
|
yuuji@0
|
172 return ret;
|
yuuji@0
|
173 }
|
yuuji@0
|
174
|
yuuji@0
|
175 /* TCP receive line or partial line
|
yuuji@0
|
176 * Accepts: TCP stream
|
yuuji@0
|
177 * pointer to return size
|
yuuji@0
|
178 * pointer to return continuation flag
|
yuuji@0
|
179 * Returns: text line string, size and continuation flag, or NIL if failure
|
yuuji@0
|
180 */
|
yuuji@0
|
181
|
yuuji@0
|
182 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
|
yuuji@0
|
183 long *contd)
|
yuuji@0
|
184 {
|
yuuji@0
|
185 int argblk[5];
|
yuuji@0
|
186 unsigned long n,m;
|
yuuji@0
|
187 char *ret,*stp,*st;
|
yuuji@0
|
188 *contd = NIL; /* assume no continuation */
|
yuuji@0
|
189 argblk[1] = stream->jfn; /* read from TCP */
|
yuuji@0
|
190 /* pointer to buffer */
|
yuuji@0
|
191 argblk[2] = (int) (stream->ibuf - 1);
|
yuuji@0
|
192 argblk[3] = BUFLEN; /* max number of bytes to read */
|
yuuji@0
|
193 argblk[4] = '\012'; /* terminate on LF */
|
yuuji@0
|
194 if (!jsys (SIN,argblk)) return NIL;
|
yuuji@0
|
195 n = BUFLEN - argblk[3]; /* number of bytes read */
|
yuuji@0
|
196 /* got a complete line? */
|
yuuji@0
|
197 if ((stream->ibuf[n - 2] == '\015') && (stream->ibuf[n - 1] == '\012')) {
|
yuuji@0
|
198 memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n - 2);
|
yuuji@0
|
199 ret[n - 2] = '\0'; /* tie off string with null */
|
yuuji@0
|
200 return ret;
|
yuuji@0
|
201 }
|
yuuji@0
|
202 /* copy partial string */
|
yuuji@0
|
203 memcpy ((ret = (char *) fs_get (n)),stream->ibuf,*size = n);
|
yuuji@0
|
204 /* special case of newline broken by buffer */
|
yuuji@0
|
205 if ((stream->ibuf[n - 1] == '\015') && jsys (BIN,argblk) &&
|
yuuji@0
|
206 (argblk[2] == '\012')) { /* was it? */
|
yuuji@0
|
207 ret[n - 1] = '\0'; /* tie off string with null */
|
yuuji@0
|
208 }
|
yuuji@0
|
209 /* otherwise back up */
|
yuuji@0
|
210 else if (!jsys (BKJFN,argblk)) fs_give ((void **) &ret);
|
yuuji@0
|
211 else *contd = LONGT; /* continuation needed */
|
yuuji@0
|
212 return ret;
|
yuuji@0
|
213 }
|
yuuji@0
|
214
|
yuuji@0
|
215 /* TCP/IP receive buffer
|
yuuji@0
|
216 * Accepts: TCP/IP stream
|
yuuji@0
|
217 * size in bytes
|
yuuji@0
|
218 * buffer to read into
|
yuuji@0
|
219 * Returns: T if success, NIL otherwise
|
yuuji@0
|
220 */
|
yuuji@0
|
221
|
yuuji@0
|
222 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
|
yuuji@0
|
223 {
|
yuuji@0
|
224 int argblk[5];
|
yuuji@0
|
225 argblk[1] = stream->jfn; /* read from TCP */
|
yuuji@0
|
226 argblk[2] = (int) (buffer-1); /* pointer to buffer */
|
yuuji@0
|
227 argblk[3] = -size; /* number of bytes to read */
|
yuuji@0
|
228 if (!jsys (SIN,argblk)) return NIL;
|
yuuji@0
|
229 buffer[size] = '\0'; /* tie off text */
|
yuuji@0
|
230 return T;
|
yuuji@0
|
231 }
|
yuuji@0
|
232
|
yuuji@0
|
233
|
yuuji@0
|
234 /* TCP/IP send string as record
|
yuuji@0
|
235 * Accepts: TCP/IP stream
|
yuuji@0
|
236 * string pointer
|
yuuji@0
|
237 * Returns: T if success else NIL
|
yuuji@0
|
238 */
|
yuuji@0
|
239
|
yuuji@0
|
240 long tcp_soutr (TCPSTREAM *stream,char *string)
|
yuuji@0
|
241 {
|
yuuji@0
|
242 int argblk[5];
|
yuuji@0
|
243 argblk[1] = stream->jfn; /* write to TCP */
|
yuuji@0
|
244 argblk[2] = (int) (string-1); /* pointer to buffer */
|
yuuji@0
|
245 argblk[3] = 0; /* write until NUL */
|
yuuji@0
|
246 if (!jsys (SOUTR,argblk)) return NIL;
|
yuuji@0
|
247 return T;
|
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 int argblk[5];
|
yuuji@0
|
261 argblk[1] = stream->jfn; /* write to TCP */
|
yuuji@0
|
262 argblk[2] = (int) (string-1); /* pointer to buffer */
|
yuuji@0
|
263 argblk[3] = -size; /* write this many bytes */
|
yuuji@0
|
264 if (!jsys (SOUTR,argblk)) return NIL;
|
yuuji@0
|
265 return T;
|
yuuji@0
|
266 }
|
yuuji@0
|
267
|
yuuji@0
|
268 /* TCP/IP close
|
yuuji@0
|
269 * Accepts: TCP/IP stream
|
yuuji@0
|
270 */
|
yuuji@0
|
271
|
yuuji@0
|
272 void tcp_close (TCPSTREAM *stream)
|
yuuji@0
|
273 {
|
yuuji@0
|
274 int argblk[5];
|
yuuji@0
|
275 argblk[1] = stream->jfn; /* close TCP */
|
yuuji@0
|
276 jsys (CLOSF,argblk);
|
yuuji@0
|
277 /* flush host names */
|
yuuji@0
|
278 fs_give ((void **) &stream->host);
|
yuuji@0
|
279 fs_give ((void **) &stream->localhost);
|
yuuji@0
|
280 fs_give ((void **) &stream); /* flush the stream */
|
yuuji@0
|
281 }
|
yuuji@0
|
282
|
yuuji@0
|
283
|
yuuji@0
|
284 /* TCP/IP return host for this stream
|
yuuji@0
|
285 * Accepts: TCP/IP stream
|
yuuji@0
|
286 * Returns: host name for this stream
|
yuuji@0
|
287 */
|
yuuji@0
|
288
|
yuuji@0
|
289 char *tcp_host (TCPSTREAM *stream)
|
yuuji@0
|
290 {
|
yuuji@0
|
291 return stream->host; /* return host name */
|
yuuji@0
|
292 }
|
yuuji@0
|
293
|
yuuji@0
|
294
|
yuuji@0
|
295 /* TCP/IP return remote host for this stream
|
yuuji@0
|
296 * Accepts: TCP/IP stream
|
yuuji@0
|
297 * Returns: host name for this stream
|
yuuji@0
|
298 */
|
yuuji@0
|
299
|
yuuji@0
|
300 char *tcp_remotehost (TCPSTREAM *stream)
|
yuuji@0
|
301 {
|
yuuji@0
|
302 return stream->host; /* return host name */
|
yuuji@0
|
303 }
|
yuuji@0
|
304
|
yuuji@0
|
305
|
yuuji@0
|
306 /* TCP/IP return port for this stream
|
yuuji@0
|
307 * Accepts: TCP/IP stream
|
yuuji@0
|
308 * Returns: port number for this stream
|
yuuji@0
|
309 */
|
yuuji@0
|
310
|
yuuji@0
|
311 unsigned long tcp_port (TCPSTREAM *stream)
|
yuuji@0
|
312 {
|
yuuji@0
|
313 return stream->port; /* return port number */
|
yuuji@0
|
314 }
|
yuuji@0
|
315
|
yuuji@0
|
316
|
yuuji@0
|
317 /* TCP/IP return local host for this stream
|
yuuji@0
|
318 * Accepts: TCP/IP stream
|
yuuji@0
|
319 * Returns: local host name for this stream
|
yuuji@0
|
320 */
|
yuuji@0
|
321
|
yuuji@0
|
322 char *tcp_localhost (TCPSTREAM *stream)
|
yuuji@0
|
323 {
|
yuuji@0
|
324 return stream->localhost; /* return local host name */
|
yuuji@0
|
325 }
|
yuuji@0
|
326
|
yuuji@0
|
327 /* TCP/IP return canonical form of host name
|
yuuji@0
|
328 * Accepts: host name
|
yuuji@0
|
329 * Returns: canonical form of host name
|
yuuji@0
|
330 */
|
yuuji@0
|
331
|
yuuji@0
|
332 char *tcp_canonical (char *name)
|
yuuji@0
|
333 {
|
yuuji@0
|
334 int argblk[5];
|
yuuji@0
|
335 static char tmp[MAILTMPLEN];
|
yuuji@0
|
336 /* look like domain literal? */
|
yuuji@0
|
337 if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
|
yuuji@0
|
338 argblk[1] = _GTHPN; /* get IP address and primary name */
|
yuuji@0
|
339 argblk[2] = (int) (name-1); /* pointer to host */
|
yuuji@0
|
340 argblk[4] = (int) (tmp-1); /* pointer to return destination */
|
yuuji@0
|
341 if (!jsys (GTHST,argblk)) { /* first try DEC's domain way */
|
yuuji@0
|
342 argblk[1] = _GTHPN; /* get IP address and primary name */
|
yuuji@0
|
343 argblk[2] = (int) (name-1);
|
yuuji@0
|
344 argblk[4] = (int) (tmp-1);
|
yuuji@0
|
345 if (!jsys (GTDOM,argblk)) { /* try the CHIVES domain way */
|
yuuji@0
|
346 argblk[1] = _GTHSN; /* failed, do the host table then */
|
yuuji@0
|
347 if (!jsys (GTHST,argblk)) return name;
|
yuuji@0
|
348 argblk[1] = _GTHNS; /* convert number to string */
|
yuuji@0
|
349 argblk[2] = (int) (tmp-1);
|
yuuji@0
|
350 /* get the official name */
|
yuuji@0
|
351 if (!jsys (GTHST,argblk)) return name;
|
yuuji@0
|
352 }
|
yuuji@0
|
353 }
|
yuuji@0
|
354 return tmp;
|
yuuji@0
|
355 }
|
yuuji@0
|
356
|
yuuji@0
|
357
|
yuuji@0
|
358 /* TCP/IP get client host name (server calls only)
|
yuuji@0
|
359 * Returns: client host name
|
yuuji@0
|
360 */
|
yuuji@0
|
361
|
yuuji@0
|
362 char *tcp_clienthost ()
|
yuuji@0
|
363 {
|
yuuji@0
|
364 return "UNKNOWN";
|
yuuji@0
|
365 }
|