#include "pcpt.h" e_pcpt_t _pcptGetErrorFromWin(int err) { switch (err) { case WSAEBADF: case WSAEINVAL: case WSAENOTSOCK: case WSAEISCONN: return e_pcpt_wsa2_generic; case WSAEMFILE: return e_pcpt_cannot_open; case WSAEWOULDBLOCK: case WSAETIMEDOUT: return e_pcpt_to; case WSAEADDRNOTAVAIL: return e_pcpt_inval_addr; case WSAECONNABORTED: case WSAECONNRESET: return e_pcpt_closed; case WSAENOBUFS: return e_pcpt_nobufs; case WSANOTINITIALISED: return e_pcpt_wsa_noinit; default: return e_pcpt_unknown; } } e_pcpt_t pcptInitStream(pcpt_t *sock) { SOCKET s; if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } s = socket(AF_INET, SOCK_STREAM, 0); if (s == SOCKET_INVAL) return _errW2T(WSAGetLastError()); closesocket(s); sock->client_open = 0; sock->open = PCPT_CLOSED; sock->client_event = NULL; sock->server_event = NULL; sock->send_buf = NULL; sock->send_buf_count = NULL; sock->recv_buf_count = NULL; sock->recv_buf = NULL; sock->server_sock = SOCKET_INVAL; sock->client_sock = SOCKET_INVAL; sock->err = e_pcpt_unknown; memset(&sock->client_addr, 0, sizeof sock->client_addr); sock->field_0x58 = 0; sock->tcp_nodelay = 0; sock->config_0 = 12000; sock->config_1 = 5; sock->so_linger = 1; return e_pcpt_ok; } void pcptClose(pcpt_t *sock) { if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return; } if (sock->server_sock != SOCKET_INVAL) { WSAEventSelect(sock->server_sock, 0, 0); WSACloseEvent(sock->server_event); sock->server_event = NULL; closesocket(sock->server_sock); sock->server_sock = SOCKET_INVAL; } if (sock->client_sock != SOCKET_INVAL) { WSAEventSelect(sock->client_sock, 0, 0); WSACloseEvent(sock->client_event); sock->client_event = NULL; closesocket(sock->client_sock); sock->client_sock = SOCKET_INVAL; } sock->client_open = 0; sock->open = PCPT_CLOSED; sock->err = e_pcpt_unknown; if (sock->client_event != NULL) { WSACloseEvent(sock->client_event); sock->client_event = NULL; } if (sock->server_event != NULL) { WSACloseEvent(sock->server_event); sock->server_event = NULL; } sock->send_buf = NULL; sock->send_buf_count = NULL; sock->recv_buf_count = NULL; sock->recv_buf = NULL; memset(&sock->client_addr, 0, sizeof sock->client_addr); sock->field_0x58 = 0; } void pcptCloseDataSock(pcpt_t *sock) { if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return; } if (sock->field_0x58 != 0) { sock->open = PCPT_LISTENING; } sock->client_open = 0; if (sock->client_sock != SOCKET_INVAL) { WSAEventSelect(sock->client_sock, 0, 0); WSACloseEvent(sock->client_event); sock->client_event = NULL; closesocket(sock->client_sock); sock->client_sock = SOCKET_INVAL; } } e_pcpt_t pcptAcceptServer(pcpt_t *stream, timeout_t timeout_ms) { if (stream == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } e_pcpt_t err = pcptCheckEvent(stream->server_event, timeout_ms, stream->server_sock, FD_ACCEPT); if (err != e_pcpt_ok) return err; int addrlen = 16; SOCKET client = accept(stream->server_sock, &stream->client_addr, &addrlen); stream->client_sock = client; if (client == SOCKET_INVAL) return _errW2T(GetLastError()); WSAEVENT event = WSACreateEvent(); stream->client_event = event; if (event == NULL) { closesocket(stream->client_sock); stream->client_sock = SOCKET_INVAL; return e_pcpt_unknown; } WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE); uint so_linger = (uint)(!!stream->so_linger); setsockopt(stream->client_sock, SOL_SOCKET, SO_LINGER, (void *)&so_linger, sizeof so_linger); uint nodelay = (uint)(!stream->tcp_nodelay); setsockopt(stream->client_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&nodelay, sizeof nodelay); return e_pcpt_ok; } e_pcpt_t pcptCheckConnectAble(pcpt_t *stream, timeout_t timeout_ms) { DWORD DVar1; uint uVar3; HANDLE event; bool bVar5; e_pcpt_t local_44; u_long local_40; amtime_t now; amtime_t start; if (stream == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } amiTimerGet(&start); DVar1 = timeout_ms; if (timeout_ms == TIMEOUT_NONE) DVar1 = TIMEOUT_NONE; while (DVar1 = WaitForSingleObject(stream->client_event, DVar1), DVar1 == WAIT_TIMEOUT) { LAB_004589c8: amiTimerGet(&now); uVar3 = _amTimeDelta(now, start); if (timeout_ms <= uVar3) return e_pcpt_to; DVar1 = timeout_ms - uVar3; } if (DVar1 == 0) { WSANETWORKEVENTS net_events; if (FAILED(WSAEnumNetworkEvents(stream->client_sock, stream->client_event, &net_events))) { bVar5 = WSAGetLastError() == WSAEWOULDBLOCK; } else { if ((net_events.lNetworkEvents & 0x10) != 0 && net_events.iErrorCode[FD_CONNECT_BIT] == 0) { local_44 = e_pcpt_ok; goto LAB_00458a1e; } if (WSAGetLastError() == WSAEWOULDBLOCK) goto LAB_004589c8; bVar5 = net_events.iErrorCode[FD_CONNECT_BIT] == WSAECONNREFUSED; } if (bVar5) goto LAB_004589c8; } local_44 = e_pcpt_wsa2_generic; LAB_00458a1e: local_40 = 0; WSAEventSelect(stream->client_sock, 0, 0); WSACloseEvent(stream->client_event); stream->client_event = NULL; if (local_44 != e_pcpt_ok) { closesocket(stream->client_sock); stream->client_sock = SOCKET_INVAL; return local_44; } ioctlsocket(stream->client_sock, FIONBIO, &local_40); event = WSACreateEvent(); stream->client_event = event; if (event != NULL) { WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE); return e_pcpt_ok; } closesocket(stream->client_sock); stream->client_sock = SOCKET_INVAL; return e_pcpt_unknown; } e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask) { amtime_t now; amtime_t start; WSANETWORKEVENTS networkEvents; amiTimerGet(&start); now.seconds = start.seconds; now.microseconds = start.microseconds; DWORD wait_timeout = timeout_ms; if (timeout_ms == TIMEOUT_NONE) wait_timeout = TIMEOUT_NONE; if (event == NULL) { PCP_LOG("Error : EVENT HANDLE error\n"); return e_pcpt_pointer_unset; } event_mask &= 0xffffffdf; while (1) { DWORD err = WaitForSingleObject(event, wait_timeout); if ((err != WAIT_TIMEOUT && err != 0) || FAILED(err)) { return e_pcpt_wsa2_generic; } if (err != WAIT_TIMEOUT) { if (FAILED(WSAEnumNetworkEvents(socket, event, &networkEvents))) return e_pcpt_wsa2_generic; if ((networkEvents.lNetworkEvents & 0x20) != 0) return e_pcpt_closed; if ((event_mask & networkEvents.lNetworkEvents) != 0) return e_pcpt_ok; } if (timeout_ms != TIMEOUT_NONE) { amiTimerGet(&now); uint elapsed = _amTimeDelta(now, start); if ((uint)timeout_ms <= elapsed) return e_pcpt_to; wait_timeout = timeout_ms - elapsed; } } } e_pcpt_t pcptOpenDataSockServer(pcpt_t *sock, timeout_t timeout_ms) { if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } if (sock->open == PCPT_CONNECTED) return e_pcpt_already_open; if (sock->open == PCPT_CLOSED) return e_pcpt_not_open; if ((sock->client_sock == SOCKET_INVAL)) { e_pcpt_t err = pcptAcceptServer(sock, timeout_ms); if (err != e_pcpt_ok) return err; } sock->open = PCPT_CONNECTED; return e_pcpt_ok; } e_pcpt_t pcptOpenServer(pcpt_t *stream, int open_mode, ushort port) { e_pcpt_t err; if (stream == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } if (stream->server_sock != SOCKET_INVAL || stream->client_sock != SOCKET_INVAL) return stream->err = e_pcpt_already_open; amtime_t start; amiTimerGet(&start); stream->field_0x58 = 1; stream->open = PCPT_CLOSED; SOCKET s = socket(AF_INET, SOCK_STREAM, 0); stream->server_sock = s; if (s == SOCKET_INVAL) return stream->err = _errW2T(GetLastError()); uint reuseaddr = 1; if (FAILED(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddr, 4))) { err = _errW2T(GetLastError()); closesocket(stream->server_sock); stream->server_sock = SOCKET_INVAL; return stream->err = err; } SOCKADDR_IN addr = { .sin_family = AF_INET, .sin_port = ntohs(port), .sin_addr.s_addr = ntohl(0) }; if (open_mode != OPEN_MODE_GLOBAL) { INT len = sizeof &addr.sin_addr.s_addr; WSAStringToAddressW(L"127.0.0.1", AF_INET, NULL, (LPSOCKADDR)&addr.sin_addr.s_addr, &len); } if (FAILED(bind(stream->server_sock, (SOCKADDR *)&addr, sizeof addr))) { err = _errW2T(GetLastError()); closesocket(stream->server_sock); stream->server_sock = SOCKET_INVAL; return stream->err = err; } if (FAILED(listen(stream->server_sock, 128))) { err = _errW2T(GetLastError()); closesocket(stream->server_sock); stream->server_sock = SOCKET_INVAL; return stream->err = err; } WSAEVENT event = WSACreateEvent(); stream->server_event = event; if (event != NULL) { WSAEventSelect(stream->server_sock, event, FD_CLOSE | FD_ACCEPT); stream->open = PCPT_LISTENING; stream->client_open = 0; return stream->err = e_pcpt_ok; } closesocket(stream->server_sock); stream->server_sock = SOCKET_INVAL; return stream->err = e_pcpt_unknown; } e_pcpt_t pcptRecv(pcpt_t *sock, unsigned char *recv_buf, size_t *recv_buf_len, timeout_t timeout_ms) { e_pcpt_t err; amtime_t now; amtime_t start; if (sock == NULL || recv_buf == NULL || recv_buf_len == NULL) { printf("%p %p %p\n", sock, recv_buf, recv_buf_len); PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open; if (sock->client_open != 0) return sock->err = e_pcpt_already_connected; sock->recv_buf = recv_buf; sock->recv_buf_count = recv_buf_len; sock->client_open = 3; if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) { amiTimerGet(&start); sock->err = err = pcptOpenDataSockServer(sock, timeout_ms); if (err == e_pcpt_to) return e_pcpt_to; if (err != e_pcpt_ok) { pcptCloseDataSock(sock); return sock->err; } if (timeout_ms != TIMEOUT_NONE) { amiTimerGet(&now); uint elapsed = _amTimeDelta(now, start); if (elapsed < timeout_ms) timeout_ms = timeout_ms - elapsed; else timeout_ms = 0; } } sock->err = err = pcptCheckEvent(sock->client_event, timeout_ms, sock->client_sock, FD_READ); if (err == e_pcpt_to) return e_pcpt_to; sock->client_open = 0; if (err == e_pcpt_ok) { size_t recv_count = recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0); if (0 < (int)recv_count) { *recv_buf_len = recv_count; sock->err = e_pcpt_ok; return e_pcpt_ok; } if (recv_count == 0) { pcptCloseDataSock(sock); return sock->err = e_pcpt_closed; } sock->err = _errW2T(GetLastError()); } pcptCloseDataSock(sock); return sock->err; } e_pcpt_t pcptSend(pcpt_t *sock, unsigned char *send_buf, size_t *send_len, uint param_4, timeout_t timeout_ms) { e_pcpt_t err; amtime_t now; amtime_t start_time; if (sock == NULL || send_buf == NULL || send_len == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open; if (sock->client_open != 0) return sock->err = e_pcpt_already_connected; sock->send_buf_count = send_len; sock->send_buf = send_buf; sock->client_open = 2; sock->field_0x14 = param_4; sock->field_0x54 = 0; if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) { amiTimerGet(&start_time); err = pcptOpenDataSockServer(sock, timeout_ms); sock->err = err; if (err == e_pcpt_to) return e_pcpt_to; if (err == e_pcpt_ok) { amiTimerGet(&now); uint elapsed = _amTimeDelta(now, start_time); if (timeout_ms != TIMEOUT_NONE) { if (elapsed < timeout_ms) timeout_ms = timeout_ms - elapsed; else timeout_ms = 0; } goto LAB_0045930e; } } else { LAB_0045930e: err = pcptSendAllMsg(sock, timeout_ms); sock->err = err; if (err == e_pcpt_to) { return e_pcpt_to; } sock->client_open = 0; if (err == e_pcpt_ok) return err; } pcptCloseDataSock(sock); return sock->err; } e_pcpt_t pcptSendAllMsg(pcpt_t *sock, timeout_t timeout_ms) { size_t sVar1; bool bVar2; e_pcpt_t err; bool bVar3; amtime_t now; amtime_t start; if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } if (sock->send_buf == NULL || sock->send_buf_count == NULL) { PCP_LOG("error send buffer isn\'t set\n"); return e_pcpt_pointer_unset; } bVar3 = sock->field_0x54 == 0; amiTimerGet(&start); sVar1 = *sock->send_buf_count; while (1) { if (sVar1 == 0) { sock->field_0x54 = 0; return e_pcpt_ok; } bVar2 = false; amiTimerGet(&now); uint elapsed = _amTimeDelta(now, start); if (timeout_ms != TIMEOUT_NONE && timeout_ms < elapsed) return e_pcpt_to; uint wait_time; if (bVar3) { wait_time = timeout_ms; if (timeout_ms != TIMEOUT_NONE) wait_time = timeout_ms - elapsed; } else { if ((timeout_ms == TIMEOUT_NONE) || (wait_time = timeout_ms - elapsed, sock->field_0x14 <= wait_time && wait_time != sock->field_0x14)) { wait_time = sock->field_0x14; bVar2 = true; } } int sent = send(sock->client_sock, (char *)sock->send_buf, *sock->send_buf_count, 0); if (sent == -1) { err = _errW2T(GetLastError()); if (err != e_pcpt_to) return err; err = pcptCheckEvent(sock->client_event, wait_time, sock->client_sock, FD_WRITE); if (err == e_pcpt_to) { if (!bVar2) return e_pcpt_to; sock->field_0x54 = 0; return e_pcpt_NO_IDEA_WHAT_THIS_IS; } if (err != e_pcpt_ok) return err; } else { sock->send_buf = sock->send_buf + sent; sock->field_0x54 = 1; *sock->send_buf_count = *sock->send_buf_count - sent; } bVar3 = false; sVar1 = *sock->send_buf_count; } } void pcptSetConfig(pcpt_t *stream, uint config, uint value) { if (stream == NULL) { PCP_LOG("error don\'t set stream\n"); return; } switch (config) { case PCPT_CONFIG_0: stream->config_0 = value; break; case PCPT_CONFIG_1: stream->config_1 = value; break; case PCPT_SO_LINGER: stream->so_linger = value; break; case PCPT_TCP_NODELAY: stream->tcp_nodelay = value; break; } } // TODO: TIDY e_pcpt_t pcptIsBusy(pcpt_t *sock, timeout_t timeout_ms) { bool bVar1; bool bVar2; uint uVar3; uint uVar4; SOCKET SVar5; WSAEVENT event; int iVar7; e_pcpt_t eVar8; u_long timeout_ms_00; uint uVar10; amtime_t local_18; amtime_t local_10; amtime_t local_8; timeout_ms_00 = timeout_ms; if (sock == NULL) { PCP_LOG("error PCP stream isn\'t set\n"); return e_pcpt_pointer_unset; } switch (sock->client_open) { case 0: sock->err = e_pcpt_no_client; return sock->err; case 1: if (sock->open != PCPT_CLOSED) { sock->err = e_pcpt_cannot_open; sock->client_open = 0; return sock->err; } amiTimerGet(&local_10); uVar10 = timeout_ms_00; do { bVar1 = false; bVar2 = false; amiTimerGet(&local_18); if (uVar10 != TIMEOUT_NONE) { uVar3 = _amTimeDelta(local_18, local_10); if (uVar3 < uVar10) { timeout_ms_00 = uVar10 - uVar3; } else { bVar2 = true; timeout_ms_00 = 0; } } amiTimerGet(&local_18); uVar4 = _amTimeMs(local_18) - sock->field_0x40; uVar3 = sock->config_0; if (uVar3 < uVar4) { timeout_ms_00 = 0; LAB_00459626: bVar1 = true; } else { if ((uVar10 == TIMEOUT_NONE) || (uVar3 < timeout_ms_00)) { timeout_ms_00 = uVar3 - uVar4; goto LAB_00459626; } } eVar8 = pcptCheckConnectAble(sock, timeout_ms_00); sock->err = eVar8; if (eVar8 != e_pcpt_to) { sock->client_open = 0; if (eVar8 == e_pcpt_ok) { sock->open = PCPT_CONNECTED; return sock->err; } break; } if (bVar1) { WSAEventSelect(sock->client_sock, 0, 0); WSACloseEvent(sock->client_event); sock->client_event = NULL; closesocket(sock->client_sock); sock->client_sock = SOCKET_INVAL; SVar5 = socket(2, 1, 0); sock->client_sock = SVar5; if (SVar5 == SOCKET_INVAL) goto LAB_004599cf; event = WSACreateEvent(); sock->client_event = event; if (event == NULL) { closesocket(sock->client_sock); sock->err = e_pcpt_unknown; sock->client_sock = SOCKET_INVAL; return sock->err; } WSAEventSelect(sock->client_sock, event, FD_CONNECT | FD_CLOSE); iVar7 = connect(sock->client_sock, &sock->client_addr, 16); if (iVar7 != -1) { WSAEventSelect(sock->client_sock, 0, 0); WSACloseEvent(sock->client_event); sock->client_event = NULL; timeout_ms = 0; ioctlsocket(sock->client_sock, FIONBIO, (u_long *)&timeout_ms); event = WSACreateEvent(); sock->client_event = event; if (event != NULL) { WSAEventSelect(sock->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE); sock->err = e_pcpt_ok; sock->client_open = 0; sock->open = PCPT_CONNECTED; return e_pcpt_ok; } closesocket(sock->client_sock); sock->err = e_pcpt_unknown; sock->client_sock = SOCKET_INVAL; return sock->err; } amiTimerGet(&local_8); sock->field_0x40 = _amTimeMs(local_8); } else { if (bVar2) { sock->err = e_pcpt_to; return e_pcpt_to; } } uVar10 = timeout_ms; } while (sock->err == e_pcpt_to); break; case 2: if (sock->open == PCPT_CLOSED) { sock->err = e_pcpt_not_open; return e_pcpt_not_open; } if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) { amiTimerGet(&local_10); eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00); sock->err = eVar8; if (eVar8 == e_pcpt_to) { return e_pcpt_to; } if (eVar8 != e_pcpt_ok) { LAB_0045997d: pcptCloseDataSock(sock); return sock->err; } amiTimerGet(&local_18); if (timeout_ms_00 != TIMEOUT_NONE) { iVar7 = (local_18.microseconds - local_10.microseconds) / 1000; if (timeout_ms_00 < (uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) { timeout_ms_00 = ((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00; } else { timeout_ms_00 = 0; } } } eVar8 = pcptSendAllMsg(sock, timeout_ms_00); sock->err = eVar8; if (eVar8 != e_pcpt_to) { if (eVar8 != e_pcpt_ok) { pcptCloseDataSock(sock); } sock->client_open = 0; return sock->err; } break; case 3: if (sock->open == PCPT_CLOSED) { sock->err = e_pcpt_not_open; return sock->err; } if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) { amiTimerGet(&local_10); eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00); sock->err = eVar8; if (eVar8 == e_pcpt_to) { return e_pcpt_to; } if (eVar8 != e_pcpt_ok) goto LAB_0045997d; amiTimerGet(&local_18); if (timeout_ms_00 != TIMEOUT_NONE) { iVar7 = (local_18.microseconds - local_10.microseconds) / 1000; if (timeout_ms_00 < (uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) { timeout_ms_00 = ((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00; } else { timeout_ms_00 = 0; } } } eVar8 = pcptCheckEvent(sock->client_event, timeout_ms_00, sock->client_sock, 1); sock->err = eVar8; if (eVar8 == e_pcpt_to) break; sock->client_open = 0; if (eVar8 != e_pcpt_ok) goto LAB_0045997d; if (sock->recv_buf == NULL || sock->recv_buf_count == NULL) { PCP_LOG("error Recv buffer isn\'t set\n"); return sock->err = e_pcpt_recv_unset; } size_t received = recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0); if (received < 1) { pcptCloseDataSock(sock); if (received == 0) { sock->err = e_pcpt_closed; return e_pcpt_closed; } LAB_004599cf: return sock->err = _errW2T(GetLastError()); } *sock->recv_buf_count = received; default: sock->err = e_pcpt_ok; } return sock->err; }