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