Index: build_tools/debug_server/debug_server/common/debug_socket.cpp |
=================================================================== |
--- build_tools/debug_server/debug_server/common/debug_socket.cpp (revision 0) |
+++ build_tools/debug_server/debug_server/common/debug_socket.cpp (revision 0) |
@@ -0,0 +1,245 @@ |
+#include "debug_socket.h" |
+ |
+namespace { |
+fd_set* kNoFdSet = NULL; |
+const int kMicrosecondsInOneMillisecons = 1000; |
+const char* kAnyLocalHost = NULL; |
+sockaddr* kNoPeerAddress = NULL; |
+const int kWaitForOneWriteMs = 1000; |
+const int kTmpBufferSize = 2048; |
+ |
+bool InitSocketLib() { |
+ WSADATA wsa_data; |
+ WORD version_requested = MAKEWORD(1, 1); |
+ return (WSAStartup(version_requested, &wsa_data) == 0); |
+} |
+ |
+void FreeSocketLib() { |
+ WSACleanup(); |
+} |
+ |
+void CloseSocket(SOCKET* sock) { |
+ if (INVALID_SOCKET != *sock) { |
+ closesocket(*sock); |
+ *sock = INVALID_SOCKET; |
+ } |
+} |
+ |
+timeval CreateTimeval(int milliseconds) { |
+ timeval timeout; |
+ timeout.tv_sec = 0; |
+ timeout.tv_usec = milliseconds * kMicrosecondsInOneMillisecons; |
+ return timeout; |
+} |
+ |
+sockaddr_in CreateSockAddr(const char* host, int port) { |
+ sockaddr_in addr; |
+ memset(&addr, 0, sizeof(addr)); |
+ addr.sin_family = AF_INET; |
+ addr.sin_port = htons(port); // Convert port number from host byte order |
+ // to network byte order. |
+ if ((NULL == host) || (strlen(host) == 0)) { |
+ addr.sin_addr.s_addr = htonl(INADDR_ANY); |
+ } else { |
+ hostent* hostDescr = gethostbyname(host); |
+ if (NULL != hostDescr) |
+ addr.sin_addr.s_addr = |
+ *(reinterpret_cast<unsigned long**>(hostDescr->h_addr_list)[0]); |
+ } |
+ return addr; |
+} |
+ |
+void SetSocketOptions(SOCKET sock) { |
+ if (INVALID_SOCKET != sock) { |
+ // Setup socket to flush pending data on close. |
+ linger ling; |
+ ling.l_onoff = 1; |
+ ling.l_linger = 10; // The socket will remain open for a specified amount |
+ // of time (in seconds). |
+ setsockopt(sock, |
+ SOL_SOCKET, |
+ SO_LINGER, |
+ reinterpret_cast<char*>(&ling), |
+ sizeof(ling)); |
+ // Turn off buffering, to speedup debugger communication. |
+ long opt = 1; |
+ setsockopt(sock, |
+ IPPROTO_TCP, |
+ TCP_NODELAY, |
+ reinterpret_cast<char*>(&opt), |
+ sizeof(opt)); |
+ } |
+} |
+} // namespace |
+ |
+namespace debug { |
+ListeningSocket::ListeningSocket() |
+ : sock_(INVALID_SOCKET) { |
+ init_success_ = InitSocketLib(); |
+} |
+ |
+ListeningSocket::~ListeningSocket() { |
+ CloseSocket(&sock_); |
+ if (init_success_) |
+ FreeSocketLib(); |
+} |
+ |
+void ListeningSocket::Close() { |
+ CloseSocket(&sock_); |
+} |
+ |
+bool ListeningSocket::Setup(int port) { |
+ Close(); |
+ sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
+ if (INVALID_SOCKET == sock_) |
+ return false; |
+ |
+ // Associate local address with socket. |
+ sockaddr_in addr = CreateSockAddr(kAnyLocalHost, port); |
+ if (bind(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) { |
+ CloseSocket(&sock_); |
+ return false; |
+ } |
+ // Mark a socket as accepting connections. |
+ if (listen(sock_, SOMAXCONN) != 0) |
+ CloseSocket(&sock_); |
+ return (INVALID_SOCKET != sock_); |
+} |
+ |
+bool ListeningSocket::Accept(Socket* new_connection, long wait_ms) { |
+ fd_set socks; |
+ FD_ZERO(&socks); |
+ FD_SET(sock_, &socks); |
+ |
+ // Wait for incoming connection. |
+ timeval timeout = CreateTimeval(wait_ms); |
+ if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { |
+ CloseSocket(&sock_); |
+ return false; |
+ } |
+ // No connection requests. |
+ if (!FD_ISSET(sock_, &socks)) |
+ return false; |
+ |
+ // Accept a connection request. |
+ SOCKET sock = accept(sock_, kNoPeerAddress, 0); |
+ if(INVALID_SOCKET != sock) |
+ new_connection->AttachTo(sock); |
+ |
+ return new_connection->IsConnected(); |
+} |
+ |
+Socket::Socket() |
+ : sock_(INVALID_SOCKET) { |
+ init_success_ = InitSocketLib(); |
+} |
+ |
+void Socket::AttachTo(SOCKET sock) { |
+ Close(); |
+ sock_ = sock; |
+ SetSocketOptions(sock_); |
+} |
+ |
+Socket::~Socket() { |
+ CloseSocket(&sock_); |
+ if (init_success_) |
+ FreeSocketLib(); |
+} |
+ |
+void Socket::Close() { |
+ CloseSocket(&sock_); |
+} |
+ |
+bool Socket::ConnectTo(const std::string& host, int port) { |
+ Close(); |
+ sock_ = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
+ if (INVALID_SOCKET == sock_) |
+ return false; |
+ |
+ sockaddr_in addr = CreateSockAddr(host.c_str(), port); |
+ if (connect(sock_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0) |
+ CloseSocket(&sock_); |
+ else |
+ SetSocketOptions(sock_); |
+ return IsConnected(); |
+} |
+ |
+bool Socket::IsConnected() const { |
+ return (INVALID_SOCKET != sock_); |
+} |
+ |
+size_t Socket::Write(const void* buff, size_t sz, int wait_ms) { |
+ if (!IsConnected()) |
+ return 0; |
+ |
+ fd_set socks; |
+ FD_ZERO(&socks); |
+ FD_SET(sock_, &socks); |
+ |
+ // Wait for 'write ready'. |
+ timeval timeout = CreateTimeval(wait_ms); |
+ if (select(sock_ + 1, kNoFdSet, &socks, kNoFdSet, &timeout) < 0) { |
+ CloseSocket(&sock_); |
+ return 0; |
+ } |
+ size_t bytes_send = 0; |
+ if (FD_ISSET(sock_, &socks)) { |
+ bytes_send = send(sock_, static_cast<const char*>(buff), sz, 0); |
+ if (bytes_send < 0) |
+ CloseSocket(&sock_); |
+ } |
+ return bytes_send; |
+} |
+ |
+// Blocks until all data has been send. |
+void Socket::WriteAll(const void* buff, size_t sz) { |
+ const char* ptr = static_cast<const char*>(buff); |
+ while (sz) { |
+ long wr = Write(ptr, sz, kWaitForOneWriteMs); |
+ if (!IsConnected()) |
+ break; |
+ sz -= wr; |
+ ptr += wr; |
+ } |
+} |
+ |
+void Socket::WriteAll(const Blob& blob) { |
+ char buff[kTmpBufferSize]; |
+ size_t pos = 0; |
+ while (pos < blob.Size()) { |
+ size_t num = blob.Size() - pos; |
+ if (num > sizeof(buff)) |
+ num = sizeof(buff); |
+ for (size_t i = 0; i < num; i++) |
+ buff[i] = blob[pos + i]; |
+ WriteAll(buff, num); |
+ pos += num; |
+ } |
+} |
+ |
+size_t Socket::Read(void* buff, size_t sz, int wait_ms) { |
+ if (!IsConnected()) |
+ return 0; |
+ |
+ fd_set socks; |
+ FD_ZERO(&socks); |
+ FD_SET(sock_, &socks); |
+ timeval timeout = CreateTimeval(wait_ms); |
+ |
+ // Wait for data. |
+ if (select(sock_ + 1, &socks, kNoFdSet, kNoFdSet, &timeout) < 0) { |
+ CloseSocket(&sock_); |
+ return 0; |
+ } |
+ // No data available. |
+ if (!FD_ISSET(sock_, &socks)) |
+ return 0; |
+ |
+ size_t read_bytes = recv(sock_, static_cast<char*>(buff), sz, 0); |
+ if ((SOCKET_ERROR == read_bytes) || (0 == read_bytes)) { |
+ CloseSocket(&sock_); |
+ return 0; |
+ } |
+ return read_bytes; |
+} |
+} // namespace debug |