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