X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Ftcpip.c;h=af2d8132c2cecf6564434c863f9bf59f3c3800bd;hp=5168c77b31137d36bcca669ddb4cda677dc5c9f3;hb=11dbebdf973d652e486f2b5e457cc46d1478556f;hpb=8a0937d20238aa0f26e564f7eacc0483acb102da diff --git a/src/tcpip.c b/src/tcpip.c index 5168c77..af2d813 100644 --- a/src/tcpip.c +++ b/src/tcpip.c @@ -1,8 +1,8 @@ /* - * Copyright (C) 1995-2005, Index Data ApS + * Copyright (C) 1995-2006, Index Data ApS * See the file LICENSE for details. * - * $Id: tcpip.c,v 1.20 2006-08-30 12:04:43 adam Exp $ + * $Id: tcpip.c,v 1.28 2006-09-06 15:01:53 adam Exp $ */ /** * \file tcpip.c @@ -26,7 +26,9 @@ #endif #ifdef WIN32 -#include +#include +#include +#define HAVE_GETADDRINFO 1 #else #include #include @@ -94,7 +96,11 @@ typedef struct tcpip_state int written; /* -1 if we aren't writing */ int towrite; /* to verify against user input */ int (*complete)(const unsigned char *buf, int len); /* length/comple. */ +#if HAVE_GETADDRINFO + struct addrinfo *ai; +#else struct sockaddr_in addr; /* returned by cs_straddr */ +#endif char buf[128]; /* returned by cs_addrstr */ #if HAVE_OPENSSL_SSL_H SSL_CTX *ctx; /* current CTX. */ @@ -131,44 +137,20 @@ static int tcpip_init (void) * This function is always called through the cs_create() macro. * s >= 0: socket has already been established for us. */ -COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) +COMSTACK tcpip_type(int s, int flags, int protocol, void *vp) { COMSTACK p; tcpip_state *sp; - int new_socket; -#ifdef WIN32 - unsigned long tru = 1; -#endif if (!tcpip_init ()) return 0; - if (s < 0) - { - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return 0; - new_socket = 1; - } - else - new_socket = 0; if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack)))) return 0; if (!(sp = (struct tcpip_state *)(p->cprivate = xmalloc(sizeof(tcpip_state))))) return 0; - if (!((p->blocking = blocking)&1)) - { -#ifdef WIN32 - if (ioctlsocket(s, FIONBIO, &tru) < 0) - return 0; -#else - if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) - return 0; -#ifndef MSG_NOSIGNAL - signal (SIGPIPE, SIG_IGN); -#endif -#endif - } + p->flags = flags; p->io_pending = 0; p->iofile = s; @@ -189,7 +171,7 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) p->f_set_blocking = tcpip_set_blocking; p->max_recv_bytes = 5000000; - p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */ + p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */ p->event = CS_NONE; p->cerrno = 0; p->stackerr = 0; @@ -201,6 +183,9 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) strcpy(sp->cert_fname, "yaz.pem"); #endif +#if HAVE_GETADDRINFO + sp->ai = 0; +#endif sp->altbuf = 0; sp->altsize = sp->altlen = 0; sp->towrite = sp->written = -1; @@ -217,12 +202,12 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) #if HAVE_OPENSSL_SSL_H -COMSTACK ssl_type(int s, int blocking, int protocol, void *vp) +COMSTACK ssl_type(int s, int flags, int protocol, void *vp) { tcpip_state *sp; COMSTACK p; - p = tcpip_type (s, blocking, protocol, 0); + p = tcpip_type (s, flags, protocol, 0); if (!p) return 0; p->f_get = ssl_get; @@ -237,28 +222,67 @@ COMSTACK ssl_type(int s, int blocking, int protocol, void *vp) } #endif +#if HAVE_GETADDRINFO +/* resolve using getaddrinfo */ +struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port) +{ + struct addrinfo hints, *res; + int error; + char host[512], *p; + + hints.ai_flags = 0; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + strncpy(host, str, sizeof(host)-1); + host[sizeof(host)-1] = 0; + if ((p = strchr(host, '/'))) + *p = 0; + if ((p = strrchr(host, ':'))) + { + *p = '\0'; + port = p+1; + } + + if (!strcmp("@", host)) + { + hints.ai_flags = AI_PASSIVE; + error = getaddrinfo(0, port, &hints, &res); + } + else + { + error = getaddrinfo(host, port, &hints, &res); + } + if (error) + return 0; + return res; +} + +#endif +/* gethostbyname .. old systems */ int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add, int default_port) { struct hostent *hp; -#if HAVE_GETHOSTBYNAME_R - struct hostent h; - char hbuf[1024]; - int h_error; -#endif char *p, buf[512]; short int port = default_port; +#ifdef WIN32 + unsigned long tmpadd; +#else in_addr_t tmpadd; - - if (!tcpip_init ()) - return 0; +#endif TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL")); add->sin_family = AF_INET; - strncpy(buf, str, 511); - buf[511] = 0; + strncpy(buf, str, sizeof(buf)-1); + buf[sizeof(buf)-1] = 0; if ((p = strchr(buf, '/'))) *p = 0; - if ((p = strchr(buf, ':'))) + if ((p = strrchr(buf, ':'))) { *p = 0; port = atoi(p + 1); @@ -268,49 +292,74 @@ int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add, { add->sin_addr.s_addr = INADDR_ANY; } - else if ((tmpadd = inet_addr(buf)) != INADDR_NONE) + else if ((tmpadd = inet_addr(buf)) != -1) { memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr)); } -#if HAVE_GETHOSTBYNAME_R - else if (gethostbyname_r(buf, &h, hbuf, sizeof(hbuf), &hp, &h_error) == 0) - { - memcpy(&add->sin_addr.s_addr, *hp->h_addr_list, - sizeof(struct in_addr)); - } -#else else if ((hp = gethostbyname(buf))) { memcpy(&add->sin_addr.s_addr, *hp->h_addr_list, sizeof(struct in_addr)); } -#endif else return 0; return 1; } + +#if HAVE_GETADDRINFO void *tcpip_straddr(COMSTACK h, const char *str) { tcpip_state *sp = (tcpip_state *)h->cprivate; - int port = 210; + const char *port = "210"; + if (h->protocol == PROTO_HTTP) + port = "80"; + if (!tcpip_init ()) + return 0; + if (sp->ai) + freeaddrinfo(sp->ai); + sp->ai = tcpip_getaddrinfo(str, port); + if (sp->ai && h->state == CS_ST_UNBND) + { + int s; + struct addrinfo *ai = sp->ai; + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s < 0) + return 0; + h->iofile = s; + + if (!tcpip_set_blocking(h, h->flags)) + return 0; + } + return sp->ai; +} +#else +void *tcpip_straddr(COMSTACK h, const char *str) +{ + tcpip_state *sp = (tcpip_state *)h->cprivate; + int port = 210; if (h->protocol == PROTO_HTTP) port = 80; + if (!tcpip_init ()) + return 0; if (!tcpip_strtoaddr_ex (str, &sp->addr, port)) return 0; - return &sp->addr; -} + if (h->state == CS_ST_UNBND) + { + int s; + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return 0; + h->iofile = s; -struct sockaddr_in *tcpip_strtoaddr(const char *str) -{ - static struct sockaddr_in add; - - if (!tcpip_strtoaddr_ex (str, &add, 210)) - return 0; - return &add; + if (!tcpip_set_blocking(h, h->blocking)) + return 0; + } + return &sp->addr; } +#endif int tcpip_more(COMSTACK h) { @@ -327,7 +376,11 @@ int tcpip_more(COMSTACK h) */ int tcpip_connect(COMSTACK h, void *address) { - struct sockaddr_in *add = (struct sockaddr_in *)address; +#if HAVE_GETADDRINFO + tcpip_state *sp = (tcpip_state *)h->cprivate; +#else + struct sockaddr_in *add = (struct sockaddr_in *) address; +#endif int r; #ifdef __sun__ int recbuflen; @@ -340,6 +393,13 @@ int tcpip_connect(COMSTACK h, void *address) h->cerrno = CSOUTSTATE; return -1; } +#if HAVE_GETADDRINFO + if (sp->ai != (struct addrinfo *) address) + { + h->cerrno = CSOUTSTATE; + return -1; + } +#endif #ifdef __sun__ /* On Suns, you must set a bigger Receive Buffer BEFORE a call to connect * This gives the connect a chance to negotiate with the other side @@ -366,7 +426,14 @@ int tcpip_connect(COMSTACK h, void *address) TRC(fprintf( stderr, "New Size of TCP Receive Buffer = %d\n", recbuflen )); #endif + +#if HAVE_GETADDRINFO + r = connect(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen); + freeaddrinfo(sp->ai); + sp->ai = 0; +#else r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add)); +#endif if (r < 0) { #ifdef WIN32 @@ -484,15 +551,27 @@ static void tcpip_setsockopt (int fd) static int tcpip_bind(COMSTACK h, void *address, int mode) { + int r; + tcpip_state *sp = (tcpip_state *)h->cprivate; +#if HAVE_GETADDRINFO +#else struct sockaddr *addr = (struct sockaddr *)address; +#endif #ifdef WIN32 BOOL one = 1; #else unsigned long one = 1; #endif +#if HAVE_GETADDRINFO + if (sp->ai != (struct addrinfo *) address) + { + h->cerrno = CSOUTSTATE; + return -1; + } +#endif + #if HAVE_OPENSSL_SSL_H - tcpip_state *sp = (tcpip_state *)h->cprivate; if (h->type == ssl_type && !sp->ctx) { SSL_load_error_strings(); @@ -548,7 +627,14 @@ static int tcpip_bind(COMSTACK h, void *address, int mode) } #endif tcpip_setsockopt(h->iofile); - if (bind(h->iofile, addr, sizeof(struct sockaddr_in))) +#if HAVE_GETADDRINFO + r = bind(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen); + freeaddrinfo(sp->ai); + sp->ai = 0; +#else + r = bind(h->iofile, addr, sizeof(struct sockaddr_in)); +#endif + if (r) { h->cerrno = CSYSERR; return -1; @@ -658,13 +744,7 @@ COMSTACK tcpip_accept(COMSTACK h) } return 0; } - if (!(cnew->blocking&1) && -#ifdef WIN32 - (ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0) -#else - (fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0) -#endif - ) + if (!tcpip_set_blocking(cnew, cnew->flags)) { h->cerrno = CSYSERR; if (h->newfd != -1) @@ -685,6 +765,9 @@ COMSTACK tcpip_accept(COMSTACK h) state->altsize = state->altlen = 0; state->towrite = state->written = -1; state->complete = st->complete; +#if HAVE_GETADDRINFO + state->ai = 0; +#endif cnew->state = CS_ST_ACCEPT; h->state = CS_ST_IDLE; @@ -791,7 +874,7 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread)); if (res < 0) { - TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), + TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), strerror(yaz_errno()))); #ifdef WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) @@ -800,7 +883,10 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) break; } else + { + h->cerrno = CSYSERR; return -1; + } #else if (yaz_errno() == EWOULDBLOCK #ifdef EAGAIN @@ -820,7 +906,10 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) else if (yaz_errno() == 0) continue; else + { + h->cerrno = CSYSERR; return -1; + } #endif } else if (!res) @@ -844,10 +933,16 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) if (!sp->altbuf) { if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req))) + { + h->cerrno = CSYSERR; return -1; + } } else if (sp->altsize < req) if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req))) + { + h->cerrno = CSYSERR; return -1; + } TRC(fprintf(stderr, " Moving %d bytes to altbuf(0x%x)\n", tomove, (unsigned) sp->altbuf)); memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove); @@ -1097,6 +1192,10 @@ int tcpip_close(COMSTACK h) if (sp->ctx_alloc) SSL_CTX_free (sp->ctx_alloc); #endif +#if HAVE_GETADDRINFO + if (sp->ai) + freeaddrinfo(sp->ai); +#endif xfree(sp); xfree(h); return 0; @@ -1104,25 +1203,50 @@ int tcpip_close(COMSTACK h) char *tcpip_addrstr(COMSTACK h) { - struct sockaddr_in addr; tcpip_state *sp = (struct tcpip_state *)h->cprivate; char *r = 0, *buf = sp->buf; - YAZ_SOCKLEN_T len; + +#if HAVE_GETADDRINFO + char host[120]; + struct sockaddr_storage addr; + YAZ_SOCKLEN_T len = sizeof(addr); + + if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0) + { + h->cerrno = CSYSERR; + return 0; + } + if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1, + 0, 0, + (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0)) + { + r = "unknown"; + } + else + r = host; + +#else + + struct sockaddr_in addr; + YAZ_SOCKLEN_T len = sizeof(addr); struct hostent *host; - len = sizeof(addr); if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0) { h->cerrno = CSYSERR; return 0; } - if (!(h->blocking&2)) { - if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr), - AF_INET))) + if (!(h->flags & CS_FLAGS_NUMERICHOST)) + { + if ((host = gethostbyaddr((char*)&addr.sin_addr, + sizeof(addr.sin_addr), + AF_INET))) r = (char*) host->h_name; } if (!r) - r = inet_ntoa(addr.sin_addr); + r = inet_ntoa(addr.sin_addr); +#endif + if (h->protocol == PROTO_HTTP) sprintf(buf, "http:%s", r); else @@ -1139,26 +1263,27 @@ char *tcpip_addrstr(COMSTACK h) return buf; } -int static tcpip_set_blocking(COMSTACK p, int blocking) +int static tcpip_set_blocking(COMSTACK p, int flags) { unsigned long flag; - if (p->blocking == blocking) - return 1; #ifdef WIN32 - flag = 1; + flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1; if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0) return 0; #else flag = fcntl(p->iofile, F_GETFL, 0); - if(!(blocking&1)) - flag = flag & ~O_NONBLOCK; + if (flags & CS_FLAGS_BLOCKING) + flag = flag & ~O_NONBLOCK; /* blocking */ else - flag = flag | O_NONBLOCK; + { + flag = flag | O_NONBLOCK; /* non-blocking */ + signal(SIGPIPE, SIG_IGN); + } if (fcntl(p->iofile, F_SETFL, flag) < 0) return 0; #endif - p->blocking = blocking; + p->flags = flags; return 1; }