Mercurial > hg > nnchat
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[] = { - { '<', "<" }, - { '>', ">" }, -}; - -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[] = { + { '<', "<" }, + { '>', ">" }, +}; + +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; }