Added support for extended handlers in backend server interface.
[yaz-moved-to-github.git] / server / seshigh.c
index 94c4d45..987f84c 100644 (file)
@@ -1,10 +1,30 @@
 /*
- * Copyright (c) 1995, Index Data
+ * Copyright (c) 1995-1998, Index Data
  * See the file LICENSE for details.
  * Sebastian Hammer, Adam Dickmeiss
  *
  * $Log: seshigh.c,v $
- * Revision 1.65  1997-09-01 08:53:01  adam
+ * Revision 1.71  1998-02-10 11:03:57  adam
+ * Added support for extended handlers in backend server interface.
+ *
+ * Revision 1.70  1998/01/29 13:15:35  adam
+ * Implemented sort for the backend interface.
+ *
+ * Revision 1.69  1997/09/30 11:48:12  adam
+ * Fixed bug introduced by previous commit.
+ *
+ * Revision 1.68  1997/09/29 13:18:59  adam
+ * Added function, oid_ent_to_oid, to replace the function
+ * oid_getoidbyent, which is not thread safe.
+ *
+ * Revision 1.67  1997/09/17 12:10:40  adam
+ * YAZ version 1.4.
+ *
+ * Revision 1.66  1997/09/05 15:26:44  adam
+ * Added ODR encode in search and scen bend request structures.
+ * Fixed a few enums that caused trouble with C++.
+ *
+ * Revision 1.65  1997/09/01 08:53:01  adam
  * New windows NT/95 port using MSV5.0. The test server 'ztest' was
  * moved a separate directory. MSV5.0 project server.dsp created.
  * As an option, the server can now operate as an NT service.
 
 #include <backend.h>
 
-static int process_request(association *assoc);
+static int process_request(association *assoc, request *req);
 void backend_response(IOCHAN i, int event);
 static int process_response(association *assoc, request *req, Z_APDU *res);
 static Z_APDU *process_initRequest(association *assoc, request *reqb);
 static Z_APDU *process_searchRequest(association *assoc, request *reqb,
     int *fd);
 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
-    bend_searchresult *bsrt, int *fd);
+    bend_search_rr *bsrr, int *fd);
 static Z_APDU *process_presentRequest(association *assoc, request *reqb,
     int *fd);
 static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd);
+static Z_APDU *process_sortRequest(association *assoc, request *reqb, int *fd);
 static void process_close(association *assoc, request *reqb);
+void save_referenceId (request *reqb, Z_ReferenceId *refid);
 
 static FILE *apduf = 0; /* for use in static mode */
 static statserv_options_block *control_block = 0;
@@ -276,16 +298,16 @@ static statserv_options_block *control_block = 0;
  */
 association *create_association(IOCHAN channel, COMSTACK link)
 {
-    association *new;
+    association *anew;
 
     if (!control_block)
        control_block = statserv_getcontrol();
-    if (!(new = xmalloc(sizeof(*new))))
+    if (!(anew = xmalloc(sizeof(*anew))))
        return 0;
-    new->client_chan = channel;
-    new->client_link = link;
-    if (!(new->decode = odr_createmem(ODR_DECODE)) ||
-       !(new->encode = odr_createmem(ODR_ENCODE)))
+    anew->client_chan = channel;
+    anew->client_link = link;
+    if (!(anew->decode = odr_createmem(ODR_DECODE)) ||
+       !(anew->encode = odr_createmem(ODR_ENCODE)))
        return 0;
     if (*control_block->apdufile)
     {
@@ -293,7 +315,7 @@ association *create_association(IOCHAN channel, COMSTACK link)
        FILE *f;
 
        strcpy(filename, control_block->apdufile);
-       if (!(new->print = odr_createmem(ODR_PRINT)))
+       if (!(anew->print = odr_createmem(ODR_PRINT)))
            return 0;
        if (*control_block->apdufile != '-')
        {
@@ -321,19 +343,19 @@ association *create_association(IOCHAN channel, COMSTACK link)
                }
                setvbuf(f, 0, _IONBF, 0);
            }
-           odr_setprint(new->print, f);
+           odr_setprint(anew->print, f);
        }
     }
     else
