PDU_Assoc keeps track of children. Using yaz_log instead of logf.
[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  * $Log: yaz-z-assoc.cpp,v $
6  * Revision 1.21  2001-08-13 16:39:12  adam
7  * PDU_Assoc keeps track of children. Using yaz_log instead of logf.
8  *
9  * Revision 1.20  2001/04/25 18:59:30  adam
10  * Added referenceId handling for server.
11  *
12  * Revision 1.19  2001/03/27 14:47:45  adam
13  * New server facility scheme.
14  *
15  * Revision 1.18  2001/03/26 14:43:49  adam
16  * New threaded PDU association.
17  *
18  * Revision 1.17  2001/01/04 14:25:25  heikki
19  * No SIGPIPES in windows...
20  *
21  * Revision 1.16  2000/12/14 16:00:39  adam
22  * Ignoring signal SIGPIPE.
23  *
24  * Revision 1.15  2000/10/11 11:58:17  adam
25  * Moved header files to include/yaz++. Switched to libtool and automake.
26  * Configure script creates yaz++-config script.
27  *
28  * Revision 1.14  2000/09/12 16:40:33  heikki
29  * minor
30  *
31  * Revision 1.13  2000/09/08 10:23:42  adam
32  * Added skeleton of yaz-z-server.
33  *
34  * Revision 1.12  2000/09/05 13:57:28  adam
35  * Fixed get_otherInfoAPDU to return otherInfo for extended services.
36  *
37  * Revision 1.11  2000/09/04 08:59:16  adam
38  * Changed call to logging functions (yaz_ added).
39  *
40  * Revision 1.10  2000/09/04 08:29:22  adam
41  * Fixed memory leak(s). Added re-use of associations, rather than
42  * re-init, when maximum number of targets are in use.
43  *
44  * Revision 1.9  2000/08/10 08:42:42  adam
45  * Fixes for {set,get}_APDU_log.
46  *
47  * Revision 1.8  2000/08/07 14:19:59  adam
48  * Fixed serious bug regarding timeouts. Improved logging for proxy.
49  *
50  * Revision 1.7  2000/05/10 11:36:58  ian
51  * Added default parameters for refid to request functions.
52  * Added default parameter for result set name to search and present request.
53  * Commented out forced logging of PDU contents.
54  * Added send_deleteResultSetRequest
55  *
56  * Revision 1.6  1999/12/06 13:52:45  adam
57  * Modified for new location of YAZ header files. Experimental threaded
58  * operation.
59  *
60  * Revision 1.5  1999/11/10 10:02:34  adam
61  * Work on proxy.
62  *
63  * Revision 1.4  1999/09/13 12:53:44  adam
64  * Proxy removes OtherInfo Proxy Address and Session ID. Other
65  * Otherinfo remains untouched.
66  *
67  * Revision 1.3  1999/04/21 12:09:01  adam
68  * Many improvements. Modified to proxy server to work with "sessions"
69  * based on cookies.
70  *
71  * Revision 1.2  1999/04/20 10:30:05  adam
72  * Implemented various stuff for client and proxy. Updated calls
73  * to ODR to reflect new name parameter.
74  *
75  * Revision 1.1  1999/04/09 11:46:57  adam
76  * Added object Yaz_Z_Assoc. Much more functional client.
77  *
78  */
79
80 #include <assert.h>
81 #include <signal.h>
82
83 #include <yaz/log.h>
84 #include <yaz++/yaz-z-assoc.h>
85 #include <yaz/otherinfo.h>
86
87 int Yaz_Z_Assoc::yaz_init_func()
88 {
89 #ifndef WIN32
90     signal (SIGPIPE, SIG_IGN);
91 #endif
92     nmem_init();
93     return 1;
94 }
95
96 int Yaz_Z_Assoc::yaz_init_flag =  Yaz_Z_Assoc::yaz_init_func();  
97
98 Yaz_Z_Assoc::Yaz_Z_Assoc(IYaz_PDU_Observable *the_PDU_Observable)
99 {
100     m_PDU_Observable = the_PDU_Observable;
101     m_odr_in = odr_createmem (ODR_DECODE);
102     m_odr_out = odr_createmem (ODR_ENCODE);
103     m_odr_print = odr_createmem (ODR_PRINT);
104     m_log = LOG_DEBUG;
105     m_APDU_file = 0;
106     m_APDU_fname = 0;
107     m_hostname = 0;
108 }
109
110 void Yaz_Z_Assoc::set_APDU_log(const char *fname)
111 {
112     if (m_APDU_file && m_APDU_file != stderr)
113     {
114         fclose (m_APDU_file);
115         m_APDU_file = 0;
116     }
117     delete [] m_APDU_fname;
118     m_APDU_fname = 0;
119
120     if (fname) 
121     {
122         m_APDU_fname = new char[strlen(fname)+1];
123         strcpy (m_APDU_fname, fname);
124         if (*fname && strcmp(fname, "-"))
125             m_APDU_file = fopen (fname, "a");
126         else
127             m_APDU_file = stderr;
128         odr_setprint(m_odr_print, m_APDU_file);
129     }
130 }
131
132 const char *Yaz_Z_Assoc::get_APDU_log()
133 {
134     return m_APDU_fname;
135 }
136
137 Yaz_Z_Assoc::~Yaz_Z_Assoc()
138 {
139     m_PDU_Observable->destroy();  
140     delete m_PDU_Observable;
141     odr_destroy (m_odr_print);     // note: also runs fclose on m_APDU_file ..
142     odr_destroy (m_odr_out);
143     odr_destroy (m_odr_in);
144     delete [] m_APDU_fname;
145     delete [] m_hostname;
146 }
147
148 void Yaz_Z_Assoc::recv_PDU(const char *buf, int len)
149 {
150     yaz_log (m_log, "recv_PDU len=%d", len);
151     Z_APDU *apdu = decode_Z_PDU (buf, len);
152     if (apdu)
153     {
154         recv_Z_PDU (apdu);
155     }
156     else
157     {
158         close();
159     }
160 }
161
162 Z_APDU *Yaz_Z_Assoc::create_Z_PDU(int type)
163 {
164     Z_APDU *apdu = zget_APDU(m_odr_out, type);
165     if (apdu->which == Z_APDU_initRequest)
166     {
167         Z_InitRequest * p = apdu->u.initRequest;
168         char *newName = (char*) odr_malloc(m_odr_out, 50);
169         strcpy (newName, p->implementationName);
170         strcat (newName, " YAZ++");
171         p->implementationName = newName;
172     }
173     return apdu;
174 }
175
176 Z_ReferenceId **Yaz_Z_Assoc::get_referenceIdP(Z_APDU *apdu)
177 {
178     switch (apdu->which)
179     {
180     case  Z_APDU_initRequest:
181         return &apdu->u.initRequest->referenceId; 
182     case  Z_APDU_initResponse:
183         return &apdu->u.initResponse->referenceId;
184     case  Z_APDU_searchRequest:
185         return &apdu->u.searchRequest->referenceId;
186     case  Z_APDU_searchResponse:
187         return &apdu->u.searchResponse->referenceId;
188     case  Z_APDU_presentRequest:
189         return &apdu->u.presentRequest->referenceId;
190     case  Z_APDU_presentResponse:
191         return &apdu->u.presentResponse->referenceId;
192     case  Z_APDU_deleteResultSetRequest:
193         return &apdu->u.deleteResultSetRequest->referenceId;
194     case  Z_APDU_deleteResultSetResponse:
195         return &apdu->u.deleteResultSetResponse->referenceId;
196     case  Z_APDU_accessControlRequest:
197         return &apdu->u.accessControlRequest->referenceId;
198     case  Z_APDU_accessControlResponse:
199         return &apdu->u.accessControlResponse->referenceId;
200     case  Z_APDU_resourceControlRequest:
201         return &apdu->u.resourceControlRequest->referenceId;
202     case  Z_APDU_resourceControlResponse:
203         return &apdu->u.resourceControlResponse->referenceId;
204     case  Z_APDU_triggerResourceControlRequest:
205         return &apdu->u.triggerResourceControlRequest->referenceId;
206     case  Z_APDU_resourceReportRequest:
207         return &apdu->u.resourceReportRequest->referenceId;
208     case  Z_APDU_resourceReportResponse:
209         return &apdu->u.resourceReportResponse->referenceId;
210     case  Z_APDU_scanRequest:
211         return &apdu->u.scanRequest->referenceId;
212     case  Z_APDU_scanResponse:
213         return &apdu->u.scanResponse->referenceId;
214     case  Z_APDU_sortRequest:
215         return &apdu->u.sortRequest->referenceId;
216     case  Z_APDU_sortResponse:
217         return &apdu->u.sortResponse->referenceId;
218     case  Z_APDU_segmentRequest:
219         return &apdu->u.segmentRequest->referenceId;
220     case  Z_APDU_extendedServicesRequest:
221         return &apdu->u.extendedServicesRequest->referenceId;
222     case  Z_APDU_extendedServicesResponse:
223         return &apdu->u.extendedServicesResponse->referenceId;
224     case  Z_APDU_close:
225         return &apdu->u.close->referenceId;
226     }
227     return 0;
228 }
229
230 void Yaz_Z_Assoc::transfer_referenceId(Z_APDU *from, Z_APDU *to)
231 {
232     Z_ReferenceId **id_from = get_referenceIdP(from);
233     Z_ReferenceId **id_to = get_referenceIdP(to);
234     if (id_from && *id_from && id_to)
235     {
236         *id_to = (Z_ReferenceId*) odr_malloc (m_odr_out, sizeof(**id_to));
237         (*id_to)->size = (*id_to)->len = (*id_from)->len;
238         (*id_to)->buf = (unsigned char*) odr_malloc (m_odr_out, (*id_to)->len);
239         memcpy ((*id_to)->buf, (*id_from)->buf, (*id_to)->len);
240     }
241     else if (id_to)
242         *id_to = 0;
243 }
244
245 int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu)
246 {
247     char *buf;
248     int len;
249     if (encode_Z_PDU(apdu, &buf, &len) > 0)
250         return m_PDU_Observable->send_PDU(buf, len);
251     return -1;
252 }
253
254 Z_APDU *Yaz_Z_Assoc::decode_Z_PDU(const char *buf, int len)
255 {
256     Z_APDU *apdu;
257
258     odr_reset (m_odr_in);
259     odr_setbuf (m_odr_in, (char*) buf, len, 0);
260
261     if (!z_APDU(m_odr_in, &apdu, 0, 0))
262     {
263         yaz_log(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
264              odr_errmsg(odr_geterror(m_odr_in)),
265              odr_offset(m_odr_in));
266         yaz_log(LOG_LOG, "PDU dump:");
267         odr_dumpBER(yaz_log_file(), buf, len);
268         return 0;
269     }
270     else
271     {
272         if (m_APDU_file)
273             z_APDU(m_odr_print, &apdu, 0, "decode");
274         return apdu;
275     }
276 }
277
278 int Yaz_Z_Assoc::encode_Z_PDU(Z_APDU *apdu, char **buf, int *len)
279 {
280     if (m_APDU_file)
281         z_APDU(m_odr_print, &apdu, 0, "encode");
282     if (!z_APDU(m_odr_out, &apdu, 0, 0))
283     {
284         yaz_log (LOG_LOG, "yaz_Z_Assoc::encode_Z_PDU failed");
285         return -1;
286     }
287     *buf = odr_getbuf (m_odr_out, len, 0);
288     odr_reset (m_odr_out);
289     return *len;
290 }
291
292 const char *Yaz_Z_Assoc::get_hostname()
293 {
294     return m_hostname;
295 }
296
297 void Yaz_Z_Assoc::client(const char *addr)
298 {
299     delete [] m_hostname;
300     m_hostname = new char[strlen(addr)+1];
301     strcpy (m_hostname, addr);
302     m_PDU_Observable->connect (this, addr);
303 }
304
305 void Yaz_Z_Assoc::close()
306 {
307     m_PDU_Observable->close ();
308 }
309
310 void Yaz_Z_Assoc::server(const char *addr)
311 {
312     delete [] m_hostname;
313     m_hostname = new char[strlen(addr)+1];
314     strcpy (m_hostname, addr);
315     m_PDU_Observable->listen (this, addr);
316 }
317
318 ODR Yaz_Z_Assoc::odr_encode()
319 {
320     return m_odr_out;
321 }
322
323 ODR Yaz_Z_Assoc::odr_decode()
324 {
325     return m_odr_in;
326 }
327 ODR Yaz_Z_Assoc::odr_print()
328 {
329     return m_odr_print;
330 }
331
332 void Yaz_Z_Assoc::timeout(int timeout)
333 {
334     m_PDU_Observable->idleTime(timeout);
335 }
336
337 void Yaz_Z_Assoc::get_otherInfoAPDU(Z_APDU *apdu, Z_OtherInformation ***oip)
338 {
339     switch (apdu->which)
340     {
341     case Z_APDU_initRequest:
342         *oip = &apdu->u.initRequest->otherInfo;
343         break;
344     case Z_APDU_searchRequest:
345         *oip = &apdu->u.searchRequest->otherInfo;
346         break;
347     case Z_APDU_presentRequest:
348         *oip = &apdu->u.presentRequest->otherInfo;
349         break;
350     case Z_APDU_sortRequest:
351         *oip = &apdu->u.sortRequest->otherInfo;
352         break;
353     case Z_APDU_scanRequest:
354         *oip = &apdu->u.scanRequest->otherInfo;
355         break;
356     case Z_APDU_extendedServicesRequest:
357         *oip = &apdu->u.extendedServicesRequest->otherInfo;
358         break;
359     case Z_APDU_deleteResultSetRequest:
360         *oip = &apdu->u.deleteResultSetRequest->otherInfo;
361         break;
362     case Z_APDU_initResponse:
363         *oip = &apdu->u.initResponse->otherInfo;
364         break;
365     case Z_APDU_searchResponse:
366         *oip = &apdu->u.searchResponse->otherInfo;
367         break;
368     case Z_APDU_presentResponse:
369         *oip = &apdu->u.presentResponse->otherInfo;
370         break;
371     case Z_APDU_sortResponse:
372         *oip = &apdu->u.sortResponse->otherInfo;
373         break;
374     case Z_APDU_scanResponse:
375         *oip = &apdu->u.scanResponse->otherInfo;
376         break;
377     case Z_APDU_extendedServicesResponse:
378         *oip = &apdu->u.extendedServicesResponse->otherInfo;
379         break;
380     case Z_APDU_deleteResultSetResponse:
381         *oip = &apdu->u.deleteResultSetResponse->otherInfo;
382         break;
383     default:
384         *oip = 0;
385         break;
386     }
387 }
388
389 void Yaz_Z_Assoc::set_otherInformationString (
390     Z_APDU *apdu,
391     int oidval, int categoryValue,
392     const char *str)
393 {
394     Z_OtherInformation **otherInformation;
395     get_otherInfoAPDU(apdu, &otherInformation);
396     if (!otherInformation)
397         return;
398     set_otherInformationString(otherInformation, oidval, categoryValue, str);
399 }
400
401 void Yaz_Z_Assoc::set_otherInformationString (
402     Z_OtherInformation **otherInformation,
403     int oidval, int categoryValue,
404     const char *str)
405 {
406     int oid[OID_SIZE];
407     struct oident ent;
408     ent.proto = PROTO_Z3950;
409     ent.oclass = CLASS_USERINFO;
410     ent.value = (oid_value) oidval;
411     if (!oid_ent_to_oid (&ent, oid))
412         return ;
413     set_otherInformationString(otherInformation, oid, categoryValue, str);
414 }
415
416 void Yaz_Z_Assoc::set_otherInformationString (
417     Z_OtherInformation **otherInformation,
418     int *oid, int categoryValue, const char *str)
419 {
420     Z_OtherInformationUnit *oi =
421         update_otherInformation(otherInformation, 1, oid, categoryValue, 0);
422     if (!oi)
423         return;
424     oi->information.characterInfo = odr_strdup (odr_encode(), str);
425 }
426
427 Z_OtherInformationUnit *Yaz_Z_Assoc::update_otherInformation (
428     Z_OtherInformation **otherInformationP, int createFlag,
429     int *oid, int categoryValue, int deleteFlag)
430 {
431     return yaz_oi_update (otherInformationP,
432                           (createFlag ? odr_encode() : 0),
433                           oid, categoryValue, deleteFlag);
434 }
435
436 Z_ReferenceId* Yaz_Z_Assoc::getRefID(char* str)
437 {
438     Z_ReferenceId* id = NULL;
439
440     if (str)
441     {
442         id = (Z_ReferenceId*) odr_malloc (m_odr_out, sizeof(*id));
443         id->size = id->len = strlen(str);
444         id->buf = (unsigned char *) str;
445     }
446     return id;
447 }
448