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