diff --git a/lib/winapi/Makefile b/lib/winapi/Makefile index 47e8d2f1d..f93e86b28 100644 --- a/lib/winapi/Makefile +++ b/lib/winapi/Makefile @@ -1,4 +1,5 @@ include $(NXDK_DIR)/lib/winapi/winmm/Makefile +include $(NXDK_DIR)/lib/winapi/ws2_32/Makefile WINAPI_SRCS := \ $(NXDK_DIR)/lib/winapi/badptr.c \ diff --git a/lib/winapi/ws2_32/Makefile b/lib/winapi/ws2_32/Makefile new file mode 100644 index 000000000..8206c022b --- /dev/null +++ b/lib/winapi/ws2_32/Makefile @@ -0,0 +1,19 @@ +NXDK_NET=y + +WS2_32_SRCS := \ + $(wildcard $(NXDK_DIR)/lib/winapi/ws2_32/*.c) + +WS2_32_OBJS = $(addsuffix .obj, $(basename $(WS2_32_SRCS))) + +NXDK_CFLAGS += -I$(NXDK_DIR)/lib/winapi/ws2_32 -I$(NXDK_DIR)/lib/net/pktdrv +NXDK_CXXFLAGS += -I$(NXDK_DIR)/lib/winapi/ws2_32 -I$(NXDK_DIR)/lib/net/pktdrv + +$(NXDK_DIR)/lib/ws2_32.lib: $(WS2_32_OBJS) + +main.exe: $(NXDK_DIR)/lib/ws2_32.lib + +CLEANRULES += clean-ws2_32 + +.PHONY: clean-ws2_32 +clean-ws2_32: + $(VE)rm -f $(WS2_32_OBJS) $(NXDK_DIR)/lib/ws2_32.lib diff --git a/lib/winapi/ws2_32/winsock.c b/lib/winapi/ws2_32/winsock.c new file mode 100644 index 000000000..5dae2dd3a --- /dev/null +++ b/lib/winapi/ws2_32/winsock.c @@ -0,0 +1,232 @@ +#define DHCP + + +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include +#ifdef DHCP +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "winsock2.h" + + +#define PKT_TMR_INTERVAL 5 /* ms */ +#define DEBUGGING 0 + +struct netif nforce_netif, *g_pnetif; + +err_t nforceif_init(struct netif *netif); +static void packet_timer(void *arg); + +static void tcpip_init_done(void *arg) +{ + sys_sem_t *init_complete = arg; + sys_sem_signal(init_complete); +} + +static void packet_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + Pktdrv_ReceivePackets(); + sys_timeout(PKT_TMR_INTERVAL, packet_timer, NULL); +} + +#include +#include + +static int map_error_to_winsock(int error) { + switch(error) { +#define MAP_ERROR(error_name) case error_name: return WSA ## error_name; +#undef MAP_ERROR + default: + debugPrint("unhandled error: %d\n", error); + assert(0); + break; + } + return -1; +} + + +int WSAStartup( + WORD wVersionRequired, + LPWSADATA lpWSAData +) { + assert(wVersionRequired == MAKEDWORD(1,1)); + lpWSAData->wVersion = wVersionRequired; + lpWSAData->wHighVersion = MAKEDWORD(1,1); + + + + + + sys_sem_t init_complete; + const ip4_addr_t *ip; + static ip4_addr_t ipaddr, netmask, gw; + +#if DEBUGGING + asm volatile ("jmp ."); + debug_flags = LWIP_DBG_ON; +#else + debug_flags = 0; +#endif + + /* Initialize the TCP/IP stack. Wait for completion. */ + sys_sem_new(&init_complete, 0); + tcpip_init(tcpip_init_done, &init_complete); + sys_sem_wait(&init_complete); + sys_sem_free(&init_complete); + + g_pnetif = netif_add(&nforce_netif, &ipaddr, &netmask, &gw, + NULL, nforceif_init, ethernet_input); + if (!g_pnetif) { + debugPrint("netif_add failed\n"); + return 1; + } + + netif_set_default(g_pnetif); + netif_set_up(g_pnetif); + +#ifdef DHCP + dhcp_start(g_pnetif); +#else + autoip_start(g_pnetif); +#endif + + packet_timer(NULL); + + +#ifdef DHCP + debugPrint("Waiting for IP (DHCP)...\n"); + while (dhcp_supplied_address(g_pnetif) == 0) + NtYieldExecution(); +#else + debugPrint("Waiting for IP (AUTOIP)...\n"); + while (autoip_supplied_address(g_pnetif) == 0) + NtYieldExecution(); +#endif + debugPrint("IP bound!\n"); + + debugPrint("\n"); + debugPrint("IP address.. %s\n", ip4addr_ntoa(netif_ip4_addr(g_pnetif))); + debugPrint("Mask........ %s\n", ip4addr_ntoa(netif_ip4_netmask(g_pnetif))); + debugPrint("Gateway..... %s\n", ip4addr_ntoa(netif_ip4_gw(g_pnetif))); + debugPrint("\n"); + + + + return 0; +} + + +static int last_winsock_error = 0; + +int WSAGetLastError() { + return last_winsock_error; +} + +void WSASetLastError( + int iError +) { + last_winsock_error = iError; +} + +int WSAAPI WSASendTo( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesSent, + DWORD dwFlags, + const sockaddr *lpTo, + int iTolen, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +) { + assert(lpOverlapped == NULL); + assert(lpCompletionRoutine == NULL); + + int flags = dwFlags; //FIXME: Should we filter certain flags? + + struct iovec *iov = __builtin_alloca(sizeof(struct iovec) * dwBufferCount); + for(int i = 0; i < dwBufferCount; i++) { + iov[i].iov_base = lpBuffers[i].buf; + iov[i].iov_len = lpBuffers[i].len; + } + + struct msghdr msg; + + msg.msg_name = (const sockaddr *)lpTo; + msg.msg_namelen = iTolen; + msg.msg_iov = iov; + msg.msg_iovlen = dwBufferCount; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + ssize_t ret = sendmsg(s, &msg, flags); + if (ret == -1) { + WSASetLastError(map_error_to_winsock(errno)); + return SOCKET_ERROR; + } + + *lpNumberOfBytesSent = ret; + + return 0; +} + +int WSAAPI WSARecvFrom( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesRecvd, + LPDWORD lpFlags, + sockaddr *lpFrom, + LPINT lpFromlen, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +) { + assert(lpOverlapped == NULL); + assert(lpCompletionRoutine == NULL); + assert(dwBufferCount == 1); + + int flags = *lpFlags; //FIXME: Should we filter certain flags? + + struct iovec *iov = __builtin_alloca(sizeof(struct iovec) * dwBufferCount); + for(int i = 0; i < dwBufferCount; i++) { + iov[i].iov_base = lpBuffers[i].buf; + iov[i].iov_len = lpBuffers[i].len; + } + + struct msghdr msg; + + msg.msg_name = (const sockaddr *)lpFrom; + msg.msg_namelen = *lpFromlen; + msg.msg_iov = iov; + msg.msg_iovlen = dwBufferCount; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + ssize_t ret = recvmsg(s, &msg, flags); + if (ret == -1) { + WSASetLastError(map_error_to_winsock(errno)); + return SOCKET_ERROR; + } + + *lpFromlen = msg.msg_namelen; //FIXME: Is this updated? It almost certainly isn't winsock behaviour + *lpFlags = msg.msg_flags; + *lpNumberOfBytesRecvd = ret; + + return 0; +} diff --git a/lib/winapi/ws2_32/winsock2.h b/lib/winapi/ws2_32/winsock2.h new file mode 100644 index 000000000..04dbe03e0 --- /dev/null +++ b/lib/winapi/ws2_32/winsock2.h @@ -0,0 +1,79 @@ + +typedef unsigned long u_long; + +// We do not support this +#define gethostbyaddr(...) NULL +#define WSACleanup(...) Pktdrv_Quit() + +#define SOMAXCONN 128 + +#define MSG_PARTIAL 0 + +#include +#include + +#include + +#define WSAAPI + +#define MAKEDWORD(...) 1 +#define HIBYTE(...) 1 +#define LOBYTE(...) 1 +#define MAKEWORD(...) 1 + +typedef int SOCKET; +#define INVALID_SOCKET ((SOCKET)-1) +#define SOCKET_ERROR -1 + +typedef struct WSAData { + WORD wVersion; + WORD wHighVersion; + //FIXME: There's potentially more here +} WSADATA; + +typedef struct sockaddr sockaddr; + +typedef WSADATA *LPWSADATA; + +typedef void *LPWSAOVERLAPPED_COMPLETION_ROUTINE; //FIXME: !!! +typedef void *LPWSAOVERLAPPED; //FIXME: !!! + +int WSAStartup( + WORD wVersionRequired, + LPWSADATA lpWSAData +); + +typedef struct _WSABUF { + ULONG len; + CHAR *buf; +} WSABUF, *LPWSABUF; + +int WSAGetLastError(); + +void WSASetLastError( + int iError +); + +int WSAAPI WSASendTo( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesSent, + DWORD dwFlags, + const sockaddr *lpTo, + int iTolen, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +); + +int WSAAPI WSARecvFrom( + SOCKET s, + LPWSABUF lpBuffers, + DWORD dwBufferCount, + LPDWORD lpNumberOfBytesRecvd, + LPDWORD lpFlags, + sockaddr *lpFrom, + LPINT lpFromlen, + LPWSAOVERLAPPED lpOverlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine +);