diff options
author | Arisotura <thetotalworm@gmail.com> | 2020-07-27 16:01:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-07-27 16:01:55 +0200 |
commit | dff14ca80ada883870131c7ff17d85866254ccc0 (patch) | |
tree | c15926879ed78d68d313c75e4cb7d764cb4c1fea /src/frontend/qt_sdl | |
parent | 17ce4d2a73770ecd8c5f0ff036636b5453cb86c9 (diff) | |
parent | 6a682a8ef0d1cc3aa35eaa70c4f7a7d106b25b06 (diff) |
Merge pull request #682 from nadiaholmquist/slirp-merge
Merge slirp branch into master
Diffstat (limited to 'src/frontend/qt_sdl')
-rw-r--r-- | src/frontend/qt_sdl/CMakeLists.txt | 11 | ||||
-rw-r--r-- | src/frontend/qt_sdl/LAN_Socket.cpp | 1058 | ||||
-rw-r--r-- | src/frontend/qt_sdl/main.cpp | 6 |
3 files changed, 243 insertions, 832 deletions
diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index ea7849f..05c42d1 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -46,7 +46,9 @@ set(CMAKE_AUTORCC ON) find_package(Threads REQUIRED) find_package(PkgConfig REQUIRED) +find_package(Iconv REQUIRED) pkg_check_modules(SDL2 REQUIRED sdl2) +pkg_check_modules(SLIRP REQUIRED slirp) if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL Release)) add_executable(melonDS WIN32 ${SOURCES_QT_SDL}) @@ -57,15 +59,20 @@ endif() target_link_libraries(melonDS ${CMAKE_THREAD_LIBS_INIT}) target_include_directories(melonDS PRIVATE ${SDL2_INCLUDE_DIRS}) +target_include_directories(melonDS PRIVATE ${SLIRP_INCLUDE_DIRS}) target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}") target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..") target_link_libraries(melonDS core) if (BUILD_STATIC) - target_link_libraries(melonDS -static ${SDL2_LIBRARIES}) + target_link_libraries(melonDS -static ${SDL2_STATIC_LIBRARIES} ${SLIRP_STATIC_LIBRARIES}) else() - target_link_libraries(melonDS ${SDL2_LIBRARIES}) + target_link_libraries(melonDS ${SDL2_LIBRARIES} ${SLIRP_LIBRARIES}) +endif() + +if (NOT Iconv_IS_BUILT_IN) + target_link_libraries(melonDS iconv) endif() if (UNIX) diff --git a/src/frontend/qt_sdl/LAN_Socket.cpp b/src/frontend/qt_sdl/LAN_Socket.cpp index c6fbd4b..458c931 100644 --- a/src/frontend/qt_sdl/LAN_Socket.cpp +++ b/src/frontend/qt_sdl/LAN_Socket.cpp @@ -21,30 +21,20 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "../Wifi.h" +#include "Wifi.h" #include "LAN_Socket.h" -#include "../Config.h" +#include "Config.h" +#include "FIFO.h" + +#include <slirp/libslirp.h> #ifdef __WIN32__ - #include <winsock2.h> #include <ws2tcpip.h> - #define socket_t SOCKET - #define sockaddr_t SOCKADDR #else - #include <unistd.h> - #include <arpa/inet.h> - #include <netinet/in.h> - #include <sys/types.h> - #include <sys/select.h> #include <sys/socket.h> #include <netdb.h> - #define socket_t int - #define sockaddr_t struct sockaddr - #define closesocket close -#endif - -#ifndef INVALID_SOCKET -#define INVALID_SOCKET (socket_t)-1 + #include <poll.h> + #include <time.h> #endif @@ -57,85 +47,192 @@ const u32 kDNSIP = kSubnet | 0x02; const u32 kClientIP = kSubnet | 0x10; const u8 kServerMAC[6] = {0x00, 0xAB, 0x33, 0x28, 0x99, 0x44}; -const u8 kDNSMAC[6] = {0x00, 0xAB, 0x33, 0x28, 0x99, 0x55}; -u8 PacketBuffer[2048]; -int PacketLen; -volatile int RXNum; +FIFO<u32>* RXBuffer = nullptr; + +u32 IPv4ID; + +Slirp* Ctx = nullptr; + +/*const int FDListMax = 64; +struct pollfd FDList[FDListMax]; +int FDListSize;*/ + + +#ifdef __WIN32__ + +#define poll WSAPoll + +// https://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows + +struct timespec { long tv_sec; long tv_nsec; }; +#define CLOCK_MONOTONIC 1312 + +int clock_gettime(int, struct timespec *spec) +{ + __int64 wintime; + GetSystemTimeAsFileTime((FILETIME*)&wintime); + wintime -=116444736000000000LL; //1jan1601 to 1jan1970 + spec->tv_sec = wintime / 10000000LL; //seconds + spec->tv_nsec = wintime % 10000000LL * 100; //nano-seconds + return 0; +} + +#endif // __WIN32__ + + +void RXEnqueue(const void* buf, int len) +{ + int alignedlen = (len + 3) & ~3; + int totallen = alignedlen + 4; + + if (!RXBuffer->CanFit(totallen >> 2)) + { + printf("slirp: !! NOT ENOUGH SPACE IN RX BUFFER\n"); + return; + } + + u32 header = (alignedlen & 0xFFFF) | (len << 16); + RXBuffer->Write(header); + for (int i = 0; i < alignedlen; i += 4) + RXBuffer->Write(((u32*)buf)[i>>2]); +} -u16 IPv4ID; +ssize_t SlirpCbSendPacket(const void* buf, size_t len, void* opaque) +{ + if (len > 2048) + { + printf("slirp: packet too big (%d)\n", len); + return 0; + } + printf("slirp: response packet of %d bytes, type %04X\n", len, ntohs(((u16*)buf)[6])); -// TODO: UDP sockets -// * use FIFO list -// * assign new socket when seeing new IP/port + RXEnqueue(buf, len); + return len; +} -typedef struct +void SlirpCbGuestError(const char* msg, void* opaque) { - u8 DestIP[4]; - u16 SourcePort; - u16 DestPort; + printf("SLIRP: error: %s\n", msg); +} - u32 SeqNum; // sequence number for incoming frames - u32 AckNum; +int64_t SlirpCbClockGetNS(void* opaque) +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; +} - // 0: unused - // 1: connected - u8 Status; +void* SlirpCbTimerNew(SlirpTimerCb cb, void* cb_opaque, void* opaque) +{ + return nullptr; +} - socket_t Backend; +void SlirpCbTimerFree(void* timer, void* opaque) +{ +} -} TCPSocket; +void SlirpCbTimerMod(void* timer, int64_t expire_time, void* opaque) +{ +} -typedef struct +void SlirpCbRegisterPollFD(int fd, void* opaque) { - u8 DestIP[4]; - u16 SourcePort; - u16 DestPort; + printf("Slirp: register poll FD %d\n", fd); + + /*if (FDListSize >= FDListMax) + { + printf("!! SLIRP FD LIST FULL\n"); + return; + } + + for (int i = 0; i < FDListSize; i++) + { + if (FDList[i].fd == fd) return; + } - socket_t Backend; - struct sockaddr_in BackendAddr; + FDList[FDListSize].fd = fd; + FDListSize++;*/ +} -} UDPSocket; +void SlirpCbUnregisterPollFD(int fd, void* opaque) +{ + printf("Slirp: unregister poll FD %d\n", fd); -TCPSocket TCPSocketList[16]; -UDPSocket UDPSocketList[4]; + /*if (FDListSize < 1) + { + printf("!! SLIRP FD LIST EMPTY\n"); + return; + } -int UDPSocketID = 0; + for (int i = 0; i < FDListSize; i++) + { + if (FDList[i].fd == fd) + { + FDListSize--; + FDList[i] = FDList[FDListSize]; + } + }*/ +} +void SlirpCbNotify(void* opaque) +{ + printf("Slirp: notify???\n"); +} + +SlirpCb cb = +{ + .send_packet = SlirpCbSendPacket, + .guest_error = SlirpCbGuestError, + .clock_get_ns = SlirpCbClockGetNS, + .timer_new = SlirpCbTimerNew, + .timer_free = SlirpCbTimerFree, + .timer_mod = SlirpCbTimerMod, + .register_poll_fd = SlirpCbRegisterPollFD, + .unregister_poll_fd = SlirpCbUnregisterPollFD, + .notify = SlirpCbNotify +}; bool Init() { - // TODO: how to deal with cases where an adapter is unplugged or changes config?? - //if (PCapLib) return true; + IPv4ID = 0; + + //FDListSize = 0; + //memset(FDList, 0, sizeof(FDList)); - //Lib = NULL; - PacketLen = 0; - RXNum = 0; + RXBuffer = new FIFO<u32>(0x8000 >> 2); - IPv4ID = 1; + SlirpConfig cfg; + memset(&cfg, 0, sizeof(cfg)); + cfg.version = 1; - memset(TCPSocketList, 0, sizeof(TCPSocketList)); - memset(UDPSocketList, 0, sizeof(UDPSocketList)); + cfg.in_enabled = true; + *(u32*)&cfg.vnetwork = htonl(kSubnet); + *(u32*)&cfg.vnetmask = htonl(0xFFFFFF00); + *(u32*)&cfg.vhost = htonl(kServerIP); + cfg.vhostname = "melonServer"; + *(u32*)&cfg.vdhcp_start = htonl(kClientIP); + *(u32*)&cfg.vnameserver = htonl(kDNSIP); - UDPSocketID = 0; + Ctx = slirp_new(&cfg, &cb, nullptr); return true; } void DeInit() { - for (int i = 0; i < (sizeof(TCPSocketList)/sizeof(TCPSocket)); i++) + if (Ctx) { - TCPSocket* sock = &TCPSocketList[i]; - if (sock->Backend) closesocket(sock->Backend); + slirp_cleanup(Ctx); + Ctx = nullptr; } - for (int i = 0; i < (sizeof(UDPSocketList)/sizeof(UDPSocket)); i++) + if (RXBuffer) { - UDPSocket* sock = &UDPSocketList[i]; - if (sock->Backend) closesocket(sock->Backend); + delete RXBuffer; + RXBuffer = nullptr; } } @@ -179,165 +276,6 @@ void FinishUDPFrame(u8* data, int len) *(u16*)&udpheader[6] = htons(tmp); } -void FinishTCPFrame(u8* data, int len) -{ - u8* ipheader = &data[0xE]; - u8* tcpheader = &data[0x22]; - - // lengths - *(u16*)&ipheader[2] = htons(len - 0xE); - - // IP checksum - u32 tmp = 0; - - for (int i = 0; i < 20; i += 2) - tmp += ntohs(*(u16*)&ipheader[i]); - while (tmp >> 16) - tmp = (tmp & 0xFFFF) + (tmp >> 16); - tmp ^= 0xFFFF; - *(u16*)&ipheader[10] = htons(tmp); - - u32 tcplen = ntohs(*(u16*)&ipheader[2]) - 0x14; - - // TCP checksum - tmp = 0; - tmp += ntohs(*(u16*)&ipheader[12]); - tmp += ntohs(*(u16*)&ipheader[14]); - tmp += ntohs(*(u16*)&ipheader[16]); - tmp += ntohs(*(u16*)&ipheader[18]); - tmp += ntohs(0x0600); - tmp += tcplen; - for (u8* i = tcpheader; i < &tcpheader[tcplen-1]; i += 2) - tmp += ntohs(*(u16*)i); - if (tcplen & 1) - tmp += ntohs((u_short)tcpheader[tcplen-1]); - while (tmp >> 16) - tmp = (tmp & 0xFFFF) + (tmp >> 16); - tmp ^= 0xFFFF; - *(u16*)&tcpheader[16] = htons(tmp); -} - - -void HandleDHCPFrame(u8* data, int len) -{ - u8 type = 0xFF; - - u32 transid = *(u32*)&data[0x2E]; - - u8* options = &data[0x11A]; - for (;;) - { - if (options >= &data[len]) break; - u8 opt = *options++; - if (opt == 255) break; - - u8 len = *options++; - switch (opt) - { - case 53: // frame type - type = options[0]; - break; - } - - options += len; - } - - if (type == 0xFF) - { - printf("DHCP: bad frame\n"); - return; - } - - printf("DHCP: frame type %d, transid %08X\n", type, transid); - - if (type == 1 || // discover - type == 3) // request - { - u8 resp[512]; - u8* out = &resp[0]; - - // ethernet - memcpy(out, &data[6], 6); out += 6; - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0800); out += 2; - - // IP - u8* ipheader = out; - *out++ = 0x45; - *out++ = 0x00; - *(u16*)out = 0; out += 2; // total length - *(u16*)out = htons(IPv4ID); out += 2; IPv4ID++; - *out++ = 0x00; - *out++ = 0x00; - *out++ = 0x80; // TTL - *out++ = 0x11; // protocol (UDP) - *(u16*)out = 0; out += 2; // checksum - *(u32*)out = htonl(kServerIP); out += 4; // source IP - if (type == 1) - { - *(u32*)out = htonl(0xFFFFFFFF); out += 4; // destination IP - } - else if (type == 3) - { - *(u32*)out = htonl(kClientIP); out += 4; // destination IP - } - - // UDP - u8* udpheader = out; - *(u16*)out = htons(67); out += 2; // source port - *(u16*)out = htons(68); out += 2; // destination port - *(u16*)out = 0; out += 2; // length - *(u16*)out = 0; out += 2; // checksum - - // DHCP - u8* body = out; - *out++ = 0x02; - *out++ = 0x01; - *out++ = 0x06; - *out++ = 0x00; - *(u32*)out = transid; out += 4; - *(u16*)out = 0; out += 2; // seconds elapsed - *(u16*)out = 0; out += 2; - *(u32*)out = htonl(0x00000000); out += 4; // client IP - *(u32*)out = htonl(kClientIP); out += 4; // your IP - *(u32*)out = htonl(kServerIP); out += 4; // server IP - *(u32*)out = htonl(0x00000000); out += 4; // gateway IP - memcpy(out, &data[6], 6); out += 6; - memset(out, 0, 10); out += 10; - memset(out, 0, 192); out += 192; - *(u32*)out = 0x63538263; out += 4; // DHCP magic - - // DHCP options - *out++ = 53; *out++ = 1; - *out++ = (type==1) ? 2 : 5; // DHCP type: offer/ack - *out++ = 1; *out++ = 4; - *(u32*)out = htonl(0xFFFFFF00); out += 4; // subnet mask - *out++ = 3; *out++ = 4; - *(u32*)out = htonl(kServerIP); out += 4; // router - *out++ = 51; *out++ = 4; - *(u32*)out = htonl(442030); out += 4; // lease time - *out++ = 54; *out++ = 4; - *(u32*)out = htonl(kServerIP); out += 4; // DHCP server - *out++ = 6; *out++ = 4; - *(u32*)out = htonl(kDNSIP); out += 4; // DNS (hax) - - *out++ = 0xFF; - memset(out, 0, 20); out += 20; - - u32 framelen = (u32)(out - &resp[0]); - if (framelen & 1) { *out++ = 0; framelen++; } - FinishUDPFrame(resp, framelen); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; - } -} - void HandleDNSFrame(u8* data, int len) { u8* ipheader = &data[0xE]; @@ -458,12 +396,13 @@ void HandleDNSFrame(u8* data, int len) while (p) { struct sockaddr_in* addr = (struct sockaddr_in*)p->ai_addr; - /*printf(" -> %d.%d.%d.%d", - addr->sin_addr.S_un.S_un_b.s_b1, addr->sin_addr.S_un.S_un_b.s_b2, - addr->sin_addr.S_un.S_un_b.s_b3, addr->sin_addr.S_un.S_un_b.s_b4);*/ - - //addr_res = addr->sin_addr.S_un.S_addr; addr_res = *(u32*)&addr->sin_addr; + + printf(" -> %d.%d.%d.%d", + addr_res & 0xFF, (addr_res >> 8) & 0xFF, + (addr_res >> 16) & 0xFF, addr_res >> 24); + + break; p = p->ai_next; } } @@ -490,653 +429,116 @@ void HandleDNSFrame(u8* data, int len) if (framelen & 1) { *out++ = 0; framelen++; } FinishUDPFrame(resp, framelen); - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; + RXEnqueue(resp, framelen); } -void UDP_BuildIncomingFrame(UDPSocket* sock, u8* data, int len) -{ - u8 resp[2048]; - u8* out = &resp[0]; - - if (len > 1536) return; - - // ethernet - memcpy(out, Wifi::GetMAC(), 6); out += 6; // hurf - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0800); out += 2; - - // IP - u8* resp_ipheader = out; - *out++ = 0x45; - *out++ = 0x00; - *(u16*)out = 0; out += 2; // total length - *(u16*)out = htons(IPv4ID); out += 2; IPv4ID++; - *out++ = 0x00; - *out++ = 0x00; - *out++ = 0x80; // TTL - *out++ = 0x11; // protocol (UDP) - *(u16*)out = 0; out += 2; // checksum - memcpy(out, sock->DestIP, 4); out += 4; // source IP - *(u32*)out = htonl(kClientIP); out += 4; // destination IP - - // UDP - u8* resp_tcpheader = out; - *(u16*)out = htons(sock->DestPort); out += 2; // source port - *(u16*)out = htons(sock->SourcePort); out += 2; // destination port - *(u16*)out = htons(len+8); out += 2; // length of header+data - *(u16*)out = 0; out += 2; // checksum - - memcpy(out, data, len); out += len; - - u32 framelen = (u32)(out - &resp[0]); - FinishUDPFrame(resp, framelen); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; -} - -void HandleUDPFrame(u8* data, int len) +int SendPacket(u8* data, int len) { - u8* ipheader = &data[0xE]; - u8* udpheader = &data[0x22]; - - // debug - /*for (int j = 0; j < len; j += 16) - { - int rem = len - j; - if (rem > 16) rem = 16; - for (int i = 0; i < rem; i++) - { - printf("%02X ", data[i+j]); - } - printf("\n"); - }*/ - - u16 srcport = ntohs(*(u16*)&udpheader[0]); - u16 dstport = ntohs(*(u16*)&udpheader[2]); + if (!Ctx) return 0; - int sockid = -1; - UDPSocket* sock; - for (int i = 0; i < (sizeof(UDPSocketList)/sizeof(UDPSocket)); i++) + if (len > 2048) { - sock = &UDPSocketList[i]; - if (sock->Backend != 0 && !memcmp(&sock->DestIP, &ipheader[16], 4) && - sock->SourcePort == srcport && sock->DestPort == dstport) - { - sockid = i; - break; - } + printf("LAN_SendPacket: error: packet too long (%d)\n", len); + return 0; } - if (sockid == -1) - { - sockid = UDPSocketID; - sock = &UDPSocketList[sockid]; - - UDPSocketID++; - if (UDPSocketID >= (sizeof(UDPSocketList)/sizeof(UDPSocket))) - UDPSocketID = 0; + u16 ethertype = ntohs(*(u16*)&data[0xC]); - if (sock->Backend != 0) + if (ethertype == 0x800) + { + u8 protocol = data[0x17]; + if (protocol == 0x11) // UDP { - printf("LANMAGIC: closing previous UDP socket #%d\n", sockid); - closesocket(sock->Backend); + u16 dstport = ntohs(*(u16*)&data[0x24]); + if (dstport == 53 && htonl(*(u32*)&data[0x1E]) == kDNSIP) // DNS + { + HandleDNSFrame(data, len); + return len; + } } - - sock->Backend = socket(AF_INET, SOCK_DGRAM, 0); - - memcpy(sock->DestIP, &ipheader[16], 4); - sock->SourcePort = srcport; - sock->DestPort = dstport; - - memset(&sock->BackendAddr, 0, sizeof(sock->BackendAddr)); - sock->BackendAddr.sin_family = AF_INET; - sock->BackendAddr.sin_port = htons(dstport); - memcpy(&sock->BackendAddr.sin_addr, &ipheader[16], 4); - /*if (bind(sock->Backend, (struct sockaddr*)&sock->BackendAddr, sizeof(sock->BackendAddr)) == -1) - { - printf("bind() shat itself :(\n"); - }*/ - - printf("LANMAGIC: opening UDP socket #%d to %d.%d.%d.%d:%d, srcport %d\n", - sockid, - ipheader[16], ipheader[17], ipheader[18], ipheader[19], - dstport, srcport); } - u16 udplen = ntohs(*(u16*)&udpheader[4]) - 8; - - printf("UDP: socket %d sending %d bytes\n", sockid, udplen); - sendto(sock->Backend, (char*)&udpheader[8], udplen, 0, - (struct sockaddr*)&sock->BackendAddr, sizeof(sock->BackendAddr)); -} - -void TCP_SYNACK(TCPSocket* sock, u8* data, int len) -{ - u8 resp[128]; - u8* out = &resp[0]; - - u8* ipheader = &data[0xE]; - u8* tcpheader = &data[0x22]; - - u32 seqnum = htonl(*(u32*)&tcpheader[4]); - seqnum++; - sock->AckNum = seqnum; - - //printf("SYNACK SEQ=%08X|%08X\n", sock->SeqNum, sock->AckNum); - - // ethernet - memcpy(out, &data[6], 6); out += 6; - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0800); out += 2; - - // IP - u8* resp_ipheader = out; - *out++ = 0x45; - *out++ = 0x00; - *(u16*)out = 0; out += 2; // total length - *(u16*)out = htons(IPv4ID); out += 2; IPv4ID++; - *out++ = 0x00; - *out++ = 0x00; - *out++ = 0x80; // TTL - *out++ = 0x06; // protocol (TCP) - *(u16*)out = 0; out += 2; // checksum - *(u32*)out = *(u32*)&ipheader[16]; out += 4; // source IP - *(u32*)out = *(u32*)&ipheader[12]; out += 4; // destination IP - - // TCP - u8* resp_tcpheader = out; - *(u16*)out = *(u16*)&tcpheader[2]; out += 2; // source port - *(u16*)out = *(u16*)&tcpheader[0]; out += 2; // destination port - *(u32*)out = htonl(sock->SeqNum); out += 4; sock->SeqNum++; // seq number - *(u32*)out = htonl(seqnum); out += 4; // ack seq number - *(u16*)out = htons(0x8012); out += 2; // flags (SYN+ACK) - *(u16*)out = htons(0x7000); out += 2; // window size (uuuh) - *(u16*)out = 0; out += 2; // checksum - *(u16*)out = 0; out += 2; // urgent pointer - - // TCP options - *out++ = 0x02; *out++ = 0x04; // max segment size - *(u16*)out = htons(0x05B4); out += 2; - *out++ = 0x01; - *out++ = 0x01; - *out++ = 0x04; *out++ = 0x02; // SACK permitted - *out++ = 0x01; - *out++ = 0x03; *out++ = 0x03; // window size - *out++ = 0x08; - - u32 framelen = (u32)(out - &resp[0]); - //if (framelen & 1) { *out++ = 0; framelen++; } - FinishTCPFrame(resp, framelen); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; -} - -void TCP_ACK(TCPSocket* sock, bool fin) -{ - u8 resp[64]; - u8* out = &resp[0]; - - u16 flags = 0x5010; - if (fin) flags |= 0x0001; - - //printf("%sACK SEQ=%08X|%08X\n", fin?"FIN":" ", sock->SeqNum, sock->AckNum); - - // ethernet - memcpy(out, Wifi::GetMAC(), 6); out += 6; - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0800); out += 2; - - // IP - u8* resp_ipheader = out; - *out++ = 0x45; - *out++ = 0x00; - *(u16*)out = 0; out += 2; // total length - *(u16*)out = htons(IPv4ID); out += 2; IPv4ID++; - *out++ = 0x00; - *out++ = 0x00; - *out++ = 0x80; // TTL - *out++ = 0x06; // protocol (TCP) - *(u16*)out = 0; out += 2; // checksum - *(u32*)out = *(u32*)&sock->DestIP; out += 4; // source IP - *(u32*)out = htonl(kClientIP); out += 4; // destination IP - - // TCP - u8* resp_tcpheader = out; - *(u16*)out = htonl(sock->DestPort); out += 2; // source port - *(u16*)out = htonl(sock->SourcePort); out += 2; // destination port - *(u32*)out = htonl(sock->SeqNum); out += 4; // seq number - *(u32*)out = htonl(sock->AckNum); out += 4; // ack seq number - *(u16*)out = htons(flags); out += 2; // flags - *(u16*)out = htons(0x7000); out += 2; // window size (uuuh) - *(u16*)out = 0; out += 2; // checksum - *(u16*)out = 0; out += 2; // urgent pointer - - u32 framelen = (u32)(out - &resp[0]); - //if (framelen & 1) { *out++ = 0; framelen++; } - FinishTCPFrame(resp, framelen); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; + slirp_input(Ctx, data, len); + return len; } -void TCP_BuildIncomingFrame(TCPSocket* sock, u8* data, int len) -{ - u8 resp[2048]; - u8* out = &resp[0]; - - if (len > 1536) return; -//printf("INCOMING SEQ=%08X|%08X\n", sock->SeqNum, sock->AckNum); - // ethernet - memcpy(out, Wifi::GetMAC(), 6); out += 6; // hurf - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0800); out += 2; - - // IP - u8* resp_ipheader = out; - *out++ = 0x45; - *out++ = 0x00; - *(u16*)out = 0; out += 2; // total length - *(u16*)out = htons(IPv4ID); out += 2; IPv4ID++; - *out++ = 0x00; - *out++ = 0x00; - *out++ = 0x80; // TTL - *out++ = 0x06; // protocol (TCP) - *(u16*)out = 0; out += 2; // checksum - memcpy(out, sock->DestIP, 4); out += 4; // source IP - *(u32*)out = htonl(kClientIP); out += 4; // destination IP - - // TCP - u8* resp_tcpheader = out; - *(u16*)out = htons(sock->DestPort); out += 2; // source port - *(u16*)out = htons(sock->SourcePort); out += 2; // destination port - *(u32*)out = htonl(sock->SeqNum); out += 4; // seq number - *(u32*)out = htonl(sock->AckNum); out += 4; // ack seq number - *(u16*)out = htons(0x5018); out += 2; // flags (ACK, PSH) - *(u16*)out = htons(0x7000); out += 2; // window size (uuuh) - *(u16*)out = 0; out += 2; // checksum - *(u16*)out = 0; out += 2; // urgent pointer - - memcpy(out, data, len); out += len; - - u32 framelen = (u32)(out - &resp[0]); - FinishTCPFrame(resp, framelen); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; - - sock->SeqNum += len; -} +const int PollListMax = 64; +struct pollfd PollList[PollListMax]; +int PollListSize; -void HandleTCPFrame(u8* data, int len) +int SlirpCbAddPoll(int fd, int events, void* opaque) { - u8* ipheader = &data[0xE]; - u8* tcpheader = &data[0x22]; - - u16 srcport = ntohs(*(u16*)&tcpheader[0]); - u16 dstport = ntohs(*(u16*)&tcpheader[2]); - u16 flags = ntohs(*(u16*)&tcpheader[12]); - - u32 tcpheaderlen = 4 * (flags >> 12); - u32 tcplen = ntohs(*(u16*)&ipheader[2]) - 0x14; - u32 tcpdatalen = tcplen - tcpheaderlen; - - /*printf("tcpflags=%04X header=%d data=%d seq=%08X|%08X\n", - flags, tcpheaderlen, tcpdatalen, - ntohl(*(u32*)&tcpheader[4]), - ntohl(*(u32*)&tcpheader[8]));*/ - - if (flags & 0x002) // SYN + if (PollListSize >= PollListMax) { - int sockid = -1; - TCPSocket* sock; - for (int i = 0; i < (sizeof(TCPSocketList)/sizeof(TCPSocket)); i++) - { - sock = &TCPSocketList[i]; - if (sock->Status != 0 && !memcmp(&sock->DestIP, &ipheader[16], 4) && - sock->SourcePort == srcport && sock->DestPort == dstport) - { - printf("LANMAGIC: duplicate TCP socket\n"); - sockid = i; - break; - } - } - - if (sockid == -1) - { - for (int i = 0; i < (sizeof(TCPSocketList)/sizeof(TCPSocket)); i++) - { - sock = &TCPSocketList[i]; - if (sock->Status == 0) - { - sockid = i; - break; - } - } - } - - if (sockid == -1) - { - printf("LANMAGIC: !! TCP SOCKET LIST FULL\n"); - return; - } - - printf("LANMAGIC: opening TCP socket #%d to %d.%d.%d.%d:%d, srcport %d\n", - sockid, - ipheader[16], ipheader[17], ipheader[18], ipheader[19], - dstport, srcport); - - // keep track of it - sock->Status = 1; - memcpy(sock->DestIP, &ipheader[16], 4); - sock->DestPort = dstport; - sock->SourcePort = srcport; - sock->SeqNum = 0x13370000; - sock->AckNum = 0; - - // open backend socket - if (!sock->Backend) - { - sock->Backend = socket(AF_INET, SOCK_STREAM, 0); - } - - struct sockaddr_in conn_addr; - memset(&conn_addr, 0, sizeof(conn_addr)); - conn_addr.sin_family = AF_INET; - memcpy(&conn_addr.sin_addr, &ipheader[16], 4); - conn_addr.sin_port = htons(dstport); - if (connect(sock->Backend, (sockaddr*)&conn_addr, sizeof(conn_addr)) == -1) - { - printf("connect() shat itself :(\n"); - } - else - { - // acknowledge it - TCP_SYNACK(sock, data, len); - } + printf("slirp: POLL LIST FULL\n"); + return -1; } - else - { - int sockid = -1; - TCPSocket* sock; - for (int i = 0; i < (sizeof(TCPSocketList)/sizeof(TCPSocket)); i++) - { - sock = &TCPSocketList[i]; - if (sock->Status != 0 && !memcmp(&sock->DestIP, &ipheader[16], 4) && - sock->SourcePort == srcport && sock->DestPort == dstport) - { - sockid = i; - break; - } - } - if (sockid == -1) - { - printf("LANMAGIC: bad TCP packet\n"); - return; - } + int idx = PollListSize++; - // TODO: check those - u32 seqnum = ntohl(*(u32*)&tcpheader[4]); - u32 acknum = ntohl(*(u32*)&tcpheader[8]); - sock->SeqNum = acknum; - sock->AckNum = seqnum + tcpdatalen; + //printf("Slirp: add poll: fd=%d, idx=%d, events=%08X\n", fd, idx, events); - // send data over the socket - if (tcpdatalen > 0) - { - u8* tcpdata = &tcpheader[tcpheaderlen]; + u16 evt = 0; - printf("TCP: socket %d sending %d bytes (flags=%04X)\n", sockid, tcpdatalen, flags); - send(sock->Backend, (char*)tcpdata, tcpdatalen, 0); + if (events & SLIRP_POLL_IN) evt |= POLLIN; + if (events & SLIRP_POLL_OUT) evt |= POLLWRNORM; - // kind of a hack, there - TCP_ACK(sock, false); - } +#ifndef __WIN32__ + // CHECKME + if (events & SLIRP_POLL_PRI) evt |= POLLPRI; + if (events & SLIRP_POLL_ERR) evt |= POLLERR; + if (events & SLIRP_POLL_HUP) evt |= POLLHUP; +#endif // !__WIN32__ - if (flags & 0x001) // FIN - { - // TODO: timeout etc - printf("TCP: socket %d closing\n", sockid); + PollList[idx].fd = fd; + PollList[idx].events = evt; - sock->Status = 0; - closesocket(sock->Backend); - sock->Backend = 0; - } - } + return idx; } -void HandleARPFrame(u8* data, int len) +int SlirpCbGetREvents(int idx, void* opaque) { - u16 protocol = ntohs(*(u16*)&data[0x10]); - if (protocol != 0x0800) return; - - u16 op = ntohs(*(u16*)&data[0x14]); - u32 targetip = ntohl(*(u32*)&data[0x26]); - - // TODO: handle ARP to the client - // this only handles ARP to the DHCP/router - - if (op == 1) - { - // opcode 1=req 2=reply - // sender MAC - // sender IP - // target MAC - // target IP - - const u8* targetmac; - if (targetip == kServerIP) targetmac = kServerMAC; - else if (targetip == kDNSIP) targetmac = kDNSMAC; - else return; - - u8 resp[64]; - u8* out = &resp[0]; - - // ethernet - memcpy(out, &data[6], 6); out += 6; - memcpy(out, kServerMAC, 6); out += 6; - *(u16*)out = htons(0x0806); out += 2; - - // ARP - *(u16*)out = htons(0x0001); out += 2; // hardware type - *(u16*)out = htons(0x0800); out += 2; // protocol - *out++ = 6; // MAC address size - *out++ = 4; // IP address size - *(u16*)out = htons(0x0002); out += 2; // opcode - memcpy(out, targetmac, 6); out += 6; - *(u32*)out = htonl(targetip); out += 4; - memcpy(out, &data[0x16], 6+4); out += 6+4; - - u32 framelen = (u32)(out - &resp[0]); - - // TODO: if there is already a packet queued, this will overwrite it - // that being said, this will only happen during DHCP setup, so probably - // not a big deal - - PacketLen = framelen; - memcpy(PacketBuffer, resp, PacketLen); - RXNum = 1; - } - else - { - printf("wat??\n"); - } -} + if (idx < 0 || idx >= PollListSize) + return 0; -void HandlePacket(u8* data, int len) -{ - u16 ethertype = ntohs(*(u16*)&data[0xC]); + //printf("Slirp: get revents, idx=%d, res=%04X\n", idx, FDList[idx].revents); - if (ethertype == 0x0800) // IPv4 - { - u8 protocol = data[0x17]; - if (protocol == 0x11) // UDP - { - u16 srcport = ntohs(*(u16*)&data[0x22]); - u16 dstport = ntohs(*(u16*)&data[0x24]); - if (srcport == 68 && dstport == 67) // DHCP - { - printf("LANMAGIC: DHCP packet\n"); - return HandleDHCPFrame(data, len); - } - else if (dstport == 53 && htonl(*(u32*)&data[0x1E]) == kDNSIP) // DNS - { - printf("LANMAGIC: DNS packet\n"); - return HandleDNSFrame(data, len); - } + u16 evt = PollList[idx].revents; + int ret = 0; - printf("LANMAGIC: UDP packet %d->%d\n", srcport, dstport); - return HandleUDPFrame(data, len); - } - else if (protocol == 0x06) // TCP - { - printf("LANMAGIC: TCP packet\n"); - return HandleTCPFrame(data, len); - } - else - printf("LANMAGIC: unsupported IP protocol %02X\n", protocol); - } - else if (ethertype == 0x0806) // ARP - { - printf("LANMAGIC: ARP packet\n"); - return HandleARPFrame(data, len); - } - else - printf("LANMAGIC: unsupported ethernet type %04X\n", ethertype); -} + if (evt & POLLIN) ret |= SLIRP_POLL_IN; + if (evt & POLLWRNORM) ret |= SLIRP_POLL_OUT; + if (evt & POLLPRI) ret |= SLIRP_POLL_PRI; + if (evt & POLLERR) ret |= SLIRP_POLL_ERR; + if (evt & POLLHUP) ret |= SLIRP_POLL_HUP; -int SendPacket(u8* data, int len) -{ - if (len > 2048) - { - printf("LAN_SendPacket: error: packet too long (%d)\n", len); - return 0; - } - - HandlePacket(data, len); - return len; + return ret; } int RecvPacket(u8* data) { + if (!Ctx) return 0; + int ret = 0; - if (RXNum > 0) - { - memcpy(data, PacketBuffer, PacketLen); - ret = PacketLen; - RXNum = 0; - } - for (int i = 0; i < (sizeof(TCPSocketList)/sizeof(TCPSocket)); i++) + //if (PollListSize > 0) { - TCPSocket* sock = &TCPSocketList[i]; - if (sock->Status != 1) continue; - - fd_set fd; - struct timeval tv; - - FD_ZERO(&fd); - FD_SET(sock->Backend, &fd); - tv.tv_sec = 0; - tv.tv_usec = 0; - - if (!select(sock->Backend+1, &fd, 0, 0, &tv)) - { - continue; - } - - u8 recvbuf[1024]; - int recvlen = recv(sock->Backend, (char*)recvbuf, 1024, 0); - if (recvlen < 1) - { - if (recvlen == 0) - { - // socket has closed from the other side - printf("TCP: socket %d closed from other side\n", i); - sock->Status = 2; - TCP_ACK(sock, true); - } - continue; - } - - printf("TCP: socket %d receiving %d bytes\n", i, recvlen); - TCP_BuildIncomingFrame(sock, recvbuf, recvlen); - - // debug - /*for (int j = 0; j < recvlen; j += 16) - { - int rem = recvlen - j; - if (rem > 16) rem = 16; - for (int k = 0; k < rem; k++) - { - printf("%02X ", recvbuf[k+j]); - } - printf("\n"); - }*/ - - //recvlen = recv(sock->Backend, (char*)recvbuf, 1024, 0); - //if (recvlen == 0) printf("it closed immediately after\n"); + u32 timeout = 0; + PollListSize = 0; + slirp_pollfds_fill(Ctx, &timeout, SlirpCbAddPoll, nullptr); + int res = poll(PollList, PollListSize, timeout); + slirp_pollfds_poll(Ctx, res<0, SlirpCbGetREvents, nullptr); } - for (int i = 0; i < (sizeof(UDPSocketList)/sizeof(UDPSocket)); i++) + if (!RXBuffer->IsEmpty()) { - UDPSocket* sock = &UDPSocketList[i]; - if (sock->Backend == 0) continue; - - fd_set fd; - struct timeval tv; - - FD_ZERO(&fd); - FD_SET(sock->Backend, &fd); - tv.tv_sec = 0; - tv.tv_usec = 0; - - if (!select(sock->Backend+1, &fd, 0, 0, &tv)) - { - continue; - } - - u8 recvbuf[1024]; - sockaddr_t fromAddr; - socklen_t fromLen = sizeof(sockaddr_t); - int recvlen = recvfrom(sock->Backend, (char*)recvbuf, 1024, 0, &fromAddr, &fromLen); - if (recvlen < 1) continue; + u32 header = RXBuffer->Read(); + u32 len = header & 0xFFFF; - if (fromAddr.sa_family != AF_INET) continue; - struct sockaddr_in* fromAddrIn = (struct sockaddr_in*)&fromAddr; - if (memcmp(&fromAddrIn->sin_addr, sock->DestIP, 4)) continue; - if (ntohs(fromAddrIn->sin_port) != sock->DestPort) continue; + for (int i = 0; i < len; i += 4) + ((u32*)data)[i>>2] = RXBuffer->Read(); - printf("UDP: socket %d receiving %d bytes\n", i, recvlen); - UDP_BuildIncomingFrame(sock, recvbuf, recvlen); + ret = header >> 16; } return ret; diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index de6887c..47b3490 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1285,6 +1285,8 @@ void MainWindow::keyPressEvent(QKeyEvent* event) { if (event->isAutoRepeat()) return; + if (event->key() == Qt::Key_F11) NDS::debug(0); + Input::KeyPress(event); } @@ -2083,12 +2085,12 @@ int CALLBACK WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cmdline, int cmdsho if (argv_w) LocalFree(argv_w); - if (AttachConsole(ATTACH_PARENT_PROCESS)) + /*if (AttachConsole(ATTACH_PARENT_PROCESS)) { freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); printf("\n"); - } + }*/ int ret = main(argc, argv); |