imapext-2007

view src/osdep/vms/tcp_vmsm.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
line source
1 /* ========================================================================
2 * Copyright 1988-2008 University of Washington
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *
11 * ========================================================================
12 */
14 /*
15 * Program: VMS TCP/IP routines for Multinet
16 *
17 * Author: Mark Crispin
18 * Networks and Distributed Computing
19 * Computing & Communications
20 * University of Washington
21 * Administration Building, AG-44
22 * Seattle, WA 98195
23 * Internet: MRC@CAC.Washington.EDU
24 *
25 * Date: 2 August 1994
26 * Last Edited: 13 January 2008
27 */
30 static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */
31 static long ttmo_read = 0; /* TCP timeouts, in seconds */
32 static long ttmo_write = 0;
34 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
35 long *contd);
37 /* TCP/IP manipulate parameters
38 * Accepts: function code
39 * function-dependent value
40 * Returns: function-dependent return value
41 */
43 void *tcp_parameters (long function,void *value)
44 {
45 void *ret = NIL;
46 switch ((int) function) {
47 case SET_TIMEOUT:
48 tmoh = (tcptimeout_t) value;
49 case GET_TIMEOUT:
50 ret = (void *) tmoh;
51 break;
52 case SET_READTIMEOUT:
53 ttmo_read = (long) value;
54 case GET_READTIMEOUT:
55 ret = (void *) ttmo_read;
56 break;
57 case SET_WRITETIMEOUT:
58 ttmo_write = (long) value;
59 case GET_WRITETIMEOUT:
60 ret = (void *) ttmo_write;
61 break;
62 }
63 return ret;
64 }
66 /* TCP/IP open
67 * Accepts: host name
68 * contact service name
69 * contact port number
70 * Returns: TCP/IP stream if success else NIL
71 */
73 TCPSTREAM *tcp_open (char *host,char *service,unsigned long port)
74 {
75 TCPSTREAM *stream = NIL;
76 int sock;
77 char *s;
78 struct sockaddr_in sin;
79 struct hostent *host_name;
80 char hostname[MAILTMPLEN];
81 char tmp[MAILTMPLEN];
82 struct protoent *pt = getprotobyname ("tcp");
83 struct servent *sv = NIL;
84 port &= 0xffff; /* erase flags */
85 if (service) { /* service specified? */
86 if (*service == '*') { /* yes, special alt driver kludge? */
87 sv = getservbyname (service + 1,"tcp");
88 }
89 else sv = getservbyname (service,"tcp");
90 }
91 /* user service name port */
92 if (sv) port = ntohs (sin.sin_port = sv->s_port);
93 /* copy port number in network format */
94 else sin.sin_port = htons (port);
95 /* The domain literal form is used (rather than simply the dotted decimal
96 as with other Unix programs) because it has to be a valid "host name"
97 in mailsystem terminology. */
98 /* look like domain literal? */
99 if (host[0] == '[' && host[(strlen (host))-1] == ']') {
100 strcpy (hostname,host+1); /* yes, copy number part */
101 hostname[(strlen (hostname))-1] = '\0';
102 if ((sin.sin_addr.s_addr = inet_addr (hostname)) != -1) {
103 sin.sin_family = AF_INET; /* family is always Internet */
104 strcpy (hostname,host); /* hostname is user's argument */
105 }
106 else {
107 sprintf (tmp,"Bad format domain-literal: %.80s",host);
108 mm_log (tmp,ERROR);
109 return NIL;
110 }
111 }
113 else { /* lookup host name, note that brain-dead Unix
114 requires lowercase! */
115 strcpy (hostname,host); /* in case host is in write-protected memory */
116 if ((host_name = gethostbyname (lcase (hostname)))) {
117 /* copy address type */
118 sin.sin_family = host_name->h_addrtype;
119 /* copy host name */
120 strcpy (hostname,host_name->h_name);
121 /* copy host addresses */
122 memcpy (&sin.sin_addr,host_name->h_addr,host_name->h_length);
123 }
124 else {
125 sprintf (tmp,"No such host as %.80s",host);
126 mm_log (tmp,ERROR);
127 return NIL;
128 }
129 }
130 /* get a TCP stream */
131 if ((sock = socket (sin.sin_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) {
132 sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno));
133 mm_log (tmp,ERROR);
134 return NIL;
135 }
136 #if 0
137 /* Maybe this test is necessary. It depends upon how VMS implements
138 * fd_set. UNIX-style fd_set needs it; Windows-style does not.
139 */
140 else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */
141 sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)",
142 sock,FD_SETSIZE);
143 close (sock);
144 return NIL;
145 }
146 #endif
147 /* open connection */
148 if (connect (sock,(struct sockaddr *)&sin,sizeof (sin)) < 0) {
149 sprintf (tmp,"Can't connect to %.80s,%d: %s",hostname,port,
150 strerror (errno));
151 mm_log (tmp,ERROR);
152 return NIL;
153 }
154 /* create TCP/IP stream */
155 stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
156 /* copy official host name */
157 stream->host = cpystr (hostname);
158 /* get local name */
159 gethostname (tmp,MAILTMPLEN-1);
160 stream->localhost = cpystr ((host_name = gethostbyname (tmp)) ?
161 host_name->h_name : tmp);
162 /* init sockets */
163 stream->port = port; /* port number */
164 stream->tcpsi = stream->tcpso = sock;
165 stream->ictr = 0; /* init input counter */
166 return stream; /* return success */
167 }
169 /* TCP/IP authenticated open
170 * Accepts: NETMBX specifier
171 * service name
172 * returned user name buffer
173 * Returns: TCP/IP stream if success else NIL
174 */
176 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
177 {
178 return NIL;
179 }
181 /* TCP receive line
182 * Accepts: TCP stream
183 * Returns: text line string or NIL if failure
184 */
186 char *tcp_getline (TCPSTREAM *stream)
187 {
188 unsigned long n,contd;
189 char *ret = tcp_getline_work (stream,&n,&contd);
190 if (ret && contd) { /* got a line needing continuation? */
191 STRINGLIST *stl = mail_newstringlist ();
192 STRINGLIST *stc = stl;
193 do { /* collect additional lines */
194 stc->text.data = (unsigned char *) ret;
195 stc->text.size = n;
196 stc = stc->next = mail_newstringlist ();
197 ret = tcp_getline_work (stream,&n,&contd);
198 } while (ret && contd);
199 if (ret) { /* stash final part of line on list */
200 stc->text.data = (unsigned char *) ret;
201 stc->text.size = n;
202 /* determine how large a buffer we need */
203 for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
204 ret = fs_get (n + 1); /* copy parts into buffer */
205 for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
206 memcpy (ret + n,stc->text.data,stc->text.size);
207 ret[n] = '\0';
208 }
209 mail_free_stringlist (&stl);/* either way, done with list */
210 }
211 return ret;
212 }
214 /* TCP receive line or partial line
215 * Accepts: TCP stream
216 * pointer to return size
217 * pointer to return continuation flag
218 * Returns: text line string, size and continuation flag, or NIL if failure
219 */
221 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
222 long *contd)
223 {
224 unsigned long n;
225 char *s,*ret,c,d;
226 *contd = NIL; /* assume no continuation */
227 /* make sure have data */
228 if (!tcp_getdata (stream)) return NIL;
229 for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
230 d = *stream->iptr++; /* slurp another character */
231 if ((c == '\015') && (d == '\012')) {
232 ret = (char *) fs_get (n--);
233 memcpy (ret,s,*size = n); /* copy into a free storage string */
234 ret[n] = '\0'; /* tie off string with null */
235 return ret;
236 }
237 }
238 /* copy partial string from buffer */
239 memcpy ((ret = (char *) fs_get (n)),s,*size = n);
240 /* get more data from the net */
241 if (!tcp_getdata (stream)) fs_give ((void **) &ret);
242 /* special case of newline broken by buffer */
243 else if ((c == '\015') && (*stream->iptr == '\012')) {
244 stream->iptr++; /* eat the line feed */
245 stream->ictr--;
246 ret[*size = --n] = '\0'; /* tie off string with null */
247 }
248 else *contd = LONGT; /* continuation needed */
249 return ret;
250 }
252 /* TCP/IP receive buffer
253 * Accepts: TCP/IP stream
254 * size in bytes
255 * buffer to read into
256 * Returns: T if success, NIL otherwise
257 */
259 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
260 {
261 unsigned long n;
262 char *bufptr = buffer;
263 while (size > 0) { /* until request satisfied */
264 if (!tcp_getdata (stream)) return NIL;
265 n = min (size,stream->ictr);/* number of bytes to transfer */
266 /* do the copy */
267 memcpy (bufptr,stream->iptr,n);
268 bufptr += n; /* update pointer */
269 stream->iptr +=n;
270 size -= n; /* update # of bytes to do */
271 stream->ictr -=n;
272 }
273 bufptr[0] = '\0'; /* tie off string */
274 return T;
275 }
277 /* TCP/IP receive data
278 * Accepts: TCP/IP stream
279 * Returns: T if success, NIL otherwise
280 */
282 long tcp_getdata (TCPSTREAM *stream)
283 {
284 int i;
285 fd_set fds,efds;
286 struct timeval tmo;
287 time_t t = time (0);
288 if (stream->tcpsi < 0) return NIL;
289 while (stream->ictr < 1) { /* if nothing in the buffer */
290 time_t tl = time (0); /* start of request */
291 tmo.tv_sec = ttmo_read; /* read timeout */
292 tmo.tv_usec = 0;
293 FD_ZERO (&fds); /* initialize selection vector */
294 FD_ZERO (&efds); /* handle errors too */
295 FD_SET (stream->tcpsi,&fds);/* set bit in selection vector */
296 FD_SET(stream->tcpsi,&efds);/* set bit in error selection vector */
297 errno = NIL; /* block and read */
298 while (((i = select (getdtablesize (),&fds,0,&efds,ttmo_read ? &tmo:0))<0)
299 && (errno == EINTR));
300 if (!i) { /* timeout? */
301 time_t tc = time (0);
302 if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
303 else return tcp_abort (stream);
304 }
305 else if (i < 0) return tcp_abort (stream);
306 while (((i = socket_read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) &&
307 (errno == EINTR));
308 if (i < 1) return tcp_abort (stream);
309 stream->iptr = stream->ibuf;/* point at TCP buffer */
310 stream->ictr = i; /* set new byte count */
311 }
312 return T;
313 }
315 /* TCP/IP send string as record
316 * Accepts: TCP/IP stream
317 * string pointer
318 * Returns: T if success else NIL
319 */
321 long tcp_soutr (TCPSTREAM *stream,char *string)
322 {
323 return tcp_sout (stream,string,(unsigned long) strlen (string));
324 }
327 /* TCP/IP send string
328 * Accepts: TCP/IP stream
329 * string pointer
330 * byte count
331 * Returns: T if success else NIL
332 */
334 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
335 {
336 int i;
337 fd_set fds;
338 struct timeval tmo;
339 time_t t = time (0);
340 if (stream->tcpso < 0) return NIL;
341 while (size > 0) { /* until request satisfied */
342 time_t tl = time (0); /* start of request */
343 tmo.tv_sec = ttmo_write; /* write timeout */
344 tmo.tv_usec = 0;
345 FD_ZERO (&fds); /* initialize selection vector */
346 FD_SET (stream->tcpso,&fds);/* set bit in selection vector */
347 errno = NIL; /* block and write */
348 while (((i = select (getdtablesize (),0,&fds,0,ttmo_write ? &tmo : 0)) < 0)
349 && (errno == EINTR));
350 if (!i) { /* timeout? */
351 time_t tc = time (0);
352 if (tmoh && ((*tmoh) (tc - t,tc - tl))) continue;
353 else return tcp_abort (stream);
354 }
355 else if (i < 0) return tcp_abort (stream);
356 while (((i = socket_write (stream->tcpso,string,size)) < 0) &&
357 (errno == EINTR));
358 if (i < 0) return tcp_abort (stream);
359 size -= i; /* how much we sent */
360 string += i;
361 }
362 return T; /* all done */
363 }
365 /* TCP/IP close
366 * Accepts: TCP/IP stream
367 */
369 void tcp_close (TCPSTREAM *stream)
370 {
371 tcp_abort (stream); /* nuke the stream */
372 /* flush host names */
373 fs_give ((void **) &stream->host);
374 fs_give ((void **) &stream->localhost);
375 fs_give ((void **) &stream); /* flush the stream */
376 }
379 /* TCP/IP abort stream
380 * Accepts: TCP/IP stream
381 * Returns: NIL always
382 */
384 long tcp_abort (TCPSTREAM *stream)
385 {
386 int i;
387 if (stream->tcpsi >= 0) { /* no-op if no socket */
388 /* nuke the socket */
389 socket_close (stream->tcpsi);
390 if (stream->tcpsi != stream->tcpso) socket_close (stream->tcpso);
391 stream->tcpsi = stream->tcpso = -1;
392 }
393 return NIL;
394 }
396 /* TCP/IP get host name
397 * Accepts: TCP/IP stream
398 * Returns: host name for this stream
399 */
401 char *tcp_host (TCPSTREAM *stream)
402 {
403 return stream->host; /* return host name */
404 }
407 /* TCP/IP get remote host name
408 * Accepts: TCP/IP stream
409 * Returns: host name for this stream
410 */
412 char *tcp_remotehost (TCPSTREAM *stream)
413 {
414 return stream->host; /* return host name */
415 }
418 /* TCP/IP return port for this stream
419 * Accepts: TCP/IP stream
420 * Returns: port number for this stream
421 */
423 unsigned long tcp_port (TCPSTREAM *stream)
424 {
425 return stream->port; /* return port number */
426 }
429 /* TCP/IP get local host name
430 * Accepts: TCP/IP stream
431 * Returns: local host name
432 */
434 char *tcp_localhost (TCPSTREAM *stream)
435 {
436 return stream->localhost; /* return local host name */
437 }
439 /* Return my local host name
440 * Returns: my local host name
441 */
443 char *mylocalhost ()
444 {
445 char tmp[MAILTMPLEN];
446 struct hostent *hn;
447 if (!myLocalHost) { /* have local host yet? */
448 gethostname(tmp,MAILTMPLEN);/* get local host name */
449 myLocalHost = cpystr ((hn = gethostbyname (tmp)) ? hn->h_name : tmp);
450 }
451 return myLocalHost;
452 }
455 /* TCP/IP return canonical form of host name
456 * Accepts: host name
457 * Returns: canonical form of host name
458 */
460 char *tcp_canonical (char *name)
461 {
462 char host[MAILTMPLEN];
463 struct hostent *he;
464 /* look like domain literal? */
465 if (name[0] == '[' && name[strlen (name) - 1] == ']') return name;
466 /* note that Unix requires lowercase! */
467 else return (he = gethostbyname (lcase (strcpy (host,name)))) ?
468 he->h_name : name;
469 }
472 /* TCP/IP get client host name (server calls only)
473 * Returns: client host name
474 */
476 char *tcp_clienthost ()
477 {
478 return "UNKNOWN";
479 }

UW-IMAP'd extensions by yuuji