OLD | NEW |
| (Empty) |
1 // Copyright 2011 The Native Client SDK Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #include "debugger/base/debug_socket.h" | |
6 | |
7 namespace { | |
8 fd_set* kNoFdSet = NULL; | |
9 const int kMicroPerMilli = 1000; | |
10 const char* kAnyLocalHost = NULL; | |
11 sockaddr* kNoPeerAddress = NULL; | |
12 const int kWaitForOneWriteMs = 1000; | |
13 const int kTmpBufferSize = 2048; | |
14 | |
15 bool InitSocketLib() { | |
16 WSADATA wsa_data; | |
17 WORD version_requested = MAKEWORD(1, 1); | |
18 return (WSAStartup(version_requested, &wsa_data) == 0); | |
19 } | |
20 | |
21 void FreeSocketLib() { | |
22 WSACleanup(); | |
23 } | |
24 | |
25 void CloseSocket(SOCKET* sock) { | |
26 if ((NULL != sock) && (INVALID_SOCKET != *sock)) { | |
27 closesocket(*sock); | |
28 *sock = INVALID_SOCKET; | |
29 } | |
30 } | |
31 | |
32 timeval CreateTimeval(int milliseconds) { | |
33 timeval timeout; | |
34 timeout.tv_sec = 0; | |
35 timeout.tv_usec = milliseconds * kMicroPerMilli; | |
36 return timeout; | |
37 } | |
38 | |
39 sockaddr_in CreateSockAddr(const char* host, int port) { | |
40 sockaddr_in addr; | |
41 memset(&addr, 0, sizeof(addr)); | |
42 addr.sin_family = AF_INET; | |
43 addr.sin_port = htons(port); // Convert port number from host byte order | |
44 // to network byte order. | |
45 if ((NULL == host) || (strlen(host) == 0)) { | |
46 addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
47 } else { | |
48 hostent* hostDescr = gethostbyname(host); | |
49 if (NULL != hostDescr) | |
50 addr.sin_addr.s_addr = | |
51 *(reinterpret_cast<unsigned int**>(hostDescr->h_addr_list)[0]); | |
52 } | |
53 return addr; | |
54 } | |
55 | |
56 void SetSocketOptions(SOCKET sock) { | |
57 if (INVALID_SOCKET != sock) { | |
58 // Setup socket to flush pending data on close. | |
59 linger ling; | |
60 ling.l_onoff = 1; | |
61 ling.l_linger = 10; // The socket will remain open for a specified amount | |
62 // of time (in seconds). | |
63 setsockopt(sock, | |
64 SOL_SOCKET, | |
65 SO_LINGER, | |
66 reinterpret_cast<char*>(&ling), | |
67 sizeof(ling)); | |
68 // Turn off buffering, to speedup debugger communication. | |
69 int opt = 1; | |
70 setsockopt(sock, | |
71 IPPROTO_TCP, | |
72 TCP_NODELAY, | |
73 reinterpret_cast<char*>(&opt), | |
74 sizeof(opt)); | |
75 } | |
76 } | |
77 } // namespace | |
78 | |
79 namespace debug { | |
80 ListeningSocket::ListeningSocket() | |
81 : sock_(INVALID_SOCKET) { | |
82 init_success_ = InitSocketLib(); | |
83 } | |
84 | |
85 ListeningSocket::~ListeningSocket() { | |
86 CloseSocket(&sock_); | |
87 if (init_success_) | |
88 FreeSocketLib(); | |
89 } | |
90 | |
91 void ListeningSocket::Close() { | |
92 CloseSocket(&sock_); | |
93 } | |
94 | |
95 bool ListeningSocket::Listen(int port) { | |
96 Close(); | |
97 sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
98 if (INVALID_SOCKET == sock_) | |
99 return false; | |
100 | |
101 // Associate local address with socket. | |
102 sockaddr_in addr = CreateSockAddr(kAnyLocalHost, port); | |
103 if (bind(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) { | |
104 CloseSocket(&sock_); | |
105 return false; | |
106 } | |
107 // Mark a socket as accepting connections. | |
108 if (listen(sock_, SOMAXCONN) != 0) | |
109 CloseSocket(&sock_); | |
110 return (INVALID_SOCKET != sock_); | |
111 } | |
112 | |
113 bool ListeningSocket::Accept(Socket* new_connection, int wait_ms) { | |
114 fd_set socks; | |
115 FD_ZERO(&socks); | |
116 FD_SET(sock_, &socks); | |
117 | |
118 // Wait for incoming connection. | |
119 timeval timeout = CreateTimeval(wait_ms); | |
120 if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { | |
121 CloseSocket(&sock_); | |
122 return false; | |
123 } | |
124 // No connection requests. | |
125 if (!FD_ISSET(sock_, &socks)) | |
126 return false; | |
127 | |
128 // Accept a connection request. | |
129 SOCKET sock = accept(sock_, kNoPeerAddress, 0); | |
130 if (INVALID_SOCKET != sock) | |
131 new_connection->AttachTo(sock); | |
132 | |
133 return new_connection->IsConnected(); | |
134 } | |
135 | |
136 Socket::Socket() | |
137 : sock_(INVALID_SOCKET) { | |
138 init_success_ = InitSocketLib(); | |
139 } | |
140 | |
141 void Socket::AttachTo(SOCKET sock) { | |
142 Close(); | |
143 sock_ = sock; | |
144 SetSocketOptions(sock_); | |
145 } | |
146 | |
147 Socket::~Socket() { | |
148 CloseSocket(&sock_); | |
149 if (init_success_) | |
150 FreeSocketLib(); | |
151 } | |
152 | |
153 void Socket::Close() { | |
154 CloseSocket(&sock_); | |
155 } | |
156 | |
157 bool Socket::ConnectTo(const std::string& host, int port) { | |
158 Close(); | |
159 sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
160 if (INVALID_SOCKET == sock_) | |
161 return false; | |
162 | |
163 sockaddr_in addr = CreateSockAddr(host.c_str(), port); | |
164 if (connect(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) | |
165 CloseSocket(&sock_); | |
166 else | |
167 SetSocketOptions(sock_); | |
168 return IsConnected(); | |
169 } | |
170 | |
171 bool Socket::IsConnected() const { | |
172 return (INVALID_SOCKET != sock_); | |
173 } | |
174 | |
175 size_t Socket::Write(const void* buff, size_t sz, int wait_ms) { | |
176 if (!IsConnected()) | |
177 return 0; | |
178 | |
179 fd_set socks; | |
180 FD_ZERO(&socks); | |
181 FD_SET(sock_, &socks); | |
182 | |
183 // Wait for 'write ready'. | |
184 timeval timeout = CreateTimeval(wait_ms); | |
185 if (select(sock_ + 1, kNoFdSet, &socks, kNoFdSet, &timeout) < 0) { | |
186 CloseSocket(&sock_); | |
187 return 0; | |
188 } | |
189 size_t bytes_send = 0; | |
190 if (FD_ISSET(sock_, &socks)) { | |
191 bytes_send = send(sock_, static_cast<const char*>(buff), sz, 0); | |
192 if (bytes_send < 0) | |
193 CloseSocket(&sock_); | |
194 } | |
195 return bytes_send; | |
196 } | |
197 | |
198 // Blocks until all data has been sent. | |
199 void Socket::WriteAll(const void* buff, size_t sz) { | |
200 const char* ptr = static_cast<const char*>(buff); | |
201 while (sz) { | |
202 size_t wr = Write(ptr, sz, kWaitForOneWriteMs); | |
203 if (!IsConnected()) | |
204 break; | |
205 sz -= wr; | |
206 ptr += wr; | |
207 } | |
208 } | |
209 | |
210 void Socket::WriteAll(const Blob& blob) { | |
211 char buff[kTmpBufferSize]; | |
212 size_t pos = 0; | |
213 while (pos < blob.size()) { | |
214 size_t num = blob.size() - pos; | |
215 if (num > sizeof(buff)) | |
216 num = sizeof(buff); | |
217 for (size_t i = 0; i < num; i++) | |
218 buff[i] = blob[pos + i]; | |
219 WriteAll(buff, num); | |
220 pos += num; | |
221 } | |
222 } | |
223 | |
224 size_t Socket::Read(void* buff, size_t sz, int wait_ms) { | |
225 if (!IsConnected()) | |
226 return 0; | |
227 | |
228 fd_set socks; | |
229 FD_ZERO(&socks); | |
230 FD_SET(sock_, &socks); | |
231 timeval timeout = CreateTimeval(wait_ms); | |
232 | |
233 // Wait for data. | |
234 if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { | |
235 CloseSocket(&sock_); | |
236 return 0; | |
237 } | |
238 // No data available. | |
239 if (!FD_ISSET(sock_, &socks)) | |
240 return 0; | |
241 | |
242 size_t read_bytes = recv(sock_, static_cast<char*>(buff), sz, 0); | |
243 if ((SOCKET_ERROR == read_bytes) || (0 == read_bytes)) { | |
244 CloseSocket(&sock_); | |
245 return 0; | |
246 } | |
247 return read_bytes; | |
248 } | |
249 } // namespace debug | |
250 | |
OLD | NEW |