blob: 28774e36e5102dfee04832e9066b7c3b295753a6 [file] [log] [blame]
Jon Medhurstaaf37a32013-06-11 12:10:56 +01001/**
Jon Medhurst15ce78d2014-04-10 09:02:02 +01002 * Copyright (C) ARM Limited 2010-2014. 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>
18#include <sys/socket.h>
Jon Medhurst15ce78d2014-04-10 09:02:02 +010019#include <sys/un.h>
Jon Medhurstaaf37a32013-06-11 12:10:56 +010020#include <unistd.h>
21#include <netdb.h>
22#endif
23
24#include "Logging.h"
25
26#ifdef WIN32
27#define CLOSE_SOCKET(x) closesocket(x)
28#define SHUTDOWN_RX_TX SD_BOTH
29#define snprintf _snprintf
30#else
31#define CLOSE_SOCKET(x) close(x)
32#define SHUTDOWN_RX_TX SHUT_RDWR
33#endif
34
Jon Medhurst15ce78d2014-04-10 09:02:02 +010035OlyServerSocket::OlyServerSocket(int port) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +010036#ifdef WIN32
37 WSADATA wsaData;
38 if (WSAStartup(0x0202, &wsaData) != 0) {
39 logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
40 handleException();
41 }
42#endif
43
Jon Medhurst15ce78d2014-04-10 09:02:02 +010044 createServerSocket(port);
45}
46
Jon Medhurst15ce78d2014-04-10 09:02:02 +010047OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
48}
49
50#ifndef WIN32
51
Jon Medhurste31266f2014-08-04 15:47:44 +010052#define MIN(A, B) ({ \
53 const __typeof__(A) __a = A; \
54 const __typeof__(B) __b = B; \
55 __a > __b ? __b : __a; \
56})
57
58OlyServerSocket::OlyServerSocket(const char* path, const size_t pathSize) {
Jon Medhurst15ce78d2014-04-10 09:02:02 +010059 // Create socket
60 mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
61 if (mFDServer < 0) {
62 logg->logError(__FILE__, __LINE__, "Error creating server socket");
63 handleException();
64 }
65
Jon Medhurst15ce78d2014-04-10 09:02:02 +010066 // Create sockaddr_in structure, ensuring non-populated fields are zero
67 struct sockaddr_un sockaddr;
68 memset((void*)&sockaddr, 0, sizeof(sockaddr));
69 sockaddr.sun_family = AF_UNIX;
Jon Medhurste31266f2014-08-04 15:47:44 +010070 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
Jon Medhurst15ce78d2014-04-10 09:02:02 +010071 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
72
73 // Bind the socket to an address
74 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
75 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
76 handleException();
77 }
78
79 // Listen for connections on this socket
80 if (listen(mFDServer, 1) < 0) {
81 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
82 handleException();
Jon Medhurstaaf37a32013-06-11 12:10:56 +010083 }
84}
85
Jon Medhurste31266f2014-08-04 15:47:44 +010086int OlySocket::connect(const char* path, const size_t pathSize) {
87 int fd = socket(PF_UNIX, SOCK_STREAM, 0);
88 if (fd < 0) {
89 return -1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +010090 }
91
92 // Create sockaddr_in structure, ensuring non-populated fields are zero
93 struct sockaddr_un sockaddr;
94 memset((void*)&sockaddr, 0, sizeof(sockaddr));
95 sockaddr.sun_family = AF_UNIX;
Jon Medhurste31266f2014-08-04 15:47:44 +010096 memcpy(sockaddr.sun_path, path, MIN(pathSize, sizeof(sockaddr.sun_path)));
Jon Medhurst15ce78d2014-04-10 09:02:02 +010097 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
98
Jon Medhurste31266f2014-08-04 15:47:44 +010099 if (::connect(fd, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
100 close(fd);
101 return -1;
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100102 }
Jon Medhurste31266f2014-08-04 15:47:44 +0100103
104 return fd;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100105}
106
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100107#endif
108
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100109OlySocket::~OlySocket() {
110 if (mSocketID > 0) {
111 CLOSE_SOCKET(mSocketID);
112 }
113}
114
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100115OlyServerSocket::~OlyServerSocket() {
116 if (mFDServer > 0) {
117 CLOSE_SOCKET(mFDServer);
118 }
119}
120
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100121void OlySocket::shutdownConnection() {
122 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
123 shutdown(mSocketID, SHUTDOWN_RX_TX);
124}
125
126void OlySocket::closeSocket() {
127 // Used for closing an accepted socket but keeping the server socket active
128 if (mSocketID > 0) {
129 CLOSE_SOCKET(mSocketID);
130 mSocketID = -1;
131 }
132}
133
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100134void OlyServerSocket::closeServerSocket() {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100135 if (CLOSE_SOCKET(mFDServer) != 0) {
136 logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
137 handleException();
138 }
139 mFDServer = 0;
140}
141
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100142void OlyServerSocket::createServerSocket(int port) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000143 int family = AF_INET6;
144
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100145 // Create socket
Jon Medhurst34d97692013-12-19 09:23:06 +0000146 mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100147 if (mFDServer < 0) {
Jon Medhurst34d97692013-12-19 09:23:06 +0000148 family = AF_INET;
149 mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
150 if (mFDServer < 0) {
151 logg->logError(__FILE__, __LINE__, "Error creating server socket");
152 handleException();
153 }
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100154 }
155
156 // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
157 int on = 1;
158 if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
159 logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
160 handleException();
161 }
162
163 // Create sockaddr_in structure, ensuring non-populated fields are zero
Jon Medhurst34d97692013-12-19 09:23:06 +0000164 struct sockaddr_in6 sockaddr;
165 memset((void*)&sockaddr, 0, sizeof(sockaddr));
166 sockaddr.sin6_family = family;
167 sockaddr.sin6_port = htons(port);
168 sockaddr.sin6_addr = in6addr_any;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100169
170 // Bind the socket to an address
171 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
172 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
173 handleException();
174 }
175
176 // Listen for connections on this socket
177 if (listen(mFDServer, 1) < 0) {
178 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
179 handleException();
180 }
181}
182
183// mSocketID is always set to the most recently accepted connection
184// The user of this class should maintain the different socket connections, e.g. by forking the process
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100185int OlyServerSocket::acceptConnection() {
186 int socketID;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100187 if (mFDServer <= 0) {
188 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
189 handleException();
190 }
191
192 // Accept a connection, note that this call blocks until a client connects
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100193 socketID = accept(mFDServer, NULL, NULL);
194 if (socketID < 0) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100195 logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
196 handleException();
197 }
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100198 return socketID;
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100199}
200
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100201void OlySocket::send(const char* buffer, int size) {
Jon Medhurstaaf37a32013-06-11 12:10:56 +0100202 if (size <= 0 || buffer == NULL) {
203 return;
204 }
205
206 while (size > 0) {
207 int n = ::send(mSocketID, buffer, size, 0);
208 if (n < 0) {
209 logg->logError(__FILE__, __LINE__, "Socket send error");
210 handleException();
211 }
212 size -= n;
213 buffer += n;
214 }
215}
216
217// Returns the number of bytes received
218int OlySocket::receive(char* buffer, int size) {
219 if (size <= 0 || buffer == NULL) {
220 return 0;
221 }
222
223 int bytes = recv(mSocketID, buffer, size, 0);
224 if (bytes < 0) {
225 logg->logError(__FILE__, __LINE__, "Socket receive error");
226 handleException();
227 } else if (bytes == 0) {
228 logg->logMessage("Socket disconnected");
229 return -1;
230 }
231 return bytes;
232}
233
234// Receive exactly size bytes of data. Note, this function will block until all bytes are received
235int OlySocket::receiveNBytes(char* buffer, int size) {
236 int bytes = 0;
237 while (size > 0 && buffer != NULL) {
238 bytes = recv(mSocketID, buffer, size, 0);
239 if (bytes < 0) {
240 logg->logError(__FILE__, __LINE__, "Socket receive error");
241 handleException();
242 } else if (bytes == 0) {
243 logg->logMessage("Socket disconnected");
244 return -1;
245 }
246 buffer += bytes;
247 size -= bytes;
248 }
249 return bytes;
250}
251
252// Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
253int OlySocket::receiveString(char* buffer, int size) {
254 int bytes_received = 0;
255 bool found = false;
256
257 if (buffer == 0) {
258 return 0;
259 }
260
261 while (!found && bytes_received < size) {
262 // Receive a single character
263 int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
264 if (bytes < 0) {
265 logg->logError(__FILE__, __LINE__, "Socket receive error");
266 handleException();
267 } else if (bytes == 0) {
268 logg->logMessage("Socket disconnected");
269 return -1;
270 }
271
272 // Replace carriage returns and line feeds with zero
273 if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
274 buffer[bytes_received] = '\0';
275 found = true;
276 }
277
278 bytes_received++;
279 }
280
281 return bytes_received;
282}