Prefix resolved message
[pazpar2-moved-to-github.git] / src / logic.c
index 1facb64..bce0ad1 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: logic.c,v 1.15 2007-04-20 16:37:35 quinn Exp $
+/* $Id: logic.c,v 1.18 2007-04-22 16:41:42 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;
@@ -1100,8 +1100,12 @@ static void connection_release(struct connection *co)
 static void connection_destroy(struct connection *co)
 {
     struct host *h = co->host;
-    cs_close(co->link);
-    iochan_destroy(co->iochan);
+    
+    if (co->link)
+    {
+        cs_close(co->link);
+        iochan_destroy(co->iochan);
+    }
 
     yaz_log(YLOG_DEBUG, "Connection destroy %s", co->host->hostport);
     if (h->connections == co)
@@ -1126,54 +1130,103 @@ 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)
+static int connection_connect(struct connection *con)
 {
-    struct connection *new;
-    COMSTACK link; 
-    int res;
+    COMSTACK link = 0;
+    struct client *cl = con->client;
+    struct host *host = con->host;
     void *addr;
+    int res;
 
+    assert(host->ipport);
+    assert(cl);
 
     if (!(link = cs_create(tcpip_type, 0, PROTO_Z3950)))
-        {
-            yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create comstack");
-            exit(1);
-        }
+    {
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "Failed to create comstack");
+        exit(1);
+    }
     
     if (0 == strlen(global_parameters.zproxy_override)){
         /* no Z39.50 proxy needed - direct connect */
         yaz_log(YLOG_DEBUG, "Connection create %s", cl->database->database->url);
         
-        if (!(addr = cs_straddr(link, cl->database->database->host->ipport)))
-            {
-                yaz_log(YLOG_WARN|YLOG_ERRNO, 
-                        "Lookup of IP address %s failed", 
-                        cl->database->database->host->ipport);
-                return 0;
-            }
-    
+        if (!(addr = cs_straddr(link, host->ipport)))
+        {
+            yaz_log(YLOG_WARN|YLOG_ERRNO, 
+                    "Lookup of IP address %s failed", host->ipport);
+            return -1;
+        }
+        
     } else {
         /* Z39.50 proxy connect */
         yaz_log(YLOG_DEBUG, "Connection create %s proxy %s", 
                 cl->database->database->url, global_parameters.zproxy_override);
-
+        
         if (!(addr = cs_straddr(link, global_parameters.zproxy_override)))
-            {
-                yaz_log(YLOG_WARN|YLOG_ERRNO, 
-                        "Lookup of IP address %s failed", 
-                        global_parameters.zproxy_override);
-                return 0;
-            }
+        {
+            yaz_log(YLOG_WARN|YLOG_ERRNO, 
+                    "Lookup of IP address %s failed", 
+                    global_parameters.zproxy_override);
+            return -1;
+        }
     }
-
+    
     res = cs_connect(link, addr);
     if (res < 0)
     {
         yaz_log(YLOG_WARN|YLOG_ERRNO, "cs_connect %s", cl->database->database->url);
-        return 0;
+        return -1;
     }
+    con->link = link;
+    con->state = Conn_Connecting;
+    con->iochan = iochan_create(cs_fileno(link), connection_handler, 0);
+    iochan_setdata(con->iochan, con);
+    pazpar2_add_channel(con->iochan);
+
+    /* this fragment is bad DRY: from client_prep_connection */
+    cl->state = Client_Connecting;
+    iochan_setflag(con->iochan, EVENT_OUTPUT);
+    return 0;
+}
+
+void connect_resolver_host(struct host *host)
+{
+    struct connection *con = host->connections;
+
+    while (con)
+    {
+        if (con->state == Conn_Resolving)
+        {
+            if (!host->ipport) /* unresolved */
+            {
+                connection_destroy(con);
+                /* start all over .. at some point it will be NULL */
+                con = host->connections;
+            }
+            else if (!con->client)
+            {
+                yaz_log(YLOG_WARN, "connect_unresolved_host : ophan client");
+                connection_destroy(con);
+                /* start all over .. at some point it will be NULL */
+                con = host->connections;
+            }
+            else
+            {
+                connection_connect(con);
+                con = con->next;
+            }
+        }
+    }
+}
+
+
+// Creates a new connection for client, associated with the host of 
+// client's database
+static struct connection *connection_create(struct client *cl)
+{
+    struct connection *new;
+    struct host *host = cl->database->database->host;
 
     if ((new = connection_freelist))
         connection_freelist = new->next;
@@ -1183,17 +1236,15 @@ static struct connection *connection_create(struct client *cl)
         new->ibuf = 0;
         new->ibufsize = 0;
     }
-    new->state = Conn_Connecting;
-    new->host = cl->database->database->host;
+    new->host = host;
     new->next = new->host->connections;
     new->host->connections = new;
     new->client = cl;
     cl->connection = new;
-    new->link = link;
-
-    new->iochan = iochan_create(cs_fileno(link), handler, 0);
-    iochan_setdata(new->iochan, new);
-    pazpar2_add_channel(new->iochan);
+    new->link = 0;
+    new->state = Conn_Resolving;
+    if (host->ipport)
+        connection_connect(new);
     return new;
 }
 
@@ -1588,58 +1639,8 @@ char *search(struct session *se, char *query, char *filter)
     return 0;
 }
 
