1 // Copyright (C) 2014 The Android Open Source Project
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 #include "emugl/common/sockets.h"
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
39 static void socketSetDontLinger(int s) {
41 // TODO: Verify default behavior on WINDOWS
43 // Ungraceful shutdown, no reason to linger at all
44 struct linger so_linger;
45 so_linger.l_onoff = 1;
46 so_linger.l_linger = 0;
47 if(setsockopt(s, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger) < 0)
48 perror("Setting socket option SO_LINGER={on, 0} failed");
52 static void socketSetReuseAddress(int s) {
54 // The default behaviour on Windows is equivalent to SO_REUSEADDR
55 // so we don't need to set this option. Moreover, one should never
56 // set this option with WinSock because it's badly implemented and
57 // generates a huge security issue. See:
58 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx
61 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
62 perror("Setting socket option SO_REUSEADDR failed");
66 // Helper union to store a socket address.
77 int getFamily() const { return generic.sa_family; }
80 ::memset(this, 0, sizeof(*this));
81 this->len = static_cast<socklen_t>(sizeof(*this));
84 int initFromInet(uint32_t ip_address, int port) {
85 if (port < 0 || port >= 65536)
88 ::memset(this, 0, sizeof(*this));
89 this->inet.sin_family = AF_INET;
90 this->inet.sin_port = htons(port);
91 this->inet.sin_addr.s_addr = htonl(ip_address);
92 this->len = sizeof(this->inet);
96 int initFromLocalhost(int port) {
97 return initFromInet(0x7f000001, port);
101 // Initialize the SockAddr from a Unix path. Returns 0 on success,
102 // or -errno code on failure.
103 int initFromUnixPath(const char* path) {
104 if (!path || !path[0])
107 size_t pathLen = ::strlen(path);
108 if (pathLen >= sizeof(local.sun_path))
111 ::memset(this, 0, sizeof(*this));
112 this->local.sun_family = AF_LOCAL;
113 ::memcpy(this->local.sun_path, path, pathLen + 1U);
114 this->len = pathLen + offsetof(sockaddr_un, sun_path);
120 int socketBindInternal(const SockAddr* addr, int socketType) {
121 int s = ::socket(addr->getFamily(), socketType, 0);
123 perror("Could not create socket to bind");
127 socketSetDontLinger(s);
128 socketSetReuseAddress(s);
130 // Bind to the socket.
131 if (::bind(s, &addr->generic, addr->len) < 0 ||
132 ::listen(s, 5) < 0) {
134 perror("Could not bind or listen to socket");
142 int socketConnectInternal(const SockAddr* addr, int socketType) {
143 int s = ::socket(addr->getFamily(), socketType, 0);
145 perror("Could not create socket to connect");
149 socketSetDontLinger(s);
150 socketSetReuseAddress(s);
154 ret = ::connect(s, &addr->generic, addr->len);
155 } while (ret < 0 && errno == EINTR);
168 void socketTcpDisableNagle(int s) {
169 // disable Nagle algorithm to improve bandwidth of small
170 // packets which are quite common in our implementation.
177 setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
178 (const char*)&flag, sizeof(flag));
181 int socketGetPort(int s) {
184 if (getsockname(s, &addr.generic, &addr.len) < 0) {
187 switch (addr.generic.sa_family) {
189 return ntohs(addr.inet.sin_port);
197 int socketLocalServer(const char* path, int socketType) {
199 int ret = addr.initFromUnixPath(path);
203 return socketBindInternal(&addr, socketType);
206 int socketLocalClient(const char* path, int socketType) {
208 int ret = addr.initFromUnixPath(path);
212 return socketConnectInternal(&addr, socketType);
216 int socketTcpLoopbackServer(int port, int socketType) {
218 int ret = addr.initFromLocalhost(port);
222 return socketBindInternal(&addr, socketType);
225 int socketTcpLoopbackClient(int port, int socketType) {
227 int ret = addr.initFromLocalhost(port);
231 return socketConnectInternal(&addr, socketType);
234 int socketTcpClient(const char* hostname, int port, int socketType) {
235 // TODO(digit): Implement this.
239 int socketAccept(int serverSocket) {
242 ret = ::accept(serverSocket, NULL, NULL);
243 } while (ret < 0 && errno == EINTR);