metaproxy 1.22.1
filter_virt_db.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20
21#include "filter_virt_db.hpp"
22#include <metaproxy/package.hpp>
23
24#include <boost/thread/mutex.hpp>
25#include <boost/thread/condition.hpp>
26#include <boost/shared_ptr.hpp>
27
28#include <metaproxy/util.hpp>
29
30#include <yaz/zgdu.h>
31#include <yaz/otherinfo.h>
32#include <yaz/diagbib1.h>
33#include <yaz/match_glob.h>
34#include <yaz/log.h>
35#include <yaz/oid_db.h>
36
37#include <map>
38#include <iostream>
39
40namespace mp = metaproxy_1;
41namespace yf = mp::filter;
42
43namespace metaproxy_1 {
44 namespace filter {
45
47 Set(BackendPtr b, std::string setname);
48 Set();
49 ~Set();
50
52 std::string m_setname;
53 };
55 Map(std::string database, std::list<std::string> targets, std::string route);
56 Map(std::string database, std::string target, std::string route);
57 Map();
58 bool match(const std::string db) const;
59 std::string m_dbpattern;
60 std::list<std::string> m_targets;
61 std::string m_route;
62 };
64 mp::Session m_backend_session;
65 std::list<std::string> m_frontend_databases;
66 std::list<std::string> m_targets;
67 std::string m_route;
69 };
71 Frontend(Rep *rep);
72 ~Frontend();
73 mp::Session m_session;
76 yazpp_1::GDU m_init_gdu;
77 std::list<BackendPtr> m_backend_list;
78 std::map<std::string,VirtualDB::Set> m_sets;
79
80 void search(Package &package, Z_APDU *apdu);
81 void present(Package &package, Z_APDU *apdu);
82 void scan(Package &package, Z_APDU *apdu);
83 int relay_apdu(Package &package, Z_APDU *apdu);
84
85 void close(Package &package);
86 typedef std::map<std::string,VirtualDB::Set>::iterator Sets_it;
87
88 void fixup_package(Package &p, BackendPtr b);
89 void fixup_npr_record(ODR odr, Z_NamePlusRecord *npr,
90 BackendPtr b);
91 void fixup_npr_records(ODR odr, Z_Records *records,
92 BackendPtr b);
93
95 std::list<std::string> databases,
96 int &error_code,
97 std::string &failing_database);
98
99 BackendPtr init_backend(std::list<std::string> database,
100 Package &package,
101 int &error_code, std::string &addinfo);
103 };
105 friend class VirtualDB;
106 friend struct Frontend;
107
108 FrontendPtr get_frontend(Package &package);
109 void release_frontend(Package &package);
111 private:
112 std::list<VirtualDB::Map>m_maps;
113 typedef std::map<std::string,VirtualDB::Set>::iterator Sets_it;
114 boost::mutex m_mutex;
115 boost::condition m_cond_session_ready;
116 std::map<mp::Session, FrontendPtr> m_clients;
118 };
119 }
120}
121
122yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::create_backend_from_databases(
123 std::list<std::string> databases, int &error_code, std::string &addinfo)
124{
125 BackendPtr b(new Backend);
126 std::list<std::string>::const_iterator db_it = databases.begin();
127
128 b->m_frontend_databases = databases;
129 b->m_named_result_sets = false;
130
131 bool first_route = true;
132
133 std::map<std::string,bool> targets_dedup;
134 for (; db_it != databases.end(); db_it++)
135 {
136 std::list<VirtualDB::Map>::const_iterator map_it;
137 map_it = m_p->m_maps.begin();
138 while (map_it != m_p->m_maps.end())
139 {
140 if (map_it->match(*db_it))
141 break;
142 map_it++;
143 }
144
145 if (map_it == m_p->m_maps.end()) // database not found
146 {
147 error_code = YAZ_BIB1_DATABASE_DOES_NOT_EXIST;
148 addinfo = *db_it;
149 BackendPtr ptr;
150 return ptr;
151 }
152 std::list<std::string>::const_iterator t_it =
153 map_it->m_targets.begin();
154 for (; t_it != map_it->m_targets.end(); t_it++) {
155 if (!targets_dedup[*t_it])
156 {
157 targets_dedup[*t_it] = true;
158 b->m_targets.push_back(*t_it);
159 }
160 }
161
162 // see if we have a route conflict.
163 if (!first_route && b->m_route != map_it->m_route)
164 {
165 // we have a conflict.. routing must be same for all
166 error_code = YAZ_BIB1_COMBI_OF_SPECIFIED_DATABASES_UNSUPP;
167 BackendPtr ptr;
168 return ptr;
169 }
170 b->m_route = map_it->m_route;
171 first_route = false;
172 }
173 return b;
174}
175
176yf::VirtualDB::BackendPtr yf::VirtualDB::Frontend::init_backend(
177 std::list<std::string> databases, mp::Package &package,
178 int &error_code, std::string &addinfo)
179{
180 BackendPtr b = create_backend_from_databases(databases, error_code,
181 addinfo);
182 if (!b)
183 return b;
184 Package init_package(b->m_backend_session, package.origin());
185 init_package.copy_filter(package);
186
187 mp::odr odr;
188
189 Z_APDU *init_apdu = zget_APDU(odr, Z_APDU_initRequest);
190
191 mp::util::set_vhost_otherinfo(&init_apdu->u.initRequest->otherInfo, odr,
192 b->m_targets);
193 Z_InitRequest *req = init_apdu->u.initRequest;
194
195 // copy stuff from Frontend Init Request
196 Z_GDU *org_gdu = m_init_gdu.get();
197 Z_InitRequest *org_init = org_gdu->u.z3950->u.initRequest;
198
199
200 const char *peer_name = yaz_oi_get_string_oid(
201 &org_init->otherInfo, yaz_oid_userinfo_client_ip, 1, 0);
202 if (peer_name)
203 yaz_oi_set_string_oid(&init_apdu->u.initRequest->otherInfo, odr,
204 yaz_oid_userinfo_client_ip, 1, peer_name);
205
206 req->idAuthentication = org_init->idAuthentication;
207 req->implementationId = org_init->implementationId;
208 req->implementationName = org_init->implementationName;
209 req->implementationVersion = org_init->implementationVersion;
210 *req->preferredMessageSize = *org_init->preferredMessageSize;
211 *req->maximumRecordSize = *org_init->maximumRecordSize;
212
213 ODR_MASK_SET(req->options, Z_Options_search);
214 ODR_MASK_SET(req->options, Z_Options_present);
215 ODR_MASK_SET(req->options, Z_Options_namedResultSets);
216 ODR_MASK_SET(req->options, Z_Options_scan);
217
218 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
219 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
220 ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
221
222 init_package.request() = init_apdu;
223
224 init_package.move(b->m_route); // sending init
225
226 Z_GDU *gdu = init_package.response().get();
227 // we hope to get an init response
228 error_code = 0;
229 if (gdu && gdu->which == Z_GDU_Z3950
230 && gdu->u.z3950->which == Z_APDU_initResponse)
231 {
232 Z_InitResponse *res = gdu->u.z3950->u.initResponse;
233 if (ODR_MASK_GET(res->options, Z_Options_namedResultSets))
234 {
235 b->m_named_result_sets = true;
236 }
237 if (*res->result && !init_package.session().is_closed())
238 {
239 m_backend_list.push_back(b);
240 return b;
241 }
242 mp::util::get_init_diagnostics(res, error_code, addinfo);
243 }
244 if (error_code == 0)
245 {
246 std::list<std::string>::const_iterator db_it = databases.begin();
247 error_code = YAZ_BIB1_ACCESS_TO_SPECIFIED_DATABASE_DENIED;
248 if (db_it != databases.end())
249 addinfo = *db_it;
250 }
251 if (!init_package.session().is_closed())
252 {
253 Package close_package(b->m_backend_session, package.origin());
254 close_package.copy_filter(package);
255 close_package.session().close();
256 close_package.move(b->m_route); // closing it
257 }
258 BackendPtr null;
259 return null;
260}
261
262void yf::VirtualDB::Frontend::search(mp::Package &package, Z_APDU *apdu_req)
263{
264 yazpp_1::GDU ngdu(apdu_req);
265 Z_SearchRequest *req = ngdu.get()->u.z3950->u.searchRequest;
266 std::string vhost;
267 std::string resultSetId = req->resultSetName;
268 mp::odr odr;
269
270 std::list<std::string> databases;
271 int i;
272 for (i = 0; i<req->num_databaseNames; i++)
273 databases.push_back(req->databaseNames[i]);
274
275 Sets_it sets_it = m_sets.find(req->resultSetName);
276 bool override_set = false;
277 if (sets_it != m_sets.end())
278 {
279 // result set already exist
280 // if replace indicator is off: we return diagnostic if
281 // result set already exist.
282 if (*req->replaceIndicator == 0)
283 {
284 Z_APDU *apdu =
285 odr.create_searchResponse(
286 apdu_req,
287 YAZ_BIB1_RESULT_SET_EXISTS_AND_REPLACE_INDICATOR_OFF,
288 0);
289 package.response() = apdu;
290
291 return;
292 }
293 override_set = true;
294 }
295 // pick up any existing database with named result sets ..
296 // or one if we are overriding it
297 BackendPtr b; // null for now
298 std::list<BackendPtr>::const_iterator map_it;
299 map_it = m_backend_list.begin();
300 for (; map_it != m_backend_list.end(); map_it++)
301 {
302 BackendPtr tmp = *map_it;
303 if (mp::util::match(tmp->m_frontend_databases, databases) &&
304 (tmp->m_named_result_sets || override_set))
305 {
306 b = *map_it;
307 break;
308 }
309 }
310 if (!b) // no backend yet. Must create a new one
311 {
312 int error_code;
313 std::string addinfo;
314 b = init_backend(databases, package, error_code, addinfo);
315 if (!b)
316 {
317 // did not get a backend (unavailable somehow?)
318
319 Z_APDU *apdu =
320 odr.create_searchResponse(
321 apdu_req, error_code, addinfo.c_str());
322 package.response() = apdu;
323 return;
324 }
325 }
326 m_sets.erase(req->resultSetName);
327 // sending search to backend
328 Package search_package(b->m_backend_session, package.origin());
329
330 search_package.copy_filter(package);
331
332 std::string backend_setname;
333 if (b->m_named_result_sets)
334 {
335 backend_setname = std::string(req->resultSetName);
336 }
337 else
338 {
339 backend_setname = "default";
340 req->resultSetName = odr_strdup(odr, backend_setname.c_str());
341 }
342
343 // pick first targets spec and move the databases from it ..
344 std::list<std::string>::const_iterator t_it = b->m_targets.begin();
345 if (t_it != b->m_targets.end())
346 {
347 mp::util::set_databases_from_zurl(odr, *t_it,
348 &req->num_databaseNames,
349 &req->databaseNames);
350 }
351
352 *req->replaceIndicator = 1;
353
354 search_package.request() = ngdu;
355
356 search_package.move(b->m_route);
357
358 if (search_package.session().is_closed())
359 {
360 package.response() = search_package.response();
361 package.session().close();
362 return;
363 }
364
365 Z_GDU *gdu = search_package.response().get();
366 if (gdu && gdu->which == Z_GDU_Z3950
367 && gdu->u.z3950->which == Z_APDU_searchResponse)
368 {
369 Z_SearchResponse *b_resp = gdu->u.z3950->u.searchResponse;
370 Z_Records *z_records = b_resp->records;
371 if (!z_records || (z_records && z_records->which == Z_Records_DBOSD))
372 {
373 m_sets[resultSetId] = VirtualDB::Set(b, backend_setname);
374 fixup_package(search_package, b);
375 }
376 }
377 package.response() = search_package.response();
378}
379
380yf::VirtualDB::Frontend::Frontend(Rep *rep)
381{
382 m_p = rep;
383 m_is_virtual = false;
384}
385
386void yf::VirtualDB::Frontend::close(mp::Package &package)
387{
388 std::list<BackendPtr>::const_iterator b_it;
389
390 for (b_it = m_backend_list.begin(); b_it != m_backend_list.end(); b_it++)
391 {
392 (*b_it)->m_backend_session.close();
393 Package close_package((*b_it)->m_backend_session, package.origin());
394 close_package.copy_filter(package);
395 close_package.move((*b_it)->m_route);
396 }
397 m_backend_list.clear();
398}
399
400yf::VirtualDB::Frontend::~Frontend()
401{
402}
403
404yf::VirtualDB::FrontendPtr yf::VirtualDB::Rep::get_frontend(mp::Package &package)
405{
406 boost::mutex::scoped_lock lock(m_mutex);
407
408 std::map<mp::Session,yf::VirtualDB::FrontendPtr>::iterator it;
409
410 while(true)
411 {
412 it = m_clients.find(package.session());
413 if (it == m_clients.end())
414 break;
415
416 if (!it->second->m_in_use)
417 {
418 it->second->m_in_use = true;
419 return it->second;
420 }
421 m_cond_session_ready.wait(lock);
422 }
423 FrontendPtr f(new Frontend(this));
424 m_clients[package.session()] = f;
425 f->m_in_use = true;
426 return f;
427}
428
429void yf::VirtualDB::Rep::release_frontend(mp::Package &package)
430{
431 boost::mutex::scoped_lock lock(m_mutex);
432 std::map<mp::Session,yf::VirtualDB::FrontendPtr>::iterator it;
433
434 it = m_clients.find(package.session());
435 if (it != m_clients.end())
436 {
437 if (package.session().is_closed())
438 {
439 it->second->close(package);
440 m_clients.erase(it);
441 }
442 else
443 {
444 it->second->m_in_use = false;
445 }
446 m_cond_session_ready.notify_all();
447 }
448}
449
450
451yf::VirtualDB::Set::Set(BackendPtr b, std::string setname)
452 : m_backend(b), m_setname(setname)
453{
454}
455
456
457yf::VirtualDB::Set::Set()
458{
459}
460
461
462yf::VirtualDB::Set::~Set()
463{
464}
465
466yf::VirtualDB::Map::Map(std::string database,
467 std::list<std::string> targets, std::string route)
468 : m_dbpattern(database), m_targets(targets), m_route(route)
469{
470}
471
472yf::VirtualDB::Map::Map(std::string database,
473 std::string target, std::string route)
474 : m_dbpattern(database), m_route(route)
475{
476 m_targets.push_back(target);
477}
478
479
480yf::VirtualDB::Map::Map()
481{
482}
483
484bool yf::VirtualDB::Map::match(const std::string db) const
485{
486 std::string norm_db = mp::util::database_name_normalize(db);
487 if (yaz_match_glob(m_dbpattern.c_str(), norm_db.c_str()))
488 return true;
489 return false;
490}
491
492yf::VirtualDB::VirtualDB() : m_p(new VirtualDB::Rep)
493{
494 m_p->pass_vhosts = false;
495}
496
497yf::VirtualDB::~VirtualDB() {
498}
499
500void yf::VirtualDB::Frontend::fixup_npr_record(ODR odr, Z_NamePlusRecord *npr,
501 BackendPtr b)
502{
503 if (npr->databaseName)
504 {
505 std::string b_database = std::string(npr->databaseName);
506
507 // consider each of the frontend databases..
508 std::list<std::string>::const_iterator db_it;
509 for (db_it = b->m_frontend_databases.begin();
510 db_it != b->m_frontend_databases.end(); db_it++)
511 {
512 // see which target it corresponds to.. (if any)
513 std::list<VirtualDB::Map>::const_iterator map_it =
514 m_p->m_maps.begin();
515 while (map_it != m_p->m_maps.end())
516 {
517 if (map_it->match(*db_it))
518 break;
519 map_it++;
520 }
521 if (map_it != m_p->m_maps.end())
522 {
523 std::list<std::string>::const_iterator t
524 = map_it->m_targets.begin();
525 while (t != map_it->m_targets.end())
526 {
527 if (*t == b_database)
528 {
529 npr->databaseName = odr_strdup(odr, (*db_it).c_str());
530 return;
531 }
532 t++;
533 }
534 }
535
536 }
537 db_it = b->m_frontend_databases.begin();
538 if (db_it != b->m_frontend_databases.end())
539 {
540 std::string database = *db_it;
541 npr->databaseName = odr_strdup(odr, database.c_str());
542 }
543 }
544}
545
546void yf::VirtualDB::Frontend::fixup_npr_records(ODR odr, Z_Records *records,
547 BackendPtr b)
548{
549 if (records && records->which == Z_Records_DBOSD)
550 {
551 Z_NamePlusRecordList *nprlist = records->u.databaseOrSurDiagnostics;
552 int i;
553 for (i = 0; i < nprlist->num_records; i++)
554 {
555 fixup_npr_record(odr, nprlist->records[i], b);
556 }
557 }
558}
559
560void yf::VirtualDB::Frontend::fixup_package(mp::Package &p, BackendPtr b)
561{
562 Z_GDU *gdu = p.response().get();
563 mp::odr odr;
564
565 if (gdu && gdu->which == Z_GDU_Z3950)
566 {
567 Z_APDU *apdu = gdu->u.z3950;
568 if (apdu->which == Z_APDU_presentResponse)
569 {
570 fixup_npr_records(odr, apdu->u.presentResponse->records, b);
571 p.response() = gdu;
572 }
573 else if (apdu->which == Z_APDU_searchResponse)
574 {
575 fixup_npr_records(odr, apdu->u.searchResponse->records, b);
576 p.response() = gdu;
577 }
578 }
579}
580
581void yf::VirtualDB::Frontend::present(mp::Package &package, Z_APDU *apdu_req)
582{
583 yazpp_1::GDU ngdu(apdu_req);
584 Z_PresentRequest *req = ngdu.get()->u.z3950->u.presentRequest;
585 std::string resultSetId = req->resultSetId;
586 mp::odr odr;
587
588 Sets_it sets_it = m_sets.find(resultSetId);
589 if (sets_it == m_sets.end())
590 {
591 Z_APDU *apdu =
592 odr.create_presentResponse(
593 apdu_req,
594 YAZ_BIB1_SPECIFIED_RESULT_SET_DOES_NOT_EXIST,
595 resultSetId.c_str());
596 package.response() = apdu;
597 return;
598 }
599 Session *id =
600 new mp::Session(sets_it->second.m_backend->m_backend_session);
601
602 // sending present to backend
603 Package present_package(*id, package.origin());
604 present_package.copy_filter(package);
605
606 req->resultSetId = odr_strdup(odr, sets_it->second.m_setname.c_str());
607
608 present_package.request() = ngdu;
609
610 present_package.move(sets_it->second.m_backend->m_route);
611
612 fixup_package(present_package, sets_it->second.m_backend);
613
614 if (present_package.session().is_closed())
615 {
616 package.response() = present_package.response();
617 package.session().close();
618 }
619 else
620 {
621 package.response() = present_package.response();
622 }
623 delete id;
624}
625
626int yf::VirtualDB::Frontend::relay_apdu(mp::Package &package, Z_APDU *apdu_req)
627{
628 int no = 0;
629 std::list<BackendPtr>::const_iterator map_it;
630 map_it = m_backend_list.begin();
631 for (; map_it != m_backend_list.end(); map_it++)
632 {
633 BackendPtr b = *map_it;
634
635 Package relay_package(b->m_backend_session, package.origin());
636 relay_package.copy_filter(package);
637
638 relay_package.request() = yazpp_1::GDU(apdu_req);
639
640 relay_package.move(b->m_route);
641 package.response() = relay_package.response();
642 no++;
643 }
644 return no;
645}
646
647void yf::VirtualDB::Frontend::scan(mp::Package &package, Z_APDU *apdu_req)
648{
649 yazpp_1::GDU ngdu(apdu_req);
650 Z_ScanRequest *req = ngdu.get()->u.z3950->u.scanRequest;
651 std::string vhost;
652 mp::odr odr;
653
654 std::list<std::string> databases;
655 int i;
656 for (i = 0; i<req->num_databaseNames; i++)
657 databases.push_back(req->databaseNames[i]);
658
659 BackendPtr b;
660 // pick up any existing backend with a database match
661 std::list<BackendPtr>::const_iterator map_it;
662 map_it = m_backend_list.begin();
663 for (; map_it != m_backend_list.end(); map_it++)
664 {
665 BackendPtr tmp = *map_it;
666 if (mp::util::match(tmp->m_frontend_databases, databases))
667 break;
668 }
669 if (map_it != m_backend_list.end())
670 b = *map_it;
671 if (!b) // no backend yet. Must create a new one
672 {
673 int error_code;
674 std::string addinfo;
675 b = init_backend(databases, package, error_code, addinfo);
676 if (!b)
677 {
678 // did not get a backend (unavailable somehow?)
679 Z_APDU *apdu =
680 odr.create_scanResponse(
681 apdu_req, error_code, addinfo.c_str());
682 package.response() = apdu;
683
684 return;
685 }
686 }
687 // sending scan to backend
688 Package scan_package(b->m_backend_session, package.origin());
689
690 scan_package.copy_filter(package);
691
692 // pick first targets spec and move the databases from it ..
693 std::list<std::string>::const_iterator t_it = b->m_targets.begin();
694 if (t_it != b->m_targets.end())
695 {
696 mp::util::set_databases_from_zurl(odr, *t_it,
697 &req->num_databaseNames,
698 &req->databaseNames);
699 }
700
701 scan_package.request() = ngdu;
702
703 scan_package.move(b->m_route);
704
705 if (scan_package.session().is_closed())
706 {
707 package.response() = scan_package.response();
708 package.session().close();
709 return;
710 }
711 package.response() = scan_package.response();
712}
713
714
715void yf::VirtualDB::add_map_db2targets(std::string db,
716 std::list<std::string> targets,
717 std::string route)
718{
719 m_p->m_maps.push_back(
720 VirtualDB::Map(mp::util::database_name_normalize(db), targets, route));
721}
722
723
724void yf::VirtualDB::add_map_db2target(std::string db,
725 std::string target,
726 std::string route)
727
728{
729 m_p->m_maps.push_back(
730 VirtualDB::Map(mp::util::database_name_normalize(db), target, route));
731}
732
733void yf::VirtualDB::process(mp::Package &package) const
734{
735 FrontendPtr f = m_p->get_frontend(package);
736
737 Z_GDU *gdu = package.request().get();
738
739 if (gdu && gdu->which == Z_GDU_Z3950 && gdu->u.z3950->which ==
740 Z_APDU_initRequest && !f->m_is_virtual)
741 {
742 Z_InitRequest *req = gdu->u.z3950->u.initRequest;
743
744 std::list<std::string> vhosts;
745 mp::util::get_vhost_otherinfo(req->otherInfo, vhosts);
746
747 if (vhosts.size() > 0 && m_p->pass_vhosts)
748 {
749 package.move();
750 }
751 else
752 {
753 f->m_init_gdu = gdu;
754
755 mp::odr odr;
756 Z_APDU *apdu = odr.create_initResponse(gdu->u.z3950, 0, 0);
757 Z_InitResponse *resp = apdu->u.initResponse;
758
759 int i;
760 static const int masks[] = {
761 Z_Options_search,
762 Z_Options_present,
763 Z_Options_namedResultSets,
764 Z_Options_scan,
765 -1
766 };
767 for (i = 0; masks[i] != -1; i++)
768 if (ODR_MASK_GET(req->options, masks[i]))
769 ODR_MASK_SET(resp->options, masks[i]);
770
771 static const int versions[] = {
772 Z_ProtocolVersion_1,
773 Z_ProtocolVersion_2,
774 Z_ProtocolVersion_3,
775 -1
776 };
777 for (i = 0; versions[i] != -1; i++)
778 if (ODR_MASK_GET(req->protocolVersion, versions[i]))
779 ODR_MASK_SET(resp->protocolVersion, versions[i]);
780 else
781 break;
782
783 *resp->preferredMessageSize = *req->preferredMessageSize;
784 *resp->maximumRecordSize = *req->maximumRecordSize;
785
786 package.response() = apdu;
787 f->m_is_virtual = true;
788 }
789 }
790 else if (!f->m_is_virtual)
791 package.move();
792 else if (gdu && gdu->which == Z_GDU_Z3950)
793 {
794 Z_APDU *apdu = gdu->u.z3950;
795 if (apdu->which == Z_APDU_initRequest)
796 {
797 mp::odr odr;
798
799 package.response() = odr.create_close(
800 apdu,
801 Z_Close_protocolError,
802 "double init");
803
804 package.session().close();
805 }
806 else if (apdu->which == Z_APDU_searchRequest)
807 {
808 f->search(package, apdu);
809 }
810 else if (apdu->which == Z_APDU_presentRequest)
811 {
812 f->present(package, apdu);
813 }
814 else if (apdu->which == Z_APDU_scanRequest)
815 {
816 f->scan(package, apdu);
817 }
818 else if (apdu->which == Z_APDU_close)
819 {
820 if (f->relay_apdu(package, apdu) == 0)
821 {
822 mp::odr odr;
823
824 package.response() = odr.create_close(
825 apdu, Z_Close_finished, "virt_db");
826
827 package.session().close();
828 }
829 }
830 else
831 {
832 mp::odr odr;
833
834 package.response() = odr.create_close(
835 apdu, Z_Close_protocolError,
836 "unsupported APDU in filter_virt_db");
837
838 package.session().close();
839 }
840 }
841 m_p->release_frontend(package);
842}
843
844void mp::filter::VirtualDB::configure(const xmlNode * ptr, bool test_only,
845 const char *path)
846{
847 for (ptr = ptr->children; ptr; ptr = ptr->next)
848 {
849 if (ptr->type != XML_ELEMENT_NODE)
850 continue;
851 if (!strcmp((const char *) ptr->name, "pass-vhosts"))
852 {
853 m_p->pass_vhosts = mp::xml::get_bool(ptr, false);
854 }
855 else if (!strcmp((const char *) ptr->name, "virtual"))
856 {
857 std::string database;
858 std::list<std::string> targets;
859 xmlNode *v_node = ptr->children;
860 for (; v_node; v_node = v_node->next)
861 {
862 if (v_node->type != XML_ELEMENT_NODE)
863 continue;
864
865 if (mp::xml::is_element_mp(v_node, "database"))
866 database = mp::xml::get_text(v_node);
867 else if (mp::xml::is_element_mp(v_node, "target"))
868 targets.push_back(mp::xml::get_text(v_node));
869 else
870 throw mp::filter::FilterException
871 ("Bad element "
872 + std::string((const char *) v_node->name)
873 + " in virtual section"
874 );
875 }
876 std::string route = mp::xml::get_route(ptr);
877
878 VirtualDB::Map vmap(mp::util::database_name_normalize(database),
879 targets, route);
880 m_p->m_maps.push_back(vmap);
881 }
882 else
883 {
884 throw mp::filter::FilterException
885 ("Bad element "
886 + std::string((const char *) ptr->name)
887 + " in virt_db filter");
888 }
889 }
890}
891
892static mp::filter::Base* filter_creator()
893{
894 return new mp::filter::VirtualDB;
895}
896
897extern "C" {
898 struct metaproxy_1_filter_struct metaproxy_1_filter_virt_db = {
899 0,
900 "virt_db",
902 };
903}
904
905
906/*
907 * Local variables:
908 * c-basic-offset: 4
909 * c-file-style: "Stroustrup"
910 * indent-tabs-mode: nil
911 * End:
912 * vim: shiftwidth=4 tabstop=8 expandtab
913 */
914
std::map< mp::Session, FrontendPtr > m_clients
void release_frontend(Package &package)
std::list< VirtualDB::Map > m_maps
FrontendPtr get_frontend(Package &package)
std::map< std::string, VirtualDB::Set >::iterator Sets_it
boost::shared_ptr< Frontend > FrontendPtr
boost::scoped_ptr< Rep > m_p
boost::shared_ptr< Backend > BackendPtr
static mp::filter::Base * filter_creator()
struct metaproxy_1_filter_struct metaproxy_1_filter_virt_db
std::list< std::string > m_frontend_databases
std::map< std::string, VirtualDB::Set >::iterator Sets_it
void fixup_npr_records(ODR odr, Z_Records *records, BackendPtr b)
int relay_apdu(Package &package, Z_APDU *apdu)
void fixup_package(Package &p, BackendPtr b)
void fixup_npr_record(ODR odr, Z_NamePlusRecord *npr, BackendPtr b)
void search(Package &package, Z_APDU *apdu)
std::map< std::string, VirtualDB::Set > m_sets
void scan(Package &package, Z_APDU *apdu)
void present(Package &package, Z_APDU *apdu)
BackendPtr init_backend(std::list< std::string > database, Package &package, int &error_code, std::string &addinfo)
BackendPtr create_backend_from_databases(std::list< std::string > databases, int &error_code, std::string &failing_database)
bool match(const std::string db) const
std::list< std::string > m_targets