#include "pch.h"
#include "Socket.h"

#pragma comment(lib, "libSceNet_stub_weak.a")
#pragma comment(lib, "libSceSsl_stub_weak.a")

using namespace TwitchInGames;

namespace {
	// ...\sdk_samples\5.000\sample_code\network\api_net\console\resolver.c
	int doResolverNtoa(const char *hostname, SceNetInAddr *addr) {
		SceNetId rid = -1;
		int memid = -1;
		int ret;

		ret = sceNetPoolCreate(__FUNCTION__, 4 * 1024, 0);
		if(ret < 0) {
			printf("sceNetPoolCreate() failed (0x%x errno=%d)\n",
				ret, sce_net_errno);
			goto failed;
		}
		memid = ret;
		ret = sceNetResolverCreate("resolver", memid, 0);
		if(ret < 0) {
			printf("sceNetResolverCreate() failed (0x%x errno=%d)\n",
				ret, sce_net_errno);
			goto failed;
		}
		rid = ret;
		ret = sceNetResolverStartNtoa(rid, hostname, addr, 0, 0, 0);
		if(ret < 0) {
			printf("sceNetResolverStartNtoa() failed (0x%x errno=%d)\n",
				ret, sce_net_errno);
			goto failed;
		}
		ret = sceNetResolverDestroy(rid);
		if(ret < 0) {
			printf("sceNetResolverDestroy() failed (0x%x errno=%d)\n",
				ret, sce_net_errno);
			goto failed;
		}
		ret = sceNetPoolDestroy(memid);
		if(ret < 0) {
			printf("sceNetPoolDestroy() failed (0x%x errno=%d)\n",
				ret, sce_net_errno);
			goto failed;
		}
		return 0;

failed:
		sceNetResolverDestroy(rid);
		sceNetPoolDestroy(memid);
		return ret;
	}
}
Socket::Socket() {
	value= sceNetSocket("connection to server", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, SCE_NET_IPPROTO_IP);
}

Socket::~Socket() {
	sceNetSocketClose(value);
}

void Socket::Connect(string_t hostName, unsigned short port) {
	SceNetSockaddrIn sa{};
	if(sceNetInetPton(SCE_NET_AF_INET, hostName, &sa.sin_addr) <= 0) {
		ThrowIfFailed(doResolverNtoa(hostName, &sa.sin_addr));
	}
	sa.sin_family= SCE_NET_AF_INET;
	sa.sin_port= sceNetHtons(port);
	ThrowIfFailed(sceNetConnect(value, reinterpret_cast<SceNetSockaddr const*>(&sa), sizeof(sa)));
}

int Socket::Receive(void* buffer, size_t size) noexcept {
	return sceNetRecv(value, buffer, size, 0);
}

int Socket::Send(void const* buffer, size_t size) noexcept {
	return sceNetSend(value, buffer, size, 0);
}

void Socket::Shutdown() noexcept {
	sceNetShutdown(value, SCE_NET_SHUT_RDWR);
}
