1 /*
2 * Socket handling routines
3 *
4 * Copyright (C) 2003, Olaf Kirch <okir@suse.de>
5 */
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 #include <sys/types.h>
11 #include <netinet/in.h>
12 #include <sys/socket.h>
13 #include <sys/stat.h>
14 #include <sys/poll.h>
15 #include <sys/un.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <arpa/inet.h>
24 #include <netdb.h>
25 #include <limits.h>
26
27 #include <openct/logging.h>
28 #include <openct/socket.h>
29 #include <openct/path.h>
30 #include <openct/error.h>
31
32 static unsigned int ifd_xid = 1;
33 static int ifd_reuse_addr = 0;
34
min(unsigned int a,unsigned int b)35 static inline unsigned int min(unsigned int a, unsigned int b)
36 {
37 return (a < b) ? a : b;
38 }
39
40 static int ct_socket_default_recv_cb(ct_socket_t *);
41 static int ct_socket_default_send_cb(ct_socket_t *);
42 static int ct_socket_getcreds(ct_socket_t *);
43
44 /*
45 * Create a socket object
46 */
ct_socket_new(unsigned int bufsize)47 ct_socket_t *ct_socket_new(unsigned int bufsize)
48 {
49 ct_socket_t *sock;
50 unsigned char *p;
51
52 sock = (ct_socket_t *) calloc(1, sizeof(*sock) + 2 * bufsize);
53 if (sock == NULL)
54 return NULL;
55
56 /* Initialize socket buffer */
57 p = (unsigned char *)(sock + 1);
58 ct_buf_init(&sock->rbuf, p, bufsize);
59 ct_buf_init(&sock->sbuf, p + bufsize, bufsize);
60 sock->recv = ct_socket_default_recv_cb;
61 sock->send = ct_socket_default_send_cb;
62 sock->fd = -1;
63
64 return sock;
65 }
66
67 /*
68 * Free a socket object
69 */
ct_socket_free(ct_socket_t * sock)70 void ct_socket_free(ct_socket_t * sock)
71 {
72 ct_socket_unlink(sock);
73 if (sock->close)
74 sock->close(sock);
75 ct_socket_close(sock);
76 free(sock);
77 }
78
ct_socket_reuseaddr(int n)79 void ct_socket_reuseaddr(int n)
80 {
81 ifd_reuse_addr = n;
82 }
83
84 /*
85 * Make the socket.
86 * This code tries to deal with IPv4/IPv6 and AF_UNIX sockets
87 */
88 enum { CT_MAKESOCK_BIND, CT_MAKESOCK_CONNECT };
89
__ct_socket_make(ct_socket_t * sock,int op,const struct sockaddr * sa,socklen_t salen)90 static int __ct_socket_make(ct_socket_t * sock, int op,
91 const struct sockaddr *sa, socklen_t salen)
92 {
93 int fd, oerrno;
94
95 if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
96 return -1;
97
98 /* For non-local sockets, use network byte order */
99 if (sa->sa_family != AF_UNIX)
100 sock->use_network_byte_order = 1;
101
102 /* set close on exec */
103 if (fcntl(fd, F_SETFD, 1) < 0)
104 goto failed;
105
106 switch (op) {
107 case CT_MAKESOCK_BIND:
108 #ifdef IPV6_V6ONLY
109 # ifndef SOL_IPV6
110 # define SOL_IPV6 IPPROTO_IPV6
111 # endif
112 if (sa->sa_family == AF_INET6) {
113 int val = 1;
114
115 setsockopt(fd, SOL_IPV6, IPV6_V6ONLY,
116 &val, sizeof(val));
117 }
118 #endif
119 if (ifd_reuse_addr) {
120 int val = 1;
121
122 setsockopt(fd, SOL_SOCKET,
123 SO_REUSEADDR, &val, sizeof(val));
124 }
125 if (bind(fd, sa, salen) >= 0) {
126 sock->fd = fd;
127 return fd;
128 }
129 ct_debug("bind() failed: %m");
130 break;
131 case CT_MAKESOCK_CONNECT:
132 if (connect(fd, sa, salen) >= 0) {
133 sock->fd = fd;
134 return fd;
135 }
136 /* no error message - reader does not exist. */
137 break;
138 default:
139 errno = EINVAL;
140 }
141
142 failed:
143 oerrno = errno;
144 close(fd);
145
146 /* XXX translate error */
147 return -1;
148 }
149
ct_socket_make(ct_socket_t * sock,int op,const char * addr)150 static int ct_socket_make(ct_socket_t * sock, int op, const char *addr)
151 {
152 union {
153 struct sockaddr a;
154 struct sockaddr_in in;
155 struct sockaddr_in6 ix;
156 struct sockaddr_un un;
157 } s;
158 struct addrinfo *res, *ai;
159 char addrbuf[1024], *port;
160 unsigned int portnum = 6666;
161 int fd;
162
163 memset(&s, 0, sizeof(s));
164
165 /* Simple stuff first - unix domain sockets */
166 if (addr[0] == '/') {
167 s.un.sun_family = AF_UNIX;
168 strncpy(s.un.sun_path, addr, sizeof(s.un.sun_path));
169 if (op == CT_MAKESOCK_BIND) {
170 if (unlink(addr) < 0 && errno != ENOENT)
171 return -1;
172 }
173 return __ct_socket_make(sock, op, &s.a, sizeof(s.un));
174 }
175
176 memset(addrbuf, 0, sizeof(addrbuf));
177 strncpy(addrbuf, addr, sizeof(addrbuf) - 1);
178
179 addr = addrbuf;
180 if ((port = strchr(addrbuf, ';')) != NULL) {
181 *port++ = '\0';
182 } else
183 if ((port = strchr(addrbuf, ':')) != NULL
184 && (strchr(port + 1, ':')) == NULL) {
185 *port++ = '\0';
186 }
187
188 if (*addr == '\0')
189 addr = "0.0.0.0";
190
191 if (port) {
192 portnum = strtoul(port, &port, 10);
193 if (*port)
194 return -1;
195 portnum = htons(portnum);
196 }
197
198 if (inet_pton(AF_INET, addr, &s.in.sin_addr) > 0) {
199 s.in.sin_family = AF_INET;
200 s.in.sin_port = portnum;
201 return __ct_socket_make(sock, op, &s.a, sizeof(s.in));
202 }
203 if (inet_pton(AF_INET6, addr, &s.ix.sin6_addr) > 0) {
204 s.ix.sin6_family = AF_INET6;
205 s.ix.sin6_port = portnum;
206 return __ct_socket_make(sock, op, &s.a, sizeof(s.ix));
207 }
208
209 if (getaddrinfo(addr, NULL, NULL, &res) < 0)
210 return -1;
211
212 fd = -1;
213 for (ai = res; ai; ai = ai->ai_next) {
214 if (ai->ai_family == AF_INET)
215 ((struct sockaddr_in *)ai->ai_addr)->sin_port = portnum;
216 else if (ai->ai_family == AF_INET6)
217 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port =
218 portnum;
219 fd = __ct_socket_make(sock, op, ai->ai_addr, ai->ai_addrlen);
220 if (fd >= 0)
221 break;
222 }
223
224 freeaddrinfo(res);
225 return fd;
226 }
227
228 /*
229 * Create a client socket
230 */
ct_socket_connect(ct_socket_t * sock,const char * addr)231 int ct_socket_connect(ct_socket_t * sock, const char *addr)
232 {
233 ct_socket_close(sock);
234 if (ct_socket_make(sock, CT_MAKESOCK_CONNECT, addr) < 0)
235 return -1;
236
237 return 0;
238 }
239
240 /*
241 * Listen on a socket
242 */
ct_socket_listen(ct_socket_t * sock,const char * path,int mode)243 int ct_socket_listen(ct_socket_t * sock, const char *path, int mode)
244 {
245 ct_socket_close(sock);
246 if (ct_socket_make(sock, CT_MAKESOCK_BIND, path) < 0)
247 return -1;
248
249 if (listen(sock->fd, 5) < 0) {
250 ct_socket_close(sock);
251 return -1;
252 }
253 if (path[0] == '/')
254 chmod(path, mode);
255
256 sock->listener = 1;
257 sock->events = POLLIN;
258 return 0;
259 }
260
261 /*
262 * Accept incoming connection
263 */
ct_socket_accept(ct_socket_t * sock)264 ct_socket_t *ct_socket_accept(ct_socket_t * sock)
265 {
266 ct_socket_t *svc;
267 int fd;
268
269 if (!(svc = ct_socket_new(CT_SOCKET_BUFSIZ)))
270 return NULL;
271
272 if ((fd = accept(sock->fd, NULL, NULL)) < 0) {
273 ct_socket_free(svc);
274 return NULL;;
275 }
276
277 svc->use_network_byte_order = sock->use_network_byte_order;
278 svc->events = POLLIN;
279 svc->fd = fd;
280
281 /* obtain client credentials */
282 svc->client_uid = -2;
283 ct_socket_getcreds(svc);
284
285 /* Add socket to list */
286 ct_socket_link(sock, svc);
287
288 return svc;
289 }
290
291 /*
292 * Get client credentials
293 * Should move this to a platform specific file
294 */
ct_socket_getcreds(ct_socket_t * sock)295 static int ct_socket_getcreds(ct_socket_t * sock)
296 {
297 #ifdef SO_PEERCRED
298 struct ucred creds;
299 socklen_t len;
300
301 len = sizeof(creds);
302 if (getsockopt(sock->fd, SOL_SOCKET, SO_PEERCRED, &creds, &len) < 0)
303 return -1;
304 sock->client_uid = creds.uid;
305 #endif
306 return 0;
307 }
308
309 /*
310 * Get the peer name
311 */
ct_socket_getpeername(ct_socket_t * sock,char * buf,size_t len)312 int ct_socket_getpeername(ct_socket_t * sock, char *buf, size_t len)
313 {
314 struct sockaddr_storage ss;
315 socklen_t slen = sizeof(struct sockaddr_storage);
316
317 getpeername(sock->fd, (struct sockaddr *)&ss, &slen);
318 switch (ss.ss_family) {
319 case AF_INET:
320 inet_ntop(AF_INET,
321 &((struct sockaddr_in *)&ss)->sin_addr, buf, len);
322 break;
323 case AF_INET6:
324 inet_ntop(AF_INET6,
325 &((struct sockaddr_in6 *)&ss)->sin6_addr, buf, len);
326 break;
327 case AF_UNIX:
328 snprintf(buf, len, "<local process>");
329 break;
330 default:
331 ct_error("Unsupported address family\n");
332 return -1;
333 }
334
335 return 0;
336 }
337
338 /*
339 * Close socket
340 */
ct_socket_close(ct_socket_t * sock)341 void ct_socket_close(ct_socket_t * sock)
342 {
343 ct_buf_clear(&sock->rbuf);
344 ct_buf_clear(&sock->sbuf);
345 if (sock->fd >= 0)
346 close(sock->fd);
347 sock->fd = -1;
348 }
349
350 /*
351 * Transmit a call and receive the response
352 */
ct_socket_call(ct_socket_t * sock,ct_buf_t * args,ct_buf_t * resp)353 int ct_socket_call(ct_socket_t * sock, ct_buf_t * args, ct_buf_t * resp)
354 {
355 ct_buf_t data;
356 unsigned int xid, avail;
357 header_t header;
358 int rc;
359
360 /* Compact send buffer */
361 ct_buf_compact(&sock->sbuf);
362
363 if ((xid = ifd_xid++) == 0)
364 xid = ifd_xid++;
365
366 /* Build header - note there's no need to convert
367 * integers to network byte order: everything happens
368 * on the same host, so there's no byte order issue */
369 header.xid = xid;
370 header.count = ct_buf_avail(args);
371 header.dest = 0;
372 header.error = 0;
373
374 /* Put everything into send buffer and transmit */
375 if ((rc = ct_socket_put_packet(sock, &header, args)) < 0
376 || (rc = ct_socket_flsbuf(sock, 1)) < 0)
377 return rc;
378
379 /* Return right now if we don't expect a response */
380 if (resp == NULL)
381 return 0;
382
383 /* Loop until we receive a complete packet with the
384 * right xid in it */
385 rc = 0;
386 do {
387 if ((rc == 0) && (rc = ct_socket_filbuf(sock, -1)) < 0)
388 return -1;
389
390 ct_buf_clear(resp);
391 if ((rc = ct_socket_get_packet(sock, &header, &data)) < 0)
392 return rc;
393 } while (rc == 0 || header.xid != xid);
394
395 if (header.error)
396 return header.error;
397
398 avail = ct_buf_avail(&data);
399 if (avail > ct_buf_tailroom(resp)) {
400 ct_error("received truncated reply (%u out of %u bytes)",
401 rc, header.count);
402 return IFD_ERROR_BUFFER_TOO_SMALL;
403 }
404
405 ct_buf_put(resp, ct_buf_head(&data), avail);
406 return header.count;
407 }
408
409 /*
410 * Put packet into send buffer
411 */
ct_socket_put_packet(ct_socket_t * sock,header_t * hdr,ct_buf_t * data)412 int ct_socket_put_packet(ct_socket_t * sock, header_t * hdr, ct_buf_t * data)
413 {
414 header_t hcopy;
415 ct_buf_t *bp = &sock->sbuf;
416 size_t count;
417 int rc;
418
419 count = sizeof(*hdr) + (data ? ct_buf_avail(data) : 0);
420 if (ct_buf_tailroom(bp) < count) {
421 if ((rc = ct_socket_flsbuf(sock, 1)) < 0)
422 return rc;
423 ct_buf_compact(bp);
424 if (ct_buf_tailroom(bp) < count) {
425 ct_error("packet too large for buffer");
426 return IFD_ERROR_BUFFER_TOO_SMALL;
427 }
428 }
429
430 hdr->count = data ? ct_buf_avail(data) : 0;
431
432 hcopy = *hdr;
433 if (sock->use_network_byte_order) {
434 hcopy.error = ntohs(hcopy.error);
435 hcopy.count = ntohs(hcopy.count);
436 }
437 ct_buf_put(bp, &hcopy, sizeof(hcopy));
438
439 if (hdr->count)
440 ct_buf_put(bp, ct_buf_head(data), hdr->count);
441
442 sock->events = POLLOUT;
443 return 0;
444 }
445
ct_socket_puts(ct_socket_t * sock,const char * string)446 int ct_socket_puts(ct_socket_t * sock, const char *string)
447 {
448 ct_buf_t *bp = &sock->sbuf;
449
450 ct_buf_clear(bp);
451 if (ct_buf_puts(bp, string) < 0) {
452 ct_error("string too large for buffer");
453 return -1;
454 }
455
456 sock->events = POLLOUT;
457 return 0;
458 }
459
460 /*
461 * Get packet from buffer
462 */
ct_socket_get_packet(ct_socket_t * sock,header_t * hdr,ct_buf_t * data)463 int ct_socket_get_packet(ct_socket_t * sock, header_t * hdr, ct_buf_t * data)
464 {
465 ct_buf_t *bp = &sock->rbuf;
466 unsigned int avail;
467 header_t th;
468
469 avail = ct_buf_avail(bp);
470 if (avail < sizeof(header_t))
471 return 0;
472
473 memcpy(&th, ct_buf_head(bp), sizeof(th));
474 if (sock->use_network_byte_order) {
475 th.count = ntohs(th.count);
476 th.error = ntohs(th.error);
477 }
478
479 if (avail >= sizeof(header_t) + th.count) {
480 /* There's enough data in the buffer
481 * Extract header... */
482 ct_buf_get(bp, NULL, sizeof(*hdr));
483 *hdr = th;
484
485 /* ... set data buffer (don't copy, just set pointers) ... */
486 ct_buf_set(data, ct_buf_head(bp), hdr->count);
487
488 /* ... and advance head pointer */
489 ct_buf_get(bp, NULL, hdr->count);
490 return 1;
491 }
492
493 /* Check if this packet will ever fit into this buffer */
494 if (ct_buf_size(bp) < sizeof(header_t) + th.count) {
495 ct_error("packet too large for buffer");
496 return -1;
497 }
498
499 return 0;
500 }
501
ct_socket_gets(ct_socket_t * sock,char * buffer,size_t size)502 int ct_socket_gets(ct_socket_t * sock, char *buffer, size_t size)
503 {
504 return ct_buf_gets(&sock->rbuf, buffer, size);
505 }
506
507 /*
508 * Read some data from socket and put it into buffer
509 */
ct_socket_filbuf(ct_socket_t * sock,long timeout)510 int ct_socket_filbuf(ct_socket_t * sock, long timeout)
511 {
512 ct_buf_t *bp = &sock->rbuf;
513 unsigned int count;
514 int n;
515
516 if (!(count = ct_buf_tailroom(bp))) {
517 ct_buf_compact(bp);
518 if (!(count = ct_buf_tailroom(bp))) {
519 ct_error("packet too large");
520 return -1;
521 }
522 }
523
524 if (timeout >= 0) {
525 struct pollfd pfd;
526
527 pfd.fd = sock->fd;
528 pfd.events = POLLIN;
529 do {
530 n = poll(&pfd, 1, timeout);
531 } while (n < 0 && errno == EINTR);
532 if (n == 0)
533 return IFD_ERROR_TIMEOUT;
534 }
535
536 retry:
537 n = read(sock->fd, ct_buf_tail(bp), count);
538 if (n < 0 && errno == EINTR)
539 goto retry;
540
541 if (n < 0) {
542 ct_error("socket recv error: %m");
543 return -1;
544 }
545
546 /* When EOF occurs, the server's recv() routine
547 * should deal with it instantly. If we come here
548 * a second time we may be looping on a closed
549 * socket, so error out
550 */
551 if (n == 0) {
552 if (sock->eof) {
553 ct_error("Peer closed connection");
554 return -1;
555 }
556 sock->eof = 1;
557 return 0;
558 }
559
560 /* Advance buffer tail pointer */
561 ct_buf_put(bp, NULL, n);
562 return n;
563 }
564
565 /*
566 * Flush data from buffer to socket
567 */
ct_socket_flsbuf(ct_socket_t * sock,int all)568 int ct_socket_flsbuf(ct_socket_t * sock, int all)
569 {
570 struct sigaction act;
571 ct_buf_t *bp = &sock->sbuf;
572 int n, rc = 0;
573
574 /* Ignore SIGPIPE while writing to socket */
575 memset(&act, 0, sizeof(act));
576 act.sa_handler = SIG_IGN;
577 sigaction(SIGPIPE, &act, &act);
578
579 do {
580 if (!(n = ct_buf_avail(bp))) {
581 sock->events = POLLIN;
582 break;
583 }
584 n = write(sock->fd, ct_buf_head(bp), n);
585 if (n < 0) {
586 if (errno != EPIPE)
587 ct_error("socket send error: %m");
588 rc = IFD_ERROR_NOT_CONNECTED;
589 break;
590 }
591 /* Advance head pointer */
592 ct_buf_get(bp, NULL, n);
593 } while (all);
594
595 /* Restore old signal handler */
596 sigaction(SIGPIPE, &act, &act);
597
598 if (rc >= 0 && all == 2) {
599 /* Shutdown socket for write */
600 if (shutdown(sock->fd, 1) < 0) {
601 ct_error("socket shutdown error: %m");
602 return -1;
603 }
604 }
605
606 return rc;
607 }
608
609 /*
610 * Default send/receive handlers
611 */
ct_socket_default_recv_cb(ct_socket_t * sock)612 static int ct_socket_default_recv_cb(ct_socket_t * sock)
613 {
614 char buffer[CT_SOCKET_BUFSIZ + 64];
615 header_t header;
616 ct_buf_t args, resp;
617 int rc;
618
619 /* Error or client closed connection? */
620 if ((rc = ct_socket_filbuf(sock, -1)) <= 0)
621 return -1;
622
623 while (ct_buf_avail(&sock->rbuf)) {
624 /* If request is incomplete, go back
625 * and wait for more
626 * XXX add timeout? */
627 rc = ct_socket_get_packet(sock, &header, &args);
628 if (rc <= 0)
629 return 0;
630
631 ct_buf_init(&resp, buffer, sizeof(buffer));
632
633 if (sock->process == 0)
634 continue;
635
636 /* Process the request */
637 rc = sock->process(sock, &header, &args, &resp);
638
639 /* Do not reply if the request was dropped */
640 if (header.xid == 0)
641 continue;
642
643 if (rc >= 0) {
644 header.error = 0;
645 } else {
646 /* Do not return an error to a reply */
647 if (header.dest)
648 continue;
649 ct_buf_clear(&resp);
650 }
651
652 /* Now mark as reply */
653 header.dest = 1;
654
655 /* Put packet into transmit buffer */
656 if ((rc = ct_socket_put_packet(sock, &header, &resp)) < 0)
657 return rc;
658 }
659
660 return 0;
661 }
662
ct_socket_default_send_cb(ct_socket_t * sock)663 static int ct_socket_default_send_cb(ct_socket_t * sock)
664 {
665 return ct_socket_flsbuf(sock, 0);
666 }
667
668 /*
669 * Send/receive request
670 */
ct_socket_send(ct_socket_t * sock,header_t * hdr,ct_buf_t * data)671 int ct_socket_send(ct_socket_t * sock, header_t * hdr, ct_buf_t * data)
672 {
673 header_t hcopy = *hdr;
674
675 if (sock->use_network_byte_order) {
676 hcopy.error = htons(hcopy.error);
677 hcopy.count = htons(hcopy.count);
678 }
679 if (ct_socket_write(sock, &hcopy, sizeof(hcopy)) < 0
680 || ct_socket_write(sock, ct_buf_head(data), hdr->count) < 0)
681 return -1;
682 return 0;
683 }
684
ct_socket_recv(ct_socket_t * sock,header_t * hdr,ct_buf_t * resp)685 int ct_socket_recv(ct_socket_t * sock, header_t * hdr, ct_buf_t * resp)
686 {
687 header_t hcopy = *hdr;
688 unsigned int left, count, n;
689 unsigned char c;
690 int rc;
691
692 if (sock->use_network_byte_order) {
693 hcopy.error = htons(hcopy.error);
694 hcopy.count = htons(hcopy.count);
695 }
696 if (ct_socket_write(sock, &hcopy, sizeof(hcopy)) < 0)
697 return -1;
698
699 if (hdr->count > 1024) {
700 ct_error("oversize packet, discarding");
701 ct_socket_close(sock);
702 return -1;
703 }
704
705 /* Read the data following the packet header. If
706 * there's more data than the receive buffer can hold,
707 * truncate the packet.
708 * We return the number of bytes stored - the true packet
709 * length is available from the header
710 */
711 left = hdr->count;
712 count = 0;
713 while (left) {
714 n = min(left, ct_buf_tailroom(resp));
715 if (n == 0) {
716 rc = ct_socket_read(sock, &c, 1);
717 } else {
718 rc = ct_socket_read(sock, ct_buf_tail(resp), n);
719 }
720 if (rc < 0)
721 return -1;
722 count += n;
723 left -= rc;
724 }
725
726 return count;
727 }
728
729 /*
730 * Socket read/write routines
731 */
ct_socket_write(ct_socket_t * sock,void * ptr,size_t len)732 int ct_socket_write(ct_socket_t * sock, void *ptr, size_t len)
733 {
734 struct sigaction act;
735 unsigned int count = 0;
736 int rc;
737 caddr_t p = (caddr_t) ptr;
738
739 if (sock->fd < 0)
740 return -1;
741
742 /* Ignore SIGPIPE while writing to socket */
743 memset(&act, 0, sizeof(act));
744 act.sa_handler = SIG_IGN;
745 sigaction(SIGPIPE, &act, &act);
746
747 while (count < len) {
748 rc = write(sock->fd, (const void *)p, len);
749 if (rc < 0) {
750 ct_error("send error: %m");
751 goto done;
752 }
753 p += rc;
754 count += rc;
755 }
756 rc = count;
757
758 done: /* Restore old signal handler */
759 sigaction(SIGPIPE, &act, &act);
760 return rc;
761 }
762
ct_socket_read(ct_socket_t * sock,void * ptr,size_t size)763 int ct_socket_read(ct_socket_t * sock, void *ptr, size_t size)
764 {
765 unsigned int count = 0;
766 int rc;
767 caddr_t p = (caddr_t) ptr;
768
769 if (sock->fd < 0)
770 return -1;
771
772 while (count < size) {
773 rc = read(sock->fd, (void *)p, size - count);
774 if (rc < 0) {
775 ct_error("recv error: %m");
776 goto done;
777 }
778 if (rc == 0) {
779 ct_error("peer closed connection");
780 rc = -1;
781 goto done;
782 }
783 p += rc;
784 count += rc;
785 }
786 rc = count;
787
788 done:return rc;
789 }
790
791 /*
792 * Link/unlink socket
793 */
ct_socket_link(ct_socket_t * prev,ct_socket_t * sock)794 void ct_socket_link(ct_socket_t * prev, ct_socket_t * sock)
795 {
796 ct_socket_t *next;
797
798 if (!prev)
799 return;
800
801 next = prev->next;
802
803 if (next)
804 next->prev = sock;
805
806 prev->next = sock;
807 sock->prev = prev;
808 sock->next = next;
809 }
810
ct_socket_unlink(ct_socket_t * sock)811 void ct_socket_unlink(ct_socket_t * sock)
812 {
813 ct_socket_t *next = sock->next, *prev = sock->prev;
814
815 if (next)
816 next->prev = prev;
817 if (prev)
818 prev->next = next;
819 sock->prev = sock->next = NULL;
820 }
821