-// Apply a session override to a database
-void session_apply_setting(struct session *se, char *dbname, char *setting, char *value)
-{
-    struct session_database *sdb;
-
-    for (sdb = se->databases; sdb; sdb = sdb->next)
-        if (!strcmp(dbname, sdb->database->url))
-        {
-            struct setting *new = nmem_malloc(se->session_nmem, sizeof(*new));
-            int offset = settings_offset(setting);
-
-            if (offset < 0)
-            {
-                yaz_log(YLOG_WARN, "Unknown setting %s", setting);
-                return;
-            }
-            new->precedence = 0;
-            new->target = dbname;
-            new->name = setting;
-            new->value = value;
-            new->next = sdb->settings[offset];
-            sdb->settings[offset] = new;
-
-            // Force later recompute of settings-driven data structures
-            // (happens when a search starts and client connections are prepared)
-            switch (offset)
-            {
-                case PZ_NATIVESYNTAX:
-                    if (sdb->yaz_marc)
-                    {
-                        yaz_marc_destroy(sdb->yaz_marc);
-                        sdb->yaz_marc = 0;
-                    }
-                    break;
-                case PZ_XSLT:
-                    if (sdb->map)
-                    {
-                        struct database_retrievalmap *m;
-                        // We don't worry about the map structure -- it's in nmem
-                        for (m = sdb->map; m; m = m->next)
-                            xsltFreeStylesheet(m->stylesheet);
-                        sdb->map = 0;
-                    }
-                    break;
-            }
-            break;
-        }
-    if (!sdb)
-        yaz_log(YLOG_WARN, "Unknown database in setting override: %s", dbname);
-}
-
-void session_init_databases_fun(void *context, struct database *db)
+// Creates a new session_database object for a database
+static void session_init_databases_fun(void *context, struct database *db)
 {
     struct session *se = (struct session *) context;
     struct session_database *new = nmem_malloc(se->session_nmem, sizeof(*new));
@@ -1650,12 +1651,27 @@ void session_init_databases_fun(void *context, struct database *db)
     new->yaz_marc = 0;
     new->map = 0;
     new->settings = nmem_malloc(se->session_nmem, sizeof(struct settings *) * num);
-    for (i = 0; i < num; i++)
-        new->settings[i] = db->settings[i];
+    memset(new->settings, 0, sizeof(struct settings*) * num);
+    if (db->settings)
+    {
+        for (i = 0; i < num; i++)
+            new->settings[i] = db->settings[i];
+    }
     new->next = se->databases;
     se->databases = new;
 }
 
+// Doesn't free memory associated with sdb -- nmem takes care of that
+static void session_database_destroy(struct session_database *sdb)
+{
+    struct database_retrievalmap *m;
+
+    for (m = sdb->map; m; m = m->next)
+        xsltFreeStylesheet(m->stylesheet);
+    if (sdb->yaz_marc)
+        yaz_marc_destroy(sdb->yaz_marc);
+}
+
 // Initialize session_database list -- this represents this session's view
 // of the database list -- subject to modification by the settings ws command
 void session_init_databases(struct session *se)
@@ -1664,11 +1680,80 @@ void session_init_databases(struct session *se)
     grep_databases(se, 0, session_init_databases_fun);
 }
 
+// Probably session_init_databases_fun should be refactored instead of
+// called here.
+static struct session_database *load_session_database(struct session *se, char *id)
+{
+    struct database *db = find_database(id, 0);
+
+    session_init_databases_fun((void*) se, db);
+    // New sdb is head of se->databases list
+    return se->databases;
+}
+
+// Find an existing session database. If not found, load it
+static struct session_database *find_session_database(struct session *se, char *id)
+{
+    struct session_database *sdb;
+
+    for (sdb = se->databases; sdb; sdb = sdb->next)
+        if (!strcmp(sdb->database->url, id))
+            return sdb;
+    return load_session_database(se, id);
+}
+
+// Apply a session override to a database
+void session_apply_setting(struct session *se, char *dbname, char *setting, char *value)
+{
+    struct session_database *sdb = find_session_database(se, dbname);
+    struct setting *new = nmem_malloc(se->session_nmem, sizeof(*new));
+    int offset = settings_offset(setting);
+
+    if (offset < 0)
+    {
+        yaz_log(YLOG_WARN, "Unknown setting %s", setting);
+        return;
+    }
+    new->precedence = 0;
+    new->target = dbname;
+    new->name = setting;
+    new->value = value;
+    new->next = sdb->settings[offset];
+    sdb->settings[offset] = new;
+
+    // Force later recompute of settings-driven data structures
+    // (happens when a search starts and client connections are prepared)
+    switch (offset)
+    {
+        case PZ_NATIVESYNTAX:
+            if (sdb->yaz_marc)
+            {
+                yaz_marc_destroy(sdb->yaz_marc);
+                sdb->yaz_marc = 0;
+            }
+            break;
+        case PZ_XSLT:
+            if (sdb->map)
+            {
+                struct database_retrievalmap *m;
+                // We don't worry about the map structure -- it's in nmem
+                for (m = sdb->map; m; m = m->next)
+                    xsltFreeStylesheet(m->stylesheet);
+                sdb->map = 0;
+            }
+            break;
+    }
+}
+
 void destroy_session(struct session *s)
 {
+    struct session_database *sdb;
+
     yaz_log(YLOG_LOG, "Destroying session");
     while (s->clients)
         client_destroy(s->clients);
+    for (sdb = s->databases; sdb; sdb = sdb->next)
+        session_database_destroy(sdb);
     nmem_destroy(s->nmem);
     wrbuf_destroy(s->wrbuf);
 }