Fixed get_otherInfoAPDU to return otherInfo for extended services.
[yazpp-moved-to-github.git] / src / yaz-z-assoc.cpp
1 /*
2  * Copyright (c) 1998-1999, Index Data.
3  * See the file LICENSE for details.
4  * Sebastian Hammer, Adam Dickmeiss
5  * 
6  * $Log: yaz-z-assoc.cpp,v $
7  * Revision 1.12  2000-09-05 13:57:28  adam
8  * Fixed get_otherInfoAPDU to return otherInfo for extended services.
9  *
10  * Revision 1.11  2000/09/04 08:59:16  adam
11  * Changed call to logging functions (yaz_ added).
12  *
13  * Revision 1.10  2000/09/04 08:29:22  adam
14  * Fixed memory leak(s). Added re-use of associations, rather than
15  * re-init, when maximum number of targets are in use.
16  *
17  * Revision 1.9  2000/08/10 08:42:42  adam
18  * Fixes for {set,get}_APDU_log.
19  *
20  * Revision 1.8  2000/08/07 14:19:59  adam
21  * Fixed serious bug regarding timeouts. Improved logging for proxy.
22  *
23  * Revision 1.7  2000/05/10 11:36:58  ian
24  * Added default parameters for refid to request functions.
25  * Added default parameter for result set name to search and present request.
26  * Commented out forced logging of PDU contents.
27  * Added send_deleteResultSetRequest
28  *
29  * Revision 1.6  1999/12/06 13:52:45  adam
30  * Modified for new location of YAZ header files. Experimental threaded
31  * operation.
32  *
33  * Revision 1.5  1999/11/10 10:02:34  adam
34  * Work on proxy.
35  *
36  * Revision 1.4  1999/09/13 12:53:44  adam
37  * Proxy removes OtherInfo Proxy Address and Session ID. Other
38  * Otherinfo remains untouched.
39  *
40  * Revision 1.3  1999/04/21 12:09:01  adam
41  * Many improvements. Modified to proxy server to work with "sessions"
42  * based on cookies.
43  *
44  * Revision 1.2  1999/04/20 10:30:05  adam
45  * Implemented various stuff for client and proxy. Updated calls
46  * to ODR to reflect new name parameter.
47  *
48  * Revision 1.1  1999/04/09 11:46:57  adam
49  * Added object Yaz_Z_Assoc. Much more functional client.
50  *
51  */
52
53 #include <assert.h>
54
55 #include <yaz/log.h>
56 #include <yaz-z-assoc.h>
57 #include <yaz/otherinfo.h>
58
59 int Yaz_Z_Assoc::yaz_init_func()
60 {
61     nmem_init();
62     return 1;
63 }
64
65 int Yaz_Z_Assoc::yaz_init_flag = Yaz_Z_Assoc::yaz_init_func();
66
67 Yaz_Z_Assoc::Yaz_Z_Assoc(IYaz_PDU_Observable *the_PDU_Observable)
68 {
69     m_PDU_Observable = the_PDU_Observable;
70     m_odr_in = odr_createmem (ODR_DECODE);
71     m_odr_out = odr_createmem (ODR_ENCODE);
72     m_odr_print = odr_createmem (ODR_PRINT);
73     m_log = LOG_DEBUG;
74     m_APDU_file = 0;
75     m_APDU_fname = 0;
76     m_hostname = 0;
77 }
78
79 void Yaz_Z_Assoc::set_APDU_log(const char *fname)
80 {
81     if (m_APDU_file && m_APDU_file != stderr)
82     {
83         fclose (m_APDU_file);
84         m_APDU_file = 0;
85     }
86     delete [] m_APDU_fname;
87     m_APDU_fname = 0;
88
89     if (fname)
90     {
91         m_APDU_fname = new char[strlen(fname)+1];
92         strcpy (m_APDU_fname, fname);
93         if (*fname && strcmp(fname, "-"))
94             m_APDU_file = fopen (fname, "a");
95         else
96             m_APDU_file = stderr;
97         odr_setprint(m_odr_print, m_APDU_file);
98     }
99 }
100
101 const char *Yaz_Z_Assoc::get_APDU_log()
102 {
103     return m_APDU_fname;
104 }
105
106 Yaz_Z_Assoc::~Yaz_Z_Assoc()
107 {
108     m_PDU_Observable->destroy();
109     delete m_PDU_Observable;
110     odr_destroy (m_odr_print);     // note: also runs fclose on m_APDU_file ..
111     odr_destroy (m_odr_out);
112     odr_destroy (m_odr_in);
113     delete [] m_APDU_fname;
114     delete [] m_hostname;
115 }
116
117 void Yaz_Z_Assoc::recv_PDU(const char *buf, int len)
118 {
119     logf (m_log, "recv_PDU len=%d", len);
120     Z_APDU *apdu = decode_Z_PDU (buf, len);
121     if (apdu)
122     {
123         recv_Z_PDU (apdu);
124     }
125 }
126
127 Z_APDU *Yaz_Z_Assoc::create_Z_PDU(int type)
128 {
129     Z_APDU *apdu = zget_APDU(m_odr_out, type);
130     if (apdu->which == Z_APDU_initRequest)
131     {
132         Z_InitRequest * p = apdu->u.initRequest;
133         char *newName = (char*) odr_malloc(m_odr_out, 50);
134         strcpy (newName, p->implementationName);
135         strcat (newName, " YAZ++");
136         p->implementationName = newName;
137     }
138     return apdu;
139 }
140
141 int Yaz_Z_Assoc::send_Z_PDU(Z_APDU *apdu)
142 {
143     char *buf;
144     int len;
145     if (encode_Z_PDU(apdu, &buf, &len) > 0)
146         return m_PDU_Observable->send_PDU(buf, len);
147     return -1;
148 }
149
150 Z_APDU *Yaz_Z_Assoc::decode_Z_PDU(const char *buf, int len)
151 {
152     Z_APDU *apdu;
153
154     odr_reset (m_odr_in);
155     odr_setbuf (m_odr_in, (char*) buf, len, 0);
156
157     if (!z_APDU(m_odr_in, &apdu, 0, 0))
158     {
159         logf(LOG_LOG, "ODR error on incoming PDU: %s [near byte %d] ",
160              odr_errmsg(odr_geterror(m_odr_in)),
161              odr_offset(m_odr_in));
162         logf(LOG_LOG, "PDU dump:");
163         odr_dumpBER(yaz_log_file(), buf, len);
164         return 0;
165     }
166     else
167     {
168         if (m_APDU_file)
169             z_APDU(m_odr_print, &apdu, 0, "decode");
170         return apdu;
171     }
172 }
173
174 int Yaz_Z_Assoc::encode_Z_PDU(Z_APDU *apdu, char **buf, int *len)
175 {
176     if (!z_APDU(m_odr_out, &apdu, 0, 0))
177     {
178         logf (LOG_LOG, "yaz_Z_Assoc::encode_Z_PDU failed");
179         return -1;
180     }
181     if (m_APDU_file)
182         z_APDU(m_odr_print, &apdu, 0, "encode");
183     *buf = odr_getbuf (m_odr_out, len, 0);
184     odr_reset (m_odr_out);
185     return *len;
186 }
187
188 const char *Yaz_Z_Assoc::get_hostname()
189 {
190     return m_hostname;
191 }
192
193 void Yaz_Z_Assoc::client(const char *addr)
194 {
195     delete [] m_hostname;
196     m_hostname = new char[strlen(addr)+1];
197     strcpy (m_hostname, addr);
198     m_PDU_Observable->connect (this, addr);
199 }
200
201 void Yaz_Z_Assoc::close()
202 {
203     m_PDU_Observable->close ();
204 }
205
206 void Yaz_Z_Assoc::server(const char *addr)
207 {
208     delete [] m_hostname;
209     m_hostname = new char[strlen(addr)+1];
210     strcpy (m_hostname, addr);
211     m_PDU_Observable->listen (this, addr);
212 }
213
214 ODR Yaz_Z_Assoc::odr_encode()
215 {
216     return m_odr_out;
217 }
218
219 ODR Yaz_Z_Assoc::odr_decode()
220 {
221     return m_odr_in;
222 }
223 ODR Yaz_Z_Assoc::odr_print()
224 {
225     return m_odr_print;
226 }
227
228 void Yaz_Z_Assoc::timeout(int timeout)
229 {
230     m_PDU_Observable->idleTime(timeout);
231 }
232
233 void Yaz_Z_Assoc::get_otherInfoAPDU(Z_APDU *apdu, Z_OtherInformation ***oip)
234 {
235     switch (apdu->which)
236     {
237     case Z_APDU_initRequest:
238         *oip = &apdu->u.initRequest->otherInfo;
239         break;
240     case Z_APDU_searchRequest:
241         *oip = &apdu->u.searchRequest->otherInfo;
242         break;
243     case Z_APDU_presentRequest:
244         *oip = &apdu->u.presentRequest->otherInfo;
245         break;
246     case Z_APDU_sortRequest:
247         *oip = &apdu->u.sortRequest->otherInfo;
248         break;
249     case Z_APDU_scanRequest:
250         *oip = &apdu->u.scanRequest->otherInfo;
251         break;
252     case Z_APDU_extendedServicesRequest:
253         *oip = &apdu->u.extendedServicesRequest->otherInfo;
254         break;
255     case Z_APDU_deleteResultSetRequest:
256         *oip = &apdu->u.deleteResultSetRequest->otherInfo;
257         break;
258     case Z_APDU_initResponse:
259         *oip = &apdu->u.initResponse->otherInfo;
260         break;
261     case Z_APDU_searchResponse:
262         *oip = &apdu->u.searchResponse->otherInfo;
263         break;
264     case Z_APDU_presentResponse:
265         *oip = &apdu->u.presentResponse->otherInfo;
266         break;
267     case Z_APDU_sortResponse:
268         *oip = &apdu->u.sortResponse->otherInfo;
269         break;
270     case Z_APDU_scanResponse:
271         *oip = &apdu->u.scanResponse->otherInfo;
272         break;
273     case Z_APDU_extendedServicesResponse:
274         *oip = &apdu->u.extendedServicesResponse->otherInfo;
275         break;
276     case Z_APDU_deleteResultSetResponse:
277         *oip = &apdu->u.deleteResultSetResponse->otherInfo;
278         break;
279     default:
280         *oip = 0;
281         break;
282     }
283 }
284
285 void Yaz_Z_Assoc::set_otherInformationString (
286     Z_APDU *apdu,
287     int oidval, int categoryValue,
288     const char *str)
289 {
290     Z_OtherInformation **otherInformation;
291     get_otherInfoAPDU(apdu, &otherInformation);
292     if (!otherInformation)
293         return;
294     set_otherInformationString(otherInformation, oidval, categoryValue, str);
295 }
296
297 void Yaz_Z_Assoc::set_otherInformationString (
298     Z_OtherInformation **otherInformation,
299     int oidval, int categoryValue,
300     const char *str)
301 {
302     int oid[OID_SIZE];
303     struct oident ent;
304     ent.proto = PROTO_Z3950;
305     ent.oclass = CLASS_USERINFO;
306     ent.value = (oid_value) oidval;
307     if (!oid_ent_to_oid (&ent, oid))
308         return ;
309     set_otherInformationString(otherInformation, oid, categoryValue, str);
310 }
311
312 void Yaz_Z_Assoc::set_otherInformationString (
313     Z_OtherInformation **otherInformation,
314     int *oid, int categoryValue, const char *str)
315 {
316     Z_OtherInformationUnit *oi =
317         update_otherInformation(otherInformation, 1, oid, categoryValue, 0);
318     if (!oi)
319         return;
320     oi->information.characterInfo = odr_strdup (odr_encode(), str);
321 }
322
323 Z_OtherInformationUnit *Yaz_Z_Assoc::update_otherInformation (
324     Z_OtherInformation **otherInformationP, int createFlag,
325     int *oid, int categoryValue, int deleteFlag)
326 {
327     return yaz_oi_update (otherInformationP,
328                           (createFlag ? odr_encode() : 0),
329                           oid, categoryValue, deleteFlag);
330 }
331
332 Z_ReferenceId* Yaz_Z_Assoc::getRefID(char* str)
333 {
334     Z_ReferenceId* id = NULL;
335
336     if ( str )
337     {
338         id = (Z_ReferenceId*) odr_malloc (m_odr_out, sizeof(*id));
339         id->size = id->len = strlen(str);
340         id->buf = (unsigned char *) str;
341     }
342
343     return id;
344 }
345