2 * $Id: zoom-c.c,v 1.41 2002-08-24 09:28:30 oleg Exp $
4 * ZOOM layer for C, connections, result sets, queries.
7 #include <yaz/xmalloc.h>
8 #include <yaz/otherinfo.h>
10 #include <yaz/pquery.h>
11 #include <yaz/diagbib1.h>
12 #include <yaz/charneg.h>
21 static int ZOOM_connection_send_init (ZOOM_connection c);
22 static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out);
24 static ZOOM_Event ZOOM_Event_create (int kind)
26 ZOOM_Event event = (ZOOM_Event) xmalloc (sizeof(*event));
33 static void ZOOM_Event_destroy (ZOOM_Event event)
38 static void ZOOM_connection_put_event (ZOOM_connection c, ZOOM_Event event)
42 c->m_queue_back->prev = event;
43 assert (c->m_queue_front);
47 assert (!c->m_queue_front);
48 c->m_queue_front = event;
50 event->next = c->m_queue_back;
52 c->m_queue_back = event;
55 static ZOOM_Event ZOOM_connection_get_event(ZOOM_connection c)
57 ZOOM_Event event = c->m_queue_front;
60 assert (c->m_queue_back);
61 c->m_queue_front = event->prev;
64 assert (c->m_queue_back);
65 c->m_queue_front->next = 0;
69 c->last_event = event->kind;
73 static void clear_error (ZOOM_connection c)
78 case ZOOM_ERROR_CONNECT:
79 case ZOOM_ERROR_MEMORY:
80 case ZOOM_ERROR_DECODE:
81 case ZOOM_ERROR_CONNECTION_LOST:
83 case ZOOM_ERROR_INTERNAL:
86 c->error = ZOOM_ERROR_NONE;
92 ZOOM_task ZOOM_connection_add_task (ZOOM_connection c, int which)
94 ZOOM_task *taskp = &c->tasks;
96 taskp = &(*taskp)->next;
97 *taskp = (ZOOM_task) xmalloc (sizeof(**taskp));
98 (*taskp)->running = 0;
99 (*taskp)->which = which;
105 ZOOM_task ZOOM_connection_insert_task (ZOOM_connection c, int which)
107 ZOOM_task task = (ZOOM_task) xmalloc (sizeof(*task));
109 task->next = c->tasks;
118 void ZOOM_connection_remove_task (ZOOM_connection c)
120 ZOOM_task task = c->tasks;
124 c->tasks = task->next;
127 case ZOOM_TASK_SEARCH:
128 ZOOM_resultset_destroy (task->u.search.resultset);
130 case ZOOM_TASK_RETRIEVE:
131 ZOOM_resultset_destroy (task->u.retrieve.resultset);
133 case ZOOM_TASK_CONNECT:
136 ZOOM_scanset_destroy (task->u.scan.scan);
138 case ZOOM_TASK_PACKAGE:
139 ZOOM_package_destroy (task->u.package);
146 Fix me!!! May be it is not right place for reset of the ODR stream,
147 but if happens to read records from cache we will be get memory leaks
148 without it (see send_present()).
150 odr_reset(c->odr_out);
154 void ZOOM_connection_remove_tasks (ZOOM_connection c)
157 ZOOM_connection_remove_task(c);
160 static ZOOM_record record_cache_lookup (ZOOM_resultset r, int pos);
162 ZOOM_API(ZOOM_connection)
163 ZOOM_connection_create (ZOOM_options options)
165 ZOOM_connection c = (ZOOM_connection) xmalloc (sizeof(*c));
170 c->state = STATE_IDLE;
171 c->error = ZOOM_ERROR_NONE;
179 c->options = ZOOM_options_create_with_parent(options);
184 c->charset = c->lang = 0;
191 c->odr_in = odr_createmem (ODR_DECODE);
192 c->odr_out = odr_createmem (ODR_ENCODE);
195 c->support_named_resultsets = 0;
196 c->last_event = ZOOM_EVENT_NONE;
198 c->m_queue_front = 0;
203 /* set database names. Take local databases (if set); otherwise
204 take databases given in ZURL (if set); otherwise use Default */
205 static char **set_DatabaseNames (ZOOM_connection con, ZOOM_options options,
208 char **databaseNames;
211 const char *cp = ZOOM_options_get (options, "databaseName");
215 if (strncmp (con->host_port, "unix:", 5) == 0)
216 cp = strchr (con->host_port+5, ':');
218 cp = strchr (con->host_port, '/');
225 while ((c = strchr(c, '+')))
233 databaseNames = (char**)
234 odr_malloc (con->odr_out, no * sizeof(*databaseNames));
238 c = strchr (cp, '+');
246 /* cp ptr to first char of db name, c is char
248 databaseNames[no] = (char*) odr_malloc (con->odr_out, 1+c-cp);
249 memcpy (databaseNames[no], cp, c-cp);
250 databaseNames[no++][c-cp] = '\0';
255 databaseNames[no] = NULL;
257 return databaseNames;
260 ZOOM_API(ZOOM_connection)
261 ZOOM_connection_new (const char *host, int portnum)
263 ZOOM_connection c = ZOOM_connection_create (0);
265 ZOOM_connection_connect (c, host, portnum);
270 ZOOM_connection_connect(ZOOM_connection c,
271 const char *host, int portnum)
278 yaz_log (LOG_DEBUG, "reconnect");
282 yaz_log(LOG_DEBUG, "connect");
284 val = ZOOM_options_get (c->options, "proxy");
286 c->proxy = xstrdup (val);
291 val = ZOOM_options_get (c->options, "charset");
293 c->charset = xstrdup (val);
298 val = ZOOM_options_get (c->options, "lang");
300 c->lang = xstrdup (val);
304 xfree (c->host_port);
308 sprintf (hostn, "%.80s:%d", host, portnum);
309 c->host_port = xstrdup(hostn);
312 c->host_port = xstrdup(host);
314 ZOOM_options_set(c->options, "host", c->host_port);
316 val = ZOOM_options_get (c->options, "cookie");
318 c->cookie_out = xstrdup (val);
320 val = ZOOM_options_get (c->options, "clientIP");
322 c->client_IP = xstrdup (val);
324 c->async = ZOOM_options_get_bool (c->options, "async", 0);
326 c->error = ZOOM_ERROR_NONE;
328 task = ZOOM_connection_add_task (c, ZOOM_TASK_CONNECT);
332 while (ZOOM_event (1, &c))
338 ZOOM_query_create(void)
340 ZOOM_query s = (ZOOM_query) xmalloc (sizeof(*s));
345 s->odr = odr_createmem (ODR_ENCODE);
351 ZOOM_query_destroy(ZOOM_query s)
357 yaz_log (LOG_DEBUG, "ZOOM_query_destroy count=%d", s->refcount);
358 if (s->refcount == 0)
360 odr_destroy (s->odr);
366 ZOOM_query_prefix(ZOOM_query s, const char *str)
368 s->query = (Z_Query *) odr_malloc (s->odr, sizeof(*s->query));
369 s->query->which = Z_Query_type_1;
370 s->query->u.type_1 = p_query_rpn(s->odr, PROTO_Z3950, str);
371 if (!s->query->u.type_1)
377 ZOOM_query_sortby(ZOOM_query s, const char *criteria)
379 s->sort_spec = yaz_sort_spec (s->odr, criteria);
385 static int do_write(ZOOM_connection c);
388 ZOOM_connection_destroy(ZOOM_connection c)
395 for (r = c->resultsets; r; r = r->next)
400 odr_destroy (c->odr_in);
401 odr_destroy (c->odr_out);
402 ZOOM_options_destroy (c->options);
403 ZOOM_connection_remove_tasks (c);
404 xfree (c->host_port);
408 xfree (c->cookie_out);
409 xfree (c->cookie_in);
410 xfree (c->client_IP);
414 void ZOOM_resultset_addref (ZOOM_resultset r)
419 ZOOM_resultset ZOOM_resultset_create ()
421 ZOOM_resultset r = (ZOOM_resultset) xmalloc (sizeof(*r));
425 r->odr = odr_createmem (ODR_ENCODE);
439 ZOOM_API(ZOOM_resultset)
440 ZOOM_connection_search_pqf(ZOOM_connection c, const char *q)
443 ZOOM_query s = ZOOM_query_create();
445 ZOOM_query_prefix (s, q);
447 r = ZOOM_connection_search (c, s);
448 ZOOM_query_destroy (s);
452 ZOOM_API(ZOOM_resultset)
453 ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
455 ZOOM_resultset r = ZOOM_resultset_create ();
459 r->r_sort_spec = q->sort_spec;
460 r->r_query = q->query;
463 r->options = ZOOM_options_create_with_parent(c->options);
465 r->start = ZOOM_options_get_int(r->options, "start", 0);
466 r->count = ZOOM_options_get_int(r->options, "count", 0);
467 r->piggyback = ZOOM_options_get_bool (r->options, "piggyback", 1);
468 cp = ZOOM_options_get (r->options, "setname");
470 r->setname = xstrdup (cp);
474 r->next = c->resultsets;
477 task = ZOOM_connection_add_task (c, ZOOM_TASK_SEARCH);
478 task->u.search.resultset = r;
479 ZOOM_resultset_addref (r);
485 while (ZOOM_event (1, &c))
492 ZOOM_resultset_destroy(ZOOM_resultset r)
497 yaz_log (LOG_DEBUG, "destroy r = %p count=%d", r, r->refcount);
498 if (r->refcount == 0)
500 ZOOM_record_cache rc;
502 for (rc = r->record_cache; rc; rc = rc->next)
503 if (rc->rec.wrbuf_marc)
504 wrbuf_free (rc->rec.wrbuf_marc, 1);
507 /* remove ourselves from the resultsets in connection */
508 ZOOM_resultset *rp = &r->connection->resultsets;
511 assert (*rp); /* we must be in this list!! */
513 { /* OK, we're here - take us out of it */
520 ZOOM_query_destroy (r->search);
521 ZOOM_options_destroy (r->options);
522 odr_destroy (r->odr);
529 ZOOM_resultset_size (ZOOM_resultset r)
534 static void do_close (ZOOM_connection c)
540 c->state = STATE_IDLE;
543 static void ZOOM_resultset_retrieve (ZOOM_resultset r,
544 int force_sync, int start, int count)
554 task = ZOOM_connection_add_task (c, ZOOM_TASK_RETRIEVE);
555 task->u.retrieve.resultset = r;
556 task->u.retrieve.start = start;
557 task->u.retrieve.count = count;
559 ZOOM_resultset_addref (r);
561 if (!r->connection->async || force_sync)
562 while (r->connection && ZOOM_event (1, &r->connection))
567 ZOOM_resultset_records (ZOOM_resultset r, ZOOM_record *recs,
568 size_t start, size_t count)
570 int force_present = 0;
576 ZOOM_resultset_retrieve (r, force_present, start, count);
580 for (i = 0; i< count; i++)
581 recs[i] = ZOOM_resultset_record_immediate (r, i+start);
585 static int do_connect (ZOOM_connection c)
588 const char *effective_host;
591 effective_host = c->proxy;
593 effective_host = c->host_port;
595 yaz_log (LOG_DEBUG, "do_connect host=%s", effective_host);
598 c->cs = cs_create_host (effective_host, 0, &add);
602 int ret = cs_connect (c->cs, add);
605 ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
606 ZOOM_connection_put_event(c, event);
607 ZOOM_connection_send_init(c);
608 c->state = STATE_ESTABLISHED;
613 c->state = STATE_CONNECTING;
614 c->mask = ZOOM_SELECT_EXCEPT;
615 if (c->cs->io_pending & CS_WANT_WRITE)
616 c->mask += ZOOM_SELECT_WRITE;
617 if (c->cs->io_pending & CS_WANT_READ)
618 c->mask += ZOOM_SELECT_READ;
622 c->state = STATE_IDLE;
623 c->error = ZOOM_ERROR_CONNECT;
627 int z3950_connection_socket(ZOOM_connection c)
630 return cs_fileno(c->cs);
634 int z3950_connection_mask(ZOOM_connection c)
641 static void otherInfo_attach (ZOOM_connection c, Z_APDU *a, ODR out)
644 for (i = 0; i<200; i++)
647 Z_OtherInformation **oi;
653 sprintf (buf, "otherInfo%d", i);
654 val = ZOOM_options_get (c->options, buf);
657 cp = strchr (val, ':');
661 if (len >= sizeof(buf))
663 memcpy (buf, val, len);
665 oidval = oid_getvalbyname (buf);
666 if (oidval == VAL_NONE)
670 yaz_oi_set_string_oidval(oi, out, oidval, 1, cp+1);
674 static int encode_APDU(ZOOM_connection c, Z_APDU *a, ODR out)
679 Z_OtherInformation **oi;
681 yaz_oi_set_string_oidval(oi, out, VAL_COOKIE, 1, c->cookie_out);
685 Z_OtherInformation **oi;
687 yaz_oi_set_string_oidval(oi, out, VAL_CLIENT_IP, 1, c->client_IP);
689 otherInfo_attach (c, a, out);
690 if (!z_APDU(out, &a, 0, 0))
692 FILE *outf = fopen("/tmp/apdu.txt", "a");
695 ODR odr_pr = odr_createmem(ODR_PRINT);
696 fprintf (outf, "a=%p\n", a);
697 odr_setprint(odr_pr, outf);
698 z_APDU(odr_pr, &a, 0, 0);
701 c->error = ZOOM_ERROR_ENCODE;
709 static int send_APDU (ZOOM_connection c, Z_APDU *a)
713 if (encode_APDU(c, a, c->odr_out))
715 c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
716 event = ZOOM_Event_create (ZOOM_EVENT_SEND_APDU);
717 ZOOM_connection_put_event (c, event);
718 odr_reset(c->odr_out);
723 static int ZOOM_connection_send_init (ZOOM_connection c)
726 Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_initRequest);
727 Z_InitRequest *ireq = apdu->u.initRequest;
728 Z_IdAuthentication *auth = (Z_IdAuthentication *)
729 odr_malloc(c->odr_out, sizeof(*auth));
730 const char *auth_groupId = ZOOM_options_get (c->options, "group");
731 const char *auth_userId = ZOOM_options_get (c->options, "user");
732 const char *auth_password = ZOOM_options_get (c->options, "pass");
734 ODR_MASK_SET(ireq->options, Z_Options_search);
735 ODR_MASK_SET(ireq->options, Z_Options_present);
736 ODR_MASK_SET(ireq->options, Z_Options_scan);
737 ODR_MASK_SET(ireq->options, Z_Options_sort);
738 ODR_MASK_SET(ireq->options, Z_Options_extendedServices);
739 ODR_MASK_SET(ireq->options, Z_Options_namedResultSets);
741 ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_1);
742 ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2);
743 ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3);
745 impname = ZOOM_options_get (c->options, "implementationName");
746 ireq->implementationName =
747 (char *) odr_malloc (c->odr_out, 15 + (impname ? strlen(impname) : 0));
748 strcpy (ireq->implementationName, "");
751 strcat (ireq->implementationName, impname);
752 strcat (ireq->implementationName, "/");
754 strcat (ireq->implementationName, "ZOOM-C/YAZ");
756 *ireq->maximumRecordSize =
757 ZOOM_options_get_int (c->options, "maximumRecordSize", 1024*1024);
758 *ireq->preferredMessageSize =
759 ZOOM_options_get_int (c->options, "preferredMessageSize", 1024*1024);
761 if (auth_groupId || auth_password)
763 Z_IdPass *pass = (Z_IdPass *) odr_malloc(c->odr_out, sizeof(*pass));
766 if (auth_groupId && *auth_groupId)
768 pass->groupId = (char *)
769 odr_malloc(c->odr_out, strlen(auth_groupId)+1);
770 strcpy(pass->groupId, auth_groupId);
774 if (auth_userId && *auth_userId)
776 pass->userId = (char *)
777 odr_malloc(c->odr_out, strlen(auth_userId)+1);
778 strcpy(pass->userId, auth_userId);
782 if (auth_password && *auth_password)
784 pass->password = (char *)
785 odr_malloc(c->odr_out, strlen(auth_password)+1);
786 strcpy(pass->password, auth_password);
791 auth->which = Z_IdAuthentication_idPass;
792 auth->u.idPass = pass;
793 ireq->idAuthentication = auth;
796 else if (auth_userId)
798 auth->which = Z_IdAuthentication_open;
799 auth->u.open = (char *)
800 odr_malloc(c->odr_out, strlen(auth_userId)+1);
801 strcpy(auth->u.open, auth_userId);
802 ireq->idAuthentication = auth;
805 yaz_oi_set_string_oidval(&ireq->otherInfo, c->odr_out,
806 VAL_PROXY, 1, c->host_port);
807 if (c->charset||c->lang)
809 Z_OtherInformation **oi;
810 Z_OtherInformationUnit *oi_unit;
812 yaz_oi_APDU(apdu, &oi);
814 if ((oi_unit = yaz_oi_update(oi, c->odr_out, NULL, 0, 0)))
816 ODR_MASK_SET(ireq->options, Z_Options_negotiationModel);
818 oi_unit->which = Z_OtherInfo_externallyDefinedInfo;
819 oi_unit->information.externallyDefinedInfo =
820 yaz_set_proposal_charneg
822 (const char **)&c->charset, (c->charset) ? 1:0,
823 (const char **)&c->lang, (c->lang) ? 1:0, 1);
832 static int ZOOM_connection_send_search (ZOOM_connection c)
835 int lslb, ssub, mspn;
837 Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_searchRequest);
838 Z_SearchRequest *search_req = apdu->u.searchRequest;
839 const char *elementSetName;
840 const char *smallSetElementSetName;
841 const char *mediumSetElementSetName;
845 assert (c->tasks->which == ZOOM_TASK_SEARCH);
847 r = c->tasks->u.search.resultset;
850 ZOOM_options_get (r->options, "elementSetName");
851 smallSetElementSetName =
852 ZOOM_options_get (r->options, "smallSetElementSetName");
853 mediumSetElementSetName =
854 ZOOM_options_get (r->options, "mediumSetElementSetName");
856 ZOOM_options_get (r->options, "schema");
858 if (!smallSetElementSetName)
859 smallSetElementSetName = elementSetName;
861 if (!mediumSetElementSetName)
862 mediumSetElementSetName = elementSetName;
867 /* prepare query for the search request */
868 search_req->query = r->r_query;
870 search_req->databaseNames =
871 set_DatabaseNames (c, r->options, &search_req->num_databaseNames);
873 /* get syntax (no need to provide unless piggyback is in effect) */
874 syntax = ZOOM_options_get (r->options, "preferredRecordSyntax");
876 lslb = ZOOM_options_get_int (r->options, "largeSetLowerBound", -1);
877 ssub = ZOOM_options_get_int (r->options, "smallSetUpperBound", -1);
878 mspn = ZOOM_options_get_int (r->options, "mediumSetPresentNumber", -1);
879 if (lslb != -1 && ssub != -1 && mspn != -1)
881 /* So're a Z39.50 expert? Let's hope you don't do sort */
882 *search_req->largeSetLowerBound = lslb;
883 *search_req->smallSetUpperBound = ssub;
884 *search_req->mediumSetPresentNumber = mspn;
886 else if (r->start == 0 && r->count > 0
887 && r->piggyback && !r->r_sort_spec && !schema)
889 /* Regular piggyback - do it unless we're going to do sort */
890 *search_req->largeSetLowerBound = 2000000000;
891 *search_req->smallSetUpperBound = r->count;
892 *search_req->mediumSetPresentNumber = r->count;
893 smallSetElementSetName = 0; /* no need to provide this */
897 /* non-piggyback. Need not provide elementsets or syntaxes .. */
898 smallSetElementSetName = 0;
899 mediumSetElementSetName = 0;
902 if (smallSetElementSetName && *smallSetElementSetName)
904 Z_ElementSetNames *esn = (Z_ElementSetNames *)
905 odr_malloc (c->odr_out, sizeof(*esn));
907 esn->which = Z_ElementSetNames_generic;
908 esn->u.generic = odr_strdup (c->odr_out, smallSetElementSetName);
909 search_req->smallSetElementSetNames = esn;
911 if (mediumSetElementSetName && *mediumSetElementSetName)
913 Z_ElementSetNames *esn = (Z_ElementSetNames *)
914 odr_malloc (c->odr_out, sizeof(*esn));
916 esn->which = Z_ElementSetNames_generic;
917 esn->u.generic = odr_strdup (c->odr_out, mediumSetElementSetName);
918 search_req->mediumSetElementSetNames = esn;
921 search_req->preferredRecordSyntax =
922 yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
926 if (c->support_named_resultsets)
930 /* find the lowest unused ordinal so that we re-use
931 result sets on the server. */
932 for (ord = 1; ; ord++)
935 sprintf (setname, "%d", ord);
936 for (rp = c->resultsets; rp; rp = rp->next)
937 if (rp->setname && !strcmp (rp->setname, setname))
942 r->setname = xstrdup (setname);
943 yaz_log (LOG_DEBUG, "allocating %s", r->setname);
946 r->setname = xstrdup ("default");
947 ZOOM_options_set (r->options, "setname", r->setname);
949 search_req->resultSetName = odr_strdup(c->odr_out, r->setname);
950 /* send search request */
955 static void response_diag (ZOOM_connection c, Z_DiagRec *p)
957 Z_DefaultDiagFormat *r;
962 if (p->which != Z_DiagRec_defaultFormat)
964 c->error = ZOOM_ERROR_DECODE;
967 r = p->u.defaultFormat;
970 case Z_DefaultDiagFormat_v2Addinfo:
971 addinfo = r->u.v2Addinfo;
973 case Z_DefaultDiagFormat_v3Addinfo:
974 addinfo = r->u.v3Addinfo;
978 c->addinfo = xstrdup (addinfo);
979 c->error = *r->condition;
982 ZOOM_API(ZOOM_record)
983 ZOOM_record_clone (ZOOM_record srec)
990 odr_enc = odr_createmem(ODR_ENCODE);
991 if (!z_NamePlusRecord (odr_enc, &srec->npr, 0, 0))
993 buf = odr_getbuf (odr_enc, &size, 0);
995 nrec = (ZOOM_record) xmalloc (sizeof(*nrec));
996 nrec->odr = odr_createmem(ODR_DECODE);
997 nrec->wrbuf_marc = 0;
998 odr_setbuf (nrec->odr, buf, size, 0);
999 z_NamePlusRecord (nrec->odr, &nrec->npr, 0, 0);
1001 odr_destroy (odr_enc);
1005 ZOOM_API(ZOOM_record)
1006 ZOOM_resultset_record_immediate (ZOOM_resultset s,size_t pos)
1008 return record_cache_lookup (s, pos);
1011 ZOOM_API(ZOOM_record)
1012 ZOOM_resultset_record (ZOOM_resultset r, size_t pos)
1014 ZOOM_resultset_retrieve (r, 1, pos, 1);
1015 return ZOOM_resultset_record_immediate (r, pos);
1019 ZOOM_record_destroy (ZOOM_record rec)
1023 if (rec->wrbuf_marc)
1024 wrbuf_free (rec->wrbuf_marc, 1);
1025 odr_destroy (rec->odr);
1029 ZOOM_API(const char *)
1030 ZOOM_record_get (ZOOM_record rec, const char *type, int *len)
1032 Z_NamePlusRecord *npr;
1035 *len = 0; /* default return */
1042 if (!strcmp (type, "database"))
1045 *len = strlen(npr->databaseName);
1046 return npr->databaseName;
1048 else if (!strcmp (type, "syntax"))
1050 if (npr->which == Z_NamePlusRecord_databaseRecord)
1052 Z_External *r = (Z_External *) npr->u.databaseRecord;
1053 oident *ent = oid_getentbyoid(r->direct_reference);
1057 *len = strlen(ent->desc);
1063 else if (!strcmp (type, "render") &&
1064 npr->which == Z_NamePlusRecord_databaseRecord)
1066 Z_External *r = (Z_External *) npr->u.databaseRecord;
1067 oident *ent = oid_getentbyoid(r->direct_reference);
1069 if (r->which == Z_External_sutrs)
1071 if (len) *len = r->u.sutrs->len;
1072 return (const char *) r->u.sutrs->buf;
1074 else if (r->which == Z_External_octet)
1083 case VAL_APPLICATION_XML:
1086 if (!rec->wrbuf_marc)
1087 rec->wrbuf_marc = wrbuf_alloc();
1088 wrbuf_rewind (rec->wrbuf_marc);
1089 if (yaz_marc_decode ((const char *)
1090 r->u.octet_aligned->buf,
1092 r->u.octet_aligned->len,
1095 if (len) *len = wrbuf_len(rec->wrbuf_marc);
1096 return wrbuf_buf(rec->wrbuf_marc);
1099 if (len) *len = r->u.octet_aligned->len;
1100 return (const char *) r->u.octet_aligned->buf;
1102 else if (r->which == Z_External_grs1)
1109 else if (!strcmp (type, "xml") &&
1110 npr->which == Z_NamePlusRecord_databaseRecord)
1112 Z_External *r = (Z_External *) npr->u.databaseRecord;
1113 oident *ent = oid_getentbyoid(r->direct_reference);
1115 if (r->which == Z_External_sutrs)
1117 if (len) *len = r->u.sutrs->len;
1118 return (const char *) r->u.sutrs->buf;
1120 else if (r->which == Z_External_octet)
1129 case VAL_APPLICATION_XML:
1132 if (!rec->wrbuf_marc)
1133 rec->wrbuf_marc = wrbuf_alloc();
1134 wrbuf_rewind (rec->wrbuf_marc);
1135 if (yaz_marc_decode ((const char *)
1136 r->u.octet_aligned->buf,
1138 r->u.octet_aligned->len,
1141 if (len) *len = wrbuf_len(rec->wrbuf_marc);
1142 return wrbuf_buf(rec->wrbuf_marc);
1145 if (len) *len = r->u.octet_aligned->len;
1146 return (const char *) r->u.octet_aligned->buf;
1148 else if (r->which == Z_External_grs1)
1155 else if (!strcmp (type, "raw"))
1157 if (npr->which == Z_NamePlusRecord_databaseRecord)
1159 Z_External *r = (Z_External *) npr->u.databaseRecord;
1161 if (r->which == Z_External_sutrs)
1163 if (len) *len = r->u.sutrs->len;
1164 return (const char *) r->u.sutrs->buf;
1166 else if (r->which == Z_External_octet)
1168 if (len) *len = r->u.octet_aligned->len;
1169 return (const char *) r->u.octet_aligned->buf;
1171 else /* grs-1, explain, ... */
1174 return (const char *) npr->u.databaseRecord;
1179 else if (!strcmp (type, "ext"))
1181 if (npr->which == Z_NamePlusRecord_databaseRecord)
1182 return (const char *) npr->u.databaseRecord;
1188 static void record_cache_add (ZOOM_resultset r, Z_NamePlusRecord *npr, int pos)
1190 ZOOM_record_cache rc;
1191 const char *elementSetName =
1192 ZOOM_resultset_option_get (r, "elementSetName");
1193 const char *syntax =
1194 ZOOM_resultset_option_get (r, "preferredRecordSyntax");
1197 for (rc = r->record_cache; rc; rc = rc->next)
1201 if ((!elementSetName && !rc->elementSetName)
1202 || (elementSetName && rc->elementSetName &&
1203 !strcmp (elementSetName, rc->elementSetName)))
1205 if ((!syntax && !rc->syntax)
1206 || (syntax && rc->syntax &&
1207 !strcmp (syntax, rc->syntax)))
1209 /* not destroying rc->npr (it's handled by nmem )*/
1211 /* keeping wrbuf_marc too */
1217 rc = (ZOOM_record_cache) odr_malloc (r->odr, sizeof(*rc));
1220 rc->rec.wrbuf_marc = 0;
1222 rc->elementSetName = odr_strdup (r->odr, elementSetName);
1224 rc->elementSetName = 0;
1227 rc->syntax = odr_strdup (r->odr, syntax);
1232 rc->next = r->record_cache;
1233 r->record_cache = rc;
1236 static ZOOM_record record_cache_lookup (ZOOM_resultset r, int pos)
1238 ZOOM_record_cache rc;
1239 const char *elementSetName =
1240 ZOOM_resultset_option_get (r, "elementSetName");
1241 const char *syntax =
1242 ZOOM_resultset_option_get (r, "preferredRecordSyntax");
1244 for (rc = r->record_cache; rc; rc = rc->next)
1248 if ((!elementSetName && !rc->elementSetName)
1249 || (elementSetName && rc->elementSetName &&
1250 !strcmp (elementSetName, rc->elementSetName)))
1252 if ((!syntax && !rc->syntax)
1253 || (syntax && rc->syntax &&
1254 !strcmp (syntax, rc->syntax)))
1262 static void handle_records (ZOOM_connection c, Z_Records *sr,
1265 ZOOM_resultset resultset;
1269 switch (c->tasks->which)
1271 case ZOOM_TASK_SEARCH:
1272 resultset = c->tasks->u.search.resultset;
1274 case ZOOM_TASK_RETRIEVE:
1275 resultset = c->tasks->u.retrieve.resultset;
1280 if (sr && sr->which == Z_Records_NSD)
1282 Z_DiagRec dr, *dr_p = &dr;
1283 dr.which = Z_DiagRec_defaultFormat;
1284 dr.u.defaultFormat = sr->u.nonSurrogateDiagnostic;
1286 response_diag (c, dr_p);
1288 else if (sr && sr->which == Z_Records_multipleNSD)
1290 if (sr->u.multipleNonSurDiagnostics->num_diagRecs >= 1)
1291 response_diag(c, sr->u.multipleNonSurDiagnostics->diagRecs[0]);
1293 c->error = ZOOM_ERROR_DECODE;
1297 if (resultset->count + resultset->start > resultset->size)
1298 resultset->count = resultset->size - resultset->start;
1299 if (resultset->count < 0)
1300 resultset->count = 0;
1301 if (sr && sr->which == Z_Records_DBOSD)
1304 NMEM nmem = odr_extract_mem (c->odr_in);
1305 Z_NamePlusRecordList *p =
1306 sr->u.databaseOrSurDiagnostics;
1307 for (i = 0; i<p->num_records; i++)
1309 record_cache_add (resultset, p->records[i],
1310 i+ resultset->start);
1312 /* transfer our response to search_nmem .. we need it later */
1313 nmem_transfer (resultset->odr->mem, nmem);
1314 nmem_destroy (nmem);
1315 if (present_phase && p->num_records == 0)
1317 /* present response and we didn't get any records! */
1318 c->error = ZOOM_ERROR_DECODE;
1321 else if (present_phase)
1323 /* present response and we didn't get any records! */
1324 c->error = ZOOM_ERROR_DECODE;
1329 static void handle_present_response (ZOOM_connection c, Z_PresentResponse *pr)
1331 handle_records (c, pr->records, 1);
1334 static void handle_search_response (ZOOM_connection c, Z_SearchResponse *sr)
1336 ZOOM_resultset resultset;
1338 yaz_log (LOG_DEBUG, "got search response");
1340 if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH)
1343 resultset = c->tasks->u.search.resultset;
1345 resultset->size = *sr->resultCount;
1346 handle_records (c, sr->records, 0);
1349 static void sort_response (ZOOM_connection c, Z_SortResponse *res)
1351 if (res->diagnostics && res->num_diagnostics > 0)
1352 response_diag (c, res->diagnostics[0]);
1355 static int scan_response (ZOOM_connection c, Z_ScanResponse *res)
1357 NMEM nmem = odr_extract_mem (c->odr_in);
1360 if (!c->tasks || c->tasks->which != ZOOM_TASK_SCAN)
1362 scan = c->tasks->u.scan.scan;
1364 if (res->entries && res->entries->nonsurrogateDiagnostics)
1365 response_diag(c, res->entries->nonsurrogateDiagnostics[0]);
1366 scan->scan_response = res;
1367 nmem_transfer (scan->odr->mem, nmem);
1369 ZOOM_options_set_int (scan->options, "stepSize", *res->stepSize);
1370 if (res->positionOfTerm)
1371 ZOOM_options_set_int (scan->options, "position", *res->positionOfTerm);
1372 if (res->scanStatus)
1373 ZOOM_options_set_int (scan->options, "scanStatus", *res->scanStatus);
1374 if (res->numberOfEntriesReturned)
1375 ZOOM_options_set_int (scan->options, "number",
1376 *res->numberOfEntriesReturned);
1377 nmem_destroy (nmem);
1381 static int send_sort (ZOOM_connection c)
1383 ZOOM_resultset resultset;
1385 if (!c->tasks || c->tasks->which != ZOOM_TASK_SEARCH)
1388 resultset = c->tasks->u.search.resultset;
1392 resultset->r_sort_spec = 0;
1395 if (resultset->r_sort_spec)
1397 Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_sortRequest);
1398 Z_SortRequest *req = apdu->u.sortRequest;
1400 req->num_inputResultSetNames = 1;
1401 req->inputResultSetNames = (Z_InternationalString **)
1402 odr_malloc (c->odr_out, sizeof(*req->inputResultSetNames));
1403 req->inputResultSetNames[0] =
1404 odr_strdup (c->odr_out, resultset->setname);
1405 req->sortedResultSetName = odr_strdup (c->odr_out, resultset->setname);
1406 req->sortSequence = resultset->r_sort_spec;
1407 resultset->r_sort_spec = 0;
1408 send_APDU (c, apdu);
1414 static int send_present (ZOOM_connection c)
1416 Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_presentRequest);
1417 Z_PresentRequest *req = apdu->u.presentRequest;
1419 const char *syntax = 0;
1420 const char *elementSetName = 0;
1421 const char *schema = 0;
1422 ZOOM_resultset resultset;
1427 switch (c->tasks->which)
1429 case ZOOM_TASK_SEARCH:
1430 resultset = c->tasks->u.search.resultset;
1432 case ZOOM_TASK_RETRIEVE:
1433 resultset = c->tasks->u.retrieve.resultset;
1434 resultset->start = c->tasks->u.retrieve.start;
1435 resultset->count = c->tasks->u.retrieve.count;
1437 if (resultset->start >= resultset->size)
1439 if (resultset->start + resultset->count > resultset->size)
1440 resultset->count = resultset->size - resultset->start;
1446 syntax = ZOOM_resultset_option_get (resultset, "preferredRecordSyntax");
1447 elementSetName = ZOOM_resultset_option_get (resultset, "elementSetName");
1448 schema = ZOOM_resultset_option_get (resultset, "schema");
1450 if (c->error) /* don't continue on error */
1452 if (resultset->start < 0)
1454 for (i = 0; i<resultset->count; i++)
1457 record_cache_lookup (resultset, i + resultset->start);
1461 if (i == resultset->count)
1464 resultset->start += i;
1465 resultset->count -= i;
1466 *req->resultSetStartPoint = resultset->start + 1;
1467 *req->numberOfRecordsRequested = resultset->count;
1468 assert (*req->numberOfRecordsRequested > 0);
1470 if (syntax && *syntax)
1471 req->preferredRecordSyntax =
1472 yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, syntax);
1474 if (schema && *schema)
1476 Z_RecordComposition *compo = (Z_RecordComposition *)
1477 odr_malloc (c->odr_out, sizeof(*compo));
1479 req->recordComposition = compo;
1480 compo->which = Z_RecordComp_complex;
1481 compo->u.complex = (Z_CompSpec *)
1482 odr_malloc(c->odr_out, sizeof(*compo->u.complex));
1483 compo->u.complex->selectAlternativeSyntax = (bool_t *)
1484 odr_malloc(c->odr_out, sizeof(bool_t));
1485 *compo->u.complex->selectAlternativeSyntax = 0;
1487 compo->u.complex->generic = (Z_Specification *)
1488 odr_malloc(c->odr_out, sizeof(*compo->u.complex->generic));
1490 compo->u.complex->generic->schema = (Odr_oid *)
1491 yaz_str_to_z3950oid (c->odr_out, CLASS_SCHEMA, schema);
1493 if (!compo->u.complex->generic->schema)
1495 /* OID wasn't a schema! Try record syntax instead. */
1497 compo->u.complex->generic->schema = (Odr_oid *)
1498 yaz_str_to_z3950oid (c->odr_out, CLASS_RECSYN, schema);
1500 if (elementSetName && *elementSetName)
1502 compo->u.complex->generic->elementSpec = (Z_ElementSpec *)
1503 odr_malloc(c->odr_out, sizeof(Z_ElementSpec));
1504 compo->u.complex->generic->elementSpec->which =
1505 Z_ElementSpec_elementSetName;
1506 compo->u.complex->generic->elementSpec->u.elementSetName =
1507 odr_strdup (c->odr_out, elementSetName);
1510 compo->u.complex->generic->elementSpec = 0;
1511 compo->u.complex->num_dbSpecific = 0;
1512 compo->u.complex->dbSpecific = 0;
1513 compo->u.complex->num_recordSyntax = 0;
1514 compo->u.complex->recordSyntax = 0;
1516 else if (elementSetName && *elementSetName)
1518 Z_ElementSetNames *esn = (Z_ElementSetNames *)
1519 odr_malloc (c->odr_out, sizeof(*esn));
1520 Z_RecordComposition *compo = (Z_RecordComposition *)
1521 odr_malloc (c->odr_out, sizeof(*compo));
1523 esn->which = Z_ElementSetNames_generic;
1524 esn->u.generic = odr_strdup (c->odr_out, elementSetName);
1525 compo->which = Z_RecordComp_simple;
1526 compo->u.simple = esn;
1527 req->recordComposition = compo;
1529 req->resultSetId = odr_strdup(c->odr_out, resultset->setname);
1530 send_APDU (c, apdu);
1534 ZOOM_API(ZOOM_scanset)
1535 ZOOM_connection_scan (ZOOM_connection c, const char *start)
1537 ZOOM_scanset scan = (ZOOM_scanset) xmalloc (sizeof(*scan));
1539 scan->connection = c;
1540 scan->odr = odr_createmem (ODR_DECODE);
1541 scan->options = ZOOM_options_create_with_parent (c->options);
1543 scan->scan_response = 0;
1545 if ((scan->termListAndStartPoint =
1546 p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet,
1549 ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_SCAN);
1550 task->u.scan.scan = scan;
1555 while (ZOOM_event (1, &c))
1563 ZOOM_scanset_destroy (ZOOM_scanset scan)
1568 if (scan->refcount == 0)
1570 odr_destroy (scan->odr);
1572 ZOOM_options_destroy (scan->options);
1577 static int send_package (ZOOM_connection c)
1582 assert (c->tasks->which == ZOOM_TASK_PACKAGE);
1584 event = ZOOM_Event_create (ZOOM_EVENT_SEND_APDU);
1585 ZOOM_connection_put_event (c, event);
1587 do_write_ex (c, c->tasks->u.package->buf_out,
1588 c->tasks->u.package->len_out);
1592 static int send_scan (ZOOM_connection c)
1595 Z_APDU *apdu = zget_APDU(c->odr_out, Z_APDU_scanRequest);
1596 Z_ScanRequest *req = apdu->u.scanRequest;
1599 assert (c->tasks->which == ZOOM_TASK_SCAN);
1600 scan = c->tasks->u.scan.scan;
1602 req->termListAndStartPoint = scan->termListAndStartPoint;
1603 req->attributeSet = scan->attributeSet;
1605 *req->numberOfTermsRequested =
1606 ZOOM_options_get_int(scan->options, "number", 10);
1608 req->preferredPositionInResponse =
1609 odr_intdup (c->odr_out,
1610 ZOOM_options_get_int(scan->options, "position", 1));
1613 odr_intdup (c->odr_out,
1614 ZOOM_options_get_int(scan->options, "stepSize", 0));
1616 req->databaseNames = set_DatabaseNames (c, scan->options,
1617 &req->num_databaseNames);
1619 send_APDU (c, apdu);
1625 ZOOM_scanset_size (ZOOM_scanset scan)
1627 if (!scan || !scan->scan_response || !scan->scan_response->entries)
1629 return scan->scan_response->entries->num_entries;
1632 ZOOM_API(const char *)
1633 ZOOM_scanset_term (ZOOM_scanset scan, size_t pos,
1636 const char *term = 0;
1637 size_t noent = ZOOM_scanset_size (scan);
1638 Z_ScanResponse *res = scan->scan_response;
1644 if (res->entries->entries[pos]->which == Z_Entry_termInfo)
1646 Z_TermInfo *t = res->entries->entries[pos]->u.termInfo;
1648 if (t->term->which == Z_Term_general)
1650 term = (const char *) t->term->u.general->buf;
1651 *len = t->term->u.general->len;
1653 *occ = t->globalOccurrences ? *t->globalOccurrences : 0;
1658 ZOOM_API(const char *)
1659 ZOOM_scanset_option_get (ZOOM_scanset scan, const char *key)
1661 return ZOOM_options_get (scan->options, key);
1665 ZOOM_scanset_option_set (ZOOM_scanset scan, const char *key,
1668 ZOOM_options_set (scan->options, key, val);
1673 static Z_APDU *create_es_package (ZOOM_package p, int type)
1676 Z_APDU *apdu = zget_APDU(p->odr_out, Z_APDU_extendedServicesRequest);
1677 Z_ExtendedServicesRequest *req = apdu->u.extendedServicesRequest;
1679 *req->function = Z_ExtendedServicesRequest_create;
1681 str = ZOOM_options_get(p->options, "package-name");
1683 req->packageName = nmem_strdup (p->odr_out->mem, str);
1685 str = ZOOM_options_get(p->options, "user-id");
1687 req->userId = nmem_strdup (p->odr_out->mem, str);
1689 req->packageType = yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
1692 str = ZOOM_options_get(p->options, "function");
1695 if (!strcmp (str, "create"))
1697 if (!strcmp (str, "delete"))
1699 if (!strcmp (str, "modify"))
1705 static const char *ill_array_lookup (void *clientData, const char *idx)
1707 ZOOM_package p = (ZOOM_package) clientData;
1708 return ZOOM_options_get (p->options, idx+4);
1711 static Z_External *encode_ill_request (ZOOM_package p)
1713 ODR out = p->odr_out;
1716 struct ill_get_ctl ctl;
1718 ctl.odr = p->odr_out;
1720 ctl.f = ill_array_lookup;
1722 req = ill_get_ILLRequest(&ctl, "ill", 0);
1724 if (!ill_Request (out, &req, 0, 0))
1726 int ill_request_size;
1727 char *ill_request_buf = odr_getbuf (out, &ill_request_size, 0);
1728 if (ill_request_buf)
1729 odr_setbuf (out, ill_request_buf, ill_request_size, 1);
1735 int illRequest_size = 0;
1736 char *illRequest_buf = odr_getbuf (out, &illRequest_size, 0);
1738 oid.proto = PROTO_GENERAL;
1739 oid.oclass = CLASS_GENERAL;
1740 oid.value = VAL_ISO_ILL_1;
1742 r = (Z_External *) odr_malloc (out, sizeof(*r));
1743 r->direct_reference = odr_oiddup(out,oid_getoidbyent(&oid));
1744 r->indirect_reference = 0;
1746 r->which = Z_External_single;
1748 r->u.single_ASN1_type = (Odr_oct *)
1749 odr_malloc (out, sizeof(*r->u.single_ASN1_type));
1750 r->u.single_ASN1_type->buf = odr_malloc (out, illRequest_size);
1751 r->u.single_ASN1_type->len = illRequest_size;
1752 r->u.single_ASN1_type->size = illRequest_size;
1753 memcpy (r->u.single_ASN1_type->buf, illRequest_buf, illRequest_size);
1758 static Z_ItemOrder *encode_item_order(ZOOM_package p)
1760 Z_ItemOrder *req = odr_malloc (p->odr_out, sizeof(*req));
1763 req->which=Z_IOItemOrder_esRequest;
1764 req->u.esRequest = (Z_IORequest *)
1765 odr_malloc(p->odr_out,sizeof(Z_IORequest));
1767 /* to keep part ... */
1768 req->u.esRequest->toKeep = (Z_IOOriginPartToKeep *)
1769 odr_malloc(p->odr_out,sizeof(Z_IOOriginPartToKeep));
1770 req->u.esRequest->toKeep->supplDescription = 0;
1771 req->u.esRequest->toKeep->contact =
1772 odr_malloc (p->odr_out, sizeof(*req->u.esRequest->toKeep->contact));
1774 str = ZOOM_options_get(p->options, "contact-name");
1775 req->u.esRequest->toKeep->contact->name = str ?
1776 nmem_strdup (p->odr_out->mem, str) : 0;
1778 str = ZOOM_options_get(p->options, "contact-phone");
1779 req->u.esRequest->toKeep->contact->phone = str ?
1780 nmem_strdup (p->odr_out->mem, str) : 0;
1782 str = ZOOM_options_get(p->options, "contact-email");
1783 req->u.esRequest->toKeep->contact->email = str ?
1784 nmem_strdup (p->odr_out->mem, str) : 0;
1786 req->u.esRequest->toKeep->addlBilling = 0;
1788 /* not to keep part ... */
1789 req->u.esRequest->notToKeep = (Z_IOOriginPartNotToKeep *)
1790 odr_malloc(p->odr_out,sizeof(Z_IOOriginPartNotToKeep));
1792 req->u.esRequest->notToKeep->resultSetItem = (Z_IOResultSetItem *)
1793 odr_malloc(p->odr_out, sizeof(Z_IOResultSetItem));
1795 str = ZOOM_options_get(p->options, "itemorder-setname");
1798 req->u.esRequest->notToKeep->resultSetItem->resultSetId =
1799 nmem_strdup (p->odr_out->mem, str);
1800 req->u.esRequest->notToKeep->resultSetItem->item =
1801 (int *) odr_malloc(p->odr_out, sizeof(int));
1803 str = ZOOM_options_get(p->options, "itemorder-item");
1804 *req->u.esRequest->notToKeep->resultSetItem->item =
1805 (str ? atoi(str) : 1);
1807 req->u.esRequest->notToKeep->itemRequest = encode_ill_request(p);
1813 ZOOM_package_send (ZOOM_package p, const char *type)
1820 odr_reset (p->odr_out);
1823 if (!strcmp(type, "itemorder"))
1826 apdu = create_es_package (p, VAL_ITEMORDER);
1829 r = odr_malloc (p->odr_out, sizeof(*r));
1831 r->direct_reference =
1832 yaz_oidval_to_z3950oid(p->odr_out, CLASS_EXTSERV,
1835 r->which = Z_External_itemOrder;
1836 r->indirect_reference = 0;
1837 r->u.itemOrder = encode_item_order (p);
1839 apdu->u.extendedServicesRequest->taskSpecificParameters = r;
1844 if (encode_APDU(p->connection, apdu, p->odr_out) == 0)
1848 ZOOM_task task = ZOOM_connection_add_task (c, ZOOM_TASK_PACKAGE);
1849 task->u.package = p;
1850 buf = odr_getbuf(p->odr_out, &p->len_out, 0);
1851 p->buf_out = xmalloc (p->len_out);
1852 memcpy (p->buf_out, buf, p->len_out);
1857 while (ZOOM_event (1, &c))
1864 ZOOM_API(ZOOM_package)
1865 ZOOM_connection_package (ZOOM_connection c, ZOOM_options options)
1867 ZOOM_package p = (ZOOM_package) xmalloc (sizeof(*p));
1870 p->odr_out = odr_createmem (ODR_ENCODE);
1871 p->options = ZOOM_options_create_with_parent2 (options, c->options);
1879 ZOOM_package_destroy(ZOOM_package p)
1884 if (p->refcount == 0)
1886 odr_destroy (p->odr_out);
1889 ZOOM_options_destroy (p->options);
1894 ZOOM_API(const char *)
1895 ZOOM_package_option_get (ZOOM_package p, const char *key)
1897 return ZOOM_options_get (p->options, key);
1901 ZOOM_package_option_set (ZOOM_package p, const char *key,
1904 ZOOM_options_set (p->options, key, val);
1907 static int ZOOM_connection_exec_task (ZOOM_connection c)
1909 ZOOM_task task = c->tasks;
1911 yaz_log (LOG_DEBUG, "ZOOM_connection_exec_task");
1914 if (c->error != ZOOM_ERROR_NONE ||
1915 (!c->cs && task->which != ZOOM_TASK_CONNECT))
1917 ZOOM_connection_remove_tasks (c);
1920 yaz_log (LOG_DEBUG, "ZOOM_connection_exec_task type=%d run=%d",
1921 task->which, task->running);
1925 switch (task->which)
1927 case ZOOM_TASK_SEARCH:
1928 /* see if search hasn't been sent yet. */
1929 if (ZOOM_connection_send_search (c))
1932 case ZOOM_TASK_RETRIEVE:
1933 if (send_present (c))
1936 case ZOOM_TASK_CONNECT:
1940 case ZOOM_TASK_SCAN:
1944 case ZOOM_TASK_PACKAGE:
1945 if (send_package(c))
1948 ZOOM_connection_remove_task (c);
1952 static int send_sort_present (ZOOM_connection c)
1954 int r = send_sort (c);
1956 r = send_present (c);
1960 static int es_response (ZOOM_connection c,
1961 Z_ExtendedServicesResponse *res)
1963 if (!c->tasks || c->tasks->which != ZOOM_TASK_PACKAGE)
1965 if (res->diagnostics && res->num_diagnostics > 0)
1966 response_diag(c, res->diagnostics[0]);
1967 if (res->taskPackage &&
1968 res->taskPackage->which == Z_External_extendedService)
1970 Z_TaskPackage *taskPackage = res->taskPackage->u.extendedService;
1971 Odr_oct *id = taskPackage->targetReference;
1974 ZOOM_options_setl (c->tasks->u.package->options,
1975 "targetReference", id->buf, id->len);
1981 static void handle_apdu (ZOOM_connection c, Z_APDU *apdu)
1983 Z_InitResponse *initrs;
1986 yaz_log (LOG_DEBUG, "hande_apdu type=%d", apdu->which);
1989 case Z_APDU_initResponse:
1990 initrs = apdu->u.initResponse;
1991 if (!*initrs->result)
1993 c->error = ZOOM_ERROR_INIT;
1998 yaz_oi_get_string_oidval (&apdu->u.initResponse->otherInfo,
2000 xfree (c->cookie_in);
2003 c->cookie_in = xstrdup(cookie);
2004 if (ODR_MASK_GET(initrs->options, Z_Options_namedResultSets) &&
2005 ODR_MASK_GET(initrs->protocolVersion, Z_ProtocolVersion_3))
2006 c->support_named_resultsets = 1;
2009 assert (c->tasks->which == ZOOM_TASK_CONNECT);
2010 ZOOM_connection_remove_task (c);
2012 ZOOM_connection_exec_task (c);
2014 if (ODR_MASK_GET(initrs->options, Z_Options_negotiationModel))
2016 NMEM tmpmem = nmem_create();
2017 Z_CharSetandLanguageNegotiation *p =
2018 yaz_get_charneg_record(initrs->otherInfo);
2022 char *charset=NULL, *lang=NULL;
2025 yaz_get_response_charneg(tmpmem, p, &charset, &lang, &selected);
2026 yaz_log(LOG_DEBUG, "Target accepted: charset - %s,"
2027 "language - %s, select - %d",
2028 charset, lang, selected);
2030 nmem_destroy(tmpmem);
2034 case Z_APDU_searchResponse:
2035 handle_search_response (c, apdu->u.searchResponse);
2036 if (!send_sort_present (c))
2037 ZOOM_connection_remove_task (c);
2039 case Z_APDU_presentResponse:
2040 handle_present_response (c, apdu->u.presentResponse);
2041 if (!send_present (c))
2042 ZOOM_connection_remove_task (c);
2044 case Z_APDU_sortResponse:
2045 sort_response (c, apdu->u.sortResponse);
2046 if (!send_present (c))
2047 ZOOM_connection_remove_task (c);
2049 case Z_APDU_scanResponse:
2050 scan_response (c, apdu->u.scanResponse);
2051 ZOOM_connection_remove_task (c);
2053 case Z_APDU_extendedServicesResponse:
2054 es_response (c, apdu->u.extendedServicesResponse);
2055 ZOOM_connection_remove_task (c);
2058 if (c->reconnect_ok)
2061 c->tasks->running = 0;
2062 ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
2066 c->error = ZOOM_ERROR_CONNECTION_LOST;
2071 c->error = ZOOM_ERROR_DECODE;
2076 static int do_read (ZOOM_connection c)
2082 event = ZOOM_Event_create (ZOOM_EVENT_RECV_DATA);
2083 ZOOM_connection_put_event (c, event);
2085 yaz_log (LOG_DEBUG, "do_read len=%d", c->len_in);
2087 r = cs_get (c->cs, &c->buf_in, &c->len_in);
2092 if (c->reconnect_ok)
2095 c->reconnect_ok = 0;
2096 yaz_log (LOG_DEBUG, "reconnect read");
2097 c->tasks->running = 0;
2098 ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
2102 c->error= ZOOM_ERROR_CONNECTION_LOST;
2109 odr_reset (c->odr_in);
2110 odr_setbuf (c->odr_in, c->buf_in, r, 0);
2111 event = ZOOM_Event_create (ZOOM_EVENT_RECV_APDU);
2112 ZOOM_connection_put_event (c, event);
2113 if (!z_APDU (c->odr_in, &apdu, 0, 0))
2115 c->error = ZOOM_ERROR_DECODE;
2119 handle_apdu (c, apdu);
2120 c->reconnect_ok = 0;
2125 static int do_write_ex (ZOOM_connection c, char *buf_out, int len_out)
2130 event = ZOOM_Event_create(ZOOM_EVENT_SEND_DATA);
2131 ZOOM_connection_put_event (c, event);
2133 yaz_log (LOG_DEBUG, "do_write_ex len=%d", len_out);
2134 if ((r=cs_put (c->cs, buf_out, len_out)) < 0)
2136 if (c->reconnect_ok)
2139 c->reconnect_ok = 0;
2140 yaz_log (LOG_DEBUG, "reconnect write");
2141 c->tasks->running = 0;
2142 ZOOM_connection_insert_task (c, ZOOM_TASK_CONNECT);
2145 if (c->state == STATE_CONNECTING)
2146 c->error = ZOOM_ERROR_CONNECT;
2148 c->error = ZOOM_ERROR_CONNECTION_LOST;
2154 c->mask = ZOOM_SELECT_EXCEPT;
2155 if (c->cs->io_pending & CS_WANT_WRITE)
2156 c->mask += ZOOM_SELECT_WRITE;
2157 if (c->cs->io_pending & CS_WANT_READ)
2158 c->mask += ZOOM_SELECT_READ;
2159 yaz_log (LOG_DEBUG, "do_write_ex 1 mask=%d", c->mask);
2163 // c->reconnect_ok = 0;
2164 c->mask = ZOOM_SELECT_READ|ZOOM_SELECT_EXCEPT;
2165 yaz_log (LOG_DEBUG, "do_write_ex 2 mask=%d", c->mask);
2170 static int do_write(ZOOM_connection c)
2172 return do_write_ex (c, c->buf_out, c->len_out);
2176 ZOOM_API(const char *)
2177 ZOOM_connection_option_get (ZOOM_connection c, const char *key)
2179 return ZOOM_options_get (c->options, key);
2183 ZOOM_connection_option_set (ZOOM_connection c, const char *key,
2186 ZOOM_options_set (c->options, key, val);
2189 ZOOM_API(const char *)
2190 ZOOM_resultset_option_get (ZOOM_resultset r, const char *key)
2192 return ZOOM_options_get (r->options, key);
2196 ZOOM_resultset_option_set (ZOOM_resultset r, const char *key,
2199 ZOOM_options_set (r->options, key, val);
2204 ZOOM_connection_errcode (ZOOM_connection c)
2206 return ZOOM_connection_error (c, 0, 0);
2209 ZOOM_API(const char *)
2210 ZOOM_connection_errmsg (ZOOM_connection c)
2213 ZOOM_connection_error (c, &msg, 0);
2217 ZOOM_API(const char *)
2218 ZOOM_connection_addinfo (ZOOM_connection c)
2220 const char *addinfo;
2221 ZOOM_connection_error (c, 0, &addinfo);
2226 ZOOM_connection_error (ZOOM_connection c, const char **cp,
2227 const char **addinfo)
2229 int error = c->error;
2234 case ZOOM_ERROR_NONE:
2235 *cp = "No error"; break;
2236 case ZOOM_ERROR_CONNECT:
2237 *cp = "Connect failed"; break;
2238 case ZOOM_ERROR_MEMORY:
2239 *cp = "Out of memory"; break;
2240 case ZOOM_ERROR_ENCODE:
2241 *cp = "Encoding failed"; break;
2242 case ZOOM_ERROR_DECODE:
2243 *cp = "Decoding failed"; break;
2244 case ZOOM_ERROR_CONNECTION_LOST:
2245 *cp = "Connection lost"; break;
2246 case ZOOM_ERROR_INIT:
2247 *cp = "Init rejected"; break;
2248 case ZOOM_ERROR_INTERNAL:
2249 *cp = "Internal failure"; break;
2250 case ZOOM_ERROR_TIMEOUT:
2251 *cp = "Timeout"; break;
2253 *cp = diagbib1_str (error);
2259 *addinfo = c->addinfo;
2266 static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
2268 ZOOM_Event event = 0;
2269 int r = cs_look(c->cs);
2270 yaz_log (LOG_DEBUG, "ZOOM_connection_do_io c=%p mask=%d cs_look=%d",
2275 event = ZOOM_Event_create (ZOOM_EVENT_CONNECT);
2276 c->error = ZOOM_ERROR_CONNECT;
2278 ZOOM_connection_put_event (c, event);
2280 else if (r == CS_CONNECT)
2283 event = ZOOM_Event_create (ZOOM_EVENT_CONNECT);
2285 ret = cs_rcvconnect (c->cs);
2286 yaz_log (LOG_DEBUG, "cs_rcvconnect returned %d", ret);
2289 c->mask = ZOOM_SELECT_EXCEPT;
2290 if (c->cs->io_pending & CS_WANT_WRITE)
2291 c->mask += ZOOM_SELECT_WRITE;
2292 if (c->cs->io_pending & CS_WANT_READ)
2293 c->mask += ZOOM_SELECT_READ;
2294 ZOOM_connection_put_event (c, event);
2298 ZOOM_connection_put_event (c, event);
2299 ZOOM_connection_send_init (c);
2300 c->state = STATE_ESTABLISHED;
2304 c->error = ZOOM_ERROR_CONNECT;
2306 ZOOM_connection_put_event (c, event);
2311 if (mask & ZOOM_SELECT_READ)
2313 if (c->cs && (mask & ZOOM_SELECT_WRITE))
2320 ZOOM_connection_last_event(ZOOM_connection cs)
2323 return ZOOM_EVENT_NONE;
2324 return cs->last_event;
2328 ZOOM_event (int no, ZOOM_connection *cs)
2332 struct pollfd pollfds[1024];
2333 ZOOM_connection poll_cs[1024];
2336 fd_set input, output, except;
2341 for (i = 0; i<no; i++)
2343 ZOOM_connection c = cs[i];
2345 if (c && (event = ZOOM_connection_get_event(c)))
2347 ZOOM_Event_destroy (event);
2351 for (i = 0; i<no; i++)
2353 ZOOM_connection c = cs[i];
2355 if (c && ZOOM_connection_exec_task (c))
2357 if ((event = ZOOM_connection_get_event(c)))
2359 ZOOM_Event_destroy (event);
2372 for (i = 0; i<no; i++)
2374 ZOOM_connection c = cs[i];
2380 fd = z3950_connection_socket(c);
2381 mask = z3950_connection_mask(c);
2388 this_timeout = ZOOM_options_get_int (c->options, "timeout", -1);
2389 if (this_timeout != -1 && this_timeout < timeout)
2390 timeout = this_timeout;
2394 short poll_events = 0;
2396 if (mask & ZOOM_SELECT_READ)
2397 poll_events += POLLIN;
2398 if (mask & ZOOM_SELECT_WRITE)
2399 poll_events += POLLOUT;
2400 if (mask & ZOOM_SELECT_EXCEPT)
2401 poll_events += POLLERR;
2402 pollfds[nfds].fd = fd;
2403 pollfds[nfds].events = poll_events;
2404 pollfds[nfds].revents = 0;
2409 if (mask & ZOOM_SELECT_READ)
2411 FD_SET (fd, &input);
2414 if (mask & ZOOM_SELECT_WRITE)
2416 FD_SET (fd, &output);
2419 if (mask & ZOOM_SELECT_EXCEPT)
2421 FD_SET (fd, &except);
2426 if (timeout >= 5000)
2433 r = poll (pollfds, nfds, timeout * 1000);
2434 for (i = 0; i<nfds; i++)
2436 ZOOM_connection c = poll_cs[i];
2440 if (pollfds[i].revents & POLLIN)
2441 mask += ZOOM_SELECT_READ;
2442 if (pollfds[i].revents & POLLOUT)
2443 mask += ZOOM_SELECT_WRITE;
2444 if (pollfds[i].revents & POLLERR)
2445 mask += ZOOM_SELECT_EXCEPT;
2447 ZOOM_connection_do_io(c, mask);
2449 else if (r == 0 && c->mask)
2451 ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
2452 /* timeout and this connection was waiting */
2453 c->error = ZOOM_ERROR_TIMEOUT;
2455 ZOOM_connection_put_event(c, event);
2459 tv.tv_sec = timeout;
2461 yaz_log (LOG_DEBUG, "select start");
2462 r = select (max_fd+1, &input, &output, &except, &tv);
2463 yaz_log (LOG_DEBUG, "select stop, returned r=%d", r);
2464 for (i = 0; i<no; i++)
2466 ZOOM_connection c = cs[i];
2471 fd = z3950_connection_socket(c);
2475 /* no timeout and real socket */
2476 if (FD_ISSET(fd, &input))
2477 mask += ZOOM_SELECT_READ;
2478 if (FD_ISSET(fd, &output))
2479 mask += ZOOM_SELECT_WRITE;
2480 if (FD_ISSET(fd, &except))
2481 mask += ZOOM_SELECT_EXCEPT;
2483 ZOOM_connection_do_io(c, mask);
2485 if (r == 0 && c->mask)
2487 ZOOM_Event event = ZOOM_Event_create(ZOOM_EVENT_TIMEOUT);
2488 /* timeout and this connection was waiting */
2489 c->error = ZOOM_ERROR_TIMEOUT;
2491 yaz_log (LOG_DEBUG, "timeout");
2492 ZOOM_connection_put_event(c, event);
2496 for (i = 0; i<no; i++)
2498 ZOOM_connection c = cs[i];
2500 if (c && (event = ZOOM_connection_get_event(c)))
2502 ZOOM_Event_destroy (event);