YAZ  5.34.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 
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 
81 static void tcpip_close(COMSTACK h);
82 static int tcpip_put(COMSTACK h, char *buf, int size);
83 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
84 static int tcpip_connect(COMSTACK h, void *address);
85 static int tcpip_more(COMSTACK h);
86 static int tcpip_rcvconnect(COMSTACK h);
87 static int tcpip_bind(COMSTACK h, void *address, int mode);
88 static 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);
91 static int tcpip_set_blocking(COMSTACK p, int blocking);
92 
93 struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port,
94  int *ipv6_only);
95 
97 static const char *tcpip_addrstr(COMSTACK h);
98 static 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
105 struct 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 */
112 typedef 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. */
121  char *bind_host;
122  char *host_port;
123  struct addrinfo *ai;
124  struct addrinfo *ai_connect;
126 #if RESOLVER_THREAD
127  int pipefd[2];
128  const char *port;
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 
144 static int log_level = 0;
145 
146 static 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 
173 static 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  */
207 COMSTACK 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;
231  p->f_listen = tcpip_listen;
232  p->f_accept = tcpip_accept;
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");
284  sp->connect_request_len = strlen(sp->connect_request_buf);
285  }
286 }
287 
288 COMSTACK 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 
300 COMSTACK 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 
307 COMSTACK 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
314 static 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 
324 COMSTACK 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 
345 COMSTACK 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
358 static 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 
376 static 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 
415 struct 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 
467 static 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 
545 void *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  write(sp->pipefd[1], "1", 1);
555  return 0;
556 }
557 
558 static struct addrinfo *wait_resolver_thread(COMSTACK h)
559 {
560  tcpip_state *sp = (tcpip_state *)h->cprivate;
561  char buf;
562 
563  read(sp->pipefd[0], &buf, 1);
564  yaz_thread_join(&sp->thread_id, 0);
565  close(sp->pipefd[0]);
566  close(sp->pipefd[1]);
567  sp->pipefd[0] = -1;
568  h->iofile = -1;
569  return create_net_socket(h);
570 }
571 
572 #endif
573 
574 void *tcpip_straddr(COMSTACK h, const char *str)
575 {
576  tcpip_state *sp = (tcpip_state *)h->cprivate;
577  const char *port = "210";
578 
579  if (!tcpip_init())
580  return 0;
581 
582  if (h->protocol == PROTO_HTTP)
583  {
584  if (h->type == ssl_type)
585  port = "443";
586  else
587  port = "80";
588  }
589  xfree(sp->host_port);
590  sp->host_port = xstrdup(str);
591 #if RESOLVER_THREAD
592  if (h->flags & CS_FLAGS_DNS_NO_BLOCK)
593  {
594  if (sp->pipefd[0] != -1)
595  return 0;
596  if (pipe(sp->pipefd) == -1)
597  return 0;
598 
599  sp->port = port;
601  return sp->host_port;
602  }
603 #endif
604  if (sp->ai)
605  freeaddrinfo(sp->ai);
606  sp->ai = tcpip_getaddrinfo(sp->host_port, port, &sp->ipv6_only);
607  if (sp->ai && h->state == CS_ST_UNBND)
608  {
609  return create_net_socket(h);
610  }
611  return sp->ai;
612 }
613 
615 {
616  tcpip_state *sp = (tcpip_state *)h->cprivate;
617 
618  return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen);
619 }
620 
621 static int cont_connect(COMSTACK h)
622 {
623  tcpip_state *sp = (tcpip_state *)h->cprivate;
624  struct addrinfo *ai = sp->ai_connect;
625  while (ai && (ai = ai->ai_next))
626  {
627  int s;
628  s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
629  if (s != -1)
630  {
631 #if HAVE_GNUTLS_H
632  if (h->type == ssl_type && sp->session)
633  {
634  gnutls_bye(sp->session, GNUTLS_SHUT_WR);
635  gnutls_deinit(sp->session);
636  sp->session = 0;
637  }
638 #endif
639 #ifdef WIN32
640  closesocket(h->iofile);
641 #else
642  close(h->iofile);
643 #endif
644  yaz_log(log_level, "Other socket call fd=%d", s);
645  h->state = CS_ST_UNBND;
646  h->iofile = s;
647  tcpip_set_blocking(h, h->flags);
648  return tcpip_connect(h, ai);
649  }
650  }
651  h->cerrno = CSYSERR;
652  return -1;
653 }
654 
655 
656 /*
657  * connect(2) will block (sometimes) - nothing we can do short of doing
658  * weird things like spawning subprocesses or threading or some weird junk
659  * like that.
660  */
661 int tcpip_connect(COMSTACK h, void *address)
662 {
663  struct addrinfo *ai = (struct addrinfo *) address;
664  tcpip_state *sp = (tcpip_state *)h->cprivate;
665  int r;
666  yaz_log(log_level, "tcpip_connect h=%p", h);
667  h->io_pending = 0;
668  if (h->state != CS_ST_UNBND)
669  {
670  h->cerrno = CSOUTSTATE;
671  return -1;
672  }
673 #if RESOLVER_THREAD
674  if (sp->pipefd[0] != -1)
675  {
676  if (h->flags & CS_FLAGS_BLOCKING)
677  {
678  ai = wait_resolver_thread(h);
679  if (!ai)
680  return -1;
681  }
682  else
683  {
684  h->event = CS_CONNECT;
685  h->state = CS_ST_CONNECTING;
687  h->iofile = sp->pipefd[0];
688  return 1;
689  }
690  }
691 #endif
692  r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen);
693  sp->ai_connect = ai;
694  if (r < 0)
695  {
696 #ifdef WIN32
697  if (WSAGetLastError() == WSAEWOULDBLOCK)
698  {
699  h->event = CS_CONNECT;
700  h->state = CS_ST_CONNECTING;
702  return 1;
703  }
704 #else
705  if (yaz_errno() == EINPROGRESS)
706  {
707  yaz_log(log_level, "Pending fd=%d", h->iofile);
708  h->event = CS_CONNECT;
709  h->state = CS_ST_CONNECTING;
711  return 1;
712  }
713 #endif
714  return cont_connect(h);
715  }
716  h->event = CS_CONNECT;
717  h->state = CS_ST_CONNECTING;
718 
719  return tcpip_rcvconnect(h);
720 }
721 
722 /*
723  * nop
724  */
726 {
727  tcpip_state *sp = (tcpip_state *)h->cprivate;
728  yaz_log(log_level, "tcpip_rcvconnect h=%p", h);
729 
730  if (h->state == CS_ST_DATAXFER)
731  return 0;
732 #if RESOLVER_THREAD
733  if (sp->pipefd[0] != -1)
734  {
735  struct addrinfo *ai = wait_resolver_thread(h);
736  if (!ai)
737  return -1;
738  h->state = CS_ST_UNBND;
739  return tcpip_connect(h, ai);
740  }
741 #endif
742  if (h->state != CS_ST_CONNECTING)
743  {
744  h->cerrno = CSOUTSTATE;
745  return -1;
746  }
747  if (sp->connect_request_buf)
748  {
749  int r;
750 
752  if (sp->connect_request_len > 0)
753  {
754  r = tcpip_put(h, sp->connect_request_buf,
755  sp->connect_request_len);
756  yaz_log(log_level, "tcpip_rcvconnect connect put r=%d", r);
757  h->event = CS_CONNECT; /* because tcpip_put sets it */
758  if (r) /* < 0 is error, 1 is in-complete */
759  return r;
760  yaz_log(log_level, "tcpip_rcvconnect connect complete");
761  }
762  sp->connect_request_len = 0;
763 
765  yaz_log(log_level, "tcpip_rcvconnect connect get r=%d", r);
766  if (r == 1)
767  return r;
768  if (r <= 0)
769  return -1;
771  sp->connect_request_buf = 0;
773  }
774 #if HAVE_GNUTLS_H
775  if (h->type == ssl_type && !sp->session)
776  {
777  const char *host = 0;
778  const char *port = 0;
779  char tmp[512];
780 
781  tcpip_create_cred(h);
782  gnutls_init(&sp->session, GNUTLS_CLIENT);
783  sp->use_bye = 1; /* only say goodbye in client */
784  gnutls_set_default_priority(sp->session);
785  gnutls_credentials_set (sp->session, GNUTLS_CRD_CERTIFICATE,
786  sp->cred_ptr->xcred);
787  parse_host_port(sp->host_port, tmp, sizeof tmp, &host, &port);
788  /* raw IPV6 seems to be rejected on the server */
789  if (!strchr(host, ':'))
790  gnutls_server_name_set(sp->session, GNUTLS_NAME_DNS,
791  host, strlen(host));
792  SET_GNUTLS_SOCKET(sp->session, h->iofile);
793  }
794  if (sp->session)
795  {
796  int res = gnutls_handshake(sp->session);
797  if (res < 0)
798  {
799  if (ssl_check_error(h, sp, res))
800  return 1;
801  return cont_connect(h);
802  }
803  }
804 #endif
805  h->event = CS_DATA;
806  h->state = CS_ST_DATAXFER;
807  return 0;
808 }
809 
810 static int tcpip_bind(COMSTACK h, void *address, int mode)
811 {
812  int r;
813  tcpip_state *sp = (tcpip_state *)h->cprivate;
814  struct addrinfo *ai = (struct addrinfo *) address;
815 #ifdef WIN32
816  BOOL one = 1;
817 #else
818  int one = 1;
819 #endif
820 
821  yaz_log(log_level, "tcpip_bind h=%p", h);
822 #if RESOLVER_THREAD
823  if (sp->pipefd[0] != -1)
824  {
825  ai = wait_resolver_thread(h);
826  if (!ai)
827  return -1;
828  }
829 #endif
830 #if HAVE_GNUTLS_H
831  if (h->type == ssl_type && !sp->session)
832  {
833  int res;
834  tcpip_create_cred(h);
835  res = gnutls_certificate_set_x509_key_file(sp->cred_ptr->xcred,
836  sp->cert_fname,
837  sp->cert_fname,
838  GNUTLS_X509_FMT_PEM);
839  if (res != GNUTLS_E_SUCCESS)
840  {
841  yaz_log(log_level, "gnutls_certificate_set_x509_key_file r=%d fatal=%d msg=%s",
842  res,
843  gnutls_error_is_fatal(res),
844  gnutls_strerror(res));
845  h->cerrno = CSERRORSSL;
846  return -1;
847  }
848  }
849 #endif
850 #ifndef WIN32
851  if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*)
852  &one, sizeof(one)) < 0)
853  {
854  h->cerrno = CSYSERR;
855  return -1;
856  }
857 #endif
858  r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen);
859  freeaddrinfo(sp->ai);
860  sp->ai = 0;
861  if (r)
862  {
863  h->cerrno = CSYSERR;
864  return -1;
865  }
866  /* Allow a maximum-sized backlog of waiting-to-connect clients */
867  if (mode == CS_SERVER && listen(h->iofile, SOMAXCONN) < 0)
868  {
869  h->cerrno = CSYSERR;
870  return -1;
871  }
872  h->state = CS_ST_IDLE;
873  h->event = CS_LISTEN;
874  return 0;
875 }
876 
877 int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
878  int (*check_ip)(void *cd, const char *a, int len, int t),
879  void *cd)
880 {
881 #ifdef WIN32
882  /* we don't get peer address on Windows (via accept) */
883 #else
884  struct sockaddr_in addr;
885  YAZ_SOCKLEN_T len = sizeof(addr);
886 #endif
887 
888  yaz_log(log_level, "tcpip_listen h=%p", h);
889  if (h->state != CS_ST_IDLE)
890  {
891  h->cerrno = CSOUTSTATE;
892  return -1;
893  }
894 #ifdef WIN32
895  h->newfd = accept(h->iofile, 0, 0);
896 #else
897  h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len);
898 #endif
899  if (h->newfd < 0)
900  {
901  if (
902 #ifdef WIN32
903  WSAGetLastError() == WSAEWOULDBLOCK
904 #else
905  yaz_errno() == EWOULDBLOCK
906 #ifdef EAGAIN
907 #if EAGAIN != EWOULDBLOCK
908  || yaz_errno() == EAGAIN
909 #endif
910 #endif
911 #endif
912  )
913  h->cerrno = CSNODATA;
914  else
915  {
916  shutdown(h->iofile, 0); /* SHUT_RD/SHUT_RECEIVE */
917  listen(h->iofile, SOMAXCONN);
918  h->cerrno = CSYSERR;
919  }
920  return -1;
921  }
922 #ifdef WIN32
923  if (addrlen)
924  *addrlen = 0;
925 #else
926  if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in))
927  memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
928  else if (addrlen)
929  *addrlen = 0;
930  if (check_ip && (*check_ip)(cd, (const char *) &addr,
931  sizeof(addr), AF_INET))
932  {
933  h->cerrno = CSDENY;
934 #ifdef WIN32
935  closesocket(h->newfd);
936 #else
937  close(h->newfd);
938 #endif
939  h->newfd = -1;
940  return -1;
941  }
942 #endif
943  h->state = CS_ST_INCON;
944  return 0;
945 }
946 
948 {
949  COMSTACK cnew;
950 #ifdef WIN32
951  unsigned long tru = 1;
952 #endif
953 
954  yaz_log(log_level, "tcpip_accept h=%p", h);
955  if (h->state == CS_ST_INCON)
956  {
957 #if HAVE_GNUTLS_H
958  tcpip_state *st = (tcpip_state *)h->cprivate;
959 #endif
960  tcpip_state *state = tcpip_state_create();
961  cnew = (COMSTACK) xmalloc(sizeof(*cnew));
962 
963  memcpy(cnew, h, sizeof(*h));
964  cnew->iofile = h->newfd;
965  cnew->io_pending = 0;
966  cnew->cprivate = state;
967 
968  if (!tcpip_set_blocking(cnew, cnew->flags))
969  {
970  h->cerrno = CSYSERR;
971  if (h->newfd != -1)
972  {
973 #ifdef WIN32
974  closesocket(h->newfd);
975 #else
976  close(h->newfd);
977 #endif
978  h->newfd = -1;
979  }
980  xfree(state);
981  xfree(cnew);
982  return 0;
983  }
984  h->newfd = -1;
985  cnew->state = CS_ST_ACCEPT;
986  h->state = CS_ST_IDLE;
987 
988 #if HAVE_GNUTLS_H
989  state->cred_ptr = st->cred_ptr;
990  if (st->cred_ptr)
991  {
992  int res;
993 
994  (state->cred_ptr->ref)++;
995  gnutls_init(&state->session, GNUTLS_SERVER);
996  if (!state->session)
997  {
998  xfree(cnew);
999  xfree(state);
1000  return 0;
1001  }
1002  res = gnutls_set_default_priority(state->session);
1003  if (res != GNUTLS_E_SUCCESS)
1004  {
1005  xfree(cnew);
1006  xfree(state);
1007  return 0;
1008  }
1009  res = gnutls_credentials_set(state->session,
1010  GNUTLS_CRD_CERTIFICATE,
1011  st->cred_ptr->xcred);
1012  if (res != GNUTLS_E_SUCCESS)
1013  {
1014  xfree(cnew);
1015  xfree(state);
1016  return 0;
1017  }
1018  SET_GNUTLS_SOCKET(state->session, cnew->iofile);
1019  }
1020 #endif
1021  h = cnew;
1022  }
1023  if (h->state == CS_ST_ACCEPT)
1024  {
1025 #if HAVE_GNUTLS_H
1026  tcpip_state *state = (tcpip_state *)h->cprivate;
1027  if (state->session)
1028  {
1029  int res = gnutls_handshake(state->session);
1030  if (res < 0)
1031  {
1032  if (ssl_check_error(h, state, res))
1033  {
1034  yaz_log(log_level, "tcpip_accept gnutls_handshake interrupted");
1035  return h;
1036  }
1037  yaz_log(log_level, "tcpip_accept gnutls_handshake failed");
1038  cs_close(h);
1039  return 0;
1040  }
1041  }
1042 #endif
1043  }
1044  else
1045  {
1046  h->cerrno = CSOUTSTATE;
1047  return 0;
1048  }
1049  h->io_pending = 0;
1050  h->state = CS_ST_DATAXFER;
1051  h->event = CS_DATA;
1052  return h;
1053 }
1054 
1055 #define CS_TCPIP_BUFCHUNK 4096
1056 
1057 /*
1058  * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
1059  * 0=connection closed.
1060  */
1061 int tcpip_get(COMSTACK h, char **buf, int *bufsize)
1062 {
1063  tcpip_state *sp = (tcpip_state *)h->cprivate;
1064  char *tmpc;
1065  int tmpi, berlen, rest, req, tomove;
1066  int hasread = 0, res;
1067 
1068  yaz_log(log_level, "tcpip_get h=%p bufsize=%d", h, *bufsize);
1069  if (sp->altlen) /* switch buffers */
1070  {
1071  yaz_log(log_level, " %d bytes in altbuf (%p)", sp->altlen, sp->altbuf);
1072  tmpc = *buf;
1073  tmpi = *bufsize;
1074  *buf = sp->altbuf;
1075  *bufsize = sp->altsize;
1076  hasread = sp->altlen;
1077  sp->altlen = 0;
1078  sp->altbuf = tmpc;
1079  sp->altsize = tmpi;
1080  }
1081  h->io_pending = 0;
1082  while (!(berlen = (*sp->complete)(*buf, hasread)))
1083  {
1084  if (!*bufsize)
1085  {
1086  if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK)))
1087  {
1088  h->cerrno = CSYSERR;
1089  return -1;
1090  }
1091  }
1092  else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
1093  if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
1094  {
1095  h->cerrno = CSYSERR;
1096  return -1;
1097  }
1098 #if HAVE_GNUTLS_H
1099  if (sp->session)
1100  {
1101  res = gnutls_record_recv(sp->session, *buf + hasread,
1103  if (res == 0)
1104  {
1105  yaz_log(log_level, "gnutls_record_recv returned 0");
1106  return 0;
1107  }
1108  else if (res < 0)
1109  {
1110  if (ssl_check_error(h, sp, res))
1111  break;
1112  return -1;
1113  }
1114  }
1115  else
1116 #endif
1117  {
1118 #ifdef __sun__
1119  yaz_set_errno( 0 );
1120  /* unfortunatly, sun sometimes forgets to set errno in recv
1121  when EWOULDBLOCK etc. would be required (res = -1) */
1122 #endif
1123  res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0);
1124  yaz_log(log_level, " recv res=%d, hasread=%d", res, hasread);
1125  if (res < 0)
1126  {
1127  yaz_log(log_level, " recv errno=%d, (%s)", yaz_errno(),
1128  strerror(yaz_errno()));
1129 #ifdef WIN32
1130  if (WSAGetLastError() == WSAEWOULDBLOCK)
1131  {
1132  h->io_pending = CS_WANT_READ;
1133  break;
1134  }
1135  else
1136  {
1137  h->cerrno = CSYSERR;
1138  return -1;
1139  }
1140 #else
1141  if (yaz_errno() == EWOULDBLOCK
1142 #ifdef EAGAIN
1143 #if EAGAIN != EWOULDBLOCK
1144  || yaz_errno() == EAGAIN
1145 #endif
1146 #endif
1147  || yaz_errno() == EINPROGRESS
1148 #ifdef __sun__
1149  || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
1150 #endif
1151  )
1152  {
1153  h->io_pending = CS_WANT_READ;
1154  break;
1155  }
1156  else if (yaz_errno() == 0)
1157  continue;
1158  else
1159  {
1160  h->cerrno = CSYSERR;
1161  return -1;
1162  }
1163 #endif
1164  }
1165  else if (!res)
1166  return hasread;
1167  }
1168  hasread += res;
1169  if (hasread > h->max_recv_bytes)
1170  {
1171  h->cerrno = CSBUFSIZE;
1172  return -1;
1173  }
1174  }
1175  yaz_log(log_level, " Out of read loop with hasread=%d, berlen=%d",
1176  hasread, berlen);
1177  /* move surplus buffer (or everything if we didn't get a BER rec.) */
1178  if (hasread > berlen)
1179  {
1180  tomove = req = hasread - berlen;
1181  rest = tomove % CS_TCPIP_BUFCHUNK;
1182  if (rest)
1183  req += CS_TCPIP_BUFCHUNK - rest;
1184  if (!sp->altbuf)
1185  {
1186  if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req)))
1187  {
1188  h->cerrno = CSYSERR;
1189  return -1;
1190  }
1191  } else if (sp->altsize < req)
1192  if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req)))
1193  {
1194  h->cerrno = CSYSERR;
1195  return -1;
1196  }
1197  yaz_log(log_level, " Moving %d bytes to altbuf(%p)", tomove,
1198  sp->altbuf);
1199  memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove);
1200  }
1201  if (berlen < CS_TCPIP_BUFCHUNK - 1)
1202  *(*buf + berlen) = '\0';
1203  return berlen ? berlen : 1;
1204 }
1205 
1206 
1207 /*
1208  * Returns 1, 0 or -1
1209  * In nonblocking mode, you must call again with same buffer while
1210  * return value is 1.
1211  */
1212 int tcpip_put(COMSTACK h, char *buf, int size)
1213 {
1214  int res;
1215  struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
1216 
1217  yaz_log(log_level, "tcpip_put h=%p size=%d", h, size);
1218  h->io_pending = 0;
1219  h->event = CS_DATA;
1220  if (state->towrite < 0)
1221  {
1222  state->towrite = size;
1223  state->written = 0;
1224  }
1225  else if (state->towrite != size)
1226  {
1227  h->cerrno = CSWRONGBUF;
1228  return -1;
1229  }
1230  while (state->towrite > state->written)
1231  {
1232 #if HAVE_GNUTLS_H
1233  if (state->session)
1234  {
1235  res = gnutls_record_send(state->session, buf + state->written,
1236  size - state->written);
1237  if (res <= 0)
1238  {
1239  if (ssl_check_error(h, state, res))
1240  return 1;
1241  return -1;
1242  }
1243  }
1244  else
1245 #endif
1246  {
1247  if ((res =
1248  send(h->iofile, buf + state->written, size -
1249  state->written,
1250 #ifdef MSG_NOSIGNAL
1251  MSG_NOSIGNAL
1252 #else
1253  0
1254 #endif
1255  )) < 0)
1256  {
1257  if (
1258 #ifdef WIN32
1259  WSAGetLastError() == WSAEWOULDBLOCK
1260 #else
1261  yaz_errno() == EWOULDBLOCK
1262 #ifdef EAGAIN
1263 #if EAGAIN != EWOULDBLOCK
1264  || yaz_errno() == EAGAIN
1265 #endif
1266 #endif
1267 #ifdef __sun__
1268  || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
1269 #endif
1270  || yaz_errno() == EINPROGRESS
1271 #endif
1272  )
1273  {
1274  yaz_log(log_level, " Flow control stop");
1276  return 1;
1277  }
1278  if (h->flags & CS_FLAGS_BLOCKING)
1279  {
1280  h->cerrno = CSYSERR;
1281  return -1;
1282  }
1283  else
1284  return cont_connect(h);
1285  }
1286  }
1287  state->written += res;
1288  yaz_log(log_level, " Wrote %d, written=%d, nbytes=%d",
1289  res, state->written, size);
1290  }
1291  state->towrite = state->written = -1;
1292  yaz_log(log_level, " Ok");
1293  return 0;
1294 }
1295 
1297 {
1298  tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1299 
1300  yaz_log(log_level, "tcpip_close: h=%p", h);
1301  xfree(sp->bind_host);
1302 #if RESOLVER_THREAD
1303  if (sp->pipefd[0] != -1)
1304  {
1305  yaz_thread_join(&sp->thread_id, 0);
1306  close(sp->pipefd[0]);
1307  close(sp->pipefd[1]);
1308  h->iofile = -1;
1309  }
1310 #endif
1311  if (h->iofile != -1)
1312  {
1313 #if HAVE_GNUTLS_H
1314  if (sp->session && sp->use_bye)
1315  {
1316  yaz_log(log_level, "tcpip_close: gnutls_bye");
1317  gnutls_bye(sp->session, GNUTLS_SHUT_WR);
1318  }
1319 #endif
1320 #ifdef WIN32
1321  closesocket(h->iofile);
1322 #else
1323  close(h->iofile);
1324 #endif
1325  }
1326  if (sp->altbuf)
1327  xfree(sp->altbuf);
1328 #if HAVE_GNUTLS_H
1329  if (sp->session)
1330  {
1331  gnutls_deinit(sp->session);
1332  }
1333  if (sp->cred_ptr)
1334  {
1335  assert(sp->cred_ptr->ref > 0);
1336 
1337  if (--(sp->cred_ptr->ref) == 0)
1338  {
1339  yaz_log(log_level, "tcpip_close: removed credentials h=%p",
1340  sp->cred_ptr->xcred);
1341  gnutls_certificate_free_credentials(sp->cred_ptr->xcred);
1342  xfree(sp->cred_ptr);
1343  }
1344  sp->cred_ptr = 0;
1345  }
1346 #endif
1347  if (sp->ai)
1348  freeaddrinfo(sp->ai);
1349  xfree(sp->host_port);
1352  xfree(sp);
1353  xfree(h);
1354 }
1355 
1356 const char *tcpip_addrstr(COMSTACK h)
1357 {
1358  tcpip_state *sp = (struct tcpip_state *)h->cprivate;
1359  char *r = 0, *buf = sp->buf;
1360 
1361  char host[120];
1362  struct sockaddr_storage addr;
1363  YAZ_SOCKLEN_T len = sizeof(addr);
1364 
1365  if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0)
1366  {
1367  h->cerrno = CSYSERR;
1368  return 0;
1369  }
1370  if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1,
1371  0, 0,
1372  (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0))
1373  {
1374  r = "unknown";
1375  }
1376  else
1377  r = host;
1378 
1379  if (h->protocol == PROTO_HTTP)
1380  sprintf(buf, "http:%s", r);
1381  else
1382  sprintf(buf, "tcp:%s", r);
1383 #if HAVE_GNUTLS_H
1384  if (sp->session)
1385  {
1386  if (h->protocol == PROTO_HTTP)
1387  sprintf(buf, "https:%s", r);
1388  else
1389  sprintf(buf, "ssl:%s", r);
1390  }
1391 #endif
1392  return buf;
1393 }
1394 
1395 static int tcpip_set_blocking(COMSTACK p, int flags)
1396 {
1397  unsigned long flag;
1398 
1399 #ifdef WIN32
1400  flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
1401  if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0)
1402  return 0;
1403 #else
1404  flag = fcntl(p->iofile, F_GETFL, 0);
1405  if (flags & CS_FLAGS_BLOCKING)
1406  flag = flag & ~O_NONBLOCK; /* blocking */
1407  else
1408  {
1409  flag = flag | O_NONBLOCK; /* non-blocking */
1410  signal(SIGPIPE, SIG_IGN);
1411  }
1412  if (fcntl(p->iofile, F_SETFL, flag) < 0)
1413  return 0;
1414 #endif
1415  p->flags = flags;
1416  return 1;
1417 }
1418 
1419 
1420 #if HAVE_GNUTLS_H
1421 /* gnutls_x509_crt_print appeared in 1.7.6. Memory leaks were fixed in 1.7.9.
1422  GNUTLS_CRT_PRINT_FULL appeared in 2.4.0. */
1423 #if GNUTLS_VERSION_NUMBER >= 0x020400
1424 #define USE_GNUTLS_X509_CRT_PRINT 1
1425 #else
1426 #define USE_GNUTLS_X509_CRT_PRINT 0
1427 #endif
1428 
1429 
1430 #if USE_GNUTLS_X509_CRT_PRINT
1431 #else
1432 static const char *bin2hex(const void *bin, size_t bin_size)
1433 {
1434  static char printable[110];
1435  const unsigned char *_bin = bin;
1436  char *print;
1437  size_t i;
1438  if (bin_size > 50)
1439  bin_size = 50;
1440  print = printable;
1441  for (i = 0; i < bin_size; i++)
1442  {
1443  sprintf(print, "%.2x ", _bin[i]);
1444  print += 2;
1445  }
1446  return printable;
1447 }
1448 
1449 static void x509_crt_print(gnutls_x509_crt_t cert)
1450 {
1451  time_t expiration_time, activation_time;
1452  size_t size;
1453  char serial[40];
1454  char dn[256];
1455  unsigned int algo, bits;
1456 
1457  expiration_time = gnutls_x509_crt_get_expiration_time(cert);
1458  activation_time = gnutls_x509_crt_get_activation_time(cert);
1459 
1460  printf("\tCertificate is valid since: %s", ctime(&activation_time));
1461  printf("\tCertificate expires: %s", ctime(&expiration_time));
1462 
1463  /* Print the serial number of the certificate. */
1464  size = sizeof(serial);
1465  gnutls_x509_crt_get_serial(cert, serial, &size);
1466 
1467  printf("\tCertificate serial number: %s\n", bin2hex(serial, size));
1468 
1469  /* Extract some of the public key algorithm's parameters
1470  */
1471  algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits);
1472 
1473  printf("Certificate public key: %s", gnutls_pk_algorithm_get_name(algo));
1474 
1475  /* Print the version of the X.509 certificate. */
1476  printf("\tCertificate version: #%d\n", gnutls_x509_crt_get_version(cert));
1477 
1478  size = sizeof(dn);
1479  gnutls_x509_crt_get_dn(cert, dn, &size);
1480  printf("\tDN: %s\n", dn);
1481 
1482  size = sizeof(dn);
1483  gnutls_x509_crt_get_issuer_dn(cert, dn, &size);
1484  printf("\tIssuer's DN: %s\n", dn);
1485 }
1486 #endif
1487 #endif
1488 
1490 {
1491 #if HAVE_GNUTLS_H
1492  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1493  if (cs->type == ssl_type && sp->session)
1494  {
1495  const gnutls_datum_t *cert_list;
1496  unsigned i, cert_list_size;
1497  if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1498  return;
1499  printf("X509 certificate\n");
1500  cert_list = gnutls_certificate_get_peers(sp->session,
1501  &cert_list_size);
1502  printf("Peer provided %u certificates\n", cert_list_size);
1503  for (i = 0; i < cert_list_size; i++)
1504  {
1505  gnutls_x509_crt_t cert;
1506 #if USE_GNUTLS_X509_CRT_PRINT
1507  int ret;
1508  gnutls_datum_t cinfo;
1509 #endif
1510  gnutls_x509_crt_init(&cert);
1511  gnutls_x509_crt_import(cert, &cert_list[i], GNUTLS_X509_FMT_DER);
1512  printf("Certificate info %u:\n", i + 1);
1513 #if USE_GNUTLS_X509_CRT_PRINT
1514  ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL,
1515  &cinfo);
1516  if (ret == 0)
1517  {
1518  printf("\t%s\n", cinfo.data);
1519  gnutls_free(cinfo.data);
1520  }
1521 #else
1522  x509_crt_print(cert);
1523 #endif
1524  gnutls_x509_crt_deinit(cert);
1525 
1526  }
1527  }
1528 #endif
1529 }
1530 
1532 {
1533  /* doesn't do anything for GNUTLS */
1534  return 0;
1535 }
1536 
1537 int cs_set_ssl_ctx(COMSTACK cs, void *ctx)
1538 {
1539 #if HAVE_GNUTLS_H
1540  if (cs && cs->type == ssl_type)
1541  {
1542  /* doesn't do anything for GNUTLS */
1543  return 1;
1544  }
1545 #endif
1546  return 0;
1547 }
1548 
1549 int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
1550 {
1551 #if HAVE_GNUTLS_H
1552  if (cs && cs->type == ssl_type)
1553  {
1554  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1555  strncpy(sp->cert_fname, fname, sizeof(sp->cert_fname)-1);
1556  sp->cert_fname[sizeof(sp->cert_fname)-1] = '\0';
1557  return 1;
1558  }
1559 #endif
1560  return 0;
1561 }
1562 
1563 int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
1564 {
1565 
1566 #if HAVE_GNUTLS_H
1567 #if USE_GNUTLS_X509_CRT_PRINT
1568  struct tcpip_state *sp = (struct tcpip_state *) cs->cprivate;
1569  if (cs->type == ssl_type && sp->session)
1570  {
1571  const gnutls_datum_t *cert_list;
1572  unsigned cert_list_size;
1573  if (gnutls_certificate_type_get(sp->session) != GNUTLS_CRT_X509)
1574  return 0;
1575  cert_list = gnutls_certificate_get_peers(sp->session, &cert_list_size);
1576  if (cert_list_size > 0)
1577  {
1578  gnutls_x509_crt_t cert;
1579  int ret;
1580  gnutls_datum_t cinfo;
1581 
1582  gnutls_x509_crt_init(&cert);
1583  gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
1584 
1585  ret = gnutls_x509_crt_print(cert, GNUTLS_CRT_PRINT_FULL, &cinfo);
1586  if (ret == 0)
1587  {
1588  *buf = xstrdup((char *) cinfo.data);
1589  *len = strlen(*buf);
1590  gnutls_free(cinfo.data);
1591  gnutls_x509_crt_deinit(cert);
1592  return 1;
1593  }
1594  gnutls_x509_crt_deinit(cert);
1595  }
1596  }
1597 #endif
1598 #endif
1599  return 0;
1600 }
1601 
1602 int cs_set_head_only(COMSTACK cs, int head_only)
1603 {
1604  if (cs->type == tcpip_type || cs->type == ssl_type)
1605  {
1606  tcpip_state *sp = (tcpip_state *)cs->cprivate;
1607  if (head_only)
1609  else
1610  sp->complete = cs_complete_auto;
1611  return 0;
1612  }
1613  cs->cerrno = CS_ST_INCON;
1614  return -1;
1615 }
1616 
1617 /*
1618  * Local variables:
1619  * c-basic-offset: 4
1620  * c-file-style: "Stroustrup"
1621  * indent-tabs-mode: nil
1622  * End:
1623  * vim: shiftwidth=4 tabstop=8 expandtab
1624  */
1625 
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)
Definition: init_globals.c:47
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.
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 * 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
void *(* f_straddr)(COMSTACK handle, const char *str)
Definition: comstack.h:85
CS_TYPE type
Definition: comstack.h:48
int(* f_more)(COMSTACK handle)
Definition: comstack.h:73
const char *(* f_addrstr)(COMSTACK handle)
Definition: comstack.h:84
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
struct addrinfo * ai_connect
Definition: tcpip.c:124
int written
Definition: tcpip.c:118
int pipefd[2]
Definition: tcpip.c:127
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
const char * port
Definition: tcpip.c:128
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
yaz_thread_t thread_id
Definition: tcpip.c:129
int connect_request_len
Definition: tcpip.c:139
int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
Definition: tcpip.c:1549
void cs_print_session_info(COMSTACK cs)
Definition: tcpip.c:1489
int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len)
Definition: tcpip.c:1563
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:574
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:1537
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:1356
void * cs_get_ssl(COMSTACK cs)
Definition: tcpip.c:1531
static struct tcpip_state * tcpip_state_create(void)
Definition: tcpip.c:173
COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
Definition: tcpip.c:324
static int tcpip_more(COMSTACK h)
Definition: tcpip.c:614
void * resolver_thread(void *arg)
Definition: tcpip.c:545
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:1061
#define CS_TCPIP_BUFCHUNK
Definition: tcpip.c:1055
static int log_level
Definition: tcpip.c:144
static int cont_connect(COMSTACK h)
Definition: tcpip.c:621
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:1602
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:1212
static struct addrinfo * wait_resolver_thread(COMSTACK h)
Definition: tcpip.c:558
static void tcpip_close(COMSTACK h)
Definition: tcpip.c:1296
static int tcpip_init(void)
Definition: tcpip.c:146
struct tcpip_state tcpip_state
static COMSTACK tcpip_accept(COMSTACK h)
Definition: tcpip.c:947
static int tcpip_connect(COMSTACK h, void *address)
Definition: tcpip.c:661
static int tcpip_bind(COMSTACK h, void *address, int mode)
Definition: tcpip.c:810
static int tcpip_set_blocking(COMSTACK p, int blocking)
Definition: tcpip.c:1395
static int tcpip_rcvconnect(COMSTACK h)
Definition: tcpip.c:725
#define YAZ_SOCKLEN_T
Definition: tcpip.c:101
static struct addrinfo * create_net_socket(COMSTACK h)
Definition: tcpip.c:467
Header for TCP/IP + SSL COMSTACK.
yaz_thread_t yaz_thread_create(void *(*start_routine)(void *p), void *arg)
create thread
Definition: thread_create.c:55
void yaz_thread_join(yaz_thread_t *tp, void **value_ptr)
join thread
Definition: thread_create.c:86
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