1 /*
2  *  Copyright 2006  Serge van den Boom <svdb@stack.nl>
3  *
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 2 of the License, or
7  *  (at your option) any later version.
8  *
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.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 // Socket functions for BSD sockets.
20 
21 #define SOCKET_INTERNAL
22 #include "socket.h"
23 
24 #include "libs/log.h"
25 
26 #include <assert.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netdb.h>
33 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
34 #	include <netinet/in_systm.h>
35 #	include <netinet/in.h>
36 #endif
37 #include <netinet/ip.h>
38 #include <netinet/tcp.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 
42 
43 static Socket *
Socket_alloc(void)44 Socket_alloc(void) {
45 	return malloc(sizeof (Socket));
46 }
47 
48 static void
Socket_free(Socket * sock)49 Socket_free(Socket *sock) {
50 	free(sock);
51 }
52 
53 Socket *
Socket_openNative(int domain,int type,int protocol)54 Socket_openNative(int domain, int type, int protocol) {
55 	Socket *result;
56 	int fd;
57 
58 	fd = socket(domain, type, protocol);
59 	if (fd == -1) {
60 		// errno is set
61 		return Socket_noSocket;
62 	}
63 
64 	result = Socket_alloc();
65 	result->fd = fd;
66 	return result;
67 }
68 
69 int
Socket_close(Socket * sock)70 Socket_close(Socket *sock) {
71 	int closeResult;
72 
73 	do {
74 		closeResult = close(sock->fd);
75 		if (closeResult == 0) {
76 			Socket_free(sock);
77 			return 0;
78 		}
79 	} while (errno == EINTR);
80 
81 	return -1;
82 }
83 
84 int
Socket_connect(Socket * sock,const struct sockaddr * addr,socklen_t addrLen)85 Socket_connect(Socket *sock, const struct sockaddr *addr,
86 		socklen_t addrLen) {
87 	int connectResult;
88 
89 	do {
90 		connectResult = connect(sock->fd, addr, addrLen);
91 	} while (connectResult == -1 && errno == EINTR);
92 
93 	return connectResult;
94 }
95 
96 int
Socket_bind(Socket * sock,const struct sockaddr * addr,socklen_t addrLen)97 Socket_bind(Socket *sock, const struct sockaddr *addr, socklen_t addrLen) {
98 	return bind(sock->fd, addr, addrLen);
99 }
100 
101 int
Socket_listen(Socket * sock,int backlog)102 Socket_listen(Socket *sock, int backlog) {
103 	return listen(sock->fd, backlog);
104 }
105 
106 Socket *
Socket_accept(Socket * sock,struct sockaddr * addr,socklen_t * addrLen)107 Socket_accept(Socket *sock, struct sockaddr *addr, socklen_t *addrLen) {
108 	int acceptResult;
109 	socklen_t tempAddrLen;
110 
111 	do {
112 		tempAddrLen = *addrLen;
113 		acceptResult = accept(sock->fd, addr, &tempAddrLen);
114 		if (acceptResult != -1) {
115 			Socket *result = Socket_alloc();
116 			result->fd = acceptResult;
117 			*addrLen = tempAddrLen;
118 			return result;
119 		}
120 
121 	} while (errno == EINTR);
122 
123 	// errno is set
124 	return Socket_noSocket;
125 }
126 
127 ssize_t
Socket_send(Socket * sock,const void * buf,size_t len,int flags)128 Socket_send(Socket *sock, const void *buf, size_t len, int flags) {
129 	return send(sock->fd, buf, len, flags);
130 }
131 
132 ssize_t
Socket_sendto(Socket * sock,const void * buf,size_t len,int flags,const struct sockaddr * addr,socklen_t addrLen)133 Socket_sendto(Socket *sock, const void *buf, size_t len, int flags,
134 		const struct sockaddr *addr, socklen_t addrLen) {
135 	return sendto(sock->fd, buf, len, flags, addr, addrLen);
136 }
137 
138 ssize_t
Socket_recv(Socket * sock,void * buf,size_t len,int flags)139 Socket_recv(Socket *sock, void *buf, size_t len, int flags) {
140 	return recv(sock->fd, buf, len, flags);
141 }
142 
143 ssize_t
Socket_recvfrom(Socket * sock,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromLen)144 Socket_recvfrom(Socket *sock, void *buf, size_t len, int flags,
145 		struct sockaddr *from, socklen_t *fromLen) {
146 	return recvfrom(sock->fd, buf, len, flags, from, fromLen);
147 }
148 
149 int
Socket_setNonBlocking(Socket * sock)150 Socket_setNonBlocking(Socket *sock) {
151 	int flags;
152 
153 	flags = fcntl(sock->fd, F_GETFL);
154 	if (flags == -1) {
155 		int savedErrno = errno;
156 		log_add(log_Error, "Getting file descriptor flags of socket failed: "
157 				"%s.", strerror(errno));
158 		errno = savedErrno;
159 		return -1;
160 	}
161 
162 	if (fcntl(sock->fd, F_SETFL, flags | O_NONBLOCK) == -1) {
163 		int savedErrno = errno;
164 		log_add(log_Error, "Setting non-blocking mode on socket failed: "
165 				"%s.", strerror(errno));
166 		errno = savedErrno;
167 		return -1;
168 	}
169 
170 	return 0;
171 }
172 
173 int
Socket_setReuseAddr(Socket * sock)174 Socket_setReuseAddr(Socket *sock) {
175 	int flag = 1;
176 
177 	if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof flag)
178 			== -1) {
179 		int savedErrno = errno;
180 		log_add(log_Error, "Setting socket reuse failed: %s.",
181 				strerror(errno));
182 		errno = savedErrno;
183 		return -1;
184 	}
185 	return 0;
186 }
187 
188 // Send data as soon as it is available. Do not collect data to send at
189 // once.
190 int
Socket_setNodelay(Socket * sock)191 Socket_setNodelay(Socket *sock) {
192 	int flag = 1;
193 
194 	if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag)
195 			== -1) {
196 #ifdef DEBUG
197 		int savedErrno = errno;
198 		log_add(log_Warning, "Disabling Nagle algorithm failed: %s.",
199 				strerror(errno));
200 		errno = savedErrno;
201 #endif
202 		return -1;
203 	}
204 	return 0;
205 }
206 
207 // 'tos' should be IPTOS_LOWDELAY, IPTOS_THROUGHPUT, IPTOS_THROUGHPUT,
208 // IPTOS_RELIABILITY, or IPTOS_MINCOST.
209 int
Socket_setTOS(Socket * sock,int tos)210 Socket_setTOS(Socket *sock, int tos) {
211 	if (setsockopt(sock->fd, IPPROTO_IP, IP_TOS, &tos, sizeof tos) == -1) {
212 #ifdef DEBUG
213 		int savedErrno = errno;
214 		log_add(log_Warning, "Setting socket type-of-service failed: %s.",
215 				strerror(errno));
216 		errno = savedErrno;
217 #endif
218 		return -1;
219 	}
220 	return 0;
221 }
222 
223 // This function setups the socket for optimal configuration for an
224 // interactive connection.
225 int
Socket_setInteractive(Socket * sock)226 Socket_setInteractive(Socket *sock) {
227 	if (Socket_setNodelay(sock) == -1) {
228 		// errno is set
229 		return -1;
230 	}
231 
232 	if (Socket_setTOS(sock, IPTOS_LOWDELAY) == -1) {
233 		// errno is set
234 		return -1;
235 	}
236 	return 0;
237 }
238 
239 int
Socket_setInlineOOB(Socket * sock)240 Socket_setInlineOOB(Socket *sock) {
241 	int flag = 1;
242 
243 	if (setsockopt(sock->fd, SOL_SOCKET, SO_OOBINLINE, &flag, sizeof flag)
244 			== -1) {
245 		int savedErrno = errno;
246 		log_add(log_Error, "Setting inline OOB on socket failed: %s",
247 				strerror(errno));
248 		errno = savedErrno;
249 		return -1;
250 	}
251 	return 0;
252 }
253 
254 int
Socket_setKeepAlive(Socket * sock)255 Socket_setKeepAlive(Socket *sock) {
256 	int flag = 1;
257 
258 	if (setsockopt(sock->fd, IPPROTO_TCP, SO_KEEPALIVE, &flag, sizeof flag)
259 			== -1) {
260 		int savedErrno = errno;
261 		log_add(log_Error, "Setting keep-alive on socket failed: %s",
262 				strerror(errno));
263 		errno = savedErrno;
264 		return -1;
265 	}
266 	return 0;
267 }
268 
269 int
Socket_getError(Socket * sock,int * err)270 Socket_getError(Socket *sock, int *err) {
271 	socklen_t errLen = sizeof(*err);
272 
273 	if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, err, &errLen) == -1) {
274 		// errno is set
275 		return -1;
276 	}
277 
278 	assert(errLen == sizeof(*err));
279 	// err is set
280 	return 0;
281 }
282 
283 
284