git » nmdb » commit 28cb009

Implement SCTP on libnmdb.

author Alberto Bertogli
2007-08-26 00:05:21 UTC
committer Alberto Bertogli
2007-08-26 00:05:21 UTC
parent 696db4407f15de7b632c7a615f325238d9ebbd03

Implement SCTP on libnmdb.

Signed-off-by: Alberto Bertogli <albertito@gmail.com>

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
+