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