Mercurial > hg > nnchat
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 { '<', "<" }, | |
17 { '>', ">" }, | |
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 { '<', "<" }, | |
417 { '>', ">" }, | |
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) |