blob: 078d2020922684f011a5f6cd66a888964b919fc7 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2010-2015. All rights reserved.
Jon Medhurstaaf37a32013-06-11 12:10:56 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "OlySocket.h"
10
11#include <stdio.h>
Jon Medhurste31266f2014-08-04 15:47:44 +010012#include <string.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010013#ifdef WIN32
14#include <Winsock2.h>
Jon Medhurst34d97692013-12-19 09:23:06 +000015#include <ws2tcpip.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010016#else
17#include <netinet/in.h>
Jon Medhurst15ce78d2014-04-10 09:02:02 +010018#include <sys/un.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010019#include <unistd.h>
20#include <netdb.h>
Jon Medhurst96b56152014-10-30 18:01:15 +000021#include <fcntl.h>
Jon Medhurstb1d07442015-05-08 12:04:18 +010022#include <stddef.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010023#endif
24
25#include "Logging.h"
26
27#ifdef WIN32
28#define CLOSE_SOCKET(x) closesocket(x)
29#define SHUTDOWN_RX_TX SD_BOTH
30#define snprintf _snprintf
31#else
32#define CLOSE_SOCKET(x) close(x)
33#define SHUTDOWN_RX_TX SHUT_RDWR
34#endif
35
Jon Medhurst96b56152014-10-30 18:01:15 +000036int socket_cloexec(int domain, int type, int protocol) {
37#ifdef SOCK_CLOEXEC
38 return socket(domain, type | SOCK_CLOEXEC, protocol);
39#else
40 int sock = socket(domain, type, protocol);
41#ifdef FD_CLOEXEC
42 if (sock < 0) {
43 return -1;
44 }
45 int fdf = fcntl(sock, F_GETFD);
46 if ((fdf == -1) || (fcntl(sock, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
47 close(sock);
48 return -1;
49 }
50#endif
51 return sock;
52#endif
53}
54
55int accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
56 int sock;
57#ifdef SOCK_CLOEXEC
58 sock = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
59 if (sock >= 0) {
60 return sock;
61 }
62 // accept4 with SOCK_CLOEXEC may not work on all kernels, so fallback
63#endif
64 sock = accept(sockfd, addr, addrlen);
65#ifdef FD_CLOEXEC
66 if (sock < 0) {
67 return -1;
68 }
69 int fdf = fcntl(sock, F_GETFD);
70 if ((fdf == -1) || (fcntl(sock, F_SETFD, fdf | FD_CLOEXEC) != 0)) {
71 close(sock);
72 return -1;
73 }
74#endif
75 return sock;
76}
77
Jon Medhurst15ce78d2014-04-10 09:02:02 +010078OlyServerSocket::OlyServerSocket(int port) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010079#ifdef WIN32
80 WSADATA wsaData;
81 if (WSAStartup(0x0202, &wsaData) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010082 logg->logError("Windows socket initialization failed");
Jon Medhurstaaf37a32013-06-11 12:10:56 +010083 handleException();
84 }
85#endif
86
Jon Medhurst15ce78d2014-04-10 09:02:02 +010087 createServerSocket(port);
88}
89
Jon Medhurst15ce78d2014-04-10 09:02:02 +010090OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
91}
92
93#ifndef WIN32
94
Jon Medhurste31266f2014-08-04 15:47:44 +010095#define MIN(A, B) ({ \
96 const __typeof__(A) __a = A; \
97 const __typeof__(B) __b = B; \
98 __a > __b ? __b : __a; \
99})
100
Jon Medhurstb1d07442015-05-08 12:04:18 +0100101OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize, const bool calculateAddrlen) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100102 // Create socket
Jon Medhurst96b56152014-10-30 18:01:15 +0000103 mFDServer = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100104 if (mFDServer < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100105 logg->logError("Error creating server socket");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100106 handleException();
107 }
108
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100109 // Create sockaddr_in structure, ensuring non-populated fields are zero
110 struct sockaddr_un sockaddr;
111 memset((void*)&sockaddr, 0, sizeof(sockaddr));
112 sockaddr.sun_family = AF_UNIX;
Jon Medhurste31266f2014-08-04 15:47:44 +0100113 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100114 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
115
116 // Bind the socket to an address
Jon Medhurstb1d07442015-05-08 12:04:18 +0100117 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) {
118 logg->logError("Binding of server socket failed.");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100119 handleException();
120 }
121
122 // Listen for connections on this socket
123 if (listen(mFDServer, 1) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100124 logg->logError("Listening of server socket failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100125 handleException();
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100126 }
127}
128
Jon Medhurstb1d07442015-05-08 12:04:18 +0100129int OlySocket::connect(const char* path, const size_t pathSize, const bool calculateAddrlen) {
Jon Medhurst96b56152014-10-30 18:01:15 +0000130 int fd = socket_cloexec(PF_UNIX, SOCK_STREAM, 0);
Jon Medhurste31266f2014-08-04 15:47:44 +0100131 if (fd < 0) {
132 return -1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100133 }
134
135 // Create sockaddr_in structure, ensuring non-populated fields are zero
136 struct sockaddr_un sockaddr;
137 memset((void*)&sockaddr, 0, sizeof(sockaddr));
138 sockaddr.sun_family = AF_UNIX;
Jon Medhurste31266f2014-08-04 15:47:44 +0100139 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100140 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
141
Jon Medhurstb1d07442015-05-08 12:04:18 +0100142 if (::connect(fd, (const struct sockaddr*)&sockaddr, calculateAddrlen ? offsetof(struct sockaddr_un, sun_path) + pathSize - 1 : sizeof(sockaddr)) < 0) {
Jon Medhurste31266f2014-08-04 15:47:44 +0100143 close(fd);
144 return -1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100145 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100146
147 return fd;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100148}
149
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100150#endif
151
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100152OlySocket::~OlySocket() {
153 if (mSocketID > 0) {
154 CLOSE_SOCKET(mSocketID);
155 }
156}
157
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100158OlyServerSocket::~OlyServerSocket() {
159 if (mFDServer > 0) {
160 CLOSE_SOCKET(mFDServer);
161 }
162}
163
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100164void OlySocket::shutdownConnection() {
165 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
166 shutdown(mSocketID, SHUTDOWN_RX_TX);
167}
168
169void OlySocket::closeSocket() {
170 // Used for closing an accepted socket but keeping the server socket active
171 if (mSocketID > 0) {
172 CLOSE_SOCKET(mSocketID);
173 mSocketID = -1;
174 }
175}
176
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100177void OlyServerSocket::closeServerSocket() {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100178 if (mFDServer > 0 && CLOSE_SOCKET(mFDServer) != 0) {
179 logg->logError("Failed to close server socket.");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100180 handleException();
181 }
Jon Medhurstb1d07442015-05-08 12:04:18 +0100182 mFDServer = -1;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100183}
184
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100185void OlyServerSocket::createServerSocket(int port) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000186 int family = AF_INET6;
187
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100188 // Create socket
Jon Medhurst96b56152014-10-30 18:01:15 +0000189 mFDServer = socket_cloexec(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100190 if (mFDServer < 0) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000191 family = AF_INET;
Jon Medhurst96b56152014-10-30 18:01:15 +0000192 mFDServer = socket_cloexec(PF_INET, SOCK_STREAM, IPPROTO_TCP);
Jon Medhurst34d97692013-12-19 09:23:06 +0000193 if (mFDServer < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100194 logg->logError("Error creating server socket");
Jon Medhurst34d97692013-12-19 09:23:06 +0000195 handleException();
196 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100197 }
198
199 // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
200 int on = 1;
201 if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100202 logg->logError("Setting server socket reuse option failed");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100203 handleException();
204 }
205
Jon Medhurstb1d07442015-05-08 12:04:18 +0100206 // Listen on both IPv4 and IPv6
207 on = 0;
208 if (setsockopt(mFDServer, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(on)) != 0) {
209 logg->logMessage("setsockopt IPV6_V6ONLY failed");
210 }
211
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100212 // Create sockaddr_in structure, ensuring non-populated fields are zero
Jon Medhurst34d97692013-12-19 09:23:06 +0000213 struct sockaddr_in6 sockaddr;
214 memset((void*)&sockaddr, 0, sizeof(sockaddr));
215 sockaddr.sin6_family = family;
216 sockaddr.sin6_port = htons(port);
217 sockaddr.sin6_addr = in6addr_any;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100218
219 // Bind the socket to an address
220 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100221 logg->logError("Binding of server socket on port %i failed.\nIs an instance already running or is another application using that port?", port);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100222 handleException();
223 }
224
225 // Listen for connections on this socket
226 if (listen(mFDServer, 1) < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100227 logg->logError("Listening of server socket failed");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100228 handleException();
229 }
230}
231
232// mSocketID is always set to the most recently accepted connection
233// The user of this class should maintain the different socket connections, e.g. by forking the process
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100234int OlyServerSocket::acceptConnection() {
235 int socketID;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100236 if (mFDServer <= 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100237 logg->logError("Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100238 handleException();
239 }
240
241 // Accept a connection, note that this call blocks until a client connects
Jon Medhurst96b56152014-10-30 18:01:15 +0000242 socketID = accept_cloexec(mFDServer, NULL, NULL);
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100243 if (socketID < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100244 logg->logError("Socket acceptance failed");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100245 handleException();
246 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100247 return socketID;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100248}
249
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100250void OlySocket::send(const char* buffer, int size) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100251 if (size <= 0 || buffer == NULL) {
252 return;
253 }
254
255 while (size > 0) {
256 int n = ::send(mSocketID, buffer, size, 0);
257 if (n < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100258 logg->logError("Socket send error");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100259 handleException();
260 }
261 size -= n;
262 buffer += n;
263 }
264}
265
266// Returns the number of bytes received
267int OlySocket::receive(char* buffer, int size) {
268 if (size <= 0 || buffer == NULL) {
269 return 0;
270 }
271
272 int bytes = recv(mSocketID, buffer, size, 0);
273 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100274 logg->logError("Socket receive error");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100275 handleException();
276 } else if (bytes == 0) {
277 logg->logMessage("Socket disconnected");
278 return -1;
279 }
280 return bytes;
281}
282
283// Receive exactly size bytes of data. Note, this function will block until all bytes are received
284int OlySocket::receiveNBytes(char* buffer, int size) {
285 int bytes = 0;
286 while (size > 0 && buffer != NULL) {
287 bytes = recv(mSocketID, buffer, size, 0);
288 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100289 logg->logError("Socket receive error");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100290 handleException();
291 } else if (bytes == 0) {
292 logg->logMessage("Socket disconnected");
293 return -1;
294 }
295 buffer += bytes;
296 size -= bytes;
297 }
298 return bytes;
299}
300
301// Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
302int OlySocket::receiveString(char* buffer, int size) {
303 int bytes_received = 0;
304 bool found = false;
305
306 if (buffer == 0) {
307 return 0;
308 }
309
310 while (!found && bytes_received < size) {
311 // Receive a single character
312 int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
313 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100314 logg->logError("Socket receive error");
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100315 handleException();
316 } else if (bytes == 0) {
317 logg->logMessage("Socket disconnected");
318 return -1;
319 }
320
321 // Replace carriage returns and line feeds with zero
322 if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
323 buffer[bytes_received] = '\0';
324 found = true;
325 }
326
327 bytes_received++;
328 }
329
330 return bytes_received;
331}