-       new->print = 0;
-    new->input_buffer = 0;
-    new->input_buffer_len = 0;
-    new->backend = 0;
-    new->state = ASSOC_NEW;
-    request_initq(&new->incoming);
-    request_initq(&new->outgoing);
-    new->proto = cs_getproto(link);
-    return new;
+       anew->print = 0;
+    anew->input_buffer = 0;
+    anew->input_buffer_len = 0;
+    anew->backend = 0;
+    anew->state = ASSOC_NEW;
+    request_initq(&anew->incoming);
+    request_initq(&anew->outgoing);
+    anew->proto = cs_getproto(link);
+    return anew;
 }
 
 /*
@@ -474,8 +496,11 @@ void ir_session(IOCHAN h, int event)
        /* can we do something yet? */
        req = request_head(&assoc->incoming);
        if (req->state == REQUEST_IDLE)
-           if (process_request(assoc) < 0)
+       {
+           request_deq(&assoc->incoming);
+           if (process_request(assoc, req) < 0)
                do_close(assoc, Z_Close_systemProblem, "Unknown error");
+       }
     }
     if (event & EVENT_OUTPUT)
     {
@@ -514,13 +539,12 @@ void ir_session(IOCHAN h, int event)
 /*
  * Initiate request processing.
  */
-static int process_request(association *assoc)
+static int process_request(association *assoc, request *req)
 {
-    request *req = request_head(&assoc->incoming);
     int fd = -1;
     Z_APDU *res;
+    int retval;
 
-    logf(LOG_DEBUG, "process_request");
     assert(req && req->state == REQUEST_IDLE);
     switch (req->request->which)
     {
@@ -532,6 +556,15 @@ static int process_request(association *assoc)
            res = process_presentRequest(assoc, req, &fd); break;
        case Z_APDU_scanRequest:
            res = process_scanRequest(assoc, req, &fd); break;
+       case Z_APDU_sortRequest:
+           if (assoc->bend_sort)
+               res = process_sortRequest(assoc, req, &fd);
+           else
+           {
+               logf(LOG_WARN, "Cannot handle SORT APDU");
+               return -1;
+           }
+           break;
        case Z_APDU_close:
            process_close(assoc, req); return 0;
        default:
@@ -541,12 +574,12 @@ static int process_request(association *assoc)
     if (res)
     {
        logf(LOG_DEBUG, "  result immediately available");
-       return process_response(assoc, req, res);
+       retval = process_response(assoc, req, res);
     }
     else if (fd < 0)
     {
-       logf(LOG_WARN, "   bad result");
-       return -1;
+       logf(LOG_DEBUG, "  result unavailble");
+       retval = 0;
     }
     else /* no result yet - one will be provided later */
     {
@@ -559,8 +592,9 @@ static int process_request(association *assoc)
        if (!(chan = iochan_create(fd, backend_response, EVENT_INPUT)))
            abort();
        iochan_setdata(chan, assoc);
-       return 0;
+       retval = 0;
     }
+    return retval;
 }
 
 /*
@@ -627,18 +661,18 @@ static int process_response(association *assoc, request *req, Z_APDU *res)
            odr_errmsg(odr_geterror(assoc->print)));
        odr_reset(assoc->print);
     }
-    /* change this when we make the backend reentrant */
-    if (req == request_head(&assoc->incoming))
-    {
-       req->state = REQUEST_IDLE;
-       request_deq(&assoc->incoming);
-    }
+    req->state = REQUEST_IDLE;
     request_enq(&assoc->outgoing, req);
     /* turn the work over to the ir_session handler */
     iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
     /* Is there more work to be done? give that to the input handler too */
+#if 1
     if (request_head(&assoc->incoming))
+    {
+       logf (LOG_DEBUG, "more work to be done");
        iochan_setevent(assoc->client_chan, EVENT_WORK);
+    }
+#endif
     return 0;
 }
 
@@ -666,8 +700,12 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     if (req->implementationVersion)
        logf(LOG_LOG, "Version:   %s", req->implementationVersion);
 
+    binitreq.stream = assoc->encode;
     binitreq.configname = "default-config";
     binitreq.auth = req->idAuthentication;
+    binitreq.bend_sort = NULL;
+    binitreq.bend_search = NULL;
+    binitreq.bend_present = NULL;
     if (!(binitres = bend_init(&binitreq)))
     {
        logf(LOG_WARN, "Bad response from backend.");
@@ -675,6 +713,12 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
     }
 
     assoc->backend = binitres->handle;
+    if ((assoc->bend_sort = binitreq.bend_sort))
+       logf (LOG_DEBUG, "Sort handler installed");
+    if ((assoc->bend_search = binitreq.bend_search))
+       logf (LOG_DEBUG, "Search handler installed");
+    if ((assoc->bend_present = binitreq.bend_present))
+       logf (LOG_DEBUG, "Present handler installed");
     resp->referenceId = req->referenceId;
     *options = '\0';
     /* let's tell the client what we can do */
@@ -710,7 +754,11 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
        ODR_MASK_SET(resp->options, Z_Options_concurrentOperations);
        strcat(options, " concurop");
     }
