/*

この作品は、クリエイティブ・コモンズの帰属ライセンスの下でライセンスされています。
この使用許諾条件を見るには、http://creativecommons.org/licenses/by/2.0/jp/ をチェックするか、
クリエイティブ･コモンズに郵便にてお問い合わせください。
住所は：559 Nathan Abbott Way, Stanford, California 94305, USA です。

by ◆F99a.q8oVE http://f99aq.s57.xrea.com
*/

#include "stdafx.h"

//#include <cassert>

//#include "socket.h"

// *****************************************
//	TCPSocket
// *****************************************
void TCPSocket::close()
{
	if (socket_ != INVALID_SOCKET) {
		shutdown(socket_, 1);
		closesocket(socket_);
		socket_ = INVALID_SOCKET;
	}
}

void TCPSocket::nonblocking() const
{
	assert(socket_ != INVALID_SOCKET);
	unsigned long flag = 1;
	ioctlsocket(socket_, FIONBIO, &flag);
}

bool TCPSocket::connect(unsigned long naddr, unsigned short port) const
{
	assert(socket_ != INVALID_SOCKET);
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = naddr;
	sin.sin_port = htons(port);
	bool res = ::connect(socket_, reinterpret_cast<sockaddr*>(&sin), sizeof sin) == 0;
	return res || WSAGetLastError() == WSAEWOULDBLOCK;
}

bool TCPSocket::connect(const char * const host, unsigned short port) const
{
	assert(socket_ != INVALID_SOCKET);
	hostent* phostent = gethostbyname(host);
	if (!phostent)
		return false;

	unsigned long naddr;
	memcpy(&naddr, phostent->h_addr, sizeof naddr);
	return connect(naddr, port);
}

bool TCPSocket::listen(unsigned short port, unsigned long bindaddr) const
{
	assert(socket_ != INVALID_SOCKET);
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = htonl(bindaddr);

	if (bind(socket_, reinterpret_cast<sockaddr*>(&sin), sizeof sin) != 0)
		return false;

	if (::listen(socket_, SOMAXCONN) != 0)
		return false;

	return true;
}

bool TCPSocket::getpeername(sockaddr * const name) const
{
	assert(socket_ != INVALID_SOCKET);
	int len = sizeof sockaddr;
	return ::getpeername(socket_, name, &len) == 0;
}

bool TCPSocket::readable(long sec, long usec) const
{
	assert(socket_ != INVALID_SOCKET);
	fd_set fds;
	FD_ZERO(&fds);
#pragma warning(push, 3)
	FD_SET(socket_, &fds);
#pragma warning(pop)

	timeval waitval = {sec, usec};
	return ::select(FD_SETSIZE, &fds, NULL, NULL, &waitval) > 0;
}

SOCKET TCPSocket::accept(sockaddr * const addr) const
{
	assert(socket_ != INVALID_SOCKET);
	if (addr) {
		int len = sizeof sockaddr;
		return ::accept(socket_, addr, &len);
	} else {
		return ::accept(socket_, NULL, NULL);
	}
}

int TCPSocket::recv(char * const buf, int len) const
{
	assert(socket_ != INVALID_SOCKET);
	return ::recv(socket_, buf, len, 0);
}

int TCPSocket::send(const char * const buf, int len) const
{
	assert(socket_ != INVALID_SOCKET);
	return ::send(socket_, buf, len, 0);
}

// *****************************************
//	TimedTCPSocket
// *****************************************

bool TimedTCPSocket::recvTimeout(int timeout) const
{
	time_t now;
	time(&now);
	return (now - lastrecved) > timeout;
}

bool TimedTCPSocket::sendTimeout(int timeout) const
{
	time_t now;
	time(&now);
	return (now - lastsent) > timeout;
}
