Filter z3950_client may be configured to always send a close APDU
to backend target when connection/session is closed. This will only
happen if close APDU is not already sent. Enabled by configuration
for z3950_client (force_close).
+Filter z3950_client may be configured to always send a close APDU
+to backend target when connection/session is closed. This will only
+happen if close APDU is not already sent. Enabled by configuration
+for z3950_client (force_close).
+
Filter virt_db and multi relays close APDU.
Filter virt_db and multi: relay init size parameters
Filter virt_db and multi relays close APDU.
Filter virt_db and multi: relay init size parameters
</para>
</listitem>
</varlistentry>
</para>
</listitem>
</varlistentry>
+ <varlistentry><term>force_close</term>
+ <listitem>
+ <para>
+ Is a boolean value (false, true). If true, the Z39.50 client will
+ terminate Z39.50 sessions with a close APDU followed by a socket close.
+ If false (default), the Z39.50 client will be transparent and only
+ send a close if the peer client does it too.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
</refsect1>
</variablelist>
</para>
</refsect1>
</filter>
<filter id="backend" type="z3950_client">
<timeout>30</timeout>
</filter>
<filter id="backend" type="z3950_client">
<timeout>30</timeout>
- <default_target>z3950.indexdata.dk</default_target>
+ <default_target>localhost:9999</default_target>
+ <force_close>true</force_close>
</filter>
</filters>
<routes>
</filter>
</filters>
<routes>
bool m_waiting;
bool m_destroyed;
bool m_connected;
bool m_waiting;
bool m_destroyed;
bool m_connected;
int m_queue_len;
int m_time_elapsed;
int m_time_max;
int m_queue_len;
int m_time_elapsed;
int m_time_max;
// number of seconds to wait before we give up request
int m_timeout_sec;
int m_max_sockets;
// number of seconds to wait before we give up request
int m_timeout_sec;
int m_max_sockets;
std::string m_default_target;
std::string m_force_target;
boost::mutex m_mutex;
std::string m_default_target;
std::string m_force_target;
boost::mutex m_mutex;
: Z_Assoc(PDU_Observable),
m_socket_manager(socket_manager), m_PDU_Observable(PDU_Observable),
m_package(0), m_in_use(true), m_waiting(false),
: Z_Assoc(PDU_Observable),
m_socket_manager(socket_manager), m_PDU_Observable(PDU_Observable),
m_package(0), m_in_use(true), m_waiting(false),
- m_destroyed(false), m_connected(false), m_queue_len(1),
+ m_destroyed(false), m_connected(false), m_has_closed(false),
+ m_queue_len(1),
m_time_elapsed(0), m_time_max(timeout_sec), m_time_connect_max(10),
m_host(host)
{
m_time_elapsed(0), m_time_max(timeout_sec), m_time_connect_max(10),
m_host(host)
{
{
m_p->m_timeout_sec = 30;
m_p->m_max_sockets = 0;
{
m_p->m_timeout_sec = 30;
m_p->m_max_sockets = 0;
+ m_p->m_force_close = false;
}
yf::Z3950Client::~Z3950Client() {
}
yf::Z3950Client::~Z3950Client() {
std::map<mp::Session,yf::Z3950Client::Assoc *>::iterator it;
Z_GDU *gdu = package.request().get();
std::map<mp::Session,yf::Z3950Client::Assoc *>::iterator it;
Z_GDU *gdu = package.request().get();
- // only deal with Z39.50
- if (!gdu || gdu->which != Z_GDU_Z3950)
- {
- package.move();
- return 0;
- }
int max_sockets = package.origin().get_max_sockets();
if (max_sockets == 0)
int max_sockets = package.origin().get_max_sockets();
if (max_sockets == 0)
m_cond_session_ready.wait(lock);
}
}
m_cond_session_ready.wait(lock);
}
}
+ if (!gdu || gdu->which != Z_GDU_Z3950)
+ {
+ package.move();
+ return 0;
+ }
// new Z39.50 session ..
Z_APDU *apdu = gdu->u.z3950;
// check that it is init. If not, close
// new Z39.50 session ..
Z_APDU *apdu = gdu->u.z3950;
// check that it is init. If not, close
void yf::Z3950Client::Rep::send_and_receive(Package &package,
yf::Z3950Client::Assoc *c)
{
void yf::Z3950Client::Rep::send_and_receive(Package &package,
yf::Z3950Client::Assoc *c)
{
- Z_GDU *gdu = package.request().get();
-
if (c->m_destroyed)
return;
if (c->m_destroyed)
return;
+ c->m_package = &package;
+
+ if (package.session().is_closed() && c->m_connected && !c->m_has_closed
+ && m_force_close)
+ {
+ mp::odr odr;
+
+ package.request() = odr.create_close(
+ 0, Z_Close_finished, "z3950_client");
+ c->m_package = 0; // don't inspect response
+ }
+ Z_GDU *gdu = package.request().get();
+
if (!gdu || gdu->which != Z_GDU_Z3950)
return;
if (!gdu || gdu->which != Z_GDU_Z3950)
return;
+ if (gdu->u.z3950->which == Z_APDU_close)
+ c->m_has_closed = true;
+
+ // prepare connect
- c->m_package = &package;
c->m_waiting = true;
if (!c->m_connected)
{
c->m_waiting = true;
if (!c->m_connected)
{
int len;
c->send_GDU(gdu, &len);
int len;
c->send_GDU(gdu, &len);
- switch(gdu->u.z3950->which)
+ switch (gdu->u.z3950->which)
{
case Z_APDU_triggerResourceControlRequest:
// request only..
{
case Z_APDU_triggerResourceControlRequest:
// request only..
it = m_clients.find(package.session());
if (it != m_clients.end())
{
it = m_clients.find(package.session());
if (it != m_clients.end())
{
- Z_GDU *gdu = package.request().get();
- if (gdu && gdu->which == Z_GDU_Z3950)
- { // only Z39.50 packages lock in get_assoc.. release it
- it->second->m_in_use = false;
- it->second->m_queue_len--;
- }
+ it->second->m_in_use = false;
+ it->second->m_queue_len--;
if (package.session().is_closed())
{
if (package.session().is_closed())
{
if (c)
{
m_p->send_and_receive(package, c);
if (c)
{
m_p->send_and_receive(package, c);
+ m_p->release_assoc(package);
- m_p->release_assoc(package);
}
void yf::Z3950Client::configure(const xmlNode *ptr, bool test_only)
}
void yf::Z3950Client::configure(const xmlNode *ptr, bool test_only)
{
m_p->m_max_sockets = mp::xml::get_int(ptr->children, 0);
}
{
m_p->m_max_sockets = mp::xml::get_int(ptr->children, 0);
}
+ else if (!strcmp((const char *) ptr->name, "force_close"))
+ {
+ m_p->m_force_close = mp::xml::get_bool(ptr->children, 0);
+ }
else
{
throw mp::filter::FilterException("Bad element "
else
{
throw mp::filter::FilterException("Bad element "
attribute init-options { xsd:boolean }?,
attribute request-session { xsd:boolean }?,
attribute response-session { xsd:boolean }?,
attribute init-options { xsd:boolean }?,
attribute request-session { xsd:boolean }?,
attribute response-session { xsd:boolean }?,
+ attribute session { xsd:boolean }?,
attribute apdu { xsd:boolean }?,
attribute request-apdu { xsd:boolean }?,
attribute response-apdu { xsd:boolean }?
attribute apdu { xsd:boolean }?,
attribute request-apdu { xsd:boolean }?,
attribute response-apdu { xsd:boolean }?
attribute name { xsd:NCName }?,
element mp:timeout { xsd:integer }?,
element mp:default_target { xsd:string }?,
attribute name { xsd:NCName }?,
element mp:timeout { xsd:integer }?,
element mp:default_target { xsd:string }?,
- element mp:force_target { xsd:string }?
+ element mp:force_target { xsd:string }?,
+ element mp:force_close { xsd:boolean }?
filter_limit =
attribute type { "limit" },
filter_limit =
attribute type { "limit" },
</attribute>
</optional>
<optional>
</attribute>
</optional>
<optional>
+ <attribute name="session">
+ <data type="boolean"/>
+ </attribute>
+ </optional>
+ <optional>
<attribute name="apdu">
<data type="boolean"/>
</attribute>
<attribute name="apdu">
<data type="boolean"/>
</attribute>
<data type="string"/>
</element>
</optional>
<data type="string"/>
</element>
</optional>
+ <optional>
+ <element name="mp:force_close">
+ <data type="boolean"/>
+ </element>
+ </optional>
</define>
<define name="filter_limit">
<attribute name="type">
</define>
<define name="filter_limit">
<attribute name="type">
<xs:attribute name="init-options" type="xs:boolean"/>
<xs:attribute name="request-session" type="xs:boolean"/>
<xs:attribute name="response-session" type="xs:boolean"/>
<xs:attribute name="init-options" type="xs:boolean"/>
<xs:attribute name="request-session" type="xs:boolean"/>
<xs:attribute name="response-session" type="xs:boolean"/>
+ <xs:attribute name="session" type="xs:boolean"/>
<xs:attribute name="apdu" type="xs:boolean"/>
<xs:attribute name="request-apdu" type="xs:boolean"/>
<xs:attribute name="response-apdu" type="xs:boolean"/>
<xs:attribute name="apdu" type="xs:boolean"/>
<xs:attribute name="request-apdu" type="xs:boolean"/>
<xs:attribute name="response-apdu" type="xs:boolean"/>
<xs:element minOccurs="0" ref="mp:timeout"/>
<xs:element minOccurs="0" ref="mp:default_target"/>
<xs:element minOccurs="0" ref="mp:force_target"/>
<xs:element minOccurs="0" ref="mp:timeout"/>
<xs:element minOccurs="0" ref="mp:default_target"/>
<xs:element minOccurs="0" ref="mp:force_target"/>
+ <xs:element minOccurs="0" ref="mp:force_close"/>
</xs:sequence>
</xs:group>
<xs:element name="default_target" type="xs:string"/>
<xs:element name="force_target" type="xs:string"/>
</xs:sequence>
</xs:group>
<xs:element name="default_target" type="xs:string"/>
<xs:element name="force_target" type="xs:string"/>
+ <xs:element name="force_close" type="xs:boolean"/>
<xs:attributeGroup name="filter_z3950_client">
<xs:attribute name="type" use="required">
<xs:simpleType>
<xs:attributeGroup name="filter_z3950_client">
<xs:attribute name="type" use="required">
<xs:simpleType>