commit ba767a66b0881490fa34cb6fd810260e3d13d9df
parent ded92c4fae4f49ac28aec433adc69cbe63b0ab74
Author: dsp <dsp@2f30.org>
Date: Mon, 2 Jul 2012 17:32:35 +0300
applied lostd patch in style and abstraction
Diffstat:
M | nbeng.c | | | 336 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
1 file changed, 195 insertions(+), 141 deletions(-)
diff --git a/nbeng.c b/nbeng.c
@@ -1,51 +1,57 @@
/*
- * NonBlocking network engine for tcp/udp/ssl connections
+ * Non-blocking 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 :)
+ * data. The relevant data are stored in a connection context
+ * which is passed around the functions for dealing with it.
+ * Also provided are sample reading and writing functions.
+ * Copyleft:
+ * DsP <dsp@2f30.org>
+ * Lazaros Koromilas <lostd@2f30.org>
+ * Cheers go to PhotoRec for helping recover this file :)
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+
#include <sys/types.h>
#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+
#include <netdb.h>
-#include <ctype.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <err.h>
-#include <errno.h>
-/*connection types*/
-#define UDPCON 1
-#define TCPCON 2
-#define SSLCON 3
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
-/* flag to know when to quit the prog */
-unsigned int quitflag=0;
+/* global flags */
+unsigned int tflag = 0;
+unsigned int sflag = 0;
+unsigned int qflag = 0;
/* connection context */
typedef struct concontxt_t {
+#define UDPCON 1
+#define TCPCON 2
+#define SSLCON 3
unsigned int contype; /* connection type */
int confd; /* net connection fd */
int clifds[FD_SETSIZE]; /* for tcp connected clients */
fd_set lset; /* the set that we select() on */
struct addrinfo *clinfo; /* info on where we connect */
struct addrinfo *srvinfo; /* info for the local part */
+#define INBUFSIZ 512
+ char *buf; /* buffer used for input/output */
+ unsigned int buflen;
+ int wfd, lfd; /* local file descriptors */
} concontxt;
-static void
-usage(const char *s)
+void
+usage(int ret)
{
- fprintf(stderr, "usage: %s [-ht] rhost rport\n"
- " -t\ttcp session\n"
- " -h\tThis help screen\n", s);
+ fprintf(stderr, "usage: nbeng [-ht] rhost rport\n"
+ "\t-t Use TCP for transport\n"
+ "\t-h This help screen\n");
+ if (ret)
+ exit(1);
}
static void
@@ -73,32 +79,32 @@ set_blocking(int fd)
}
/*
- * 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.
- * the flag for the connection type lives in the context.
+ * 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.
+ * The flag for the connection type lives in the context.
*/
static void
-prepare_socket(concontxt *c, char *to, char *port)
+prepare_socket(concontxt *con, char *host, char *port)
{
struct addrinfo cli_hints, *cli_servinfo, srv_hints, *srv_servinfo, *p0;
int rv, cli_sockfd, optval = 1, i;
/* all client fds are available */
for (i = 0; i < FD_SETSIZE; i++)
- c->clifds[i] = -1;
+ con->clifds[i] = -1;
- if ((c == NULL) || (to == NULL) || (port == NULL))
+ if ((con == NULL) || (host == 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));
+ memset(&cli_hints, 0, sizeof (cli_hints));
+ memset(&srv_hints, 0, sizeof (srv_hints));
cli_hints.ai_family = srv_hints.ai_family = AF_INET;
srv_hints.ai_flags = AI_PASSIVE;
cli_hints.ai_socktype = srv_hints.ai_socktype =
- ((c->contype == TCPCON) || (c->contype == SSLCON))
+ ((con->contype == TCPCON) || (con->contype == SSLCON))
? SOCK_STREAM : SOCK_DGRAM;
- rv = getaddrinfo(to, port, &cli_hints, &cli_servinfo);
+ rv = getaddrinfo(host, port, &cli_hints, &cli_servinfo);
if (rv)
errx(1, "getaddrinfo: %s", gai_strerror(rv));
rv = getaddrinfo(NULL, port, &srv_hints, &srv_servinfo);
@@ -111,7 +117,7 @@ prepare_socket(concontxt *c, char *to, char *port)
if (cli_sockfd < 0)
continue; /* until the socket is ready */
rv = setsockopt(cli_sockfd, SOL_SOCKET,
- SO_REUSEADDR, &optval, sizeof(optval));
+ SO_REUSEADDR, &optval, sizeof (optval));
if (rv < 0) {
close(cli_sockfd);
warn("setsockopt");
@@ -133,167 +139,213 @@ prepare_socket(concontxt *c, char *to, char *port)
if (!p0)
errx(1, "failed to bind socket");
/* if it's a tcp connection we have to listen() */
- if (c->contype != UDPCON)
- listen(cli_sockfd,5);
+ if (con->contype != UDPCON)
+ listen(cli_sockfd, 5);
/* all was ok, so we register the socket to the context */
- c->confd = cli_sockfd;
- c->clinfo = cli_servinfo;
+ con->confd = cli_sockfd;
+ con->clinfo = cli_servinfo;
+}
+
+/*
+ * Reads data from standard input and saves them in the context.
+ * Sets the qflag on "Q".
+ */
+static void
+readstdin(concontxt *con)
+{
+ char buf[INBUFSIZ];
+ ssize_t n;
+
+ /* handle input data */
+ n = read(con->wfd, buf, INBUFSIZ);
+ buf[n] = '\0';
+
+ /* user quits? */
+ if (n == 0 || strncmp(buf, "Q\n", 3) == 0) {
+ qflag = 1;
+ return;
+ }
+ printf("n=%zd buf=%s", n, buf);
+
+ /* copy to context */
+ if ((con->buf = (char *)malloc(n)) == NULL) {
+ warn("malloc");
+ goto freex;
+ }
+ memcpy(con->buf, buf, n);
+ con->buflen = n;
+ return;
+
+freex:
+ if (con->buf != NULL)
+ free(con->buf);
+ con->buf = NULL;
+ con->buflen = 0;
+ return;
}
/*
- * 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.
+ * Sends data available in the context to all peers.
*/
static void
-stdinputdata(concontxt *con)
-{ char *inbuf = NULL, *linbuf = NULL;
- ssize_t inbufln, sent;
- int tcpfd, i;
-
- /* deal with input data */
- inbuf = fgetln(stdin, &inbufln);
- if (inbuf[inbufln - 1] == '\n')
- inbuf[inbufln - 1] = '\0';
- else {
- /* EOF without EOL,
- copy and add the NULL */
- if ((linbuf = malloc(inbufln + 1))
- == NULL) {
- warnx("linbuf alloc failed");
- goto freex;
- }
- memcpy(linbuf, inbuf, inbufln);
- linbuf[inbufln] = '\0';
- inbuf = linbuf;
- }
- if ((strncmp(inbuf, "Q", 2) == 0))
- goto endit;
- printf("got msg: %s len %d, to : %x sending it\n", inbuf,inbufln,con->clinfo->ai_addr);
+writesock(concontxt *con)
+{
+ ssize_t sent;
+ int newfd;
+ int i;
+
+ /* nothing to do */
+ if (con->buf == NULL)
+ return;
+
if (con->contype == UDPCON) {
- sent = sendto(con->confd, inbuf, inbufln, 0,
+ sent = sendto(con->confd, con->buf, con->buflen, 0,
con->clinfo->ai_addr,
con->clinfo->ai_addrlen);
- if(sent < 0)
- warn("sendto failed");
+ if (sent < 0)
+ warn("sendto");
} else {
- tcpfd = connect(con->confd,
+ newfd = connect(con->confd,
con->clinfo->ai_addr,
con->clinfo->ai_addrlen);
- if (tcpfd < 0) {
- warn("tcp connect");
+ printf("newfd=%d\n", newfd);
+ if (newfd < 0) {
+ warn("connect");
goto freex;
}
- /* XXX: check if we hit the setsiz limit */
for (i = 0; i < FD_SETSIZE; i++) {
if (con->clifds[i] == -1) {
- con->clifds[i] = tcpfd;
+ con->clifds[i] = newfd;
break;
}
}
}
- fflush(stdout);
- /* free the buf */
-freex:
- if(linbuf != NULL)
- free(linbuf);
- return; /*here we normally go out*/
-endit: /* let the main process know we want out */
- if(linbuf != NULL)
- free(linbuf);
- quitflag=1;
+
+freex:
+ if (con->buf != NULL)
+ free(con->buf);
+ con->buf = NULL;
+ con->buflen = 0;
+ return;
}
/*
- * This sample receive func, reads up to 512 bytes of input
- * from the socket stored in the context.
+ * Reads data from the socket and saves them in the context.
*/
static void
-srvinputdata(concontxt *con)
+readsock(concontxt *con)
{
- ssize_t bytes=0;
- int ret;
+ char buf[INBUFSIZ];
+ ssize_t n;
+ int r;
char host[NI_MAXHOST];
- char buf[512];
socklen_t addr_len;
struct sockaddr_storage their_addr;
- addr_len = sizeof(their_addr);
+
+ addr_len = sizeof (their_addr);
if (con->contype == UDPCON) {
- bytes = recvfrom(con->confd, buf,
- sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *)&their_addr,
- &addr_len);
+ n = recvfrom(con->confd, buf, sizeof (buf), MSG_DONTWAIT,
+ (struct sockaddr *)&their_addr, &addr_len);
} else {
/* code for tcp */
+ n = 0;
}
- if (bytes > 0) {
- ret = getnameinfo((struct sockaddr *)&their_addr,
- addr_len, host,
- sizeof(host), NULL, 0, 0);
- if (ret < 0) {
- warn("getnameinfo");
- snprintf(host, sizeof(host), "unknown");
+ buf[n] = '\0';
+
+ /* copy to context */
+ if ((con->buf = (char *)malloc(n)) == NULL) {
+ warn("malloc");
+ goto freex;
+ }
+ memcpy(con->buf, buf, n);
+ con->buflen = n;
+
+ if (n > 0) {
+ r = getnameinfo((struct sockaddr *)&their_addr, addr_len,
+ host, sizeof (host), NULL, 0, 0);
+ if (r < 0) {
+ warn("getnameinfo");
+ snprintf(host, sizeof (host), "unknown");
}
- printf("Received %zd bytes from %s that read: %s \n", bytes, host, buf);
}
+ printf("host=%s n=%zd buf=%s", host, n, buf);
+ return;
+
+freex:
+ if (con->buf != NULL)
+ free(con->buf);
+ con->buf = NULL;
+ con->buflen = 0;
+ return;
}
+/*
+ * Writes data available in the context to standard output.
+ */
+static void
+writestdout(concontxt *con)
+{
+ write(con->lfd, con->buf, con->buflen);
+
+ if (con->buf != NULL)
+ free(con->buf);
+ con->buf = NULL;
+ con->buflen = 0;
+ return;
+}
int
main(int argc, char *argv[])
{
- /* our input is the stdin for now, we record lines and send them */
- int recfd = STDIN_FILENO;
- char *prog = *argv;
- int c,i;
- fd_set rsocks;
+ int c, i;
int highsock, readsocks;
struct timeval timeout;
- concontxt *con = (concontxt *) malloc(sizeof (concontxt));
- if (con == NULL)
- errx(1,"malloc");
- /* our default is the udp connection type */
- con->contype = UDPCON;
+ char *host, *port;
+ concontxt *con;
+
while ((c = getopt(argc, argv, "ht")) != -1) {
switch (c) {
case 'h':
- usage(prog);
- goto freex;
+ usage(1);
break;
case 't':
- con->contype = TCPCON;
+ tflag = 1;
break;
- case '?':
default:
- goto freex;
+ usage(1);
}
}
argc -= optind;
argv += optind;
- if (argc != 2) {
- usage(prog);
- goto freex;
- }
- prepare_socket(con, argv[0], argv[1]);
- highsock = con->confd;
- /*FD_ZERO(&(con->lset));
- FD_SET(recfd, &(con->lset));
- FD_SET(con->confd, &(con->lset));
- timeout.tv_sec = 1;
- timeout.tv_usec = 0; */
+ if (argc != 2)
+ usage(1);
+ host = argv[0];
+ port = argv[1];
+
+ con = (concontxt *) malloc(sizeof (concontxt));
+ if (con == NULL)
+ errx(1,"malloc");
+ /* defaults */
+ con->wfd = fileno(stdin);
+ con->lfd = fileno(stdout);
+ con->contype = (tflag || sflag) ? TCPCON : UDPCON;
+
+ prepare_socket(con, host, port);
+
timeout.tv_sec = 1;
timeout.tv_usec = 0;
- /* these are the sockets for reading (stdin + connection fd) */
+ /* file descriptors for reading are stdin and confd */
while (1) {
FD_ZERO(&(con->lset));
- FD_SET(recfd, &(con->lset));
+ FD_SET(con->wfd, &(con->lset));
FD_SET(con->confd, &(con->lset));
+ highsock = con->confd;
/* add all connected clients */
for (i = 0; i < FD_SETSIZE && con->clifds[i] != -1; i++) {
FD_SET(con->clifds[i], &(con->lset));
}
- if (quitflag)
+ if (qflag)
goto freex;
readsocks = select(highsock + 1, &(con->lset), (fd_set *)0,
(fd_set *)0, &timeout);
@@ -306,11 +358,13 @@ main(int argc, char *argv[])
printf(".");
fflush(stdout);
} else {
- if (FD_ISSET(recfd, &(con->lset))) {
- stdinputdata(con);
+ if (FD_ISSET(con->wfd, &(con->lset))) {
+ readstdin(con);
+ writesock(con);
}
if (FD_ISSET(con->confd, &(con->lset))) {
- srvinputdata(con);
+ readsock(con);
+ writestdout(con);
}
}
}