YAZ 5.35.1
tcpip.c
Go to the documentation of this file.
1/* This file is part of the YAZ toolkit.
2 * Copyright (C) Index Data
3 * See the file LICENSE for details.
4 */
9#if HAVE_CONFIG_H
10#include <config.h>
11#endif
12
13#include <yaz/yconfig.h>
14
15#include <stdio.h>
16#include <string.h>
17#include <assert.h>
18#include <stdlib.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <signal.h>
22#if HAVE_SYS_TYPES_H
23#include <sys/types.h>
24#endif
25#if HAVE_SYS_TIME_H
26#include <sys/time.h>
27#endif
28#if HAVE_UNISTD_H
29#include <unistd.h>
30#endif
31#include <yaz/thread_create.h>
32#include <yaz/log.h>
33
34#ifdef WIN32
35#include <winsock2.h>
36#include <ws2tcpip.h>
37#endif
38
39#if HAVE_NETINET_IN_H
40#include <netinet/in.h>
41#endif
42#if HAVE_NETDB_H
43#include <netdb.h>
44#endif
45#if HAVE_ARPA_INET_H
46#include <arpa/inet.h>
47#endif
48#if HAVE_NETINET_TCP_H
49#include <netinet/tcp.h>
50#endif
51#if HAVE_SYS_SOCKET_H
52#include <sys/socket.h>
53#endif
54#if HAVE_SYS_WAIT_H
55#include <sys/wait.h>
56#endif
57
58#if HAVE_GNUTLS_H
59#include <gnutls/x509.h>
60#include <gnutls/gnutls.h>
61#endif
62
63#include <yaz/base64.h>
64#include <yaz/comstack.h>
65#include <yaz/errno.h>
66#include <yaz/tcpip.h>
67
68#ifndef WIN32
69#define RESOLVER_THREAD 1
70#endif
71
72#if HAVE_GNUTLS_H
73#if GNUTLS_VERSION_NUMBER >= 0x030109
74#define SET_GNUTLS_SOCKET(ses, socket) gnutls_transport_set_int(ses, socket)
75#else
76#define SET_GNUTLS_SOCKET(ses, socket) \
77 gnutls_transport_set_ptr(ses, (gnutls_transport_ptr_t) (size_t) socket)
78#endif
79#endif
80
81static void tcpip_close(COMSTACK h);
82static int tcpip_put(COMSTACK h, char *buf, int size);
83static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
84static int tcpip_connect(COMSTACK h, void *address);
85static int tcpip_more(COMSTACK h);
86static int tcpip_rcvconnect(COMSTACK h);
87static int tcpip_bind(COMSTACK h, void *address, int mode);
88static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
89 int (*check_ip)(void *cd, const char *a, int len, int type),
90 void *cd);
91static int tcpip_set_blocking(COMSTACK p, int blocking);
92
93struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port,
94 int *ipv6_only);
95
97static const char *tcpip_addrstr(COMSTACK h);
98static void *tcpip_straddr(COMSTACK h, const char *str);
99
100#ifndef YAZ_SOCKLEN_T
101#define YAZ_SOCKLEN_T int
102#endif
103
104#if HAVE_GNUTLS_H
105struct tcpip_cred_ptr {
106 gnutls_certificate_credentials_t xcred;
107 int ref;
108};
109
110#endif
111/* this state is used for both SSL and straight TCP/IP */
112typedef struct tcpip_state
113{
114 char *altbuf; /* alternate buffer for surplus data */
115 int altsize; /* size as xmalloced */
116 int altlen; /* length of data or 0 if none */
117
118 int written; /* -1 if we aren't writing */
119 int towrite; /* to verify against user input */
120 int (*complete)(const char *buf, int len); /* length/complete. */
123 struct addrinfo *ai;
124 struct addrinfo *ai_connect;
126#if RESOLVER_THREAD
127 int pipefd[2];
128 const char *port;
129 yaz_thread_t thread_id;
130#endif
131 char buf[128]; /* returned by cs_addrstr */
132#if HAVE_GNUTLS_H
133 struct tcpip_cred_ptr *cred_ptr;
134 gnutls_session_t session;
135 char cert_fname[256];
136 int use_bye;
137#endif
143
144static int log_level = 0;
145
146static int tcpip_init(void)
147{
148 static int log_level_set = 0;
149#ifdef WIN32
150 static int initialized = 0;
151#endif
153#ifdef WIN32
154 if (!initialized)
155 {
156 WORD requested;
157 WSADATA wd;
158
159 requested = MAKEWORD(1, 1);
160 if (WSAStartup(requested, &wd))
161 return 0;
162 initialized = 1;
163 }
164#endif
165 if (!log_level_set)
166 {
167 log_level = yaz_log_module_level("comstack");
168 log_level_set = 1;
169 }
170 return 1;
171}
172
173static struct tcpip_state *tcpip_state_create(void)
174{
175 tcpip_state *sp = (struct tcpip_state *) xmalloc(sizeof(*sp));
176
177 sp->altbuf = 0;
178 sp->altsize = sp->altlen = 0;
179 sp->towrite = sp->written = -1;
181 sp->bind_host = 0;
182 sp->host_port = 0;
183 sp->ai = 0;
184 sp->ai_connect = 0;
185#if RESOLVER_THREAD
186 sp->pipefd[0] = sp->pipefd[1] = -1;
187 sp->port = 0;
188#endif
189
190#if HAVE_GNUTLS_H
191 sp->cred_ptr = 0;
192 sp->session = 0;
193 strcpy(sp->cert_fname, "yaz.pem");
194 sp->use_bye = 0;
195#endif
196 sp->connect_request_buf = 0;
197 sp->connect_request_len = 0;
198 sp->connect_response_buf = 0;
199 sp->connect_response_len = 0;
200 return sp;
201}
202
203/*
204 * This function is always called through the cs_create() macro.
205 * s >= 0: socket has already been established for us.
206 */
207COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
208{
209 COMSTACK p;
210
211 if (!tcpip_init())
212 return 0;
213 if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack))))
214 return 0;
215
217 p->flags = flags;
218
219 p->io_pending = 0;
220 p->iofile = s;
221 p->type = tcpip_type;
222 p->protocol = (enum oid_proto) protocol;
223
226 p->f_get = tcpip_get;
227 p->f_put = tcpip_put;
228 p->f_close = tcpip_close;
229 p->f_more = tcpip_more;
230 p->f_bind = tcpip_bind;
236 p->max_recv_bytes = 128 * 1024 * 1024;
237
238 p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */
239 p->event = CS_NONE;
240 p->cerrno = 0;
241 p->user = 0;
242
243 yaz_log(log_level, "Created TCP/SSL comstack h=%p", p);
244
245 return p;
246}
247
249 const char *connect_host, const char *connect_auth,
250 const char *bind_host)
251{
252 if (bind_host)
253 {
254 tcpip_state *sp = (tcpip_state *) p->cprivate;
255 char *cp;
256 sp->bind_host = xmalloc(strlen(bind_host) + 4);
257 strcpy(sp->bind_host, bind_host);
258 cp = strrchr(sp->bind_host, ':');
259
260 if (!cp || cp[1] == '\0')
261 strcat(sp->bind_host, ":0");
262 else
263 strcpy(cp, ":0");
264 }
265 if (connect_host)
266 {
267 tcpip_state *sp = (tcpip_state *) p->cprivate;
268 char *cp;
269 sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 130);
270 strcpy(sp->connect_request_buf, "CONNECT ");
271 strcat(sp->connect_request_buf, connect_host);
272 cp = strchr(sp->connect_request_buf, '/');
273 if (cp)
274 *cp = '\0';
275 strcat(sp->connect_request_buf, " HTTP/1.0\r\n");
276 if (connect_auth && strlen(connect_auth) < 40)
277 {
278 strcat(sp->connect_request_buf, "Proxy-Authorization: Basic ");
279 yaz_base64encode(connect_auth, sp->connect_request_buf +
280 strlen(sp->connect_request_buf));
281 strcat(sp->connect_request_buf, "\r\n");
282 }
283 strcat(sp->connect_request_buf, "\r\n");
285 }
286}
287
288COMSTACK yaz_tcpip_create3(int s, int flags, int protocol,
289 const char *connect_host,
290 const char *connect_auth,
291 const char *bind_host)
292{
293 COMSTACK p = tcpip_type(s, flags, protocol, 0);
294 if (!p)
295 return 0;
296 connect_and_bind(p, connect_host, 0, bind_host);
297 return p;
298}
299
300COMSTACK yaz_tcpip_create2(int s, int flags, int protocol,
301 const char *connect_host,
302 const char *bind_host)
303{
304 return yaz_tcpip_create3(s, flags, protocol, connect_host, 0, bind_host);
305}
306
307COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
308 const char *connect_host)
309{
310 return yaz_tcpip_create2(s, flags, protocol, connect_host, 0);
311}
312
313#if HAVE_GNUTLS_H
314static void tcpip_create_cred(COMSTACK cs)
315{
316 tcpip_state *sp = (tcpip_state *) cs->cprivate;
317 sp->cred_ptr = (struct tcpip_cred_ptr *) xmalloc(sizeof(*sp->cred_ptr));
318 sp->cred_ptr->ref = 1;
319 gnutls_certificate_allocate_credentials(&sp->cred_ptr->xcred);
320}
321
322#endif
323
324COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
325{
326#if HAVE_GNUTLS_H
327 tcpip_state *sp;
328 COMSTACK p;
329
330 p = tcpip_type(s, flags, protocol, 0);
331 if (!p)
332 return 0;
333 p->type = ssl_type;
334 sp = (tcpip_state *) p->cprivate;
335
336 sp->session = (gnutls_session_t) vp;
337 /* note: we don't handle already opened socket in SSL mode - yet */
338
339 return p;
340#else
341 return 0;
342#endif
343}
344
345COMSTACK yaz_ssl_create(int s, int flags, int protocol,
346 const char *connect_host,
347 const char *connect_auth,
348 const char *bind_host)
349{
350 COMSTACK p = ssl_type(s, flags, protocol, 0);
351 if (!p)
352 return 0;
353 connect_and_bind(p, connect_host, connect_auth, bind_host);
354 return p;
355}
356
357#if HAVE_GNUTLS_H
358static int ssl_check_error(COMSTACK h, tcpip_state *sp, int res)
359{
360 yaz_log(log_level, "ssl_check_error error=%d fatal=%d msg=%s",
361 res,
362 gnutls_error_is_fatal(res),
363 gnutls_strerror(res));
364 if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
365 {
366 int dir = gnutls_record_get_direction(sp->session);
367 yaz_log(log_level, " -> incomplete dir=%d", dir);
369 return 1;
370 }
371 h->cerrno = CSERRORSSL;
372 return 0;
373}
374#endif
375
376static void parse_host_port(const char *host_port, char *tmp, size_t tmp_sz,
377 const char **host, const char **port)
378{
379 char *cp = tmp;
380 char *cp1;
381
382 *host = 0;
383 strncpy(tmp, host_port, tmp_sz-1);
384 tmp[tmp_sz-1] = 0;
385
386 if (*cp != '[')
387 *host = cp;
388 else
389 {
390 *host = ++cp;
391 while (*cp)
392 {
393 if (*cp == ']')
394 {
395 *cp++ = '\0';
396 break;
397 }
398 cp++;
399 }
400 }
401 cp1 = strchr(cp, '/');
402 if (cp1)
403 *cp1 = '\0';
404 cp1 = strchr(cp, '?');
405 if (cp1)
406 *cp1 = '\0';
407 cp1 = strrchr(cp, ':');
408 if (cp1)
409 {
410 *port = cp1 + 1;
411 *cp1 = '\0';
412 }
413}
414
415struct addrinfo *tcpip_getaddrinfo(const char *host_and_port,
416 const char *port,
417 int *ipv6_only)
418{
419 struct addrinfo hints, *res;
420 int error;
421 char tmp[512];
422 const char *host;
423
424 hints.ai_flags = 0;
425 hints.ai_family = AF_UNSPEC;
426 hints.ai_socktype = SOCK_STREAM;
427 hints.ai_protocol = 0;
428 hints.ai_addrlen = 0;
429 hints.ai_addr = NULL;
430 hints.ai_canonname = NULL;
431 hints.ai_next = NULL;
432
433 /* default port, might be changed below */
434 parse_host_port(host_and_port, tmp, sizeof tmp, &host, &port);
435
436 if (!strcmp("@", host))
437 {
438 hints.ai_flags = AI_PASSIVE;
439 hints.ai_family = AF_UNSPEC;
440 error = getaddrinfo(0, port, &hints, &res);
441 *ipv6_only = 0;
442 }
443 else if (!strcmp("@4", host))
444 {
445 hints.ai_flags = AI_PASSIVE;
446 hints.ai_family = AF_INET;
447 error = getaddrinfo(0, port, &hints, &res);
448 *ipv6_only = -1;
449 }
450 else if (!strcmp("@6", host))
451 {
452 hints.ai_flags = AI_PASSIVE;
453 hints.ai_family = AF_INET6;
454 error = getaddrinfo(0, port, &hints, &res);
455 *ipv6_only = 1;
456 }
457 else
458 {
459 error = getaddrinfo(host, port, &hints, &res);
460 *ipv6_only = -1;
461 }
462 if (error)
463 return 0;
464 return res;
465}
466
467static struct addrinfo *create_net_socket(COMSTACK h)
468{
469 tcpip_state *sp = (tcpip_state *)h->cprivate;
470 int s = -1;
471 struct addrinfo *ai = 0;
472 if (sp->ipv6_only >= 0)
473 {
474 for (ai = sp->ai; ai; ai = ai->ai_next)
475 {
476 if (ai->ai_family == AF_INET6)
477 {
478 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
479 if (s != -1)
480 break;
481 }
482 }
483 }
484 if (s == -1)
485 {
486 for (ai = sp->ai; ai; ai = ai->ai_next)
487 {
488 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
489 if (s != -1)
490 break;
491 }
492 }
493 if (s == -1)
494 return 0;
495 yaz_log(log_level, "First socket fd=%d", s);
496 assert(ai);
497 h->iofile = s;
498 if (ai->ai_family == AF_INET6 && sp->ipv6_only >= 0 &&
499 setsockopt(h->iofile,
500 IPPROTO_IPV6,
501 IPV6_V6ONLY, &sp->ipv6_only, sizeof(sp->ipv6_only)))
502 return 0;
503 if (sp->bind_host)
504 {
505 int r = -1;
506 int ipv6_only = 0;
507 struct addrinfo *ai;
508
509#ifndef WIN32
510 int one = 1;
511 if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
512 &one, sizeof(one)) < 0)
513 {
514 h->cerrno = CSYSERR;
515 return 0;
516 }
517#endif
518 ai = tcpip_getaddrinfo(sp->bind_host, "0", &ipv6_only);
519 if (!ai)
520 return 0;
521 {
522 struct addrinfo *a;
523 for (a = ai; a; a = a->ai_next)
524 {
525 r = bind(h->iofile, a->ai_addr, a->ai_addrlen);
526 if (!r)
527 break;
528 }
529 }
530 if (r)
531 {
532 h->cerrno = CSYSERR;
533 freeaddrinfo(ai);
534 return 0;
535 }
536 freeaddrinfo(ai);
537 }
538 if (!tcpip_set_blocking(h, h->flags))
539 return 0;
540 return ai;
541}
542
543#if RESOLVER_THREAD
544
545void *resolver_thread(void *arg)
546{
547 COMSTACK h = (COMSTACK) arg;
548 tcpip_state *sp = (tcpip_state *)h->cprivate;
549
550 sp->ipv6_only = 0;
551 if (sp->ai)
552 freeaddrinfo(sp->ai);
553 sp->ai = tcpip_getaddrinfo(sp->host_port, sp->port, &sp->ipv6_only);
554 if (write(sp->pipefd[1], "1", 1) != 1)
555 yaz_log(YLOG_WARN, "tcpip.c: resolver_thread: write error");
556
557 return 0;
558}
559
560static struct addrinfo *wait_resolver_thread(COMSTACK h)
561{
562 tcpip_state *sp = (tcpip_state *)h->cprivate;
563 char buf;
564
565 if (read(sp->pipefd[0], &buf, 1) == (ssize_t) -1)
566 return 0;
567 yaz_thread_join(&sp->thread_id, 0);
568 close(sp->pipefd[0]);
569 close(sp->pipefd[1]);
570 sp->pipefd[0] = -1;
571 h->iofile = -1;
572 return create_net_socket(h);
573}
574
575#endif
576
577void *tcpip_straddr(COMSTACK h, const char *str)
578{
579 tcpip_state *sp = (tcpip_state *)h->cprivate;
580 const char *port = "210";
581
582 if (!tcpip_init())
583 return 0;
584
585 if (h->protocol == PROTO_HTTP)
586 {
587 if (h->type == ssl_type)
588 port = "443";
589 else
590 port = "80";
591 }
592 xfree(sp->host_port);
593 sp->host_port = xstrdup(str);
594#if RESOLVER_THREAD
596 {
597 if (sp->pipefd[0] != -1)
598 return 0;
599 if (pipe(sp->pipefd) == -1)
600 return 0;
601
602 sp->port = port;
603 sp->thread_id = yaz_thread_create(resolver_thread, h);
604 return sp->host_port;
605 }
606#endif
607 if (sp->ai)
608 freeaddrinfo(sp->ai);
609 sp->ai = tcpip_getaddrinfo(sp->host_port, port, &sp->ipv6_only);
610 if (sp->ai && h->state == CS_ST_UNBND)
611 {
612 return create_net_socket(h);
613 }
614 return sp->ai;
615}
616
618{
619 tcpip_state *sp = (tcpip_state *)h->cprivate;
620
621 return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
622}
623
625{
626 tcpip_state *sp = (tcpip_state *)h->cprivate;
627 struct addrinfo *ai = sp->ai_connect;
628 while (ai && (ai = ai->ai_next))
629 {
630 int s;
631 s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
632 if (s != -1)
633 {
634#if HAVE_GNUTLS_H
635 if (h->type == ssl_type && sp->session)
636 {
637 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
638 gnutls_deinit(sp->session);
639 sp->session = 0;
640 }
641#endif
642#ifdef WIN32
643 closesocket(h->iofile);
644#else
645 close(h->iofile);
646#endif
647 yaz_log(log_level, "Other socket call fd=%d", s);
648 h->state = CS_ST_UNBND;
649 h->iofile = s;
651 return tcpip_connect(h, ai);
652 }
653 }
654 h->cerrno = CSYSERR;
655 return -1;
656}
657
658
659/*
660 * connect(2) will block (sometimes) - nothing we can do short of doing
661 * weird things like spawning subprocesses or threading or some weird junk
662 * like that.
663 */
664int tcpip_connect(COMSTACK h, void *address)
665{
666 struct addrinfo *ai = (struct addrinfo *) address;
667 tcpip_state *sp = (tcpip_state *)h->cprivate;
668 int r;
669 yaz_log(log_level, "tcpip_connect h=%p", h);
670 h->io_pending = 0;
671 if (h->state != CS_ST_UNBND)
672 {
673 h->cerrno = CSOUTSTATE;
674 return -1;
675 }
676#if RESOLVER_THREAD
677 if (sp->pipefd[0] != -1)
678 {
679 if (h->flags & CS_FLAGS_BLOCKING)
680 {
681 ai = wait_resolver_thread(h);
682 if (!ai)
683 return -1;
684 }
685 else
686 {
687 h->event = CS_CONNECT;
690 h->iofile = sp->pipefd[0];
691 return 1;
692 }
693 }
694#endif
695 r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen);
696 sp->ai_connect = ai;
697 if (r < 0)
698 {
699#ifdef WIN32
700 if (WSAGetLastError() == WSAEWOULDBLOCK)
701 {
702 h->event = CS_CONNECT;
705 return 1;
706 }
707#else
708 if (yaz_errno() == EINPROGRESS)
709 {
710 yaz_log(log_level, "Pending fd=%d", h->iofile);
711 h->event = CS_CONNECT;
714 return 1;
715 }
716#endif
717 return cont_connect(h);
718 }
719 h->event = CS_CONNECT;
721
722 return tcpip_rcvconnect(h);
723}
724
725/*
726 * nop
727 */
729{
730 tcpip_state *sp = (tcpip_state *)h->cprivate;
731 yaz_log(log_level, "tcpip_rcvconnect h=%p", h);
732
733 if (h->state == CS_ST_DATAXFER)
734 return 0;
735#if RESOLVER_THREAD
736 if (sp->pipefd[0] != -1)
737 {
738 struct addrinfo *ai = wait_resolver_thread(h);
739 if (!ai)
740 return -1;
741 h->state = CS_ST_UNBND;
742 return tcpip_connect(h, ai);
743 }
744#endif
745 if (h->state != CS_ST_CONNECTING)
746 {
747 h->cerrno = CSOUTSTATE;
748 return -1;
749 }
750 if (sp->connect_request_buf)
751 {
752 int r;
753
755 if (sp->connect_request_len > 0)
756 {
759 yaz_log(log_level, "tcpip_rcvconnect connect put r=%d", r);
760 h->event = CS_CONNECT; /* because tcpip_put sets it */
761 if (r) /* < 0 is error, 1 is in-complete */
762 return r;
763 yaz_log(log_level, "tcpip_rcvconnect connect complete");
764 }
765 sp->connect_request_len = 0;
766
768 yaz_log(log_level, "tcpip_rcvconnect connect get r=%d", r);
769 if (r == 1)
770 return r;
771 if (r <= 0)
772 return -1;
774 sp->connect_request_buf = 0;
776 }
777#if HAVE_GNUTLS_H
778 if (h->type == ssl_type && !sp->session)
779 {
780 const char *host = 0;
781 const char *port = 0;
782 char tmp[512];
783
784 tcpip_create_cred(h);
785 gnutls_init(&sp->session, GNUTLS_CLIENT);
786 sp->use_bye = 1; /* only say goodbye in client */
787 gnutls_set_default_priority(sp->session);
788 gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
789 sp->cred_ptr->xcred);
790 parse_host_port(sp->host_port, tmp, sizeof tmp, &host, &port);
791 /* raw IPV6 seems to be rejected on the server */
792 if (!strchr(host, ':'))
793 gnutls_server_name_set(sp->session, GNUTLS_NAME_DNS,
794 host, strlen(host));
795 SET_GNUTLS_SOCKET(sp->session, h->iofile);
796 }
797 if (sp->session)
798 {
799 int res = gnutls_handshake(sp->session);
800 if (res < 0)
801 {
802 if (ssl_check_error(h, sp, res))
803 return 1;
804 return cont_connect(h);
805 }
806 }
807#endif
808 h->event = CS_DATA;
810 return 0;
811}
812
813static int tcpip_bind(COMSTACK h, void *address, int mode)
814{
815 int r;
816 tcpip_state *sp = (tcpip_state *)h->cprivate;
817 struct addrinfo *ai = (struct addrinfo *) address;
818#ifdef WIN32
819 BOOL one = 1;
820#else
821 int one = 1;
822#endif
823
824 yaz_log(log_level, "tcpip_bind h=%p", h);
825#if RESOLVER_THREAD
826 if (sp->pipefd[0] != -1)
827 {
828 ai = wait_resolver_thread(h);
829 if (!ai)
830 return -1;
831 }
832#endif
833#if HAVE_GNUTLS_H
834 if (h->type == ssl_type && !sp->session)
835 {
836 int res;
837 tcpip_create_cred(h);
838 res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
839 sp->cert_fname,
840 sp->cert_fname,
841 GNUTLS_X509_FMT_PEM);
842 if (res != GNUTLS_E_SUCCESS)
843 {
844 yaz_log(log_level, "gnutls_certificate_set_x509_key_file r=%d fatal=%d msg=%s",
845 res,
846 gnutls_error_is_fatal(res),
847 gnutls_strerror(res));
848 h->cerrno = CSERRORSSL;
849 return -1;
850 }
851 }
852#endif
853#ifndef WIN32
854 if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
855 &one, sizeof(one)) < 0)
856 {
857 h->cerrno = CSYSERR;
858 return -1;
859 }
860#endif
861 r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
862 freeaddrinfo(sp->ai);
863 sp->ai = 0;
864 if (r)
865 {
866 h->cerrno = CSYSERR;
867 return -1;
868 }
869 /* Allow a maximum-sized backlog of waiting-to-connect clients */
870 if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
871 {
872 h->cerrno = CSYSERR;
873 return -1;
874 }
875 h->state = CS_ST_IDLE;
876 h->event = CS_LISTEN;
877 return 0;
878}
879
880int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
881 int (*check_ip)(void *cd, const char *a, int len, int t),
882 void *cd)
883{
884#ifdef WIN32
885 /* we don't get peer address on Windows (via accept) */
886#else
887 struct sockaddr_in addr;
888 YAZ_SOCKLEN_T len = sizeof(addr);
889#endif
890
891 yaz_log(log_level, "tcpip_listen h=%p", h);
892 if (h->state != CS_ST_IDLE)
893 {
894 h->cerrno = CSOUTSTATE;
895 return -1;
896 }
897#ifdef WIN32
898 h->newfd = accept(h->iofile, 0, 0);
899#else
900 h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
901#endif
902 if (h->newfd < 0)
903 {
904 if (
905#ifdef WIN32
906 WSAGetLastError() == WSAEWOULDBLOCK
907#else
908 yaz_errno() == EWOULDBLOCK
909#ifdef EAGAIN
910#if EAGAIN != EWOULDBLOCK
911 || yaz_errno() == EAGAIN
912#endif
913#endif
914#endif
915 )
916 h->cerrno = CSNODATA;
917 else
918 {
919 shutdown(h->iofile, 0); /* SHUT_RD/SHUT_RECEIVE */
920 listen(h->iofile, SOMAXCONN);
921 h->cerrno = CSYSERR;
922 }
923 return -1;
924 }
925#ifdef WIN32
926 if (addrlen)
927 *addrlen = 0;
928#else
929 if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
930 memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
931 else if (addrlen)
932 *addrlen = 0;
933 if (check_ip && (*check_ip)(cd, (const char *) &addr,
934 sizeof(addr), AF_INET))
935 {
936 h->cerrno = CSDENY;
937#ifdef WIN32
938 closesocket(h->newfd);
939#else
940 close(h->newfd);
941#endif
942 h->newfd = -1;
943 return -1;
944 }
945#endif
946 h->state = CS_ST_INCON;
947 return 0;
948}
949
951{
952 COMSTACK cnew;
953#ifdef WIN32
954 unsigned long tru = 1;
955#endif
956
957 yaz_log(log_level, "tcpip_accept h=%p", h);
958 if (h->state == CS_ST_INCON)
959 {
960#if HAVE_GNUTLS_H
961 tcpip_state *st = (tcpip_state *)h->cprivate;
962#endif
964 cnew = (COMSTACK) xmalloc(sizeof(*cnew));
965
966 memcpy(cnew, h, sizeof(*h));
967 cnew->iofile = h->newfd;
968 cnew->io_pending = 0;
969 cnew->cprivate = state;
970
971 if (!tcpip_set_blocking(cnew, cnew->flags))
972 {
973 h->cerrno = CSYSERR;
974 if (h->newfd != -1)
975 {
976#ifdef WIN32
977 closesocket(h->newfd);
978#else
979 close(h->newfd);
980#endif
981 h->newfd = -1;
982 }
983 xfree(state);
984 xfree(cnew);
985 return 0;
986 }
987 h->newfd = -1;
988 cnew->state = CS_ST_ACCEPT;
989 h->state = CS_ST_IDLE;
990
991#if HAVE_GNUTLS_H
992 state->cred_ptr = st->cred_ptr;
993 if (st->cred_ptr)
994 {
995 int res;
996
997 (state->cred_ptr->ref)++;
998 gnutls_init(&state->session, GNUTLS_SERVER);
999 if (!state->session)
1000 {
1001 xfree(cnew);
1002 xfree(state);
1003 return 0;
1004 }
1005 res = gnutls_set_default_priority(state->session);
1006 if (res != GNUTLS_E_SUCCESS)
1007 {
1008 xfree(cnew);
1009 xfree(state);
1010 return 0;
1011 }
1012 res = gnutls_credentials_set(state->session,
1013 GNUTLS_CRD_CERTIFICATE,
1014 st->cred_ptr->xcred);
1015 if (res != GNUTLS_E_SUCCESS)
1016 {
1017 xfree(cnew);
1018 xfree(state);
1019 return 0;
1020 }
1021 SET_GNUTLS_SOCKET(state->session, cnew->iofile);
1022 }
1023#endif
1024 h = cnew;
1025 }
1026 if (h->state == CS_ST_ACCEPT)
1027 {
1028#if HAVE_GNUTLS_H
1029 tcpip_state *state = (tcpip_state *)h->cprivate;
1030 if (state->session)
1031 {
1032 int res = gnutls_handshake(state->session);
1033 if (res < 0)
1034 {
1035 if (ssl_check_error(h, state, res))
1036 {
1037 yaz_log(log_level, "tcpip_accept gnutls_handshake interrupted");
1038 return h;
1039 }
1040 yaz_log(log_level, "tcpip_accept gnutls_handshake failed");
1041 cs_close(h);
1042 return 0;
1043 }
1044 }
1045#endif
1046 }
1047 else
1048 {
1049 h->cerrno = CSOUTSTATE;
1050 return 0;
1051 }
1052 h->io_pending = 0;
1053 h->state = CS_ST_DATAXFER;
1054 h->event = CS_DATA;
1055 return h;
1056}
1057
1058#define CS_TCPIP_BUFCHUNK 4096
1059
1060/*
1061 * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1062 * 0=connection closed.
1063 */
1064int tcpip_get(COMSTACK h, char **buf, int *bufsize)
1065{
1066 tcpip_state *sp = (tcpip_state *)h->cprivate;
1067 char *tmpc;
1068 int tmpi, berlen, rest, req, tomove;
1069 int hasread = 0, res;
1070
1071 yaz_log(log_level, "tcpip_get h=%p bufsize=%d", h, *bufsize);
1072 if (sp->altlen) /* switch buffers */
1073 {
1074 yaz_log(log_level, " %d bytes in altbuf (%p)", sp->altlen, sp->altbuf);
1075 tmpc = *buf;
1076 tmpi = *bufsize;
1077 *buf = sp->altbuf;
1078 *bufsize = sp->altsize;
1079 hasread = sp->altlen;
1080 sp->altlen = 0;
1081 sp->altbuf = tmpc;
1082 sp->altsize = tmpi;
1083 }
1084 h->io_pending = 0;
1085 while (!(berlen = (*sp->complete)(*buf, hasread)))
1086 {
1087 if (!*bufsize)
1088 {
1089 if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1090 {
1091 h->cerrno = CSYSERR;
1092 return -1;
1093 }
1094 }
1095 else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1096 if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1097 {
1098 h->cerrno = CSYSERR;
1099 return -1;
1100 }
1101#if HAVE_GNUTLS_H
1102 if (sp->session)
1103 {
1104 res = gnutls_record_recv(sp->session, *buf + hasread,
1106 if (res == 0)
1107 {
1108 yaz_log(log_level, "gnutls_record_recv returned 0");
1109 return 0;
1110 }
1111 else if (res < 0)
1112 {
1113 if (ssl_check_error(h, sp, res))
1114 break;
1115 return -1;
1116 }
1117 }
1118 else
1119#endif
1120 {
1121#ifdef __sun__
1122 yaz_set_errno( 0 );
1123 /* unfortunatly, sun sometimes forgets to set errno in recv
1124 when EWOULDBLOCK etc. would be required (res = -1) */
1125#endif
1126 res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
1127 yaz_log(log_level, " recv res=%d, hasread=%d", res, hasread);
1128 if (res < 0)
1129 {
1130 yaz_log(log_level, " recv errno=%d, (%s)", yaz_errno(),
1131 strerror(yaz_errno()));
1132#ifdef WIN32
1133 if (WSAGetLastError() == WSAEWOULDBLOCK)
1134 {
1136 break;
1137 }
1138 else
1139 {
1140 h->cerrno = CSYSERR;
1141 return -1;
1142 }
1143#else
1144 if (yaz_errno() == EWOULDBLOCK
1145#ifdef EAGAIN
1146#if EAGAIN != EWOULDBLOCK
1147 || yaz_errno() == EAGAIN
1148#endif
1149#endif
1150 || yaz_errno() == EINPROGRESS
1151#ifdef __sun__
1152 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
1153#endif
1154 )
1155 {
1157 break;
1158 }
1159 else if (yaz_errno() == 0)
1160 continue;
1161 else
1162 {
1163 h->cerrno = CSYSERR;
1164 return -1;
1165 }
1166#endif
1167 }
1168 else if (!res)
1169 return hasread;
1170 }
1171 hasread += res;
1172 if (hasread > h->max_recv_bytes)
1173 {
1174 h->cerrno = CSBUFSIZE;
1175 return -1;
1176 }
1177 }
1178 yaz_log(log_level, " Out of read loop with hasread=%d, berlen=%d",
1179 hasread, berlen);
1180 /* move surplus buffer (or everything if we didn't get a BER rec.) */
1181 if (hasread > berlen)
1182 {
1183 tomove = req = hasread - berlen;
1184 rest = tomove % CS_TCPIP_BUFCHUNK;
1185 if (rest)
1186 req += CS_TCPIP_BUFCHUNK - rest;
1187 if (!sp->altbuf)
1188 {
1189 if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1190 {
1191 h->cerrno = CSYSERR;
1192 return -1;
1193 }
1194 } else if (sp->altsize < req)
1195 if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1196 {
1197 h->cerrno = CSYSERR;
1198 return -1;
1199 }
1200 yaz_log(log_level, " Moving %d bytes to altbuf(%p)", tomove,
1201 sp->altbuf);
1202 memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1203 }
1204 if (berlen < CS_TCPIP_BUFCHUNK - 1)
1205 *(*buf + berlen) = '\0';
1206 return berlen ? berlen : 1;
1207}
1208
1209
1210/*
1211 * Returns 1, 0 or -1
1212 * In nonblocking mode, you must call again with same buffer while
1213 * return value is 1.
1214 */
1215int tcpip_put(COMSTACK h, char *buf, int size)
1216{
1217 int res;
1218 struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1219
1220 yaz_log(log_level, "tcpip_put h=%p size=%d", h, size);
1221 h->io_pending = 0;
1222 h->event = CS_DATA;
1223 if (state->towrite < 0)
1224 {
1225 state->towrite = size;
1226 state->written = 0;
1227 }
1228 else if (state->towrite != size)
1229 {
1230 h->cerrno = CSWRONGBUF;
1231 return -1;
1232 }
1233 while (state->towrite > state->written)
1234 {
1235#if HAVE_GNUTLS_H
1236 if (state->session)
1237 {
1238 res = gnutls_record_send(state->session, buf + state->written,
1239 size - state->written);
1240 if (res <= 0)
1241 {
1242 if (ssl_check_error(h, state, res))
1243 return 1;
1244 return -1;
1245 }
1246 }
1247 else
1248#endif
1249 {
1250 if ((res =
1251 send(h->iofile, buf + state->written, size -
1252 state->written,
1253#ifdef MSG_NOSIGNAL
1254 MSG_NOSIGNAL
1255#else
1256 0
1257#endif
1258 )) < 0)
1259 {
1260 if (
1261#ifdef WIN32
1262 WSAGetLastError() == WSAEWOULDBLOCK
1263#else
1264 yaz_errno() == EWOULDBLOCK
1265#ifdef EAGAIN
1266#if EAGAIN != EWOULDBLOCK
1267 || yaz_errno() == EAGAIN
1268#endif
1269#endif
1270#ifdef __sun__
1271 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1272#endif
1273 || yaz_errno() == EINPROGRESS
1274#endif
1275 )
1276 {
1277 yaz_log(log_level, " Flow control stop");
1279 return 1;
1280 }
1281 if (h->flags & CS_FLAGS_BLOCKING)
1282 {
1283 h->cerrno = CSYSERR;
1284 return -1;
1285 }
1286 else
1287 return cont_connect(h);
1288 }
1289 }
1290 state->written += res;
1291 yaz_log(log_level, " Wrote %d, written=%d, nbytes=%d",
1292 res, state->written, size);
1293 }
1294 state->towrite = state->written = -1;
1295 yaz_log(log_level, " Ok");
1296 return 0;
1297}
1298
1300{
1301 tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1302
1303 yaz_log(log_level, "tcpip_close: h=%p", h);
1304 xfree(sp->bind_host);
1305#if RESOLVER_THREAD
1306 if (sp->pipefd[0] != -1)
1307 {
1308 yaz_thread_join(&sp->thread_id, 0);
1309 close(sp->pipefd[0]);
1310 close(sp->pipefd[1]);
1311 h->iofile = -1;
1312 }
1313#endif
1314 if (h->iofile != -1)
1315 {
1316#if HAVE_GNUTLS_H
1317 if (sp->session && sp->use_bye)
1318 {
1319 yaz_log(log_level, "tcpip_close: gnutls_bye");
1320 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1321 }
1322#endif
1323#ifdef WIN32
1324 closesocket(h->iofile);
1325#else
1326 close(h->iofile);
1327#endif
1328 }
1329 if (sp->altbuf)
1330 xfree(sp->altbuf);
1331#if HAVE_GNUTLS_H
1332 if (sp->session)
1333 {
1334 gnutls_deinit(sp->session);
1335 }
1336 if (sp->cred_ptr)
1337 {
1338 assert(sp->cred_ptr->ref > 0);
1339
1340 if (--(sp->cred_ptr->ref) == 0)
1341 {
1342 yaz_log(log_level, "tcpip_close: removed credentials h=%p",
1343 sp->cred_ptr->xcred);
1344 gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1345 xfree(sp->cred_ptr);
1346 }
1347 sp->cred_ptr = 0;
1348 }
1349#endif
1350 if (sp->ai)
1351 freeaddrinfo(sp->ai);
1352 xfree(sp->host_port);
1355 xfree(sp);
1356 xfree(h);
1357}
1358
1360{
1361 tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1362 char *r = 0, *buf = sp->buf;
1363
1364 char host[120];
1365 struct sockaddr_storage addr;
1366 YAZ_SOCKLEN_T len = sizeof(addr);
1367
1368 if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1369 {
1370 h->cerrno = CSYSERR;
1371 return 0;
1372 }
1373 if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
1374 0, 0,
1375 (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1376 {
1377 r = "unknown";
1378 }
1379 else
1380 r = host;
1381
1382 if (h->protocol == PROTO_HTTP)
1383 sprintf(buf, "http:%s", r);
1384 else
1385 sprintf(buf, "tcp:%s", r);
1386#if HAVE_GNUTLS_H
1387 if (sp->session)
1388 {
1389 if (h->protocol == PROTO_HTTP)
1390 sprintf(buf, "https:%s", r);
1391 else
1392 sprintf(buf, "ssl:%s", r);
1393 }
1394#endif
1395 return buf;
1396}
1397
1398static int tcpip_set_blocking(COMSTACK p, int flags)
1399{
1400 unsigned long flag;
1401
1402#ifdef WIN32
1403 flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1404 if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1405 return 0;
1406#else
1407 flag = fcntl(p->iofile, F_GETFL, 0);
1408 if (flags & CS_FLAGS_BLOCKING)
1409 flag = flag & ~O_NONBLOCK; /* blocking */
1410 else
1411 {
1412 flag = flag | O_NONBLOCK; /* non-blocking */
1413 signal(SIGPIPE, SIG_IGN);
1414 }
1415 if (fcntl(p->iofile, F_SETFL, flag) < 0)
1416 return 0;
1417#endif
1418 p->flags = flags;
1419 return 1;
1420}
1421
1422
1423#if HAVE_GNUTLS_H
1424/* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
1425 GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
1426#if GNUTLS_VERSION_NUMBER >= 0x020400
1427#define USE_GNUTLS_X509_CRT_PRINT 1
1428#else
1429#define USE_GNUTLS_X509_CRT_PRINT 0
1430#endif
1431
1432
1433#if USE_GNUTLS_X509_CRT_PRINT
1434#else
1435static const char *bin2hex(const void *bin, size_t bin_size)
1436{
1437 static char printable[110];
1438 const unsigned char *_bin = bin;
1439 char *print;
1440 size_t i;
1441 if (bin_size > 50)
1442 bin_size = 50;
1443 print = printable;
1444 for (i = 0; i < bin_size; i++)
1445 {
1446 sprintf(print, "%.2x ", _bin[i]);
1447 print += 2;
1448 }
1449 return printable;
1450}
1451
1452static void x509_crt_print(gnutls_x509_crt_t cert)
1453{
1454 time_t expiration_time, activation_time;
1455 size_t size;
1456 char serial[40];
1457 char dn[256];
1458 unsigned int algo, bits;
1459
1460 expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1461 activation_time = gnutls_x509_crt_get_activation_time(cert);
1462
1463 printf("\tCertificate is valid since: %s", ctime(&activation_time));
1464 printf("\tCertificate expires: %s", ctime(&expiration_time));
1465
1466 /* Print the serial number of the certificate. */
1467 size = sizeof(serial);
1468 gnutls_x509_crt_get_serial(cert, serial, &size);
1469
1470 printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
1471
1472 /* Extract some of the public key algorithm's parameters
1473 */
1474 algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1475
1476 printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1477
1478 /* Print the version of the X.509 certificate. */
1479 printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1480
1481 size = sizeof(dn);
1482 gnutls_x509_crt_get_dn(cert, dn, &size);
1483 printf("\tDN: %s\n", dn);
1484
1485 size = sizeof(dn);
1486 gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1487 printf("\tIssuer's DN: %s\n", dn);
1488}
1489#endif
1490#endif
1491
1493{
1494#if HAVE_GNUTLS_H
1495 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1496 if (cs->type == ssl_type && sp->session)
1497 {
1498 const gnutls_datum_t *cert_list;
1499 unsigned i, cert_list_size;
1500 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1501 return;
1502 printf("X509 certificate\n");
1503 cert_list = gnutls_certificate_get_peers(sp->session,
1504 &cert_list_size);
1505 printf("Peer provided %u certificates\n", cert_list_size);
1506 for (i = 0; i < cert_list_size; i++)
1507 {
1508 gnutls_x509_crt_t cert;
1509#if USE_GNUTLS_X509_CRT_PRINT
1510 int ret;
1511 gnutls_datum_t cinfo;
1512#endif
1513 gnutls_x509_crt_init(&cert);
1514 gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1515 printf("Certificate info %u:\n", i + 1);
1516#if USE_GNUTLS_X509_CRT_PRINT
1517 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1518 &cinfo);
1519 if (ret == 0)
1520 {
1521 printf("\t%s\n", cinfo.data);
1522 gnutls_free(cinfo.data);
1523 }
1524#else
1525 x509_crt_print(cert);
1526#endif
1527 gnutls_x509_crt_deinit(cert);
1528
1529 }
1530 }
1531#endif
1532}
1533
1535{
1536 /* doesn't do anything for GNUTLS */
1537 return 0;
1538}
1539
1540int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1541{
1542#if HAVE_GNUTLS_H
1543 if (cs && cs->type == ssl_type)
1544 {
1545 /* doesn't do anything for GNUTLS */
1546 return 1;
1547 }
1548#endif
1549 return 0;
1550}
1551
1552int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1553{
1554#if HAVE_GNUTLS_H
1555 if (cs && cs->type == ssl_type)
1556 {
1557 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1558 strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1559 sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1560 return 1;
1561 }
1562#endif
1563 return 0;
1564}
1565
1567{
1568
1569#if HAVE_GNUTLS_H
1570#if USE_GNUTLS_X509_CRT_PRINT
1571 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1572 if (cs->type == ssl_type && sp->session)
1573 {
1574 const gnutls_datum_t *cert_list;
1575 unsigned cert_list_size;
1576 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1577 return 0;
1578 cert_list = gnutls_certificate_get_peers(sp->session, &cert_list_size);
1579 if (cert_list_size > 0)
1580 {
1581 gnutls_x509_crt_t cert;
1582 int ret;
1583 gnutls_datum_t cinfo;
1584
1585 gnutls_x509_crt_init(&cert);
1586 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1587
1588 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &cinfo);
1589 if (ret == 0)
1590 {
1591 *buf = xstrdup((char *) cinfo.data);
1592 *len = strlen(*buf);
1593 gnutls_free(cinfo.data);
1594 gnutls_x509_crt_deinit(cert);
1595 return 1;
1596 }
1597 gnutls_x509_crt_deinit(cert);
1598 }
1599 }
1600#endif
1601#endif
1602 return 0;
1603}
1604
1605int cs_set_head_only(COMSTACK cs, int head_only)
1606{
1607 if (cs->type == tcpip_type || cs->type == ssl_type)
1608 {
1609 tcpip_state *sp = (tcpip_state *)cs->cprivate;
1610 if (head_only)
1612 else
1614 return 0;
1615 }
1616 cs->cerrno = CS_ST_INCON;
1617 return -1;
1618}
1619
1620/*
1621 * Local variables:
1622 * c-basic-offset: 4
1623 * c-file-style: "Stroustrup"
1624 * indent-tabs-mode: nil
1625 * End:
1626 * vim: shiftwidth=4 tabstop=8 expandtab
1627 */
1628
void yaz_base64encode(const char *in, char *out)
encodes Base64 string
Definition base64.c:16
Header for Base64 utilities.
int cs_complete_auto(const char *buf, int len)
Definition comstack.c:466
int cs_complete_auto_head(const char *buf, int len)
Definition comstack.c:471
Header for COMSTACK.
#define CS_ST_ACCEPT
Definition comstack.h:59
#define cs_close(handle)
Definition comstack.h:99
#define CS_ST_CONNECTING
Definition comstack.h:60
#define CS_LISTEN
Definition comstack.h:68
#define CSWRONGBUF
Definition comstack.h:159
#define CS_DATA
Definition comstack.h:69
#define CSDENY
Definition comstack.h:160
#define CSOUTSTATE
Definition comstack.h:157
#define CS_WANT_READ
Definition comstack.h:114
#define CS_NONE
Definition comstack.h:65
#define CSNODATA
Definition comstack.h:158
#define CS_CONNECT
Definition comstack.h:66
#define CS_ST_UNBND
Definition comstack.h:54
struct comstack * COMSTACK
Definition comstack.h:43
#define CSBUFSIZE
Definition comstack.h:162
#define CS_FLAGS_DNS_NO_BLOCK
Definition comstack.h:167
#define CSERRORSSL
Definition comstack.h:161
#define CS_WANT_WRITE
Definition comstack.h:115
#define CS_SERVER
Definition comstack.h:78
#define CS_FLAGS_BLOCKING
Definition comstack.h:165
#define CS_FLAGS_NUMERICHOST
Definition comstack.h:166
#define CS_ST_DATAXFER
Definition comstack.h:58
#define CS_ST_INCON
Definition comstack.h:56
#define CS_ST_IDLE
Definition comstack.h:55
#define CSYSERR
Definition comstack.h:156
int yaz_errno(void)
returns errno
Definition errno.c:31
void yaz_set_errno(int v)
sets errno to value
Definition errno.c:36
Header for errno utilities.
void yaz_init_globals(void)
enum l_file_type type
Definition log.c:47
void yaz_log(int level, const char *fmt,...)
Writes log message.
Definition log.c:487
int yaz_log_module_level(const char *name)
returns level for module
Definition log.c:586
Logging utility.
#define YLOG_WARN
log level: warning
Definition log.h:46
oid_proto
Definition oid_util.h:45
@ PROTO_HTTP
Definition oid_util.h:48
int(* f_bind)(COMSTACK handle, void *address, int mode)
Definition comstack.h:76
int flags
Definition comstack.h:62
COMSTACK(* f_accept)(COMSTACK handle)
Definition comstack.h:82
void(* f_close)(COMSTACK handle)
Definition comstack.h:83
unsigned io_pending
Definition comstack.h:63
void *(* f_straddr)(COMSTACK handle, const char *str)
Definition comstack.h:85
void * user
Definition comstack.h:87
int(* f_listen)(COMSTACK h, char *raddr, int *addrlen, int(*check_ip)(void *cd, const char *a, int len, int type), void *cd)
Definition comstack.h:79
int(* f_put)(COMSTACK handle, char *buf, int size)
Definition comstack.h:71
CS_TYPE type
Definition comstack.h:48
int(* f_more)(COMSTACK handle)
Definition comstack.h:73
int state
Definition comstack.h:53
int event
Definition comstack.h:64
int newfd
Definition comstack.h:61
int(* f_set_blocking)(COMSTACK handle, int blocking)
Definition comstack.h:86
int iofile
Definition comstack.h:50
int(* f_rcvconnect)(COMSTACK handle)
Definition comstack.h:75
int cerrno
Definition comstack.h:49
int(* f_connect)(COMSTACK handle, void *address)
Definition comstack.h:74
int(* f_get)(COMSTACK handle, char **buf, int *bufsize)
Definition comstack.h:72
enum oid_proto protocol
Definition comstack.h:70
void * cprivate
Definition comstack.h:51
int max_recv_bytes
Definition comstack.h:52
const char *(* f_addrstr)(COMSTACK handle)
Definition comstack.h:84
struct addrinfo * ai_connect
Definition tcpip.c:124
int written
Definition tcpip.c:118
char * connect_response_buf
Definition tcpip.c:140
int connect_response_len
Definition tcpip.c:141
int(* complete)(const char *buf, int len)
Definition tcpip.c:120
int ipv6_only
Definition tcpip.c:125
char buf[128]
Definition tcpip.c:131
char * host_port
Definition tcpip.c:122
char * bind_host
Definition tcpip.c:121
char * altbuf
Definition tcpip.c:114
char * connect_request_buf
Definition tcpip.c:138
int altlen
Definition tcpip.c:116
int towrite
Definition tcpip.c:119
int altsize
Definition tcpip.c:115
struct addrinfo * ai
Definition tcpip.c:123
int connect_request_len
Definition tcpip.c:139
int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
Definition tcpip.c:1552
void cs_print_session_info(COMSTACK cs)
Definition tcpip.c:1492
static struct addrinfo * create_net_socket(COMSTACK h)
Definition tcpip.c:467
int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
Definition tcpip.c:1566
static void connect_and_bind(COMSTACK p, const char *connect_host, const char *connect_auth, const char *bind_host)
Definition tcpip.c:248
struct addrinfo * tcpip_getaddrinfo(const char *str, const char *port, int *ipv6_only)
Definition tcpip.c:415
COMSTACK yaz_ssl_create(int s, int flags, int protocol, const char *connect_host, const char *connect_auth, const char *bind_host)
Definition tcpip.c:345
static void * tcpip_straddr(COMSTACK h, const char *str)
Definition tcpip.c:577
COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
Definition tcpip.c:207
int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
Definition tcpip.c:1540
COMSTACK yaz_tcpip_create2(int s, int flags, int protocol, const char *connect_host, const char *bind_host)
Definition tcpip.c:300
static const char * tcpip_addrstr(COMSTACK h)
Definition tcpip.c:1359
COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
Definition tcpip.c:324
static int tcpip_more(COMSTACK h)
Definition tcpip.c:617
static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, int(*check_ip)(void *cd, const char *a, int len, int type), void *cd)
static int tcpip_get(COMSTACK h, char **buf, int *bufsize)
Definition tcpip.c:1064
#define CS_TCPIP_BUFCHUNK
Definition tcpip.c:1058
static int log_level
Definition tcpip.c:144
static int cont_connect(COMSTACK h)
Definition tcpip.c:624
COMSTACK yaz_tcpip_create(int s, int flags, int protocol, const char *connect_host)
Definition tcpip.c:307
COMSTACK yaz_tcpip_create3(int s, int flags, int protocol, const char *connect_host, const char *connect_auth, const char *bind_host)
Definition tcpip.c:288
int cs_set_head_only(COMSTACK cs, int head_only)
Definition tcpip.c:1605
static void parse_host_port(const char *host_port, char *tmp, size_t tmp_sz, const char **host, const char **port)
Definition tcpip.c:376
static int tcpip_put(COMSTACK h, char *buf, int size)
Definition tcpip.c:1215
static struct tcpip_state * tcpip_state_create(void)
Definition tcpip.c:173
static void tcpip_close(COMSTACK h)
Definition tcpip.c:1299
static int tcpip_init(void)
Definition tcpip.c:146
void * cs_get_ssl(COMSTACK cs)
Definition tcpip.c:1534
static COMSTACK tcpip_accept(COMSTACK h)
Definition tcpip.c:950
static int tcpip_connect(COMSTACK h, void *address)
Definition tcpip.c:664
static int tcpip_bind(COMSTACK h, void *address, int mode)
Definition tcpip.c:813
static int tcpip_set_blocking(COMSTACK p, int blocking)
Definition tcpip.c:1398
static int tcpip_rcvconnect(COMSTACK h)
Definition tcpip.c:728
#define YAZ_SOCKLEN_T
Definition tcpip.c:101
Header for TCP/IP + SSL COMSTACK.
yaz_thread_t yaz_thread_create(void *(*start_routine)(void *p), void *arg)
create thread
void yaz_thread_join(yaz_thread_t *tp, void **value_ptr)
join thread
Implements thread creation wrappers.
#define xstrdup(s)
utility macro which calls xstrdup_f
Definition xmalloc.h:55
#define xfree(x)
utility macro which calls xfree_f
Definition xmalloc.h:53
#define xrealloc(o, x)
utility macro which calls xrealloc_f
Definition xmalloc.h:47
#define xmalloc(x)
utility macro which calls malloc_f
Definition xmalloc.h:49
Header with fundamental macros.
static int log_level_set
Definition ztest.c:41