mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-29 02:21:44 +00:00
Fix Windows client.
Windows returns WSAEWOULDBLOCK on a connect() attempt on a nonblocking socket. Also wrap socket error handling so errors are correctly reported on Windows. Fixes #19.
This commit is contained in:
27
src/tcpsockets/SocketError.cpp
Normal file
27
src/tcpsockets/SocketError.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "SocketError.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace tcpsockets {
|
||||
|
||||
std::string SocketStrerror(int code) {
|
||||
#ifdef _WIN32
|
||||
LPSTR errstr = nullptr;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
0, code, 0, (LPSTR)&errstr, 0, 0);
|
||||
std::string rv(errstr);
|
||||
LocalFree(errstr);
|
||||
return rv;
|
||||
#else
|
||||
return strerror(code);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace tcpsockets
|
||||
37
src/tcpsockets/SocketError.h
Normal file
37
src/tcpsockets/SocketError.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef TCPSOCKETS_SOCKETERROR_H_
|
||||
#define TCPSOCKETS_SOCKETERROR_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <WinSock2.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
namespace tcpsockets {
|
||||
|
||||
static inline int SocketErrno() {
|
||||
#ifdef _WIN32
|
||||
return WSAGetLastError();
|
||||
#else
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string SocketStrerror(int code);
|
||||
|
||||
static inline std::string SocketStrerror() {
|
||||
return SocketStrerror(SocketErrno());
|
||||
}
|
||||
|
||||
} // namespace tcpsockets
|
||||
|
||||
#endif // TCPSOCKETS_SOCKETERROR_H_
|
||||
@@ -36,6 +36,9 @@
|
||||
|
||||
#include "llvm/SmallString.h"
|
||||
#include "../Log.h"
|
||||
#include "SocketError.h"
|
||||
|
||||
using namespace tcpsockets;
|
||||
|
||||
TCPAcceptor::TCPAcceptor(int port, const char* address)
|
||||
: m_lsd(0),
|
||||
@@ -75,7 +78,7 @@ int TCPAcceptor::start() {
|
||||
if (m_address.size() > 0) {
|
||||
#ifdef _WIN32
|
||||
llvm::SmallString<128> addr_copy(m_address);
|
||||
addr_copy.append('\0');
|
||||
addr_copy.push_back('\0');
|
||||
int size = sizeof(address);
|
||||
WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size);
|
||||
#else
|
||||
@@ -91,13 +94,13 @@ int TCPAcceptor::start() {
|
||||
|
||||
int result = bind(m_lsd, (struct sockaddr*)&address, sizeof(address));
|
||||
if (result != 0) {
|
||||
ERROR("bind() failed: " << strerror(errno));
|
||||
ERROR("bind() failed: " << SocketStrerror());
|
||||
return result;
|
||||
}
|
||||
|
||||
result = listen(m_lsd, 5);
|
||||
if (result != 0) {
|
||||
ERROR("listen() failed: " << strerror(errno));
|
||||
ERROR("listen() failed: " << SocketStrerror());
|
||||
return result;
|
||||
}
|
||||
m_listening = true;
|
||||
@@ -125,7 +128,7 @@ std::unique_ptr<NetworkStream> TCPAcceptor::accept() {
|
||||
std::memset(&address, 0, sizeof(address));
|
||||
int sd = ::accept(m_lsd, (struct sockaddr*)&address, &len);
|
||||
if (sd < 0) {
|
||||
if (!m_shutdown) ERROR("accept() failed: " << strerror(errno));
|
||||
if (!m_shutdown) ERROR("accept() failed: " << SocketStrerror());
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
|
||||
#include "llvm/SmallString.h"
|
||||
#include "../Log.h"
|
||||
#include "SocketError.h"
|
||||
|
||||
using namespace tcpsockets;
|
||||
|
||||
static int ResolveHostName(const char* hostname, struct in_addr* addr) {
|
||||
struct addrinfo* res;
|
||||
@@ -73,7 +76,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
if (ResolveHostName(server, &(address.sin_addr)) != 0) {
|
||||
#ifdef _WIN32
|
||||
llvm::SmallString<128> addr_copy(server);
|
||||
addr_copy.append('\0');
|
||||
addr_copy.push_back('\0');
|
||||
int size = sizeof(address);
|
||||
WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size);
|
||||
#else
|
||||
@@ -85,7 +88,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
if (timeout == 0) {
|
||||
int sd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) {
|
||||
DEBUG("connect() failed: " << strerror(errno));
|
||||
DEBUG("connect() failed: " << SocketStrerror());
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
|
||||
@@ -108,10 +111,14 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
#endif
|
||||
|
||||
// Connect with time limit
|
||||
std::string message;
|
||||
if ((result = ::connect(sd, (struct sockaddr*)&address, sizeof(address))) <
|
||||
0) {
|
||||
if (errno == EINPROGRESS) {
|
||||
int my_errno = SocketErrno();
|
||||
#ifdef _WIN32
|
||||
if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) {
|
||||
#else
|
||||
if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) {
|
||||
#endif
|
||||
tv.tv_sec = timeout;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&sdset);
|
||||
@@ -120,7 +127,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
len = sizeof(int);
|
||||
getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len);
|
||||
if (valopt) {
|
||||
DEBUG("connect() error " << valopt << " - " << strerror(valopt));
|
||||
DEBUG("select() error " << valopt << " - " << SocketStrerror(valopt));
|
||||
}
|
||||
// connection established
|
||||
else
|
||||
@@ -128,7 +135,7 @@ std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
|
||||
} else
|
||||
DEBUG("connect() timed out");
|
||||
} else
|
||||
DEBUG("connect() error " << errno << " - " << strerror(errno));
|
||||
DEBUG("connect() error " << SocketErrno() << " - " << SocketStrerror());
|
||||
}
|
||||
|
||||
// Return socket to blocking mode
|
||||
|
||||
Reference in New Issue
Block a user