diff --git a/core/deps/picotcp/include/arch/pico_posix.h b/core/deps/picotcp/include/arch/pico_posix.h index 427fed8f0..5ddd1fa6d 100644 --- a/core/deps/picotcp/include/arch/pico_posix.h +++ b/core/deps/picotcp/include/arch/pico_posix.h @@ -16,7 +16,11 @@ #define TIME_PRESCALE #define PICO_SUPPORT_THREADING */ +#ifdef RELEASE +#define dbg(...) +#else #define dbg printf +#endif #define stack_fill_pattern(...) do {} while(0) #define stack_count_free_words(...) do {} while(0) diff --git a/core/deps/picotcp/modules/pico_dev_ppp.c b/core/deps/picotcp/modules/pico_dev_ppp.c index 443354936..e1ba6384a 100644 --- a/core/deps/picotcp/modules/pico_dev_ppp.c +++ b/core/deps/picotcp/modules/pico_dev_ppp.c @@ -311,10 +311,12 @@ static void pppdump(uint8_t *buf, int len, int egress) if (dumpfp == NULL) { dumpfp = fopen("ppp.dump", "a"); - uint32_t reset_time = long_be(PICO_TIME()); - fputc(7, dumpfp); // Reset time - fwrite(&reset_time, sizeof(reset_time), 1, dumpfp); - last_time_ms = PICO_TIME_MS(); + if (dumpfp == NULL) + return; + uint32_t reset_time = long_be(PICO_TIME()); + fputc(7, dumpfp); // Reset time + fwrite(&reset_time, sizeof(reset_time), 1, dumpfp); + last_time_ms = PICO_TIME_MS(); } uint32_t delta = (PICO_TIME_MS() - last_time_ms) / 100; diff --git a/core/deps/picotcp/modules/pico_tcp.c b/core/deps/picotcp/modules/pico_tcp.c index 6dc9ac566..8792e49aa 100644 --- a/core/deps/picotcp/modules/pico_tcp.c +++ b/core/deps/picotcp/modules/pico_tcp.c @@ -1241,6 +1241,8 @@ int pico_tcp_initconn(struct pico_socket *s) hdr->trans.sport = ts->sock.local_port; hdr->trans.dport = ts->sock.remote_port; + syn->local_ip.addr = s->local_addr.ip4.addr; // Masqueraded + hdr->crc = 0; hdr->crc = short_be(pico_tcp_checksum(syn)); diff --git a/core/deps/picotcp/stack/pico_socket.c b/core/deps/picotcp/stack/pico_socket.c index 4827ad862..1e2bfdd23 100644 --- a/core/deps/picotcp/stack/pico_socket.c +++ b/core/deps/picotcp/stack/pico_socket.c @@ -1662,13 +1662,16 @@ int pico_socket_connect(struct pico_socket *s, const void *remote_addr, uint16_t struct pico_ip4 *local = NULL; const struct pico_ip4 *ip = (const struct pico_ip4 *)remote_addr; s->remote_addr.ip4 = *ip; - local = pico_ipv4_source_find(ip); - if (local) { - get_sock_dev(s); - s->local_addr.ip4 = *local; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; + if (s->local_addr.ip4.addr == 0) // Not for masquerading socket + { + local = pico_ipv4_source_find(ip); + if (local) { + get_sock_dev(s); + s->local_addr.ip4 = *local; + } else { + pico_err = PICO_ERR_EHOSTUNREACH; + return -1; + } } #endif diff --git a/core/hw/holly/sb.cpp b/core/hw/holly/sb.cpp index eb38b1018..9faf0fa5d 100644 --- a/core/hw/holly/sb.cpp +++ b/core/hw/holly/sb.cpp @@ -10,6 +10,7 @@ #include "hw/gdrom/gdrom_if.h" #include "hw/maple/maple_if.h" #include "hw/aica/aica_if.h" +#include "hw/modem/modem.h" #include "hw/naomi/naomi.h" @@ -54,6 +55,11 @@ u32 sb_ReadMem(u32 addr,u32 sz) else { //printf("SB: %08X\n",addr); + if (sb_regs[offset].readFunctionAddr == NULL) + { + EMUERROR("sb_ReadMem write-only reg %08x %d\n", addr, sz); + return 0; + } return sb_regs[offset].readFunctionAddr(addr); } #ifdef TRACE @@ -771,6 +777,10 @@ void sb_Init() pvr_sb_Init(); maple_Init(); aica_sb_Init(); + +#if DC_PLATFORM != DC_PLATFORM_NAOMI + ModemInit(); +#endif } void sb_Reset(bool Manual) @@ -797,4 +807,4 @@ void sb_Term() naomi_reg_Term(); #endif asic_reg_Term(); -} \ No newline at end of file +} diff --git a/core/hw/modem/modem.cpp b/core/hw/modem/modem.cpp index 690a76d42..a5415af55 100644 --- a/core/hw/modem/modem.cpp +++ b/core/hw/modem/modem.cpp @@ -59,7 +59,7 @@ static modemreg_t modem_regs; static u8 dspram[0x1000]; -static int modem_sched; +int modem_sched; enum ModemStates { @@ -314,11 +314,13 @@ static int modem_sched_func(int tag, int c, int j) return callback_cycles; } +void ModemInit() +{ + modem_sched = sh4_sched_register(0, &modem_sched_func); +} + static void schedule_callback(int ms) { - if (modem_sched == 0) - // FIXME would break save state -> relies on all schedule to be registered at init - modem_sched = sh4_sched_register(0, &modem_sched_func); sh4_sched_request(modem_sched, SH4_MAIN_CLOCK / 1000 * ms); } diff --git a/core/hw/modem/modem.h b/core/hw/modem/modem.h index 2b9c5460f..50e5af26c 100644 --- a/core/hw/modem/modem.h +++ b/core/hw/modem/modem.h @@ -24,5 +24,6 @@ #pragma once #include "types.h" +void ModemInit(); u32 ModemReadMem_A0_006(u32 addr,u32 size); void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size); diff --git a/core/hw/modem/net_platform.h b/core/hw/modem/net_platform.h index 3e6c6ae85..8ec9ba9ee 100644 --- a/core/hw/modem/net_platform.h +++ b/core/hw/modem/net_platform.h @@ -11,6 +11,7 @@ #include #include #include +#include #else #include #endif diff --git a/core/hw/modem/picoppp.cpp b/core/hw/modem/picoppp.cpp index 1def8e9a2..3d99a576d 100644 --- a/core/hw/modem/picoppp.cpp +++ b/core/hw/modem/picoppp.cpp @@ -58,6 +58,7 @@ struct pico_ip4 afo_ip; // src socket -> socket fd static map tcp_sockets; +static map tcp_connecting_sockets; // src port -> socket fd static map udp_sockets; @@ -165,6 +166,38 @@ void set_non_blocking(sock_t fd) #endif } +void set_tcp_nodelay(sock_t fd) +{ + int optval = 1; + socklen_t optlen = sizeof(optval); +#if defined(_WIN32) + struct protoent *tcp_proto = getprotobyname("TCP"); + setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen); +#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) + setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen); +#else + struct protoent *tcp_proto = getprotobyname("TCP"); + setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen); +#endif +} + +static void read_from_dc_socket(pico_socket *pico_sock, sock_t nat_sock) +{ + char buf[1510]; + + int r = pico_socket_read(pico_sock, buf, sizeof(buf)); + if (r > 0) + { + if (send(nat_sock, buf, r, 0) < r) + { + perror("tcp_callback send"); + closesocket(nat_sock); + pico_socket_close(pico_sock); + tcp_sockets.erase(pico_sock); + } + } +} + static void tcp_callback(uint16_t ev, struct pico_socket *s) { int r = 0; @@ -174,23 +207,12 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s) auto it = tcp_sockets.find(s); if (it == tcp_sockets.end()) { - printf("Unknown socket: remote port %d\n", s->remote_port); + if (tcp_connecting_sockets.find(s) == tcp_connecting_sockets.end()) + printf("Unknown socket: remote port %d\n", short_be(s->remote_port)); } else { - char buf[1510]; - - r = pico_socket_read(it->first, buf, sizeof(buf)); - if (r > 0) { - if (send(it->second, buf, r, 0) < r) - { - perror("tcp_callback send"); - closesocket(it->second); - pico_socket_close(it->first); - tcp_sockets.erase(it); - return; - } - } + read_from_dc_socket(it->first, it->second); } } @@ -205,12 +227,14 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s) struct pico_socket *sock_a = pico_socket_accept(s, &orig, &port); if (sock_a == NULL) { - printf("pico_socket_accept: %s\n", strerror(pico_err)); + // Also called for child sockets + if (tcp_sockets.find(s) == tcp_sockets.end()) + printf("pico_socket_accept: %s\n", strerror(pico_err)); } else { pico_ipv4_to_string(peer, orig.addr); - //printf("Connection established with %s:%d.\n", peer, short_be(port)); + //printf("Connection established from %s:%d to %08x:%d\n", peer, short_be(port), sock_a->local_addr.ip4.addr, short_be(sock_a->local_port)); pico_socket_setoption(sock_a, PICO_TCP_NODELAY, &yes); /* Set keepalive options */ // ka_val = 5; @@ -235,28 +259,23 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s) serveraddr.sin_addr.s_addr = afo_ip.addr; serveraddr.sin_port = sock_a->local_port; + set_non_blocking(sockfd); if (connect(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { - pico_ipv4_to_string(peer, sock_a->local_addr.ip4.addr); - printf("TCP connection to %s:%d failed: ", peer, sock_a->local_port); - perror(NULL); - closesocket(sockfd); + if (get_last_error() != EINPROGRESS && get_last_error() != L_EWOULDBLOCK) + { + pico_ipv4_to_string(peer, sock_a->local_addr.ip4.addr); + printf("TCP connection to %s:%d failed: ", peer, short_be(sock_a->local_port)); + perror(NULL); + closesocket(sockfd); + } + else + tcp_connecting_sockets[sock_a] = sockfd; } else { - set_non_blocking(sockfd); + set_tcp_nodelay(sockfd); - int optval = 1; - socklen_t optlen = sizeof(optval); -#if defined(_WIN32) - struct protoent *tcp_proto = getprotobyname("TCP"); - setsockopt(sockfd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen); -#elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) - setsockopt(sockfd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen); -#else - struct protoent *tcp_proto = getprotobyname("TCP"); - setsockopt(sockfd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen); -#endif tcp_sockets[sock_a] = sockfd; } } @@ -264,38 +283,45 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s) } if (ev & PICO_SOCK_EV_FIN) { - //printf("Socket closed. Exit normally. \n"); auto it = tcp_sockets.find(s); if (it == tcp_sockets.end()) { - printf("PICO_SOCK_EV_FIN: Unknown socket: remote port %d\n", s->remote_port); + printf("PICO_SOCK_EV_FIN: Unknown socket: remote port %d\n", short_be(s->remote_port)); } else { closesocket(it->second); - pico_socket_close(s); - tcp_sockets.erase(s); + tcp_sockets.erase(it); } } if (ev & PICO_SOCK_EV_ERR) { - printf("Socket error received: %s. Bailing out.\n", strerror(pico_err)); + printf("Socket error received: %s\n", strerror(pico_err)); auto it = tcp_sockets.find(s); if (it == tcp_sockets.end()) { - printf("PICO_SOCK_EV_ERR: Unknown socket: remote port %d\n", s->remote_port); + printf("PICO_SOCK_EV_ERR: Unknown socket: remote port %d\n", short_be(s->remote_port)); } else { closesocket(it->second); - pico_socket_close(s); - tcp_sockets.erase(s); + tcp_sockets.erase(it); } } -// if (ev & PICO_SOCK_EV_CLOSE) -// { -// } + if (ev & PICO_SOCK_EV_CLOSE) + { + auto it = tcp_sockets.find(s); + if (it == tcp_sockets.end()) + { + printf("PICO_SOCK_EV_CLOSE: Unknown socket: remote port %d\n", short_be(s->remote_port)); + } + else + { + shutdown(it->second, SHUT_WR); + pico_socket_shutdown(s, PICO_SHUT_RD); + } + } // if (ev & PICO_SOCK_EV_WR) // { @@ -374,22 +400,22 @@ static void read_native_sockets() socklen_t addr_len; // Accept incoming TCP connections - for (auto it = tcp_listening_sockets.begin(); it != tcp_listening_sockets.end(); it++) - { + for (auto it = tcp_listening_sockets.begin(); it != tcp_listening_sockets.end(); it++) + { addr_len = sizeof(src_addr); memset(&src_addr, 0, addr_len); - sock_t sockfd = accept(it->second, (struct sockaddr *)&src_addr, &addr_len); - if (!VALID(sockfd)) - { - if (get_last_error() != L_EAGAIN && get_last_error() != L_EWOULDBLOCK) - perror("accept"); - continue; - } - printf("Incoming TCP connection from %08x to port %d\n", src_addr.sin_addr.s_addr, short_be(it->first)); - struct pico_socket *ps = pico_socket_tcp_open(PICO_PROTO_IPV4); + sock_t sockfd = accept(it->second, (struct sockaddr *)&src_addr, &addr_len); + if (!VALID(sockfd)) + { + if (get_last_error() != L_EAGAIN && get_last_error() != L_EWOULDBLOCK) + perror("accept"); + continue; + } + //printf("Incoming TCP connection from %08x to port %d\n", src_addr.sin_addr.s_addr, short_be(it->first)); + struct pico_socket *ps = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcp_callback); if (ps == NULL) { - printf("pico_socket_tcp_open failed: error %d\n", pico_err); + printf("pico_socket_open failed: error %d\n", pico_err); closesocket(sockfd); continue; } @@ -402,8 +428,53 @@ static void read_native_sockets() pico_socket_close(ps); continue; } + set_non_blocking(sockfd); + set_tcp_nodelay(sockfd); tcp_sockets[ps] = sockfd; - } + } + + // Check connecting outbound TCP sockets + fd_set write_fds; + FD_ZERO(&write_fds); + int max_fd = -1; + for (auto it = tcp_connecting_sockets.begin(); it != tcp_connecting_sockets.end(); it++) + { + FD_SET(it->second, &write_fds); + max_fd = max(max_fd, it->second); + } + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + if (select(max_fd + 1, NULL, &write_fds, NULL, &tv) > 0) + { + for (auto it = tcp_connecting_sockets.begin(); it != tcp_connecting_sockets.end(); ) + { + if (!FD_ISSET(it->second, &write_fds)) + { + it++; + continue; + } + int value; + socklen_t l = sizeof(int); + if (getsockopt(it->second, SOL_SOCKET, SO_ERROR, &value, &l) < 0 || value) + { + char peer[30]; + pico_ipv4_to_string(peer, it->first->local_addr.ip4.addr); + printf("TCP connection to %s:%d failed: ", peer, short_be(it->first->local_port)); + perror(NULL); + pico_socket_close(it->first); + closesocket(it->second); + } + else + { + set_tcp_nodelay(it->second); + tcp_sockets[it->first] = it->second; + + read_from_dc_socket(it->first, it->second); + } + it = tcp_connecting_sockets.erase(it); + } + } char buf[1500]; // FIXME MTU ? struct pico_msginfo msginfo; @@ -428,7 +499,7 @@ static void read_native_sockets() msginfo.ttl = 0; msginfo.local_addr.ip4.addr = src_addr.sin_addr.s_addr; msginfo.local_port = src_addr.sin_port; -// printf("read_native_sockets UCP received %d bytes from %08x:%d\n", r, long_be(msginfo.local_addr.ip4.addr), short_be(msginfo.local_port)); + //printf("read_native_sockets UDP received %d bytes from %08x:%d\n", r, long_be(msginfo.local_addr.ip4.addr), short_be(msginfo.local_port)); int r2 = pico_socket_sendto_extended(pico_udp_socket, buf, r, &dcaddr, it->first, &msginfo); if (r2 < r) printf("%s: error UDP sending to %d: %s\n", __FUNCTION__, short_be(it->first), strerror(pico_err)); @@ -441,19 +512,26 @@ static void read_native_sockets() } // Read TCP sockets - for (auto it = tcp_sockets.begin(); it != tcp_sockets.end(); it++) + for (auto it = tcp_sockets.begin(); it != tcp_sockets.end(); ) { uint32_t space; pico_tcp_get_bufspace_out(it->first, &space); if (space < sizeof(buf)) { // Wait for the out buffer to empty a bit + it++; continue; } r = recv(it->second, buf, sizeof(buf), 0); if (r > 0) { -// printf("read_native_sockets TCP received %d bytes\n", r); + if (it->first->remote_port == short_be(5011) && r >= 5) + { + // Visual Concepts sport games + if (buf[0] == 1) + memcpy(&buf[1], &it->first->local_addr.ip4.addr, 4); + } + int r2 = pico_socket_send(it->first, buf, r); if (r2 < 0) printf("%s: error TCP sending: %s\n", __FUNCTION__, strerror(pico_err)); @@ -463,15 +541,18 @@ static void read_native_sockets() } else if (r == 0) { - pico_socket_shutdown(it->first, PICO_SHUT_RDWR); + pico_socket_shutdown(it->first, PICO_SHUT_WR); + shutdown(it->second, SHUT_RD); } else if (r < 0 && get_last_error() != L_EAGAIN && get_last_error() != L_EWOULDBLOCK) { perror("recv tcp socket"); closesocket(it->second); pico_socket_close(it->first); - tcp_sockets.erase(it); + it = tcp_sockets.erase(it); + continue; } + it++; } }