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