summaryrefslogtreecommitdiffstats
path: root/net/base/tcp_client_socket.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/base/tcp_client_socket.cc')
-rw-r--r--net/base/tcp_client_socket.cc57
1 files changed, 38 insertions, 19 deletions
diff --git a/net/base/tcp_client_socket.cc b/net/base/tcp_client_socket.cc
index 6f9e52b..cef7ef2 100644
--- a/net/base/tcp_client_socket.cc
+++ b/net/base/tcp_client_socket.cc
@@ -45,19 +45,26 @@ static int MapWinsockError(DWORD err) {
case WSAETIMEDOUT:
return ERR_TIMED_OUT;
case WSAECONNRESET:
- case WSAENETRESET:
+ case WSAENETRESET: // Related to keep-alive
return ERR_CONNECTION_RESET;
case WSAECONNABORTED:
return ERR_CONNECTION_ABORTED;
case WSAECONNREFUSED:
return ERR_CONNECTION_REFUSED;
case WSAEDISCON:
+ // Returned by WSARecv or WSARecvFrom for message-oriented sockets (where
+ // a return value of zero means a zero-byte message) to indicate graceful
+ // connection shutdown. We should not ever see this error code for TCP
+ // sockets, which are byte stream oriented.
+ NOTREACHED();
return ERR_CONNECTION_CLOSED;
case WSAEHOSTUNREACH:
case WSAENETUNREACH:
return ERR_ADDRESS_UNREACHABLE;
case WSAEADDRNOTAVAIL:
return ERR_ADDRESS_INVALID;
+ case WSA_IO_INCOMPLETE:
+ return ERR_UNEXPECTED;
case ERROR_SUCCESS:
return OK;
default:
@@ -92,6 +99,11 @@ int TCPClientSocket::Connect(CompletionCallback* callback) {
if (rv != OK)
return rv;
+ overlapped_.hEvent = WSACreateEvent();
+ // WSAEventSelect sets the socket to non-blocking mode as a side effect.
+ // Our connect() and recv() calls require that the socket be non-blocking.
+ WSAEventSelect(socket_, overlapped_.hEvent, FD_CONNECT);
+
if (!connect(socket_, ai->ai_addr, static_cast<int>(ai->ai_addrlen))) {
// Connected without waiting!
return OK;
@@ -103,9 +115,6 @@ int TCPClientSocket::Connect(CompletionCallback* callback) {
return MapWinsockError(err);
}
- overlapped_.hEvent = WSACreateEvent();
- WSAEventSelect(socket_, overlapped_.hEvent, FD_CONNECT);
-
watcher_.StartWatching(overlapped_.hEvent, this);
wait_state_ = WAITING_CONNECT;
callback_ = callback;
@@ -124,12 +133,18 @@ void TCPClientSocket::Disconnect() {
// Make sure the message loop is not watching this object anymore.
watcher_.StopWatching();
+ // In most socket implementations, closing a socket results in a graceful
+ // connection shutdown, but in Winsock we have to call shutdown explicitly.
+ // See the MSDN page "Graceful Shutdown, Linger Options, and Socket Closure"
+ // at http://msdn.microsoft.com/en-us/library/ms738547.aspx
+ shutdown(socket_, SD_SEND);
+
// This cancels any pending IO.
closesocket(socket_);
socket_ = INVALID_SOCKET;
WSACloseEvent(overlapped_.hEvent);
- overlapped_.hEvent = NULL;
+ memset(&overlapped_, 0, sizeof(overlapped_));
// Reset for next time.
current_ai_ = addresses_.head();
@@ -150,7 +165,9 @@ bool TCPClientSocket::IsConnected() const {
return true;
}
-int TCPClientSocket::Read(char* buf, int buf_len, CompletionCallback* callback) {
+int TCPClientSocket::Read(char* buf,
+ int buf_len,
+ CompletionCallback* callback) {
DCHECK(socket_ != INVALID_SOCKET);
DCHECK(wait_state_ == NOT_WAITING);
DCHECK(!callback_);
@@ -171,7 +188,9 @@ int TCPClientSocket::Read(char* buf, int buf_len, CompletionCallback* callback)
return MapWinsockError(WSAGetLastError());
}
-int TCPClientSocket::Write(const char* buf, int buf_len, CompletionCallback* callback) {
+int TCPClientSocket::Write(const char* buf,
+ int buf_len,
+ CompletionCallback* callback) {
DCHECK(socket_ != INVALID_SOCKET);
DCHECK(wait_state_ == NOT_WAITING);
DCHECK(!callback_);
@@ -196,17 +215,10 @@ int TCPClientSocket::CreateSocket(const struct addrinfo* ai) {
socket_ = WSASocket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, NULL, 0,
WSA_FLAG_OVERLAPPED);
if (socket_ == INVALID_SOCKET) {
- LOG(ERROR) << "WSASocket failed: " << WSAGetLastError();
- return ERR_FAILED;
- }
-
- // Configure non-blocking mode.
- u_long non_blocking_mode = 1;
- if (ioctlsocket(socket_, FIONBIO, &non_blocking_mode)) {
- LOG(ERROR) << "ioctlsocket failed: " << WSAGetLastError();
- return ERR_FAILED;
+ DWORD err = WSAGetLastError();
+ LOG(ERROR) << "WSASocket failed: " << err;
+ return MapWinsockError(err);
}
-
return OK;
}
@@ -226,8 +238,11 @@ void TCPClientSocket::DidCompleteConnect() {
wait_state_ = NOT_WAITING;
WSANETWORKEVENTS events;
- WSAEnumNetworkEvents(socket_, overlapped_.hEvent, &events);
- if (events.lNetworkEvents & FD_CONNECT) {
+ int rv = WSAEnumNetworkEvents(socket_, overlapped_.hEvent, &events);
+ if (rv == SOCKET_ERROR) {
+ NOTREACHED();
+ result = MapWinsockError(WSAGetLastError());
+ } else if (events.lNetworkEvents & FD_CONNECT) {
wait_state_ = NOT_WAITING;
DWORD error_code = static_cast<DWORD>(events.iErrorCode[FD_CONNECT_BIT]);
if (current_ai_->ai_next && (
@@ -258,6 +273,7 @@ void TCPClientSocket::DidCompleteIO() {
DWORD num_bytes, flags;
BOOL ok = WSAGetOverlappedResult(
socket_, &overlapped_, &num_bytes, FALSE, &flags);
+ WSAResetEvent(overlapped_.hEvent);
wait_state_ = NOT_WAITING;
DoCallback(ok ? num_bytes : MapWinsockError(WSAGetLastError()));
}
@@ -273,6 +289,9 @@ void TCPClientSocket::OnObjectSignaled(HANDLE object) {
case WAITING_WRITE:
DidCompleteIO();
break;
+ default:
+ NOTREACHED();
+ break;
}
}