changeset 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 fd93de78a115
files libnnchat.c libnnchat.h nnchat.c
diffstat 3 files changed, 296 insertions(+), 177 deletions(-) [+]
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;
 }
 
--- a/libnnchat.h	Sat Nov 06 18:00:22 2010 +0200
+++ b/libnnchat.h	Sun Nov 14 22:08:08 2010 +0200
@@ -21,9 +21,11 @@
 #include <errno.h>
 #include "th_string.h"
 
-#define SET_BUFSIZE     (4096)
-#define SET_ALLOC_SIZE  (128)
-
+#define NN_TMPBUF_SIZE    (4096)
+#define NN_ALLOC_SIZE     (128)
+#define NN_CONNBUF_SIZE   (64 * 1024)
+#define NN_NUM_BUCKETS    (256)
+#define NN_DELAY_USEC     (15 * 250)
 
 typedef struct {
     char **data;
@@ -44,25 +46,46 @@
 } nn_user_t;
 
 
-#define NN_NUM_BUCKETS (256)
 
 typedef struct {
     nn_user_t *buckets[NN_NUM_BUCKETS];
 } nn_userhash_t;
 
+enum {
+    NN_CONN_UNINIT = 0,
+    NN_CONN_OPEN,
+    NN_CONN_CLOSED
+};
 
-#ifdef __WIN32
-const char *hstrerror(int err);
-#endif
-int         nn_get_socket_errno(void);
-const char *nn_get_socket_errstr(int err);
+typedef struct _nn_conn_t {
+    int socket;
+    int port;
+    struct in_addr address;
+    fd_set sockfds;
+
+    void (*errfunc)(struct _nn_conn_t *conn, const char *fmt, va_list ap);
+    void (*msgfunc)(struct _nn_conn_t *conn, const char *fmt, va_list ap);
+
+    int err;
+    int status;
+    
+    char buf[NN_CONNBUF_SIZE + 16];
+    char *ptr;
+    ssize_t got;
+} nn_conn_t;
+
+
+const char *nn_get_errstr(int err);
 BOOL        nn_network_init(void);
 void        nn_network_close(void);
 
-int         nn_open_connection(struct in_addr *addr, const int port);
-void        nn_close_connection(const int sock);
-BOOL        nn_send_to_socket(const int sock, char *buf, const size_t bufLen);
-BOOL        nn_send_msg(const int sock, const char *user, const char *fmt, ...);
+nn_conn_t * nn_conn_open(struct in_addr *addr, const int port);
+void        nn_conn_close(nn_conn_t *);
+BOOL        nn_conn_pull(nn_conn_t *);
+BOOL        nn_conn_send_buf(nn_conn_t *, const char *buf, const size_t len);
+BOOL        nn_conn_send_msg(nn_conn_t *, const char *user, const char *fmt, ...);
+BOOL        nn_conn_check(nn_conn_t *);
+
 
 nn_userhash_t *nn_userhash_new(void);
 nn_user_t * nn_userhash_foreach(const nn_userhash_t *, int (*func)(const nn_user_t *));
@@ -75,6 +98,7 @@
 nn_user_t * nn_user_copy(const nn_user_t *src);
 nn_user_t * nn_user_find(const nn_userhash_t *list, const char *name);
 
+
 char *      nn_encode_str1(const char *str);
 char *      nn_decode_str1(const char *str);
 char *      nn_encode_str2(const char *str);
@@ -88,6 +112,7 @@
 void        nn_ringbuf_free(nn_ringbuf_t *buf);
 void        nn_ringbuf_add(nn_ringbuf_t *buf, const char *str);
 
+
 int         nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch);
 int         nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch);
 int         nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos);
--- a/nnchat.c	Sat Nov 06 18:00:22 2010 +0200
+++ b/nnchat.c	Sun Nov 14 22:08:08 2010 +0200
@@ -29,7 +29,6 @@
 #define SET_MIN_BACKBUF (1024)      /* Backbuffer size (in lines) */
 #define SET_MAX_HISTORY (16)        /* Command history length */
 #define SET_DELAY       (15)
-#define SET_DELAY_USEC  (SET_DELAY * 250)
 #define SET_KEEPALIVE   (15*60)     /* Ping/keepalive period in seconds */
 
 
