diff libnnchat.c @ 168:2e4850ece456

Partially re-factor connection handling.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 14 Nov 2010 22:08:08 +0200
parents b0b63d164702
children 659b8229d015
line wrap: on
line diff
--- a/libnnchat.c	Sat Nov 06 18:00:22 2010 +0200
+++ b/libnnchat.c	Sun Nov 14 22:08:08 2010 +0200
@@ -6,20 +6,6 @@
 #include "libnnchat.h"
 
 
-typedef struct {
-    char c;
-    char *ent;
-} html_entity_t;
-
-
-static const html_entity_t HTMLEntities[] = {
-    { '<', "&lt;" },
-    { '>', "&gt;" },
-};
-
-static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]);
-
-
 #ifdef __WIN32
 const char *hstrerror(int err)
 {
@@ -36,8 +22,21 @@
 const char *nn_get_socket_errstr(int err)
 {
     static char buf[64];
-    snprintf(buf, sizeof(buf), "Error #%d", err);
-    return buf;
+    switch (err) {
+        case WSAEADDRINUSE:      return "Address already in use";
+        case WSAECONNABORTED:    return "Software caused connection abort";
+        case WSAECONNREFUSED:    return "Connection refused";
+        case WSAECONNRESET:      return "Connection reset by peer";
+        case WSAEHOSTUNREACH:    return "No route to host";
+        case WSAENETDOWN:        return "Network is down";
+        case WSAETIMEDOUT:       return "Connection timed out";
+        case WSAHOST_NOT_FOUND:  return "Host not found";
+        case WSAVERNOTSUPPORTED: return "Wrong WinSock DLL version";
+        default:
+            snprintf(buf, sizeof(buf), "Error #%d", err);
+            return buf;
+            break;
+    }
 }
 #else
 int nn_get_socket_errno(void)
@@ -52,46 +51,164 @@
 #endif
 
 
-int nn_open_connection(struct in_addr *addr, const int port)
+void nn_conn_err(nn_conn_t *conn, const char *fmt, ...)
 {
-    struct sockaddr_in tmpAddr;
-    int sock = -1;
+    conn->err = TRUE;
+
+    if (conn->errfunc) {
+        va_list ap;
+        va_start(ap, fmt);
+        conn->errfunc(conn, fmt, ap);
+        va_end(ap);
+    }
+}
+
+
+static void nn_conn_msg(nn_conn_t *conn, const char *fmt, ...)
+{
+    if (conn->msgfunc) {
+        va_list ap;
+        va_start(ap, fmt);
+        conn->msgfunc(conn, fmt, ap);
+        va_end(ap);
+    }
+}
+
+
+nn_conn_t *nn_conn_open(struct in_addr *addr, const int port)
+{
+    nn_conn_t *conn = th_calloc(1, sizeof(nn_conn_t));
+    struct sockaddr_in dest;
     
-    tmpAddr.sin_family = AF_INET;
-    tmpAddr.sin_port = htons(port);
-    tmpAddr.sin_addr = *addr;
+    if (conn == NULL)
+        return NULL;
+
+    dest.sin_family = AF_INET;
+    dest.sin_port = htons(port);
+    dest.sin_addr = *addr;
 
-    THMSG(1, "Connecting to %s:%d ...\n",
-        inet_ntoa(tmpAddr.sin_addr), port);
+    nn_conn_msg(conn, "Connecting to %s:%d ...\n",
+        inet_ntoa(dest.sin_addr), port);
 
-    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
-        THERR("Could not open socket: %s\n", strerror(errno));
-        return -2;
+    if ((conn->socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+        nn_conn_err(conn, "Could not open socket: %s\n", strerror(errno));
+        conn->status = NN_CONN_CLOSED;
+        return conn;
     }
     
-    THMSG(2, "Using socket %d.\n", sock);
+    nn_conn_msg(conn, "Using socket %d.\n", conn->socket);
     
-    if (connect(sock, (struct sockaddr *) &tmpAddr, sizeof(tmpAddr)) == -1) {
-        THERR("Could not connect: %s\n", strerror(errno));
-        return -5;
+    if (connect(conn->socket, (struct sockaddr *) &dest, sizeof(dest)) == -1) {
+        nn_conn_err(conn, "Could not connect: %s\n", strerror(errno));
+        conn->status = NN_CONN_CLOSED;
+        return conn;
     }
+
+    conn->port = port;
+    conn->address = *addr;
+    FD_ZERO(&(conn->sockfds));
+    FD_SET(conn->socket, &(conn->sockfds));
+    conn->status = NN_CONN_OPEN;
     
-    return sock;
+    return conn;
 }
 
 
-void nn_close_connection(const int sock)
+void nn_conn_close(nn_conn_t *conn)
 {
-    if (sock >= 0) {
+    if (conn == NULL)
+        return;
+    
+    if (conn->socket >= 0) {
 #ifdef __WIN32
-        closesocket(sock);
+        closesocket(conn->socket);
 #else
-        close(sock);
+        close(conn->socket);
 #endif
+        conn->socket = -1;
     }
+    
+    conn->status = NN_CONN_CLOSED;
+    
+    th_free(conn);
 }
 
 
+BOOL nn_conn_send_buf(nn_conn_t *conn, const char *buf, const size_t len)
+{
+    size_t bufLeft = len;
+    const char *bufPtr = buf;
+    
+    while (bufLeft > 0) {
+        ssize_t bufSent;
+        bufSent = send(conn->socket, bufPtr, bufLeft, 0);
+        if (bufSent < 0) {
+            nn_conn_err(conn, "nn_conn_send_buf() failed: %s", strerror(errno));
+            return FALSE;
+        }
+        bufLeft -= bufSent;
+        bufPtr += bufSent;
+    }
+
+    return TRUE;
+}
+
+
+BOOL nn_conn_pull(nn_conn_t *conn)
+{
+    int result;
+    struct timeval socktv;
+    fd_set tmpfds;
+
+    if (conn == NULL)
+        return -1;
+
+    conn->ptr = conn->buf;
+
+    /* Check for incoming data */
+    socktv.tv_sec = 0;
+    socktv.tv_usec = NN_DELAY_USEC;
+    tmpfds = conn->sockfds;
+
+    if ((result = select(conn->socket + 1, &tmpfds, NULL, NULL, &socktv)) == -1) {
+        int err = nn_get_socket_errno();
+        if (err != EINTR) {
+            nn_conn_err(conn, "Error occured in select(%d, sockfds): %d, %s\n",
+                socket, err, nn_get_socket_errstr(err));
+            return -1;
+        }
+    } else
+    if (FD_ISSET(conn->socket, &tmpfds)) {
+        conn->got = recv(conn->socket, conn->ptr, NN_CONNBUF_SIZE, 0);
+
+        if (conn->got < 0) {
+            int res = nn_get_socket_errno();
+            nn_conn_err(conn, "Error in recv: %d, %s\n", res, nn_get_socket_errstr(res));
+            return -2;
+        } else if (conn->got == 0) {
+            nn_conn_err(conn, "Server closed connection.\n");
+            conn->status = NN_CONN_CLOSED;
+            return -3;
+        } else {
+            /* Handle protocol data */
+            conn->buf[conn->got] = 0;
+            return 0;
+        }
+    }
+    
+    return 1;
+}
+
+BOOL nn_conn_check(nn_conn_t *conn)
+{
+    if (conn == NULL)
+        return FALSE;
+
+    return conn->err == 0 && conn->status == NN_CONN_OPEN;
+}
+
+
+
 BOOL nn_network_init(void)
 {
 #ifdef __WIN32
@@ -115,31 +232,15 @@
 }
 
 
-BOOL nn_send_to_socket(const int sock, char *buf, const size_t bufLen)
-{
-    size_t bufLeft = bufLen;
-    char *bufPtr = buf;
-    
-    while (bufLeft > 0) {
-        ssize_t bufSent;
-        bufSent = send(sock, bufPtr, bufLeft, 0);
-        if (bufSent < 0) return FALSE;
-        bufLeft -= bufSent;
-        bufPtr += bufSent;
-    }
-    return TRUE;
-}
-
-
-BOOL bufRealloc(char **buf, size_t *size, size_t add)
+static BOOL bufRealloc(char **buf, size_t *size, size_t add)
 {
     return ((*buf = th_realloc(*buf, *size + add)) != NULL);
 }
 
 #define PUSHCHAR(x) bufPushChar(&result, &resSize, &resPos, x)
-BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch)
+static BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch)
 {
-    if (*pos >= *size && !bufRealloc(buf, size, SET_ALLOC_SIZE))
+    if (*pos >= *size && !bufRealloc(buf, size, NN_ALLOC_SIZE))
         return FALSE;
     
     (*buf)[*pos] = ch;
@@ -148,14 +249,14 @@
 }
 
 #define PUSHSTR(x) bufPushStr(&result, &resSize, &resPos, x)
-BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str)
+static BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str)
 {
     size_t tmpLen;
     
     if (str == NULL) return FALSE;
     tmpLen = strlen(str);
     
-    if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + SET_ALLOC_SIZE))
+    if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + NN_ALLOC_SIZE))
         return FALSE;
     
     strcpy(*buf + *pos, str);
