2 * Copyright (C) ARM Limited 2010-2014. All rights reserved.
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.
16 #include <netinet/in.h>
17 #include <sys/socket.h>
26 #define CLOSE_SOCKET(x) closesocket(x)
27 #define SHUTDOWN_RX_TX SD_BOTH
28 #define snprintf _snprintf
30 #define CLOSE_SOCKET(x) close(x)
31 #define SHUTDOWN_RX_TX SHUT_RDWR
34 OlyServerSocket::OlyServerSocket(int port) {
37 if (WSAStartup(0x0202, &wsaData) != 0) {
38 logg->logError(__FILE__, __LINE__, "Windows socket initialization failed");
43 createServerSocket(port);
46 OlySocket::OlySocket(int port, const char* host) {
47 createClientSocket(host, port);
50 OlySocket::OlySocket(int socketID) : mSocketID(socketID) {
55 OlyServerSocket::OlyServerSocket(const char* path) {
57 mFDServer = socket(PF_UNIX, SOCK_STREAM, 0);
59 logg->logError(__FILE__, __LINE__, "Error creating server socket");
65 // Create sockaddr_in structure, ensuring non-populated fields are zero
66 struct sockaddr_un sockaddr;
67 memset((void*)&sockaddr, 0, sizeof(sockaddr));
68 sockaddr.sun_family = AF_UNIX;
69 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
70 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
72 // Bind the socket to an address
73 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
74 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.");
78 // Listen for connections on this socket
79 if (listen(mFDServer, 1) < 0) {
80 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
85 OlySocket::OlySocket(const char* path) {
86 mSocketID = socket(PF_UNIX, SOCK_STREAM, 0);
91 // Create sockaddr_in structure, ensuring non-populated fields are zero
92 struct sockaddr_un sockaddr;
93 memset((void*)&sockaddr, 0, sizeof(sockaddr));
94 sockaddr.sun_family = AF_UNIX;
95 strncpy(sockaddr.sun_path, path, sizeof(sockaddr.sun_path) - 1);
96 sockaddr.sun_path[sizeof(sockaddr.sun_path) - 1] = '\0';
98 if (connect(mSocketID, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
107 OlySocket::~OlySocket() {
109 CLOSE_SOCKET(mSocketID);
113 OlyServerSocket::~OlyServerSocket() {
115 CLOSE_SOCKET(mFDServer);
119 void OlySocket::shutdownConnection() {
120 // Shutdown is primarily used to unblock other threads that are blocking on send/receive functions
121 shutdown(mSocketID, SHUTDOWN_RX_TX);
124 void OlySocket::closeSocket() {
125 // Used for closing an accepted socket but keeping the server socket active
127 CLOSE_SOCKET(mSocketID);
132 void OlyServerSocket::closeServerSocket() {
133 if (CLOSE_SOCKET(mFDServer) != 0) {
134 logg->logError(__FILE__, __LINE__, "Failed to close server socket.");
140 void OlySocket::createClientSocket(const char* hostname, int portno) {
142 // TODO: Implement for Windows
145 struct addrinfo hints, *res, *res0;
147 snprintf(buf, sizeof(buf), "%d", portno);
149 memset((void*)&hints, 0, sizeof(hints));
150 hints.ai_family = PF_UNSPEC;
151 hints.ai_socktype = SOCK_STREAM;
153 if (getaddrinfo(hostname, buf, &hints, &res0)) {
154 logg->logError(__FILE__, __LINE__, "Client socket failed to get address info for %s", hostname);
157 for (res=res0; res!=NULL; res = res->ai_next) {
158 if ( res->ai_family != PF_INET || res->ai_socktype != SOCK_STREAM ) {
161 mSocketID = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
165 if (connect(mSocketID, res->ai_addr, res->ai_addrlen) < 0) {
174 if (mSocketID <= 0) {
175 logg->logError(__FILE__, __LINE__, "Could not connect to client socket. Ensure ARM Streamline is running.");
181 void OlyServerSocket::createServerSocket(int port) {
182 int family = AF_INET6;
185 mFDServer = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
188 mFDServer = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
190 logg->logError(__FILE__, __LINE__, "Error creating server socket");
195 // Enable address reuse, another solution would be to create the server socket once and only close it when the object exits
197 if (setsockopt(mFDServer, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)) != 0) {
198 logg->logError(__FILE__, __LINE__, "Setting server socket options failed");
202 // Create sockaddr_in structure, ensuring non-populated fields are zero
203 struct sockaddr_in6 sockaddr;
204 memset((void*)&sockaddr, 0, sizeof(sockaddr));
205 sockaddr.sin6_family = family;
206 sockaddr.sin6_port = htons(port);
207 sockaddr.sin6_addr = in6addr_any;
209 // Bind the socket to an address
210 if (bind(mFDServer, (const struct sockaddr*)&sockaddr, sizeof(sockaddr)) < 0) {
211 logg->logError(__FILE__, __LINE__, "Binding of server socket failed.\nIs an instance already running?");
215 // Listen for connections on this socket
216 if (listen(mFDServer, 1) < 0) {
217 logg->logError(__FILE__, __LINE__, "Listening of server socket failed");
222 // mSocketID is always set to the most recently accepted connection
223 // The user of this class should maintain the different socket connections, e.g. by forking the process
224 int OlyServerSocket::acceptConnection() {
226 if (mFDServer <= 0) {
227 logg->logError(__FILE__, __LINE__, "Attempting multiple connections on a single connection server socket or attempting to accept on a client socket");
231 // Accept a connection, note that this call blocks until a client connects
232 socketID = accept(mFDServer, NULL, NULL);
234 logg->logError(__FILE__, __LINE__, "Socket acceptance failed");
240 void OlySocket::send(const char* buffer, int size) {
241 if (size <= 0 || buffer == NULL) {
246 int n = ::send(mSocketID, buffer, size, 0);
248 logg->logError(__FILE__, __LINE__, "Socket send error");
256 // Returns the number of bytes received
257 int OlySocket::receive(char* buffer, int size) {
258 if (size <= 0 || buffer == NULL) {
262 int bytes = recv(mSocketID, buffer, size, 0);
264 logg->logError(__FILE__, __LINE__, "Socket receive error");
266 } else if (bytes == 0) {
267 logg->logMessage("Socket disconnected");
273 // Receive exactly size bytes of data. Note, this function will block until all bytes are received
274 int OlySocket::receiveNBytes(char* buffer, int size) {
276 while (size > 0 && buffer != NULL) {
277 bytes = recv(mSocketID, buffer, size, 0);
279 logg->logError(__FILE__, __LINE__, "Socket receive error");
281 } else if (bytes == 0) {
282 logg->logMessage("Socket disconnected");
291 // Receive data until a carriage return, line feed, or null is encountered, or the buffer fills
292 int OlySocket::receiveString(char* buffer, int size) {
293 int bytes_received = 0;
300 while (!found && bytes_received < size) {
301 // Receive a single character
302 int bytes = recv(mSocketID, &buffer[bytes_received], 1, 0);
304 logg->logError(__FILE__, __LINE__, "Socket receive error");
306 } else if (bytes == 0) {
307 logg->logMessage("Socket disconnected");
311 // Replace carriage returns and line feeds with zero
312 if (buffer[bytes_received] == '\n' || buffer[bytes_received] == '\r' || buffer[bytes_received] == '\0') {
313 buffer[bytes_received] = '\0';
320 return bytes_received;