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