@@ -360,12 +359,12 @@
 }
 
 
-int handleUser(int sock, const char *str)
+int handleUser(nn_conn_t *conn, const char *str)
 {
     const char *msg = "</USER><MESSAGE>", *p = str;
     char *q, *s, *t, *h, *p2;
     
-    (void) sock;
+    (void) conn;
     
     s = strstr(str, msg);
     if (!s) return 1;
@@ -428,7 +427,7 @@
 }
 
 
-int handleLogin(int sock, const char *str)
+int handleLogin(nn_conn_t *conn, const char *str)
 {
     char tmpStr[256];
     
@@ -439,18 +438,18 @@
         return -2;
     } else if (!strncmp(str, "SUCCESS", 7)) {
         printMsg("½2½Login success½0½ - ½3½%s½0½\n", tmpStr);
-        nn_send_msg(sock, optUserName2, "%%2FRequestUserList");
+        nn_conn_send_msg(conn, optUserName2, "%%2FRequestUserList");
         return 0;
     } else
         return 1;
 }
 
 
-int handleAddUser(int sock, const char *str)
+int handleAddUser(nn_conn_t *conn, const char *str)
 {
     char *p, *s = strstr(str, "</ADD_USER>");
 
-    (void) sock;
+    (void) conn;
 
     if (!s) return 1;
     *s = 0;
@@ -466,11 +465,11 @@
 }
 
 
-int handleDeleteUser(int sock, const char *str)
+int handleDeleteUser(nn_conn_t *conn, const char *str)
 {
     char *p, *s = strstr(str, "</DELETE_USER>");
 
-    (void) sock;
+    (void) conn;
 
     if (!s) return 1;
     *s = 0;
@@ -486,17 +485,17 @@
 }
 
 
-int handleFoo(int sock, const char *str)
+int handleFoo(nn_conn_t *conn, const char *str)
 {
-    (void) sock; (void) str;
+    (void) conn; (void) str;
     
     return 0;
 }
 
 
-int handleBoot(int sock, const char *str)
+int handleBoot(nn_conn_t *conn, const char *str)
 {
-    (void) sock; (void) str;
+    (void) conn; (void) str;
     errorMsg("Booted by server.\n");
     return -1;
 }
@@ -505,7 +504,7 @@
 typedef struct {
     char *cmd;
     ssize_t len;
-    int (*handler)(int, const char *);
+    int (*handler)(nn_conn_t *, const char *);
 } protocmd_t;
 
 
@@ -521,7 +520,7 @@
 static const int nprotoCmds = sizeof(protoCmds) / sizeof(protoCmds[0]);
 
 
