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: VMS TCP/IP routines for Netlib.
|
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: 2 August 1994
|
yuuji@0
|
26 * Last Edited: 13 January 2008
|
yuuji@0
|
27 */
|
yuuji@0
|
28
|
yuuji@0
|
29 /* Thanks to Yehavi Bourvine at The Hebrew University of Jerusalem who
|
yuuji@0
|
30 contributed the original VMS code */
|
yuuji@0
|
31
|
yuuji@0
|
32 #include <descrip.h>
|
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
|
yuuji@0
|
49 /* TCP/IP open
|
yuuji@0
|
50 * Accepts: host name
|
yuuji@0
|
51 * contact service name
|
yuuji@0
|
52 * contact port number
|
yuuji@0
|
53 * Returns: TCP/IP stream if success else NIL
|
yuuji@0
|
54 */
|
yuuji@0
|
55
|
yuuji@0
|
56 TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
|
yuuji@0
|
57 {
|
yuuji@0
|
58 TCPSTREAM *stream = NIL;
|
yuuji@0
|
59 unsigned long sock;
|
yuuji@0
|
60 int status;
|
yuuji@0
|
61 char tmp[MAILTMPLEN];
|
yuuji@0
|
62 /* hostname to connect to */
|
yuuji@0
|
63 struct dsc$descriptor HostDesc = { 0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL };
|
yuuji@0
|
64 port &= 0xffff; /* erase flags */
|
yuuji@0
|
65 /* assign a local socket */
|
yuuji@0
|
66 if (!((status = net_assign (&sock)) & 0x1)) {
|
yuuji@0
|
67 sprintf (tmp,"Unable to assign to net, status=%d",status);
|
yuuji@0
|
68 mm_log (tmp,ERROR);
|
yuuji@0
|
69 return NIL;
|
yuuji@0
|
70 }
|
yuuji@0
|
71 if (!((status = net_bind (&sock,1)) & 0x1)) {
|
yuuji@0
|
72 sprintf (tmp,"Unable to create local socket, status=%d",status);
|
yuuji@0
|
73 mm_log (tmp,ERROR);
|
yuuji@0
|
74 return NIL;
|
yuuji@0
|
75 }
|
yuuji@0
|
76 /* open connection */
|
yuuji@0
|
77 HostDesc.dsc$w_length = strlen (host);
|
yuuji@0
|
78 HostDesc.dsc$a_pointer = host;
|
yuuji@0
|
79 if (!((status = tcp_connect (&sock,&HostDesc,port)) & 0x1)) {
|
yuuji@0
|
80 sprintf (tmp,"Can't connect to %.80s,%lu: %s",host,port,strerror (errno));
|
yuuji@0
|
81 mm_log (tmp,ERROR);
|
yuuji@0
|
82 return NIL;
|
yuuji@0
|
83 }
|
yuuji@0
|
84 /* create TCP/IP stream */
|
yuuji@0
|
85 stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
|
yuuji@0
|
86 stream->host = cpystr (host); /* copy official host name */
|
yuuji@0
|
87 /* copy local host name */
|
yuuji@0
|
88 stream->localhost = cpystr (mylocalhost ());
|
yuuji@0
|
89 stream->port = port; /* copy port number */
|
yuuji@0
|
90 /* init sockets */
|
yuuji@0
|
91 stream->tcpsi = stream->tcpso = sock;
|
yuuji@0
|
92 stream->ictr = 0; /* init input counter */
|
yuuji@0
|
93 return stream; /* return success */
|
yuuji@0
|
94 }
|
yuuji@0
|
95
|
yuuji@0
|
96 /* TCP/IP authenticated open
|
yuuji@0
|
97 * Accepts: NETMBX specifier
|
yuuji@0
|
98 * service name
|
yuuji@0
|
99 * returned user name buffer
|
yuuji@0
|
100 * Returns: TCP/IP stream if success else NIL
|
yuuji@0
|
101 */
|
yuuji@0
|
102
|
yuuji@0
|
103 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
|
yuuji@0
|
104 {
|
yuuji@0
|
105 return NIL;
|
yuuji@0
|
106 }
|
yuuji@0
|
107
|
yuuji@0
|
108 /* TCP receive line
|
yuuji@0
|
109 * Accepts: TCP stream
|
yuuji@0
|
110 * Returns: text line string or NIL if failure
|
yuuji@0
|
111 */
|
yuuji@0
|
112
|
yuuji@0
|
113 char *tcp_getline (TCPSTREAM *stream)
|
yuuji@0
|
114 {
|
yuuji@0
|
115 unsigned long n,contd;
|
yuuji@0
|
116 char *ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
117 if (ret && contd) { /* got a line needing continuation? */
|
yuuji@0
|
118 STRINGLIST *stl = mail_newstringlist ();
|
yuuji@0
|
119 STRINGLIST *stc = stl;
|
yuuji@0
|
120 do { /* collect additional lines */
|
yuuji@0
|
121 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
122 stc->text.size = n;
|
yuuji@0
|
123 stc = stc->next = mail_newstringlist ();
|
yuuji@0
|
124 ret = tcp_getline_work (stream,&n,&contd);
|
yuuji@0
|
125 } while (ret && contd);
|
yuuji@0
|
126 if (ret) { /* stash final part of line on list */
|
yuuji@0
|
127 stc->text.data = (unsigned char *) ret;
|
yuuji@0
|
128 stc->text.size = n;
|
yuuji@0
|
129 /* determine how large a buffer we need */
|
yuuji@0
|
130 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
|
yuuji@0
|
131 ret = fs_get (n + 1); /* copy parts into buffer */
|
yuuji@0
|
132 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
|
yuuji@0
|
133 memcpy (ret + n,stc->text.data,stc->text.size);
|
yuuji@0
|
134 ret[n] = '\0';
|
yuuji@0
|
135 }
|
yuuji@0
|
136 mail_free_stringlist (&stl);/* either way, done with list */
|
yuuji@0
|
137 }
|
yuuji@0
|
138 return ret;
|
yuuji@0
|
139 }
|
yuuji@0
|
140
|
yuuji@0
|
141 /* TCP receive line or partial line
|
yuuji@0
|
142 * Accepts: TCP stream
|
yuuji@0
|
143 * pointer to return size
|
yuuji@0
|
144 * pointer to return continuation flag
|
yuuji@0
|
145 * Returns: text line string, size and continuation flag, or NIL if failure
|
yuuji@0
|
146 */
|
yuuji@0
|
147
|
yuuji@0
|
148 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
|
yuuji@0
|
149 long *contd)
|
yuuji@0
|
150 {
|
yuuji@0
|
151 unsigned long n;
|
yuuji@0
|
152 char *s,*ret,c,d;
|
yuuji@0
|
153 *contd = NIL; /* assume no continuation */
|
yuuji@0
|
154 /* make sure have data */
|
yuuji@0
|
155 if (!tcp_getdata (stream)) return NIL;
|
yuuji@0
|
156 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
|
yuuji@0
|
157 d = *stream->iptr++; /* slurp another character */
|
yuuji@0
|
158 if ((c == '\015') && (d == '\012')) {
|
yuuji@0
|
159 ret = (char *) fs_get (n--);
|
yuuji@0
|
160 memcpy (ret,s,*size = n); /* copy into a free storage string */
|
yuuji@0
|
161 ret[n] = '\0'; /* tie off string with null */
|
yuuji@0
|
162 return ret;
|
yuuji@0
|
163 }
|
yuuji@0
|
164 }
|
yuuji@0
|
165 /* copy partial string from buffer */
|
yuuji@0
|
166 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
|
yuuji@0
|
167 /* get more data from the net */
|
yuuji@0
|
168 if (!tcp_getdata (stream)) fs_give ((void **) &ret);
|
yuuji@0
|
169 /* special case of newline broken by buffer */
|
yuuji@0
|
170 else if ((c == '\015') && (*stream->iptr == '\012')) {
|
yuuji@0
|
171 stream->iptr++; /* eat the line feed */
|
yuuji@0
|
172 stream->ictr--;
|
yuuji@0
|
173 ret[*size = --n] = '\0'; /* tie off string with null */
|
yuuji@0
|
174 }
|
yuuji@0
|
175 else *contd = LONGT; /* continuation needed */
|
yuuji@0
|
176 return ret;
|
yuuji@0
|
177 }
|
yuuji@0
|
178
|
yuuji@0
|
179 /* TCP/IP receive buffer
|
yuuji@0
|
180 * Accepts: TCP/IP stream
|
yuuji@0
|
181 * size in bytes
|
yuuji@0
|
182 * buffer to read into
|
yuuji@0
|
183 * Returns: T if success, NIL otherwise
|
yuuji@0
|
184 */
|
yuuji@0
|
185
|
yuuji@0
|
186 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
|
yuuji@0
|
187 {
|
yuuji@0
|
188 unsigned long n;
|
yuuji@0
|
189 char *bufptr = buffer;
|
yuuji@0
|
190 while (size > 0) { /* until request satisfied */
|
yuuji@0
|
191 if (!tcp_getdata (stream)) return NIL;
|
yuuji@0
|
192 n = min (size,stream->ictr);/* number of bytes to transfer */
|
yuuji@0
|
193 /* do the copy */
|
yuuji@0
|
194 memcpy (bufptr,stream->iptr,n);
|
yuuji@0
|
195 bufptr += n; /* update pointer */
|
yuuji@0
|
196 stream->iptr +=n;
|
yuuji@0
|
197 size -= n; /* update # of bytes to do */
|
yuuji@0
|
198 stream->ictr -=n;
|
yuuji@0
|
199 }
|
yuuji@0
|
200 bufptr[0] = '\0'; /* tie off string */
|
yuuji@0
|
201 return T;
|
yuuji@0
|
202 }
|
yuuji@0
|
203
|
yuuji@0
|
204
|
yuuji@0
|
205 /* TCP/IP receive data
|
yuuji@0
|
206 * Accepts: TCP/IP stream
|
yuuji@0
|
207 * Returns: T if success, NIL otherwise
|
yuuji@0
|
208 */
|
yuuji@0
|
209
|
yuuji@0
|
210 long tcp_getdata (TCPSTREAM *stream)
|
yuuji@0
|
211 {
|
yuuji@0
|
212 char tmp[MAILTMPLEN];
|
yuuji@0
|
213 int i,status;
|
yuuji@0
|
214 /* Note: the doc says we need here dynamic descriptor, but we need static
|
yuuji@0
|
215 * one... */
|
yuuji@0
|
216 struct dsc$descriptor BufDesc = {BUFLEN,DSC$K_DTYPE_T,DSC$K_CLASS_S,
|
yuuji@0
|
217 stream->ibuf};
|
yuuji@0
|
218 static short iosb[4];
|
yuuji@0
|
219 if (stream->tcpsi < 0) return NIL;
|
yuuji@0
|
220 while (stream->ictr < 1) { /* if nothing in the buffer */
|
yuuji@0
|
221 if (!((status = tcp_receive(&(stream->tcpsi), &BufDesc, iosb)) & 0x1)) {
|
yuuji@0
|
222 sprintf (tmp,"Error reading from TcpIp/NETLIB, status=%d",status);
|
yuuji@0
|
223 mm_log (tmp,ERROR);
|
yuuji@0
|
224 return tcp_abort (stream);
|
yuuji@0
|
225 }
|
yuuji@0
|
226 if (iosb[1] > BUFLEN) i = BUFLEN;
|
yuuji@0
|
227 else i = iosb[1];
|
yuuji@0
|
228 if (i < 1) return tcp_abort (stream);
|
yuuji@0
|
229 stream->ictr = i; /* set new byte count */
|
yuuji@0
|
230 stream->iptr = stream->ibuf;/* point at TCP buffer */
|
yuuji@0
|
231 }
|
yuuji@0
|
232 return T;
|
yuuji@0
|
233 }
|
yuuji@0
|
234
|
yuuji@0
|
235 /* TCP/IP send string as record
|
yuuji@0
|
236 * Accepts: TCP/IP stream
|
yuuji@0
|
237 * string pointer
|
yuuji@0
|
238 * Returns: T if success else NIL
|
yuuji@0
|
239 */
|
yuuji@0
|
240
|
yuuji@0
|
241 long tcp_soutr (TCPSTREAM *stream,char *string)
|
yuuji@0
|
242 {
|
yuuji@0
|
243 return tcp_sout (stream,string,(unsigned long) strlen (string));
|
yuuji@0
|
244 }
|
yuuji@0
|
245
|
yuuji@0
|
246
|
yuuji@0
|
247 /* TCP/IP send string
|
yuuji@0
|
248 * Accepts: TCP/IP stream
|
yuuji@0
|
249 * string pointer
|
yuuji@0
|
250 * byte count
|
yuuji@0
|
251 * Returns: T if success else NIL
|
yuuji@0
|
252 */
|
yuuji@0
|
253
|
yuuji@0
|
254 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
|
yuuji@0
|
255 {
|
yuuji@0
|
256 int status;
|
yuuji@0
|
257 struct dsc$descriptor_s BufDesc = {strlen(string),DSC$K_DTYPE_T,
|
yuuji@0
|
258 DSC$K_CLASS_S,string };
|
yuuji@0
|
259 /* 2 = Do not add \r\n */
|
yuuji@0
|
260 return ((status = tcp_send (&(stream->tcpso),&BufDesc,2)) & 0x1) ? T :
|
yuuji@0
|
261 tcp_abort (stream);
|
yuuji@0
|
262 }
|
yuuji@0
|
263
|
yuuji@0
|
264 /* TCP/IP close
|
yuuji@0
|
265 * Accepts: TCP/IP stream
|
yuuji@0
|
266 */
|
yuuji@0
|
267
|
yuuji@0
|
268 void tcp_close (TCPSTREAM *stream)
|
yuuji@0
|
269 {
|
yuuji@0
|
270 tcp_abort (stream); /* nuke the stream */
|
yuuji@0
|
271 /* flush host names */
|
yuuji@0
|
272 fs_give ((void **) &stream->host);
|
yuuji@0
|
273 fs_give ((void **) &stream->localhost);
|
yuuji@0
|
274 fs_give ((void **) &stream); /* flush the stream */
|
yuuji@0
|
275 }
|
yuuji@0
|
276
|
yuuji@0
|
277
|
yuuji@0
|
278 /* TCP/IP abort stream
|
yuuji@0
|
279 * Accepts: TCP/IP stream
|
yuuji@0
|
280 * Returns: NIL always
|
yuuji@0
|
281 */
|
yuuji@0
|
282
|
yuuji@0
|
283 long tcp_abort (TCPSTREAM *stream)
|
yuuji@0
|
284 {
|
yuuji@0
|
285 if (stream->tcpsi >= 0) { /* no-op if no socket */
|
yuuji@0
|
286 /* nuke the socket */
|
yuuji@0
|
287 tcp_disconnect (&(stream->tcpsi));
|
yuuji@0
|
288 stream->tcpsi = stream->tcpso = -1;
|
yuuji@0
|
289 }
|
yuuji@0
|
290 return NIL;
|
yuuji@0
|
291 }
|
yuuji@0
|
292
|
yuuji@0
|
293 /* TCP/IP get 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_host (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 get remote host name
|
yuuji@0
|
305 * Accepts: TCP/IP stream
|
yuuji@0
|
306 * Returns: host name for this stream
|
yuuji@0
|
307 */
|
yuuji@0
|
308
|
yuuji@0
|
309 char *tcp_remotehost (TCPSTREAM *stream)
|
yuuji@0
|
310 {
|
yuuji@0
|
311 return stream->host; /* return host name */
|
yuuji@0
|
312 }
|
yuuji@0
|
313
|
yuuji@0
|
314
|
yuuji@0
|
315 /* TCP/IP return port for this stream
|
yuuji@0
|
316 * Accepts: TCP/IP stream
|
yuuji@0
|
317 * Returns: port number for this stream
|
yuuji@0
|
318 */
|
yuuji@0
|
319
|
yuuji@0
|
320 unsigned long tcp_port (TCPSTREAM *stream)
|
yuuji@0
|
321 {
|
yuuji@0
|
322 return stream->port; /* return port number */
|
yuuji@0
|
323 }
|
yuuji@0
|
324
|
yuuji@0
|
325
|
yuuji@0
|
326 /* TCP/IP get local host name
|
yuuji@0
|
327 * Accepts: TCP/IP stream
|
yuuji@0
|
328 * Returns: local host name
|
yuuji@0
|
329 */
|
yuuji@0
|
330
|
yuuji@0
|
331 char *tcp_localhost (TCPSTREAM *stream)
|
yuuji@0
|
332 {
|
yuuji@0
|
333 return stream->localhost; /* return local host name */
|
yuuji@0
|
334 }
|
yuuji@0
|
335
|
yuuji@0
|
336 /* Return my local host name
|
yuuji@0
|
337 * Returns: my local host name
|
yuuji@0
|
338 */
|
yuuji@0
|
339
|
yuuji@0
|
340 char *mylocalhost ()
|
yuuji@0
|
341 {
|
yuuji@0
|
342 int status;
|
yuuji@0
|
343 char tmp[MAILTMPLEN];
|
yuuji@0
|
344 if (!myLocalHost) { /* have local host yet? */
|
yuuji@0
|
345 /* receives local host name */
|
yuuji@0
|
346 struct dsc$descriptor LocalhostDesc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,NULL};
|
yuuji@0
|
347 if (!((status = net_get_hostname (&LocalhostDesc)) & 0x1)) {
|
yuuji@0
|
348 sprintf (tmp,"Can't get local hostname, status=%d",status);
|
yuuji@0
|
349 mm_log (tmp,ERROR);
|
yuuji@0
|
350 return "UNKNOWN";
|
yuuji@0
|
351 }
|
yuuji@0
|
352 strncpy (tmp,LocalhostDesc.dsc$a_pointer,LocalhostDesc.dsc$w_length);
|
yuuji@0
|
353 tmp[LocalhostDesc.dsc$w_length] = '\0';
|
yuuji@0
|
354 str$free1_dx (&LocalhostDesc);
|
yuuji@0
|
355 myLocalHost = cpystr (tmp);
|
yuuji@0
|
356 }
|
yuuji@0
|
357 return myLocalHost;
|
yuuji@0
|
358 }
|
yuuji@0
|
359
|
yuuji@0
|
360 /* TCP/IP return canonical form of host name
|
yuuji@0
|
361 * Accepts: host name
|
yuuji@0
|
362 * Returns: canonical form of host name
|
yuuji@0
|
363 */
|
yuuji@0
|
364
|
yuuji@0
|
365 char *tcp_canonical (char *name)
|
yuuji@0
|
366 {
|
yuuji@0
|
367 return name;
|
yuuji@0
|
368 }
|
yuuji@0
|
369
|
yuuji@0
|
370
|
yuuji@0
|
371 /* TCP/IP get client host name (server calls only)
|
yuuji@0
|
372 * Returns: client host name
|
yuuji@0
|
373 */
|
yuuji@0
|
374
|
yuuji@0
|
375 char *tcp_clienthost ()
|
yuuji@0
|
376 {
|
yuuji@0
|
377 return "UNKNOWN";
|
yuuji@0
|
378 }
|