@@ -172,7 +273,7 @@
     
     if (str == NULL) return NULL;
     
-    resSize = strlen(str) + SET_ALLOC_SIZE;
+    resSize = strlen(str) + NN_ALLOC_SIZE;
     if ((result = th_malloc(resSize)) == NULL)
         return NULL;
     
@@ -227,7 +328,7 @@
     
     if (str == NULL) return NULL;
     
-    resSize = strlen(str) + SET_ALLOC_SIZE;
+    resSize = strlen(str) + NN_ALLOC_SIZE;
     if ((result = th_malloc(resSize)) == NULL)
         return NULL;
     
@@ -288,7 +389,7 @@
     
     if (str == NULL) return NULL;
     
-    resSize = strlen(str) + SET_ALLOC_SIZE;
+    resSize = strlen(str) + NN_ALLOC_SIZE;
     if ((result = th_malloc(resSize)) == NULL)
         return NULL;
     
@@ -305,6 +406,20 @@
 }
 
 
+typedef struct {
+    char c;
+    char *ent;
+} html_entity_t;
+
+
+static const html_entity_t HTMLEntities[] = {
+    { '<', "&lt;" },
+    { '>', "&gt;" },
+};
+
+static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]);
+
+
 char *nn_encode_str2(const char *str)
 {
     const char *s = str;
@@ -313,7 +428,7 @@
     
     if (str == NULL) return NULL;
     
-    resSize = strlen(str) + SET_ALLOC_SIZE;
+    resSize = strlen(str) + NN_ALLOC_SIZE;
     if ((result = th_malloc(resSize)) == NULL)
         return NULL;
     
@@ -400,23 +515,27 @@
 }
 
 
