1 | /*
|
---|
2 | * Copyright (c) 1995-1999, Index Data
|
---|
3 | * See the file LICENSE for details.
|
---|
4 | * Sebastian Hammer, Adam Dickmeiss
|
---|
5 | *
|
---|
6 | * $Log$
|
---|
7 | * Revision 1.1 2000/08/03 03:10:05 johnmcp
|
---|
8 | * Added the YAZ toolkit source to the packages directory (for z39.50 stuff)
|
---|
9 | *
|
---|
10 | * Revision 1.32 1999/11/30 13:47:11 adam
|
---|
11 | * Improved installation. Moved header files to include/yaz.
|
---|
12 | *
|
---|
13 | * Revision 1.31 1999/04/29 07:31:23 adam
|
---|
14 | * Changed tcpip_strtoaddr_ex so that only part 'till '/' is considered
|
---|
15 | * part of hostname.
|
---|
16 | *
|
---|
17 | * Revision 1.30 1999/04/20 09:56:48 adam
|
---|
18 | * Added 'name' paramter to encoder/decoder routines (typedef Odr_fun).
|
---|
19 | * Modified all encoders/decoders to reflect this change.
|
---|
20 | *
|
---|
21 | * Revision 1.29 1999/04/16 14:45:55 adam
|
---|
22 | * Added interface for tcpd wrapper for access control.
|
---|
23 | *
|
---|
24 | * Revision 1.28 1999/03/31 11:11:14 adam
|
---|
25 | * Function getprotobyname only called once. Minor change in tcpip_get
|
---|
26 | * to handle multi-threaded conditions.
|
---|
27 | *
|
---|
28 | * Revision 1.27 1999/02/02 13:57:31 adam
|
---|
29 | * Uses preprocessor define WIN32 instead of WINDOWS to build code
|
---|
30 | * for Microsoft WIN32.
|
---|
31 | *
|
---|
32 | * Revision 1.26 1999/01/08 11:23:14 adam
|
---|
33 | * Added const modifier to some of the BER/ODR encoding routines.
|
---|
34 | *
|
---|
35 | * Revision 1.25 1998/07/07 15:49:23 adam
|
---|
36 | * Added braces to avoid warning.
|
---|
37 | *
|
---|
38 | * Revision 1.24 1998/06/29 07:59:17 adam
|
---|
39 | * Minor fix.
|
---|
40 | *
|
---|
41 | * Revision 1.23 1998/06/23 15:37:50 adam
|
---|
42 | * Added type cast to prevent warning.
|
---|
43 | *
|
---|
44 | * Revision 1.22 1998/06/22 11:32:36 adam
|
---|
45 | * Added 'conditional cs_listen' feature.
|
---|
46 | *
|
---|
47 | * Revision 1.21 1998/05/20 09:55:32 adam
|
---|
48 | * Function tcpip_get treats EINPROGRESS error in the same way as
|
---|
49 | * EWOULDBLOCK. EINPROGRESS shouldn't be returned - but it is on
|
---|
50 | * Solaris in some cases.
|
---|
51 | *
|
---|
52 | * Revision 1.20 1998/05/18 10:10:40 adam
|
---|
53 | * Minor change to avoid C++ warning.
|
---|
54 | *
|
---|
55 | * Revision 1.19 1998/02/11 11:53:33 adam
|
---|
56 | * Changed code so that it compiles as C++.
|
---|
57 | *
|
---|
58 | * Revision 1.18 1997/09/29 07:15:25 adam
|
---|
59 | * Changed use of setsockopt to avoid warnings on MSVC.
|
---|
60 | *
|
---|
61 | * Revision 1.17 1997/09/17 12:10:30 adam
|
---|
62 | * YAZ version 1.4.
|
---|
63 | *
|
---|
64 | * Revision 1.16 1997/09/01 08:49:14 adam
|
---|
65 | * New windows NT/95 port using MSV5.0. Minor changes only.
|
---|
66 | *
|
---|
67 | * Revision 1.15 1997/05/14 06:53:33 adam
|
---|
68 | * C++ support.
|
---|
69 | *
|
---|
70 | * Revision 1.14 1997/05/01 15:06:32 adam
|
---|
71 | * Moved WINSOCK init. code to tcpip_init routine.
|
---|
72 | *
|
---|
73 | * Revision 1.13 1996/11/01 08:45:18 adam
|
---|
74 | * Bug fix: used close on MS-Windows. Fixed to closesocket.
|
---|
75 | *
|
---|
76 | * Revision 1.12 1996/07/06 19:58:30 quinn
|
---|
77 | * System headerfiles gathered in yconfig
|
---|
78 | *
|
---|
79 | * Revision 1.11 1996/02/23 10:00:39 quinn
|
---|
80 | * WAIS Work
|
---|
81 | *
|
---|
82 | * Revision 1.10 1996/02/20 12:52:11 quinn
|
---|
83 | * WAIS protocol support.
|
---|
84 | *
|
---|
85 | * Revision 1.9 1996/02/10 12:23:11 quinn
|
---|
86 | * Enablie inetd operations fro TCP/IP stack
|
---|
87 | *
|
---|
88 | * Revision 1.8 1995/11/01 13:54:27 quinn
|
---|
89 | * Minor adjustments
|
---|
90 | *
|
---|
91 | * Revision 1.7 1995/10/30 12:41:16 quinn
|
---|
92 | * Added hostname lookup for server.
|
---|
93 | *
|
---|
94 | * Revision 1.6 1995/09/29 17:12:00 quinn
|
---|
95 | * Smallish
|
---|
96 | *
|
---|
97 | * Revision 1.5 1995/09/29 17:01:48 quinn
|
---|
98 | * More Windows work
|
---|
99 | *
|
---|
100 | * Revision 1.4 1995/09/28 10:12:26 quinn
|
---|
101 | * Windows-support changes
|
---|
102 | *
|
---|
103 | * Revision 1.3 1995/09/27 15:02:45 quinn
|
---|
104 | * Modified function heads & prototypes.
|
---|
105 | *
|
---|
106 | * Revision 1.2 1995/06/15 12:30:06 quinn
|
---|
107 | * Added @ as hostname alias for INADDR ANY.
|
---|
108 | *
|
---|
109 | * Revision 1.1 1995/06/14 09:58:20 quinn
|
---|
110 | * Renamed yazlib to comstack.
|
---|
111 | *
|
---|
112 | * Revision 1.20 1995/05/16 08:51:16 quinn
|
---|
113 | * License, documentation, and memory fixes
|
---|
114 | *
|
---|
115 | * Revision 1.19 1995/04/10 10:24:08 quinn
|
---|
116 | * Some bug-fixes.
|
---|
117 | *
|
---|
118 | * Revision 1.18 1995/03/30 13:29:27 quinn
|
---|
119 | * Added REUSEADDR in tcpip_bind
|
---|
120 | *
|
---|
121 | * Revision 1.17 1995/03/27 08:36:10 quinn
|
---|
122 | * Some work on nonblocking operation in xmosi.c and rfct.c.
|
---|
123 | * Added protocol parameter to cs_create()
|
---|
124 | *
|
---|
125 | * Revision 1.16 1995/03/21 15:53:41 quinn
|
---|
126 | * Added rcvconnect
|
---|
127 | *
|
---|
128 | * Revision 1.15 1995/03/21 12:31:27 quinn
|
---|
129 | * Added check for EINPROGRESS on connect.
|
---|
130 | *
|
---|
131 | * Revision 1.14 1995/03/20 09:47:21 quinn
|
---|
132 | * Added server-side support to xmosi.c
|
---|
133 | * Fixed possible problems in rfct
|
---|
134 | * Other little mods
|
---|
135 | *
|
---|
136 | * Revision 1.13 1995/03/15 16:15:13 adam
|
---|
137 | * Removed p_write.
|
---|
138 | *
|
---|
139 | * Revision 1.12 1995/03/15 15:36:27 quinn
|
---|
140 | * Mods to support nonblocking I/O
|
---|
141 | *
|
---|
142 | * Revision 1.11 1995/03/15 08:37:57 quinn
|
---|
143 | * Now we're pretty much set for nonblocking I/O.
|
---|
144 | *
|
---|
145 | * Revision 1.10 1995/03/14 17:00:07 quinn
|
---|
146 | * Bug-fixes - added tracing info to tcpip.c
|
---|
147 | *
|
---|
148 | * Revision 1.9 1995/03/14 10:28:42 quinn
|
---|
149 | * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
|
---|
150 | *
|
---|
151 | * Revision 1.8 1995/03/10 14:22:50 quinn
|
---|
152 | * Removed debug output.
|
---|
153 | *
|
---|
154 | * Revision 1.7 1995/03/10 11:44:59 quinn
|
---|
155 | * Fixes and debugging
|
---|
156 | *
|
---|
157 | * Revision 1.6 1995/03/07 10:26:55 quinn
|
---|
158 | * Initialized type field in the comstacks.
|
---|
159 | *
|
---|
160 | * Revision 1.5 1995/02/14 20:40:07 quinn
|
---|
161 | * Various stuff.
|
---|
162 | *
|
---|
163 | * Revision 1.4 1995/02/14 11:54:49 quinn
|
---|
164 | * Beginning to add full CCL.
|
---|
165 | *
|
---|
166 | * Revision 1.3 1995/02/10 18:58:10 quinn
|
---|
167 | * Fixed tcpip_get (formerly tcpip_read).
|
---|
168 | * Turned tst (cli) into a proper, event-driven thingy.
|
---|
169 | *
|
---|
170 | * Revision 1.2 1995/02/10 15:55:47 quinn
|
---|
171 | * Small things.
|
---|
172 | *
|
---|
173 | * Revision 1.1 1995/02/09 15:51:52 quinn
|
---|
174 | * Works better now.
|
---|
175 | *
|
---|
176 | */
|
---|
177 |
|
---|
178 | #include <stdio.h>
|
---|
179 | #include <string.h>
|
---|
180 | #include <stdlib.h>
|
---|
181 | #ifndef WIN32
|
---|
182 | #include <unistd.h>
|
---|
183 | #endif
|
---|
184 | #include <errno.h>
|
---|
185 | #include <fcntl.h>
|
---|
186 |
|
---|
187 | #include <yaz/comstack.h>
|
---|
188 | #include <yaz/tcpip.h>
|
---|
189 | #include <yaz/log.h>
|
---|
190 |
|
---|
191 | /* Chas added the following, so we get the definition of completeBER */
|
---|
192 | #include <yaz/odr.h>
|
---|
193 |
|
---|
194 | int tcpip_close(COMSTACK h);
|
---|
195 | int tcpip_put(COMSTACK h, char *buf, int size);
|
---|
196 | int tcpip_get(COMSTACK h, char **buf, int *bufsize);
|
---|
197 | int tcpip_connect(COMSTACK h, void *address);
|
---|
198 | int tcpip_more(COMSTACK h);
|
---|
199 | int tcpip_rcvconnect(COMSTACK h);
|
---|
200 | int tcpip_bind(COMSTACK h, void *address, int mode);
|
---|
201 | int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
|
---|
202 | int (*check_ip)(void *cd, const char *a, int len, int type),
|
---|
203 | void *cd);
|
---|
204 |
|
---|
205 | COMSTACK tcpip_accept(COMSTACK h);
|
---|
206 | char *tcpip_addrstr(COMSTACK h);
|
---|
207 | void *tcpip_straddr(COMSTACK h, const char *str);
|
---|
208 |
|
---|
209 | #undef TRACE_TCPIP
|
---|
210 | #ifdef TRACE_TCPIP
|
---|
211 | #define TRC(x) x
|
---|
212 | #else
|
---|
213 | #define TRC(X)
|
---|
214 | #endif
|
---|
215 |
|
---|
216 | typedef struct tcpip_state
|
---|
217 | {
|
---|
218 | char *altbuf; /* alternate buffer for surplus data */
|
---|
219 | int altsize; /* size as xmalloced */
|
---|
220 | int altlen; /* length of data or 0 if none */
|
---|
221 |
|
---|
222 | int written; /* -1 if we aren't writing */
|
---|
223 | int towrite; /* to verify against user input */
|
---|
224 | int (*complete)(const unsigned char *buf, int len); /* length/comple. */
|
---|
225 | struct sockaddr_in addr; /* returned by cs_straddr */
|
---|
226 | char buf[128]; /* returned by cs_addrstr */
|
---|
227 | } tcpip_state;
|
---|
228 |
|
---|
229 | #ifdef WIN32
|
---|
230 | static int tcpip_init (void)
|
---|
231 | {
|
---|
232 | static int initialized = 0;
|
---|
233 | if (!initialized)
|
---|
234 | {
|
---|
235 | WORD requested;
|
---|
236 | WSADATA wd;
|
---|
237 |
|
---|
238 | requested = MAKEWORD(1, 1);
|
---|
239 | if (WSAStartup(requested, &wd))
|
---|
240 | return 0;
|
---|
241 | initialized = 1;
|
---|
242 | }
|
---|
243 | return 1;
|
---|
244 | }
|
---|
245 | #else
|
---|
246 |
|
---|
247 | static int proto_number = 0;
|
---|
248 |
|
---|
249 | static int tcpip_init (void)
|
---|
250 | {
|
---|
251 | struct protoent *proto;
|
---|
252 | /* only call getprotobyname once, in case it allocates memory */
|
---|
253 | if (!(proto = getprotobyname("tcp")))
|
---|
254 | return 0;
|
---|
255 | proto_number = proto->p_proto;
|
---|
256 | return 1;
|
---|
257 | }
|
---|
258 | #endif
|
---|
259 | /*
|
---|
260 | * This function is always called through the cs_create() macro.
|
---|
261 | * s >= 0: socket has already been established for us.
|
---|
262 | */
|
---|
263 | COMSTACK tcpip_type(int s, int blocking, int protocol)
|
---|
264 | {
|
---|
265 | COMSTACK p;
|
---|
266 | tcpip_state *state;
|
---|
267 | int new_socket;
|
---|
268 | #ifdef WIN32
|
---|
269 | unsigned long tru = 1;
|
---|
270 | #endif
|
---|
271 |
|
---|
272 | if (!tcpip_init ())
|
---|
273 | return 0;
|
---|
274 | if (s < 0)
|
---|
275 | {
|
---|
276 | #ifdef WIN32
|
---|
277 | if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
---|
278 | return 0;
|
---|
279 | #else
|
---|
280 | if ((s = socket(AF_INET, SOCK_STREAM, proto_number)) < 0)
|
---|
281 | return 0;
|
---|
282 | #endif
|
---|
283 | new_socket = 1;
|
---|
284 | }
|
---|
285 | else
|
---|
286 | new_socket = 0;
|
---|
287 | if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
|
---|
288 | return 0;
|
---|
289 | if (!(state = (struct tcpip_state *)(p->cprivate =
|
---|
290 | xmalloc(sizeof(tcpip_state)))))
|
---|
291 | return 0;
|
---|
292 |
|
---|
293 | #ifdef WIN32
|
---|
294 | if (!(p->blocking = blocking) && ioctlsocket(s, FIONBIO, &tru) < 0)
|
---|
295 | #else
|
---|
296 | if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
|
---|
297 | #endif
|
---|
298 | return 0;
|
---|
299 |
|
---|
300 | p->iofile = s;
|
---|
301 | p->type = tcpip_type;
|
---|
302 | p->protocol = (enum oid_proto) protocol;
|
---|
303 |
|
---|
304 | p->f_connect = tcpip_connect;
|
---|
305 | p->f_rcvconnect = tcpip_rcvconnect;
|
---|
306 | p->f_get = tcpip_get;
|
---|
307 | p->f_put = tcpip_put;
|
---|
308 | p->f_close = tcpip_close;
|
---|
309 | p->f_more = tcpip_more;
|
---|
310 | p->f_bind = tcpip_bind;
|
---|
311 | p->f_listen = tcpip_listen;
|
---|
312 | p->f_accept = tcpip_accept;
|
---|
313 | p->f_addrstr = tcpip_addrstr;
|
---|
314 | p->f_straddr = tcpip_straddr;
|
---|
315 |
|
---|
316 | p->state = new_socket ? CS_UNBND : CS_IDLE; /* state of line */
|
---|
317 | p->event = CS_NONE;
|
---|
318 | p->cerrno = 0;
|
---|
319 | p->stackerr = 0;
|
---|
320 |
|
---|
321 | state->altbuf = 0;
|
---|
322 | state->altsize = state->altlen = 0;
|
---|
323 | state->towrite = state->written = -1;
|
---|
324 | if (protocol == PROTO_WAIS)
|
---|
325 | state->complete = completeWAIS;
|
---|
326 | else
|
---|
327 | state->complete = completeBER;
|
---|
328 |
|
---|
329 | p->timeout = COMSTACK_DEFAULT_TIMEOUT;
|
---|
330 | TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
|
---|
331 |
|
---|
332 | return p;
|
---|
333 | }
|
---|
334 |
|
---|
335 | int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add)
|
---|
336 | {
|
---|
337 | struct hostent *hp;
|
---|
338 | char *p, buf[512];
|
---|
339 | short int port = 210;
|
---|
340 | unsigned tmpadd;
|
---|
341 |
|
---|
342 | if (!tcpip_init ())
|
---|
343 | return 0;
|
---|
344 | TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
|
---|
345 | add->sin_family = AF_INET;
|
---|
346 | strncpy(buf, str, 511);
|
---|
347 | buf[511] = 0;
|
---|
348 | if ((p = strchr(buf, '/')))
|
---|
349 | *p = 0;
|
---|
350 | if ((p = strchr(buf, ':')))
|
---|
351 | {
|
---|
352 | *p = 0;
|
---|
353 | port = atoi(p + 1);
|
---|
354 | }
|
---|
355 | add->sin_port = htons(port);
|
---|
356 | if (!strcmp("@", buf))
|
---|
357 | add->sin_addr.s_addr = INADDR_ANY;
|
---|
358 | else if ((hp = gethostbyname(buf)))
|
---|
359 | memcpy(&add->sin_addr.s_addr, *hp->h_addr_list,
|
---|
360 | sizeof(struct in_addr));
|
---|
361 | else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
|
---|
362 | memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
|
---|
363 | else
|
---|
364 | return 0;
|
---|
365 | return 1;
|
---|
366 | }
|
---|
367 |
|
---|
368 | void *tcpip_straddr(COMSTACK h, const char *str)
|
---|
369 | {
|
---|
370 | tcpip_state *sp = (tcpip_state *)h->cprivate;
|
---|
371 |
|
---|
372 | if (!tcpip_strtoaddr_ex (str, &sp->addr))
|
---|
373 | return 0;
|
---|
374 | return &sp->addr;
|
---|
375 | }
|
---|
376 |
|
---|
377 | struct sockaddr_in *tcpip_strtoaddr(const char *str)
|
---|
378 | {
|
---|
379 | static struct sockaddr_in add;
|
---|
380 |
|
---|
381 | if (!tcpip_strtoaddr_ex (str, &add))
|
---|
382 | return 0;
|
---|
383 | return &add;
|
---|
384 | }
|
---|
385 |
|
---|
386 | int tcpip_more(COMSTACK h)
|
---|
387 | {
|
---|
388 | tcpip_state *sp = (tcpip_state *)h->cprivate;
|
---|
389 |
|
---|
390 | return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf,
|
---|
391 | sp->altlen);
|
---|
392 | }
|
---|
393 |
|
---|
394 | /*
|
---|
395 | * connect(2) will block (sometimes) - nothing we can do short of doing
|
---|
396 | * weird things like spawning subprocesses or threading or some weird junk
|
---|
397 | * like that.
|
---|
398 | */
|
---|
399 | int tcpip_connect(COMSTACK h, void *address)
|
---|
400 | {
|
---|
401 | struct sockaddr_in *add = (struct sockaddr_in *)address;
|
---|
402 |
|
---|
403 | TRC(fprintf(stderr, "tcpip_connect\n"));
|
---|
404 | if (connect(h->iofile, (struct sockaddr *) add, sizeof(*add)) < 0)
|
---|
405 | {
|
---|
406 | #ifdef WIN32
|
---|
407 | if (WSAGetLastError() == WSAEWOULDBLOCK)
|
---|
408 | #else
|
---|
409 | if (errno == EINPROGRESS)
|
---|
410 | #endif
|
---|
411 | return 1;
|
---|
412 | return -1;
|
---|
413 | }
|
---|
414 | h->state = CS_DATAXFER;
|
---|
415 | return 0;
|
---|
416 | }
|
---|
417 |
|
---|
418 | /*
|
---|
419 | * nop
|
---|
420 | */
|
---|
421 | int tcpip_rcvconnect(COMSTACK h)
|
---|
422 | {
|
---|
423 | TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
|
---|
424 | return 0;
|
---|
425 | }
|
---|
426 |
|
---|
427 | int tcpip_bind(COMSTACK h, void *address, int mode)
|
---|
428 | {
|
---|
429 | struct sockaddr *addr = (struct sockaddr *)address;
|
---|
430 | #ifdef WIN32
|
---|
431 | BOOL one = 1;
|
---|
432 | #else
|
---|
433 | unsigned long one = 1;
|
---|
434 | #endif
|
---|
435 |
|
---|
436 | TRC(fprintf(stderr, "tcpip_bind\n"));
|
---|
437 | if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
|
---|
438 | &one, sizeof(one)) < 0)
|
---|
439 | {
|
---|
440 | h->cerrno = CSYSERR;
|
---|
441 | return -1;
|
---|
442 | }
|
---|
443 | if (bind(h->iofile, addr, sizeof(struct sockaddr_in)) < 0)
|
---|
444 | {
|
---|
445 | h->cerrno = CSYSERR;
|
---|
446 | return -1;
|
---|
447 | }
|
---|
448 | if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
|
---|
449 | {
|
---|
450 | h->cerrno = CSYSERR;
|
---|
451 | return -1;
|
---|
452 | }
|
---|
453 | h->state = CS_IDLE;
|
---|
454 | return 0;
|
---|
455 | }
|
---|
456 |
|
---|
457 | int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
|
---|
458 | int (*check_ip)(void *cd, const char *a, int len, int t),
|
---|
459 | void *cd)
|
---|
460 | {
|
---|
461 | struct sockaddr_in addr;
|
---|
462 | int len = sizeof(addr);
|
---|
463 |
|
---|
464 | TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
|
---|
465 | if (h->state != CS_IDLE)
|
---|
466 | {
|
---|
467 | h->cerrno = CSOUTSTATE;
|
---|
468 | return -1;
|
---|
469 | }
|
---|
470 | if ((h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len)) < 0)
|
---|
471 | {
|
---|
472 | #ifdef WIN32
|
---|
473 | if (WSAGetLastError() == WSAEWOULDBLOCK)
|
---|
474 | #else
|
---|
475 | if (errno == EWOULDBLOCK)
|
---|
476 | #endif
|
---|
477 |
|
---|
478 | h->cerrno = CSNODATA;
|
---|
479 | else
|
---|
480 | h->cerrno = CSYSERR;
|
---|
481 | return -1;
|
---|
482 | }
|
---|
483 | if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
|
---|
484 | memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
|
---|
485 | else if (addrlen)
|
---|
486 | *addrlen = 0;
|
---|
487 | if (check_ip && (*check_ip)(cd, (const char *) &addr,
|
---|
488 | sizeof(addr), AF_INET))
|
---|
489 | {
|
---|
490 | h->cerrno = CSDENY;
|
---|
491 | #ifdef WIN32
|
---|
492 | closesocket(h->newfd);
|
---|
493 | #else
|
---|
494 | close(h->newfd);
|
---|
495 | #endif
|
---|
496 | return -1;
|
---|
497 | }
|
---|
498 | h->state = CS_INCON;
|
---|
499 | return 0;
|
---|
500 | }
|
---|
501 |
|
---|
502 | COMSTACK tcpip_accept(COMSTACK h)
|
---|
503 | {
|
---|
504 | COMSTACK cnew;
|
---|
505 | tcpip_state *state, *st = (tcpip_state *)h->cprivate;
|
---|
506 | #ifdef WIN32
|
---|
507 | unsigned long tru = 1;
|
---|
508 | #endif
|
---|
509 |
|
---|
510 | TRC(fprintf(stderr, "tcpip_accept\n"));
|
---|
511 | if (h->state != CS_INCON)
|
---|
512 | {
|
---|
513 | h->cerrno = CSOUTSTATE;
|
---|
514 | return 0;
|
---|
515 | }
|
---|
516 | if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew))))
|
---|
517 | {
|
---|
518 | h->cerrno = CSYSERR;
|
---|
519 | return 0;
|
---|
520 | }
|
---|
521 | memcpy(cnew, h, sizeof(*h));
|
---|
522 | cnew->iofile = h->newfd;
|
---|
523 | if (!(state = (tcpip_state *)
|
---|
524 | (cnew->cprivate = xmalloc(sizeof(tcpip_state)))))
|
---|
525 | {
|
---|
526 | h->cerrno = CSYSERR;
|
---|
527 | return 0;
|
---|
528 | }
|
---|
529 | #ifdef WIN32
|
---|
530 | if (!cnew->blocking && ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0)
|
---|
531 | #else
|
---|
532 | if (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0)
|
---|
533 | #endif
|
---|
534 | return 0;
|
---|
535 | state->altbuf = 0;
|
---|
536 | state->altsize = state->altlen = 0;
|
---|
537 | state->towrite = state->written = -1;
|
---|
538 | state->complete = st->complete;
|
---|
539 | cnew->state = CS_DATAXFER;
|
---|
540 | h->state = CS_IDLE;
|
---|
541 | return cnew;
|
---|
542 | }
|
---|
543 |
|
---|
544 | #define CS_TCPIP_BUFCHUNK 4096
|
---|
545 |
|
---|
546 | /*
|
---|
547 | * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
|
---|
548 | * 0=connection closed.
|
---|
549 | */
|
---|
550 | int tcpip_get(COMSTACK h, char **buf, int *bufsize)
|
---|
551 | {
|
---|
552 | tcpip_state *sp = (tcpip_state *)h->cprivate;
|
---|
553 | char *tmpc;
|
---|
554 | int tmpi, berlen, rest, req, tomove;
|
---|
555 | int hasread = 0, res;
|
---|
556 |
|
---|
557 | TRC(fprintf(stderr, "tcpip_get: bufsize=%d\n", *bufsize));
|
---|
558 | if (sp->altlen) /* switch buffers */
|
---|
559 | {
|
---|
560 | TRC(fprintf(stderr, " %d bytes in altbuf (0x%x)\n", sp->altlen,
|
---|
561 | (unsigned) sp->altbuf));
|
---|
562 | tmpc = *buf;
|
---|
563 | tmpi = *bufsize;
|
---|
564 | *buf = sp->altbuf;
|
---|
565 | *bufsize = sp->altsize;
|
---|
566 | hasread = sp->altlen;
|
---|
567 | sp->altlen = 0;
|
---|
568 | sp->altbuf = tmpc;
|
---|
569 | sp->altsize = tmpi;
|
---|
570 | }
|
---|
571 | while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
|
---|
572 | {
|
---|
573 | if (!*bufsize)
|
---|
574 | {
|
---|
575 | if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
|
---|
576 | return -1;
|
---|
577 | }
|
---|
578 | else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
|
---|
579 | if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
|
---|
580 | return -1;
|
---|
581 | if ((res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0)) < 0)
|
---|
582 | {
|
---|
583 | #ifdef WIN32
|
---|
584 | if (WSAGetLastError() == WSAEWOULDBLOCK)
|
---|
585 | break;
|
---|
586 | else
|
---|
587 | return -1;
|
---|
588 | #else
|
---|
589 | if (errno == EWOULDBLOCK
|
---|
590 | #ifdef EINPROGRESS
|
---|
591 | || errno == EINPROGRESS
|
---|
592 | #endif
|
---|
593 | )
|
---|
594 | break;
|
---|
595 | else if (errno == 0)
|
---|
596 | continue;
|
---|
597 | else
|
---|
598 | return -1;
|
---|
599 | #endif
|
---|
600 | }
|
---|
601 | if (!res)
|
---|
602 | return 0;
|
---|
603 | hasread += res;
|
---|
604 | TRC(fprintf(stderr, " res=%d, hasread=%d\n", res, hasread));
|
---|
605 | }
|
---|
606 | TRC(fprintf(stderr, " Out of read loop with hasread=%d, berlen=%d\n",
|
---|
607 | hasread, berlen));
|
---|
608 | /* move surplus buffer (or everything if we didn't get a BER rec.) */
|
---|
609 | if (hasread > berlen)
|
---|
610 | {
|
---|
611 | tomove = req = hasread - berlen;
|
---|
612 | rest = tomove % CS_TCPIP_BUFCHUNK;
|
---|
613 | if (rest)
|
---|
614 | req += CS_TCPIP_BUFCHUNK - rest;
|
---|
615 | if (!sp->altbuf)
|
---|
616 | {
|
---|
617 | if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
|
---|
618 | return -1;
|
---|
619 | } else if (sp->altsize < req)
|
---|
620 | if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
|
---|
621 | return -1;
|
---|
622 | TRC(fprintf(stderr, " Moving %d bytes to altbuf(0x%x)\n", tomove,
|
---|
623 | (unsigned) sp->altbuf));
|
---|
624 | memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
|
---|
625 | }
|
---|
626 | if (berlen < CS_TCPIP_BUFCHUNK - 1)
|
---|
627 | *(*buf + berlen) = '\0';
|
---|
628 | return berlen ? berlen : 1;
|
---|
629 | }
|
---|
630 |
|
---|
631 | /*
|
---|
632 | * Returns 1, 0 or -1
|
---|
633 | * In nonblocking mode, you must call again with same buffer while
|
---|
634 | * return value is 1.
|
---|
635 | */
|
---|
636 | int tcpip_put(COMSTACK h, char *buf, int size)
|
---|
637 | {
|
---|
638 | int res;
|
---|
639 | struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
|
---|
640 |
|
---|
641 | TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
|
---|
642 | if (state->towrite < 0)
|
---|
643 | {
|
---|
644 | state->towrite = size;
|
---|
645 | state->written = 0;
|
---|
646 | }
|
---|
647 | else if (state->towrite != size)
|
---|
648 | {
|
---|
649 | h->cerrno = CSWRONGBUF;
|
---|
650 | return -1;
|
---|
651 | }
|
---|
652 | while (state->towrite > state->written)
|
---|
653 | {
|
---|
654 | if ((res = send(h->iofile, buf + state->written, size -
|
---|
655 | state->written, 0)) < 0)
|
---|
656 | {
|
---|
657 | #ifdef WIN32
|
---|
658 | if (WSAGetLastError() == WSAEWOULDBLOCK)
|
---|
659 | #else
|
---|
660 | if (errno == EAGAIN)
|
---|
661 | #endif
|
---|
662 | {
|
---|
663 | TRC(fprintf(stderr, " Flow control stop\n"));
|
---|
664 | return 1;
|
---|
665 | }
|
---|
666 | h->cerrno = CSYSERR;
|
---|
667 | return -1;
|
---|
668 | }
|
---|
669 | state->written += res;
|
---|
670 | TRC(fprintf(stderr, " Wrote %d, written=%d, nbytes=%d\n",
|
---|
671 | res, state->written, size));
|
---|
672 | }
|
---|
673 | state->towrite = state->written = -1;
|
---|
674 | TRC(fprintf(stderr, " Ok\n"));
|
---|
675 | return 0;
|
---|
676 | }
|
---|
677 |
|
---|
678 | int tcpip_close(COMSTACK h)
|
---|
679 | {
|
---|
680 | tcpip_state *sp = (struct tcpip_state *)h->cprivate;
|
---|
681 |
|
---|
682 | TRC(fprintf(stderr, "tcpip_close\n"));
|
---|
683 | if (h->iofile != -1)
|
---|
684 | #ifdef WIN32
|
---|
685 | closesocket(h->iofile);
|
---|
686 | #else
|
---|
687 | close(h->iofile);
|
---|
688 | #endif
|
---|
689 | if (sp->altbuf)
|
---|
690 | xfree(sp->altbuf);
|
---|
691 | xfree(sp);
|
---|
692 | xfree(h);
|
---|
693 | return 0;
|
---|
694 | }
|
---|
695 |
|
---|
696 | char *tcpip_addrstr(COMSTACK h)
|
---|
697 | {
|
---|
698 | struct sockaddr_in addr;
|
---|
699 | tcpip_state *sp = (struct tcpip_state *)h->cprivate;
|
---|
700 | char *r, *buf = sp->buf;
|
---|
701 | size_t len;
|
---|
702 | struct hostent *host;
|
---|
703 |
|
---|
704 | len = sizeof(addr);
|
---|
705 | if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0)
|
---|
706 | {
|
---|
707 | h->cerrno = CSYSERR;
|
---|
708 | return 0;
|
---|
709 | }
|
---|
710 | if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr),
|
---|
711 | AF_INET)))
|
---|
712 | r = (char*) host->h_name;
|
---|
713 | else
|
---|
714 | r = inet_ntoa(addr.sin_addr);
|
---|
715 | sprintf(buf, "tcp:%s", r);
|
---|
716 | return buf;
|
---|
717 | }
|
---|