1 // Copyright (C) 2014 The Android Open Source Project
2 //
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
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14
15 #include "emugl/common/sockets.h"
16
17 #include <errno.h>
18
19 #ifdef _WIN32
20 #include <winsock2.h>
21 #include <ws2tcpip.h>
22 #else
23 #include <netinet/in.h>
24 #include <netinet/tcp.h>
25 #include <sys/un.h>
26 #include <sys/stat.h>
27 #endif
28
29 #include <stddef.h>
30 #include <stdint.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 namespace emugl {
35
36 namespace {
37
socketSetReuseAddress(int s)38 static void socketSetReuseAddress(int s) {
39 #ifdef _WIN32
40 // The default behaviour on Windows is equivalent to SO_REUSEADDR
41 // so we don't need to set this option. Moreover, one should never
42 // set this option with WinSock because it's badly implemented and
43 // generates a huge security issue. See:
44 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx
45 #else
46 int val = 1;
47 setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
48 #endif
49 }
50
51 // Helper union to store a socket address.
52 struct SockAddr {
53 socklen_t len;
54 union {
55 sockaddr generic;
56 sockaddr_in inet;
57 #ifndef _WIN32
58 sockaddr_un local;
59 #endif
60 };
61
getFamilyemugl::__anonfa764a300111::SockAddr62 int getFamily() const { return generic.sa_family; }
63
initEmptyemugl::__anonfa764a300111::SockAddr64 void initEmpty() {
65 ::memset(this, 0, sizeof(*this));
66 this->len = static_cast<socklen_t>(sizeof(*this));
67 }
68
initFromInetemugl::__anonfa764a300111::SockAddr69 int initFromInet(uint32_t ip_address, int port) {
70 if (port < 0 || port >= 65536)
71 return -EINVAL;
72
73 ::memset(this, 0, sizeof(*this));
74 this->inet.sin_family = AF_INET;
75 this->inet.sin_port = htons(port);
76 this->inet.sin_addr.s_addr = htonl(ip_address);
77 this->len = sizeof(this->inet);
78 return 0;
79 }
80
initFromLocalhostemugl::__anonfa764a300111::SockAddr81 int initFromLocalhost(int port) {
82 return initFromInet(0x7f000001, port);
83 }
84
85 #ifndef _WIN32
86 // Initialize the SockAddr from a Unix path. Returns 0 on success,
87 // or -errno code on failure.
initFromUnixPathemugl::__anonfa764a300111::SockAddr88 int initFromUnixPath(const char* path) {
89 if (!path || !path[0])
90 return -EINVAL;
91
92 size_t pathLen = ::strlen(path);
93 if (pathLen >= sizeof(local.sun_path))
94 return -E2BIG;
95
96 ::memset(this, 0, sizeof(*this));
97 this->local.sun_family = AF_LOCAL;
98 ::memcpy(this->local.sun_path, path, pathLen + 1U);
99 this->len = pathLen + offsetof(sockaddr_un, sun_path);
100 return 0;
101 }
102 #endif
103 };
104
socketBindInternal(const SockAddr * addr,int socketType)105 int socketBindInternal(const SockAddr* addr, int socketType) {
106 int s = ::socket(addr->getFamily(), socketType, 0);
107 if (s < 0)
108 return -errno;
109
110 // Bind to the socket.
111 if (::bind(s, &addr->generic, addr->len) < 0 ||
112 ::listen(s, 5) < 0) {
113 int ret = -errno;
114 ::close(s);
115 return ret;
116 }
117
118 socketSetReuseAddress(s);
119 return s;
120 }
121
socketConnectInternal(const SockAddr * addr,int socketType)122 int socketConnectInternal(const SockAddr* addr, int socketType) {
123 int s = ::socket(addr->getFamily(), socketType, 0);
124 if (s < 0)
125 return -errno;
126
127 int ret;
128 do {
129 ret = ::connect(s, &addr->generic, addr->len);
130 } while (ret < 0 && errno == EINTR);
131
132 if (ret < 0) {
133 ret = -errno;
134 ::close(s);
135 return ret;
136 }
137
138 return s;
139 }
140
141 } // namespace
142
socketTcpDisableNagle(int s)143 void socketTcpDisableNagle(int s) {
144 // disable Nagle algorithm to improve bandwidth of small
145 // packets which are quite common in our implementation.
146 #ifdef _WIN32
147 DWORD flag;
148 #else
149 int flag;
150 #endif
151 flag = 1;
152 setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
153 (const char*)&flag, sizeof(flag));
154 }
155
socketGetPort(int s)156 int socketGetPort(int s) {
157 SockAddr addr;
158 addr.initEmpty();
159 if (getsockname(s, &addr.generic, &addr.len) < 0) {
160 return -errno;
161 }
162 switch (addr.generic.sa_family) {
163 case AF_INET:
164 return ntohs(addr.inet.sin_port);
165 default:
166 ;
167 }
168 return -EINVAL;
169 }
170
171 #ifndef _WIN32
socketLocalServer(const char * path,int socketType)172 int socketLocalServer(const char* path, int socketType) {
173 SockAddr addr;
174 int ret = addr.initFromUnixPath(path);
175 if (ret < 0) {
176 return ret;
177 }
178 return socketBindInternal(&addr, socketType);
179 }
180
socketLocalClient(const char * path,int socketType)181 int socketLocalClient(const char* path, int socketType) {
182 SockAddr addr;
183 int ret = addr.initFromUnixPath(path);
184 if (ret < 0) {
185 return ret;
186 }
187 return socketConnectInternal(&addr, socketType);
188 }
189 #endif // !_WIN32
190
socketTcpLoopbackServer(int port,int socketType)191 int socketTcpLoopbackServer(int port, int socketType) {
192 SockAddr addr;
193 int ret = addr.initFromLocalhost(port);
194 if (ret < 0) {
195 return ret;
196 }
197 return socketBindInternal(&addr, socketType);
198 }
199
socketTcpLoopbackClient(int port,int socketType)200 int socketTcpLoopbackClient(int port, int socketType) {
201 SockAddr addr;
202 int ret = addr.initFromLocalhost(port);
203 if (ret < 0) {
204 return ret;
205 }
206 return socketConnectInternal(&addr, socketType);
207 }
208
socketTcpClient(const char * hostname,int port,int socketType)209 int socketTcpClient(const char* hostname, int port, int socketType) {
210 // TODO(digit): Implement this.
211 return -ENOSYS;
212 }
213
socketAccept(int serverSocket)214 int socketAccept(int serverSocket) {
215 int ret;
216 do {
217 ret = ::accept(serverSocket, NULL, NULL);
218 } while (ret < 0 && errno == EINTR);
219 return ret;
220 }
221
222 } // namespace emugl
223