1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #ifdef _WIN32
8 : #include <windows.h>
9 : #ifndef AF_IPX
10 : #include <winsock2.h>
11 : #endif
12 : #define SOCKET_HANDLE SOCKET
13 : #else
14 :
15 : #include <arpa/inet.h>
16 : #include <netdb.h>
17 : #include <sys/select.h>
18 : #include <sys/socket.h>
19 : #include <sys/types.h>
20 : #include <unistd.h>
21 :
22 : #define SOCKET_HANDLE int
23 : #define closesocket close
24 : #endif
25 :
26 : #include <stdlib.h>
27 : #include <string>
28 :
29 : #include "native_client/src/trusted/gdb_rsp/util.h"
30 : #include "native_client/src/trusted/port/platform.h"
31 : #include "native_client/src/trusted/port/transport.h"
32 :
33 : using gdb_rsp::stringvec;
34 : using gdb_rsp::StringSplit;
35 :
36 : namespace port {
37 :
38 : typedef int socklen_t;
39 :
40 : class Transport : public ITransport {
41 : public:
42 : Transport() {
43 : handle_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
44 : }
45 :
46 0 : explicit Transport(SOCKET_HANDLE s) {
47 0 : handle_ = s;
48 0 : }
49 :
50 0 : ~Transport() {
51 0 : if (handle_ != -1) closesocket(handle_);
52 0 : }
53 :
54 : // Read from this transport, return a negative value if there is an error
55 : // otherwise return the number of bytes actually read.
56 0 : virtual int32_t Read(void *ptr, int32_t len) {
57 0 : return ::recv(handle_, reinterpret_cast<char *>(ptr), len, 0);
58 : }
59 :
60 : // Write to this transport, return a negative value if there is an error
61 : // otherwise return the number of bytes actually written.
62 0 : virtual int32_t Write(const void *ptr, int32_t len) {
63 0 : return ::send(handle_, reinterpret_cast<const char *>(ptr), len, 0);
64 : }
65 :
66 : // Return true if data becomes availible or false after ms milliseconds.
67 0 : virtual bool ReadWaitWithTimeout(uint32_t ms = 0) {
68 : fd_set fds;
69 :
70 0 : FD_ZERO(&fds);
71 0 : FD_SET(handle_, &fds);
72 :
73 : // We want a "non-blocking" check
74 : struct timeval timeout;
75 0 : timeout.tv_sec = 0;
76 0 : timeout.tv_usec= ms * 1000;
77 :
78 : // Check if this file handle can select on read
79 0 : int cnt = select(static_cast<int>(handle_) + 1, &fds, 0, 0, &timeout);
80 :
81 : // If we are ready, or if there is an error. We return true
82 : // on error, to "timeout" and let the next IO request fail.
83 0 : if (cnt != 0) return true;
84 :
85 0 : return false;
86 : }
87 :
88 : // On windows, the header that defines this has other definition
89 : // colitions, so we define it outselves just in case
90 : #ifndef SD_BOTH
91 : #define SD_BOTH 2
92 : #endif
93 :
94 0 : virtual void Disconnect() {
95 : // Shutdown the conneciton in both diections. This should
96 : // always succeed, and nothing we can do if this fails.
97 0 : (void) ::shutdown(handle_, SD_BOTH);
98 0 : }
99 :
100 : protected:
101 : SOCKET_HANDLE handle_;
102 : };
103 :
104 : // Convert string in the form of [addr][:port] where addr is a
105 : // IPv4 address or host name, and port is a 16b tcp/udp port.
106 : // Both portions are optional, and only the portion of the address
107 : // provided is updated. Values are provided in network order.
108 : static bool StringToIPv4(const std::string &instr, uint32_t *addr,
109 0 : uint16_t *port) {
110 : // Make a copy so the are unchanged unless we succeed
111 0 : uint32_t outaddr = *addr;
112 0 : uint16_t outport = *port;
113 :
114 : // Substrings of the full ADDR:PORT
115 0 : std::string addrstr;
116 0 : std::string portstr;
117 :
118 : // We should either have one or two tokens in the form of:
119 : // IP - IP, NUL
120 : // IP: - IP, NUL
121 : // :PORT - NUL, PORT
122 : // IP:PORT - IP, PORT
123 :
124 : // Search for the port marker
125 0 : size_t portoff = instr.find(':');
126 :
127 : // If we found a ":" before the end, get both substrings
128 0 : if ((portoff != std::string::npos) && (portoff + 1 < instr.size())) {
129 0 : addrstr = instr.substr(0, portoff);
130 0 : portstr = instr.substr(portoff + 1, std::string::npos);
131 : } else {
132 : // otherwise the entire string is the addr portion.
133 0 : addrstr = instr;
134 0 : portstr = "";
135 : }
136 :
137 : // If the address portion was provided, update it
138 0 : if (addrstr.size()) {
139 : // Special case 0.0.0.0 which means any IPv4 interface
140 0 : if (addrstr == "0.0.0.0") {
141 0 : outaddr = 0;
142 : } else {
143 0 : struct hostent *host = gethostbyname(addrstr.data());
144 :
145 : // Check that we found an IPv4 host
146 0 : if ((NULL == host) || (AF_INET != host->h_addrtype)) return false;
147 :
148 : // Make sure the IP list isn't empty.
149 0 : if (0 == host->h_addr_list[0]) return false;
150 :
151 : // Use the first address in the array of address pointers.
152 0 : uint32_t **addrarray = reinterpret_cast<uint32_t**>(host->h_addr_list);
153 0 : outaddr = *addrarray[0];
154 : }
155 : }
156 :
157 : // if the port portion was provided, then update it
158 0 : if (portstr.size()) {
159 0 : int val = atoi(portstr.data());
160 0 : if ((val < 0) || (val > 65535)) return false;
161 0 : outport = ntohs(static_cast<uint16_t>(val));
162 : }
163 :
164 : // We haven't failed, so set the values
165 0 : *addr = outaddr;
166 0 : *port = outport;
167 0 : return true;
168 : }
169 :
170 :
171 : static SOCKET_HANDLE s_ServerSock;
172 :
173 0 : static bool SocketInit() {
174 0 : s_ServerSock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
175 0 : if (s_ServerSock == -1) {
176 0 : IPlatform::LogError("Failed to create socket.\n");
177 0 : return false;
178 : }
179 :
180 0 : return true;
181 : }
182 :
183 0 : static bool SocketsAvailable() {
184 0 : static bool _init = SocketInit();
185 0 : return _init;
186 : }
187 :
188 0 : static bool BuildSockAddr(const char *addr, struct sockaddr_in *sockaddr) {
189 0 : std::string addrstr = addr;
190 0 : uint32_t *pip = reinterpret_cast<uint32_t*>(&sockaddr->sin_addr.s_addr);
191 0 : uint16_t *pport = reinterpret_cast<uint16_t*>(&sockaddr->sin_port);
192 :
193 0 : sockaddr->sin_family = AF_INET;
194 0 : return StringToIPv4(addrstr, pip, pport);
195 : }
196 :
197 0 : ITransport* ITransport::Connect(const char *addr) {
198 0 : if (!SocketsAvailable()) return NULL;
199 :
200 0 : SOCKET_HANDLE s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
201 0 : if (s == -1) {
202 0 : IPlatform::LogError("Failed to create connection socket.\n");
203 0 : return NULL;
204 : }
205 :
206 : struct sockaddr_in saddr;
207 0 : saddr.sin_family = AF_INET;
208 0 : saddr.sin_addr.s_addr = htonl(0x7F000001);
209 0 : saddr.sin_port = htons(4014);
210 :
211 : // Override portions address that are provided
212 0 : if (addr) BuildSockAddr(addr, &saddr);
213 :
214 0 : if (::connect(s, reinterpret_cast<sockaddr*>(&saddr), sizeof(saddr)) != 0) {
215 0 : closesocket(s);
216 0 : IPlatform::LogError("Failed to connect.\n");
217 0 : return NULL;
218 : }
219 :
220 0 : return new Transport(s);
221 : }
222 :
223 0 : ITransport* ITransport::Accept(const char *addr) {
224 : static bool listening = false;
225 0 : if (!SocketsAvailable()) return NULL;
226 :
227 0 : if (!listening) {
228 : struct sockaddr_in saddr;
229 0 : socklen_t addrlen = static_cast<socklen_t>(sizeof(saddr));
230 0 : saddr.sin_family = AF_INET;
231 0 : saddr.sin_addr.s_addr = htonl(0x7F000001);
232 0 : saddr.sin_port = htons(4014);
233 :
234 : // Override portions address that are provided
235 0 : if (addr) BuildSockAddr(addr, &saddr);
236 :
237 : // This is necessary to ensure that the TCP port is released
238 : // promptly when sel_ldr exits. Without this, the TCP port might
239 : // only be released after a timeout, and later processes can fail
240 : // to bind it.
241 0 : int reuse_address = 1;
242 : setsockopt(s_ServerSock, SOL_SOCKET, SO_REUSEADDR,
243 : reinterpret_cast<char *>(&reuse_address),
244 0 : sizeof(reuse_address));
245 :
246 0 : struct sockaddr *psaddr = reinterpret_cast<struct sockaddr *>(&saddr);
247 0 : if (bind(s_ServerSock, psaddr, addrlen)) {
248 0 : IPlatform::LogError("Failed to bind server.\n");
249 0 : return NULL;
250 : }
251 :
252 0 : if (listen(s_ServerSock, 1)) {
253 0 : IPlatform::LogError("Failed to listen.\n");
254 0 : return NULL;
255 : }
256 :
257 0 : listening = true;
258 : }
259 :
260 0 : if (listening) {
261 0 : SOCKET_HANDLE s = ::accept(s_ServerSock, NULL, 0);
262 0 : if (-1 != s) return new Transport(s);
263 0 : return NULL;
264 : }
265 :
266 0 : return NULL;
267 : }
268 :
269 0 : void ITransport::Free(ITransport* itrans) {
270 0 : Transport* trans = static_cast<Transport*>(itrans);
271 0 : delete trans;
272 0 : }
273 :
274 : } // namespace port
|