2 openisis - an open implementation of the CDS/ISIS database
3 Version 0.8.x (patchlevel see file Version)
4 Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 see README for more information
24 $Id: lstb.c,v 1.41 2003/06/15 15:57:43 mawag Exp $
25 implementation of client side session and communication functions.
29 #include <limits.h> /* PATH_MAX */
43 #define snprintf _snprintf
44 #define vsnprintf _vsnprintf
47 #define LSTB_STHOSTLEN 32
49 #define LSTB_MAXDBS 255 /* according to OPENISIS_DBIDMSK */
50 #define LSTB_MAXSTUBS 255 /* according to OPENISIS_SCIDMSK */
53 #define LSTB_INCRSTUB 8
55 /* ************************************************************
59 /* stub id 0 has idx -1 */
60 /* stub id 0x0100 has idx 0 */
62 #define SC_X2I(s) ( ( (1 + (s)) << 8 ) & OPENISIS_SCIDMSK )
64 #define SC_I2X(s) ( ( ((s) & OPENISIS_SCIDMSK) >> 8 ) - 1 )
66 #define DB_X2I(d,s) ( ((s) & OPENISIS_SCIDMSK) | ((d) & OPENISIS_DBIDMSK) )
68 #define DB_I2X(d) ( (d) & OPENISIS_DBIDMSK )
70 #define DB_IDX_OK(st,idx) \
71 (0 <= (idx) && (st)->head.ndbs > (idx) && * (st)->head.dbs[idx]->name)
73 /* ************************************************************
81 static void cdbCtor (CDb *that,
82 const char *name, int dbid, int tms, Fdt *fdt, Rec *cfg
84 strncpy (that->head.name, name, DBNLEN - 1) [DBNLEN - 1] = 0;
85 that->head.dbid = dbid;
91 static void cdbDtor (CDb *that) {
93 fFree (that->head.fdt);
96 mFree (that->head.cfg);
98 memset (that, 0, sizeof (CDb));
101 /* ************************************************************
105 typedef struct OpenIsisStb {
107 char host[LSTB_STHOSTLEN];
109 int srq; /* rqs serial no */
110 Rec *rqs; /* last request */
111 Rec *rsp; /* last response */
112 Db *rdb; /* db of embedded rsp recs */
113 CDb *dbase; /* db array of non-local schema */
116 OpenIsisStbRqsProc *rqsp;
117 OpenIsisStbDelProc *delp;
118 void *cld; /* client_data of rqsp */
120 OpenIsisRspCb *actcb;
122 OpenIsisStubCbData cbdta;
127 static Stub RmtStubs = 0;
128 static int NumStubs = 0;
130 static LutiLT StubLT = 0;
132 #define STBSIZE (sizeof(Stb))
134 static int stbLocalRqs (Stub that, Rec *rqs);
135 static int stbSyncRqs (Stub that, Rec *rqs);
137 static void stbClear (Stub that) {
138 memset (that, 0, STBSIZE);
142 static int stbCtor (Stub that,
143 const char *name, int scid, Rec *cfg,
144 OpenIsisStbRqsProc *rqsp, OpenIsisStbDelProc *delp, void *cld,
145 OpenIsisStubCbData *cbd
147 strncpy (that->head.name, name, SCNLEN - 1) [SCNLEN - 1] = 0;
148 that->head.scid = scid;
150 if (! rString (cfg, OPENISIS_SC_HOST, 0, that->host, LSTB_STHOSTLEN)) {
153 that->port = rInt (cfg, OPENISIS_SC_PORT, 0, 0);
154 if (0 >= that->port) {
161 that->rqsp = &stbSyncRqs;
165 that->rqsp = &stbLocalRqs;
168 rSet (cfg, RCHG | RDIS, OPENISIS_SC_NAME, that->head.name, 0);
171 that->hsh = luti_ltnew ();
173 memcpy (&that->cbdta, cbd, sizeof (OpenIsisStubCbData));
175 luti_ltadd (StubLT, that->head.name, scid);
179 /* return idx or -err */
180 static int cdbNewIdx (Stub that) {
181 int ndb = that->head.ndbs;
183 for (j = 0; ndb > j; ++j) {
184 if (! * that->dbase[j].head.name) {
188 rt = luti_ptrincr (&that->dbase, &ndb,
189 LSTB_INCRDB, sizeof (CDb), LSTB_MAXDBS);
191 return sMsg (ERR_NOMEM, "%s: cdbNewIdx: out of memory",
194 rt = luti_ptrincr (&that->head.dbs, &that->head.ndbs,
195 LSTB_INCRDB, sizeof (CDb*), LSTB_MAXDBS);
197 return sMsg (ERR_NOMEM, "%s: cdbNewIdx: out of memory",
200 for (j = that->head.ndbs; 0 <= --j; ) {
201 that->head.dbs[j] = (Db*) (that->dbase + j);
206 /* return bool newly allocated or -err */
207 static int cdbNewIdx0 (Stub that, int dbid) {
209 if (dbid < that->head.ndbs) {
210 if (that->head.dbs[dbid]) {
215 rt = luti_ptrincr (&that->head.dbs, &that->head.ndbs,
216 1 + dbid - that->head.ndbs, sizeof (CDb*), -1);
218 return sMsg (ERR_NOMEM, "%s: cdbNewIdx0(%d): out of memory",
219 that->head.name, dbid);
224 static int stbNewIdx () {
226 for (j = 0; NumStubs > j; ++j) {
227 if (! * RmtStubs[j].head.name) {
231 j = luti_ptrincr (&RmtStubs, &NumStubs,
232 LSTB_INCRSTUB, STBSIZE, LSTB_MAXSTUBS);
233 /* stbClear (RmtStubs + j) done in nOpen */
237 static Stub stbById (int sid) {
239 if (0 > sid || ! stub0) {
247 log_msg (LOG_ERROR, "stbById: illegal id %x", sid);
250 if (NumStubs <= idx) {
253 if (! * RmtStubs[idx].head.name) {
256 return RmtStubs + idx;
259 static void stbDtor (Stub that) {
260 luti_ltrmv (StubLT, that->head.name);
261 if (that->cbdta.delcb) {
263 (*that->cbdta.delcb) (
264 that->cbdta.delcld, that, that->actcld);
266 if (that->cbdta.dfltcld) {
267 (*that->cbdta.delcb) (
268 that->cbdta.delcld, that, that->cbdta.dfltcld);
270 (*that->cbdta.delcb) (that->cbdta.delcld, that, 0);
274 for (j = that->head.ndbs; 0 <= --j; ) {
275 if (* that->dbase[j].head.name) {
276 cdbDtor (that->dbase + j);
281 if (that->head.dbs) {
282 mFree (that->head.dbs);
284 if (that->head.cfg) {
285 mFree (that->head.cfg);
287 luti_ltdel (that->hsh);
292 static int stbDbidFromName (Stub that, const char *dbn) {
297 id = luti_ltget (that->hsh, dbn);
301 static int stbDbIdxFromName (Stub that, const char *dbn) {
302 int idx = stbDbidFromName (that, dbn);
307 if (! DB_IDX_OK (that, idx)) {
313 static int stbOpenDb (Stub that) {
320 if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, DBNLEN)) {
321 return sMsg (ERR_IDIOT, "%s: stbOpenDb: missing db name in rsp",
324 idx = stbDbIdxFromName (that, dbn);
327 idx = cdbNewIdx (that);
334 cdbDtor (that->dbase + idx);
337 fdt = fRec2Fdt (that->rsp);
338 cfg = luti_unwrap (that->rsp, 0, OPENISIS_COM_CFG, -1);
339 tms = rInt (that->rsp, OPENISIS_COM_TMS, 0, 0);
340 dbid = DB_X2I (idx, that->head.scid);
342 cdbCtor (that->dbase + idx, dbn, dbid, tms, fdt, cfg);
345 luti_ltadd (that->hsh, dbn, dbid);
350 static int stbOpenDb0 (Stub that) {
353 int dbid = rInt (that->rsp, OPENISIS_RSP_DBID, -1, 0);
355 return sMsg (ERR_IDIOT, "stbOpenDb0: missing dbid in rsp");
358 newdb = cdbNewIdx0 (that, dbid);
363 dbh = ldb_getdb (dbid);
365 return sMsg (ERR_TRASH, "stbOpenDb0: no such db %d", dbid);
367 log_msg (LOG_INFO, "stbOpenDb0 %d %s", dbid, dbh->name);
369 that->head.dbs[dbid] = dbh;
371 luti_ltadd (that->hsh, dbh->name, dbid);
376 static int stbCloseDb (Stub that) {
380 if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, sizeof (dbn))) {
381 return sMsg (ERR_IDIOT, "%s: stbCloseDb: missing db name in rsp",
384 dbid = stbDbIdxFromName (that, dbn);
386 return sMsg (ERR_TRASH, "%s: stbCloseDb: illegal db name <%s> in rsp",
387 that->head.name, dbn);
389 db = that->dbase + dbid;
390 luti_ltrmv (that->hsh, db->head.name);
395 static int stbCloseDb0 (Stub that) {
397 int dbid = rInt (that->rsp, OPENISIS_RSP_DBID, -1, 0);
399 return sMsg (ERR_IDIOT, "stbCloseDb0: missing dbid in rsp");
401 if (that->head.ndbs <= dbid) {
402 return sMsg (ERR_TRASH, "stbCloseDb0: illegal dbid %d(%d) in rsp",
403 dbid, that->head.ndbs);
405 if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, DBNLEN)) {
406 return sMsg (ERR_IDIOT, "stbCloseDb0: missing db name in rsp\n");
408 log_msg (LOG_INFO, "stbCloseDb0 %d %s", dbid, dbn);
409 luti_ltrmv (that->hsh, dbn);
410 that->head.dbs[dbid] = 0;
414 /* (local) response callback
416 static int stbRspCb (Rec **rsp, void *cld) {
419 int sid, ser, err, err2, err3;
422 sid = rInt (*rsp, OPENISIS_COM_SID, -1, 0);
423 ser = rInt (*rsp, OPENISIS_COM_SER, -1, 0);
424 err = rInt (*rsp, OPENISIS_RSP_ERR, -1, 0);
426 that = stbById (sid);
428 return sMsg (ERR_TRASH, "illegal stub id %d in stbRspCb\n", sid);
430 if (ser != that->srq) {
431 return sMsg (ERR_TRASH, "%s: rqs serial mismatch %d != %d",
432 that->head.name, ser, that->srq);
435 return sMsg (ERR_TRASH, "%s/%d: response without request",
436 that->head.name, sid);
439 sMsg (ERR_TRASH, "%s: multiple responses",
450 int rtyp = rInt (that->rqs, OPENISIS_RQS_TYPE, -1, 0);
453 case OPENISIS_RQST_LSDB:
454 case OPENISIS_RQST_EVAL:
457 case OPENISIS_RQST_CLOS:
459 err2 = sMsg (ERR_IDIOT, "%s: db close on remote stub",
463 err2 = stbCloseDb0 (that);
467 case OPENISIS_RQST_OPEN:
469 err2 = sMsg (ERR_IDIOT, "%s: db open on remote stub",
473 err2 = stbOpenDb0 (that);
476 case OPENISIS_RQST_MNT:
478 err2 = sMsg (ERR_IDIOT, "db mount on local stub");
481 err2 = stbOpenDb (that);
488 if (! rString (that->rsp, OPENISIS_COM_DBN, 0, dbn, sizeof(dbn))) {
490 err2 = sMsg (ERR_IDIOT,
491 "%s: stbRspCb: missing db name in rsp",
495 err2 = sMsg (ERR_IDIOT,
496 "stbRspCb: missing db name in rsp");
500 rdid = stbDbidFromName (that, dbn);
503 err2 = sMsg (ERR_TRASH,
504 "%s: stbRspCb: illegal db name <%s> in rsp",
505 that->head.name, dbn);
508 err2 = sMsg (ERR_TRASH,
509 "stbRspCb: illegal db name <%s> in rsp", dbn);
515 if (! DB_IDX_OK (that, rx)) {
517 err2 = sMsg (ERR_TRASH,
518 "%s: stbRspCb: illegal db id %d %d <%s>",
519 that->head.name, rdid, rx, dbn);
522 err2 = sMsg (ERR_TRASH,
523 "stbRspCb: illegal db id %d %d <%s>",
528 that->rdb = that->head.dbs[rx];
537 tms = rInt (that->rsp, OPENISIS_COM_TMS, 0, 0);
538 if (tms && sid) { /* remounted */
539 err2 = stbCloseDb (that);
543 rsp2 = rAddI (that->rsp, OPENISIS_RSP_CERR, err2, !0);
549 err3 = (*that->actcb) (that->actcld,
550 that, that->rsp, that->rdb);
551 if (that->actcld && that->cbdta.delcb) {
552 (*that->cbdta.delcb) (
553 that->cbdta.delcld, that, that->actcld);
558 else if (that->cbdta.dfltcb) {
559 err3 = (*that->cbdta.dfltcb) (that->cbdta.dfltcld,
560 that, that->rsp, that->rdb);
563 sMsg (LOG_VERBOSE, "stbRspCb(%s): %d/%d err = %x,%x,%x",
564 that->head.name, sid, ser, err, err2, err3);
569 static int stbLocalRqs (Stub that, Rec *rqs) {
571 return ldspProcess (rqs, 0, &stbRspCb, 0);
574 static int stbSyncRqs (Stub that, Rec *rqs) {
577 if (0 > that->chn.sd) {
578 rt = cliConnect (&that->chn, that->host, that->port);
583 rt = cliWrite (&that->chn, rqs);
587 rsp = cliRead (&that->chn);
589 return sMsg (ERR_IO, "stbSyncRqs: read error %d - %s",
590 that->chn.err, strerror (that->chn.err));
592 rt = stbRspCb (&rsp, 0);
599 /* ************************************************************
603 /* ************************************************************
608 int argc, const char **argv, OpenIsisStubCbData *dta
616 StubLT = luti_ltnew ();
617 stub0 = mAlloc (STBSIZE);
625 cfg = rSet (0, RFDT | RARGV | RIGN | argc, openIsisFdtSyspar, argv);
627 logn = rString (cfg, OPENISIS_SLOGF, 0, buf, sizeof(buf));
628 logl = rInt (cfg, OPENISIS_SLOGV, -1, 0);
629 if (logn || 0 <= logl) {
634 stbCtor (stub0, "", 0, cfg, 0, 0, 0, dta);
639 const char *name, int argc, const char *argv[], OpenIsisStubCbData *dta
646 if (! stub0 || ! name || ! *name) {
650 idx = luti_ltget (StubLT, name);
653 if (0 > idx || NumStubs <= idx || ! * RmtStubs[idx].head.name) {
654 log_msg (LOG_ERROR, "nOpen: illegal idx %d(%d) for %s",
655 idx, NumStubs, name);
658 return RmtStubs + idx;
666 cfg = rSet (0, RFDT | RARGV | RIGN | argc, openIsisFdtScheme, argv);
670 if (! stbCtor (&buf, name, sid, cfg, 0, 0, 0, dta)) {
677 that = RmtStubs + idx;
678 memcpy (that, &buf, STBSIZE);
682 void nClose (Stub that) {
683 if (that && *that->head.name) {
692 for (j = NumStubs; 0 <= --j; ) {
693 if (* RmtStubs[j].head.name) {
694 stbDtor (RmtStubs + j);
701 for (j = stub0->head.ndbs; 0 <= --j; ) {
702 if (stub0->head.dbs[j]) {
703 cDClose (stub0->head.dbs[j]->dbid);
714 Schema* nSchema (Stub that) {
716 if (that && ( stub0 == that || ( *that->head.name &&
717 0 <= (idx = SC_I2X (that->head.scid)) && NumStubs > idx
724 void nClean (Stub that) {
736 int nSend (Stub that,
737 Rec *rqs, OpenIsisRspCb *actcb, void *actcld, int dup
744 int dbid, rtyp, setn;
746 if (!(that && rqs)) {
747 return sMsg (ERR_IDIOT, "nSend: null pointer %x %x",
748 (int)that, (int)rqs);
750 if (stub0 != that && ! *that->head.name) {
751 return sMsg (ERR_IDIOT, "nSend: invalid stub");
754 rtyp = rInt (rqs, OPENISIS_RQS_TYPE, -1, 0);
757 return sMsg (ERR_IDIOT, "nSend(%s): request without type",
759 case OPENISIS_RQST_LSDB:
760 case OPENISIS_RQST_EVAL:
763 case OPENISIS_RQST_OPEN:
764 case OPENISIS_RQST_CLOS:
766 return sMsg (ERR_IDIOT, "nSend(%s): request %d denied",
767 that->head.name, rtyp);
770 case OPENISIS_RQST_MNT:
772 return sMsg (ERR_IDIOT, "nSend: local mount denied");
774 rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
775 OPENISIS_COM_TMS, "0", 0);
777 return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
785 dbl = that->rdb ? that->rdb->name : 0;
788 i2a (sid, that->head.scid);
789 if (0 >= ++that->srq) {
791 log_msg (LOG_INFO, "stub %s: srq loop over 0", that->head.name);
793 i2a (ser, that->srq);
796 if ((dbn = rString (rqs, OPENISIS_COM_DBN, 0, buf, DBNLEN))) {
804 dbn = rString (that->head.cfg,
805 OPENISIS_SC_DFLTDB, 0, buf, DBNLEN);
809 return sMsg (ERR_IDIOT, "nSend(%s): request without db name",
812 if (0 > rInt (rqs, OPENISIS_COM_TMS, -1, 0)) {
813 dbid = stbDbIdxFromName (that, dbn);
815 i2a (tms, that->head.dbs[dbid]->tms);
821 rqs = rDup (rqs, 0, 0);
827 rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
828 OPENISIS_COM_SID, sid, OPENISIS_COM_SER, ser,
829 0 <= dbid ? OPENISIS_COM_TMS : 0, tms, 0);
831 return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
835 rqs = rSet (rqs, RFDT | RDIS | RCHG, openIsisFdtRqs,
836 OPENISIS_COM_DBN, dbn, 0);
838 return sMsg (ERR_NOMEM, "nSend(%s): out of memory",
845 if (that->actcld && that->cbdta.delcb) {
847 (*that->cbdta.delcb) (
848 that->cbdta.delcld, that, that->actcld);
852 that->actcld = actcld;
859 return (*that->rqsp) (that, that->rqs);
862 Rec* nRecv (Stub that, Db **db) {
864 stub0 == that || *that->head.name
874 Db* nDbByName (Stub that, const char *dbname) {
876 stub0 == that || *that->head.name
878 int dbid = stbDbIdxFromName (that, dbname);
880 return that->head.dbs[dbid];
886 Db* nDbById (int id) {
887 Stub that = stbById (id & OPENISIS_SCIDMSK);
892 if (! DB_IDX_OK (that, id)) {
895 return that->head.dbs[id];
898 #define FREEPTR(p) if (p) { mFree (p); p = 0; }
899 #define FREEROW if (rowids) { FREEPTR(*rowids) }
902 Stub that, int **rowids, Rec ***recs, Db **db, int *tot
907 int numt, numr, err, pos, j;
922 return sMsg (ERR_IDIOT, "nGetResult: null pointer");
925 return sMsg (ERR_IDIOT, "nGetResult(%s): no response",
928 err = rInt (that->rsp, OPENISIS_RSP_ERR, 0, 0);
930 return sMsg (ERR_IDIOT, "nGetResult(%s): response error %d",
931 that->head.name, err);
933 numr = rInt (that->rsp, OPENISIS_RSP_NUMR, -1, 0);
934 numt = rInt (that->rsp, OPENISIS_RSP_NUMT, -1, 0);
935 if (0 > numr || 0 > numt) {
936 return sMsg (ERR_IDIOT, "nGetResult(%s): no record count in response",
941 *rowids = (int*) mAlloc (numr * sizeof (int));
943 return sMsg (ERR_NOMEM, "nGetResult(%s): out of memory",
946 for (I = *rowids, j = pos = 0; numr > j; ++I, ++j) {
947 *I = rInt (that->rsp, OPENISIS_COM_ROW, -1, &pos);
950 return sMsg (ERR_TRASH,
951 "nGetResult(%s): missing rowid %d(%d)",
952 that->head.name, j, numr);
958 *recs = (Rec**) mAlloc (numr * sizeof (Rec*));
961 return sMsg (ERR_NOMEM, "nGetResult(%s): out of memory",
964 memset (*recs, 0, numr * sizeof (Rec*));
966 I = rowids ? *rowids : 0;
968 F = rGet (that->rsp, OPENISIS_COM_REC, &pos);
971 "nGetResult(%s): no records in response",
978 *R = luti_unwrap (that->rsp, &pos, OPENISIS_COM_REC,
979 that->rdb ? that->rdb->dbid : -1);
982 luti_free ((void**)*recs, j);
984 return sMsg (ERR_NOMEM,
985 "nGetResult(%s): out of memory", that->head.name);