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