YAZ 5.37.3
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_again(COMSTACK h, tcpip_state *sp, int res)
360{
361 yaz_log(log_level, "ssl_check_again 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 while (sp->session)
799 {
800 int res = gnutls_handshake(sp->session);
801 if (res == GNUTLS_E_SUCCESS)
802 break;
803 if (ssl_check_again(h, sp, res))
804 {
805 if (!(h->flags & CS_FLAGS_BLOCKING))
806 return 1;
807 }
808 else
809 {
810 return cont_connect(h);
811 }
812 }
813#endif
814 h->event = CS_DATA;
816 return 0;
817}
818
819static int tcpip_bind(COMSTACK h, void *address, int mode)
820{
821 int r;
822 tcpip_state *sp = (tcpip_state *)h->cprivate;
823 struct addrinfo *ai = (struct addrinfo *) address;
824#ifdef WIN32
825 BOOL one = 1;
826#else
827 int one = 1;
828#endif
829
830 yaz_log(log_level, "tcpip_bind h=%p", h);
831#if RESOLVER_THREAD
832 if (sp->pipefd[0] != -1)
833 {
834 ai = wait_resolver_thread(h);
835 if (!ai)
836 return -1;
837 }
838#endif
839#if HAVE_GNUTLS_H
840 if (h->type == ssl_type && !sp->session)
841 {
842 int res;
843 tcpip_create_cred(h);
844 res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
845 sp->cert_fname,
846 sp->cert_fname,
847 GNUTLS_X509_FMT_PEM);
848 if (res != GNUTLS_E_SUCCESS)
849 {
850 yaz_log(log_level, "gnutls_certificate_set_x509_key_file r=%d fatal=%d msg=%s",
851 res,
852 gnutls_error_is_fatal(res),
853 gnutls_strerror(res));
854 h->cerrno = CSERRORSSL;
855 return -1;
856 }
857 }
858#endif
859#ifndef WIN32
860 if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
861 &one, sizeof(one)) < 0)
862 {
863 h->cerrno = CSYSERR;
864 return -1;
865 }
866#endif
867 r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
868 freeaddrinfo(sp->ai);
869 sp->ai = 0;
870 if (r)
871 {
872 h->cerrno = CSYSERR;
873 return -1;
874 }
875 /* Allow a maximum-sized backlog of waiting-to-connect clients */
876 if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
877 {
878 h->cerrno = CSYSERR;
879 return -1;
880 }
881 h->state = CS_ST_IDLE;
882 h->event = CS_LISTEN;
883 return 0;
884}
885
886int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
887 int (*check_ip)(void *cd, const char *a, int len, int t),
888 void *cd)
889{
890#ifdef WIN32
891 /* we don't get peer address on Windows (via accept) */
892#else
893 struct sockaddr_in addr;
894 YAZ_SOCKLEN_T len = sizeof(addr);
895#endif
896
897 yaz_log(log_level, "tcpip_listen h=%p", h);
898 if (h->state != CS_ST_IDLE)
899 {
900 h->cerrno = CSOUTSTATE;
901 return -1;
902 }
903#ifdef WIN32
904 h->newfd = accept(h->iofile, 0, 0);
905#else
906 h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
907#endif
908 if (h->newfd < 0)
909 {
910 if (
911#ifdef WIN32
912 WSAGetLastError() == WSAEWOULDBLOCK
913#else
914 yaz_errno() == EWOULDBLOCK
915#ifdef EAGAIN
916#if EAGAIN != EWOULDBLOCK
917 || yaz_errno() == EAGAIN
918#endif
919#endif
920#endif
921 )
922 h->cerrno = CSNODATA;
923 else
924 {
925 shutdown(h->iofile, 0); /* SHUT_RD/SHUT_RECEIVE */
926 listen(h->iofile, SOMAXCONN);
927 h->cerrno = CSYSERR;
928 }
929 return -1;
930 }
931#ifdef WIN32
932 if (addrlen)
933 *addrlen = 0;
934#else
935 if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
936 memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
937 else if (addrlen)
938 *addrlen = 0;
939 if (check_ip && (*check_ip)(cd, (const char *) &addr,
940 sizeof(addr), AF_INET))
941 {
942 h->cerrno = CSDENY;
943#ifdef WIN32
944 closesocket(h->newfd);
945#else
946 close(h->newfd);
947#endif
948 h->newfd = -1;
949 return -1;
950 }
951#endif
952 h->state = CS_ST_INCON;
953 return 0;
954}
955
957{
958 COMSTACK cnew;
959#ifdef WIN32
960 unsigned long tru = 1;
961#endif
962
963 yaz_log(log_level, "tcpip_accept h=%p", h);
964 if (h->state == CS_ST_INCON)
965 {
966#if HAVE_GNUTLS_H
967 tcpip_state *st = (tcpip_state *)h->cprivate;
968#endif
970 cnew = (COMSTACK) xmalloc(sizeof(*cnew));
971
972 memcpy(cnew, h, sizeof(*h));
973 cnew->iofile = h->newfd;
974 cnew->io_pending = 0;
975 cnew->cprivate = state;
976
977 if (!tcpip_set_blocking(cnew, cnew->flags))
978 {
979 h->cerrno = CSYSERR;
980 if (h->newfd != -1)
981 {
982#ifdef WIN32
983 closesocket(h->newfd);
984#else
985 close(h->newfd);
986#endif
987 h->newfd = -1;
988 }
989 xfree(state);
990 xfree(cnew);
991 return 0;
992 }
993 h->newfd = -1;
994 cnew->state = CS_ST_ACCEPT;
995 h->state = CS_ST_IDLE;
996
997#if HAVE_GNUTLS_H
998 state->cred_ptr = st->cred_ptr;
999 if (st->cred_ptr)
1000 {
1001 int res;
1002
1003 (state->cred_ptr->ref)++;
1004 gnutls_init(&state->session, GNUTLS_SERVER);
1005 if (!state->session)
1006 {
1007 xfree(cnew);
1008 xfree(state);
1009 return 0;
1010 }
1011 res = gnutls_set_default_priority(state->session);
1012 if (res != GNUTLS_E_SUCCESS)
1013 {
1014 xfree(cnew);
1015 xfree(state);
1016 return 0;
1017 }
1018 res = gnutls_credentials_set(state->session,
1019 GNUTLS_CRD_CERTIFICATE,
1020 st->cred_ptr->xcred);
1021 if (res != GNUTLS_E_SUCCESS)
1022 {
1023 xfree(cnew);
1024 xfree(state);
1025 return 0;
1026 }
1027 SET_GNUTLS_SOCKET(state->session, cnew->iofile);
1028 }
1029#endif
1030 h = cnew;
1031 }
1032 if (h->state == CS_ST_ACCEPT)
1033 {
1034#if HAVE_GNUTLS_H
1035 tcpip_state *state = (tcpip_state *)h->cprivate;
1036 if (state->session)
1037 {
1038 int res = gnutls_handshake(state->session);
1039 if (res != GNUTLS_E_SUCCESS)
1040 {
1041 if (ssl_check_again(h, state, res))
1042 {
1043 yaz_log(log_level, "tcpip_accept gnutls_handshake interrupted");
1044 return h;
1045 }
1046 yaz_log(log_level, "tcpip_accept gnutls_handshake failed");
1047 cs_close(h);
1048 return 0;
1049 }
1050 }
1051#endif
1052 }
1053 else
1054 {
1055 h->cerrno = CSOUTSTATE;
1056 return 0;
1057 }
1058 h->io_pending = 0;
1059 h->state = CS_ST_DATAXFER;
1060 h->event = CS_DATA;
1061 return h;
1062}
1063
1064#define CS_TCPIP_BUFCHUNK 4096
1065
1066/*
1067 * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1068 * 0=connection closed.
1069 */
1070int tcpip_get(COMSTACK h, char **buf, int *bufsize)
1071{
1072 tcpip_state *sp = (tcpip_state *)h->cprivate;
1073 char *tmpc;
1074 int tmpi, berlen, rest, req, tomove;
1075 int hasread = 0, res;
1076
1077 yaz_log(log_level, "tcpip_get h=%p bufsize=%d", h, *bufsize);
1078 if (sp->altlen) /* switch buffers */
1079 {
1080 yaz_log(log_level, " %d bytes in altbuf (%p)", sp->altlen, sp->altbuf);
1081 tmpc = *buf;
1082 tmpi = *bufsize;
1083 *buf = sp->altbuf;
1084 *bufsize = sp->altsize;
1085 hasread = sp->altlen;
1086 sp->altlen = 0;
1087 sp->altbuf = tmpc;
1088 sp->altsize = tmpi;
1089 }
1090 h->io_pending = 0;
1091 while (!(berlen = (*sp->complete)(*buf, hasread)))
1092 {
1093 if (!*bufsize)
1094 {
1095 if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1096 {
1097 h->cerrno = CSYSERR;
1098 return -1;
1099 }
1100 }
1101 else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1102 if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1103 {
1104 h->cerrno = CSYSERR;
1105 return -1;
1106 }
1107#if HAVE_GNUTLS_H
1108 if (sp->session)
1109 {
1110 res = gnutls_record_recv(sp->session, *buf + hasread,
1112 if (res == 0)
1113 {
1114 yaz_log(log_level, "gnutls_record_recv returned 0");
1115 return 0;
1116 }
1117 else if (res < 0)
1118 {
1119 if (ssl_check_again(h, sp, res))
1120 {
1121 if (h->flags & CS_FLAGS_BLOCKING)
1122 continue;
1123 break;
1124 }
1125 return -1;
1126 }
1127 }
1128 else
1129#endif
1130 {
1131#ifdef __sun__
1132 yaz_set_errno( 0 );
1133 /* unfortunatly, sun sometimes forgets to set errno in recv
1134 when EWOULDBLOCK etc. would be required (res = -1) */
1135#endif
1136 res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
1137 yaz_log(log_level, " recv res=%d, hasread=%d", res, hasread);
1138 if (res < 0)
1139 {
1140 yaz_log(log_level, " recv errno=%d, (%s)", yaz_errno(),
1141 strerror(yaz_errno()));
1142#ifdef WIN32
1143 if (WSAGetLastError() == WSAEWOULDBLOCK)
1144 {
1146 break;
1147 }
1148 else
1149 {
1150 h->cerrno = CSYSERR;
1151 return -1;
1152 }
1153#else
1154 if (yaz_errno() == EWOULDBLOCK
1155#ifdef EAGAIN
1156#if EAGAIN != EWOULDBLOCK
1157 || yaz_errno() == EAGAIN
1158#endif
1159#endif
1160 || yaz_errno() == EINPROGRESS
1161#ifdef __sun__
1162 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
1163#endif
1164 )
1165 {
1167 break;
1168 }
1169 else if (yaz_errno() == 0)
1170 continue;
1171 else
1172 {
1173 h->cerrno = CSYSERR;
1174 return -1;
1175 }
1176#endif
1177 }
1178 else if (!res)
1179 return hasread;
1180 }
1181 hasread += res;
1182 if (hasread > h->max_recv_bytes)
1183 {
1184 h->cerrno = CSBUFSIZE;
1185 return -1;
1186 }
1187 }
1188 yaz_log(log_level, " Out of read loop with hasread=%d, berlen=%d",
1189 hasread, berlen);
1190 /* move surplus buffer (or everything if we didn't get a BER rec.) */
1191 if (hasread > berlen)
1192 {
1193 tomove = req = hasread - berlen;
1194 rest = tomove % CS_TCPIP_BUFCHUNK;
1195 if (rest)
1196 req += CS_TCPIP_BUFCHUNK - rest;
1197 if (!sp->altbuf)
1198 {
1199 if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1200 {
1201 h->cerrno = CSYSERR;
1202 return -1;
1203 }
1204 } else if (sp->altsize < req)
1205 if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1206 {
1207 h->cerrno = CSYSERR;
1208 return -1;
1209 }
1210 yaz_log(log_level, " Moving %d bytes to altbuf(%p)", tomove,
1211 sp->altbuf);
1212 memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1213 }
1214 if (berlen < CS_TCPIP_BUFCHUNK - 1)
1215 *(*buf + berlen) = '\0';
1216 return berlen ? berlen : 1;
1217}
1218
1219
1220/*
1221 * Returns 1, 0 or -1
1222 * In nonblocking mode, you must call again with same buffer while
1223 * return value is 1.
1224 */
1225int tcpip_put(COMSTACK h, char *buf, int size)
1226{
1227 int res;
1228 struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1229
1230 yaz_log(log_level, "tcpip_put h=%p size=%d", h, size);
1231 h->io_pending = 0;
1232 h->event = CS_DATA;
1233 if (state->towrite < 0)
1234 {
1235 state->towrite = size;
1236 state->written = 0;
1237 }
1238 else if (state->towrite != size)
1239 {
1240 h->cerrno = CSWRONGBUF;
1241 return -1;
1242 }
1243 while (state->towrite > state->written)
1244 {
1245#if HAVE_GNUTLS_H
1246 if (state->session)
1247 {
1248 res = gnutls_record_send(state->session, buf + state->written,
1249 size - state->written);
1250 if (res < 0)
1251 {
1252 if (ssl_check_again(h, state, res))
1253 {
1254 if (h->flags & CS_FLAGS_BLOCKING)
1255 continue;
1256 return 1;
1257 }
1258 return -1;
1259 }
1260 }
1261 else
1262#endif
1263 {
1264 if ((res =
1265 send(h->iofile, buf + state->written, size -
1266 state->written,
1267#ifdef MSG_NOSIGNAL
1268 MSG_NOSIGNAL
1269#else
1270 0
1271#endif
1272 )) < 0)
1273 {
1274 if (
1275#ifdef WIN32
1276 WSAGetLastError() == WSAEWOULDBLOCK
1277#else
1278 yaz_errno() == EWOULDBLOCK
1279#ifdef EAGAIN
1280#if EAGAIN != EWOULDBLOCK
1281 || yaz_errno() == EAGAIN
1282#endif
1283#endif
1284#ifdef __sun__
1285 || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1286#endif
1287 || yaz_errno() == EINPROGRESS
1288#endif
1289 )
1290 {
1291 yaz_log(log_level, " Flow control stop");
1293 return 1;
1294 }
1295 if (h->flags & CS_FLAGS_BLOCKING)
1296 {
1297 h->cerrno = CSYSERR;
1298 return -1;
1299 }
1300 else
1301 return cont_connect(h);
1302 }
1303 }
1304 state->written += res;
1305 yaz_log(log_level, " Wrote %d, written=%d, nbytes=%d",
1306 res, state->written, size);
1307 }
1308 state->towrite = state->written = -1;
1309 yaz_log(log_level, " Ok");
1310 return 0;
1311}
1312
1314{
1315 tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1316
1317 yaz_log(log_level, "tcpip_close: h=%p", h);
1318 xfree(sp->bind_host);
1319#if RESOLVER_THREAD
1320 if (sp->pipefd[0] != -1)
1321 {
1322 yaz_thread_join(&sp->thread_id, 0);
1323 close(sp->pipefd[0]);
1324 close(sp->pipefd[1]);
1325 h->iofile = -1;
1326 }
1327#endif
1328 if (h->iofile != -1)
1329 {
1330#if HAVE_GNUTLS_H
1331 if (sp->session && sp->use_bye)
1332 {
1333 yaz_log(log_level, "tcpip_close: gnutls_bye");
1334 gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1335 }
1336#endif
1337#ifdef WIN32
1338 closesocket(h->iofile);
1339#else
1340 close(h->iofile);
1341#endif
1342 }
1343 if (sp->altbuf)
1344 xfree(sp->altbuf);
1345#if HAVE_GNUTLS_H
1346 if (sp->session)
1347 {
1348 gnutls_deinit(sp->session);
1349 }
1350 if (sp->cred_ptr)
1351 {
1352 assert(sp->cred_ptr->ref > 0);
1353
1354 if (--(sp->cred_ptr->ref) == 0)
1355 {
1356 yaz_log(log_level, "tcpip_close: removed credentials h=%p",
1357 sp->cred_ptr->xcred);
1358 gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1359 xfree(sp->cred_ptr);
1360 }
1361 sp->cred_ptr = 0;
1362 }
1363#endif
1364 if (sp->ai)
1365 freeaddrinfo(sp->ai);
1366 xfree(sp->host_port);
1369 xfree(sp);
1370 xfree(h);
1371}
1372
1374{
1375 tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1376 char *r = 0;
1377
1378 char host[120];
1379 struct sockaddr_storage addr;
1380 YAZ_SOCKLEN_T len = sizeof(addr);
1381
1382 if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1383 {
1384 h->cerrno = CSYSERR;
1385 return 0;
1386 }
1387 if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
1388 0, 0,
1389 (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1390 {
1391 r = "unknown";
1392 }
1393 else
1394 r = host;
1395
1396 if (h->protocol == PROTO_HTTP)
1397 yaz_snprintf(sp->buf, sizeof(sp->buf), "http:%s", r);
1398 else
1399 yaz_snprintf(sp->buf, sizeof(sp->buf), "tcp:%s", r);
1400#if HAVE_GNUTLS_H
1401 if (sp->session)
1402 {
1403 if (h->protocol == PROTO_HTTP)
1404 yaz_snprintf(sp->buf, sizeof(sp->buf), "https:%s", r);
1405 else
1406 yaz_snprintf(sp->buf, sizeof(sp->buf), "ssl:%s", r);
1407 }
1408#endif
1409 return sp->buf;
1410}
1411
1412static int tcpip_set_blocking(COMSTACK p, int flags)
1413{
1414 unsigned long flag;
1415
1416#ifdef WIN32
1417 flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1418 if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1419 return 0;
1420#else
1421 flag = fcntl(p->iofile, F_GETFL, 0);
1422 if (flags & CS_FLAGS_BLOCKING)
1423 flag = flag & ~O_NONBLOCK; /* blocking */
1424 else
1425 {
1426 flag = flag | O_NONBLOCK; /* non-blocking */
1427 signal(SIGPIPE, SIG_IGN);
1428 }
1429 if (fcntl(p->iofile, F_SETFL, flag) < 0)
1430 return 0;
1431#endif
1432 p->flags = flags;
1433 return 1;
1434}
1435
1436
1437#if HAVE_GNUTLS_H
1438/* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
1439 GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
1440#if GNUTLS_VERSION_NUMBER >= 0x020400
1441#define USE_GNUTLS_X509_CRT_PRINT 1
1442#else
1443#define USE_GNUTLS_X509_CRT_PRINT 0
1444#endif
1445
1446
1447#if USE_GNUTLS_X509_CRT_PRINT
1448#else
1449static const char *bin2hex(const void *bin, size_t bin_size)
1450{
1451 static char printable[110];
1452 const unsigned char *_bin = bin;
1453 char *print;
1454 size_t i;
1455 if (bin_size > 50)
1456 bin_size = 50;
1457 print = printable;
1458 for (i = 0; i < bin_size; i++)
1459 {
1460 yaz_snprintf(print, 3, "%.2x", _bin[i]);
1461 print += 2;
1462 }
1463 return printable;
1464}
1465
1466static void x509_crt_print(gnutls_x509_crt_t cert)
1467{
1468 time_t expiration_time, activation_time;
1469 size_t size;
1470 char serial[40];
1471 char dn[256];
1472 unsigned int algo, bits;
1473
1474 expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1475 activation_time = gnutls_x509_crt_get_activation_time(cert);
1476
1477 printf("\tCertificate is valid since: %s", ctime(&activation_time));
1478 printf("\tCertificate expires: %s", ctime(&expiration_time));
1479
1480 /* Print the serial number of the certificate. */
1481 size = sizeof(serial);
1482 gnutls_x509_crt_get_serial(cert, serial, &size);
1483
1484 printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
1485
1486 /* Extract some of the public key algorithm's parameters
1487 */
1488 algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1489
1490 printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1491
1492 /* Print the version of the X.509 certificate. */
1493 printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1494
1495 size = sizeof(dn);
1496 gnutls_x509_crt_get_dn(cert, dn, &size);
1497 printf("\tDN: %s\n", dn);
1498
1499 size = sizeof(dn);
1500 gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1501 printf("\tIssuer's DN: %s\n", dn);
1502}
1503#endif
1504#endif
1505
1507{
1508#if HAVE_GNUTLS_H
1509 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1510 if (cs->type == ssl_type && sp->session)
1511 {
1512 const gnutls_datum_t *cert_list;
1513 unsigned i, cert_list_size;
1514 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1515 return;
1516 printf("X509 certificate\n");
1517 cert_list = gnutls_certificate_get_peers(sp->session,
1518 &cert_list_size);
1519 printf("Peer provided %u certificates\n", cert_list_size);
1520 for (i = 0; i < cert_list_size; i++)
1521 {
1522 gnutls_x509_crt_t cert;
1523#if USE_GNUTLS_X509_CRT_PRINT
1524 int ret;
1525 gnutls_datum_t cinfo;
1526#endif
1527 gnutls_x509_crt_init(&cert);
1528 gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1529 printf("Certificate info %u:\n", i + 1);
1530#if USE_GNUTLS_X509_CRT_PRINT
1531 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1532 &cinfo);
1533 if (ret == 0)
1534 {
1535 printf("\t%s\n", cinfo.data);
1536 gnutls_free(cinfo.data);
1537 }
1538#else
1539 x509_crt_print(cert);
1540#endif
1541 gnutls_x509_crt_deinit(cert);
1542
1543 }
1544 }
1545#endif
1546}
1547
1549{
1550 /* doesn't do anything for GNUTLS */
1551 return 0;
1552}
1553
1554int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1555{
1556#if HAVE_GNUTLS_H
1557 if (cs && cs->type == ssl_type)
1558 {
1559 /* doesn't do anything for GNUTLS */
1560 return 1;
1561 }
1562#endif
1563 return 0;
1564}
1565
1566int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1567{
1568#if HAVE_GNUTLS_H
1569 if (cs && cs->type == ssl_type)
1570 {
1571 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1572 strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1573 sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1574 return 1;
1575 }
1576#endif
1577 return 0;
1578}
1579
1581{
1582
1583#if HAVE_GNUTLS_H
1584#if USE_GNUTLS_X509_CRT_PRINT
1585 struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1586 if (cs->type == ssl_type && sp->session)
1587 {
1588 const gnutls_datum_t *cert_list;
1589 unsigned cert_list_size;
1590 if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1591 return 0;
1592 cert_list = gnutls_certificate_get_peers(sp->session, &cert_list_size);
1593 if (cert_list_size > 0)
1594 {
1595 gnutls_x509_crt_t cert;
1596 int ret;
1597 gnutls_datum_t cinfo;
1598
1599 gnutls_x509_crt_init(&cert);
1600 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1601
1602 ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &cinfo);
1603 if (ret == 0)
1604 {
1605 *buf = xstrdup((char *) cinfo.data);
1606 *len = strlen(*buf);
1607 gnutls_free(cinfo.data);
1608 gnutls_x509_crt_deinit(cert);
1609 return 1;
1610 }
1611 gnutls_x509_crt_deinit(cert);
1612 }
1613 }
1614#endif
1615#endif
1616 return 0;
1617}
1618
1619int cs_set_head_only(COMSTACK cs, int head_only)
1620{
1621 if (cs->type == tcpip_type || cs->type == ssl_type)
1622 {
1623 tcpip_state *sp = (tcpip_state *)cs->cprivate;
1624 if (head_only)
1626 else
1628 return 0;
1629 }
1630 cs->cerrno = CS_ST_INCON;
1631 return -1;
1632}
1633
1634/*
1635 * Local variables:
1636 * c-basic-offset: 4
1637 * c-file-style: "Stroustrup"
1638 * indent-tabs-mode: nil
1639 * End:
1640 * vim: shiftwidth=4 tabstop=8 expandtab
1641 */
1642
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:1566
void cs_print_session_info(COMSTACK cs)
Definition tcpip.c:1506
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:1580
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:1554
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:886
static const char * tcpip_addrstr(COMSTACK h)
Definition tcpip.c:1373
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:1070
#define CS_TCPIP_BUFCHUNK
Definition tcpip.c:1064
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:1619
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:1225
static struct tcpip_state * tcpip_state_create(void)
Definition tcpip.c:174
static void tcpip_close(COMSTACK h)
Definition tcpip.c:1313
static int tcpip_init(void)
Definition tcpip.c:147
void * cs_get_ssl(COMSTACK cs)
Definition tcpip.c:1548
static COMSTACK tcpip_accept(COMSTACK h)
Definition tcpip.c:956
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:819
static int tcpip_set_blocking(COMSTACK p, int blocking)
Definition tcpip.c:1412
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