git » nmdb » commit a02fc0c

Implement UDP in the C library.

author Alberto Bertogli
2007-06-07 05:15:45 UTC
committer Alberto Bertogli
2007-06-07 05:15:45 UTC
parent 4b89315ea2b0dd996c137fe9676c845d99565322

Implement UDP in the C library.

Also very straightforward, not much to comment. Fully tested.

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

libnmdb/Makefile +5 -2
libnmdb/internal.h +2 -0
libnmdb/libnmdb.c +9 -2
libnmdb/net-const.h +4 -0
libnmdb/nmdb.h +4 -0
libnmdb/udp.c +145 -0
libnmdb/udp.h +12 -0

diff --git a/libnmdb/Makefile b/libnmdb/Makefile
index cdd95b0..9206f10 100644
--- a/libnmdb/Makefile
+++ b/libnmdb/Makefile
@@ -1,10 +1,13 @@
 
 ENABLE_TIPC = 1
 ENABLE_TCP = 1
+ENABLE_UDP = 1
 
 CFLAGS += -std=c99 -Wall -O3
 ALL_CFLAGS = -D_XOPEN_SOURCE=500 -fPIC $(CFLAGS)
-ALL_CFLAGS += -DENABLE_TIPC=$(ENABLE_TIPC) -DENABLE_TCP=$(ENABLE_TCP)
+ALL_CFLAGS += -DENABLE_TIPC=$(ENABLE_TIPC) \
+		-DENABLE_TCP=$(ENABLE_TCP) \
+		-DENABLE_UDP=$(ENABLE_UDP)
 
 ifdef DEBUG
 ALL_CFLAGS += -g
@@ -22,7 +25,7 @@ endif
 PREFIX=/usr/local
 
 
-OBJS = libnmdb.o tcp.o tipc.o
+OBJS = libnmdb.o tcp.o tipc.o udp.o
 
 
 default: all
diff --git a/libnmdb/internal.h b/libnmdb/internal.h
index fac8d8e..4c2f93c 100644
--- a/libnmdb/internal.h
+++ b/libnmdb/internal.h
@@ -6,6 +6,7 @@
  * and TCP connections in struct nmdb_srv. */
 #define TIPC_CONN 1
 #define TCP_CONN 2
+#define UDP_CONN 3
 
 /* The ID code for requests is hardcoded for now, until asynchronous requests
  *  * are implemented. */
@@ -15,6 +16,7 @@
  * the message contents. */
 #define TIPC_MSG_OFFSET 0
 #define TCP_MSG_OFFSET 4
+#define UDP_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 e3fd173..ed6c7bb 100644
--- a/libnmdb/libnmdb.c
+++ b/libnmdb/libnmdb.c
@@ -11,6 +11,7 @@
 #include "net-const.h"
 #include "tipc.h"
 #include "tcp.h"
+#include "udp.h"
 #include "internal.h"
 
 
@@ -38,8 +39,8 @@ int compare_servers(const void *s1, const void *s2)
 			return 1;
 	}
 #endif
