/*
openisis - an open implementation of the CDS/ISIS database
Version 0.8.x (patchlevel see file Version)
Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
see README for more information
EOH */
/*
$Id: lstb.c,v 1.41 2003/06/15 15:57:43 mawag Exp $
implementation of client side session and communication functions.
*/
#include <errno.h>
#include <limits.h> /* PATH_MAX */
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "openisis.h"
#include "loi.h"
#include "lcli.h"
#include "ldb.h"
#include "ldsp.h"
#include "lfdt.h"
#include "luti.h"
#ifdef WIN32
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#endif
#define LSTB_STHOSTLEN 32
#define LSTB_MAXDBS 255 /* according to OPENISIS_DBIDMSK */
#define LSTB_MAXSTUBS 255 /* according to OPENISIS_SCIDMSK */
#define LSTB_INCRDB 8
#define LSTB_INCRSTUB 8
/* ************************************************************
* meta
*/
/* stub id 0 has idx -1 */
/* stub id 0x0100 has idx 0 */
#define SC_X2I(s) ( ( (1 + (s)) << 8 ) & OPENISIS_SCIDMSK )
#define SC_I2X(s) ( ( ((s) & OPENISIS_SCIDMSK) >> 8 ) - 1 )
#define DB_X2I(d,s) ( ((s) & OPENISIS_SCIDMSK) | ((d) & OPENISIS_DBIDMSK) )
#define DB_I2X(d) ( (d) & OPENISIS_DBIDMSK )
#define DB_IDX_OK(st,idx) \
(0 <= (idx) && (st)->head.ndbs > (idx) && * (st)->head.dbs[idx]->name)
/* ************************************************************
* client view of db
*/
typedef struct {
Db head;
} CDb;
static void cdbCtor (CDb *that,
const char *name, int dbid, int tms, Fdt *fdt, Rec *cfg
) {
strncpy (that->head.name, name, DBNLEN - 1) [DBNLEN - 1] = 0;
that->head.dbid = dbid;
that->head.tms = tms;
that->head.fdt = fdt;
that->head.cfg = cfg;
}
static void cdbDtor (CDb *that) {
if (that->head.fdt) {
fFree (that->head.fdt);
}
if (that->head.cfg) {
mFree (that->head.cfg);
}
memset (that, 0, sizeof (CDb));
}
/* ************************************************************
* client session
*/
typedef struct OpenIsisStb {
Schema head;
char host[LSTB_STHOSTLEN];
int port;
int srq; /* rqs serial no */
Rec *rqs; /* last request */
Rec *rsp; /* last response */
Db *rdb; /* db of embedded rsp recs */
CDb *dbase; /* db array of non-local schema */
LutiLT hsh;
CliChnl chn;
OpenIsisStbRqsProc *rqsp;
OpenIsisStbDelProc *delp;
void *cld; /* client_data of rqsp */
/*MMM deprecated*/
OpenIsisRspCb *actcb;
void *actcld;
OpenIsisStubCbData cbdta;
} OpenIsisStb;
Stub stub0 = 0;
static Stub RmtStubs = 0;
static int NumStubs = 0;
static LutiLT StubLT = 0;
#define STBSIZE (sizeof(Stb))
static int stbLocalRqs (Stub that, Rec *rqs);
static int stbSyncRqs (Stub that, Rec *rqs);
static void stbClear (Stub that) {
memset (that, 0, STBSIZE);
that->chn.sd = -1;
}
static int stbCtor (Stub that,
const char *name, int scid, Rec *cfg,
OpenIsisStbRqsProc *rqsp, OpenIsisStbDelProc *delp, void *cld,
OpenIsisStubCbData *cbd
) {
strncpy (that->head.name, name, SCNLEN - 1) [SCNLEN - 1] = 0;
that->head.scid = scid;
if (scid) {
if (! rString (cfg, OPENISIS_SC_HOST, 0, that->host, LSTB_STHOSTLEN)) {
return 0;
}
that->port = rInt (cfg, OPENISIS_SC_PORT, 0, 0);
if (0 >= that->port) {
return 0;
}
if (rqsp) {
that->rqsp = rqsp;
}
else {
that->rqsp = &stbSyncRqs;
}
}
else {
that->rqsp = &stbLocalRqs;
}
that->head.cfg =
rSet (cfg, RCHG | RDIS, OPENISIS_SC_NAME, that->head.name, 0);
that->delp = delp;
that->cld = cld;
that->hsh = luti_ltnew ();
if (cbd) {
memcpy (&that->cbdta, cbd, sizeof (OpenIsisStubCbData));
}
luti_ltadd (StubLT, that->head.name, scid);
return !0;
}
/* return idx or -err */
static int cdbNewIdx (Stub that) {
int ndb = that->head.ndbs;
int rt, j;
for (j = 0; ndb > j; ++j) {
if (! * that->dbase[j].head.name) {
return j;
}
}
rt = luti_ptrincr (&that->dbase, &ndb,
LSTB_INCRDB, sizeof (CDb), LSTB_MAXDBS);
if (0 > rt) {
return sMsg (ERR_NOMEM, "%s: cdbNewIdx: out of memory",
that->head.name);
}
rt = luti_ptrincr (&that->head.dbs, &that->head.ndbs,
LSTB_INCRDB, sizeof (CDb*), LSTB_MAXDBS);
if (0 > rt) {
return sMsg (ERR_NOMEM, "%s: cdbNewIdx: out of memory",
that->head.name);
}
for (j = that->head.ndbs; 0 <= --j; ) {
that->head.dbs[j] = (Db*) (that->dbase + j);
}
return rt;
}
/* return bool newly allocated or -err */
static int cdbNewIdx0 (Stub that, int dbid) {
int rt;
if (dbid < that->head.ndbs) {
if (that->head.dbs[dbid]) {
return 0;
}
return 1;
}
rt = luti_ptrincr (&that->head.dbs, &that->head.ndbs,
1 + dbid - that->head.ndbs, sizeof (CDb*), -1);
if (0 > rt) {
return sMsg (ERR_NOMEM, "%s: cdbNewIdx0(%d): out of memory",
that->head.name, dbid);
}
return 1;
}
static int stbNewIdx () {
int j;
for (j = 0; NumStubs > j; ++j) {
if (! * RmtStubs[j].head.name) {
return j;
}
}
j = luti_ptrincr (&RmtStubs, &NumStubs,
LSTB_INCRSTUB, STBSIZE, LSTB_MAXSTUBS);
/* stbClear (RmtStubs + j) done in nOpen */
return j;
}
static Stub stbById (int sid) {
int idx;
if (0 > sid || ! stub0) {
return 0;
}
if (0 == sid) {
return stub0;
}
idx = SC_I2X (sid);
if (0 > idx) {
log_msg (LOG_ERROR, "stbById: illegal id %x", sid);
return 0;
}
if (NumStubs <= idx) {
return 0;
}
if (! * RmtStubs[idx].head.name) {
return 0;
}
return RmtStubs + idx;
}
static void stbDtor (Stub that) {
luti_ltrmv (StubLT, that->head.name);
if (that->cbdta.delcb) {
if (that->actcld) {
(*that->cbdta.delcb) (
that->cbdta.delcld, that, that->actcld);
}
if (that->cbdta.dfltcld) {
(*that->cbdta.delcb) (
that->cbdta.delcld, that, that->cbdta.dfltcld);
}
(*that->cbdta.delcb) (that->cbdta.delcld, that, 0);
}
if (that->dbase) {
int j;
for (j = that->head.ndbs; 0 <= --j; ) {
if (* that->dbase[j].head.name) {
cdbDtor (that->dbase + j);
}
}
mFree (that->dbase);
}
if (that->head.dbs) {
mFree (that->head.dbs);
}
if (that->head.cfg) {
mFree (that->head.cfg);
}
luti_ltdel (that->hsh);
nClean (that);
stbClear (that);
}
static int stbDbidFromName (Stub that, const char *dbn) {
int id;
if (! dbn) {
return -1;
}
id = luti_ltget (that->hsh, dbn);
return id;
}
static int stbDbIdxFromName (Stub that, const char *dbn) {
int idx = stbDbidFromName (that, dbn);
if (0 > idx) {
return -1;
}
idx = DB_I2X (idx);
if (! DB_IDX_OK (that, idx)) {
return -1;
}
return idx;
}
static int stbOpenDb (Stub that) {
char dbn[DBNLEN];
Fdt *fdt;
Rec *cfg;
int idx, dbid, tms;
int newdb = 0;
if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, DBNLEN)) {
return sMsg (ERR_IDIOT, "%s: stbOpenDb: missing db name in rsp",
that->head.name);
}
idx = stbDbIdxFromName (that, dbn);
if (0 > idx) {
idx = cdbNewIdx (that);
if (0 > idx) {
return idx;
}
newdb = !0;
}
else {
cdbDtor (that->dbase + idx);
}
fdt = fRec2Fdt (that->rsp);
cfg = luti_unwrap (that->rsp, 0, OPENISIS_COM_CFG, -1);
tms = rInt (that->rsp, OPENISIS_COM_TMS, 0, 0);
dbid = DB_X2I (idx, that->head.scid);
cdbCtor (that->dbase + idx, dbn, dbid, tms, fdt, cfg);
if (newdb) {
luti_ltadd (that->hsh, dbn, dbid);
}
return 0;
}
static int stbOpenDb0 (Stub that) {
Db *dbh;
int newdb = 0;
int dbid = rInt (that->rsp, OPENISIS_RSP_DBID, -1, 0);
if (0 > dbid) {
return sMsg (ERR_IDIOT, "stbOpenDb0: missing dbid in rsp");
}
newdb = cdbNewIdx0 (that, dbid);
if (0 > newdb) {
return newdb;
}
dbh = ldb_getdb (dbid);
if (! dbh) {
return sMsg (ERR_TRASH, "stbOpenDb0: no such db %d", dbid);
}
log_msg (LOG_INFO, "stbOpenDb0 %d %s", dbid, dbh->name);
that->head.dbs[dbid] = dbh;
if (newdb) {
luti_ltadd (that->hsh, dbh->name, dbid);
}
return 0;
}
static int stbCloseDb (Stub that) {
char dbn[DBNLEN];
CDb *db;
int dbid;
if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, sizeof (dbn))) {
return sMsg (ERR_IDIOT, "%s: stbCloseDb: missing db name in rsp",
that->head.name);
}
dbid = stbDbIdxFromName (that, dbn);
if (0 > dbid) {
return sMsg (ERR_TRASH, "%s: stbCloseDb: illegal db name <%s> in rsp",
that->head.name, dbn);
}
db = that->dbase + dbid;
luti_ltrmv (that->hsh, db->head.name);
cdbDtor (db);
return 0;
}
static int stbCloseDb0 (Stub that) {
char dbn[DBNLEN];
int dbid = rInt (that->rsp, OPENISIS_RSP_DBID, -1, 0);
if (0 > dbid) {
return sMsg (ERR_IDIOT, "stbCloseDb0: missing dbid in rsp");
}
if (that->head.ndbs <= dbid) {
return sMsg (ERR_TRASH, "stbCloseDb0: illegal dbid %d(%d) in rsp",
dbid, that->head.ndbs);
}
if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, DBNLEN)) {
return sMsg (ERR_IDIOT, "stbCloseDb0: missing db name in rsp\n");
}
log_msg (LOG_INFO, "stbCloseDb0 %d %s", dbid, dbn);
luti_ltrmv (that->hsh, dbn);
that->head.dbs[dbid] = 0;
return 0;
}
/* (local) response callback
*/
static int stbRspCb (Rec **rsp, void *cld) {
Stub that;
Rec *rsp2;
int sid, ser, err, err2, err3;
(void)cld;
sid = rInt (*rsp, OPENISIS_COM_SID, -1, 0);
ser = rInt (*rsp, OPENISIS_COM_SER, -1, 0);
err = rInt (*rsp, OPENISIS_RSP_ERR, -1, 0);
that = stbById (sid);
if (! that) {
return sMsg (ERR_TRASH, "illegal stub id %d in stbRspCb\n", sid);
}
if (ser != that->srq) {
return sMsg (ERR_TRASH, "%s: rqs serial mismatch %d != %d",
that->head.name, ser, that->srq);
}
if (! that->rqs) {
return sMsg (ERR_TRASH, "%s/%d: response without request",
that->head.name, sid);
}
if (that->rsp) {
sMsg (ERR_TRASH, "%s: multiple responses",
that->head.name);
mFree (that->rsp);
}
that->rdb = 0;
that->rsp = *rsp;
*rsp = 0;
err2 = err3 = 0;
if (0 == err) {
int rtyp = rInt (that->rqs, OPENISIS_RQS_TYPE, -1, 0);
switch (rtyp) {
case OPENISIS_RQST_LSDB:
case OPENISIS_RQST_EVAL:
break;
case OPENISIS_RQST_CLOS:
if (sid) {
err2 = sMsg (ERR_IDIOT, "%s: db close on remote stub",
that->head.name);
}
else {
err2 = stbCloseDb0 (that);
}
break;
case OPENISIS_RQST_OPEN:
if (sid) {
err2 = sMsg (ERR_IDIOT, "%s: db open on remote stub",
that->head.name);
break;
}
err2 = stbOpenDb0 (that);
goto setdb;
case OPENISIS_RQST_MNT:
if (0 == sid) {
err2 = sMsg (ERR_IDIOT, "db mount on local stub");
break;
}
err2 = stbOpenDb (that);
goto setdb;
default:
setdb: {
char dbn[DBNLEN];
int rdid, rx;
if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, sizeof(dbn))) {
if (sid) {
err2 = sMsg (ERR_IDIOT,
"%s: stbRspCb: missing db name in rsp",
that->head.name);
}
else {
err2 = sMsg (ERR_IDIOT,
"stbRspCb: missing db name in rsp");
}
}
else {
rdid = stbDbidFromName (that, dbn);
if (0 > rdid) {
if (sid) {
err2 = sMsg (ERR_TRASH,
"%s: stbRspCb: illegal db name <%s> in rsp",
that->head.name, dbn);
}
else {
err2 = sMsg (ERR_TRASH,
"stbRspCb: illegal db name <%s> in rsp", dbn);
}
}
else {
/* see nDbById */
rx = DB_I2X (rdid);
if (! DB_IDX_OK (that, rx)) {
if (sid) {
err2 = sMsg (ERR_TRASH,
"%s: stbRspCb: illegal db id %d %d <%s>",
that->head.name, rdid, rx, dbn);
}
else {
err2 = sMsg (ERR_TRASH,
"stbRspCb: illegal db id %d %d <%s>",
rdid, rx, dbn);
}
}
else {
that->rdb = that->head.dbs[rx];
}
}
}
}
} /* switch */
}
else { /* err */
int tms;
tms = rInt (that->rsp, OPENISIS_COM_TMS, 0, 0);
if (tms && sid) { /* remounted */
err2 = stbCloseDb (that);
}
}
rsp2 = rAddI (that->rsp, OPENISIS_RSP_CERR, err2, !0);
if (rsp2) {
that->rsp = rsp2;
}
if (that->actcb) {
err3 = (*that->actcb) (that->actcld,
that, that->rsp, that->rdb);
if (that->actcld && that->cbdta.delcb) {
(*that->cbdta.delcb) (
that->cbdta.delcld, that, that->actcld);
}
that->actcb = 0;
that->actcld = 0;
}
else if (that->cbdta.dfltcb) {
err3 = (*that->cbdta.dfltcb) (that->cbdta.dfltcld,
that, that->rsp, that->rdb);
}
sMsg (LOG_VERBOSE, "stbRspCb(%s): %d/%d err = %x,%x,%x",
that->head.name, sid, ser, err, err2, err3);
return err3;
}
static int stbLocalRqs (Stub that, Rec *rqs) {
(void)that;
return ldspProcess (rqs, 0, &stbRspCb, 0);
}
static int stbSyncRqs (Stub that, Rec *rqs) {
Rec *rsp;
int rt;
if (0 > that->chn.sd) {
rt = cliConnect (&that->chn, that->host, that->port);
if (0 > rt) {
return rt;
}
}
rt = cliWrite (&that->chn, rqs);
if (0 > rt) {
return rt;
}
rsp = cliRead (&that->chn);
if (! rsp) {
return sMsg (ERR_IO, "stbSyncRqs: read error %d - %s",
that->chn.err, strerror (that->chn.err));
}
rt = stbRspCb (&rsp, 0);
if (rsp) {
mFree (rsp);
}
return rt;
}
/* ************************************************************
package functions
*/
/* ************************************************************
public functions
*/
Stub nInit (
int argc, const char **argv, OpenIsisStubCbData *dta
) {
Rec *cfg = 0;
if (stub0) {
return stub0;
}
StubLT = luti_ltnew ();
stub0 = mAlloc (STBSIZE);
stbClear (stub0);
if (0 < argc) {
char buf[PATH_MAX];
char *logn;
int logl;
cfg = rSet (0, RFDT | RARGV | RIGN | argc, openIsisFdtSyspar, argv);
logn = rString (cfg, OPENISIS_SLOGF, 0, buf, sizeof(buf));
logl = rInt (cfg, OPENISIS_SLOGV, -1, 0);
if (logn || 0 <= logl) {
cLog (logl, logn);
}
}
stbCtor (stub0, "", 0, cfg, 0, 0, 0, dta);
return stub0;
}
Stub nOpen (
const char *name, int argc, const char *argv[], OpenIsisStubCbData *dta
) {
OpenIsisStb buf;
Stub that;
Rec *cfg = 0;
int idx, sid;
if (! stub0 || ! name || ! *name) {
return 0;
}
idx = luti_ltget (StubLT, name);
if (0 <= idx) {
idx = SC_I2X (idx);
if (0 > idx || NumStubs <= idx || ! * RmtStubs[idx].head.name) {
log_msg (LOG_ERROR, "nOpen: illegal idx %d(%d) for %s",
idx, NumStubs, name);
return 0;
}
return RmtStubs + idx;
}
idx = stbNewIdx ();
if (0 > idx) {
return 0;
}
if (0 < argc) {
cfg = rSet (0, RFDT | RARGV | RIGN | argc, openIsisFdtScheme, argv);
}
sid = SC_X2I (idx);
stbClear (&buf);
if (! stbCtor (&buf, name, sid, cfg, 0, 0, 0, dta)) {
if (cfg) {
mFree (cfg);
}
return 0;
}
that = RmtStubs + idx;
memcpy (that, &buf, STBSIZE);
return that;
}
void nClose (Stub that) {
if (that && *that->head.name) {
stbDtor (that);
}
}
void nDeinit () {
if (stub0) {
int j;
if (RmtStubs) {
for (j = NumStubs; 0 <= --j; ) {
if (* RmtStubs[j].head.name) {
stbDtor (RmtStubs + j);
}
}
mFree (RmtStubs);
RmtStubs = 0;
NumStubs = 0;
}
for (j = stub0->head.ndbs; 0 <= --j; ) {
if (stub0->head.dbs[j]) {
cDClose (stub0->head.dbs[j]->dbid);
}
}
stbDtor (stub0);
mFree (stub0);
stub0 = 0;
luti_ltdel (StubLT);
StubLT = 0;
}
}
Schema* nSchema (Stub that) {
int idx;
if (that && ( stub0 == that || ( *that->head.name &&
0 <= (idx = SC_I2X (that->head.scid)) && NumStubs > idx
))) {
return &that->head;
}
return 0;
}
void nClean (Stub that) {
if (that->rqs) {
mFree (that->rqs);
that->rqs = 0;
}
if (that->rsp) {
mFree (that->rsp);
that->rsp = 0;
}
that->rdb = 0;
}
int nSend (Stub that,
Rec *rqs, OpenIsisRspCb *actcb, void *actcld, int dup
) {
char buf[DBNLEN];
char sid[16];
char ser[16];
char tms[16];
char *dbl, *dbn;
int dbid, rtyp, setn;
if (!(that && rqs)) {
return sMsg (ERR_IDIOT, "nSend: null pointer %x %x",
(int)that, (int)rqs);
}
if (stub0 != that && ! *that->head.name) {
return sMsg (ERR_IDIOT, "nSend: invalid stub");
}
setn = !0;
rtyp = rInt (rqs, OPENISIS_RQS_TYPE, -1, 0);
switch (rtyp) {
case -1:
return sMsg (ERR_IDIOT, "nSend(%s): request without type",
that->head.name);
case OPENISIS_RQST_LSDB:
case OPENISIS_RQST_EVAL:
setn = 0;
break;
case OPENISIS_RQST_OPEN:
case OPENISIS_RQST_CLOS:
if (stub0 != that) {
return sMsg (ERR_IDIOT, "nSend(%s): request %d denied",
that->head.name, rtyp);
}
break;
case OPENISIS_RQST_MNT:
if (stub0 == that) {
return sMsg (ERR_IDIOT, "nSend: local mount denied");
}
rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
OPENISIS_COM_TMS, "0", 0);
if (! rqs) {
return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
that->head.name);
}
break;
}
dbid = -1;
dbn = 0;
dbl = that->rdb ? that->rdb->name : 0;
nClean (that);
i2a (sid, that->head.scid);
if (0 >= ++that->srq) {
that->srq = 1;
log_msg (LOG_INFO, "stub %s: srq loop over 0", that->head.name);
}
i2a (ser, that->srq);
if (setn) {
if ((dbn = rString (rqs, OPENISIS_COM_DBN, 0, buf, DBNLEN))) {
setn = 0;
}
else {
if (dbl) {
dbn = dbl;
}
else {
dbn = rString (that->head.cfg,
OPENISIS_SC_DFLTDB, 0, buf, DBNLEN);
}
}
if (! dbn) {
return sMsg (ERR_IDIOT, "nSend(%s): request without db name",
that->head.name);
}
if (0 > rInt (rqs, OPENISIS_COM_TMS, -1, 0)) {
dbid = stbDbIdxFromName (that, dbn);
if (0 <= dbid) {
i2a (tms, that->head.dbs[dbid]->tms);
}
}
}
if (dup) {
rqs = rDup (rqs, 0, 0);
if (! rqs) {
return -1;
}
}
rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
OPENISIS_COM_SID, sid, OPENISIS_COM_SER, ser,
0 <= dbid ? OPENISIS_COM_TMS : 0, tms, 0);
if (! rqs) {
return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
that->head.name);
}
if (setn) {
rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
OPENISIS_COM_DBN, dbn, 0);
if (! rqs) {
return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
that->head.name);
}
}
that->rqs = rqs;
if (that->actcld && that->cbdta.delcb) {
/* ooups */
(*that->cbdta.delcb) (
that->cbdta.delcld, that, that->actcld);
}
if (actcb) {
that->actcb = actcb;
that->actcld = actcld;
}
else {
that->actcb = 0;
that->actcld = 0;
}
return (*that->rqsp) (that, that->rqs);
}
Rec* nRecv (Stub that, Db **db) {
if (that && (
stub0 == that || *that->head.name
)) {
if (db) {
*db = that->rdb;
}
return that->rsp;
}
return 0;
}
Db* nDbByName (Stub that, const char *dbname) {
if (that && (
stub0 == that || *that->head.name
)) {
int dbid = stbDbIdxFromName (that, dbname);
if (0 <= dbid) {
return that->head.dbs[dbid];
}
}
return 0;
}
Db* nDbById (int id) {
Stub that = stbById (id & OPENISIS_SCIDMSK);
if (! that) {
return 0;
}
id = DB_I2X (id);
if (! DB_IDX_OK (that, id)) {
return 0;
}
return that->head.dbs[id];
}
#define FREEPTR(p) if (p) { mFree (p); p = 0; }
#define FREEROW if (rowids) { FREEPTR(*rowids) }
int nResult (
Stub that, int **rowids, Rec ***recs, Db **db, int *tot
) {
Field *F;
Rec **R;
int *I;
int numt, numr, err, pos, j;
if (rowids) {
*rowids = 0;
}
if (recs) {
*recs = 0;
}
if (db) {
*db = 0;
}
if (tot) {
*tot = 0;
}
if (! that) {
return sMsg (ERR_IDIOT, "nGetResult: null pointer");
}
if (! that->rsp) {
return sMsg (ERR_IDIOT, "nGetResult(%s): no response",
that->head.name);
}
err = rInt (that->rsp, OPENISIS_RSP_ERR, 0, 0);
if (err) {
return sMsg (ERR_IDIOT, "nGetResult(%s): response error %d",
that->head.name, err);
}
numr = rInt (that->rsp, OPENISIS_RSP_NUMR, -1, 0);
numt = rInt (that->rsp, OPENISIS_RSP_NUMT, -1, 0);
if (0 > numr || 0 > numt) {
return sMsg (ERR_IDIOT, "nGetResult(%s): no record count in response",
that->head.name);
}
if (numr) {
if (rowids) {
*rowids = (int*) mAlloc (numr * sizeof (int));
if (! *rowids) {
return sMsg (ERR_NOMEM, "nGetResult(%s): out of memory",
that->head.name);
}
for (I = *rowids, j = pos = 0; numr > j; ++I, ++j) {
*I = rInt (that->rsp, OPENISIS_COM_ROW, -1, &pos);
if (0 > *I) {
FREEROW;
return sMsg (ERR_TRASH,
"nGetResult(%s): missing rowid %d(%d)",
that->head.name, j, numr);
}
}
}
if (recs) {
*recs = (Rec**) mAlloc (numr * sizeof (Rec*));
if (! *recs) {
FREEROW;
return sMsg (ERR_NOMEM, "nGetResult(%s): out of memory",
that->head.name);
}
memset (*recs, 0, numr * sizeof (Rec*));
R = *recs;
I = rowids ? *rowids : 0;
j = pos = 0;
F = rGet (that->rsp, OPENISIS_COM_REC, &pos);
if (! F) {
sMsg (LOG_WARN,
"nGetResult(%s): no records in response",
that->head.name);
FREEPTR (*recs);
}
else {
--pos;
while (numr > j) {
*R = luti_unwrap (that->rsp, &pos, OPENISIS_COM_REC,
that->rdb ? that->rdb->dbid : -1);
if (! *R) {
FREEROW;
luti_free ((void**)*recs, j);
*recs = 0;
return sMsg (ERR_NOMEM,
"nGetResult(%s): out of memory", that->head.name);
}
if (I) {
(*R)->rowid = *I;
++I;
}
++R;
++j;
}
}
} /* recs */
} /* numr */
if (db) {
*db = that->rdb;
}
if (tot) {
*tot = numt;
}
return numr;
}