author | Alberto Bertogli
<albertito@gmail.com> 2007-08-26 00:05:21 UTC |
committer | Alberto Bertogli
<albertito@gmail.com> 2007-08-26 00:05:21 UTC |
parent | 696db4407f15de7b632c7a615f325238d9ebbd03 |
libnmdb/Makefile | +6 | -3 |
libnmdb/internal.h | +4 | -2 |
libnmdb/libnmdb.c | +11 | -2 |
libnmdb/net-const.h | +4 | -0 |
libnmdb/nmdb.skel.h | +4 | -2 |
libnmdb/sctp.c | +154 | -0 |
libnmdb/sctp.h | +12 | -0 |
diff --git a/libnmdb/Makefile b/libnmdb/Makefile index 46b12de..1e7c719 100644 --- a/libnmdb/Makefile +++ b/libnmdb/Makefile @@ -2,12 +2,14 @@ ENABLE_TIPC = 1 ENABLE_TCP = 1 ENABLE_UDP = 1 +ENABLE_SCTP = 1 CFLAGS += -std=c99 -pedantic -Wall -O3 ALL_CFLAGS = -D_XOPEN_SOURCE=500 -fPIC $(CFLAGS) ALL_CFLAGS += -DENABLE_TIPC=$(ENABLE_TIPC) \ -DENABLE_TCP=$(ENABLE_TCP) \ - -DENABLE_UDP=$(ENABLE_UDP) + -DENABLE_UDP=$(ENABLE_UDP) \ + -DENABLE_SCTP=$(ENABLE_SCTP) ifdef DEBUG ALL_CFLAGS += -g @@ -22,7 +24,7 @@ endif PREFIX=/usr/local -OBJS = libnmdb.o tcp.o tipc.o udp.o +OBJS = libnmdb.o tcp.o tipc.o udp.o sctp.o default: all @@ -33,8 +35,9 @@ nmdb.h: @echo "generating nmdb.h" @cat nmdb.skel.h | \ sed 's/++CONFIG_ENABLE_TIPC++/$(ENABLE_TIPC)/g' | \ + sed 's/++CONFIG_ENABLE_TCP++/$(ENABLE_TCP)/g' | \ sed 's/++CONFIG_ENABLE_UDP++/$(ENABLE_UDP)/g' | \ - sed 's/++CONFIG_ENABLE_TCP++/$(ENABLE_TCP)/g' \ + sed 's/++CONFIG_ENABLE_SCTP++/$(ENABLE_SCTP)/g' \ > nmdb.h libs: libnmdb.so libnmdb.a diff --git a/libnmdb/internal.h b/libnmdb/internal.h index 4c2f93c..ce52cee 100644 --- a/libnmdb/internal.h +++ b/libnmdb/internal.h @@ -2,11 +2,12 @@ #ifndef _INTERNAL_H #define _INTERNAL_H -/* Different connection types. Used internally to differentiate between TIPC - * and TCP connections in struct nmdb_srv. */ +/* Different connection types. Used internally to differentiate between the + * different protocols in struct nmdb_srv. */ #define TIPC_CONN 1 #define TCP_CONN 2 #define UDP_CONN 3 +#define SCTP_CONN 4 /* The ID code for requests is hardcoded for now, until asynchronous requests * * are implemented. */ @@ -17,6 +18,7 @@ #define TIPC_MSG_OFFSET 0 #define TCP_MSG_OFFSET 4 #define UDP_MSG_OFFSET 0 +#define SCTP_MSG_OFFSET 0 /* Functions used internally but shared among the different files. */ int compare_servers(const void *s1, const void *s2); diff --git a/libnmdb/libnmdb.c b/libnmdb/libnmdb.c index 61c42cd..771cd8a 100644 --- a/libnmdb/libnmdb.c +++ b/libnmdb/libnmdb.c @@ -12,6 +12,7 @@ #include "tipc.h" #include "tcp.h" #include "udp.h" +#include "sctp.h" #include "internal.h" @@ -39,8 +40,10 @@ int compare_servers(const void *s1, const void *s2) return 1; } #endif -#if ENABLE_TCP || ENABLE_UDP - if (srv1->type == TCP_CONN || srv1->type == UDP_CONN) { +#if ENABLE_TCP || ENABLE_UDP || ENABLE_SCTP + if (srv1->type == TCP_CONN + || srv1->type == UDP_CONN + || srv1->type == SCTP_CONN) { in_addr_t a1, a2; a1 = srv1->info.in.srvsa.sin_addr.s_addr; a2 = srv2->info.in.srvsa.sin_addr.s_addr; @@ -159,6 +162,8 @@ static int srv_send(struct nmdb_srv *srv, return tcp_srv_send(srv, buf, bsize); case UDP_CONN: return udp_srv_send(srv, buf, bsize); + case SCTP_CONN: + return sctp_srv_send(srv, buf, bsize); default: return 0; } @@ -178,6 +183,8 @@ static uint32_t get_rep(struct nmdb_srv *srv, return tcp_get_rep(srv, buf, bsize, payload, psize); case UDP_CONN: return udp_get_rep(srv, buf, bsize, payload, psize); + case SCTP_CONN: + return sctp_get_rep(srv, buf, bsize, payload, psize); default: return 0; } @@ -195,6 +202,8 @@ static int srv_get_msg_offset(struct nmdb_srv *srv) return TCP_MSG_OFFSET; case UDP_CONN: return UDP_MSG_OFFSET; + case SCTP_CONN: + return SCTP_MSG_OFFSET; default: return 0; } diff --git a/libnmdb/net-const.h b/libnmdb/net-const.h index bdaa29d..79d9553 100644 --- a/libnmdb/net-const.h +++ b/libnmdb/net-const.h @@ -19,6 +19,10 @@ #define UDP_SERVER_ADDR "0.0.0.0" #define UDP_SERVER_PORT 26010 +/* SCTP default listen address and port. */ +#define SCTP_SERVER_ADDR "0.0.0.0" +#define SCTP_SERVER_PORT 26010 + /* Protocol version, for checking in the network header. */ #define PROTO_VER 1 diff --git a/libnmdb/nmdb.skel.h b/libnmdb/nmdb.skel.h index 8bb5ac3..c33e5e7 100644 --- a/libnmdb/nmdb.skel.h +++ b/libnmdb/nmdb.skel.h @@ -9,6 +9,7 @@ #define _ENABLE_TIPC ++CONFIG_ENABLE_TIPC++ #define _ENABLE_TCP ++CONFIG_ENABLE_TCP++ #define _ENABLE_UDP ++CONFIG_ENABLE_UDP++ +#define _ENABLE_SCTP ++CONFIG_ENABLE_SCTP++ #include <sys/types.h> /* socket defines */ @@ -18,7 +19,7 @@ #include <linux/tipc.h> /* struct sockaddr_tipc */ #endif -#if (_ENABLE_TCP || _ENABLE_UDP) +#if (_ENABLE_TCP || _ENABLE_UDP || _ENABLE_SCTP) #include <netinet/in.h> /* struct sockaddr_in */ #endif @@ -35,7 +36,7 @@ struct nmdb_srv { } tipc; #endif -#if (_ENABLE_TCP || _ENABLE_UDP) +#if (_ENABLE_TCP || _ENABLE_UDP || _ENABLE_SCTP) struct { struct sockaddr_in srvsa; socklen_t srvlen; @@ -54,6 +55,7 @@ nmdb_t *nmdb_init(); int nmdb_add_tipc_server(nmdb_t *db, int port); int nmdb_add_tcp_server(nmdb_t *db, const char *addr, int port); int nmdb_add_udp_server(nmdb_t *db, const char *addr, int port); +int nmdb_add_sctp_server(nmdb_t *db, const char *addr, int port); int nmdb_free(nmdb_t *db); ssize_t nmdb_get(nmdb_t *db, const unsigned char *key, size_t ksize, diff --git a/libnmdb/sctp.c b/libnmdb/sctp.c new file mode 100644 index 0000000..1f1c1ab --- /dev/null +++ b/libnmdb/sctp.c @@ -0,0 +1,154 @@ + +#if ENABLE_SCTP + +#include <sys/types.h> /* socket defines */ +#include <sys/socket.h> /* socket functions */ +#include <stdlib.h> /* malloc() */ +#include <stdint.h> /* uint32_t and friends */ +#include <arpa/inet.h> /* htonls() and friends */ +#include <string.h> /* memcpy() */ +#include <unistd.h> /* close() */ + +#include <netinet/sctp.h> /* SCTP stuff */ +#include <netdb.h> /* gethostbyname() */ + +#include "nmdb.h" +#include "net-const.h" +#include "internal.h" + + +/* Used internally to really add the server once we have an IP address. */ +static int add_sctp_server_addr(nmdb_t *db, in_addr_t *inetaddr, int port) +{ + int fd, rv; + struct nmdb_srv *newsrv, *newarray; + + fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); + if (fd < 0) + return 0; + + /* Disable Nagle algorithm because we often send small + * packets. Huge gain in performance. */ + rv = 1; + if (setsockopt(fd, IPPROTO_SCTP, SCTP_NODELAY, &rv, sizeof(rv)) < 0 ) { + close(fd); + return 0; + } + + newarray = realloc(db->servers, + sizeof(struct nmdb_srv) * (db->nservers + 1)); + if (newarray == NULL) { + close(fd); + return 0; + } + + db->servers = newarray; + db->nservers++; + + if (port < 0) + port = SCTP_SERVER_PORT; + + newsrv = &(db->servers[db->nservers - 1]); + + newsrv->fd = fd; + newsrv->info.in.srvsa.sin_family = AF_INET; + newsrv->info.in.srvsa.sin_port = htons(port); + newsrv->info.in.srvsa.sin_addr.s_addr = *inetaddr; + newsrv->info.in.srvlen = sizeof(struct sockaddr_in); + + newsrv->type = SCTP_CONN; + + /* keep the list sorted by port, so we can do a reliable selection */ + qsort(db->servers, db->nservers, sizeof(struct nmdb_srv), + compare_servers); + + return 1; +} + +/* Same as nmdb_add_tcp_server() but for SCTP. */ +int nmdb_add_sctp_server(nmdb_t *db, const char *addr, int port) +{ + int rv; + struct hostent *he; + struct in_addr ia; + + /* We try to resolve and then pass it to add_sctp_server_addr(). */ + rv = inet_pton(AF_INET, addr, &ia); + if (rv <= 0) { + he = gethostbyname(addr); + if (he == NULL) + return 0; + + ia.s_addr = *( (in_addr_t *) (he->h_addr_list[0]) ); + } + + return add_sctp_server_addr(db, &(ia.s_addr), port); +} + +int sctp_srv_send(struct nmdb_srv *srv, + const unsigned char *buf, size_t bsize) +{ + ssize_t rv; + rv = sendto(srv->fd, buf, bsize, 0, + (struct sockaddr *) &(srv->info.in.srvsa), + srv->info.in.srvlen); + if (rv <= 0) + return 0; + return 1; +} + +/* Used internally to get and parse replies from the server. */ +uint32_t sctp_get_rep(struct nmdb_srv *srv, + unsigned char *buf, size_t bsize, + unsigned char **payload, size_t *psize) +{ + ssize_t rv; + uint32_t id, reply; + + rv = recv(srv->fd, buf, bsize, 0); + if (rv < 4 + 4) { + return -1; + } + + id = * (uint32_t *) buf; + id = ntohl(id); + reply = * ((uint32_t *) buf + 1); + reply = ntohl(reply); + + if (id != ID_CODE) { + return -1; + } + + if (payload != NULL) { + *payload = buf + 4 + 4; + *psize = rv - 4 - 4; + } + return reply; +} + +#else +/* Stubs to use when SCTP is not enabled. */ + +#include <stdint.h> +#include "nmdb.h" + +int nmdb_add_sctp_server(nmdb_t *db, const char *addr, int port) +{ + return 0; +} + +int sctp_srv_send(struct nmdb_srv *srv, + const unsigned char *buf, size_t bsize) +{ + return 0; +} + +uint32_t sctp_get_rep(struct nmdb_srv *srv, + unsigned char *buf, size_t bsize, + unsigned char **payload, size_t *psize) +{ + return -1; +} + +#endif /* ENABLE_SCTP */ + diff --git a/libnmdb/sctp.h b/libnmdb/sctp.h new file mode 100644 index 0000000..56b0add --- /dev/null +++ b/libnmdb/sctp.h @@ -0,0 +1,12 @@ + +#ifndef _SCTP_H +#define _SCTP_H + +int sctp_srv_send(struct nmdb_srv *srv, + const unsigned char *buf, size_t bsize); +uint32_t sctp_get_rep(struct nmdb_srv *srv, + unsigned char *buf, size_t bsize, + unsigned char **payload, size_t *psize); + +#endif +