Bump year
[yazpp-moved-to-github.git] / src / yaz-z-assoc.cpp
1 /* This file is part of the yazpp toolkit.
2  * Copyright (C) 1998-2013 Index Data and Mike Taylor
3  * See the file LICENSE for details.
4  */
5
6 #if HAVE_CONFIG_H
7 #include <config.h>
8 #endif
9 #include <assert.h>
10 #include <signal.h>
11
12 #include <yaz/log.h>
13 #include <yazpp/z-assoc.h>
14 #include <yaz/otherinfo.h>
15 #include <yaz/oid_db.h>
16
17 namespace yazpp_1
18 {
19     class Z_Assoc_priv
20     {
21         friend class Z_Assoc;
22     private:
23         Z_Assoc_priv(IPDU_Observable *the_PDU_Observable);
24         ~Z_Assoc_priv();
25         static int yaz_init_flag;
26         static int yaz_init_func();
27         IPDU_Observable *PDU_Observable;
28         ODR odr_in;
29         ODR odr_out;
30         ODR odr_print;
31         int log;
32         FILE *APDU_file;
33         char *APDU_fname;
34         char *hostname;
35         int APDU_yazlog;
36     };
37 };
38
39 using namespace yazpp_1;
40
41 int Z_Assoc_priv::yaz_init_func()
42 {
43 #ifndef WIN32
44     signal(SIGPIPE, SIG_IGN);
45 #endif
46     return 1;
47 }
48
49 int Z_Assoc_priv::yaz_init_flag =  Z_Assoc_priv::yaz_init_func();
50
51 Z_Assoc_priv::Z_Assoc_priv(IPDU_Observable *the_PDU_Observable)
52 {
53     PDU_Observable = the_PDU_Observable;
54     odr_in = odr_createmem(ODR_DECODE);
55     odr_out = odr_createmem(ODR_ENCODE);
56     odr_print = odr_createmem(ODR_PRINT);
57     log = YLOG_DEBUG;
58     APDU_file = 0;
59     APDU_fname = 0;
60     hostname = 0;
61     APDU_yazlog = 0;
62 }
63
64 Z_Assoc_priv::~Z_Assoc_priv()
65 {
66     PDU_Observable->destroy();
67     delete PDU_Observable;
68     odr_destroy(odr_print);     // note: also runs fclose on APDU_file ..
69     odr_destroy(odr_out);
70     odr_destroy(odr_in);
71     delete [] APDU_fname;
72     delete [] hostname;
73 }
74
75 Z_Assoc::Z_Assoc(IPDU_Observable *the_PDU_Observable)
76 {
77     m_p = new Z_Assoc_priv(the_PDU_Observable);
78 }
79
80 Z_Assoc::~Z_Assoc()
81 {
82     delete m_p;
83 }
84
85 void Z_Assoc::set_APDU_log(const char *fname)
86 {
87     if (m_p->APDU_file && m_p->APDU_file != stderr)
88     {
89         fclose(m_p->APDU_file);
90         m_p->APDU_file = 0;
91     }
92     delete [] m_p->APDU_fname;
93     m_p->APDU_fname = 0;
94
95     if (fname)
96     {
97         m_p->APDU_fname = new char[strlen(fname)+1];
98         strcpy(m_p->APDU_fname, fname);
99         if (!strcmp(fname, "-"))
100             m_p->APDU_file = stderr;
101         else if (*fname == '\0')
102             m_p->APDU_file = 0;
103         else
104             m_p->APDU_file = fopen(fname, "a");
105         odr_setprint(m_p->odr_print, m_p->APDU_file);
106     }
107 }
108
109 int Z_Assoc::set_APDU_yazlog(int v)
110 {
111     int old = m_p->APDU_yazlog;
112     m_p->APDU_yazlog = v;
113     return old;
114 }
115
116 const char *Z_Assoc::get_APDU_log()
117 {
118     return m_p->APDU_fname;
119 }
120
121 void Z_Assoc::recv_PDU(const char *buf, int len)
122 {
123     yaz_log(m_p->log, "recv_PDU len=%d", len);
124     Z_GDU *apdu = decode_GDU(buf, len);
125     if (apdu)
126     {
127         recv_GDU(apdu, len);
128     }
129     else
130     {
131         m_p->PDU_Observable->shutdown();
132         failNotify();
133     }
134 }
135
136 Z_APDU *Z_Assoc::create_Z_PDU(int type)
137 {
138     Z_APDU *apdu = zget_APDU(m_p->odr_out, type);
139     if (apdu->which == Z_APDU_initRequest)
140     {
141         Z_InitRequest * p = apdu->u.initRequest;
142         char *newName = (char*) odr_malloc(m_p->odr_out, 50);
143         strcpy(newName, p->implementationName);
144         strcat(newName, " YAZ++");
145         p->implementationName = newName;
146     }
147     return apdu;
148 }
149
150 Z_ReferenceId **Z_Assoc::get_referenceIdP(Z_APDU *apdu)
151 {
152     switch (apdu->which)
153     {
154     case  Z_APDU_initRequest:
155         return &apdu->u.initRequest->referenceId;
156     case  Z_APDU_initResponse:
157         return &apdu->u.initResponse->referenceId;
158     case  Z_APDU_searchRequest:
159         return &apdu->u.searchRequest->referenceId;
160     case  Z_APDU_searchResponse:
161         return &apdu->u.searchResponse->referenceId;
162     case  Z_APDU_presentRequest:
163         return &apdu->u.presentRequest->referenceId;
164     case  Z_APDU_presentResponse:
165         return &apdu->u.presentResponse->referenceId;
166     case  Z_APDU_deleteResultSetRequest:
167         return &apdu->u.deleteResultSetRequest->referenceId;
168     case  Z_APDU_deleteResultSetResponse:
169         return &apdu->u.deleteResultSetResponse->referenceId;
170     case  Z_APDU_accessControlRequest:
171         return &apdu->u.accessControlRequest->referenceId;
172     case  Z_APDU_accessControlResponse:
173         return &apdu->u.accessControlResponse->referenceId;
174     case  Z_APDU_resourceControlRequest:
175         return &apdu->u.resourceControlRequest->referenceId;
176     case  Z_APDU_resourceControlResponse:
177         return &apdu->u.resourceControlResponse->referenceId;
178     case  Z_APDU_triggerResourceControlRequest:
179         return &apdu->u.triggerResourceControlRequest->referenceId;
180     case  Z_APDU_resourceReportRequest:
181         return &apdu->u.resourceReportRequest->referenceId;
182     case  Z_APDU_resourceReportResponse:
183         return &apdu->u.resourceReportResponse->referenceId;
184     case  Z_APDU_scanRequest:
185         return &apdu->u.scanRequest->referenceId;
186     case  Z_APDU_scanResponse:
187         return &apdu->u.scanResponse->referenceId;
188     case  Z_APDU_sortRequest:
189         return &apdu->u.sortRequest->referenceId;
190     case  Z_APDU_sortResponse:
191         return &apdu->u.sortResponse->referenceId;
192     case  Z_APDU_segmentRequest:
193         return &apdu->u.segmentRequest->referenceId;
194     case  Z_APDU_extendedServicesRequest:
195         return &apdu->u.extendedServicesRequest->referenceId;
196     case  Z_APDU_extendedServicesResponse:
197         return &apdu->u.extendedServicesResponse->referenceId;
198     case  Z_APDU_close:
199         return &apdu->u.close->referenceId;
200     }
201     return 0;
202 }
203
204 void Z_Assoc::transfer_referenceId(Z_APDU *from, Z_APDU *to)
205 {
206     Z_ReferenceId **id_from = get_referenceIdP(from);
207     Z_ReferenceId **id_to = get_referenceIdP(to);
208     if (id_from && *id_from && id_to)
209     {
210         *id_to = (Z_ReferenceId*) odr_malloc(m_p->odr_out, sizeof(**id_to));
211         (*id_to)->size = (*id_to)->len = (*id_from)->len;
212         (*id_to)->buf = (unsigned char*)
213             odr_malloc(m_p->odr_out, (*id_to)->len);
214         memcpy((*id_to)->buf, (*id_from)->buf, (*id_to)->len);
215     }
216     else if (id_to)
217         *id_to = 0;
218 }
219
220 int Z_Assoc::send_Z_PDU(Z_APDU *apdu, int *plen)
221 {
222     Z_GDU *gdu = (Z_GDU*) odr_malloc(odr_encode(), sizeof(*gdu));
223     gdu->which = Z_GDU_Z3950;
224     gdu->u.z3950 = apdu;
225     return send_GDU(gdu, plen);
226 }
227
228 int Z_Assoc::send_GDU(Z_GDU *apdu, int *plen)
229 {
230     char *buf;
231     int len;
232     if (encode_GDU(apdu, &buf, &len) > 0)
233     {
234         if (plen)
235             *plen = len;
236         return m_p->PDU_Observable->send_PDU(buf, len);
237     }
238     return -1;
239 }
240
241 Z_GDU *Z_Assoc::decode_GDU(const char *buf, int len)
242 {
243     Z_GDU *apdu;
244
245     odr_reset(m_p->odr_in);
246     odr_setbuf(m_p->odr_in, (char*) buf, len, 0);
247
248     if (!z_GDU(m_p->odr_in, &apdu, 0, 0))
249     {
250         const char *element = odr_getelement(m_p->odr_in);
251         yaz_log(YLOG_LOG, "PDU decode failed '%s' near byte %ld. Element %s",
252                 odr_errmsg(odr_geterror(m_p->odr_in)),
253                 (long) odr_offset(m_p->odr_in),
254                 element && *element ? element : "unknown");
255         yaz_log(YLOG_LOG, "Buffer length: %d", (int) len);
256         if (len > 0)
257         {
258             WRBUF w = wrbuf_alloc();
259             wrbuf_write_escaped(w, buf, len > 1024 ? 1024 : len);
260             yaz_log(YLOG_LOG, "Buffer bytes: %s", wrbuf_cstr(w));
261             wrbuf_destroy(w);
262         }
263         yaz_log(YLOG_LOG, "PDU dump:");
264         odr_dumpBER(yaz_log_file(), buf, len);
265         return 0;
266     }
267     else
268     {
269         if (m_p->APDU_yazlog)
270         {   // use YAZ log FILE
271             FILE *save = m_p->APDU_file;
272
273             odr_setprint(m_p->odr_print, yaz_log_file());
274             z_GDU(m_p->odr_print, &apdu, 0, "decode");
275             m_p->APDU_file = save;
276             odr_setprint(m_p->odr_print, save);
277         }
278         if (m_p->APDU_file)
279         {
280             z_GDU(m_p->odr_print, &apdu, 0, "decode");
281             fflush(m_p->APDU_file);
282         }
283         return apdu;
284     }
285 }
286
287 int Z_Assoc::encode_GDU(Z_GDU *apdu, char **buf, int *len)
288 {
289     const char *element = 0;
290     int r = z_GDU(m_p->odr_out, &apdu, 0, 0);
291
292     if (!r) // decoding failed. Get the failed element
293         element = odr_getelement(m_p->odr_out);
294
295     if (m_p->APDU_yazlog || !r)
296     {
297         if (!r)
298             yaz_log(YLOG_LOG, "PDU encode failed. Element %s",
299                     element ? element : "unknown");
300         FILE *save = m_p->APDU_file;
301         FILE *yazf = yaz_log_file();
302         odr_setprint(m_p->odr_print, yazf); // use YAZ log FILE
303         z_GDU(m_p->odr_print, &apdu, 0, "encode");
304         m_p->APDU_file = save;
305         odr_setprint(m_p->odr_print, save);
306     }
307     if (m_p->APDU_file)
308     {
309         if (!r)
310             fprintf(m_p->APDU_file, "PDU encode failed. Element %s",
311                     element ? element : "unknown");
312         z_GDU(m_p->odr_print, &apdu, 0, "encode");
313         fflush(m_p->APDU_file);
314     }
315     if (!r)  // encoding failed
316         return -1;
317     *buf = odr_getbuf(m_p->odr_out, len, 0);
318     odr_reset(m_p->odr_out);
319     return *len;
320 }
321
322 const char *Z_Assoc::get_hostname()
323 {
324     return m_p->hostname;
325 }
326
327 int Z_Assoc::client(const char *addr)
328 {
329     delete [] m_p->hostname;
330     m_p->hostname = new char[strlen(addr)+1];
331     strcpy(m_p->hostname, addr);
332     return m_p->PDU_Observable->connect(this, addr);
333 }
334
335 void Z_Assoc::close()
336 {
337     m_p->PDU_Observable->close_session();
338 }
339
340 int Z_Assoc::server(const char *addr)
341 {
342     delete [] m_p->hostname;
343     m_p->hostname = new char[strlen(addr)+1];
344     strcpy(m_p->hostname, addr);
345     return m_p->PDU_Observable->listen(this, addr);
346 }
347
348 ODR Z_Assoc::odr_encode()
349 {
350     return m_p->odr_out;
351 }
352
353 ODR Z_Assoc::odr_decode()
354 {
355     return m_p->odr_in;
356 }
357 ODR Z_Assoc::odr_print()
358 {
359     return m_p->odr_print;
360 }
361
362 void Z_Assoc::timeout(int timeout)
363 {
364     m_p->PDU_Observable->idleTime(timeout);
365 }
366
367 void Z_Assoc::get_otherInfoAPDU(Z_APDU *apdu, Z_OtherInformation ***oip)
368 {
369     switch (apdu->which)
370     {
371     case Z_APDU_initRequest:
372         *oip = &apdu->u.initRequest->otherInfo;
373         break;
374     case Z_APDU_searchRequest:
375         *oip = &apdu->u.searchRequest->otherInfo;
376         break;
377     case Z_APDU_presentRequest:
378         *oip = &apdu->u.presentRequest->otherInfo;
379         break;
380     case Z_APDU_sortRequest:
381         *oip = &apdu->u.sortRequest->otherInfo;
382         break;
383     case Z_APDU_scanRequest:
384         *oip = &apdu->u.scanRequest->otherInfo;
385         break;
386     case Z_APDU_extendedServicesRequest:
387         *oip = &apdu->u.extendedServicesRequest->otherInfo;
388         break;
389     case Z_APDU_deleteResultSetRequest:
390         *oip = &apdu->u.deleteResultSetRequest->otherInfo;
391         break;
392     case Z_APDU_initResponse:
393         *oip = &apdu->u.initResponse->otherInfo;
394         break;
395     case Z_APDU_searchResponse:
396         *oip = &apdu->u.searchResponse->otherInfo;
397         break;
398     case Z_APDU_presentResponse:
399         *oip = &apdu->u.presentResponse->otherInfo;
400         break;
401     case Z_APDU_sortResponse:
402         *oip = &apdu->u.sortResponse->otherInfo;
403         break;
404     case Z_APDU_scanResponse:
405         *oip = &apdu->u.scanResponse->otherInfo;
406         break;
407     case Z_APDU_extendedServicesResponse:
408         *oip = &apdu->u.extendedServicesResponse->otherInfo;
409         break;
410     case Z_APDU_deleteResultSetResponse:
411         *oip = &apdu->u.deleteResultSetResponse->otherInfo;
412         break;
413     default:
414         *oip = 0;
415         break;
416     }
417 }
418
419 void Z_Assoc::set_otherInformationString(
420     Z_APDU *apdu,
421     const Odr_oid *oid, int categoryValue, const char *str)
422 {
423     Z_OtherInformation **otherInformation;
424     get_otherInfoAPDU(apdu, &otherInformation);
425     if (!otherInformation)
426         return;
427     set_otherInformationString(otherInformation, oid, categoryValue, str);
428 }
429
430
431 void Z_Assoc::set_otherInformationString (
432     Z_OtherInformation **otherInformation,
433     const Odr_oid *oid, int categoryValue, const char *str)
434 {
435     Z_OtherInformationUnit *oi =
436         update_otherInformation(otherInformation, 1, oid, categoryValue, 0);
437     if (!oi)
438         return;
439     oi->information.characterInfo = odr_strdup(odr_encode(), str);
440 }
441
442 Z_OtherInformationUnit *Z_Assoc::update_otherInformation (
443     Z_OtherInformation **otherInformationP, int createFlag,
444     const Odr_oid *oid, int categoryValue, int deleteFlag)
445 {
446     return yaz_oi_update(otherInformationP,
447                          (createFlag ? odr_encode() : 0),
448                          oid, categoryValue, deleteFlag);
449 }
450
451 Z_ReferenceId* Z_Assoc::getRefID(char* str)
452 {
453     Z_ReferenceId* id = NULL;
454
455     if (str)
456     {
457         id = (Z_ReferenceId*) odr_malloc(m_p->odr_out, sizeof(*id));
458         id->size = id->len = strlen(str);
459         id->buf = (unsigned char *) str;
460     }
461     return id;
462 }
463
464 /*
465  * Local variables:
466  * c-basic-offset: 4
467  * c-file-style: "Stroustrup"
468  * indent-tabs-mode: nil
469  * End:
470  * vim: shiftwidth=4 tabstop=8 expandtab
471  */
472