133 lines
2.4 KiB
C++
133 lines
2.4 KiB
C++
#include "Socket.h"
|
|
|
|
#include "WinSock2.h"
|
|
#include "WS2tcpip.h"
|
|
#include "Windows.h"
|
|
|
|
#include <exception>
|
|
#include <cassert>
|
|
|
|
|
|
static bool wsa_initialized = false;
|
|
|
|
|
|
Socket::Socket()
|
|
{
|
|
// Move out to a separate function
|
|
if (!wsa_initialized)
|
|
{
|
|
WSAData data;
|
|
if (WSAStartup(MAKEWORD(2, 2), &data))
|
|
throw std::exception("Failed to initialize WSA");
|
|
wsa_initialized = true;
|
|
}
|
|
|
|
_sock = socket(
|
|
AF_INET,
|
|
SOCK_STREAM,
|
|
0 // IPPROTO_TCP
|
|
);
|
|
|
|
if (_sock == INVALID_SOCKET)
|
|
throw std::exception("Failed to create socket");
|
|
}
|
|
|
|
Socket::~Socket()
|
|
{
|
|
if (!_rc.last())
|
|
return;
|
|
// Flush comunication before closing
|
|
shutdown(_sock, SD_SEND);
|
|
char buffer[512];
|
|
while (read(buffer, sizeof(buffer))) {}
|
|
shutdown(_sock, SD_RECEIVE);
|
|
|
|
closesocket(_sock);
|
|
}
|
|
|
|
void Socket::bind(const char *address, unsigned short port)
|
|
{
|
|
sockaddr_in addr = { 0 };
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons(port);
|
|
if (address)
|
|
inet_pton(AF_INET, address, &addr.sin_addr);
|
|
else
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
if (::bind(_sock, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR)
|
|
throw std::exception("Failed to bind socket");
|
|
}
|
|
|
|
void Socket::listen(int backlog)
|
|
{
|
|
if (::listen(_sock, backlog) == SOCKET_ERROR)
|
|
throw std::exception("Failed to listen on socket");
|
|
}
|
|
|
|
Socket Socket::accept()
|
|
{
|
|
SOCKET sock = ::accept(_sock, nullptr, nullptr);
|
|
if (sock == INVALID_SOCKET)
|
|
throw std::exception("Failed to accept socket");
|
|
Socket socket(sock);
|
|
return std::move(socket);
|
|
}
|
|
|
|
int Socket::read(void* buffer, int size)
|
|
{
|
|
int ret = ::recv(_sock, (char*)buffer, size, 0);
|
|
return max(0, ret); // Clamp to 0, as socket is always synchronious
|
|
}
|
|
|
|
int Socket::write(const char *string)
|
|
{
|
|
return write(string, (int)strlen(string));
|
|
}
|
|
|
|
int Socket::write(const void *data, int size)
|
|
{
|
|
return ::send(_sock, (const char *)data, size, 0);
|
|
}
|
|
|
|
void Socket::end()
|
|
{
|
|
::shutdown(_sock, SD_SEND);
|
|
}
|
|
|
|
|
|
SocketStreamBuf::~SocketStreamBuf()
|
|
{
|
|
sync();
|
|
}
|
|
|
|
int SocketStreamBuf::underflow()
|
|
{
|
|
// System should be buffering received data
|
|
if (!_sock.read(&_c, 1))
|
|
return EOF;
|
|
setg(&_c, &_c, &_c+1);
|
|
return _c;
|
|
}
|
|
|
|
int SocketStreamBuf::overflow(int c)
|
|
{
|
|
if (_buf_size >= _buf_size_max)
|
|
sync();
|
|
|
|
// This check is not required, but it muffles a warning in VisualStudio
|
|
if (_buf_size < _buf_size_max)
|
|
_buf[_buf_size++] = c;
|
|
else
|
|
assert(0);
|
|
|
|
return c;
|
|
}
|
|
|
|
int SocketStreamBuf::sync()
|
|
{
|
|
_sock.write(_buf, _buf_size);
|
|
_buf_size = 0;
|
|
return 0;
|
|
} |