-#if ENABLE_TCP
-	if (srv1->type == TCP_CONN) {
+#if ENABLE_TCP || ENABLE_UDP
+	if (srv1->type == TCP_CONN || srv1->type == UDP_CONN) {
 		in_addr_t a1, a2;
 		a1 = srv1->info.tcp.srvsa.sin_addr.s_addr;
 		a2 = srv2->info.tcp.srvsa.sin_addr.s_addr;
@@ -155,6 +156,8 @@ static int srv_send(struct nmdb_srv *srv,
 		return tipc_srv_send(srv, buf, bsize);
 	else if (srv->type == TCP_CONN)
 		return tcp_srv_send(srv, buf, bsize);
+	else if (srv->type == UDP_CONN)
+		return udp_srv_send(srv, buf, bsize);
 	else
 		return 0;
 }
@@ -170,6 +173,8 @@ static uint32_t get_rep(struct nmdb_srv *srv,
 		return tipc_get_rep(srv, buf, bsize, payload, psize);
 	else if (srv->type == TCP_CONN)
 		return tcp_get_rep(srv, buf, bsize, payload, psize);
+	else if (srv->type == UDP_CONN)
+		return udp_get_rep(srv, buf, bsize, payload, psize);
 	else
 		return 0;
 }
@@ -183,6 +188,8 @@ static int srv_get_msg_offset(struct nmdb_srv *srv)
 		return TIPC_MSG_OFFSET;
 	else if (srv->type == TCP_CONN)
 		return TCP_MSG_OFFSET;
+	else if (srv->type == UDP_CONN)
+		return UDP_MSG_OFFSET;
 	else
 		return 0;
 }
diff --git a/libnmdb/net-const.h b/libnmdb/net-const.h
index 16871e7..bdaa29d 100644
--- a/libnmdb/net-const.h
+++ b/libnmdb/net-const.h
@@ -15,6 +15,10 @@
 #define TCP_SERVER_ADDR "0.0.0.0"
 #define TCP_SERVER_PORT 26010
 
+/* UDP default listen address and port. */
+#define UDP_SERVER_ADDR "0.0.0.0"
+#define UDP_SERVER_PORT 26010
+
 /* Protocol version, for checking in the network header. */
 #define PROTO_VER 1
 
diff --git a/libnmdb/nmdb.h b/libnmdb/nmdb.h
index 2d44b5d..ded1cd0 100644
--- a/libnmdb/nmdb.h
+++ b/libnmdb/nmdb.h
@@ -21,6 +21,10 @@ struct nmdb_srv {
 			struct sockaddr_in srvsa;
 			socklen_t srvlen;
 		} tcp;
+		struct {
+			struct sockaddr_in srvsa;
+			socklen_t srvlen;
+		} udp;
 	} info;
 };
 
diff --git a/libnmdb/udp.c b/libnmdb/udp.c
new file mode 100644
index 0000000..5ece6e8
--- /dev/null
+++ b/libnmdb/udp.c
@@ -0,0 +1,145 @@
+
+#if ENABLE_UDP
+
+#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/udp.h>	/* UDP 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_udp_server_addr(nmdb_t *db, in_addr_t *inetaddr, int port)
+{
+	int fd;
+	struct nmdb_srv *newsrv, *newarray;
+
+	fd = socket(AF_INET, SOCK_DGRAM, 0);
+	if (fd < 0)
+		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 = UDP_SERVER_PORT;
+
+	newsrv = &(db->servers[db->nservers - 1]);
+
+	newsrv->fd = fd;
+	newsrv->info.udp.srvsa.sin_family = AF_INET;
+	newsrv->info.udp.srvsa.sin_port = htons(port);
+	newsrv->info.udp.srvsa.sin_addr.s_addr = *inetaddr;
+	newsrv->info.udp.srvlen = sizeof(struct sockaddr_in);
+
+	newsrv->type = UDP_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 UDP. */
+int nmdb_add_udp_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_udp_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_udp_server_addr(db, &(ia.s_addr), port);
+}
+
+int udp_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.udp.srvsa),
+			srv->info.udp.srvlen);
+	if (rv <= 0)
+		return 0;
+	return 1;
+}
+
+/* Used internally to get and parse replies from the server. */
+uint32_t udp_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 UDP is not enabled. */
+
+#include "nmdb.h"
+
+int nmdb_add_udp_server(nmdb_t *db, int port)
+{
+	return 0;
+}
+
+int udp_srv_send(struct nmdb_srv *srv,
+		const unsigned char *buf, size_t bsize)
+{
+	return 0;
+}
+
+uint32_t udp_get_rep(struct nmdb_srv *srv,
+		unsigned char *buf, size_t bsize,
+		unsigned char **payload, size_t *psize)
+{
+	return -1;
+}
+
+#endif /* ENABLE_UDP */
+
diff --git a/libnmdb/udp.h b/libnmdb/udp.h
new file mode 100644
index 0000000..7515941
--- /dev/null
+++ b/libnmdb/udp.h
@@ -0,0 +1,12 @@
+
+#ifndef _UDP_H
+#define _UDP_H
+
+int udp_srv_send(struct nmdb_srv *srv,
+		const unsigned char *buf, size_t bsize);
+uint32_t udp_get_rep(struct nmdb_srv *srv,
+		unsigned char *buf, size_t bsize,
+		unsigned char **payload, size_t *psize);
+
+#endif
+