-
+    if (ODR_MASK_GET(req->options, Z_Options_sort && binitreq.bend_sort))
+    {
+       ODR_MASK_SET(resp->options, Z_Options_sort);
+       strcat(options, " sort");
+    }
     if (ODR_MASK_GET(req->protocolVersion, Z_ProtocolVersion_1))
     {
        ODR_MASK_SET(resp->protocolVersion, Z_ProtocolVersion_1);
@@ -756,6 +804,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
  */
 static Z_Records *diagrec(association *assoc, int error, char *addinfo)
 {
+    int oid[OID_SIZE];
     Z_Records *rec = odr_malloc (assoc->encode, sizeof(*rec));
     oident bib1;
     int *err = odr_malloc (assoc->encode, sizeof(*err));
@@ -777,7 +826,8 @@ static Z_Records *diagrec(association *assoc, int error, char *addinfo)
 #else
     rec->u.nonSurrogateDiagnostic = dr;
 #endif
-    dr->diagnosticSetId = oid_getoidbyent(&bib1);
+    dr->diagnosticSetId = odr_oiddup (assoc->encode,
+                                      oid_ent_to_oid(&bib1, oid));
     dr->condition = err;
     dr->which = Z_DiagForm_v2AddInfo;
     dr->addinfo = addinfo ? addinfo : "";
@@ -790,6 +840,7 @@ static Z_Records *diagrec(association *assoc, int error, char *addinfo)
 static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
                                            int error, char *addinfo)
 {
+    int oid[OID_SIZE];
     Z_NamePlusRecord *rec = odr_malloc (assoc->encode, sizeof(*rec));
     int *err = odr_malloc (assoc->encode, sizeof(*err));
     oident bib1;
@@ -807,7 +858,8 @@ static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
     rec->u.surrogateDiagnostic = drec;
     drec->which = Z_DiagRec_defaultFormat;
     drec->u.defaultFormat = dr;
-    dr->diagnosticSetId = oid_getoidbyent(&bib1);
+    dr->diagnosticSetId = odr_oiddup (assoc->encode,
+                                      oid_ent_to_oid(&bib1, oid));
     dr->condition = err;
     dr->which = Z_DiagForm_v2AddInfo;
     dr->addinfo = addinfo ? addinfo : "";
@@ -819,6 +871,7 @@ static Z_NamePlusRecord *surrogatediagrec(association *assoc, char *dbname,
  */
 static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
 {
+    int oid[OID_SIZE];
     Z_DiagRecs *recs = odr_malloc (assoc->encode, sizeof(*recs));
     int *err = odr_malloc (assoc->encode, sizeof(*err));
     oident bib1;
@@ -838,7 +891,8 @@ static Z_DiagRecs *diagrecs(association *assoc, int error, char *addinfo)
     drec->which = Z_DiagRec_defaultFormat;
     drec->u.defaultFormat = rec;
 
-    rec->diagnosticSetId = oid_getoidbyent(&bib1);
+    rec->diagnosticSetId = odr_oiddup (assoc->encode,
+                                      oid_ent_to_oid(&bib1, oid));
     rec->condition = err;
     rec->which = Z_DiagForm_v2AddInfo;
     rec->addinfo = addinfo ? addinfo : "";
@@ -849,6 +903,7 @@ static Z_Records *pack_records(association *a, char *setname, int start,
                                int *num, Z_RecordComposition *comp,
                                int *next, int *pres, oid_value format)
 {
+    int oid[OID_SIZE];
     int recno, total_length = 0, toget = *num, dumped_records = 0;
     Z_Records *records = odr_malloc (a->encode, sizeof(*records));
     Z_NamePlusRecordList *reclist = odr_malloc (a->encode, sizeof(*reclist));
@@ -952,7 +1007,7 @@ static Z_Records *pack_records(association *a, char *setname, int start,
        recform.oclass = CLASS_RECSYN;
        recform.value = fres->format;
        thisext->direct_reference = odr_oiddup(a->encode,
-           oid_getoidbyent(&recform));
+                                              oid_ent_to_oid(&recform, oid));
        thisext->indirect_reference = 0;
        thisext->descriptor = 0;
        if (fres->len < 0) /* Structured data */
@@ -1014,23 +1069,51 @@ static Z_APDU *process_searchRequest(association *assoc, request *reqb,
     int *fd)
 {
     Z_SearchRequest *req = reqb->request->u.searchRequest;
-    bend_searchrequest bsrq;
-    bend_searchresult *bsrt;
+    bend_search_rr *bsrr = nmem_malloc (reqb->request_mem, sizeof(*bsrr));
 
     logf(LOG_LOG, "Got SearchRequest.");
 
-    bsrq.setname = req->resultSetName;
-    bsrq.replace_set = *req->replaceIndicator;
-    bsrq.num_bases = req->num_databaseNames;
-    bsrq.basenames = req->databaseNames;
-    bsrq.query = req->query;
-
-    if (!(bsrt = bend_search(assoc->backend, &bsrq, fd)))
-       return 0;
-    return response_searchRequest(assoc, reqb, bsrt, fd);
+    save_referenceId (reqb, req->referenceId);
+    /* store ref id in request */
+    bsrr->fd = fd;
+    bsrr->request = reqb;
+    bsrr->association = assoc;
+    if (assoc->bend_search)
+    {
+       bsrr->setname = req->resultSetName;
+       bsrr->replace_set = *req->replaceIndicator;
+       bsrr->num_bases = req->num_databaseNames;
+       bsrr->basenames = req->databaseNames;
+       bsrr->query = req->query;
+       bsrr->stream = assoc->encode;
+       bsrr->errcode = 0;
+       bsrr->hits = 0;
+       bsrr->errstring = NULL;
+       (*assoc->bend_search)(assoc->backend, bsrr);
+       if (!bsrr->request)
+           return 0;
+    }
+    else
+    {
+       bend_searchrequest bsrq;
+       bend_searchresult *bsrt;
+
+       bsrq.setname = req->resultSetName;
+       bsrq.replace_set = *req->replaceIndicator;
+       bsrq.num_bases = req->num_databaseNames;
+       bsrq.basenames = req->databaseNames;
+       bsrq.query = req->query;
+       bsrq.stream = assoc->encode;
+       if (!(bsrt = bend_search(assoc->backend, &bsrq, fd)))
+           return 0;
+       bsrr->hits = bsrt->hits;
+       bsrr->errcode = bsrt->errcode;
+       bsrr->errstring = bsrt->errstring;
+    }
+    return response_searchRequest(assoc, reqb, bsrr, fd);
 }
 
-bend_searchresult *bend_searchresponse(void *handle) {return 0;}
+int bend_searchresponse(void *handle, bend_search_rr *bsrr) {return 0;}
 
 /*
  * Prepare a searchresponse based on the backend results. We probably want
@@ -1040,7 +1123,7 @@ bend_searchresult *bend_searchresponse(void *handle) {return 0;}
  * event, and we'll have to get the response for ourselves.
  */
 static Z_APDU *response_searchRequest(association *assoc, request *reqb,
-    bend_searchresult *bsrt, int *fd)
+    bend_search_rr *bsrt, int *fd)
 {
     Z_SearchRequest *req = reqb->request->u.searchRequest;
     Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
@@ -1061,7 +1144,7 @@ static Z_APDU *response_searchRequest(association *assoc, request *reqb,
     resp->additionalSearchInfo = 0;
     resp->otherInfo = 0;
     *fd = -1;
-    if (!bsrt && !(bsrt = bend_searchresponse(assoc->backend)))
+    if (!bsrt && !bend_searchresponse(assoc->backend, bsrt))
     {
        logf(LOG_FATAL, "Bad result from backend");
        return 0;
@@ -1159,39 +1242,62 @@ static Z_APDU *process_presentRequest(association *assoc, request *reqb,
     int *fd)
 {
     Z_PresentRequest *req = reqb->request->u.presentRequest;
-    Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
-    Z_PresentResponse *resp = odr_malloc (assoc->encode, sizeof(*resp));
-    int *presst = odr_malloc (assoc->encode, sizeof(*presst));
-    int *next = odr_malloc (assoc->encode, sizeof(*next));
-    int *num = odr_malloc (assoc->encode, sizeof(*num));
     oident *prefformat;
     oid_value form;
+    Z_APDU *apdu;
+    Z_PresentResponse *resp;
+    int *presst;
+    int *next;
+    int *num;
 
     logf(LOG_LOG, "Got PresentRequest.");
-    *presst = 0;
-    *next = 0;
-    *num = 0;
-
-    apdu->which = Z_APDU_presentResponse;
-    apdu->u.presentResponse = resp;
-    resp->referenceId = req->referenceId;
-    resp->otherInfo = 0;
 
     if (!(prefformat = oid_getentbyoid(req->preferredRecordSyntax)) ||
        prefformat->oclass != CLASS_RECSYN)
        form = VAL_NONE;
     else
        form = prefformat->value;
+    if (assoc->bend_present)
+    {
+       bend_present_rr *bprr = nmem_malloc (reqb->request_mem, sizeof(*bprr));
+       bprr->setname = req->resultSetId;
+       bprr->start = *req->resultSetStartPoint;
+       bprr->number = *req->numberOfRecordsRequested;
+       bprr->format = form;
+       bprr->comp = req->recordComposition;
+       bprr->stream = assoc->encode;
+       bprr->request = reqb;
+       bprr->association = assoc;
+       bprr->errcode = 0;
+       bprr->errstring = NULL;
+       (*assoc->bend_present)(assoc->backend, bprr);
+
+       if (!bprr->request)
+           return 0;
+    }
+    apdu = odr_malloc (assoc->encode, sizeof(*apdu));
+    resp = odr_malloc (assoc->encode, sizeof(*resp));
+    presst = odr_malloc (assoc->encode, sizeof(*presst));
+    next = odr_malloc (assoc->encode, sizeof(*next));
+    num = odr_malloc (assoc->encode, sizeof(*num));
+    *presst = 0;
+    *next = 0;
     *num = *req->numberOfRecordsRequested;
-    resp->records = pack_records(assoc, req->resultSetId,
-       *req->resultSetStartPoint, num, req->recordComposition, next,
-       presst, form);
+    
+    apdu->which = Z_APDU_presentResponse;
+    apdu->u.presentResponse = resp;
+    resp->referenceId = req->referenceId;
+    resp->otherInfo = 0;
+    
+    resp->records =
+       pack_records(assoc, req->resultSetId, *req->resultSetStartPoint,
+                    num, req->recordComposition, next, presst, form);
     if (!resp->records)
-       return 0;
+       return 0;
     resp->numberOfRecordsReturned = num;
     resp->presentStatus = presst;
     resp->nextResultSetPosition = next;
-
+    
     return apdu;
 }
 
@@ -1213,7 +1319,7 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
     bend_scanresult *srs;
     oident *attset;
 
-    logf(LOG_LOG, "Got scanrequest");
+    logf(LOG_LOG, "Got ScanRequest");
     *scanStatus = Z_Scan_failure;
     *numberOfEntriesReturned = 0;
 
@@ -1244,6 +1350,7 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
        srq.basenames = req->databaseNames;
        srq.num_entries = *req->numberOfTermsRequested;
        srq.term = req->termListAndStartPoint;
+       srq.stream = assoc->encode;
        if (!(attset = oid_getentbyoid(req->attributeSet)) ||
            attset->oclass != CLASS_RECSYN)
            srq.attributeset = VAL_NONE;
@@ -1304,6 +1411,44 @@ static Z_APDU *process_scanRequest(association *assoc, request *reqb, int *fd)
     return apdu;
 }
 
+static Z_APDU *process_sortRequest(association *assoc, request *reqb,
+    int *fd)
+{
+    Z_SortRequest *req = reqb->request->u.sortRequest;
+    Z_SortResponse *res = odr_malloc (assoc->encode, sizeof(*res));
+    bend_sort_rr *bsrr = odr_malloc (assoc->encode, sizeof(*bsrr));
+
+    Z_APDU *apdu = odr_malloc (assoc->encode, sizeof(*apdu));
+
+    logf(LOG_LOG, "Got SortRequest.");
+
+    bsrr->num_input_setnames = req->inputResultSetNames->num_strings;
+    bsrr->input_setnames = req->inputResultSetNames->strings;
+    bsrr->output_setname = req->sortedResultSetName;
+    bsrr->sort_sequence = req->sortSequence;
+    bsrr->stream = assoc->encode;
+
+    bsrr->sort_status = Z_SortStatus_failure;
+    bsrr->errcode = 0;
+    bsrr->errstring = 0;
+
+    (*assoc->bend_sort)(assoc->backend, bsrr);
+
+    res->referenceId = req->referenceId;
+    res->sortStatus = odr_malloc (assoc->encode, sizeof(*res->sortStatus));
+    *res->sortStatus = bsrr->sort_status;
+    res->resultSetStatus = 0;
+    if (bsrr->errcode)
+       res->diagnostics = diagrecs(assoc, bsrr->errcode, bsrr->errstring);
+    else
+       res->diagnostics = 0;
+    res->otherInfo = 0;
+
+    apdu->which = Z_APDU_sortResponse;
+    apdu->u.sortResponse = res;
+    return apdu;
+}
+
 static void process_close(association *assoc, request *reqb)
 {
     Z_Close *req = reqb->request->u.close;
@@ -1321,10 +1466,71 @@ static void process_close(association *assoc, request *reqb)
        "unspecified"
     };
 
-    logf(LOG_LOG, "Got close, reason %s, message %s",
+    logf(LOG_LOG, "Got Close, reason %s, message %s",
        reasons[*req->closeReason], req->diagnosticInformation ?
        req->diagnosticInformation : "NULL");
     if (assoc->version < 3) /* to make do_force respond with close */
        assoc->version = 3;
     do_close(assoc, Z_Close_finished, "Association terminated by client");
 }
+
+void save_referenceId (request *reqb, Z_ReferenceId *refid)
+{
+    if (refid)
+    {
+       reqb->len_refid = refid->len;
+       reqb->refid = nmem_malloc (reqb->request_mem, refid->len);
+       memcpy (reqb->refid, refid->buf, refid->len);
+    }
+    else
+    {
+       reqb->len_refid = 0;
+       reqb->refid = NULL;
+    }
+}
+
+void bend_request_send (bend_association a, bend_request req, Z_APDU *res)
+{
+    process_response (a, req, res);
+}
+
+bend_request bend_request_mk (bend_association a)
+{
+    request *nreq = request_get (&a->outgoing);
+    nreq->request_mem = nmem_create ();
+    return nreq;
+}
+
+Z_ReferenceId *bend_request_getid (ODR odr, bend_request req)
+{
+    Z_ReferenceId *id;
+    if (!req->refid)
+       return 0;
+    id = odr_malloc (odr, sizeof(*odr));
+    id->buf = odr_malloc (odr, req->len_refid);
+    id->len = id->size = req->len_refid;
+    memcpy (id->buf, req->refid, req->len_refid);
+    return id;
+}
+
+void bend_request_destroy (bend_request *req)
+{
+    nmem_destroy((*req)->request_mem);
+    request_release(*req);
+    *req = NULL;
+}
+
+int bend_backend_respond (bend_association a, bend_request req)
+{
+    return process_request (a, req);
+}
+
+void bend_request_setdata(bend_request r, void *p)
+{
+    r->clientData = p;
+}
+
+void *bend_request_getdata(bend_request r)
+{
+    return r->clientData;
+}