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