1 /* IOSockets.c - IOMultiplexer v2
2 * Copyright (C) 2014 Philipp Kreil (pk910)
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #define _IOHandler_internals
18 #include "IOInternal.h"
19 #include "IOHandler.h"
20 #include "IOSockets.h"
22 #include "IODNSLookup.h"
25 static pthread_mutex_t iosocket_sync, iosocket_dns_sync;
28 static struct _IOSocket *iosocket_first = NULL;
29 static struct _IOSocket *iosocket_last = NULL;
32 extern struct IOEngine engine_select; /* select system call (should always be useable) */
33 extern struct IOEngine engine_kevent;
34 extern struct IOEngine engine_epoll;
35 extern struct IOEngine engine_win32;
37 struct IOEngine *engine = NULL;
40 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required);
41 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records);
42 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr);
43 static void iosocket_lookup_apply(struct _IOSocket *iosock, struct IODNSAddress *addr, int bindlookup);
44 static void iosocket_connect_finish(struct _IOSocket *iosock);
45 static void iosocket_listen_finish(struct _IOSocket *iosock);
50 static void iosockets_init_engine() {
52 if(!engine && engine_kevent.init && engine_kevent.init())
53 engine = &engine_kevent;
54 if(!engine && engine_epoll.init && engine_epoll.init())
55 engine = &engine_epoll;
56 if(!engine && engine_win32.init && engine_win32.init())
57 engine = &engine_win32;
60 if(engine_select.init())
61 engine = &engine_select;
63 iolog_trigger(IOLOG_FATAL, "found no useable IO engine");
67 iolog_trigger(IOLOG_DEBUG, "using %s IOSockets engine", engine->name);
70 void _init_sockets() {
71 IOTHREAD_MUTEX_INIT(iosocket_sync);
72 IOTHREAD_MUTEX_INIT(iosocket_dns_sync);
73 iosockets_init_engine();
77 struct _IOSocket _create_socket() {
78 struct _IOSocket *iosock = calloc(1, sizeof(*iosock));
80 iolog_trigger(IOLOG_ERROR, "could not allocate memory for _IOSocket in %s:%d", __FILE__, __LINE__);
83 IOSYNCHRONIZE(iosocket_sync);
85 iosocket_last->next = iosock;
87 iosocket_first = iosock;
88 iosock->prev = iosocket_last;
89 iosocket_last = iosock;
90 IODESYNCHRONIZE(iosocket_sync);
94 void _free_socket(struct _IOSocket *iosock) {
95 iosocket_deactivate(iosock);
96 IOSYNCHRONIZE(iosocket_sync);
98 iosock->prev->next = iosock->next;
100 iosocket_first = iosock->next;
102 iosock->next->prev = iosock->prev;
104 iosocket_last = iosock->prev;
105 IODESYNCHRONIZE(iosocket_sync);
107 if(iosock->bind.addr.addresslen)
108 free(iosock->bind.addr.address);
109 if(iosock->dest.addr.addresslen)
110 free(iosock->dest.addr.address);
111 if(iosock->readbuf.buffer)
112 free(iosock->readbuf.buffer);
113 if(iosock->writebuf.buffer)
114 free(iosock->writebuf.buffer);
119 static void iosocket_activate(struct _IOSocket *iosock) {
120 if((iosock->flags & IOSOCKETFLAG_ACTIVE))
122 iosock->flags |= IOSOCKETFLAG_ACTIVE;
126 static void iosocket_deactivate(struct _IOSocket *iosock) {
127 if(!(iosock->flags & IOSOCKETFLAG_ACTIVE))
129 iosock->flags &= ~IOSOCKETFLAG_ACTIVE;
130 engine->remove(iosock);
133 static void iosocket_increase_buffer(struct IOSocketBuffer *iobuf, size_t required) {
134 if(iobuf->buflen >= required) return;
135 char *new_buf = realloc(iobuf->buffer, required + 2);
137 iobuf->buffer = new_buf;
138 iobuf->buflen = required;
142 static int iosocket_parse_address(const char *hostname, struct IODNSAddress *addr, int records) {
144 if((flags & IOSOCKET_ADDR_IPV4)) {
145 struct sockaddr_in ip4addr;
146 ret = inet_pton(AF_INET, hostname, &(ip4addr.sin_addr));
148 addr->addresslen = sizeof(*ip4addr);
149 addr->address = malloc(addr->addresslen);
151 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
154 memcpy(addr->address, ip4addr, addr->addresslen);
158 if((flags & IOSOCKET_ADDR_IPV6)) {
159 struct sockaddr_in6 ip6addr;
160 ret = inet_pton(AF_INET6, hostname, &(ip6addr.sin6_addr));
162 addr->addresslen = sizeof(*ip6addr);
163 addr->address = malloc(addr->addresslen);
165 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__);
168 memcpy(addr->address, ip6addr, addr->addresslen);
175 static int iosocket_lookup_hostname(struct _IOSocket *iosock, const char *hostname, int records, int bindaddr) {
176 struct IOSocketDNSLookup *lookup = calloc(1, sizeof(*lookup));
178 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocketDNSLookup in %s:%d", __FILE__, __LINE__);
182 struct _IODNSQuery *query = _create_dnsquery();
188 query->parent = lookup;
189 query->flags |= IODNSFLAG_PARENT_SOCKET;
190 lookup->iosocket = iosocket;
191 lookup->query = query;
192 strncpy(lookup->hostname, hostname, sizeof(lookup->hostname));
193 lookup->hostname[sizeof(lookup->hostname)-1] = 0;
195 lookup->bindlookup = 1;
196 iosock->bind.addrlookup = lookup;
198 lookup->bindlookup = 0;
199 iosock->dest.addrlookup = lookup;
203 if((records & IOSOCKET_ADDR_IPV4))
204 dnsrecords |= IODNS_RECORD_A;
205 if((records & IOSOCKET_ADDR_IPV6))
206 dnsrecords |= IODNS_RECORD_AAAA;
208 query->request.host = strdup(hostname);
209 query->type = (dnsrecords & IODNS_FORWARD);
211 _start_dnsquery(query);
215 void iosocket_lookup_callback(struct IOSocketDNSLookup *lookup, struct IODNSEvent *event) {
216 lookup->query = NULL;
217 IOSYNCHRONIZE(iosocket_dns_sync);
218 struct _IOSocket *iosock = lookup->iosock;
220 IODESYNCHRONIZE(iosocket_dns_sync);
223 if(event->type == IODNSEVENT_SUCCESS)
224 lookup->result = event->result;
226 lookup->result = NULL;
228 if(lookup->bindlookup) {
229 iosock->flags &= ~IOSOCKETFLAG_PENDING_BINDDNS;
230 iosock->flags |= IOSOCKETFLAG_DNSDONE_BINDDNS;
232 iosock->flags &= ~IOSOCKETFLAG_PENDING_DESTDNS;
233 iosock->flags |= IOSOCKETFLAG_DNSDONE_DESTDNS;
236 int dns_finished = 0;
237 if((iosock->flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0)
239 IODESYNCHRONIZE(iosocket_dns_sync);
242 ret = iosocket_lookup_apply(iosock);
243 if(ret) { //if ret=0 an error occured in iosocket_lookup_apply and we should stop here.
244 if((iosock->flags & IOSOCKETFLAG_LISTENING))
245 iosocket_listen_finish(iosock);
247 iosocket_connect_finish(iosock);
252 static void iosocket_lookup_apply(struct _IOSocket *iosock) {
254 struct IOSocketDNSLookup *bind_lookup = ((iosock->flags & IOSOCKETFLAG_DNSDONE_BINDDNS) ? iosock->bind.addrlookup : NULL);
255 struct IOSocketDNSLookup *dest_lookup = ((iosock->flags & IOSOCKETFLAG_DNSDONE_DESTDNS) ? iosock->dest.addrlookup : NULL);
256 if(!bind_lookup && !dest_lookup) {
257 iosock->flags |= IOSOCKETFLAG_DNSERROR;
258 sprintf(errbuf, "Internal Error");
259 iolog_trigger(IOLOG_ERROR, "trying to apply lookup results without any lookups processed in %s:%d", __FILE__, __LINE__);
260 goto iosocket_lookup_clear;
263 struct IODNSResult *result;
264 int bind_numip4 = 0, bind_numip6 = 0;
265 int dest_numip4 = 0, dest_numip6 = 0;
268 for(result = bind_lookup->result; result; result = result->next) {
269 if((result->type & IODNS_RECORD_A))
271 if((result->type & IODNS_RECORD_AAAA))
276 for(result = dest_lookup->result; result; result = result->next) {
277 if((result->type & IODNS_RECORD_A))
279 if((result->type & IODNS_RECORD_AAAA))
285 if(bind_lookup && (bind_numip6 == 0 && bind_numip4 == 0)) {
286 iosock->flags |= IOSOCKETFLAG_DNSERROR;
287 sprintf(errbuf, "could not lookup bind address (%s)", bind_lookup->hostname);
288 goto iosocket_lookup_clear;
289 } else if(dest_lookup && (dest_numip6 == 0 && dest_numip4 == 0)) {
290 iosock->flags |= IOSOCKETFLAG_DNSERROR;
291 sprintf(errbuf, "could not lookup destination address (%s)", dest_lookup->hostname);
292 goto iosocket_lookup_clear;
293 } else if(bind_lookup && dest_lookup) {
294 if(bind_numip6 > 0 && dest_numip6 > 0)
296 else if(bind_numip4 > 0 && dest_numip4 > 0)
299 iosock->flags |= IOSOCKETFLAG_DNSERROR;
300 sprintf(errbuf, "could not lookup adresses of the same IP family for bind and destination host. (bind: %d ip4, %d ip6 | dest: %d ip4, %d ip6)", bind_numip4, bind_numip6, dest_numip4, dest_numip6);
301 goto iosocket_lookup_clear;
303 } else if(bind_lookup) {
308 } else if(dest_lookup) {
317 usetype = IODNS_RECORD_AAAA;
318 iosock->flags |= IOSOCKETFLAG_IPV6SOCKET;
320 usetype = IODNS_RECORD_A;
323 #define IOSOCKET_APPLY_COPYADDR(type) \
324 iosock->type.addr.addresslen = result->result.addr.addresslen; \
325 iosock->type.addr.address = malloc(result->result.addr.addresslen); \
326 if(!iosock->type.addr.address) { \
327 iolog_trigger(IOLOG_ERROR, "could not allocate memory for sockaddr in %s:%d", __FILE__, __LINE__); \
328 iosock->type.addr.addresslen = 0; \
329 iosock->flags |= IOSOCKETFLAG_DNSERROR; \
330 sprintf(errbuf, "could not allocate memory for dns information"); \
331 goto iosocket_lookup_clear; \
333 memcpy(iosock->type.addr.address, result->result.addr.address, result->result.addr.addresslen);
337 int usenum = (useip6 ? bind_numip6 : bind_numip4);
338 usenum = rand() % usenum;
339 for(result = bind_lookup->result; result; result = result->next) {
340 if((result->type & usetype)) {
342 IOSOCKET_APPLY_COPYADDR(bind)
349 iosock->bind.addr.addresslen = 0;
352 int usenum = (useip6 ? dest_numip6 : dest_numip4);
353 usenum = rand() % usenum;
354 for(result = dest_lookup->result; result; result = result->next) {
355 if((result->type & usetype)) {
357 IOSOCKET_APPLY_COPYADDR(dest)
364 iosock->dest.addr.addresslen = 0;
366 iosocket_lookup_clear:
368 if(bind_lookup->result)
369 iodns_free_result(bind_lookup->result);
373 if(bind_lookup->result)
374 iodns_free_result(dest_lookup->result);
378 if((iosock->flags & IOSOCKETFLAG_DNSERROR)) {
379 // TODO: trigger error
386 static void iosocket_connect_finish(struct _IOSocket *iosock) {
388 if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET))
389 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
391 sockfd = socket(AF_INET, SOCK_STREAM, 0);
393 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
394 // TODO: trigger error
399 // set port and bind address
400 if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET)) {
401 struct sockaddr_in6 *ip6 = iosock->dest.addr.address;
402 ip6->sin6_family = AF_INET6;
403 ip6->sin6_port = htons(iosock->port);
405 if(iosock->bind.addr.addresslen) {
406 struct sockaddr_in6 *ip6bind = iosock->bind.addr.address;
407 ip6bind->sin6_family = AF_INET6;
408 ip6bind->sin6_port = htons(0);
410 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
413 struct sockaddr_in *ip4 = iosock->dest.addr.address;
414 ip->sin_family = AF_INET;
415 ip->sin_port = htons(iosock->port);
417 if(iosock->bind.addr.addresslen) {
418 struct sockaddr_in *ip4bind = iosock->bind.addr.address;
419 ip4bind->sin_family = AF_INET;
420 ip4bind->sin6_port = htons(0);
422 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
428 #if defined(SO_NOSIGPIPE)
431 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
434 signal(SIGPIPE, SIG_IGN);
438 // make sockfd unblocking
442 fcntl_flags = fcntl(sockfd, F_GETFL);
443 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
444 fcntl_flags = fcntl(sockfd, F_GETFD);
445 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
448 /* I hope you're using the Win32 backend or something else that
449 * automatically marks the file descriptor non-blocking...
453 connect(sockfd, iosock->dest.addr.address, iosock->dest.addr.addresslen); //returns EINPROGRESS here (nonblocking)
456 iosocket_activate(iosock);
459 static void iosocket_listen_finish(struct _IOSocket *iosock) {
461 if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET))
462 sockfd = socket(AF_INET6, SOCK_STREAM, 0);
464 sockfd = socket(AF_INET, SOCK_STREAM, 0);
466 iolog_trigger(IOLOG_ERROR, "could not create socket in %s:%d", __FILE__, __LINE__);
467 // TODO: trigger error
472 // set port and bind address
473 if((iosock->flags & IOSOCKETFLAG_IPV6SOCKET)) {
474 struct sockaddr_in6 *ip6bind = iosock->bind.addr.address;
475 ip6bind->sin6_family = AF_INET6;
476 ip6bind->sin6_port = htons(0);
479 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
481 bind(sockfd, (struct sockaddr*)ip6bind, sizeof(*ip6bind));
483 struct sockaddr_in *ip4bind = iosock->bind.addr.address;
484 ip4bind->sin_family = AF_INET;
485 ip4bind->sin6_port = htons(0);
488 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
490 bind(sockfd, (struct sockaddr*)ip4bind, sizeof(*ip4bind));
495 #if defined(SO_NOSIGPIPE)
498 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
501 signal(SIGPIPE, SIG_IGN);
505 // make sockfd unblocking
509 fcntl_flags = fcntl(sockfd, F_GETFL);
510 fcntl(sockfd, F_SETFL, fcntl_flags|O_NONBLOCK);
511 fcntl_flags = fcntl(sockfd, F_GETFD);
512 fcntl(sockfd, F_SETFD, fcntl_flags|FD_CLOEXEC);
515 /* I hope you're using the Win32 backend or something else that
516 * automatically marks the file descriptor non-blocking...
523 iosocket_activate(iosock);
526 /* public functions */
528 struct IOSocket *iosocket_connect(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback) {
529 return iosocket_connect_flags(hostname, port, ssl, bindhost, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
532 struct IOSocket *iosocket_connect_flags(const char *hostname, unsigned int port, int ssl, const char *bindhost, iosocket_callback *callback, int flags) {
533 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
535 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
539 struct _IOSocket *iosock = _create_socket();
545 iodescriptor->iosocket = iosock;
546 iodescriptor->status = IOSOCKET_CONNECTING;
547 iodescriptor->callback = callback;
548 iosock->parent = iodescriptor;
549 iosock->flags |= IOSOCKETFLAG_PARENT_PUBLIC;
551 iosock->flags |= IOSOCKETFLAG_SSLSOCKET;
553 IOSYNCHRONIZE(iosocket_dns_sync);
555 switch(iosocket_parse_address(bindhost, &iosock->bind.addr, flags)) {
560 /* start dns lookup */
561 iosock->flags |= IOSOCKETFLAG_PENDING_BINDDNS;
562 iosocket_lookup_hostname(iosock, bindhost, flags, 1);
569 switch(iosocket_parse_address(hostname, &iosock->dest.addr, flags)) {
574 /* start dns lookup */
575 iosock->flags |= IOSOCKETFLAG_PENDING_DESTDNS;
576 iosocket_lookup_hostname(iosock, hostname, flags, 0);
582 IODESYNCHRONIZE(iosocket_dns_sync);
583 if((iosock->flags & (IOSOCKETFLAG_PENDING_BINDDNS | IOSOCKETFLAG_PENDING_DESTDNS)) == 0) {
584 iosocket_connect_finish(iosock);
589 struct IOSocket *iosocket_listen(const char *hostname, unsigned int port, iosocket_callback *callback) {
590 return iosocket_listen_flags(hostname, port, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
593 struct IOSocket *iosocket_listen_flags(const char *hostname, unsigned int port, iosocket_callback *callback, int flags) {
594 struct IOSocket *iodescriptor = calloc(1, sizeof(*iodescriptor));
596 iolog_trigger(IOLOG_ERROR, "could not allocate memory for IOSocket in %s:%d", __FILE__, __LINE__);
600 struct _IOSocket *iosock = _create_socket();
606 iodescriptor->iosocket = iosock;
607 iodescriptor->status = IOSOCKET_CONNECTING;
608 iodescriptor->callback = callback;
609 iosock->parent = iodescriptor;
610 iosock->flags |= IOSOCKETFLAG_PARENT_PUBLIC | IOSOCKETFLAG_LISTENING;
612 iosock->flags |= IOSOCKETFLAG_SSLSOCKET;
614 IOSYNCHRONIZE(iosocket_dns_sync);
615 switch(iosocket_parse_address(hostname, &iosock->bind.addr, flags)) {
620 /* start dns lookup */
621 iosock->flags |= IOSOCKETFLAG_PENDING_BINDDNS;
622 iosocket_lookup_hostname(iosock, hostname, flags, 1);
628 IODESYNCHRONIZE(iosocket_dns_sync);
629 if((iosock->flags & IOSOCKETFLAG_PENDING_BINDDNS) == 0) {
630 iosocket_listen_finish(iosock);
635 struct IOSocket *iosocket_listen_ssl(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback) {
636 return iosocket_listen_ssl_flags(hostname, port, certfile, keyfile, callback, (IOSOCKET_ADDR_IPV4 | IOSOCKET_ADDR_IPV6));
639 struct IOSocket *iosocket_listen_ssl_flags(const char *hostname, unsigned int port, const char *certfile, const char *keyfile, iosocket_callback *callback, int flags) {
644 void iosocket_close(struct IOSocket *iosocket) {
645 struct _IOSocket *iosock = iosocket->iosocket;
647 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
651 iosock->flags |= IOSOCKETFLAG_SHUTDOWN;
653 if(iosock->writebuf.bufpos) {
654 //try to send everything before closing
658 flags = fcntl(iosock->fd, F_GETFL);
659 fcntl(iosock->fd, F_SETFL, flags & ~O_NONBLOCK);
660 flags = fcntl(iosock->fd, F_GETFD);
661 fcntl(iosock->fd, F_SETFD, flags|FD_CLOEXEC);
664 iosocket_deactivate(iosock);
666 iosocket_try_write(iosock);
669 if(iosock->sslnode) {
673 _free_socket(iosock);
674 iosocket->iosocket = NULL;
675 iosocket->status = IOSOCKET_CLOSED;
679 static int iohandler_try_write(struct _IOSocket *iosock) {
680 if(!iosock->writebuf.bufpos) return 0;
681 iolog_trigger(IOLOG_DEBUG, "write writebuf (%d bytes) to socket (fd: %d)", iosock->writebuf.bufpos, iosock->fd);
683 if(iosock->sslnode) {
684 /* res = iohandler_ssl_write(iofd, iofd->writebuf.buffer, iofd->writebuf.bufpos); */
687 res = send(iosock->fd, iosock->writebuf.buffer, iosock->writebuf.bufpos, 0);
689 if (errno != EAGAIN && errno != EWOULDBLOCK)
690 iolog_trigger(IOLOG_ERROR, "could not write to socket (fd: %d): %d - %s", iosock->fd, errno, strerror(errno));
694 iosock->writebuf.bufpos -= res;
695 if((iosock->flags & (IOSOCKETFLAG_ACTIVE & IOSOCKETFLAG_SHUTDOWN)) == IOSOCKETFLAG_ACTIVE)
696 engine->update(iosock);
701 void iosocket_send(struct IOSocket *iosocket, const char *data, size_t datalen) {
702 struct _IOSocket *iosock = iosocket->iosocket;
704 iolog_trigger(IOLOG_WARNING, "called iosocket_close for destroyed IOSocket in %s:%d", __FILE__, __LINE__);
707 if(iosock->flags & IOSOCKETFLAG_SHUTDOWN) {
708 iolog_trigger(IOLOG_ERROR, "could not write to socket (socket is closing)");
711 iolog_trigger(IOLOG_DEBUG, "add %d to writebuf (fd: %d): %s", datalen, iosock->fd, data);
712 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
713 iolog_trigger(IOLOG_DEBUG, "increase writebuf (curr: %d) to %d (+%d bytes)", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
714 iosocket_increase_buffer(&iosock->writebuf, iosock->writebuf.bufpos + datalen);
715 if(iosock->writebuf.buflen < iosock->writebuf.bufpos + datalen) {
716 iolog_trigger(IOLOG_ERROR, "increase writebuf (curr: %d) to %d (+%d bytes) FAILED", iosock->writebuf.buflen, iosock->writebuf.bufpos + datalen, (iosock->writebuf.bufpos + datalen - iosock->writebuf.buflen));
720 memcpy(iosock->writebuf.buffer + iosock->writebuf.bufpos, data, datalen);
721 iosock->writebuf.bufpos += datalen;
722 if((iosock->flags & IOSOCKETFLAG_ACTIVE))
723 engine->update(iosock);
726 void iosocket_write(struct IOSocket *iosocket, const char *line) {
727 size_t linelen = strlen(line);
728 iohandler_send(iosocket, line, linelen);
731 void iosocket_printf(struct IOSocket *iosocket, const char *text, ...) {
733 char sendBuf[IOSOCKET_LINE_LEN];
736 va_start(arg_list, text);
737 pos = vsnprintf(sendBuf, IOSOCKET_LINE_LEN - 2, text, arg_list);
739 if (pos < 0 || pos > (IOSOCKET_LINE_LEN - 2)) pos = IOSOCKET_LINE_LEN - 2;
741 sendBuf[pos+1] = '\0';
742 iohandler_send(iosocket, sendBuf, pos+1);