-BOOL nn_send_msg(const int sock, const char *user, const char *fmt, ...)
+BOOL nn_conn_send_msg(nn_conn_t *conn, const char *user, const char *fmt, ...)
 {
-    char tmpBuf[SET_BUFSIZE], tmpBuf2[SET_BUFSIZE + 256];
-    int n;
+    char *tmp, *msg;
     va_list ap;
     
     va_start(ap, fmt);
-    n = vsnprintf(tmpBuf, sizeof(tmpBuf), fmt, ap);
+    tmp = th_strdup_vprintf(fmt, ap);
     va_end(ap);
     
-    if (n < 0) return FALSE;
+    if (tmp == NULL)
+        return FALSE;
+    
+    msg = th_strdup_printf("<USER>%s</USER><MESSAGE>%s</MESSAGE>", user, tmp);
+    th_free(tmp);
     
-    snprintf(tmpBuf2, sizeof(tmpBuf2),
-        "<USER>%s</USER><MESSAGE>%s</MESSAGE>",
-        user, tmpBuf);
-    
-    return nn_send_to_socket(sock, tmpBuf2, strlen(tmpBuf2) + 1);
+    if (msg != NULL) {
+        BOOL ret = nn_conn_send_buf(conn, msg, strlen(msg) + 1);
+        th_free(msg);
+        return ret;
+    } else
+        return FALSE;
 }
 
 
@@ -459,7 +578,6 @@
 
 int nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch)
 {
-    /* Check arguments */
     if (buf->len+1 >= buf->size) return -3;
     
     if (pos < 0)
@@ -475,7 +593,6 @@
 
 int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch)
 {
-    /* Check arguments */
     if (buf->len+1 >= buf->size) return -3;
     
     if (pos < 0)
@@ -493,7 +610,6 @@
 
 int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos)
 {
-    /* Check arguments */
     if (pos < 0)
         return -1;
     else if (pos < buf->len) {
@@ -568,9 +684,12 @@
     } else
         return NULL;
 
-    str = th_malloc(siz + 1);
+    if ((str = th_malloc(siz + 1)) == NULL)
+        return NULL;
+
     memcpy(str, buf->data + start, siz);
     str[siz] = 0;
+
     return str;
 }