Add LICENSE file and Refer to it from the source. Include license material
[metaproxy-moved-to-github.git] / src / filter_session_shared.cpp
1 /* $Id: filter_session_shared.cpp,v 1.11 2006-06-10 14:29:12 adam Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5  */
6
7 #include "config.hpp"
8
9 #include "filter.hpp"
10 #include "package.hpp"
11
12 #include <boost/thread/mutex.hpp>
13 #include <boost/thread/condition.hpp>
14 #include <boost/shared_ptr.hpp>
15
16 #include "util.hpp"
17 #include "filter_session_shared.hpp"
18
19 #include <yaz/log.h>
20 #include <yaz/zgdu.h>
21 #include <yaz/otherinfo.h>
22 #include <yaz/diagbib1.h>
23
24 #include <map>
25 #include <iostream>
26
27 namespace mp = metaproxy_1;
28 namespace yf = metaproxy_1::filter;
29
30 namespace metaproxy_1 {
31
32     namespace filter {
33
34         class SessionShared::InitKey {
35         public:
36             bool operator < (const SessionShared::InitKey &k) const;
37             InitKey(Z_InitRequest *req);
38         private:
39             char *m_idAuthentication_buf;
40             int m_idAuthentication_size;
41             char *m_otherInfo_buf;
42             int m_otherInfo_size;
43             mp::odr m_odr;
44
45             std::list<std::string> m_targets;
46         };
47         class SessionShared::BackendClass {
48             yazpp_1::GDU m_init_response;
49         };
50         struct SessionShared::Frontend {
51             void init(Package &package, Z_GDU *gdu);
52             Frontend(Rep *rep);
53             ~Frontend();
54             mp::Session m_session;
55             bool m_is_virtual;
56             bool m_in_use;
57
58             void close(Package &package);
59             Rep *m_p;
60         };            
61         class SessionShared::Rep {
62             friend class SessionShared;
63             friend struct Frontend;
64             
65             FrontendPtr get_frontend(Package &package);
66             void release_frontend(Package &package);
67         private:
68             boost::mutex m_mutex;
69             boost::condition m_cond_session_ready;
70             std::map<mp::Session, FrontendPtr> m_clients;
71
72             typedef std::map<InitKey,BackendClass> BackendClassMap;
73             BackendClassMap m_backend_map;
74         };
75     }
76 }
77
78
79 yf::SessionShared::InitKey::InitKey(Z_InitRequest *req)
80 {
81     Z_IdAuthentication *t = req->idAuthentication;
82     
83     z_IdAuthentication(m_odr, &t, 1, 0);
84     m_idAuthentication_buf =
85         odr_getbuf(m_odr, &m_idAuthentication_size, 0);
86
87     Z_OtherInformation *o = req->otherInfo;
88     z_OtherInformation(m_odr, &o, 1, 0);
89     m_otherInfo_buf = odr_getbuf(m_odr, &m_otherInfo_size, 0);
90 }
91
92 bool yf::SessionShared::InitKey::operator < (const SessionShared::InitKey &k)
93     const 
94 {
95     int c;
96     c = mp::util::memcmp2(
97         (void*) m_idAuthentication_buf, m_idAuthentication_size,
98         (void*) k.m_idAuthentication_buf, k.m_idAuthentication_size);
99     if (c < 0)
100         return true;
101     else if (c > 0)
102         return false;
103
104     c = mp::util::memcmp2((void*) m_otherInfo_buf, m_otherInfo_size,
105                           (void*) k.m_otherInfo_buf, k.m_otherInfo_size);
106     if (c < 0)
107         return true;
108     else if (c > 0)
109         return false;
110     return false;
111 }
112
113 void yf::SessionShared::Frontend::init(mp::Package &package, Z_GDU *gdu)
114 {
115     Z_InitRequest *req = gdu->u.z3950->u.initRequest;
116
117     std::list<std::string> targets;
118
119     mp::util::get_vhost_otherinfo(&req->otherInfo, false, targets);
120
121     // std::cout << "SessionShared::Frontend::init\n";
122     if (targets.size() < 1)
123     {
124         // no targets given, just relay this one and don't deal with it
125         package.move();
126         return;
127     }
128     InitKey k(req);
129 }
130
131 yf::SessionShared::SessionShared() : m_p(new SessionShared::Rep)
132 {
133 }
134
135 yf::SessionShared::~SessionShared() {
136 }
137
138
139 yf::SessionShared::Frontend::Frontend(Rep *rep) : m_is_virtual(false), m_p(rep)
140 {
141 }
142
143 void yf::SessionShared::Frontend::close(mp::Package &package)
144 {
145 #if 0
146     std::list<BackendPtr>::const_iterator b_it;
147     
148     for (b_it = m_backend_list.begin(); b_it != m_backend_list.end(); b_it++)
149     {
150         (*b_it)->m_backend_session.close();
151         Package close_package((*b_it)->m_backend_session, package.origin());
152         close_package.copy_filter(package);
153         close_package.move((*b_it)->m_route);
154     }
155     m_backend_list.clear();
156 #endif
157 }
158
159
160 yf::SessionShared::Frontend::~Frontend()
161 {
162 }
163
164 yf::SessionShared::FrontendPtr yf::SessionShared::Rep::get_frontend(mp::Package &package)
165 {
166     boost::mutex::scoped_lock lock(m_mutex);
167
168     std::map<mp::Session,yf::SessionShared::FrontendPtr>::iterator it;
169     
170     while(true)
171     {
172         it = m_clients.find(package.session());
173         if (it == m_clients.end())
174             break;
175         
176         if (!it->second->m_in_use)
177         {
178             it->second->m_in_use = true;
179             return it->second;
180         }
181         m_cond_session_ready.wait(lock);
182     }
183     FrontendPtr f(new Frontend(this));
184     m_clients[package.session()] = f;
185     f->m_in_use = true;
186     return f;
187 }
188
189 void yf::SessionShared::Rep::release_frontend(mp::Package &package)
190 {
191     boost::mutex::scoped_lock lock(m_mutex);
192     std::map<mp::Session,yf::SessionShared::FrontendPtr>::iterator it;
193     
194     it = m_clients.find(package.session());
195     if (it != m_clients.end())
196     {
197         if (package.session().is_closed())
198         {
199             it->second->close(package);
200             m_clients.erase(it);
201         }
202         else
203         {
204             it->second->m_in_use = false;
205         }
206         m_cond_session_ready.notify_all();
207     }
208 }
209
210
211 void yf::SessionShared::process(mp::Package &package) const
212 {
213     FrontendPtr f = m_p->get_frontend(package);
214
215     Z_GDU *gdu = package.request().get();
216     
217     if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
218         Z_APDU_initRequest && !f->m_is_virtual)
219     {
220         f->init(package, gdu);
221     }
222     else if (!f->m_is_virtual)
223         package.move();
224     else if (gdu && gdu->which == Z_GDU_Z3950)
225     {
226         Z_APDU *apdu = gdu->u.z3950;
227         if (apdu->which == Z_APDU_initRequest)
228         {
229             mp::odr odr;
230             
231             package.response() = odr.create_close(
232                 apdu,
233                 Z_Close_protocolError,
234                 "double init");
235             
236             package.session().close();
237         }
238         else
239         {
240             mp::odr odr;
241             
242             package.response() = odr.create_close(
243                 apdu, Z_Close_protocolError,
244                 "unsupported APDU in filter_session_shared");
245             
246             package.session().close();
247         }
248     }
249     m_p->release_frontend(package);
250 }
251
252 static mp::filter::Base* filter_creator()
253 {
254     return new mp::filter::SessionShared;
255 }
256
257 extern "C" {
258     struct metaproxy_1_filter_struct metaproxy_1_filter_session_shared = {
259         0,
260         "session_shared",
261         filter_creator
262     };
263 }
264
265 /*
266  * Local variables:
267  * c-basic-offset: 4
268  * indent-tabs-mode: nil
269  * c-file-style: "stroustrup"
270  * End:
271  * vim: shiftwidth=4 tabstop=8 expandtab
272  */