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