comparison 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
comparison
equal deleted inserted replaced
167:b0b63d164702 168:2e4850ece456
4 * (C) Copyright 2008-2010 Tecnic Software productions (TNSP) 4 * (C) Copyright 2008-2010 Tecnic Software productions (TNSP)
5 */ 5 */
6 #include "libnnchat.h" 6 #include "libnnchat.h"
7 7
8 8
9 typedef struct {
10 char c;
11 char *ent;
12 } html_entity_t;
13
14
15 static const html_entity_t HTMLEntities[] = {
16 { '<', "&lt;" },
17 { '>', "&gt;" },
18 };
19
20 static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]);
21
22
23 #ifdef __WIN32 9 #ifdef __WIN32
24 const char *hstrerror(int err) 10 const char *hstrerror(int err)
25 { 11 {
26 static char buf[64]; 12 static char buf[64];
27 snprintf(buf, sizeof(buf), "Error #%d", err); 13 snprintf(buf, sizeof(buf), "Error #%d", err);
34 } 20 }
35 21
36 const char *nn_get_socket_errstr(int err) 22 const char *nn_get_socket_errstr(int err)
37 { 23 {
38 static char buf[64]; 24 static char buf[64];
39 snprintf(buf, sizeof(buf), "Error #%d", err); 25 switch (err) {
40 return buf; 26 case WSAEADDRINUSE: return "Address already in use";
27 case WSAECONNABORTED: return "Software caused connection abort";
28 case WSAECONNREFUSED: return "Connection refused";
29 case WSAECONNRESET: return "Connection reset by peer";
30 case WSAEHOSTUNREACH: return "No route to host";
31 case WSAENETDOWN: return "Network is down";
32 case WSAETIMEDOUT: return "Connection timed out";
33 case WSAHOST_NOT_FOUND: return "Host not found";
34 case WSAVERNOTSUPPORTED: return "Wrong WinSock DLL version";
35 default:
36 snprintf(buf, sizeof(buf), "Error #%d", err);
37 return buf;
38 break;
39 }
41 } 40 }
42 #else 41 #else
43 int nn_get_socket_errno(void) 42 int nn_get_socket_errno(void)
44 { 43 {
45 return errno; 44 return errno;
50 return strerror(err); 49 return strerror(err);
51 } 50 }
52 #endif 51 #endif
53 52
54 53
55 int nn_open_connection(struct in_addr *addr, const int port) 54 void nn_conn_err(nn_conn_t *conn, const char *fmt, ...)
56 { 55 {
57 struct sockaddr_in tmpAddr; 56 conn->err = TRUE;
58 int sock = -1; 57
59 58 if (conn->errfunc) {
60 tmpAddr.sin_family = AF_INET; 59 va_list ap;
61 tmpAddr.sin_port = htons(port); 60 va_start(ap, fmt);
62 tmpAddr.sin_addr = *addr; 61 conn->errfunc(conn, fmt, ap);
63 62 va_end(ap);
64 THMSG(1, "Connecting to %s:%d ...\n", 63 }
65 inet_ntoa(tmpAddr.sin_addr), port); 64 }
66 65
67 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) { 66
68 THERR("Could not open socket: %s\n", strerror(errno)); 67 static void nn_conn_msg(nn_conn_t *conn, const char *fmt, ...)
69 return -2; 68 {
70 } 69 if (conn->msgfunc) {
71 70 va_list ap;
72 THMSG(2, "Using socket %d.\n", sock); 71 va_start(ap, fmt);
73 72 conn->msgfunc(conn, fmt, ap);
74 if (connect(sock, (struct sockaddr *) &tmpAddr, sizeof(tmpAddr)) == -1) { 73 va_end(ap);
75 THERR("Could not connect: %s\n", strerror(errno)); 74 }
76 return -5; 75 }
77 } 76
78 77
79 return sock; 78 nn_conn_t *nn_conn_open(struct in_addr *addr, const int port)
80 } 79 {
81 80 nn_conn_t *conn = th_calloc(1, sizeof(nn_conn_t));
82 81 struct sockaddr_in dest;
83 void nn_close_connection(const int sock) 82
84 { 83 if (conn == NULL)
85 if (sock >= 0) { 84 return NULL;
85
86 dest.sin_family = AF_INET;
87 dest.sin_port = htons(port);
88 dest.sin_addr = *addr;
89
90 nn_conn_msg(conn, "Connecting to %s:%d ...\n",
91 inet_ntoa(dest.sin_addr), port);
92
93 if ((conn->socket = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
94 nn_conn_err(conn, "Could not open socket: %s\n", strerror(errno));
95 conn->status = NN_CONN_CLOSED;
96 return conn;
97 }
98
99 nn_conn_msg(conn, "Using socket %d.\n", conn->socket);
100
101 if (connect(conn->socket, (struct sockaddr *) &dest, sizeof(dest)) == -1) {
102 nn_conn_err(conn, "Could not connect: %s\n", strerror(errno));
103 conn->status = NN_CONN_CLOSED;
104 return conn;
105 }
106
107 conn->port = port;
108 conn->address = *addr;
109 FD_ZERO(&(conn->sockfds));
110 FD_SET(conn->socket, &(conn->sockfds));
111 conn->status = NN_CONN_OPEN;
112
113 return conn;
114 }
115
116
117 void nn_conn_close(nn_conn_t *conn)
118 {
119 if (conn == NULL)
120 return;
121
122 if (conn->socket >= 0) {
86 #ifdef __WIN32 123 #ifdef __WIN32
87 closesocket(sock); 124 closesocket(conn->socket);
88 #else 125 #else
89 close(sock); 126 close(conn->socket);
90 #endif 127 #endif
91 } 128 conn->socket = -1;
92 } 129 }
130
131 conn->status = NN_CONN_CLOSED;
132
133 th_free(conn);
134 }
135
136
137 BOOL nn_conn_send_buf(nn_conn_t *conn, const char *buf, const size_t len)
138 {
139 size_t bufLeft = len;
140 const char *bufPtr = buf;
141
142 while (bufLeft > 0) {
143 ssize_t bufSent;
144 bufSent = send(conn->socket, bufPtr, bufLeft, 0);
145 if (bufSent < 0) {
146 nn_conn_err(conn, "nn_conn_send_buf() failed: %s", strerror(errno));
147 return FALSE;
148 }
149 bufLeft -= bufSent;
150 bufPtr += bufSent;
151 }
152
153 return TRUE;
154 }
155
156
157 BOOL nn_conn_pull(nn_conn_t *conn)
158 {
159 int result;
160 struct timeval socktv;
161 fd_set tmpfds;
162
163 if (conn == NULL)
164 return -1;
165
166 conn->ptr = conn->buf;
167
168 /* Check for incoming data */
169 socktv.tv_sec = 0;
170 socktv.tv_usec = NN_DELAY_USEC;
171 tmpfds = conn->sockfds;
172
173 if ((result = select(conn->socket + 1, &tmpfds, NULL, NULL, &socktv)) == -1) {
174 int err = nn_get_socket_errno();
175 if (err != EINTR) {
176 nn_conn_err(conn, "Error occured in select(%d, sockfds): %d, %s\n",
177 socket, err, nn_get_socket_errstr(err));
178 return -1;
179 }
180 } else
181 if (FD_ISSET(conn->socket, &tmpfds)) {
182 conn->got = recv(conn->socket, conn->ptr, NN_CONNBUF_SIZE, 0);
183
184 if (conn->got < 0) {
185 int res = nn_get_socket_errno();
186 nn_conn_err(conn, "Error in recv: %d, %s\n", res, nn_get_socket_errstr(res));
187 return -2;
188 } else if (conn->got == 0) {
189 nn_conn_err(conn, "Server closed connection.\n");
190 conn->status = NN_CONN_CLOSED;
191 return -3;
192 } else {
193 /* Handle protocol data */
194 conn->buf[conn->got] = 0;
195 return 0;
196 }
197 }
198
199 return 1;
200 }
201
202 BOOL nn_conn_check(nn_conn_t *conn)
203 {
204 if (conn == NULL)
205 return FALSE;
206
207 return conn->err == 0 && conn->status == NN_CONN_OPEN;
208 }
209
93 210
94 211
95 BOOL nn_network_init(void) 212 BOOL nn_network_init(void)
96 { 213 {
97 #ifdef __WIN32 214 #ifdef __WIN32
113 WSACleanup(); 230 WSACleanup();
114 #endif 231 #endif
115 } 232 }
116 233
117 234
118 BOOL nn_send_to_socket(const int sock, char *buf, const size_t bufLen) 235 static BOOL bufRealloc(char **buf, size_t *size, size_t add)
119 {
120 size_t bufLeft = bufLen;
121 char *bufPtr = buf;
122
123 while (bufLeft > 0) {
124 ssize_t bufSent;
125 bufSent = send(sock, bufPtr, bufLeft, 0);
126 if (bufSent < 0) return FALSE;
127 bufLeft -= bufSent;
128 bufPtr += bufSent;
129 }
130 return TRUE;
131 }
132
133
134 BOOL bufRealloc(char **buf, size_t *size, size_t add)
135 { 236 {
136 return ((*buf = th_realloc(*buf, *size + add)) != NULL); 237 return ((*buf = th_realloc(*buf, *size + add)) != NULL);
137 } 238 }
138 239
139 #define PUSHCHAR(x) bufPushChar(&result, &resSize, &resPos, x) 240 #define PUSHCHAR(x) bufPushChar(&result, &resSize, &resPos, x)
140 BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch) 241 static BOOL bufPushChar(char **buf, size_t *size, size_t *pos, char ch)
141 { 242 {
142 if (*pos >= *size && !bufRealloc(buf, size, SET_ALLOC_SIZE)) 243 if (*pos >= *size && !bufRealloc(buf, size, NN_ALLOC_SIZE))
143 return FALSE; 244 return FALSE;
144 245
145 (*buf)[*pos] = ch; 246 (*buf)[*pos] = ch;
146 (*pos)++; 247 (*pos)++;
147 return TRUE; 248 return TRUE;
148 } 249 }
149 250
150 #define PUSHSTR(x) bufPushStr(&result, &resSize, &resPos, x) 251 #define PUSHSTR(x) bufPushStr(&result, &resSize, &resPos, x)
151 BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str) 252 static BOOL bufPushStr(char **buf, size_t *size, size_t *pos, char *str)
152 { 253 {
153 size_t tmpLen; 254 size_t tmpLen;
154 255
155 if (str == NULL) return FALSE; 256 if (str == NULL) return FALSE;
156 tmpLen = strlen(str); 257 tmpLen = strlen(str);
157 258
158 if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + SET_ALLOC_SIZE)) 259 if ((*pos + tmpLen) >= *size && !bufRealloc(buf, size, tmpLen + NN_ALLOC_SIZE))
159 return FALSE; 260 return FALSE;
160 261
161 strcpy(*buf + *pos, str); 262 strcpy(*buf + *pos, str);
162 (*pos) += tmpLen; 263 (*pos) += tmpLen;
163 return TRUE; 264 return TRUE;
170 char *result; 271 char *result;
171 size_t resSize, resPos = 0; 272 size_t resSize, resPos = 0;
172 273
173 if (str == NULL) return NULL; 274 if (str == NULL) return NULL;
174 275
175 resSize = strlen(str) + SET_ALLOC_SIZE; 276 resSize = strlen(str) + NN_ALLOC_SIZE;
176 if ((result = th_malloc(resSize)) == NULL) 277 if ((result = th_malloc(resSize)) == NULL)
177 return NULL; 278 return NULL;
178 279
179 while (*s) { 280 while (*s) {
180 switch (*s) { 281 switch (*s) {
225 size_t resSize, resPos = 0; 326 size_t resSize, resPos = 0;
226 int c; 327 int c;
227 328
228 if (str == NULL) return NULL; 329 if (str == NULL) return NULL;
229 330
230 resSize = strlen(str) + SET_ALLOC_SIZE; 331 resSize = strlen(str) + NN_ALLOC_SIZE;
231 if ((result = th_malloc(resSize)) == NULL) 332 if ((result = th_malloc(resSize)) == NULL)
232 return NULL; 333 return NULL;
233 334
234 while (*s) { 335 while (*s) {
235 switch (*s) { 336 switch (*s) {
286 char *result; 387 char *result;
287 size_t resSize, resPos = 0; 388 size_t resSize, resPos = 0;
288 389
289 if (str == NULL) return NULL; 390 if (str == NULL) return NULL;
290 391
291 resSize = strlen(str) + SET_ALLOC_SIZE; 392 resSize = strlen(str) + NN_ALLOC_SIZE;
292 if ((result = th_malloc(resSize)) == NULL) 393 if ((result = th_malloc(resSize)) == NULL)
293 return NULL; 394 return NULL;
294 395
295 while (*s) { 396 while (*s) {
296 if (*s == '<') { 397 if (*s == '<') {
303 404
304 return result; 405 return result;
305 } 406 }
306 407
307 408
409 typedef struct {
410 char c;
411 char *ent;
412 } html_entity_t;
413
414
415 static const html_entity_t HTMLEntities[] = {
416 { '<', "&lt;" },
417 { '>', "&gt;" },
418 };
419
420 static const int numHTMLEntities = sizeof(HTMLEntities) / sizeof(HTMLEntities[0]);
421
422
308 char *nn_encode_str2(const char *str) 423 char *nn_encode_str2(const char *str)
309 { 424 {
310 const char *s = str; 425 const char *s = str;
311 char *result; 426 char *result;
312 size_t resSize, resPos = 0; 427 size_t resSize, resPos = 0;
313 428
314 if (str == NULL) return NULL; 429 if (str == NULL) return NULL;
315 430
316 resSize = strlen(str) + SET_ALLOC_SIZE; 431 resSize = strlen(str) + NN_ALLOC_SIZE;
317 if ((result = th_malloc(resSize)) == NULL) 432 if ((result = th_malloc(resSize)) == NULL)
318 return NULL; 433 return NULL;
319 434
320 while (*s) { 435 while (*s) {
321 int i; 436 int i;
398 513
399 return res; 514 return res;
400 } 515 }
401 516
402 517
403 BOOL nn_send_msg(const int sock, const char *user, const char *fmt, ...) 518 BOOL nn_conn_send_msg(nn_conn_t *conn, const char *user, const char *fmt, ...)
404 { 519 {
405 char tmpBuf[SET_BUFSIZE], tmpBuf2[SET_BUFSIZE + 256]; 520 char *tmp, *msg;
406 int n;
407 va_list ap; 521 va_list ap;
408 522
409 va_start(ap, fmt); 523 va_start(ap, fmt);
410 n = vsnprintf(tmpBuf, sizeof(tmpBuf), fmt, ap); 524 tmp = th_strdup_vprintf(fmt, ap);
411 va_end(ap); 525 va_end(ap);
412 526
413 if (n < 0) return FALSE; 527 if (tmp == NULL)
414 528 return FALSE;
415 snprintf(tmpBuf2, sizeof(tmpBuf2), 529
416 "<USER>%s</USER><MESSAGE>%s</MESSAGE>", 530 msg = th_strdup_printf("<USER>%s</USER><MESSAGE>%s</MESSAGE>", user, tmp);
417 user, tmpBuf); 531 th_free(tmp);
418 532
419 return nn_send_to_socket(sock, tmpBuf2, strlen(tmpBuf2) + 1); 533 if (msg != NULL) {
534 BOOL ret = nn_conn_send_buf(conn, msg, strlen(msg) + 1);
535 th_free(msg);
536 return ret;
537 } else
538 return FALSE;
420 } 539 }
421 540
422 541
423 nn_ringbuf_t * nn_ringbuf_new(const size_t size) 542 nn_ringbuf_t * nn_ringbuf_new(const size_t size)
424 { 543 {
457 } 576 }
458 577
459 578
460 int nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch) 579 int nn_editbuf_write(nn_editbuf_t *buf, ssize_t pos, int ch)
461 { 580 {
462 /* Check arguments */
463 if (buf->len+1 >= buf->size) return -3; 581 if (buf->len+1 >= buf->size) return -3;
464 582
465 if (pos < 0) 583 if (pos < 0)
466 return -1; 584 return -1;
467 else if (pos >= buf->len) { 585 else if (pos >= buf->len) {
473 } 591 }
474 592
475 593
476 int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch) 594 int nn_editbuf_insert(nn_editbuf_t *buf, ssize_t pos, int ch)
477 { 595 {
478 /* Check arguments */
479 if (buf->len+1 >= buf->size) return -3; 596 if (buf->len+1 >= buf->size) return -3;
480 597
481 if (pos < 0) 598 if (pos < 0)
482 return -1; 599 return -1;
483 else if (pos >= buf->len) { 600 else if (pos >= buf->len) {
491 } 608 }
492 609
493 610
494 int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos) 611 int nn_editbuf_delete(nn_editbuf_t *buf, ssize_t pos)
495 { 612 {
496 /* Check arguments */
497 if (pos < 0) 613 if (pos < 0)
498 return -1; 614 return -1;
499 else if (pos < buf->len) { 615 else if (pos < buf->len) {
500 memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos); 616 memmove(&(buf->data[pos]), &(buf->data[pos+1]), buf->len - pos);
501 buf->len--; 617 buf->len--;
566 } else if (start <= end) { 682 } else if (start <= end) {
567 siz = end - start + 1; 683 siz = end - start + 1;
568 } else 684 } else
569 return NULL; 685 return NULL;
570 686
571 str = th_malloc(siz + 1); 687 if ((str = th_malloc(siz + 1)) == NULL)
688 return NULL;
689
572 memcpy(str, buf->data + start, siz); 690 memcpy(str, buf->data + start, siz);
573 str[siz] = 0; 691 str[siz] = 0;
692
574 return str; 693 return str;
575 } 694 }
576 695
577 696
578 void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos) 697 void nn_editbuf_setpos(nn_editbuf_t *buf, ssize_t pos)