From: Adam Dickmeiss Date: Sat, 21 Apr 2007 12:00:54 +0000 (+0000) Subject: Perform getaddrinfo in separate thread for a given struct host. X-Git-Tag: PAZPAR2.1.0.0~238 X-Git-Url: http://git.indexdata.com/?p=pazpar2-moved-to-github.git;a=commitdiff_plain;h=dedbc922fbe49e599466f41c618ba9ba8ddb9477 Perform getaddrinfo in separate thread for a given struct host. --- diff --git a/src/Makefile.am b/src/Makefile.am index bf17578..038d0a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.12 2007-04-20 14:37:17 marc Exp $ +# $Id: Makefile.am,v 1.13 2007-04-21 12:00:54 adam Exp $ bin_PROGRAMS = pazpar2 check_PROGRAMS = test_config test_relevance test_sel_thread @@ -16,7 +16,7 @@ libpazpar2_a_SOURCES = config.c config.h eventl.c eventl.h \ record.h record.c reclists.c reclists.h \ relevance.c relevance.h termlists.c termlists.h \ util.c util.h zeerex.c zeerex.h database.c database.h \ - settings.h settings.c sel_thread.c sel_thread.h + settings.h settings.c sel_thread.c sel_thread.h getaddrinfo.c pazpar2_SOURCES = pazpar2.c pazpar2_LDADD = libpazpar2.a $(YAZLIB) diff --git a/src/database.c b/src/database.c index c0c02df..df6f11a 100644 --- a/src/database.c +++ b/src/database.c @@ -1,4 +1,4 @@ -/* $Id: database.c,v 1.22 2007-04-20 16:21:19 quinn Exp $ +/* $Id: database.c,v 1.23 2007-04-21 12:00:54 adam Exp $ Copyright (c) 2006-2007, Index Data. This file is part of Pazpar2. @@ -71,45 +71,19 @@ static xmlDoc *get_explain_xml(const char *id) // Create a new host structure for hostport static struct host *create_host(const char *hostport) { - struct addrinfo *addrinfo, hints; struct host *host; - char *port; - char ipport[128]; - unsigned char addrbuf[4]; - int res; host = xmalloc(sizeof(struct host)); host->hostport = xstrdup(hostport); host->connections = 0; + host->ipport = 0; - if ((port = strchr(hostport, ':'))) - *(port++) = '\0'; - else - port = "210"; - - hints.ai_flags = 0; - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_addrlen = 0; - hints.ai_addr = 0; - hints.ai_canonname = 0; - hints.ai_next = 0; - // This is not robust code. It assumes that getaddrinfo always - // returns AF_INET address. - if ((res = getaddrinfo(hostport, port, &hints, &addrinfo))) + if (host_getaddrinfo(host)) { - yaz_log(YLOG_WARN, "Failed to resolve %s: %s", hostport, gai_strerror(res)); xfree(host->hostport); xfree(host); return 0; } - assert(addrinfo->ai_family == PF_INET); - memcpy(addrbuf, &((struct sockaddr_in*)addrinfo->ai_addr)->sin_addr.s_addr, 4); - sprintf(ipport, "%u.%u.%u.%u:%s", - addrbuf[0], addrbuf[1], addrbuf[2], addrbuf[3], port); - host->ipport = xstrdup(ipport); - freeaddrinfo(addrinfo); host->next = hosts; hosts = host; return host; diff --git a/src/getaddrinfo.c b/src/getaddrinfo.c new file mode 100644 index 0000000..26557d8 --- /dev/null +++ b/src/getaddrinfo.c @@ -0,0 +1,176 @@ +/* $Id: getaddrinfo.c,v 1.1 2007-04-21 12:00:54 adam Exp $ + Copyright (c) 2006-2007, Index Data. + +This file is part of Pazpar2. + +Pazpar2 is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Pazpar2; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#if HAVE_CONFIG_H +#include "cconfig.h" +#endif + +#include "sel_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "pazpar2.h" + +struct work { + char *hostport; /* hostport to be resolved in separate thread */ + char *ipport; /* result or NULL if it could not be resolved */ + struct host *host; /* host that we're dealing with - mother thread */ +}; + +static int log_level = YLOG_LOG; + +void perform_getaddrinfo(struct work *w) +{ + int res = 0; + char *port; + struct addrinfo *addrinfo, hints; + char *hostport = xstrdup(w->hostport); + + if ((port = strchr(hostport, ':'))) + *(port++) = '\0'; + else + port = "210"; + + hints.ai_flags = 0; + hints.ai_family = PF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_addrlen = 0; + hints.ai_addr = 0; + hints.ai_canonname = 0; + hints.ai_next = 0; + // This is not robust code. It assumes that getaddrinfo always + // returns AF_INET address. + if ((res = getaddrinfo(hostport, port, &hints, &addrinfo))) + { + yaz_log(YLOG_WARN, "Failed to resolve %s: %s", + w->hostport, gai_strerror(res)); + } + else + { + char ipport[128]; + unsigned char addrbuf[4]; + assert(addrinfo->ai_family == PF_INET); + memcpy(addrbuf, + &((struct sockaddr_in*)addrinfo->ai_addr)->sin_addr.s_addr, 4); + sprintf(ipport, "%u.%u.%u.%u:%s", + addrbuf[0], addrbuf[1], addrbuf[2], addrbuf[3], port); + freeaddrinfo(addrinfo); + w->ipport = xstrdup(ipport); + yaz_log(log_level, "%s -> %s", hostport, ipport); + } + xfree(hostport); +} + +static void work_handler(void *vp) +{ + struct work *w = vp; + + int sec = 0; /* >0 for debugging/testing purposes */ + if (sec) + { + yaz_log(log_level, "waiting %d seconds", sec); + sleep(sec); + } + perform_getaddrinfo(w); +} + +void iochan_handler(struct iochan *i, int event) +{ + sel_thread_t p = iochan_getdata(i); + + if (event & EVENT_INPUT) + { + struct work *w = sel_thread_result(p); + if (w->ipport) + yaz_log(log_level, "resolved result %s", w->ipport); + else + yaz_log(log_level, "unresolved result"); + w->host->ipport = w->ipport; + xfree(w); + } +} + +static sel_thread_t resolver_thread = 0; + +static void getaddrinfo_start(void) +{ + int fd; + sel_thread_t p = resolver_thread = sel_thread_create(work_handler, &fd); + if (!p) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "sel_create_create failed"); + exit(1); + } + else + { + IOCHAN chan = iochan_create(fd, iochan_handler, EVENT_INPUT); + iochan_setdata(chan, p); + pazpar2_add_channel(chan); + } + yaz_log(log_level, "resolver start"); + resolver_thread = p; +} + +int host_getaddrinfo(struct host *host) +{ + struct work *w = xmalloc(sizeof(*w)); + int use_thread = 1; + + w->hostport = host->hostport; + w->ipport = 0; + w->host = host; + if (use_thread) + { + if (resolver_thread == 0) + getaddrinfo_start(); + assert(resolver_thread); + sel_thread_add(resolver_thread, w); + } + else + { + perform_getaddrinfo(w); + host->ipport = w->ipport; + xfree(w); + if (!host->ipport) + return -1; + } + return 0; +} + +/* + * Local variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * vim: shiftwidth=4 tabstop=8 expandtab + */ diff --git a/src/logic.c b/src/logic.c index 1facb64..12500ff 100644 --- a/src/logic.c +++ b/src/logic.c @@ -1,4 +1,4 @@ -/* $Id: logic.c,v 1.15 2007-04-20 16:37:35 quinn Exp $ +/* $Id: logic.c,v 1.16 2007-04-21 12:00:54 adam Exp $ Copyright (c) 2006-2007, Index Data. This file is part of Pazpar2. @@ -967,7 +967,7 @@ static void do_presentResponse(IOCHAN i, Z_APDU *a) } } -static void handler(IOCHAN i, int event) +void connection_handler(IOCHAN i, int event) { struct connection *co = iochan_getdata(i); struct client *cl = co->client; @@ -1126,6 +1126,7 @@ static void connection_destroy(struct connection *co) connection_freelist = co; } + // Creates a new connection for client, associated with the host of // client's database static struct connection *connection_create(struct client *cl) @@ -1136,6 +1137,13 @@ static struct connection *connection_create(struct client *cl) void *addr; + if (!cl->database->database->host->ipport) + { + yaz_log(YLOG_WARN, "Not yet resolved: %s", + cl->database->database->url); + return 0; + } + if (!(link = cs_create(tcpip_type, 0, PROTO_Z3950))) { yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create comstack"); @@ -1191,7 +1199,7 @@ static struct connection *connection_create(struct client *cl) cl->connection = new; new->link = link; - new->iochan = iochan_create(cs_fileno(link), handler, 0); + new->iochan = iochan_create(cs_fileno(link), connection_handler, 0); iochan_setdata(new->iochan, new); pazpar2_add_channel(new->iochan); return new; diff --git a/src/pazpar2.h b/src/pazpar2.h index c962c47..ef910ab 100644 --- a/src/pazpar2.h +++ b/src/pazpar2.h @@ -1,4 +1,4 @@ -/* $Id: pazpar2.h,v 1.31 2007-04-20 16:21:19 quinn Exp $ +/* $Id: pazpar2.h,v 1.32 2007-04-21 12:00:54 adam Exp $ Copyright (c) 2006-2007, Index Data. This file is part of Pazpar2. @@ -237,7 +237,7 @@ extern struct parameters global_parameters; void pazpar2_add_channel(IOCHAN c); void pazpar2_event_loop(void); - +int host_getaddrinfo(struct host *host); #endif