Remove 'and Mike Taylor' clause from copyright
[yazpp-moved-to-github.git] / src / yaz-z-assoc.cpp
1 /* This file is part of the yazpp toolkit.
2  * Copyright (C) Index Data 
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_to)
209     {
210         if (id_from && *id_from)
211             *id_to = odr_create_Odr_oct(m_p->odr_out, (*id_from)->buf,
212                                         (*id_from)->len);
213         else
214             *id_to = 0;
215     }
216 }
217
218 int Z_Assoc::send_Z_PDU(Z_APDU *apdu, int *plen)
219 {
220     Z_GDU *gdu = (Z_GDU*) odr_malloc(odr_encode(), sizeof(*gdu));
221     gdu->which = Z_GDU_Z3950;
222     gdu->u.z3950 = apdu;
223     return send_GDU(gdu, plen);
224 }
225
226 int Z_Assoc::send_GDU(Z_GDU *apdu, int *plen)
227 {
228     char *buf;
229     int len;
230     if (encode_GDU(apdu, &buf, &len) > 0)
231     {
232         if (plen)
233             *plen = len;
234         return m_p->PDU_Observable->send_PDU(buf, len);
235     }
236     return -1;
237 }
238
239 Z_GDU *Z_Assoc::decode_GDU(const char *buf, int len)
240 {
241     Z_GDU *apdu;
242
243     odr_reset(m_p->odr_in);
244     odr_setbuf(m_p->odr_in, (char*) buf, len, 0);
245
246     if (!z_GDU(m_p->odr_in, &apdu, 0, 0))
247     {
248         const char *element = odr_getelement(m_p->odr_in);
249         yaz_log(YLOG_LOG, "PDU decode failed '%s' near byte %ld. Element %s",
250                 odr_errmsg(odr_geterror(m_p->odr_in)),
251                 (long) odr_offset(m_p->odr_in),
252                 element && *element ? element : "unknown");
253         yaz_log(YLOG_LOG, "Buffer length: %d", (int) len);
254         if (len > 0)
255         {
256             WRBUF w = wrbuf_alloc();
257             wrbuf_write_escaped(w, buf, len > 1024 ? 1024 : len);
258             yaz_log(YLOG_LOG, "Buffer bytes: %s", wrbuf_cstr(w));
259             wrbuf_destroy(w);
260         }
261         yaz_log(YLOG_LOG, "PDU dump:");
262         odr_dumpBER(yaz_log_file(), buf, len);
263         return 0;
264     }
265     else
266     {
267         if (m_p->APDU_yazlog)
268         {   // use YAZ log FILE
269             FILE *save = m_p->APDU_file;
270
271             odr_setprint(m_p->odr_print, yaz_log_file());
272             z_GDU(m_p->odr_print, &apdu, 0, "decode");
273             m_p->APDU_file = save;
274             odr_setprint(m_p->odr_print, save);
275         }
276         if (m_p->APDU_file)
277         {
278             z_GDU(m_p->odr_print, &apdu, 0, "decode");
279             fflush(m_p->APDU_file);
280         }
281         return apdu;
282     }
283 }
284
285 int Z_Assoc::encode_GDU(Z_GDU *apdu, char **buf, int *len)
286 {
287     const char *element = 0;
288     int r = z_GDU(m_p->odr_out, &apdu, 0, 0);
289
290     if (!r) // decoding failed. Get the failed element
291         element = odr_getelement(m_p->odr_out);
292
293     if (m_p->APDU_yazlog || !r)
294     {
295         if (!r)
296             yaz_log(YLOG_LOG, "PDU encode failed. Element %s",
297                     element ? element : "unknown");
298         FILE *save = m_p->APDU_file;
299         FILE *yazf = yaz_log_file();
300         odr_setprint(m_p->odr_print, yazf); // use YAZ log FILE
301         z_GDU(m_p->odr_print, &apdu, 0, "encode");
302         m_p->APDU_file = save;
303         odr_setprint(m_p->odr_print, save);
304     }
305     if (m_p->APDU_file)
306     {
307         if (!r)
308             fprintf(m_p->APDU_file, "PDU encode failed. Element %s",
309                     element ? element : "unknown");
310         z_GDU(m_p->odr_print, &apdu, 0, "encode");
311         fflush(m_p->APDU_file);
312     }
313     if (!r)  // encoding failed
314         return -1;
315     *buf = odr_getbuf(m_p->odr_out, len, 0);
316     odr_reset(m_p->odr_out);
317     return *len;
318 }
319
320 const char *Z_Assoc::get_hostname()
321 {
322     return m_p->hostname;
323 }
324
325 int Z_Assoc::client(const char *addr)
326 {
327     delete [] m_p->hostname;
328     m_p->hostname = new char[strlen(addr)+1];
329     strcpy(m_p->hostname, addr);
330     return m_p->PDU_Observable->connect(this, addr);
331 }
332
333 void Z_Assoc::close()
334 {
335     m_p->PDU_Observable->close_session();
336 }
337
338 int Z_Assoc::server(const char *addr)
339 {
340     delete [] m_p->hostname;
341     m_p->hostname = new char[strlen(addr)+1];
342     strcpy(m_p->hostname, addr);
343     return m_p->PDU_Observable->listen(this, addr);
344 }
345
346 ODR Z_Assoc::odr_encode()
347 {
348     return m_p->odr_out;
349 }
350
351 ODR Z_Assoc::odr_decode()
352 {
353     return m_p->odr_in;
354 }
355 ODR Z_Assoc::odr_print()
356 {
357     return m_p->odr_print;
358 }
359
360 void Z_Assoc::timeout(int timeout)
361 {
362     m_p->PDU_Observable->idleTime(timeout);
363 }
364
365 void Z_Assoc::get_otherInfoAPDU(Z_APDU *apdu, Z_OtherInformation ***oip)
366 {
367     switch (apdu->which)
368     {
369     case Z_APDU_initRequest:
370         *oip = &apdu->u.initRequest->otherInfo;
371         break;
372     case Z_APDU_searchRequest:
373         *oip = &apdu->u.searchRequest->otherInfo;
374         break;
375     case Z_APDU_presentRequest:
376         *oip = &apdu->u.presentRequest->otherInfo;
377         break;
378     case Z_APDU_sortRequest:
379         *oip = &apdu->u.sortRequest->otherInfo;
380         break;
381     case Z_APDU_scanRequest:
382         *oip = &apdu->u.scanRequest->otherInfo;
383         break;
384     case Z_APDU_extendedServicesRequest:
385         *oip = &apdu->u.extendedServicesRequest->otherInfo;
386         break;
387     case Z_APDU_deleteResultSetRequest:
388         *oip = &apdu->u.deleteResultSetRequest->otherInfo;
389         break;
390     case Z_APDU_initResponse:
391         *oip = &apdu->u.initResponse->otherInfo;
392         break;
393     case Z_APDU_searchResponse:
394         *oip = &apdu->u.searchResponse->otherInfo;
395         break;
396     case Z_APDU_presentResponse:
397         *oip = &apdu->u.presentResponse->otherInfo;
398         break;
399     case Z_APDU_sortResponse:
400         *oip = &apdu->u.sortResponse->otherInfo;
401         break;
402     case Z_APDU_scanResponse:
403         *oip = &apdu->u.scanResponse->otherInfo;
404         break;
405     case Z_APDU_extendedServicesResponse:
406         *oip = &apdu->u.extendedServicesResponse->otherInfo;
407         break;
408     case Z_APDU_deleteResultSetResponse:
409         *oip = &apdu->u.deleteResultSetResponse->otherInfo;
410         break;
411     default:
412         *oip = 0;
413         break;
414     }
415 }
416
417 void Z_Assoc::set_otherInformationString(
418     Z_APDU *apdu,
419     const Odr_oid *oid, int categoryValue, const char *str)
420 {
421     Z_OtherInformation **otherInformation;
422     get_otherInfoAPDU(apdu, &otherInformation);
423     if (!otherInformation)
424         return;
425     set_otherInformationString(otherInformation, oid, categoryValue, str);
426 }
427
428
429 void Z_Assoc::set_otherInformationString (
430     Z_OtherInformation **otherInformation,
431     const Odr_oid *oid, int categoryValue, const char *str)
432 {
433     Z_OtherInformationUnit *oi =
434         update_otherInformation(otherInformation, 1, oid, categoryValue, 0);
435     if (!oi)
436         return;
437     oi->information.characterInfo = odr_strdup(odr_encode(), str);
438 }
439
440 Z_OtherInformationUnit *Z_Assoc::update_otherInformation (
441     Z_OtherInformation **otherInformationP, int createFlag,
442     const Odr_oid *oid, int categoryValue, int deleteFlag)
443 {
444     return yaz_oi_update(otherInformationP,
445                          (createFlag ? odr_encode() : 0),
446                          oid, categoryValue, deleteFlag);
447 }
448
449 Z_ReferenceId* Z_Assoc::getRefID(char* str)
450 {
451     Z_ReferenceId* id = NULL;
452
453     if (str)
454         id = odr_create_Odr_oct(m_p->odr_out, 
455 #if YAZ_VERSIONL < 0x50000
456                                 (unsigned char *)
457 #endif
458                                 str, strlen(str));
459     return id;
460 }
461
462 /*
463  * Local variables:
464  * c-basic-offset: 4
465  * c-file-style: "Stroustrup"
466  * indent-tabs-mode: nil
467  * End:
468  * vim: shiftwidth=4 tabstop=8 expandtab
469  */
470