-int handleProtocol(const int sock, const char *buf, const ssize_t bufLen)
+int handleProtocol(nn_conn_t *conn, const char *buf, const ssize_t bufLen)
 {
     static BOOL protoCmdsInit = FALSE;
     int i;
@@ -535,7 +534,7 @@
     for (i = 0; i < nprotoCmds; i++) {
         ssize_t cmdLen = protoCmds[i].len;
         if (cmdLen < bufLen && !strncmp(buf, protoCmds[i].cmd, cmdLen))
-            return protoCmds[i].handler(sock, buf + cmdLen);
+            return protoCmds[i].handler(conn, buf + cmdLen);
     }
 
     if (optDebug) {
@@ -556,7 +555,7 @@
     return strcasecmp((char *) s1, (char *) s2);
 }
 
-int handleUserInput(const int sock, char *buf, size_t bufLen)
+int handleUserInput(nn_conn_t *conn, char *buf, size_t bufLen)
 {
     char *tmpStr, tmpBuf[4096];
     BOOL result;
@@ -579,7 +578,7 @@
         }
         optUserColor = tmpInt;
         printMsg("Setting color to #%06x\n", optUserColor);
-        nn_send_msg(sock, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
+        nn_conn_send_msg(conn, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
         return 0;
     } else if (!strncasecmp(buf, "/ignore", 7)) {
         char *name = trimLeft(buf + 7);
@@ -675,7 +674,7 @@
     /* Send double-encoded */
     tmpStr = nn_dblencode_str(buf);
     if (tmpStr == 0) return -2;
-    result = nn_send_msg(sock, optUserName2, "%s", tmpStr);
+    result = nn_conn_send_msg(conn, optUserName2, "%s", tmpStr);
     th_free(tmpStr);
     
     return result ? 0 : -1;
@@ -804,9 +803,11 @@
     return FALSE;
 }
 
+
 int main(int argc, char *argv[])
 {
-    int tmpSocket = -1, curVis = ERR, updateCount = 0;
+    nn_conn_t *conn = NULL;
+    int curVis = ERR, updateCount = 0;
     struct hostent *tmpHost;
     BOOL argsOK, isError = FALSE,
         exitProg = FALSE,
@@ -815,10 +816,8 @@
         networkInit = FALSE,
         insertMode = TRUE;
     time_t prevTime;
-    struct timeval socktv;
-    fd_set sockfds;
     char *tmpStr;
-    nn_editbuf_t *editBuf = nn_editbuf_new(SET_BUFSIZE);
+    nn_editbuf_t *editBuf = nn_editbuf_new(NN_TMPBUF_SIZE);
     nn_editbuf_t *histBuf[SET_MAX_HISTORY+2];
     int histPos = 0, histMax = 0;
 
@@ -926,34 +925,39 @@
     /* To emulate the official client, we first make a request for
      * policy file, even though we don't use it for anything...
      */
-    if ((tmpSocket = nn_open_connection((struct in_addr *) tmpHost->h_addr, 843)) < 0) {
+    if ((conn = nn_conn_open((struct in_addr *) tmpHost->h_addr, 843)) == NULL) {
         THERR("Policy file request connection setup failed!\n");
         goto err_exit;
     }
-    
+    if (!nn_conn_check(conn))
+        goto err_exit;
+
     tmpStr = "<policy-file-request/>";
-    if (nn_send_to_socket(tmpSocket, tmpStr, strlen(tmpStr) + 1) == FALSE) {
+    if (nn_conn_send_buf(conn, tmpStr, strlen(tmpStr) + 1) == FALSE) {
         THERR("Failed to send policy file request.\n");
         goto err_exit;
     } else {
-        ssize_t gotBuf;
-        char tmpBuf[SET_BUFSIZE];
-        gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0);
-        tmpBuf[gotBuf-1] = 0;
-        THMSG(2, "Probe got: %s\n", tmpBuf);
-        nn_close_connection(tmpSocket);
+        int cres = nn_conn_pull(conn);
+        if (cres == 0) {
+            THMSG(2, "Probe got: %s\n", conn->buf);
+        } else {
+            THMSG(2, "Could not get policy probe.\n");
+        }
     }
+    nn_conn_close(conn);
 
     /* Okay, now do the proper connection ... */
-    if ((tmpSocket = nn_open_connection((struct in_addr *) tmpHost->h_addr, optPort)) < 0) {
+    if ((conn = nn_conn_open((struct in_addr *) tmpHost->h_addr, optPort)) == NULL) {
         THERR("Main connection setup failed!\n");
         goto err_exit;
     }
+    if (!nn_conn_check(conn))
+        goto err_exit;
     
     THMSG(1, "Connected, logging in as '%s', site '%s'.\n", optUserName, optSite);
     optUserName2 = nn_dblencode_str(optUserName);
     tmpStr = nn_dblencode_str(optSite);
-    nn_send_msg(tmpSocket, optUserName2, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword);
+    nn_conn_send_msg(conn, optUserName2, "%%2Flogin%%20%%2Dsite%%20%s%%20%%2Dpassword%%20%s", tmpStr, optPassword);
     th_free(tmpStr);
     
     /* Initialize NCurses */
@@ -1001,60 +1005,30 @@
 
     /* Enter mainloop */
     prevTime = time(NULL);
-    FD_ZERO(&sockfds);
-    FD_SET(tmpSocket, &sockfds);
 
     while (!isError && !exitProg) {
-        int result;
-        fd_set tmpfds;
-        
-        /* Check for incoming data from the server */
-        socktv.tv_sec = 0;
-        socktv.tv_usec = SET_DELAY_USEC;
-        tmpfds = sockfds;
-        if ((result = select(tmpSocket+1, &tmpfds, NULL, NULL, &socktv)) == -1) {
-            int res = nn_get_socket_errno();
-            if (res != EINTR) {
-                errorMsg("Error occured in select(sockfds): %d, %s\n",
-                    res, nn_get_socket_errstr(res));
-                isError = TRUE;
-            }
-        } else if (FD_ISSET(tmpSocket, &tmpfds)) {
-            ssize_t gotBuf;
-            char tmpBuf[8192];
-            char *bufPtr = tmpBuf;
-            gotBuf = recv(tmpSocket, tmpBuf, sizeof(tmpBuf), 0);
-            
-            if (gotBuf < 0) {
-                int res = nn_get_socket_errno();
-                errorMsg("Error in recv: %d, %s\n", res, nn_get_socket_errstr(res));
-                isError = TRUE;
-            } else if (gotBuf == 0) {
-                errorMsg("Server closed connection.\n");
-                isError = TRUE;
-            } else {
-                /* Handle protocol data */
-                tmpBuf[gotBuf] = 0;
-                do {
-                    size_t bufLen = strlen(bufPtr) + 1;
-                    result = handleProtocol(tmpSocket, bufPtr, bufLen);
-                
-                    if (result > 0) {
-                        /* Couldn't handle the message for some reason */
-                        printMsg("Could not handle: %s\n", tmpBuf);
-                    } else if (result < 0) {
-                        /* Fatal error, quit */
-                        errorMsg("Fatal error with message: %s\n", tmpBuf);
-                        isError = TRUE;
-                    }
-                    
-                    gotBuf -= bufLen;
-                    bufPtr += bufLen;
-                } while (gotBuf > 0 && !isError);
-                updateStatus(insertMode);
-            }
+        int cres = nn_conn_pull(conn);
+        if (cres == 0) {
+            do {
+                size_t bufLen = strlen(conn->ptr) + 1;
+                int result = handleProtocol(conn, conn->ptr, bufLen);
+
+                if (result > 0) {
+                    /* Couldn't handle the message for some reason */
+                    printMsg("Could not handle: %s\n", conn->ptr);
+                } else if (result < 0) {
+                    /* Fatal error, quit */
+                    errorMsg("Fatal error with message: %s\n", conn->ptr);
+                    isError = TRUE;
+                }
+
+                conn->got -= bufLen;
+                conn->ptr += bufLen;
+            } while (conn->got > 0 && !isError);
         }
-        
+        if (!nn_conn_check(conn))
+            isError = TRUE;
+
         /* Handle user input */
         if (!optDaemon) {
             int c, cnt = 0;
@@ -1103,6 +1077,7 @@
             case '\r':
                 /* Call the user input handler */
                 if (editBuf->len > 0) {
+                    int result;
                     
                     if (histMax > 0) {
                         nn_editbuf_free(histBuf[SET_MAX_HISTORY+1]);
@@ -1115,7 +1090,7 @@
                     if (histMax < SET_MAX_HISTORY) histMax++;
                     
                     nn_editbuf_insert(editBuf, editBuf->len, 0);
-                    result = handleUserInput(tmpSocket, editBuf->data, editBuf->len);
+                    result = handleUserInput(conn, editBuf->data, editBuf->len);
                     
                     nn_editbuf_clear(editBuf);
                     
@@ -1261,7 +1236,7 @@
         if (++updateCount > 10) {
             time_t tmpTime = time(NULL);
             if (tmpTime - prevTime > SET_KEEPALIVE) {
-                nn_send_msg(tmpSocket, optUserName2, "/listallusers"); 
+                nn_conn_send_msg(conn, optUserName2, "/listallusers"); 
                 prevTime = tmpTime;
             }
             
@@ -1270,7 +1245,7 @@
                 printMsg("%s v%s - %s\n", th_prog_name, th_prog_version, th_prog_fullname);
                 printMsg("%s\n", th_prog_author);
                 printMsg("%s\n", th_prog_license);
-                nn_send_msg(tmpSocket, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
+                nn_conn_send_msg(conn, optUserName2, "%%2FSetFontColor%%20%%2Dcolor%%20%06X", optUserColor);
             }
             
             updateStatus(insertMode);
@@ -1301,7 +1276,7 @@
     
     th_free(optUserName2);
 
-    nn_close_connection(tmpSocket);
+    nn_conn_close(conn);
     
     if (networkInit)
         nn_network_close();