* Sebastian Hammer, Adam Dickmeiss
*
* $Log: client.c,v $
- * Revision 1.18 1995-08-28 12:21:27 quinn
+ * Revision 1.19 1995-08-29 11:17:28 quinn
+ * Added code to receive close
+ *
+ * Revision 1.18 1995/08/28 12:21:27 quinn
* Client can now ask for simple element set names.
*
* Revision 1.17 1995/08/17 12:45:02 quinn
ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_1);
ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_2);
+ ODR_MASK_SET(req->protocolVersion, Z_ProtocolVersion_3);
req->idAuthentication = auth;
odr_perror(print, "Printing userinfo\n");
odr_reset(print);
}
- if (res->userInformationField->which == ODR_EXTERNAL_octet)
+ if (res->userInformationField->which == Z_External_octet)
{
printf("Guessing visiblestring:\n");
printf("'%s'\n", res->userInformationField->u. octet_aligned->buf);
odr_reset(print);
}
}
- if (r->which == ODR_EXTERNAL_octet && p->u.octet_aligned->len)
+ if (r->which == Z_External_octet && p->u.octet_aligned->len)
marc_display ((char*)p->u.octet_aligned->buf, stdout);
else if (ent->value == VAL_SUTRS)
{
return 2;
}
+void process_close(Z_Close *req)
+{
+ static char *reasons[] =
+ {
+ "finished",
+ "shutdown",
+ "systemProblem",
+ "costLimit",
+ "resources",
+ "securityViolation",
+ "protocolError",
+ "lackOfActivity",
+ "peerAbort",
+ "unspecified"
+ };
+
+ printf("Reason: %s, message: %s\n", reasons[*req->closeReason],
+ req->diagnosticInformation ? req->diagnosticInformation : "NULL");
+}
+
static int cmd_show(char *arg)
{
if (!send_presentRequest(arg))
else
printf("No records.\n");
break;
+ case Z_APDU_close:
+ printf("Target has closed the association.\n");
+ process_close(apdu->u.close);
+ break;
default:
printf("Received unknown APDU type (%d).\n",
apdu->which);
* Sebastian Hammer, Adam Dickmeiss
*
* $Log: seshigh.c,v $
- * Revision 1.45 1995-08-21 09:11:00 quinn
+ * Revision 1.46 1995-08-29 11:17:58 quinn
+ * Added code to receive close
+ *
+ * Revision 1.45 1995/08/21 09:11:00 quinn
* Smallish fixes to suppport new formats.
*
* Revision 1.44 1995/08/17 12:45:25 quinn
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
+#include <sys/time.h>
#include <dmalloc.h>
#include <comstack.h>
new->input_buffer = 0;
new->input_buffer_len = 0;
new->backend = 0;
- new->rejected = 0;
+ new->state = ASSOC_NEW;
request_initq(&new->incoming);
request_initq(&new->outgoing);
new->proto = cs_getproto(link);
free(h);
}
+static void do_close(association *a, int reason, char *message)
+{
+ Z_APDU apdu;
+ Z_Close *cls = zget_Close(a->encode);
+ request *req = request_get();
+
+ /* Purge request queue */
+ while (request_deq(&a->incoming));
+ while (request_deq(&a->outgoing));
+ if (a->version >= 3)
+ {
+ logf(LOG_DEBUG, "Generating Close PDU");
+ apdu.which = Z_APDU_close;
+ apdu.u.close = cls;
+ *cls->closeReason = reason;
+ cls->diagnosticInformation = message;
+ process_response(a, req, &apdu);
+ iochan_settimeout(a->client_chan, 60);
+ }
+ else
+ {
+ logf(LOG_DEBUG, "v2 client. No Close PDU");
+ iochan_setevent(a->client_chan, EVENT_TIMEOUT); /* force imm close */
+ }
+ a->state = ASSOC_DEAD;
+}
+
/*
* This is where PDUs from the client are read and the further
* processing is initiated. Flow of control moves down through the
assert(h && conn && assoc);
if (event == EVENT_TIMEOUT)
{
- logf(LOG_LOG, "Timeout - closing connection.");
- cs_close(conn);
- destroy_association(assoc);
- iochan_destroy(h);
+ if (assoc->state != ASSOC_UP)
+ {
+ logf(LOG_LOG, "Final timeout - closing connection.");
+ cs_close(conn);
+ destroy_association(assoc);
+ iochan_destroy(h);
+ }
+ else
+ {
+ logf(LOG_LOG, "Session idle too long. Sending close.");
+ do_close(assoc, Z_Close_lackOfActivity, 0);
+ }
return;
}
if (event & EVENT_INPUT || event & EVENT_WORK) /* input */
logf(LOG_DEBUG, "ir_session (input)");
assert(assoc && conn);
/* We aren't speaking to this fellow */
- if (assoc->rejected)
+ if (assoc->state == ASSOC_DEAD)
{
logf(LOG_LOG, "Closed connection after reject");
cs_close(conn);
odr_errlist[odr_geterror(assoc->decode)]);
logf(LOG_LOG, "PDU dump:");
odr_dumpBER(log_file(), assoc->input_buffer, res);
- cs_close(conn);
- destroy_association(assoc);
- iochan_destroy(h);
+ do_close(assoc, Z_Close_protocolError, "Malformed package");
return;
}
req->request_mem = odr_extract_mem(assoc->decode);
req = request_head(&assoc->incoming);
if (req->state == REQUEST_IDLE)
if (process_request(assoc) < 0)
- {
- cs_close(conn);
- destroy_association(assoc);
- iochan_destroy(h);
- }
+ do_close(assoc, Z_Close_systemProblem, "Unknown error");
}
if (event & EVENT_OUTPUT)
{
if ((res && process_response(assoc, req, res) < 0) || fd < 0)
{
logf(LOG_LOG, "Fatal error when talking to backend");
- cs_close(assoc->client_link);
- destroy_association(assoc);
- iochan_destroy(assoc->client_chan);
+ do_close(assoc, Z_Close_systemProblem, 0);
iochan_destroy(i);
return;
}
odr_reset(assoc->print);
}
/* change this when we make the backend reentrant */
- assert(req == request_head(&assoc->incoming));
- req->state = REQUEST_IDLE;
- request_deq(&assoc->incoming);
+ if (req == request_head(&assoc->incoming))
+ {
+ req->state = REQUEST_IDLE;
+ request_deq(&assoc->incoming);
+ }
request_enq(&assoc->outgoing, req);
/* turn the work over to the ir_session handler */
iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
Z_InitResponse *resp = apdu->u.initResponse;
bend_initrequest binitreq;
bend_initresult *binitres;
+ char options[100];
logf(LOG_LOG, "Got initRequest");
if (req->implementationId)
assoc->backend = binitres->handle;
resp->referenceId = req->referenceId;
+ *options = '\0';
/* let's tell the client what we can do */
if (ODR_MASK_GET(req->options, Z_Options_search))
+ {
ODR_MASK_SET(resp->options, Z_Options_search);
+ strcat(options, "srch");
+ }
if (ODR_MASK_GET(req->options, Z_Options_present))
+ {
ODR_MASK_SET(resp->options, Z_Options_present);
+ strcat(options, " prst");
+ }
#if 0
if (ODR_MASK_GET(req->options, Z_Options_delSet))
+ {
ODR_MASK_SET(&options, Z_Options_delSet);
+ strcat(options, " del");
+ }
#endif
if (ODR_MASK_GET(req->options, Z_Options_namedResultSets))
+ {
ODR_MASK_SET(resp->options, Z_Options_namedResultSets);
+ strcat(options, " namedresults");
+ }
if (ODR_MASK_GET(req->options, Z_Options_scan))
+ {
ODR_MASK_SET(resp->options, Z_Options_scan);
+ strcat(options, " scan");
+ }
if (ODR_MASK_GET(req->options, Z_Options_concurrentOperations))
+ {
ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
+ strcat(options, " concurop");
+ }
if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
+ {
ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
+ assoc->version = 2; /* 1 & 2 are equivalent */
+ }
if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_2))
+ {
ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_2);
+ assoc->version = 2;
+ }
+ if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_3))
+ {
+ ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_3);
+ assoc->version = 3;
+ }
+ logf(LOG_LOG, "Negotiated to v%d: %s", assoc->version, options);
assoc->maximumRecordSize = *req->maximumRecordSize;
if (assoc->maximumRecordSize > control_block->maxrecordsize)
assoc->maximumRecordSize = control_block->maxrecordsize;
{
logf(LOG_LOG, "Connection rejected by backend.");
*resp->result = 0;
- assoc->rejected = 1;
+ assoc->state = ASSOC_DEAD;
}
+ else
+ assoc->state = ASSOC_UP;
return apdu;
}