nbeng

a non-blocking client/server engine
git clone git://git.2f30.org/nbeng
Log | Files | Refs | README

commit 5d911a560f6c8664dd93556b222f3b95bb36216d
parent 90e042484d278970be026777d54b81661efd3938
Author: dsp <dsp@2f30.org>
Date:   Tue, 19 Jun 2012 01:14:41 +0300

changed the way nbeng works , now utilizing only one socket.
removed assl dependencies, soon we will provide our custom ssl wrapper.
removed tcp code, just created placeholder.
general cleanup and comments.

Diffstat:
MMakefile | 7+++----
MREADME | 15+++++++++++----
Mnbeng.c | 197+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Assl/create_ca | 5+++++
Assl/create_client | 5+++++
Assl/create_server | 5+++++
Assl/sign_client | 2++
Assl/sign_server | 2++
8 files changed, 156 insertions(+), 82 deletions(-)

diff --git a/Makefile b/Makefile @@ -8,9 +8,8 @@ CC = gcc INCS = -I/usr/local/include LIBS = -L/usr/local/lib -CFLAGS += -Wall -Wextra -Wunused -DVERSION=\"${VER}\" ${INCS} -#add assl -#LDFLAGS += -lassl ${LIBS} +CFLAGS += -Wall -Wextra -Wunused -g -DVERSION=\"${VER}\" ${INCS} +LDFLAGS += ${LIBS} $(BIN): ${OBJ} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${OBJ} @@ -19,6 +18,6 @@ $(BIN): ${OBJ} ${CC} ${CFLAGS} -c -o $@ $< clean: - rm -rf ${BIN} ${OBJ} + rm -rf ${BIN} ${OBJ} *.core all: nbeng diff --git a/README b/README @@ -1,8 +1,15 @@ -NonBlockingENGine by <dsp@2f30.org> +NonBlockingENGine by <dsp@2f30.org>,<lostd@2f30.org> A nonblocking client/server engine for future use on sscall. (https://github.com/quantumdream/sscall.git) -Will support SSL connections via ASSL. +Will support SSL connections via a custom SSL wrapper. +For SSL you have to create and sign certificates and keys +by running the scripts in the ssl/ directory. + +cd ssl/; sh create_ca; sh create_client; sh create_server; +sh sign_client; sh sign_server; + to test get a netcat proccess listening for udp on a port: -nc -ul 127.0.0.1 8888 -./nbeng 127.0.0.1 8888 1234 +(BOX1) nc -ul 8888 (see the data that BOX2 sends) +(BOX2) ./nbeng BOX1 8888 (send data to BOX1 and recv from it) +(BOX1) nc -u BOX2 (send data to BOX2) diff --git a/nbeng.c b/nbeng.c @@ -1,3 +1,12 @@ +/* + * NonBlocking network engine for tcp/udp/ssl connections + * The design uses the same socket for sending and receiving + * data. The relevant data are stored in a connection context + * which is passed around the funcs for dealing with it. + * Also provided are 2 sample reading and writing functions. + * CopyLeft: (DsP <dsp@2f30.org>, lostd <lostd@2f30.org>) + * cheers go to photorec for helping recover this file :) + */ #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -11,95 +20,116 @@ #include <sys/time.h> #include <fcntl.h> #include <err.h> +#include <errno.h> -/* SSL flag */ -int fssl = 0; +/* TCP flag */ +unsigned int ftcp = 0; + +/* flag to know when to quit the prog */ +unsigned int quitflag=0; /* connection context */ typedef struct concontxt_t { - int clifd; /* client fd */ - int srvfd; /* server fd */ - struct addrinfo *clinfo; - struct addrinfo *srvinfo; + int confd; /* net connection fd */ + struct addrinfo *clinfo; /* info on where we connect */ + struct addrinfo *srvinfo; /* info for the local part */ } concontxt; static void usage(const char *s) { fprintf(stderr, "usage: %s [OPTIONS] " - "<remote-addr> <remote-port> <local-port>\n", s); - fprintf(stderr, " -s\tSSL on\n"); + "<remote-addr> <remote-port>\n", s); + fprintf(stderr, " -t\ttcp session\n"); fprintf(stderr, " -h\tThis help screen\n"); } -/* connect to in port port and store the fds in the context */ static void -connectit(concontxt *c, char *to, char *port) +set_nonblocking(int fd) { - struct addrinfo cli_hints, *cli_servinfo, *p0; - int rv, cli_sockfd; - if ((c == NULL) || (to == NULL) || (port == NULL)) - errx(1, "conectit was passed a null arg"); - memset(&cli_hints, 0, sizeof(cli_hints)); - cli_hints.ai_family = AF_INET; - cli_hints.ai_socktype = SOCK_DGRAM; - rv = getaddrinfo(to, port, &cli_hints, &cli_servinfo); - if (rv) - errx(1, "getaddrinfo: %s", gai_strerror(rv)); + int opts; + opts = fcntl(fd, F_GETFL); + if (opts < 0) + err(1, "fcntl"); + opts = (opts | O_NONBLOCK); + if (fcntl(fd, F_SETFL, opts) < 0) + err(1, "fcntl"); +} - for (p0 = cli_servinfo; p0; p0 = p0->ai_next) { - cli_sockfd = socket(p0->ai_family, p0->ai_socktype, - p0->ai_protocol); - if (cli_sockfd < 0) - continue; - break; - } - if (!p0) - errx(1, "failed to bind socket"); - /* all was ok, so we register the socket to the context */ - c->clifd = cli_sockfd; - c->clinfo = cli_servinfo; +static void +set_blocking(int fd) +{ + int opts; + opts = fcntl(fd, F_GETFL); + if (opts < 0) + err(1, "fcntl"); + opts &= (~O_NONBLOCK); + if (fcntl(fd, F_SETFL, opts) < 0) + err(1, "fcntl"); } +/* + * This is the main function that prepares a socket for + * a) connection to the other endpoint. + * b) being able to receive data. + * when it is ready it sets the fields in the context. + * XXX: add a flag in the parameter list for type (tcp/udp/ssl) + */ static void -serveit(concontxt *c, char *port) -{ - struct addrinfo srv_hints, *srv_servinfo, *p0; - int rv, srv_sockfd,optval; +prepare_socket(concontxt *c, char *to, char *port) +{ + struct addrinfo cli_hints, *cli_servinfo, srv_hints, *srv_servinfo, *p0; + int rv, cli_sockfd,optval=1; + if ((c == NULL) || (to == NULL) || (port == NULL)) + errx(1, "prepare_socket was passed a null arg"); + memset(&cli_hints, 0, sizeof(cli_hints)); memset(&srv_hints, 0, sizeof(srv_hints)); - srv_hints.ai_family = AF_INET; - srv_hints.ai_socktype = SOCK_DGRAM; - srv_hints.ai_flags = AI_PASSIVE; + cli_hints.ai_family = srv_hints.ai_family = AF_INET; + cli_hints.ai_socktype = srv_hints.ai_socktype = ftcp ? SOCK_STREAM : SOCK_DGRAM; + rv = getaddrinfo(to, port, &cli_hints, &cli_servinfo); + if (rv) + errx(1, "getaddrinfo: %s", gai_strerror(rv)); rv = getaddrinfo(NULL, port, &srv_hints, &srv_servinfo); if (rv) errx(1, "getaddrinfo: %s", gai_strerror(rv)); - for(p0 = srv_servinfo; p0; p0 = p0->ai_next) { - srv_sockfd = socket(p0->ai_family, p0->ai_socktype, + /* getaddrinfo returns a list of results so we iterate on it */ + for (p0 = cli_servinfo; p0; p0 = p0->ai_next) { + cli_sockfd = socket(p0->ai_family, p0->ai_socktype, p0->ai_protocol); - if (srv_sockfd < 0) - continue; - optval = 1; - rv = setsockopt(srv_sockfd, SOL_SOCKET, + if (cli_sockfd < 0) + continue; /* until the socket is ready */ + rv = setsockopt(cli_sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); if (rv < 0) { - close(srv_sockfd); + close(cli_sockfd); warn("setsockopt"); continue; } - if (bind(srv_sockfd, p0->ai_addr, p0->ai_addrlen) < 0) { - close(srv_sockfd); - warn("bind"); - continue; + break; + } + if (!p0) + errx(1, "failed to create socket"); + /* the same for our local part */ + for (p0 = srv_servinfo; p0; p0 = p0->ai_next) { + if (bind(cli_sockfd, p0->ai_addr, p0->ai_addrlen) < 0) { + close(cli_sockfd); + warn("bind"); + continue; } break; } if (!p0) errx(1, "failed to bind socket"); - /* register them to the context */ - c->srvfd = srv_sockfd; - c->srvinfo = srv_servinfo; + /* all was ok, so we register the socket to the context */ + c->confd = cli_sockfd; + c->clinfo = cli_servinfo; } +/* + * this sample func reads data from input, null-terminates them + * and sends them over the prepared socket stored in the context. + * If it gets a "Q" it quits. + */ static void stdinputdata(concontxt *con) { char *inbuf = NULL, *linbuf = NULL; @@ -123,16 +153,26 @@ stdinputdata(concontxt *con) if ((strncmp(inbuf, "Q", 2) == 0)) goto freex; printf("got msg: %s , sending it\n", inbuf); - sendto(con->clifd, inbuf, inbufln, 0, - con->clinfo->ai_addr, - con->clinfo->ai_addrlen); + if (ftcp == 0) { + sendto(con->confd, inbuf, inbufln, 0, + con->clinfo->ai_addr, + con->clinfo->ai_addrlen); + } else { + /* code for tcp */ + } fflush(stdout); /* free the buf */ freex: if(linbuf != NULL) free(linbuf); + /* let the main process know we want out */ + quitflag=1; } +/* + * This sample receive func, reads up to 512 bytes of input + * from the socket stored in the context. + */ static void srvinputdata(concontxt *con) { @@ -143,10 +183,14 @@ srvinputdata(concontxt *con) socklen_t addr_len; struct sockaddr_storage their_addr; addr_len = sizeof(their_addr); - bytes = recvfrom(con->srvfd, buf, - sizeof(buf), MSG_DONTWAIT, - (struct sockaddr *)&their_addr, - &addr_len); + if (ftcp == 0) { + bytes = recvfrom(con->confd, buf, + sizeof(buf), MSG_DONTWAIT, + (struct sockaddr *)&their_addr, + &addr_len); + } else { + /* code for tcp */ + } if (bytes > 0) { ret = getnameinfo((struct sockaddr *)&their_addr, addr_len, host, @@ -159,6 +203,7 @@ srvinputdata(concontxt *con) } } + int main(int argc, char *argv[]) { @@ -170,14 +215,14 @@ main(int argc, char *argv[]) int highsock, readsocks; struct timeval timeout; concontxt *con = (concontxt *) malloc(sizeof (concontxt)); - while ((c = getopt(argc, argv, "hs")) != -1) { + while ((c = getopt(argc, argv, "ht")) != -1) { switch (c) { case 'h': usage(prog); goto freex; break; - case 's': - fssl = 1; + case 't': + ftcp = 1; break; case '?': default: @@ -187,21 +232,24 @@ main(int argc, char *argv[]) argc -= optind; argv += optind; - if (argc != 3) { + if (argc != 2) { usage(prog); goto freex; } - /* connect to the host */ - connectit(con, argv[0], argv[1]); - /* prepare the server socket */ - serveit(con, argv[2]); - /* XXX: this should change when we add the srv fd */ - highsock = con->srvfd; - /* these are the sockets for reading (stdin + server fd) */ + if (ftcp == 0) { + /* prepare the socket for udp */ + prepare_socket(con, argv[0], argv[1]); + } else { + /* code for tcp */ + } + highsock = con->confd; + /* these are the sockets for reading (stdin + connection fd) */ while (1) { + if (quitflag) + goto freex; FD_ZERO(&rsocks); FD_SET(recfd, &rsocks); - FD_SET(con->srvfd, &rsocks); + FD_SET(con->confd, &rsocks); timeout.tv_sec = 1; timeout.tv_usec = 0; readsocks = select(highsock + 1, &rsocks, (fd_set *)0, @@ -218,15 +266,16 @@ main(int argc, char *argv[]) if (FD_ISSET(recfd, &rsocks)) { stdinputdata(con); } - if (FD_ISSET(con->srvfd,&rsocks)) { + if (FD_ISSET(con->confd, &rsocks)) { srvinputdata(con); } } } freex: + printf("exiting\n"); if (con != NULL) { - close(con->clifd); + close(con->confd); free(con); } return (0); diff --git a/ssl/create_ca b/ssl/create_ca @@ -0,0 +1,5 @@ +#/bin/sh + +mkdir -p ca/private +chmod 700 ca/private +openssl req -x509 -days 3650 -newkey rsa:1024 -keyout ca/private/ca.key -out ca/ca.crt diff --git a/ssl/create_client b/ssl/create_client @@ -0,0 +1,5 @@ +#/bin/sh +mkdir -p client/private +chmod 700 client/private +openssl genrsa -out client/private/client.key 1024 +openssl req -new -key client/private/client.key -out client/client.csr diff --git a/ssl/create_server b/ssl/create_server @@ -0,0 +1,5 @@ +#/bin/sh +mkdir -p server/private +chmod 700 server/private +openssl genrsa -out server/private/server.key 1024 +openssl req -new -key server/private/server.key -out server/server.csr diff --git a/ssl/sign_client b/ssl/sign_client @@ -0,0 +1,2 @@ +#/bin/sh +openssl x509 -req -days 3650 -in client/client.csr -CA ./ca/ca.crt -CAkey ./ca/private/ca.key -CAcreateserial -out client/client.crt diff --git a/ssl/sign_server b/ssl/sign_server @@ -0,0 +1,2 @@ +#/bin/sh +openssl x509 -req -days 3650 -in server/server.csr -CA ./ca/ca.crt -CAkey ./ca/private/ca.key -CAcreateserial -out server/server.crt