Many improvements. Modified to proxy server to work with "sessions"
[yazpp-moved-to-github.git] / src / yaz-proxy.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-proxy.cpp,v $
7  * Revision 1.5  1999-04-21 12:09:01  adam
8  * Many improvements. Modified to proxy server to work with "sessions"
9  * based on cookies.
10  *
11  * Revision 1.4  1999/04/20 10:30:05  adam
12  * Implemented various stuff for client and proxy. Updated calls
13  * to ODR to reflect new name parameter.
14  *
15  * Revision 1.3  1999/04/09 11:46:57  adam
16  * Added object Yaz_Z_Assoc. Much more functional client.
17  *
18  * Revision 1.2  1999/01/28 13:08:46  adam
19  * Yaz_PDU_Assoc better encapsulated. Memory leak fix in
20  * yaz-socket-manager.cc.
21  *
22  * Revision 1.1.1.1  1999/01/28 09:41:07  adam
23  * First implementation of YAZ++.
24  *
25  */
26
27 #include <assert.h>
28
29 #include <log.h>
30
31 #include <yaz-proxy.h>
32
33 Yaz_Proxy::Yaz_Proxy(IYaz_PDU_Observable *the_PDU_Observable) :
34     Yaz_Z_Assoc(the_PDU_Observable)
35 {
36     m_PDU_Observable = the_PDU_Observable;
37     m_client = 0;
38     m_parent = 0;
39     m_clientPool = 0;
40     m_seqno = 1;
41     m_keepalive = 1;
42 }
43
44 Yaz_Proxy::~Yaz_Proxy()
45 {
46 }
47
48 IYaz_PDU_Observer *Yaz_Proxy::clone(IYaz_PDU_Observable
49                                     *the_PDU_Observable)
50 {
51     Yaz_Proxy *new_proxy = new Yaz_Proxy(the_PDU_Observable);
52     new_proxy->m_parent = this;
53     new_proxy->timeout(120);
54     return new_proxy;
55 }
56
57 char *Yaz_Proxy::get_cookie(Z_OtherInformation **otherInfo)
58 {
59     int oid[OID_SIZE];
60     Z_OtherInformationUnit *oi;
61     struct oident ent;
62     ent.proto = PROTO_Z3950;
63     ent.oclass = CLASS_USERINFO;
64     ent.value = (oid_value) VAL_COOKIE;
65     assert (oid_ent_to_oid (&ent, oid));
66
67     if (oid_ent_to_oid (&ent, oid) && 
68         (oi = update_otherInformation(otherInfo, 0, oid, 1)) &&
69         oi->which == Z_OtherInfo_characterInfo)
70         return oi->information.characterInfo;
71     return 0;
72 }
73
74 char *Yaz_Proxy::get_proxy(Z_OtherInformation **otherInfo)
75 {
76     int oid[OID_SIZE];
77     Z_OtherInformationUnit *oi;
78     struct oident ent;
79     ent.proto = PROTO_Z3950;
80     ent.oclass = CLASS_USERINFO;
81     ent.value = (oid_value) VAL_PROXY;
82     if (oid_ent_to_oid (&ent, oid) &&
83         (oi = update_otherInformation(otherInfo, 0, oid, 1)) &&
84         oi->which == Z_OtherInfo_characterInfo)
85         return oi->information.characterInfo;
86     return 0;
87 }
88
89 Yaz_ProxyClient *Yaz_Proxy::get_client(Z_APDU *apdu)
90 {
91     assert (m_parent);
92     Yaz_Proxy *parent = m_parent;
93     Z_OtherInformation **oi;
94     Yaz_ProxyClient *c = m_client;
95     
96     get_otherInfoAPDU(apdu, &oi);
97     char *cookie = get_cookie(oi);
98     logf (LOG_LOG, "Yaz_Proxy::get_client cookie=%s", cookie ? cookie :
99           "<null>");
100     if (cookie)
101     {
102         for (c = parent->m_clientPool; c; c = c->m_next)
103         {
104             assert (c->m_prev);
105             assert (*c->m_prev == c);
106             if (!strcmp(cookie,c->m_cookie))
107             {
108                 logf (LOG_LOG, "Yaz_Proxy::get_client cached");
109                 break;
110             }
111         }
112     }
113     else if (!m_client)
114     {
115         logf (LOG_LOG, "Yaz_Proxy::get_client creating new");
116         c = new Yaz_ProxyClient(m_PDU_Observable->clone());
117         c->m_next = parent->m_clientPool;
118         if (c->m_next)
119             c->m_next->m_prev = &c->m_next;
120         parent->m_clientPool = c;
121         c->m_prev = &parent->m_clientPool;
122
123         sprintf (c->m_cookie, "%d", parent->m_seqno);
124         (parent->m_seqno)++;
125
126         if (apdu->which == Z_APDU_initRequest)
127         {
128             logf (LOG_LOG, "got InitRequest");
129             
130             char *proxy_host = get_proxy(&apdu->u.initRequest->otherInfo);
131             if (proxy_host)
132                 c->client(proxy_host);
133             else
134                 c->client("localhost:9999");
135         }
136         c->timeout(600);
137     }
138     return c;
139 }
140
141 void Yaz_Proxy::recv_Z_PDU(Z_APDU *apdu)
142 {
143     logf (LOG_LOG, "Yaz_Proxy::recv_Z_PDU");
144     // Determine our client.
145     m_client = get_client(apdu);
146     if (!m_client)
147     {
148         delete this;
149         return;
150     }
151     m_client->m_server = this;
152
153     Z_OtherInformation **oi;
154     get_otherInfoAPDU(apdu, &oi);
155     *oi = 0;
156     logf (LOG_LOG, "Yaz_ProxyClient::send_Z_PDU");
157     if (m_client->send_Z_PDU(apdu) < 0)
158     {
159         delete m_client;
160         delete this;
161     }
162 }
163
164 void Yaz_Proxy::failNotify()
165 {
166     logf (LOG_LOG, "failNotity server");
167     if (m_keepalive)
168     {
169         // Tell client (if any) that not server connection is there..
170         if (m_client)
171             m_client->m_server = 0;
172     }
173     else
174     {
175         delete m_client;
176     }
177     delete this;
178 }
179
180 void Yaz_ProxyClient::failNotify()
181 {
182     logf (LOG_LOG, "failNotity client");
183     delete m_server;
184     delete this;
185 }
186
187 IYaz_PDU_Observer *Yaz_ProxyClient::clone(IYaz_PDU_Observable
188                                           *the_PDU_Observable)
189 {
190     return new Yaz_ProxyClient(the_PDU_Observable);
191 }
192
193 Yaz_ProxyClient::~Yaz_ProxyClient()
194 {
195     if (m_prev)
196     {
197         *m_prev = m_next;
198         if (m_next)
199             m_next->m_prev = m_prev;
200     }
201 }
202
203 void Yaz_Proxy::timeoutNotify()
204 {
205     failNotify();
206 }
207
208 void Yaz_ProxyClient::timeoutNotify()
209 {
210     failNotify();
211 }
212
213 Yaz_ProxyClient::Yaz_ProxyClient(IYaz_PDU_Observable *the_PDU_Observable) :
214     Yaz_Z_Assoc (the_PDU_Observable)
215 {
216     m_cookie[0] = 0;
217     m_next = 0;
218     m_prev = 0;
219 }
220
221 void Yaz_ProxyClient::recv_Z_PDU(Z_APDU *apdu)
222 {
223     logf (LOG_LOG, "Yaz_ProxyClient::recv_Z_PDU");
224     if (m_cookie)
225         set_otherInformationString (apdu, VAL_COOKIE, 1, m_cookie);
226     if (m_server)
227     {
228         logf (LOG_LOG, "Yaz_Proxy::send_Z_PDU");
229         m_server->send_Z_PDU(apdu);
230     }
231 }