From: Sebastian Harl Date: Wed, 4 Dec 2013 18:42:45 +0000 (+0100) Subject: Added initial client library implementation. X-Git-Tag: sysdb-0.1.0~333 X-Git-Url: https://git.tokkee.org/?p=sysdb.git;a=commitdiff_plain;h=7201fdaa25c85da9321591694901a5f0dfaa04a6 Added initial client library implementation. For now, this includes a network client only. --- diff --git a/src/Makefile.am b/src/Makefile.am index e4695cd..c3eb8cd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,7 +30,18 @@ pkgutilsinclude_HEADERS = \ include/utils/strbuf.h \ include/utils/unixsock.h -lib_LTLIBRARIES = libsysdb.la +pkgclientincludedir = $(pkgincludedir)/client +pkgclientinclude_HEADERS = \ + include/client/sock.h + +lib_LTLIBRARIES = libsysdbclient.la libsysdb.la + +libsysdbclient_la_SOURCES = \ + client/sock.c include/client/sock.h +libsysdbclient_la_CFLAGS = $(AM_CFLAGS) +libsysdbclient_la_CPPFLAGS = $(AM_CPPFLAGS) $(LTDLINCL) +libsysdbclient_la_LDFLAGS = -version-info 0:0:0 -pthread +libsysdbclient_la_LIBADD = $(LIBLTDL) libsysdb_la_SOURCES = \ sysdb.c include/sysdb.h \ diff --git a/src/client/sock.c b/src/client/sock.c new file mode 100644 index 0000000..ffabdc1 --- /dev/null +++ b/src/client/sock.c @@ -0,0 +1,223 @@ +/* + * SysDB - src/client/sock.c + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "client/sock.h" +#include "utils/strbuf.h" +#include "utils/proto.h" + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include +#include + +/* + * private data types + */ + +struct sdb_client { + char *address; + int fd; +}; + +/* + * private helper functions + */ + +static int +connect_unixsock(sdb_client_t *client, const char *address) +{ + struct sockaddr_un sa; + + client->fd = socket(AF_UNIX, SOCK_STREAM, /* protocol = */ 0); + if (client->fd < 0) + return -1; + + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, address, sizeof(sa.sun_path)); + sa.sun_path[sizeof(sa.sun_path) - 1] = '\0'; + + if (connect(client->fd, (struct sockaddr *)&sa, sizeof(sa))) { + sdb_client_close(client); + return -1; + } + return client->fd; +} /* connect_unixsock */ + +/* + * public API + */ + +sdb_client_t * +sdb_client_create(const char *address) +{ + sdb_client_t *client; + + if (! address) + return NULL; + + client = malloc(sizeof(*client)); + if (! client) + return NULL; + memset(client, 0, sizeof(*client)); + client->fd = -1; + + client->address = strdup(address); + if (! client->address) { + sdb_client_destroy(client); + return NULL; + } + + return client; +} /* sdb_client_create */ + +void +sdb_client_destroy(sdb_client_t *client) +{ + if (! client) + return; + + sdb_client_close(client); + + if (client->address) + free(client->address); + client->address = NULL; + + free(client); +} /* sdb_client_destroy */ + +int +sdb_client_connect(sdb_client_t *client) +{ + if ((! client) || (! client->address)) + return -1; + + if (client->fd >= 0) + return -1; + + if (!strncasecmp(client->address, "unix:", strlen("unix:"))) + connect_unixsock(client, client->address + strlen("unix:")); + else if (*client->address == '/') + connect_unixsock(client, client->address); + else + return -1; + + if (client->fd < 0) + return -1; + return 0; +} /* sdb_client_connect */ + +void +sdb_client_close(sdb_client_t *client) +{ + if (! client) + return; + + close(client->fd); + client->fd = -1; +} /* sdb_client_close */ + +ssize_t +sdb_client_send(sdb_client_t *client, + uint32_t cmd, uint32_t msg_len, const char *msg) +{ + if ((! client) || (! client->fd)) + return -1; + + return sdb_proto_send_msg(client->fd, cmd, msg_len, msg); +} /* sdb_client_send */ + +ssize_t +sdb_client_recv(sdb_client_t *client, + uint32_t *code, sdb_strbuf_t *buf) +{ + uint32_t rstatus = UINT32_MAX; + uint32_t rlen = UINT32_MAX; + + size_t total = 0; + size_t req = 2 * sizeof(uint32_t); + + size_t data_offset = sdb_strbuf_len(buf); + + if ((! client) || (! client->fd) || (! buf)) { + errno = EBADF; + return -1; + } + + if (code) + *code = UINT32_MAX; + + while (42) { + ssize_t status; + + errno = 0; + status = sdb_strbuf_read(buf, client->fd, req); + if (status < 0) { + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) + break; + return status; + } + else if (! status) /* EOF */ + break; + + total += (size_t)status; + + if (total != req) + continue; + + if (rstatus == UINT32_MAX) { + /* retrieve status and data len */ + rstatus = sdb_proto_get_int(buf, data_offset); + rlen = sdb_proto_get_int(buf, data_offset + sizeof(rstatus)); + + if (! rlen) + break; + + req = (size_t)rlen; + total = 0; + } + else /* finished reading data */ + break; + } + + if (code) + *code = rstatus; + + return (ssize_t)total; +} /* sdb_client_recv */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ + diff --git a/src/include/client/sock.h b/src/include/client/sock.h new file mode 100644 index 0000000..5980d08 --- /dev/null +++ b/src/include/client/sock.h @@ -0,0 +1,119 @@ +/* + * SysDB - src/include/client/sock.h + * Copyright (C) 2013 Sebastian 'tokkee' Harl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SDB_CLIENT_SOCK_H +#define SDB_CLIENT_SOCK_H 1 + +#include "core/object.h" +#include "core/data.h" + +#include "utils/strbuf.h" + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sdb_client; +typedef struct sdb_client sdb_client_t; + +/* + * sdb_client_create: + * Allocates and initializes a client object to connect to the specified + * address. + * + * Returns: + * - a new client object on success + * - NULL in case of an error + */ +sdb_client_t * +sdb_client_create(const char *address); + +/* + * sdb_client_destroy: + * Destroyes the client connection and deallocates the client object. + */ +void +sdb_client_destroy(sdb_client_t *client); + +/* + * sdb_client_connect: + * Connect to the client's address. + * + * Returns: + * - 0 on success + * - a negative value else + */ +int +sdb_client_connect(sdb_client_t *client); + +/* + * sdb_client_close: + * Close the client connection. + */ +void +sdb_client_close(sdb_client_t *client); + +/* + * sdb_client_send: + * Send the specified command and accompanying data to through the client + * connection. + * + * Returns: + * - 0 on success + * - a negative value else. + */ +ssize_t +sdb_client_send(sdb_client_t *client, + uint32_t cmd, uint32_t data_len, const char *data); + +/* + * sdb_client_recv: + * Receive data from the connection. All data is written to the specified + * buffer. If specified, the returned status code is written to the memory + * location pointed to by 'code'. In case of an error or an incomplete + * command, the status code is set to UINT32_MAX. + * + * Returns: + * - the number of bytes read + * - a negative value on error + */ +ssize_t +sdb_client_recv(sdb_client_t *client, + uint32_t *code, sdb_strbuf_t *buf); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ! SDB_CLIENT_SOCK_H */ + +/* vim: set tw=78 sw=4 ts=4 noexpandtab : */ +