From 6ba98a9f9f48e13738d9736cba9c45b5e94f42f2 Mon Sep 17 00:00:00 2001 From: Brian Cully Date: Mon, 14 Apr 2008 21:52:55 -0400 Subject: Initial import --- client/.cvsignore | 7 + client/.pure | 0 client/.svn/README.txt | 2 + client/.svn/empty-file | 0 client/.svn/entries | 67 +++ client/.svn/format | 1 + client/.svn/prop-base/.cvsignore.svn-base | 1 + client/.svn/prop-base/.pure.svn-base | 1 + client/.svn/prop-base/Makefile.svn-base | 1 + client/.svn/prop-base/nastapi.c.svn-base | 1 + client/.svn/prop-base/thread.c.svn-base | 1 + client/.svn/prop-base/thread.h.svn-base | 1 + client/.svn/props/.cvsignore.svn-work | 1 + client/.svn/props/.pure.svn-work | 1 + client/.svn/props/Makefile.svn-work | 1 + client/.svn/props/nastapi.c.svn-work | 1 + client/.svn/props/thread.c.svn-work | 1 + client/.svn/props/thread.h.svn-work | 1 + client/.svn/text-base/.cvsignore.svn-base | 7 + client/.svn/text-base/.pure.svn-base | 0 client/.svn/text-base/Makefile.svn-base | 26 + client/.svn/text-base/nastapi.c.svn-base | 885 ++++++++++++++++++++++++++++++ client/.svn/text-base/thread.c.svn-base | 75 +++ client/.svn/text-base/thread.h.svn-base | 19 + client/Makefile | 26 + client/nastapi.c | 885 ++++++++++++++++++++++++++++++ client/thread.c | 75 +++ client/thread.h | 19 + 28 files changed, 2106 insertions(+) create mode 100644 client/.cvsignore create mode 100644 client/.pure create mode 100644 client/.svn/README.txt create mode 100644 client/.svn/empty-file create mode 100644 client/.svn/entries create mode 100644 client/.svn/format create mode 100644 client/.svn/prop-base/.cvsignore.svn-base create mode 100644 client/.svn/prop-base/.pure.svn-base create mode 100644 client/.svn/prop-base/Makefile.svn-base create mode 100644 client/.svn/prop-base/nastapi.c.svn-base create mode 100644 client/.svn/prop-base/thread.c.svn-base create mode 100644 client/.svn/prop-base/thread.h.svn-base create mode 100644 client/.svn/props/.cvsignore.svn-work create mode 100644 client/.svn/props/.pure.svn-work create mode 100644 client/.svn/props/Makefile.svn-work create mode 100644 client/.svn/props/nastapi.c.svn-work create mode 100644 client/.svn/props/thread.c.svn-work create mode 100644 client/.svn/props/thread.h.svn-work create mode 100644 client/.svn/text-base/.cvsignore.svn-base create mode 100644 client/.svn/text-base/.pure.svn-base create mode 100644 client/.svn/text-base/Makefile.svn-base create mode 100644 client/.svn/text-base/nastapi.c.svn-base create mode 100644 client/.svn/text-base/thread.c.svn-base create mode 100644 client/.svn/text-base/thread.h.svn-base create mode 100644 client/Makefile create mode 100644 client/nastapi.c create mode 100644 client/thread.c create mode 100644 client/thread.h (limited to 'client') diff --git a/client/.cvsignore b/client/.cvsignore new file mode 100644 index 0000000..35f79a6 --- /dev/null +++ b/client/.cvsignore @@ -0,0 +1,7 @@ +.pure +*.o +*.so +*.a +*.core +*.gmon +tags diff --git a/client/.pure b/client/.pure new file mode 100644 index 0000000..e69de29 diff --git a/client/.svn/README.txt b/client/.svn/README.txt new file mode 100644 index 0000000..271a8ce --- /dev/null +++ b/client/.svn/README.txt @@ -0,0 +1,2 @@ +This is a Subversion working copy administrative directory. +Visit http://subversion.tigris.org/ for more information. diff --git a/client/.svn/empty-file b/client/.svn/empty-file new file mode 100644 index 0000000..e69de29 diff --git a/client/.svn/entries b/client/.svn/entries new file mode 100644 index 0000000..273f9c8 --- /dev/null +++ b/client/.svn/entries @@ -0,0 +1,67 @@ + + + + + + + + + + diff --git a/client/.svn/format b/client/.svn/format new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/client/.svn/format @@ -0,0 +1 @@ +4 diff --git a/client/.svn/prop-base/.cvsignore.svn-base b/client/.svn/prop-base/.cvsignore.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/.cvsignore.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/prop-base/.pure.svn-base b/client/.svn/prop-base/.pure.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/.pure.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/prop-base/Makefile.svn-base b/client/.svn/prop-base/Makefile.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/Makefile.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/prop-base/nastapi.c.svn-base b/client/.svn/prop-base/nastapi.c.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/nastapi.c.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/prop-base/thread.c.svn-base b/client/.svn/prop-base/thread.c.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/thread.c.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/prop-base/thread.h.svn-base b/client/.svn/prop-base/thread.h.svn-base new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/prop-base/thread.h.svn-base @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/.cvsignore.svn-work b/client/.svn/props/.cvsignore.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/.cvsignore.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/.pure.svn-work b/client/.svn/props/.pure.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/.pure.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/Makefile.svn-work b/client/.svn/props/Makefile.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/Makefile.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/nastapi.c.svn-work b/client/.svn/props/nastapi.c.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/nastapi.c.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/thread.c.svn-work b/client/.svn/props/thread.c.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/thread.c.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/props/thread.h.svn-work b/client/.svn/props/thread.h.svn-work new file mode 100644 index 0000000..dce2c1d --- /dev/null +++ b/client/.svn/props/thread.h.svn-work @@ -0,0 +1 @@ +END diff --git a/client/.svn/text-base/.cvsignore.svn-base b/client/.svn/text-base/.cvsignore.svn-base new file mode 100644 index 0000000..35f79a6 --- /dev/null +++ b/client/.svn/text-base/.cvsignore.svn-base @@ -0,0 +1,7 @@ +.pure +*.o +*.so +*.a +*.core +*.gmon +tags diff --git a/client/.svn/text-base/.pure.svn-base b/client/.svn/text-base/.pure.svn-base new file mode 100644 index 0000000..e69de29 diff --git a/client/.svn/text-base/Makefile.svn-base b/client/.svn/text-base/Makefile.svn-base new file mode 100644 index 0000000..e92feed --- /dev/null +++ b/client/.svn/text-base/Makefile.svn-base @@ -0,0 +1,26 @@ +# $Id: Makefile,v 1.10 2001/01/19 02:54:37 shmit Exp $ + +LIBOBJS= nastapi.o thread.o + +all-lib: + @rm -f *.o + @make "THREADFLAGS=-UTHREADSAFECLIENT" libnast.a + @rm -f *.o + @make "THREADFLAGS=-DTHREADSAFECLIENT" libnast_r.a + +libnast.a: ${LIBOBJS} + ar r $@ ${LIBOBJS} + ranlib $@ + +libnast_r.a: ${LIBOBJS} + ar r $@ ${LIBOBJS} + ranlib $@ + +# +# Dependencies +# +nastapi.o: ../include/nastd.h ../include/nastipc.h thread.h +thread.o: thread.h + +MKDIR= ../Makefiles +include ${MKDIR}/build diff --git a/client/.svn/text-base/nastapi.c.svn-base b/client/.svn/text-base/nastapi.c.svn-base new file mode 100644 index 0000000..3e5a3b9 --- /dev/null +++ b/client/.svn/text-base/nastapi.c.svn-base @@ -0,0 +1,885 @@ +#include "conf.h" +#include "nastd.h" +#include "nastipc.h" +#include "thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RCSID("$Id: nastapi.c,v 1.13 2001/10/29 11:17:11 shmit Exp $"); + +char *nast_errmsgs[] = { + "No errors", + "The NASTD server has gone away", + "Couldn't allocate enough memory", + "Server response is unknown", + "Connection to server timed out", + "Unknown option returned", + NULL +}; + +static nast_string_t * +nast_string_new(int slen, const char *data) +{ + nast_string_t *tmp; + + tmp = malloc(sizeof(nast_string_t)); + if (tmp == NULL) + return NULL; + + tmp->strdata = malloc((slen+1) * sizeof(char *)); + if (tmp == NULL) + return NULL; + memcpy(tmp->strdata, data, slen); + tmp->strdata[slen] = '\0'; + tmp->strlen = slen; + + return tmp; +} + +static void +nast_string_delete(nast_string_t *string) +{ + string->strlen = 0; + free(string->strdata); + string->strdata = NULL; + free(string); +} + +nast_array * +nast_array_new() +{ + nast_array *aa; + + aa = malloc(sizeof(nast_array)); + if (aa == NULL) + return NULL; + + aa->nitems = 0; + aa->items = NULL; + return aa; +} + +int +nast_array_add(nast_array *array, short len, const char *data) +{ + const int GRANULARITY = 10; + + if (array->nitems % GRANULARITY == 0) { + nast_string_t **tmp; + tmp = realloc(array->items, sizeof(char *) * + (GRANULARITY + array->nitems)); + if (tmp == NULL) + return -1; + array->items = tmp; + } + array->nitems++; + + array->items[array->nitems-1] = nast_string_new(len, data); + if (array->items[array->nitems-1] == NULL) + return -1; + + return 0; +} + +void +nast_array_delete(nast_array *array) +{ + nast_free_result(array); +} + +static nast_response * +response_new() +{ + nast_response *tmp; + + tmp = malloc(sizeof(nast_response)); + if (tmp == NULL) + return NULL; + + tmp->buffer = NULL; + tmp->bufflen = 0; + tmp->errcode = NAST_OK; + tmp->errmsg = NULL; + tmp->reqid = -1; + + return tmp; +} + +static nast_response * +getmyresponse(nasth *s, unsigned short reqid) +{ + if (s->nthreads < reqid) + return NULL; + + return s->responses[reqid-1]; +} + +static void +nast_set_error(nasth *s, unsigned short reqid, errcodes code) +{ + nast_response *ar; + + ar = getmyresponse(s, reqid); + if (ar == NULL) + return; + + ar->errcode = code; +} + +static int +grow_responses(nasth *s, unsigned short maxitems) +{ + nast_response **tmp_resp; + int i; + + if (s->nthreads >= maxitems) + return 0; + + tmp_resp = realloc(s->responses, maxitems * sizeof(nast_response *)); + if (tmp_resp == NULL) + return -1; + + s->responses = tmp_resp; + for (i = s->nthreads; i < maxitems; i++) { + s->responses[i] = response_new(); + if (s->responses[i] == NULL) + return -1; + } + + s->nthreads = maxitems; + return 0; +} + +static nast_array * +build_result(nasth *s, const char *buff, short bufflen) +{ + nast_array *aa; + const char *s_p, *e_p; + short l; + + aa = nast_array_new(); + if (aa == NULL) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return NULL; + } + + /* Parse the buff into an array. */ + l = 0; + aa->nitems = 0; + aa->items = NULL; + s_p = buff+l; + for (e_p = s_p; e_p <= buff+bufflen; e_p++) { + if (e_p == buff+bufflen || *e_p == NASTSEP) { + if (nast_array_add(aa, e_p - s_p, s_p) == -1) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return NULL; + } + s_p = e_p + 1; + } + } + + return aa; +} + +static int +addresponse(nasth *s, unsigned short reqid, char *buffer, short len) +{ + nast_response *ar; + + switch (buffer[0]) { + case NASTOK: + nast_set_error(s, reqid, NAST_OK); + break; + case NASTERR: + nast_set_error(s, reqid, NAST_SERVER_ERR); + break; + default: + nast_set_error(s, reqid, NAST_UNKNOWN_RESPONSE); + } + + ar = getmyresponse(s, reqid); + if (ar == NULL) { + /* + * Somehow we got a response for something we didn't + * request. + */ + return -1; + } + + ar->reqid = reqid; + ar->buffer = malloc(len-1); + if (ar->buffer == NULL) { + nast_set_error(s, reqid, NAST_NOMEM); + return -1; + } + memcpy(ar->buffer, buffer+1, len-1); + ar->bufflen = len-1; + return 0; +} + +static void +delresponse(nasth *s, unsigned short reqid) +{ + nast_response *ar; + + ar = getmyresponse(s, reqid); + if (ar == NULL) + return; + + ar->reqid = -1; + if (ar->buffer) + free(ar->buffer); + ar->bufflen = 0; +} + +static int +checkresponse(nasth *s, unsigned short reqid) +{ + nast_response *ar; + + if (reqid > s->nthreads) + return -1; + + ar = getmyresponse(s, reqid); + if (ar == NULL || (short)ar->reqid == -1) + return -1; + + return 0; +} + +static int +sendcmd(nasth *s, const char *buff, short len) +{ + ssize_t wrote; + + /* Make sure there's room in the response array. */ + if (grow_responses(s, thread_id()) == -1) { + /* + * XXX: This is a fatal error. + * Find some better way to handle this. + */ + exit(1); + } + + /* If we're sending a command, make sure we get rid of old data. */ + delresponse(s, thread_id()); + + /* Send the command. */ + wrote = 0; + while (wrote < len) { + ssize_t rc; + + rc = write(s->socket, buff + wrote, len - wrote); + if (rc == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + nast_set_error(s, thread_id(), NAST_SERVER_GONE); + return -1; + } + wrote += rc; + } + + /* Check status. */ + return 0; +} + +static int +getresponse(nasth *s) +{ + char buffer[1024]; + nast_response *ar; + int ntries, rc; + unsigned short tid; + short nbytes; + + ntries = 0; + tid = thread_id(); +reread: + _nast_mutex_lock(s->lock); + + /* + * See if we already have the response from another thread which + * may have found it first. + */ + rc = checkresponse(s, tid); + if (rc == 0) { + _nast_mutex_unlock(s->lock); + } else { + /* Not in the already read stuff, check the network. */ + char *p; + short bufflen; + unsigned short reqid; + fd_set readfds; + struct timeval timeout; + + FD_ZERO(&readfds); + FD_SET(s->socket, &readfds); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + switch(select(s->socket+1, &readfds, NULL, NULL, &timeout)) { + case -1: + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + case 0: + /* Timeout expired. */ + _nast_mutex_unlock(s->lock); + if (ntries++ < 50) + goto reread; + nast_set_error(s, tid, NAST_TIMEDOUT); + return -1; + } + nbytes = recv(s->socket, buffer, sizeof(buffer), 0); + if (nbytes == -1) { + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + } else if (nbytes == 0) { + /* No response from server. That's bad. Terminate. */ + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + } else if (nbytes < + sizeof(bufflen) + sizeof(reqid) + sizeof(char)) { + /* Response is too short. */ + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_UNKNOWN_RESPONSE); + return -1; + } + + for (p = buffer; p < buffer+nbytes; p += bufflen) { + int l; + + memcpy(&bufflen, p, sizeof(bufflen)); + bufflen = ntohs(bufflen); + l = sizeof(bufflen); + + /* Sanity check, just in case data gets munged. */ + if (bufflen <= 0 || bufflen > nbytes) { + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_UNKNOWN_RESPONSE); + return -1; + } + + memcpy(&reqid, p+l, sizeof(reqid)); + reqid = ntohs(reqid); + l += sizeof(reqid); + + /* Save this response on the response array. */ + addresponse(s, reqid, p+l, bufflen-l); + } + /* Check the response array to see if we got our response. */ + _nast_mutex_unlock(s->lock); + goto reread; + } + + ar = getmyresponse(s, tid); + if (ar->errcode == NAST_OK) + return 0; + else + return -1; +} + +nasth * +nast_sphincter_new(const char *sock_path) +{ + nasth *tmp_h; + struct sockaddr_un sunix; + int rc; + + tmp_h = malloc(sizeof(nasth)); + if (tmp_h == NULL) { + fprintf(stderr, + "ERROR: Couldn't make space for sphincter: %s.\n", + strerror(errno)); + return NULL; + } + + tmp_h->nthreads = 0; + tmp_h->responses = NULL; + + tmp_h->lock = malloc(sizeof(_nast_mutex_t)); + if (tmp_h->lock == NULL) { + fprintf(stderr, + "ERROR: Couldn't create NAST lock: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + rc = _nast_mutex_new(tmp_h->lock); + if (rc) { + fprintf(stderr, + "ERROR: Couldn't initialise NAST lock: %s.\n", + strerror(rc)); + nast_sphincter_close(tmp_h); + return NULL; + } + + tmp_h->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (tmp_h->socket == -1) { + fprintf(stderr, + "ERROR: Couldn't initialise socket: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + + memset(&sunix, 0, sizeof(sunix)); + if (sock_path == NULL) + snprintf(sunix.sun_path, sizeof(sunix.sun_path), NASTHOLE); + else + strncpy(sunix.sun_path, sock_path, sizeof(sunix.sun_path)); + sunix.sun_family = AF_UNIX; + + if (connect(tmp_h->socket, (struct sockaddr *)&sunix, + sizeof(sunix)) == -1) { + fprintf(stderr, + "ERROR: Couldn't connect to server: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + return tmp_h; +} + +void +nast_sphincter_close(nasth *s) +{ + int i; + + if (s == NULL) + return; + + s->nthreads = 0; + + if (s->lock != NULL) { + _nast_mutex_delete(s->lock); + free(s->lock); + s->lock = NULL; + } + + if (s->socket != -1) { + close(s->socket); + s->socket = -1; + } + + if (s->responses != NULL) { + for (i = 0; i < s->nthreads; i++) { + if (s->responses[i]->buffer != NULL) + free(s->responses[i]->buffer); + free(s->responses[i]); + s->responses[i] = NULL; + } + free(s->responses); + s->responses = NULL; + } + + free(s); +} + +nast_array * +nast_get_result(nasth *s) +{ + nast_response *ar; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return NULL; + + return build_result(s, ar->buffer, ar->bufflen); +} + +void +nast_free_result(nast_array *aa) +{ + int i; + + if (aa->items) { + for (i = 0; i < aa->nitems; i++) + nast_string_delete(aa->items[i]); + free(aa->items); + aa->items = NULL; + } + aa->nitems = 0; + free(aa); +} + +static int +add_reqid(char *buffer) +{ + unsigned short tid; + + tid = thread_id(); + memcpy(buffer, &htons(tid), sizeof(tid)); + + return sizeof(tid); +} + +int +nast_options_get(nasth *s, nast_options *opts) +{ + nast_array *aa; + char buffer[512]; + short bufflen, i; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get options: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTOPTGET); + bufflen += 2 * sizeof(char); + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + if (getresponse(s) == -1) + return -1; + + /* Copy out results and free them. */ + aa = nast_get_result(s); + + if (aa->nitems != 1) { + nast_set_error(s, thread_id(), NAST_UNKNOWN_RESPONSE); + return -1; + } + + if (sizeof(buffer) < aa->items[0]->strlen) + bufflen = sizeof(buffer); + else + bufflen = aa->items[0]->strlen; + memcpy(buffer, aa->items[0]->strdata, bufflen); + nast_free_result(aa); + + /* Parse return into options. */ + for (i = 0; i < bufflen; i+=2) { + switch (buffer[i]) { + case OPTQCACHE: + if (buffer[i+1] == OPTFALSE) + opts->use_qcache = NASTFALSE; + else + opts->use_qcache = NASTTRUE; + break; + case OPTLOCALDB: + if (buffer[i+1] == OPTFALSE) + opts->use_localdb = NASTFALSE; + else + opts->use_localdb = NASTTRUE; + break; + case OPTFALLASYNC: + if (buffer[i+1] == OPTFALSE) + opts->fallthrough_async = NASTFALSE; + else + opts->fallthrough_async = NASTTRUE; + break; + case OPTALWAYSFALL: + if (buffer[i+1] == OPTFALSE) + opts->always_fallthrough = NASTFALSE; + else + opts->always_fallthrough = NASTTRUE; + break; + case OPTFAILONCE: + if (buffer[i+1] == OPTFALSE) + opts->fail_once = NASTFALSE; + else + opts->fail_once = NASTTRUE; + break; + case OPTNOFALLTHROUGH: + if (buffer[i+1] == OPTFALSE) + opts->no_fallthrough = NASTFALSE; + else + opts->no_fallthrough = NASTTRUE; + break; + default: + nast_set_error(s, thread_id(), NAST_UNKNOWN_OPT); + return -1; + } + } + + return 0; +} + +int +nast_options_set(nasth *s, nast_options *opts) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't set options: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTOPTSET); + bufflen += 2*sizeof(char); + + buffer[bufflen] = OPTQCACHE; + if (opts->use_qcache) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTLOCALDB; + if (opts->use_localdb) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTFALLASYNC; + if (opts->fallthrough_async) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTALWAYSFALL; + if (opts->always_fallthrough) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTFAILONCE; + if (opts->fail_once) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTNOFALLTHROUGH; + if (opts->no_fallthrough) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_add(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't add: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTADD, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_del(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't delete: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTDEL, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_get(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTGET, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +void +nast_die(nasth *s) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't kill nast: no sphincter.\n"); + return; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTDIE); + bufflen += 2 * sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return; +} + +int +nast_upd(nasth *s, const char *key, nast_array *valarray) +{ + char buffer[512]; + int i; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't update: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s%c", + NASTCMD, NASTUPD, key, NASTSEP); + bufflen += (3 + strlen(key))*sizeof(char); + + for (i = 0; i < valarray->nitems; i++) { + char *str; + short slen; + + str = valarray->items[i]->strdata; + slen = valarray->items[i]->strlen; + if (bufflen + slen > sizeof(buffer)) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return -1; + } + + memcpy(buffer+bufflen, str, slen); + bufflen += slen; + + if (i < valarray->nitems - 1) { + buffer[bufflen] = NASTSEP; + bufflen += sizeof(char); + } + } + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_stats(nasth *s) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get stats: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTSTATS); + bufflen += 2 * sizeof(char); + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +errcodes +nast_geterr(nasth *s) +{ + nast_response *ar; + + if (s == NULL) + return NAST_SERVER_GONE; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return NAST_OK; + + return ar->errcode; +} + +char * +nast_errmsg(nasth *s) +{ + nast_response *ar; + errcodes ec; + + ec = nast_geterr(s); + if (ec == NAST_SERVER_ERR) { + nast_array *aa; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + aa = build_result(s, ar->buffer, ar->bufflen); + if (aa == NULL || aa->nitems == 0) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + if (ar->errmsg != NULL) + free(ar->errmsg); + + ar->errmsg = malloc(aa->items[0]->strlen); + if (ar->errmsg == NULL) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + memcpy(ar->errmsg, aa->items[0]->strdata, aa->items[0]->strlen); + nast_free_result(aa); + + return ar->errmsg; + } + + return nast_errmsgs[ec]; +} diff --git a/client/.svn/text-base/thread.c.svn-base b/client/.svn/text-base/thread.c.svn-base new file mode 100644 index 0000000..bdd613a --- /dev/null +++ b/client/.svn/text-base/thread.c.svn-base @@ -0,0 +1,75 @@ +#include "conf.h" +#include "thread.h" + +#include + +#ifdef THREADSAFECLIENT +#include +#endif + +RCSID("$Id: thread.c,v 1.6 2000/09/13 20:21:30 shmit Exp $"); + +#ifdef THREADSAFECLIENT +short +thread_id() +{ + short i; + + i = (pthread_self() & 0xff) | (getpid() << 8); + return i; +} + +int +_nast_mutex_new(_nast_mutex_t *lock) +{ + return pthread_mutex_init(lock, NULL); +} + +void +_nast_mutex_delete(_nast_mutex_t *lock) +{ + (void)pthread_mutex_destroy(lock); +} + +int +_nast_mutex_lock(_nast_mutex_t *lock) +{ + return pthread_mutex_lock(lock); +} + +int +_nast_mutex_unlock(_nast_mutex_t *lock) +{ + return pthread_mutex_unlock(lock); +} +#else /* THREADSAFECLIENT */ +short +thread_id() +{ + return getpid(); +} + +int +_nast_mutex_new(_nast_mutex_t *lock) +{ + return 0; +} + +void +_nast_mutex_delete(_nast_mutex_t *lock) +{ + return; +} + +int +_nast_mutex_lock(_nast_mutex_t *lock) +{ + return 0; +} + +int +_nast_mutex_unlock(_nast_mutex_t *lock) +{ + return 0; +} +#endif /* THREADSAFECLIENT */ diff --git a/client/.svn/text-base/thread.h.svn-base b/client/.svn/text-base/thread.h.svn-base new file mode 100644 index 0000000..171fde1 --- /dev/null +++ b/client/.svn/text-base/thread.h.svn-base @@ -0,0 +1,19 @@ +/* $Id: thread.h,v 1.5 2000/09/13 20:21:30 shmit Exp $ */ + +#ifndef THREAD_H +# define THREAD_H + +#ifdef THREADSAFECLIENT +#include + +typedef pthread_mutex_t _nast_mutex_t; +#else +typedef int _nast_mutex_t; +#endif + +short thread_id(); +int _nast_mutex_new(_nast_mutex_t *lock); +void _nast_mutex_delete(_nast_mutex_t *lock); +int _nast_mutex_lock(_nast_mutex_t *lock); +int _nast_mutex_unlock(_nast_mutex_t *lock); +#endif diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..e92feed --- /dev/null +++ b/client/Makefile @@ -0,0 +1,26 @@ +# $Id: Makefile,v 1.10 2001/01/19 02:54:37 shmit Exp $ + +LIBOBJS= nastapi.o thread.o + +all-lib: + @rm -f *.o + @make "THREADFLAGS=-UTHREADSAFECLIENT" libnast.a + @rm -f *.o + @make "THREADFLAGS=-DTHREADSAFECLIENT" libnast_r.a + +libnast.a: ${LIBOBJS} + ar r $@ ${LIBOBJS} + ranlib $@ + +libnast_r.a: ${LIBOBJS} + ar r $@ ${LIBOBJS} + ranlib $@ + +# +# Dependencies +# +nastapi.o: ../include/nastd.h ../include/nastipc.h thread.h +thread.o: thread.h + +MKDIR= ../Makefiles +include ${MKDIR}/build diff --git a/client/nastapi.c b/client/nastapi.c new file mode 100644 index 0000000..3e5a3b9 --- /dev/null +++ b/client/nastapi.c @@ -0,0 +1,885 @@ +#include "conf.h" +#include "nastd.h" +#include "nastipc.h" +#include "thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RCSID("$Id: nastapi.c,v 1.13 2001/10/29 11:17:11 shmit Exp $"); + +char *nast_errmsgs[] = { + "No errors", + "The NASTD server has gone away", + "Couldn't allocate enough memory", + "Server response is unknown", + "Connection to server timed out", + "Unknown option returned", + NULL +}; + +static nast_string_t * +nast_string_new(int slen, const char *data) +{ + nast_string_t *tmp; + + tmp = malloc(sizeof(nast_string_t)); + if (tmp == NULL) + return NULL; + + tmp->strdata = malloc((slen+1) * sizeof(char *)); + if (tmp == NULL) + return NULL; + memcpy(tmp->strdata, data, slen); + tmp->strdata[slen] = '\0'; + tmp->strlen = slen; + + return tmp; +} + +static void +nast_string_delete(nast_string_t *string) +{ + string->strlen = 0; + free(string->strdata); + string->strdata = NULL; + free(string); +} + +nast_array * +nast_array_new() +{ + nast_array *aa; + + aa = malloc(sizeof(nast_array)); + if (aa == NULL) + return NULL; + + aa->nitems = 0; + aa->items = NULL; + return aa; +} + +int +nast_array_add(nast_array *array, short len, const char *data) +{ + const int GRANULARITY = 10; + + if (array->nitems % GRANULARITY == 0) { + nast_string_t **tmp; + tmp = realloc(array->items, sizeof(char *) * + (GRANULARITY + array->nitems)); + if (tmp == NULL) + return -1; + array->items = tmp; + } + array->nitems++; + + array->items[array->nitems-1] = nast_string_new(len, data); + if (array->items[array->nitems-1] == NULL) + return -1; + + return 0; +} + +void +nast_array_delete(nast_array *array) +{ + nast_free_result(array); +} + +static nast_response * +response_new() +{ + nast_response *tmp; + + tmp = malloc(sizeof(nast_response)); + if (tmp == NULL) + return NULL; + + tmp->buffer = NULL; + tmp->bufflen = 0; + tmp->errcode = NAST_OK; + tmp->errmsg = NULL; + tmp->reqid = -1; + + return tmp; +} + +static nast_response * +getmyresponse(nasth *s, unsigned short reqid) +{ + if (s->nthreads < reqid) + return NULL; + + return s->responses[reqid-1]; +} + +static void +nast_set_error(nasth *s, unsigned short reqid, errcodes code) +{ + nast_response *ar; + + ar = getmyresponse(s, reqid); + if (ar == NULL) + return; + + ar->errcode = code; +} + +static int +grow_responses(nasth *s, unsigned short maxitems) +{ + nast_response **tmp_resp; + int i; + + if (s->nthreads >= maxitems) + return 0; + + tmp_resp = realloc(s->responses, maxitems * sizeof(nast_response *)); + if (tmp_resp == NULL) + return -1; + + s->responses = tmp_resp; + for (i = s->nthreads; i < maxitems; i++) { + s->responses[i] = response_new(); + if (s->responses[i] == NULL) + return -1; + } + + s->nthreads = maxitems; + return 0; +} + +static nast_array * +build_result(nasth *s, const char *buff, short bufflen) +{ + nast_array *aa; + const char *s_p, *e_p; + short l; + + aa = nast_array_new(); + if (aa == NULL) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return NULL; + } + + /* Parse the buff into an array. */ + l = 0; + aa->nitems = 0; + aa->items = NULL; + s_p = buff+l; + for (e_p = s_p; e_p <= buff+bufflen; e_p++) { + if (e_p == buff+bufflen || *e_p == NASTSEP) { + if (nast_array_add(aa, e_p - s_p, s_p) == -1) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return NULL; + } + s_p = e_p + 1; + } + } + + return aa; +} + +static int +addresponse(nasth *s, unsigned short reqid, char *buffer, short len) +{ + nast_response *ar; + + switch (buffer[0]) { + case NASTOK: + nast_set_error(s, reqid, NAST_OK); + break; + case NASTERR: + nast_set_error(s, reqid, NAST_SERVER_ERR); + break; + default: + nast_set_error(s, reqid, NAST_UNKNOWN_RESPONSE); + } + + ar = getmyresponse(s, reqid); + if (ar == NULL) { + /* + * Somehow we got a response for something we didn't + * request. + */ + return -1; + } + + ar->reqid = reqid; + ar->buffer = malloc(len-1); + if (ar->buffer == NULL) { + nast_set_error(s, reqid, NAST_NOMEM); + return -1; + } + memcpy(ar->buffer, buffer+1, len-1); + ar->bufflen = len-1; + return 0; +} + +static void +delresponse(nasth *s, unsigned short reqid) +{ + nast_response *ar; + + ar = getmyresponse(s, reqid); + if (ar == NULL) + return; + + ar->reqid = -1; + if (ar->buffer) + free(ar->buffer); + ar->bufflen = 0; +} + +static int +checkresponse(nasth *s, unsigned short reqid) +{ + nast_response *ar; + + if (reqid > s->nthreads) + return -1; + + ar = getmyresponse(s, reqid); + if (ar == NULL || (short)ar->reqid == -1) + return -1; + + return 0; +} + +static int +sendcmd(nasth *s, const char *buff, short len) +{ + ssize_t wrote; + + /* Make sure there's room in the response array. */ + if (grow_responses(s, thread_id()) == -1) { + /* + * XXX: This is a fatal error. + * Find some better way to handle this. + */ + exit(1); + } + + /* If we're sending a command, make sure we get rid of old data. */ + delresponse(s, thread_id()); + + /* Send the command. */ + wrote = 0; + while (wrote < len) { + ssize_t rc; + + rc = write(s->socket, buff + wrote, len - wrote); + if (rc == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + nast_set_error(s, thread_id(), NAST_SERVER_GONE); + return -1; + } + wrote += rc; + } + + /* Check status. */ + return 0; +} + +static int +getresponse(nasth *s) +{ + char buffer[1024]; + nast_response *ar; + int ntries, rc; + unsigned short tid; + short nbytes; + + ntries = 0; + tid = thread_id(); +reread: + _nast_mutex_lock(s->lock); + + /* + * See if we already have the response from another thread which + * may have found it first. + */ + rc = checkresponse(s, tid); + if (rc == 0) { + _nast_mutex_unlock(s->lock); + } else { + /* Not in the already read stuff, check the network. */ + char *p; + short bufflen; + unsigned short reqid; + fd_set readfds; + struct timeval timeout; + + FD_ZERO(&readfds); + FD_SET(s->socket, &readfds); + timeout.tv_sec = 0; + timeout.tv_usec = 10000; + switch(select(s->socket+1, &readfds, NULL, NULL, &timeout)) { + case -1: + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + case 0: + /* Timeout expired. */ + _nast_mutex_unlock(s->lock); + if (ntries++ < 50) + goto reread; + nast_set_error(s, tid, NAST_TIMEDOUT); + return -1; + } + nbytes = recv(s->socket, buffer, sizeof(buffer), 0); + if (nbytes == -1) { + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + } else if (nbytes == 0) { + /* No response from server. That's bad. Terminate. */ + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_SERVER_GONE); + return -1; + } else if (nbytes < + sizeof(bufflen) + sizeof(reqid) + sizeof(char)) { + /* Response is too short. */ + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_UNKNOWN_RESPONSE); + return -1; + } + + for (p = buffer; p < buffer+nbytes; p += bufflen) { + int l; + + memcpy(&bufflen, p, sizeof(bufflen)); + bufflen = ntohs(bufflen); + l = sizeof(bufflen); + + /* Sanity check, just in case data gets munged. */ + if (bufflen <= 0 || bufflen > nbytes) { + _nast_mutex_unlock(s->lock); + nast_set_error(s, tid, NAST_UNKNOWN_RESPONSE); + return -1; + } + + memcpy(&reqid, p+l, sizeof(reqid)); + reqid = ntohs(reqid); + l += sizeof(reqid); + + /* Save this response on the response array. */ + addresponse(s, reqid, p+l, bufflen-l); + } + /* Check the response array to see if we got our response. */ + _nast_mutex_unlock(s->lock); + goto reread; + } + + ar = getmyresponse(s, tid); + if (ar->errcode == NAST_OK) + return 0; + else + return -1; +} + +nasth * +nast_sphincter_new(const char *sock_path) +{ + nasth *tmp_h; + struct sockaddr_un sunix; + int rc; + + tmp_h = malloc(sizeof(nasth)); + if (tmp_h == NULL) { + fprintf(stderr, + "ERROR: Couldn't make space for sphincter: %s.\n", + strerror(errno)); + return NULL; + } + + tmp_h->nthreads = 0; + tmp_h->responses = NULL; + + tmp_h->lock = malloc(sizeof(_nast_mutex_t)); + if (tmp_h->lock == NULL) { + fprintf(stderr, + "ERROR: Couldn't create NAST lock: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + rc = _nast_mutex_new(tmp_h->lock); + if (rc) { + fprintf(stderr, + "ERROR: Couldn't initialise NAST lock: %s.\n", + strerror(rc)); + nast_sphincter_close(tmp_h); + return NULL; + } + + tmp_h->socket = socket(AF_UNIX, SOCK_STREAM, 0); + if (tmp_h->socket == -1) { + fprintf(stderr, + "ERROR: Couldn't initialise socket: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + + memset(&sunix, 0, sizeof(sunix)); + if (sock_path == NULL) + snprintf(sunix.sun_path, sizeof(sunix.sun_path), NASTHOLE); + else + strncpy(sunix.sun_path, sock_path, sizeof(sunix.sun_path)); + sunix.sun_family = AF_UNIX; + + if (connect(tmp_h->socket, (struct sockaddr *)&sunix, + sizeof(sunix)) == -1) { + fprintf(stderr, + "ERROR: Couldn't connect to server: %s.\n", + strerror(errno)); + nast_sphincter_close(tmp_h); + return NULL; + } + return tmp_h; +} + +void +nast_sphincter_close(nasth *s) +{ + int i; + + if (s == NULL) + return; + + s->nthreads = 0; + + if (s->lock != NULL) { + _nast_mutex_delete(s->lock); + free(s->lock); + s->lock = NULL; + } + + if (s->socket != -1) { + close(s->socket); + s->socket = -1; + } + + if (s->responses != NULL) { + for (i = 0; i < s->nthreads; i++) { + if (s->responses[i]->buffer != NULL) + free(s->responses[i]->buffer); + free(s->responses[i]); + s->responses[i] = NULL; + } + free(s->responses); + s->responses = NULL; + } + + free(s); +} + +nast_array * +nast_get_result(nasth *s) +{ + nast_response *ar; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return NULL; + + return build_result(s, ar->buffer, ar->bufflen); +} + +void +nast_free_result(nast_array *aa) +{ + int i; + + if (aa->items) { + for (i = 0; i < aa->nitems; i++) + nast_string_delete(aa->items[i]); + free(aa->items); + aa->items = NULL; + } + aa->nitems = 0; + free(aa); +} + +static int +add_reqid(char *buffer) +{ + unsigned short tid; + + tid = thread_id(); + memcpy(buffer, &htons(tid), sizeof(tid)); + + return sizeof(tid); +} + +int +nast_options_get(nasth *s, nast_options *opts) +{ + nast_array *aa; + char buffer[512]; + short bufflen, i; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get options: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTOPTGET); + bufflen += 2 * sizeof(char); + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + if (getresponse(s) == -1) + return -1; + + /* Copy out results and free them. */ + aa = nast_get_result(s); + + if (aa->nitems != 1) { + nast_set_error(s, thread_id(), NAST_UNKNOWN_RESPONSE); + return -1; + } + + if (sizeof(buffer) < aa->items[0]->strlen) + bufflen = sizeof(buffer); + else + bufflen = aa->items[0]->strlen; + memcpy(buffer, aa->items[0]->strdata, bufflen); + nast_free_result(aa); + + /* Parse return into options. */ + for (i = 0; i < bufflen; i+=2) { + switch (buffer[i]) { + case OPTQCACHE: + if (buffer[i+1] == OPTFALSE) + opts->use_qcache = NASTFALSE; + else + opts->use_qcache = NASTTRUE; + break; + case OPTLOCALDB: + if (buffer[i+1] == OPTFALSE) + opts->use_localdb = NASTFALSE; + else + opts->use_localdb = NASTTRUE; + break; + case OPTFALLASYNC: + if (buffer[i+1] == OPTFALSE) + opts->fallthrough_async = NASTFALSE; + else + opts->fallthrough_async = NASTTRUE; + break; + case OPTALWAYSFALL: + if (buffer[i+1] == OPTFALSE) + opts->always_fallthrough = NASTFALSE; + else + opts->always_fallthrough = NASTTRUE; + break; + case OPTFAILONCE: + if (buffer[i+1] == OPTFALSE) + opts->fail_once = NASTFALSE; + else + opts->fail_once = NASTTRUE; + break; + case OPTNOFALLTHROUGH: + if (buffer[i+1] == OPTFALSE) + opts->no_fallthrough = NASTFALSE; + else + opts->no_fallthrough = NASTTRUE; + break; + default: + nast_set_error(s, thread_id(), NAST_UNKNOWN_OPT); + return -1; + } + } + + return 0; +} + +int +nast_options_set(nasth *s, nast_options *opts) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't set options: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTOPTSET); + bufflen += 2*sizeof(char); + + buffer[bufflen] = OPTQCACHE; + if (opts->use_qcache) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTLOCALDB; + if (opts->use_localdb) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTFALLASYNC; + if (opts->fallthrough_async) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTALWAYSFALL; + if (opts->always_fallthrough) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTFAILONCE; + if (opts->fail_once) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + buffer[bufflen] = OPTNOFALLTHROUGH; + if (opts->no_fallthrough) + buffer[bufflen+1] = OPTTRUE; + else + buffer[bufflen+1] = OPTFALSE; + bufflen += 2; + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_add(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't add: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTADD, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_del(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't delete: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTDEL, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_get(nasth *s, const char *query) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s", + NASTCMD, NASTGET, query); + bufflen += (2 + strlen(query))*sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +void +nast_die(nasth *s) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't kill nast: no sphincter.\n"); + return; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTDIE); + bufflen += 2 * sizeof(char); + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return; +} + +int +nast_upd(nasth *s, const char *key, nast_array *valarray) +{ + char buffer[512]; + int i; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't update: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c%s%c", + NASTCMD, NASTUPD, key, NASTSEP); + bufflen += (3 + strlen(key))*sizeof(char); + + for (i = 0; i < valarray->nitems; i++) { + char *str; + short slen; + + str = valarray->items[i]->strdata; + slen = valarray->items[i]->strlen; + if (bufflen + slen > sizeof(buffer)) { + nast_set_error(s, thread_id(), NAST_NOMEM); + return -1; + } + + memcpy(buffer+bufflen, str, slen); + bufflen += slen; + + if (i < valarray->nitems - 1) { + buffer[bufflen] = NASTSEP; + bufflen += sizeof(char); + } + } + + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +int +nast_stats(nasth *s) +{ + char buffer[512]; + short bufflen; + + if (s == NULL) { + fprintf(stderr, "ERROR: Can't get stats: no sphincter.\n"); + return -1; + } + + bufflen = sizeof(short); + bufflen += add_reqid(buffer+bufflen); + + snprintf(buffer+bufflen, sizeof(buffer)-bufflen, "%c%c", + NASTCMD, NASTSTATS); + bufflen += 2 * sizeof(char); + memcpy(buffer, &htons(bufflen), sizeof(short)); + sendcmd(s, buffer, bufflen); + return getresponse(s); +} + +errcodes +nast_geterr(nasth *s) +{ + nast_response *ar; + + if (s == NULL) + return NAST_SERVER_GONE; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return NAST_OK; + + return ar->errcode; +} + +char * +nast_errmsg(nasth *s) +{ + nast_response *ar; + errcodes ec; + + ec = nast_geterr(s); + if (ec == NAST_SERVER_ERR) { + nast_array *aa; + + ar = getmyresponse(s, thread_id()); + if (ar == NULL) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + aa = build_result(s, ar->buffer, ar->bufflen); + if (aa == NULL || aa->nitems == 0) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + if (ar->errmsg != NULL) + free(ar->errmsg); + + ar->errmsg = malloc(aa->items[0]->strlen); + if (ar->errmsg == NULL) + return nast_errmsgs[NAST_UNKNOWN_RESPONSE]; + + memcpy(ar->errmsg, aa->items[0]->strdata, aa->items[0]->strlen); + nast_free_result(aa); + + return ar->errmsg; + } + + return nast_errmsgs[ec]; +} diff --git a/client/thread.c b/client/thread.c new file mode 100644 index 0000000..bdd613a --- /dev/null +++ b/client/thread.c @@ -0,0 +1,75 @@ +#include "conf.h" +#include "thread.h" + +#include + +#ifdef THREADSAFECLIENT +#include +#endif + +RCSID("$Id: thread.c,v 1.6 2000/09/13 20:21:30 shmit Exp $"); + +#ifdef THREADSAFECLIENT +short +thread_id() +{ + short i; + + i = (pthread_self() & 0xff) | (getpid() << 8); + return i; +} + +int +_nast_mutex_new(_nast_mutex_t *lock) +{ + return pthread_mutex_init(lock, NULL); +} + +void +_nast_mutex_delete(_nast_mutex_t *lock) +{ + (void)pthread_mutex_destroy(lock); +} + +int +_nast_mutex_lock(_nast_mutex_t *lock) +{ + return pthread_mutex_lock(lock); +} + +int +_nast_mutex_unlock(_nast_mutex_t *lock) +{ + return pthread_mutex_unlock(lock); +} +#else /* THREADSAFECLIENT */ +short +thread_id() +{ + return getpid(); +} + +int +_nast_mutex_new(_nast_mutex_t *lock) +{ + return 0; +} + +void +_nast_mutex_delete(_nast_mutex_t *lock) +{ + return; +} + +int +_nast_mutex_lock(_nast_mutex_t *lock) +{ + return 0; +} + +int +_nast_mutex_unlock(_nast_mutex_t *lock) +{ + return 0; +} +#endif /* THREADSAFECLIENT */ diff --git a/client/thread.h b/client/thread.h new file mode 100644 index 0000000..171fde1 --- /dev/null +++ b/client/thread.h @@ -0,0 +1,19 @@ +/* $Id: thread.h,v 1.5 2000/09/13 20:21:30 shmit Exp $ */ + +#ifndef THREAD_H +# define THREAD_H + +#ifdef THREADSAFECLIENT +#include + +typedef pthread_mutex_t _nast_mutex_t; +#else +typedef int _nast_mutex_t; +#endif + +short thread_id(); +int _nast_mutex_new(_nast_mutex_t *lock); +void _nast_mutex_delete(_nast_mutex_t *lock); +int _nast_mutex_lock(_nast_mutex_t *lock); +int _nast_mutex_unlock(_nast_mutex_t *lock); +#endif -- cgit v1.2.3