TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / external / android-emugl / shared / emugl / common / sockets.cpp
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 #include <stdio.h>
28 #endif
29
30 #include <stddef.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <unistd.h>
34
35 namespace emugl {
36
37 namespace {
38
39 static void socketSetDontLinger(int s) {
40 #ifdef _WIN32
41   // TODO: Verify default behavior on WINDOWS
42 #else
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");
49 #endif
50 }
51
52 static void socketSetReuseAddress(int s) {
53 #ifdef _WIN32
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
59 #else
60     int val = 1;
61     if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
62       perror("Setting socket option SO_REUSEADDR failed");
63 #endif
64 }
65
66 // Helper union to store a socket address.
67 struct SockAddr {
68     socklen_t len;
69     union {
70         sockaddr generic;
71         sockaddr_in inet;
72 #ifndef _WIN32
73         sockaddr_un local;
74 #endif
75     };
76
77     int getFamily() const { return generic.sa_family; }
78
79     void initEmpty() {
80         ::memset(this, 0, sizeof(*this));
81         this->len = static_cast<socklen_t>(sizeof(*this));
82     }
83
84     int initFromInet(uint32_t ip_address, int port) {
85         if (port < 0 || port >= 65536)
86             return -EINVAL;
87
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);
93         return 0;
94     }
95
96     int initFromLocalhost(int port) {
97         return initFromInet(0x7f000001, port);
98     }
99
100 #ifndef _WIN32
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])
105             return -EINVAL;
106
107         size_t pathLen = ::strlen(path);
108         if (pathLen >= sizeof(local.sun_path))
109             return -E2BIG;
110
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);
115         return 0;
116     }
117 #endif
118 };
119
120 int socketBindInternal(const SockAddr* addr, int socketType) {
121     int s = ::socket(addr->getFamily(), socketType, 0);
122     if (s < 0) {
123         perror("Could not create socket to bind");
124         return -errno;
125     }
126
127     socketSetDontLinger(s);
128     socketSetReuseAddress(s);
129
130     // Bind to the socket.
131     if (::bind(s, &addr->generic, addr->len) < 0 ||
132         ::listen(s, 5) < 0) {
133         int ret = -errno;
134         perror("Could not bind or listen to socket");
135         ::close(s);
136         return ret;
137     }
138
139     return s;
140 }
141
142 int socketConnectInternal(const SockAddr* addr, int socketType) {
143     int s = ::socket(addr->getFamily(), socketType, 0);
144     if (s < 0) {
145         perror("Could not create socket to connect");
146         return -errno;
147     }
148
149     socketSetDontLinger(s);
150     socketSetReuseAddress(s);
151
152     int ret;
153     do {
154         ret = ::connect(s, &addr->generic, addr->len);
155     } while (ret < 0 && errno == EINTR);
156
157     if (ret < 0) {
158         ret = -errno;
159         ::close(s);
160         return ret;
161     }
162
163     return s;
164 }
165
166 }  // namespace
167
168 void socketTcpDisableNagle(int s) {
169     // disable Nagle algorithm to improve bandwidth of small
170     // packets which are quite common in our implementation.
171 #ifdef _WIN32
172     DWORD  flag;
173 #else
174     int    flag;
175 #endif
176     flag = 1;
177     setsockopt(s, IPPROTO_TCP, TCP_NODELAY,
178                (const char*)&flag, sizeof(flag));
179 }
180
181 int socketGetPort(int s) {
182     SockAddr addr;
183     addr.initEmpty();
184     if (getsockname(s, &addr.generic, &addr.len) < 0) {
185         return -errno;
186     }
187     switch (addr.generic.sa_family) {
188         case AF_INET:
189             return ntohs(addr.inet.sin_port);
190         default:
191             ;
192     }
193     return -EINVAL;
194 }
195
196 #ifndef _WIN32
197 int socketLocalServer(const char* path, int socketType) {
198     SockAddr addr;
199     int ret = addr.initFromUnixPath(path);
200     if (ret < 0) {
201         return ret;
202     }
203     return socketBindInternal(&addr, socketType);
204 }
205
206 int socketLocalClient(const char* path, int socketType) {
207     SockAddr addr;
208     int ret = addr.initFromUnixPath(path);
209     if (ret < 0) {
210         return ret;
211     }
212     return socketConnectInternal(&addr, socketType);
213 }
214 #endif  // !_WIN32
215
216 int socketTcpLoopbackServer(int port, int socketType) {
217     SockAddr addr;
218     int ret = addr.initFromLocalhost(port);
219     if (ret < 0) {
220         return ret;
221     }
222     return socketBindInternal(&addr, socketType);
223 }
224
225 int socketTcpLoopbackClient(int port, int socketType) {
226     SockAddr addr;
227     int ret = addr.initFromLocalhost(port);
228     if (ret < 0) {
229         return ret;
230     }
231     return socketConnectInternal(&addr, socketType);
232 }
233
234 int socketTcpClient(const char* hostname, int port, int socketType) {
235     // TODO(digit): Implement this.
236     return -ENOSYS;
237 }
238
239 int socketAccept(int serverSocket) {
240     int ret;
241     do {
242         ret = ::accept(serverSocket, NULL, NULL);
243     } while (ret < 0 && errno == EINTR);
244     return ret;
245 }
246
247 }  // namespace emugl