Rename from yp2 to metaproxy. The namespace for all definitions
[metaproxy-moved-to-github.git] / src / filter_session_shared.cpp
1 /* $Id: filter_session_shared.cpp,v 1.7 2006-03-16 10:40:59 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/shared_ptr.hpp>
14
15 #include "util.hpp"
16 #include "filter_session_shared.hpp"
17
18 #include <yaz/log.h>
19 #include <yaz/zgdu.h>
20 #include <yaz/otherinfo.h>
21 #include <yaz/diagbib1.h>
22
23 #include <map>
24 #include <iostream>
25
26 namespace mp = metaproxy_1;
27 namespace yf = mp::filter;
28
29 namespace metaproxy_1 {
30     namespace filter {
31         class SessionShared::Rep {
32             friend class SessionShared;
33             void handle_init(Z_InitRequest *req, Package &package);
34             void handle_search(Z_APDU *req, Package &package);
35         public:
36             typedef boost::shared_ptr<SessionShared::List> SharedList;
37
38             typedef std::map<SessionShared::InitKey,SharedList> InitListMap;
39             InitListMap m_init_list_map;
40
41             typedef std::map<Session,SharedList> SessionListMap;
42             SessionListMap m_session_list_map;
43
44         };
45         class SessionShared::InitKey {
46             friend class SessionShared;
47             friend class SessionShared::Rep;
48             std::string m_vhost;
49             std::string m_open;
50             std::string m_user;
51             std::string m_group;
52             std::string m_password;
53         public:
54             bool operator < (const SessionShared::InitKey &k) const;
55         };
56         class SessionShared::List {
57         public:
58             yazpp_1::GDU m_init_response;  // init response for backend 
59             Session m_session;             // session for backend
60         };
61     }
62     
63 }
64
65 using namespace mp;
66
67 bool yf::SessionShared::InitKey::operator < (const SessionShared::InitKey
68                                               &k) const 
69 {
70     if (m_vhost < k.m_vhost)
71         return true;
72     else if (m_vhost < k.m_vhost)
73         return false;
74
75     if (m_open < k.m_open)
76         return true;
77     else if (m_open > k.m_open)
78         return false;
79
80     if (m_user < k.m_user)
81         return true;
82     else if (m_user > k.m_user)
83         return false;
84  
85     if (m_group < k.m_group)
86         return true;
87     else if (m_group > k.m_group)
88         return false;
89
90     if (m_password < k.m_password)
91         return true;
92     else if (m_password > k.m_password)
93         return false;
94     return false;
95 }
96
97 yf::SessionShared::SessionShared() : m_p(new Rep)
98 {
99 }
100
101 yf::SessionShared::~SessionShared()
102 {
103 }
104
105 void yf::SessionShared::Rep::handle_search(Z_APDU *apdu_req,
106                                            Package &package)
107 {
108     yaz_log(YLOG_LOG, "Got search");
109
110     // Z_SearchRequest *req = apdu_req->u.searchRequest;
111
112     SessionListMap::iterator it = m_session_list_map.find(package.session());
113     if (it == m_session_list_map.end())
114     {
115         mp::odr odr;
116         package.response() =
117             odr.create_close(apdu_req,
118                              Z_Close_protocolError,
119                              "no session for search request in session_shared");
120         package.session().close();
121         
122         return;
123     }
124     Package search_package(it->second->m_session, package.origin());
125     search_package.copy_filter(package);
126     search_package.request() = package.request();
127     
128     search_package.move();
129         
130     // transfer to frontend
131     package.response() = search_package.response();
132 }
133
134 void yf::SessionShared::Rep::handle_init(Z_InitRequest *req, Package &package)
135 {
136     yaz_log(YLOG_LOG, "Got init");
137
138     SessionShared::InitKey key;
139     const char *vhost =
140         yaz_oi_get_string_oidval(&req->otherInfo, VAL_PROXY, 1, 0);
141     if (vhost)
142         key.m_vhost = vhost;
143
144     if (!req->idAuthentication)
145     {
146         yaz_log(YLOG_LOG, "No authentication");
147     }
148     else
149     {
150         Z_IdAuthentication *auth = req->idAuthentication;
151         switch(auth->which)
152         {
153         case Z_IdAuthentication_open:
154             yaz_log(YLOG_LOG, "open auth open=%s", auth->u.open);
155             key.m_open = auth->u.open;
156             break;
157         case Z_IdAuthentication_idPass:
158             yaz_log(YLOG_LOG, "idPass user=%s group=%s pass=%s",
159                     auth->u.idPass->userId, auth->u.idPass->groupId,
160                     auth->u.idPass->password);
161             if (auth->u.idPass->userId)
162                 key.m_user = auth->u.idPass->userId;
163             if (auth->u.idPass->groupId)
164                 key.m_group  = auth->u.idPass->groupId;
165             if (auth->u.idPass->password)
166                 key.m_password  = auth->u.idPass->password;
167             break;
168         case Z_IdAuthentication_anonymous:
169             yaz_log(YLOG_LOG, "anonymous");
170             break;
171         default:
172             yaz_log(YLOG_LOG, "other");
173         } 
174     }
175     InitListMap::iterator it = m_init_list_map.find(key);
176     if (it == m_init_list_map.end())
177     {
178         yaz_log(YLOG_LOG, "New KEY");
179
180         // building new package with original init and new session 
181         SharedList l(new SessionShared::List);  // new session for backend
182
183         Package init_package(l->m_session, package.origin());
184         init_package.copy_filter(package);
185         init_package.request() = package.request();
186
187         init_package.move();
188         
189         // transfer to frontend
190         package.response() = init_package.response();
191          
192         // check that we really got Z39.50 Init Response
193         Z_GDU *gdu = init_package.response().get();
194         if (gdu && gdu->which == Z_GDU_Z3950
195            && gdu->u.z3950->which == Z_APDU_initResponse)
196         {
197             // save the init response
198             l->m_init_response = init_package.response();
199             
200             // save session and init response for later
201             m_init_list_map[key] = l;
202
203             m_session_list_map[package.session()] = l;
204         }
205     }
206     else
207     {
208         yaz_log(YLOG_LOG, "Existing KEY");
209         package.response() = it->second->m_init_response;
210
211         m_session_list_map[package.session()] = it->second;
212     }
213 }
214
215 void yf::SessionShared::process(Package &package) const
216 {
217     // don't tell the backend if the "fronent" filter closes..
218     // we want to keep them alive
219     if (package.session().is_closed())
220     {
221         m_p->m_session_list_map.erase(package.session());
222         return;
223     }
224
225     Z_GDU *gdu = package.request().get();
226
227     if (gdu && gdu->which == Z_GDU_Z3950)
228     {
229         Z_APDU *apdu = gdu->u.z3950;
230
231         switch(apdu->which)
232         {
233         case Z_APDU_initRequest:
234             m_p->handle_init(apdu->u.initRequest, package);
235             break;
236         case Z_APDU_searchRequest:
237             m_p->handle_search(apdu, package);
238             break;
239         default:
240             mp::odr odr;
241             package.response() =
242                 odr.create_close(apdu, Z_Close_protocolError,
243                                  "cannot handle a package of this type");
244             package.session().close();
245             break;
246             
247         }
248         if (package.session().is_closed()) {
249             m_p->m_session_list_map.erase(package.session());
250         }
251     }
252     else
253         package.move();  // Not Z39.50 or not Init
254 }
255
256 static mp::filter::Base* filter_creator()
257 {
258     return new mp::filter::SessionShared;
259 }
260
261 extern "C" {
262     struct metaproxy_1_filter_struct metaproxy_1_filter_session_shared = {
263         0,
264         "session_shared",
265         filter_creator
266     };
267 }
268
269
270
271 /*
272  * Local variables:
273  * c-basic-offset: 4
274  * indent-tabs-mode: nil
275  * c-file-style: "stroustrup"
276  * End:
277  * vim: shiftwidth=4 tabstop=8 expandtab
278  */