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