/*
- * $Id: zoom-c.c,v 1.1 2001-10-23 21:00:20 adam Exp $
+ * $Id: zoom-c.c,v 1.5 2001-11-13 22:57:03 adam Exp $
*
* ZOOM layer for C, connections, result sets, queries.
*/
#include "zoom-p.h"
-static Z3950_record record_cache_lookup (Z3950_resultset r,
- int pos,
- const char *elementSetName);
+#if HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+
+static Z3950_Event Z3950_Event_create (int kind)
+{
+ Z3950_Event event = xmalloc (sizeof(*event));
+ event->kind = kind;
+ event->next = 0;
+ event->prev = 0;
+ return event;
+}
+
+static void Z3950_Event_destroy (Z3950_Event event)
+{
+ xfree (event);
+}
+
+static void Z3950_connection_put_event (Z3950_connection c, Z3950_Event event)
+{
+ // put in back of queue
+ if (c->m_queue_back)
+ {
+ c->m_queue_back->prev = event;
+ assert (c->m_queue_front);
+ }
+ else
+ {
+ assert (!c->m_queue_front);
+ c->m_queue_front = event;
+ }
+ event->next = c->m_queue_back;
+ event->prev = 0;
+ c->m_queue_back = event;
+}
+
+static Z3950_Event Z3950_connection_get_event(Z3950_connection c)
+{
+ // get from front of queue
+ Z3950_Event event = c->m_queue_front;
+ if (!event)
+ return 0;
+ assert (c->m_queue_back);
+ c->m_queue_front = event->prev;
+ if (c->m_queue_front)
+ {
+ assert (c->m_queue_back);
+ c->m_queue_front->next = 0;
+ }
+ else
+ c->m_queue_back = 0;
+ return event;
+}
static void clear_error (Z3950_connection c)
{
c->addinfo = 0;
}
+Z3950_task Z3950_connection_add_task (Z3950_connection c, int which)
+{
+ Z3950_task *taskp = &c->tasks;
+ while (*taskp)
+ taskp = &(*taskp)->next;
+ *taskp = xmalloc (sizeof(**taskp));
+ (*taskp)->running = 0;
+ (*taskp)->which = which;
+ (*taskp)->u.resultset = 0; /* one null pointer there at least */
+ (*taskp)->next = 0;
+ clear_error (c);
+ return *taskp;
+}
+
+void Z3950_connection_remove_task (Z3950_connection c)
+{
+ Z3950_task task = c->tasks;
+
+ if (task)
+ {
+ c->tasks = task->next;
+ switch (task->which)
+ {
+ case Z3950_TASK_SEARCH:
+ Z3950_resultset_destroy (task->u.resultset);
+ break;
+ case Z3950_TASK_RETRIEVE:
+ Z3950_resultset_destroy (task->u.resultset);
+ break;
+ case Z3950_TASK_CONNECT:
+ break;
+ default:
+ assert (0);
+ }
+ xfree (task);
+ }
+}
+
+void Z3950_connection_remove_tasks (Z3950_connection c)
+{
+ while (c->tasks)
+ Z3950_connection_remove_task(c);
+}
+
+static Z3950_record record_cache_lookup (Z3950_resultset r,
+ int pos,
+ const char *elementSetName);
+
Z3950_connection Z3950_connection_create (Z3950_options options)
{
Z3950_connection c = xmalloc (sizeof(*c));
- c->event_pending = 0;
c->cs = 0;
c->mask = 0;
c->state = STATE_IDLE;
c->odr_out = odr_createmem (ODR_ENCODE);
c->async = 0;
+
+ c->m_queue_front = 0;
+ c->m_queue_back = 0;
return c;
}
const char *host, int portnum)
{
const char *val;
+ Z3950_task task;
val = Z3950_options_get (c->options, "proxy");
if (val && *val)
c->async = Z3950_options_get_bool (c->options, "async", 0);
+ task = Z3950_connection_add_task (c, Z3950_TASK_CONNECT);
+
if (!c->async)
{
while (Z3950_event (1, &c))
}
}
-Z3950_search Z3950_search_create(void)
+Z3950_query Z3950_query_create(void)
{
- Z3950_search s = xmalloc (sizeof(*s));
+ Z3950_query s = xmalloc (sizeof(*s));
s->refcount = 1;
s->query = 0;
return c->host_port;
}
-void Z3950_search_destroy(Z3950_search s)
+void Z3950_query_destroy(Z3950_query s)
{
if (!s)
return;
(s->refcount)--;
- yaz_log (LOG_DEBUG, "Z3950_search_destroy count=%d", s->refcount);
+ yaz_log (LOG_DEBUG, "Z3950_query_destroy count=%d", s->refcount);
if (s->refcount == 0)
{
odr_destroy (s->odr);
}
}
-int Z3950_search_prefix(Z3950_search s, const char *str)
+int Z3950_query_prefix(Z3950_query s, const char *str)
{
s->query = odr_malloc (s->odr, sizeof(*s->query));
s->query->which = Z_Query_type_1;
return 0;
}
-int Z3950_search_sortby(Z3950_search s, const char *criteria)
+int Z3950_query_sortby(Z3950_query s, const char *criteria)
{
s->sort_spec = yaz_sort_spec (s->odr, criteria);
if (!s->sort_spec)
static int do_write(Z3950_connection c);
-
-Z3950_task Z3950_connection_add_task (Z3950_connection c, int which)
-{
- Z3950_task *taskp = &c->tasks;
- while (*taskp)
- taskp = &(*taskp)->next;
- *taskp = xmalloc (sizeof(**taskp));
- (*taskp)->running = 0;
- (*taskp)->which = which;
- (*taskp)->u.resultset = 0; /* one null pointer there at least */
- (*taskp)->next = 0;
- clear_error (c);
- return *taskp;
-}
-
-void Z3950_connection_remove_task (Z3950_connection c)
-{
- Z3950_task task = c->tasks;
-
- if (task)
- {
- c->tasks = task->next;
- switch (task->which)
- {
- case Z3950_TASK_SEARCH:
- Z3950_resultset_destroy (task->u.resultset);
- break;
- case Z3950_TASK_RETRIEVE:
- Z3950_resultset_destroy (task->u.resultset);
- break;
- default:
- assert (0);
- }
- xfree (task);
- }
-}
-
-void Z3950_connection_remove_tasks (Z3950_connection c)
-{
- while (c->tasks)
- Z3950_connection_remove_task(c);
-}
-
void Z3950_connection_destroy(Z3950_connection c)
{
Z3950_resultset r;
Z3950_resultset Z3950_connection_search_pqf(Z3950_connection c, const char *q)
{
Z3950_resultset r;
- Z3950_search s = Z3950_search_create();
+ Z3950_query s = Z3950_query_create();
- Z3950_search_prefix (s, q);
+ Z3950_query_prefix (s, q);
r = Z3950_connection_search (c, s);
- Z3950_search_destroy (s);
+ Z3950_query_destroy (s);
return r;
}
-Z3950_resultset Z3950_connection_search(Z3950_connection c, Z3950_search q)
+Z3950_resultset Z3950_connection_search(Z3950_connection c, Z3950_query q)
{
Z3950_resultset r = Z3950_resultset_create ();
Z3950_task task;
rp = &(*rp)->next;
}
}
- Z3950_search_destroy (r->search);
+ Z3950_query_destroy (r->search);
Z3950_options_destroy (r->options);
odr_destroy (r->odr);
xfree (r);
}
void Z3950_resultset_records (Z3950_resultset r, Z3950_record *recs,
- size_t *cnt)
+ size_t start, size_t count)
{
int force_present = 0;
- int start, count;
if (!r)
return ;
- start = Z3950_options_get_int (r->options, "start", 0);
- count = Z3950_options_get_int (r->options, "count", 0);
- if (cnt && recs)
+ if (count && recs)
force_present = 1;
Z3950_resultset_retrieve (r, force_present, start, count);
if (force_present)
{
- int i;
- for (i = 0; i< *cnt; i++)
+ size_t i;
+ for (i = 0; i< count; i++)
recs[i] = Z3950_resultset_record_immediate (r, i+start);
}
}
-static void do_connect (Z3950_connection c)
+static int do_connect (Z3950_connection c)
{
void *add;
const char *effective_host;
if (c->cs)
{
- cs_connect (c->cs, add);
- c->state = STATE_CONNECTING;
- c->mask = Z3950_SELECT_READ | Z3950_SELECT_WRITE;
- }
- else
- {
- c->state = STATE_IDLE;
- c->error = Z3950_ERROR_CONNECT;
+ int ret = cs_connect (c->cs, add);
+ yaz_log (LOG_DEBUG, "cs_connect returned %d", ret);
+ if (ret >= 0)
+ {
+ c->state = STATE_CONNECTING;
+ c->mask = Z3950_SELECT_READ | Z3950_SELECT_WRITE |
+ Z3950_SELECT_EXCEPT;
+ return 1;
+ }
}
+ c->state = STATE_IDLE;
+ c->error = Z3950_ERROR_CONNECT;
+ return 0;
}
int z3950_connection_socket(Z3950_connection c)
return nrec;
}
-Z3950_record Z3950_resultset_record_immediate (Z3950_resultset s, int pos)
+Z3950_record Z3950_resultset_record_immediate (Z3950_resultset s,size_t pos)
{
Z3950_record rec = record_cache_lookup (s, pos, 0);
if (!rec)
return Z3950_record_dup (rec);
}
-Z3950_record Z3950_resultset_record (Z3950_resultset r, int pos)
+Z3950_record Z3950_resultset_record (Z3950_resultset r, size_t pos)
{
Z3950_resultset_retrieve (r, 1, pos, 1);
return Z3950_resultset_record_immediate (r, pos);
xfree (rec);
}
-void *Z3950_record_get (Z3950_record rec, const char *type, int *len)
+void *Z3950_record_get (Z3950_record rec, const char *type, size_t *len)
{
Z_NamePlusRecord *npr;
if (!rec)
}
return 0;
}
+ else if (!strcmp (type, "raw"))
+ {
+ if (npr->which == Z_NamePlusRecord_databaseRecord)
+ {
+ *len = -1;
+ return (Z_External *) npr->u.databaseRecord;
+ }
+ return 0;
+ }
return 0;
}
-void *Z3950_resultset_get (Z3950_resultset s, int pos, const char *type,
- int *len)
+void *Z3950_resultset_get (Z3950_resultset s, size_t pos, const char *type,
+ size_t *len)
{
Z3950_record rec = record_cache_lookup (s, pos, 0);
return Z3950_record_get (rec, type, len);
{
Z3950_task task = c->tasks;
- yaz_log (LOG_DEBUG, "Z3950_connection_exec_task");
+ yaz_log (LOG_LOG, "Z3950_connection_exec_task");
if (!task)
return 0;
- if (c->error != Z3950_ERROR_NONE || !c->cs)
+ if (c->error != Z3950_ERROR_NONE ||
+ (!c->cs && task->which != Z3950_TASK_CONNECT))
{
Z3950_connection_remove_tasks (c);
return 0;
if (send_present (c))
return 1;
break;
+ case Z3950_TASK_CONNECT:
+ if (do_connect(c))
+ return 1;
}
Z3950_connection_remove_task (c);
return 0;
c->cookie_in = 0;
if (cookie)
c->cookie_in = xstrdup(cookie);
+ if (c->tasks)
+ {
+ assert (c->tasks->which == Z3950_TASK_CONNECT);
+ Z3950_connection_remove_task (c);
+ }
Z3950_connection_exec_task (c);
}
break;
else if (r == 1)
{
c->state = STATE_ESTABLISHED;
- c->mask = Z3950_SELECT_READ|Z3950_SELECT_WRITE;
+ c->mask = Z3950_SELECT_READ|Z3950_SELECT_WRITE|Z3950_SELECT_EXCEPT;
}
else
{
c->state = STATE_ESTABLISHED;
- c->mask = Z3950_SELECT_READ;
+ c->mask = Z3950_SELECT_READ|Z3950_SELECT_EXCEPT;
}
return 0;
}
const char *Z3950_connection_option (Z3950_connection c, const char *key,
const char *val)
{
- const char *old_val = Z3950_options_get (c->options, key);
if (val)
{
Z3950_options_set (c->options, key, val);
+ return val;
}
- return old_val;
+ return Z3950_options_get (c->options, key);
}
const char *Z3950_resultset_option (Z3950_resultset r, const char *key,
const char *val)
{
- const char *old_val = Z3950_options_get (r->options, key);
if (val)
{
Z3950_options_set (r->options, key, val);
+ return val;
}
- return old_val;
+ return Z3950_options_get (r->options, key);
}
int Z3950_connection_do_io(Z3950_connection c, int mask)
{
+ Z3950_Event event;
#if 0
int r = cs_look(c->cs);
yaz_log (LOG_LOG, "Z3950_connection_do_io c=%p mask=%d cs_look=%d",
do_close (c);
}
#endif
- c->event_pending = 1;
+ event = Z3950_Event_create (1);
+ Z3950_connection_put_event (c, event);
return 1;
}
+
int Z3950_event (int no, Z3950_connection *cs)
{
+#if HAVE_SYS_POLL_H
+ struct pollfd pollfds[1024];
+ Z3950_connection poll_cs[1024];
+#else
struct timeval tv;
- fd_set input, output;
- int i, r;
+ fd_set input, output, except;
+#endif
+ int i, r, nfds;
int max_fd = 0;
for (i = 0; i<no; i++)
{
Z3950_connection c = cs[i];
- if (c && c->event_pending)
- {
- c->event_pending = 0;
+ Z3950_Event event;
+ if (c && (event = Z3950_connection_get_event(c)))
+ {
+ Z3950_Event_destroy (event);
return i+1;
- }
+ }
+ }
+ for (i = 0; i<no; i++)
+ {
+ Z3950_connection c = cs[i];
+ if (c && Z3950_connection_exec_task (c))
+ return i+1;
}
+#if HAVE_SYS_POLL_H
+#else
tv.tv_sec = 15;
tv.tv_usec = 0;
FD_ZERO (&input);
FD_ZERO (&output);
- r = 0;
+ FD_ZERO (&except);
+#endif
+ nfds = 0;
for (i = 0; i<no; i++)
{
Z3950_connection c = cs[i];
continue;
if (max_fd < fd)
max_fd = fd;
+
+#if HAVE_SYS_POLL_H
+ if (mask)
+ {
+ short poll_events = 0;
+
+ if (mask & Z3950_SELECT_READ)
+ poll_events += POLLIN;
+ if (mask & Z3950_SELECT_WRITE)
+ poll_events += POLLOUT;
+ if (mask & Z3950_SELECT_EXCEPT)
+ poll_events += POLLERR;
+ pollfds[nfds].fd = fd;
+ pollfds[nfds].events = poll_events;
+ pollfds[nfds].revents = 0;
+ poll_cs[nfds] = c;
+ nfds++;
+ }
+#else
if (mask & Z3950_SELECT_READ)
{
FD_SET (fd, &input);
- r++;
+ nfds++;
}
if (mask & Z3950_SELECT_WRITE)
{
FD_SET (fd, &output);
- r++;
+ nfds++;
}
- }
- if (!r)
- {
- for (i = 0; i<no; i++)
+ if (mask & Z3950_SELECT_EXCEPT)
{
- Z3950_connection c = cs[i];
- if (!c)
- continue;
- if (!c->cs && c->host_port && c->error == Z3950_ERROR_NONE)
- {
- do_connect (c);
- return i+1;
- }
- else
- {
- if (Z3950_connection_exec_task (c))
- return i+1;
- }
+ FD_SET (fd, &except);
+ nfds++;
}
- yaz_log (LOG_DEBUG, "no more events");
- return 0;
+#endif
}
- r = select (max_fd+1, &input, &output, 0, &tv);
-
+ if (!nfds)
+ return 0;
+#if HAVE_SYS_POLL_H
+ yaz_log (LOG_LOG, "poll start");
+ r = poll (pollfds, nfds, 15000);
+ yaz_log (LOG_LOG, "poll stop, returned r=%d", r);
+ for (i = 0; i<nfds; i++)
+ {
+ Z3950_connection c = poll_cs[i];
+ if (r && c->mask)
+ {
+ int mask = 0;
+ if (pollfds[i].revents & POLLIN)
+ mask += Z3950_SELECT_READ;
+ if (pollfds[i].revents & POLLOUT)
+ mask += Z3950_SELECT_WRITE;
+ if (pollfds[i].revents & POLLERR)
+ mask += Z3950_SELECT_EXCEPT;
+ if (mask)
+ Z3950_connection_do_io(c, mask);
+ }
+ else if (r == 0 && c->mask)
+ {
+ Z3950_Event event = Z3950_Event_create(0);
+ /* timeout and this connection was waiting */
+ c->error = Z3950_ERROR_TIMEOUT;
+ do_close (c);
+ Z3950_connection_put_event(c, event);
+ }
+ }
+#else
+ yaz_log (LOG_DEBUG, "select start");
+ r = select (max_fd+1, &input, &output, &except, &tv);
+ yaz_log (LOG_DEBUG, "select stop, returned r=%d", r);
for (i = 0; i<no; i++)
{
Z3950_connection c = cs[i];
mask += Z3950_SELECT_READ;
if (FD_ISSET(fd, &output))
mask += Z3950_SELECT_WRITE;
+ if (FD_ISSET(fd, &except))
+ mask += Z3950_SELECT_EXCEPT;
if (mask)
Z3950_connection_do_io(c, mask);
}
if (r == 0 && c->mask)
{
+ Z3950_Event event = Z3950_Event_create(0);
/* timeout and this connection was waiting */
c->error = Z3950_ERROR_TIMEOUT;
- c->event_pending = 1;
+ do_close (c);
+ yaz_log (LOG_LOG, "timeout");
+ Z3950_connection_put_event(c, event);
}
}
+#endif
for (i = 0; i<no; i++)
{
Z3950_connection c = cs[i];
- if (!c)
- continue;
- if (c->event_pending)
- {
- c->event_pending = 0;
+ Z3950_Event event;
+ if (c && (event = Z3950_connection_get_event(c)))
+ {
+ Z3950_Event_destroy (event);
return i+1;
- }
+ }
}
return 0;
}