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