Added test for uploading big files.
[elinks.git] / src / network / socket.c
blob304ba8f6f50e6fd94cbe89509c77238092659666
1 /* Sockets-o-matic */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <errno.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #ifdef HAVE_NETINET_IN_H
11 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
12 #endif
13 #ifdef HAVE_SYS_SOCKET_H
14 #include <sys/socket.h> /* OS/2 needs this after sys/types.h */
15 #endif
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h> /* OS/2 needs this after sys/types.h */
18 #endif
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22 #ifdef HAVE_WS2TCPIP_H
23 #include <ws2tcpip.h> /* socklen_t for MinGW */
24 #endif
26 #ifdef HAVE_GETIFADDRS
27 #ifdef HAVE_NETDB_H
28 #include <netdb.h>
29 #endif
30 #ifdef HAVE_NET_IF_H
31 #include <net/if.h>
32 #endif
33 #ifdef HAVE_IFADDRS_H
34 #include <ifaddrs.h> /* getifaddrs() */
35 #endif
36 #endif /* HAVE_GETIFADDRS */
38 #ifdef HAVE_ARPA_INET_H
39 #include <arpa/inet.h>
40 #endif
42 #include "elinks.h"
44 #include "config/options.h"
45 #include "main/select.h"
46 #include "network/connection.h"
47 #include "network/dns.h"
48 #include "network/socket.h"
49 #include "network/ssl/socket.h"
50 #include "osdep/osdep.h"
51 #include "osdep/getifaddrs.h"
52 #include "protocol/protocol.h"
53 #include "protocol/uri.h"
54 #include "util/error.h"
55 #include "util/memory.h"
56 #include "util/string.h"
59 /* Holds information used during the connection establishing phase. */
60 struct connect_info {
61 struct sockaddr_storage *addr; /* Array of found addresses. */
62 int addrno; /* Number of found addresses. */
63 int triedno; /* Index of last tried address */
64 socket_connect_T done; /* Callback signaled when connected. */
65 void *dnsquery; /* Pointer to DNS query info. */
66 int port; /* Which port to bind to. */
67 int ip_family; /* If non-zero, force to IP version. */
71 /* To enable logging of tranfers, for debugging purposes. */
72 #if 0
74 #define DEBUG_TRANSFER_LOGFILE "/tmp/log"
76 static void
77 debug_transfer_log(unsigned char *data, int len)
79 int fd = open(DEBUG_TRANSFER_LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0622);
81 if (fd == -1) return;
83 set_bin(fd);
84 write(fd, data, len < 0 ? strlen(data) : len);
85 close(fd);
87 #undef DEBUG_TRANSFER_LOGFILE
89 #else
90 #define debug_transfer_log(data, len)
91 #endif
94 static struct connect_info *
95 init_connection_info(struct uri *uri, struct socket *socket,
96 socket_connect_T connect_done)
98 struct connect_info *connect_info = mem_calloc(1, sizeof(*connect_info));
100 if (!connect_info) return NULL;
102 connect_info->done = connect_done;
103 connect_info->port = get_uri_port(uri);
104 connect_info->ip_family = uri->ip_family;
105 connect_info->triedno = -1;
106 connect_info->addr = NULL;
108 return connect_info;
111 static void
112 done_connection_info(struct socket *socket)
114 struct connect_info *connect_info = socket->connect_info;
116 assert(socket->connect_info);
118 if (connect_info->dnsquery) kill_dns_request(&connect_info->dnsquery);
120 mem_free_if(connect_info->addr);
121 mem_free_set(&socket->connect_info, NULL);
124 struct socket *
125 init_socket(void *conn, struct socket_operations *ops)
127 struct socket *socket;
129 socket = mem_calloc(1, sizeof(*socket));
130 if (!socket) return NULL;
132 socket->fd = -1;
133 socket->conn = conn;
134 socket->ops = ops;
136 return socket;
139 void
140 done_socket(struct socket *socket)
142 close_socket(socket);
144 if (socket->connect_info)
145 done_connection_info(socket);
147 mem_free_set(&socket->read_buffer, NULL);
148 mem_free_set(&socket->write_buffer, NULL);
151 void
152 close_socket(struct socket *socket)
154 if (socket->fd == -1) return;
155 #ifdef CONFIG_SSL
156 if (socket->ssl) ssl_close(socket);
157 #endif
158 close(socket->fd);
159 clear_handlers(socket->fd);
160 socket->fd = -1;
163 void
164 dns_exception(struct socket *socket)
166 connect_socket(socket, S_EXCEPT);
169 static void
170 exception(struct socket *socket)
172 socket->ops->retry(socket, S_EXCEPT);
176 void
177 timeout_socket(struct socket *socket)
179 if (!socket->connect_info) {
180 socket->ops->retry(socket, S_TIMEOUT);
181 return;
184 /* Is the DNS resolving still in progress? */
185 if (socket->connect_info->dnsquery) {
186 socket->ops->done(socket, S_TIMEOUT);
187 return;
190 /* Try the next address, */
191 connect_socket(socket, S_TIMEOUT);
193 /* Reset the timeout if connect_socket() started a new attempt
194 * to connect. */
195 if (socket->connect_info)
196 socket->ops->set_timeout(socket, 0);
200 /* DNS callback. */
201 static void
202 dns_found(struct socket *socket, struct sockaddr_storage *addr, int addrlen)
204 struct connect_info *connect_info = socket->connect_info;
205 int size;
207 if (!addr) {
208 socket->ops->done(socket, S_NO_DNS);
209 return;
212 assert(connect_info);
214 size = sizeof(*addr) * addrlen;
216 connect_info->addr = mem_alloc(size);
217 if (!connect_info->addr) {
218 socket->ops->done(socket, S_OUT_OF_MEM);
219 return;
222 memcpy(connect_info->addr, addr, size);
223 connect_info->addrno = addrlen;
225 /* XXX: Passing non-result state here is bad but a lack of alternatives
226 * makes it so. Well adding get_state() socket operation could maybe fix
227 * it but the returned state would most likely be a non-result one at
228 * this point in the connection lifecycle. This will, however, only be a
229 * problem if connect_socket() fails without doing any system calls
230 * which is only the case when forcing the IP family. So it is better to
231 * handle it in connect_socket(). */
232 connect_socket(socket, S_CONN);
235 void
236 make_connection(struct socket *socket, struct uri *uri,
237 socket_connect_T connect_done, int no_cache)
239 unsigned char *host = get_uri_string(uri, URI_DNS_HOST);
240 struct connect_info *connect_info;
241 enum dns_result result;
243 socket->ops->set_timeout(socket, 0);
245 if (!host) {
246 socket->ops->retry(socket, S_OUT_OF_MEM);
247 return;
250 connect_info = init_connection_info(uri, socket, connect_done);
251 if (!connect_info) {
252 mem_free(host);
253 socket->ops->retry(socket, S_OUT_OF_MEM);
254 return;
257 socket->connect_info = connect_info;
258 /* XXX: Keep here and not in init_connection_info() to make
259 * complete_connect_socket() work from the HTTP implementation. */
260 socket->need_ssl = get_protocol_need_ssl(uri->protocol);
262 debug_transfer_log("\nCONNECTION: ", -1);
263 debug_transfer_log(host, -1);
264 debug_transfer_log("\n", -1);
266 result = find_host(host, &connect_info->dnsquery, (dns_callback_T) dns_found,
267 socket, no_cache);
269 mem_free(host);
271 if (result == DNS_ASYNC)
272 socket->ops->set_state(socket, S_DNS);
276 /* Returns negative if error, otherwise pasv socket's fd. */
278 get_pasv_socket(struct socket *ctrl_socket, struct sockaddr_storage *addr)
280 struct sockaddr_in bind_addr4;
281 struct sockaddr *bind_addr;
282 struct sockaddr *pasv_addr = (struct sockaddr *) addr;
283 size_t addrlen;
284 int sock = -1;
285 int syspf; /* Protocol Family given to system, not EL_PF_... */
286 socklen_t len;
287 #ifdef CONFIG_IPV6
288 struct sockaddr_in6 bind_addr6;
290 if (ctrl_socket->protocol_family == EL_PF_INET6) {
291 bind_addr = (struct sockaddr *) &bind_addr6;
292 addrlen = sizeof(bind_addr6);
293 syspf = PF_INET6;
294 } else
295 #endif
297 bind_addr = (struct sockaddr *) &bind_addr4;
298 addrlen = sizeof(bind_addr4);
299 syspf = PF_INET;
302 memset(pasv_addr, 0, addrlen);
303 memset(bind_addr, 0, addrlen);
305 /* Get our endpoint of the control socket */
306 len = addrlen;
307 if (getsockname(ctrl_socket->fd, pasv_addr, &len)) {
308 sock_error:
309 if (sock != -1) close(sock);
310 ctrl_socket->ops->retry(ctrl_socket, -errno);
311 return -1;
314 /* Get a passive socket */
316 sock = socket(syspf, SOCK_STREAM, IPPROTO_TCP);
317 if (sock < 0)
318 goto sock_error;
320 /* Set it non-blocking */
322 if (set_nonblocking_fd(sock) < 0)
323 goto sock_error;
325 /* Bind it to some port */
327 memcpy(bind_addr, pasv_addr, addrlen);
328 #ifdef CONFIG_IPV6
329 if (ctrl_socket->protocol_family == EL_PF_INET6)
330 bind_addr6.sin6_port = 0;
331 else
332 #endif
333 bind_addr4.sin_port = 0;
335 if (bind(sock, bind_addr, addrlen))
336 goto sock_error;
338 /* Get our endpoint of the passive socket and save it to port */
340 len = addrlen;
341 if (getsockname(sock, pasv_addr, &len))
342 goto sock_error;
344 /* Go listen */
346 if (listen(sock, 1))
347 goto sock_error;
349 set_ip_tos_throughput(sock);
351 return sock;
354 #ifdef CONFIG_IPV6
355 static inline int
356 check_if_local_address6(struct sockaddr_in6 *addr)
358 struct ifaddrs *ifaddrs;
359 int local = IN6_IS_ADDR_LOOPBACK(&(addr->sin6_addr));
361 if (!local && !getifaddrs(&ifaddrs)) {
362 struct ifaddrs *ifa;
364 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
365 if (!ifa->ifa_addr)
366 continue;
368 if (ifa->ifa_addr->sa_family == AF_INET6
369 && !memcmp(&addr->sin6_addr.s6_addr,
370 &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr.s6_addr,
371 sizeof(addr->sin6_addr.s6_addr))) {
372 local = 1;
373 break;
376 if (ifa->ifa_addr->sa_family == AF_INET
377 && !memcmp(&((struct sockaddr_in *) &addr)->sin_addr.s_addr,
378 &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr,
379 sizeof(((struct sockaddr_in *) &addr)->sin_addr.s_addr))) {
380 local = 1;
381 break;
385 freeifaddrs(ifaddrs);
388 return local;
390 #endif /* CONFIG_IPV6 */
392 static inline int
393 check_if_local_address4(struct sockaddr_in *addr)
395 struct ifaddrs *ifaddrs;
396 int local = (ntohl(addr->sin_addr.s_addr) >> 24) == IN_LOOPBACKNET;
398 if (!local && !getifaddrs(&ifaddrs)) {
399 struct ifaddrs *ifa;
401 for (ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
402 if (!ifa->ifa_addr)
403 continue;
405 if (ifa->ifa_addr->sa_family != AF_INET) continue;
407 if (!memcmp(&addr->sin_addr.s_addr,
408 &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr,
409 sizeof(addr->sin_addr.s_addr))) {
410 local = 1;
411 break;
415 freeifaddrs(ifaddrs);
418 return local;
422 void
423 complete_connect_socket(struct socket *socket, struct uri *uri,
424 socket_connect_T done)
426 struct connect_info *connect_info = socket->connect_info;
428 /* This is a special case used by the HTTP implementation to acquire an
429 * SSL link for handling CONNECT requests. */
430 if (!connect_info) {
431 assert(uri && socket);
432 connect_info = init_connection_info(uri, socket, done);
433 if (!connect_info) {
434 socket->ops->done(socket, S_OUT_OF_MEM);
435 return;
438 socket->connect_info = connect_info;
441 #ifdef CONFIG_SSL
442 /* Check if the connection should run over an encrypted link */
443 if (socket->need_ssl
444 && !socket->ssl
445 && ssl_connect(socket) < 0)
446 return;
447 #endif
449 if (connect_info->done)
450 connect_info->done(socket);
452 done_connection_info(socket);
455 /* Select handler which is set for the socket descriptor when connect() has
456 * indicated (via errno) that it is in progress. On completion this handler gets
457 * called. */
458 static void
459 connected(struct socket *socket)
461 int err = 0;
462 socklen_t len = sizeof(err);
464 assertm(socket->connect_info != NULL, "Lost connect_info!");
465 if_assert_failed return;
467 if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == 0) {
468 /* Why does EMX return so large values? */
469 if (err >= 10000) err -= 10000;
470 } else {
471 /* getsockopt() failed */
472 if (errno > 0)
473 err = errno;
474 else
475 err = -(S_STATE);
478 if (err > 0) {
479 /* There are maybe still some more candidates. */
480 connect_socket(socket, -err);
481 return;
484 complete_connect_socket(socket, NULL, NULL);
487 void
488 connect_socket(struct socket *csocket, enum connection_state state)
490 int sock = -1;
491 struct connect_info *connect_info = csocket->connect_info;
492 int i;
493 int trno = connect_info->triedno;
494 int only_local = get_cmd_opt_bool("localhost");
495 int saved_errno = 0;
496 int at_least_one_remote_ip = 0;
497 #ifdef CONFIG_IPV6
498 int try_ipv6 = get_opt_bool("connection.try_ipv6", NULL);
499 #endif
500 int try_ipv4 = get_opt_bool("connection.try_ipv4", NULL);
501 /* We tried something but we failed in such a way that we would rather
502 * prefer the connection to retain the information about previous
503 * failures. That is, we i.e. decided we are forbidden to even think
504 * about such a connection attempt.
505 * XXX: Unify with @local_only handling? --pasky */
506 int silent_fail = 0;
508 csocket->ops->set_state(csocket, state);
510 /* Clear handlers, the connection to the previous RR really timed
511 * out and doesn't interest us anymore. */
512 if (csocket->fd >= 0)
513 close_socket(csocket);
515 for (i = connect_info->triedno + 1; i < connect_info->addrno; i++) {
516 #ifdef CONFIG_IPV6
517 struct sockaddr_in6 addr = *((struct sockaddr_in6 *) &connect_info->addr[i]);
518 int family = addr.sin6_family;
519 #else
520 struct sockaddr_in addr = *((struct sockaddr_in *) &connect_info->addr[i]);
521 int family = addr.sin_family;
522 #endif
523 int pf;
524 int force_family = connect_info->ip_family;
526 connect_info->triedno++;
528 if (only_local) {
529 int local = 0;
530 #ifdef CONFIG_IPV6
531 if (family == AF_INET6)
532 local = check_if_local_address6((struct sockaddr_in6 *) &addr);
533 else
534 #endif
535 local = check_if_local_address4((struct sockaddr_in *) &addr);
537 /* This forbids connections to anything but local, if option is set. */
538 if (!local) {
539 at_least_one_remote_ip = 1;
540 continue;
544 #ifdef CONFIG_IPV6
545 if (family == AF_INET6) {
546 if (!try_ipv6 || (force_family && force_family != 6)) {
547 silent_fail = 1;
548 continue;
550 pf = PF_INET6;
552 } else
553 #endif
554 if (family == AF_INET) {
555 if (!try_ipv4 || (force_family && force_family != 4)) {
556 silent_fail = 1;
557 continue;
559 pf = PF_INET;
561 } else {
562 continue;
564 silent_fail = 0;
566 sock = socket(pf, SOCK_STREAM, IPPROTO_TCP);
567 if (sock == -1) {
568 if (errno && !saved_errno) saved_errno = errno;
569 continue;
572 if (set_nonblocking_fd(sock) < 0) {
573 if (errno && !saved_errno) saved_errno = errno;
574 close(sock);
575 continue;
577 csocket->fd = sock;
579 #ifdef CONFIG_IPV6
580 addr.sin6_port = htons(connect_info->port);
581 #else
582 addr.sin_port = htons(connect_info->port);
583 #endif
585 /* We can set csocket->protocol_family here even if the connection
586 * will fail, as we will use it only when it will be successfully
587 * established. At least I hope that noone else will want to do
588 * something else ;-). --pasky */
589 /* And in fact we must set it early, because of EINPROGRESS. */
591 #ifdef CONFIG_IPV6
592 if (family == AF_INET6) {
593 csocket->protocol_family = EL_PF_INET6;
594 if (connect(sock, (struct sockaddr *) &addr,
595 sizeof(struct sockaddr_in6)) == 0) {
596 /* Success */
597 complete_connect_socket(csocket, NULL, NULL);
598 return;
600 } else
601 #endif
603 csocket->protocol_family = EL_PF_INET;
604 if (connect(sock, (struct sockaddr *) &addr,
605 sizeof(struct sockaddr_in)) == 0) {
606 /* Success */
607 complete_connect_socket(csocket, NULL, NULL);
608 return;
612 if (errno == EALREADY
613 #ifdef EWOULDBLOCK
614 || errno == EWOULDBLOCK
615 #endif
616 || errno == EINPROGRESS) {
617 /* It will take some more time... */
618 set_handlers(sock, NULL, (select_handler_T) connected,
619 (select_handler_T) dns_exception, csocket);
620 csocket->ops->set_state(csocket, S_CONN);
621 return;
624 if (errno && !saved_errno) saved_errno = errno;
626 close(sock);
629 assert(i >= connect_info->addrno);
631 /* Tried everything, but it didn't help :(. */
633 if (only_local && !saved_errno && at_least_one_remote_ip) {
634 /* Yes we might hit a local address and fail in the process, but
635 * what matters is the last one because we do not know the
636 * previous one's errno, and the added complexity wouldn't
637 * really be worth it. */
638 csocket->ops->done(csocket, S_LOCAL_ONLY);
639 return;
642 /* Retry reporting the errno state only if we already tried something
643 * new. Else use the S_DNS _progress_ state to make sure that no
644 * download callbacks will report any errors. */
645 if (trno != connect_info->triedno && !silent_fail)
646 state = -errno;
647 else if (trno == -1 && silent_fail)
648 /* All failed. */
649 state = S_NO_FORCED_DNS;
651 csocket->ops->retry(csocket, state);
655 struct write_buffer {
656 /* A routine called when all the data is sent (therefore this is
657 * _different_ from read_buffer.done !). */
658 socket_write_T done;
660 int length;
661 int pos;
663 unsigned char data[1]; /* must be at end of struct */
666 static int
667 generic_write(struct socket *socket, unsigned char *data, int len)
669 int wr = safe_write(socket->fd, data, len);
671 if (!wr) return SOCKET_CANT_WRITE;
673 return wr < 0 ? SOCKET_SYSCALL_ERROR : wr;
676 static void
677 write_select(struct socket *socket)
679 struct write_buffer *wb = socket->write_buffer;
680 int wr;
682 assertm(wb != NULL, "write socket has no buffer");
683 if_assert_failed {
684 socket->ops->done(socket, S_INTERNAL);
685 return;
688 /* We are making some progress, therefore reset the timeout; ie. when
689 * uploading large files the time needed for all the data to be sent can
690 * easily exceed the timeout. */
691 socket->ops->set_timeout(socket, 0);
693 #if 0
694 printf("ws: %d\n",wb->length-wb->pos);
695 for (wr = wb->pos; wr < wb->length; wr++) printf("%c", wb->data[wr]);
696 printf("-\n");
697 #endif
699 #ifdef CONFIG_SSL
700 if (socket->ssl) {
701 wr = ssl_write(socket, wb->data + wb->pos, wb->length - wb->pos);
702 } else
703 #endif
705 assert(wb->length - wb->pos > 0);
706 wr = generic_write(socket, wb->data + wb->pos, wb->length - wb->pos);
709 switch (wr) {
710 case SOCKET_CANT_WRITE:
711 socket->ops->retry(socket, S_CANT_WRITE);
712 break;
714 case SOCKET_SYSCALL_ERROR:
715 socket->ops->retry(socket, -errno);
716 break;
718 case SOCKET_INTERNAL_ERROR:
719 /* The global errno variable is used for passing
720 * internal connection_state error value. */
721 socket->ops->done(socket, -errno);
722 break;
724 default:
725 if (wr < 0) break;
727 /*printf("wr: %d\n", wr);*/
728 wb->pos += wr;
730 if (wb->pos == wb->length) {
731 socket_write_T done = wb->done;
733 if (!socket->duplex) {
734 clear_handlers(socket->fd);
736 } else {
737 select_handler_T read_handler;
738 select_handler_T error_handler;
740 read_handler = get_handler(socket->fd, SELECT_HANDLER_READ);
741 error_handler = read_handler
742 ? (select_handler_T) exception
743 : NULL;
745 set_handlers(socket->fd, read_handler, NULL,
746 error_handler, socket);
749 mem_free_set(&socket->write_buffer, NULL);
750 done(socket);
755 void
756 write_to_socket(struct socket *socket, unsigned char *data, int len,
757 enum connection_state state, socket_write_T write_done)
759 select_handler_T read_handler;
760 struct write_buffer *wb;
762 debug_transfer_log(data, len);
764 assert(len > 0);
765 if_assert_failed return;
767 socket->ops->set_timeout(socket, 0);
769 wb = mem_alloc(sizeof(*wb) + len);
770 if (!wb) {
771 socket->ops->done(socket, S_OUT_OF_MEM);
772 return;
775 wb->length = len;
776 wb->pos = 0;
777 wb->done = write_done;
778 memcpy(wb->data, data, len);
779 mem_free_set(&socket->write_buffer, wb);
781 if (socket->duplex) {
782 read_handler = get_handler(socket->fd, SELECT_HANDLER_READ);
783 } else {
784 read_handler = NULL;
787 set_handlers(socket->fd, read_handler, (select_handler_T) write_select,
788 (select_handler_T) exception, socket);
789 socket->ops->set_state(socket, state);
792 #define RD_ALLOC_GR (2<<11) /* 4096 */
793 #define RD_MEM(rb) (sizeof(*(rb)) + 4 * RD_ALLOC_GR + RD_ALLOC_GR)
794 #define RD_SIZE(rb, len) ((RD_MEM(rb) + (len)) & ~(RD_ALLOC_GR - 1))
796 static ssize_t
797 generic_read(struct socket *socket, unsigned char *data, int len)
799 ssize_t rd = safe_read(socket->fd, data, len);
801 if (!rd) return SOCKET_CANT_READ;
803 return rd < 0 ? SOCKET_SYSCALL_ERROR : rd;
806 static void
807 read_select(struct socket *socket)
809 struct read_buffer *rb = socket->read_buffer;
810 ssize_t rd;
812 assertm(rb != NULL, "read socket has no buffer");
813 if_assert_failed {
814 socket->ops->done(socket, S_INTERNAL);
815 return;
818 /* We are making some progress, therefore reset the timeout; we do this
819 * for read_select() to avoid that the periodic calls to user handlers
820 * has to do it. */
821 socket->ops->set_timeout(socket, 0);
823 if (!socket->duplex)
824 clear_handlers(socket->fd);
826 if (!rb->freespace) {
827 int size = RD_SIZE(rb, rb->length);
829 rb = mem_realloc(rb, size);
830 if (!rb) {
831 socket->ops->done(socket, S_OUT_OF_MEM);
832 return;
834 rb->freespace = size - sizeof(*rb) - rb->length;
835 assert(rb->freespace > 0);
836 socket->read_buffer = rb;
839 #ifdef CONFIG_SSL
840 if (socket->ssl) {
841 rd = ssl_read(socket, rb->data + rb->length, rb->freespace);
842 } else
843 #endif
845 rd = generic_read(socket, rb->data + rb->length, rb->freespace);
848 switch (rd) {
849 #ifdef CONFIG_SSL
850 case SOCKET_SSL_WANT_READ:
851 read_from_socket(socket, rb, S_TRANS, rb->done);
852 break;
853 #endif
854 case SOCKET_CANT_READ:
855 if (socket->state != SOCKET_RETRY_ONCLOSE) {
856 socket->state = SOCKET_CLOSED;
857 rb->done(socket, rb);
858 break;
861 errno = -S_CANT_READ;
862 /* Fall-through */
864 case SOCKET_SYSCALL_ERROR:
865 socket->ops->retry(socket, -errno);
866 break;
868 case SOCKET_INTERNAL_ERROR:
869 socket->ops->done(socket, -errno);
870 break;
872 default:
873 debug_transfer_log(rb->data + rb->length, rd);
875 rb->length += rd;
876 rb->freespace -= rd;
877 assert(rb->freespace >= 0);
879 rb->done(socket, rb);
883 struct read_buffer *
884 alloc_read_buffer(struct socket *socket)
886 struct read_buffer *rb;
888 rb = mem_calloc(1, RD_SIZE(rb, 0));
889 if (!rb) {
890 socket->ops->done(socket, S_OUT_OF_MEM);
891 return NULL;
894 rb->freespace = RD_SIZE(rb, 0) - sizeof(*rb);
896 return rb;
899 #undef RD_ALLOC_GR
900 #undef RD_MEM
901 #undef RD_SIZE
903 void
904 read_from_socket(struct socket *socket, struct read_buffer *buffer,
905 enum connection_state state, socket_read_T done)
907 select_handler_T write_handler;
909 buffer->done = done;
911 socket->ops->set_timeout(socket, 0);
912 socket->ops->set_state(socket, state);
914 if (socket->read_buffer && buffer != socket->read_buffer)
915 mem_free(socket->read_buffer);
916 socket->read_buffer = buffer;
918 if (socket->duplex) {
919 write_handler = get_handler(socket->fd, SELECT_HANDLER_WRITE);
920 } else {
921 write_handler = NULL;
924 set_handlers(socket->fd, (select_handler_T) read_select, write_handler,
925 (select_handler_T) exception, socket);
928 static void
929 read_response_from_socket(struct socket *socket)
931 struct read_buffer *rb = alloc_read_buffer(socket);
933 if (rb) read_from_socket(socket, rb, S_SENT, socket->read_done);
936 void
937 request_from_socket(struct socket *socket, unsigned char *data, int datalen,
938 enum connection_state state, enum socket_state sock_state,
939 socket_read_T read_done)
941 socket->read_done = read_done;
942 socket->state = sock_state;
943 write_to_socket(socket, data, datalen, state,
944 read_response_from_socket);
947 void
948 kill_buffer_data(struct read_buffer *rb, int n)
950 assertm(n >= 0 && n <= rb->length, "bad number of bytes: %d", n);
951 if_assert_failed { rb->length = 0; return; }
953 if (!n) return; /* FIXME: We accept to kill 0 bytes... */
954 rb->length -= n;
955 memmove(rb->data, rb->data + n, rb->length);
956 rb->freespace += n;