TCP/IP support

This commit is contained in:
Cacodemon345
2024-03-12 14:27:19 +06:00
parent 10e0dbaafa
commit d51ba85814
6 changed files with 479 additions and 10 deletions

View File

@@ -451,6 +451,12 @@ serial_set_ri(serial_t *dev, uint8_t enabled)
}
}
int
serial_get_ri(serial_t *dev)
{
return !!(dev->msr & (1 << 6));
}
void
serial_set_clock_src(serial_t *dev, double clock_src)
{

View File

@@ -137,6 +137,7 @@ extern void serial_set_cts(serial_t *dev, uint8_t enabled);
extern void serial_set_dsr(serial_t *dev, uint8_t enabled);
extern void serial_set_dcd(serial_t *dev, uint8_t enabled);
extern void serial_set_ri(serial_t *dev, uint8_t enabled);
extern int serial_get_ri(serial_t *dev);
extern const device_t ns8250_device;
extern const device_t ns8250_pcjr_device;

View File

@@ -20,6 +20,7 @@
#include <86box/plat.h>
#include <86box/network.h>
#include <86box/plat_unused.h>
#include <86box/plat_netsocket.h>
/* From RFC 1055. */
#define END 0300 /* indicates end of packet */
@@ -93,9 +94,17 @@ typedef struct modem_t
bool connected, ringing;
bool echo, numericresponse;
bool tcpIpMode, tcpIpConnInProgress;
uint32_t tcpIpConnCounter;
int doresponse;
int cmdpause;
int listen_port;
int ringtimer;
SOCKET serversocket;
SOCKET clientsocket;
SOCKET waitingclientsocket;
struct {
bool binary[2];
@@ -309,7 +318,7 @@ modem_data_mode_process_byte(modem_t* modem, uint8_t data)
if (modem->tx_count < 0x10000 && modem->connected) {
modem->tx_pkt_ser_line[modem->tx_count++] = data;
if (data == END) {
if (data == END && !modem->tcpIpMode) {
process_tx_packet(modem, modem->tx_pkt_ser_line, (uint32_t)modem->tx_count);
modem->tx_count = 0;
}
@@ -321,6 +330,9 @@ host_to_modem_cb(void *priv)
{
modem_t* modem = (modem_t*)priv;
if (modem->in_warmup)
goto no_write_to_machine;
if ((modem->serial->type >= SERIAL_16550) && modem->serial->fifo_enabled) {
if (fifo_get_full(modem->serial->rcvr_fifo)) {
goto no_write_to_machine;
@@ -441,6 +453,37 @@ modem_enter_idle_state(modem_t* modem)
modem->ringing = false;
modem->mode = MODEM_MODE_COMMAND;
modem->in_warmup = 0;
modem->tcpIpConnInProgress = 0;
modem->tcpIpConnCounter = 0;
if (modem->waitingclientsocket != -1)
plat_netsocket_close(modem->waitingclientsocket);
if (modem->clientsocket != -1)
plat_netsocket_close(modem->clientsocket);
modem->clientsocket = modem->waitingclientsocket = -1;
if (modem->serversocket != -1) {
modem->waitingclientsocket = plat_netsocket_accept(modem->serversocket);
while (modem->waitingclientsocket != -1) {
plat_netsocket_close(modem->waitingclientsocket);
modem->waitingclientsocket = plat_netsocket_accept(modem->serversocket);
}
plat_netsocket_close(modem->serversocket);
modem->serversocket = -1;
}
if (modem->waitingclientsocket != -1)
plat_netsocket_close(modem->waitingclientsocket);
modem->waitingclientsocket = -1;
modem->tcpIpMode = false;
modem->tcpIpConnInProgress = false;
if (modem->listen_port) {
modem->serversocket = plat_netsocket_create_server(NET_SOCKET_TCP, modem->listen_port);
}
serial_set_cts(modem->serial, 1);
serial_set_dsr(modem->serial, 1);
serial_set_dcd(modem->serial, 0);
@@ -454,6 +497,9 @@ modem_enter_connected_state(modem_t* modem)
modem->mode = MODEM_MODE_DATA;
modem->ringing = false;
modem->connected = true;
modem->tcpIpMode = true;
plat_netsocket_close(modem->serversocket);
modem->serversocket = -1;
memset(&modem->telClient, 0, sizeof(modem->telClient));
serial_set_dcd(modem->serial, 1);
serial_set_ri(modem->serial, 0);
@@ -488,15 +534,40 @@ void
modem_dial(modem_t* modem, const char* str)
{
/* TODO: Port TCP/IP support from DOSBox. */
modem->tcpIpConnCounter = 0;
modem->tcpIpMode = false;
if (!strncmp(str, "0.0.0.0", sizeof("0.0.0.0") - 1))
{
pclog("Turning on SLIP\n");
modem_enter_connected_state(modem);
modem->tcpIpMode = false;
}
else
{
modem_send_res(modem, ResNOCARRIER);
modem_enter_idle_state(modem);
char buf[128] = "";
const char *destination = buf;
strcpy(buf, str);
// Scan host for port
uint16_t port;
char * hasport = strrchr(buf,':');
if (hasport) {
*hasport++ = 0;
port = (uint16_t)atoi(hasport);
}
else {
port = 23;
}
modem->clientsocket = plat_netsocket_create(NET_SOCKET_TCP);
if (modem->clientsocket == -1) {
modem_send_res(modem, ResNOCARRIER);
modem_enter_idle_state(modem);
return;
}
plat_netsocket_connect(modem->clientsocket, buf, port);
modem->tcpIpConnInProgress = 1;
modem->tcpIpConnCounter = 0;
}
}
@@ -551,6 +622,16 @@ char *trim(char *str)
return str;
}
static const char *modem_get_address_from_phonebook(modem_t* modem, const char *input) {
int i = 0;
for (i = 0; i < modem->entries_num; i++) {
if (strcmp(input, modem->entries[i].phone) == 0)
return modem->entries[i].address;
}
return NULL;
}
static void
modem_do_command(modem_t* modem)
{
@@ -583,7 +664,9 @@ modem_do_command(modem_t* modem)
char buffer[128];
char obuffer[128];
char * foundstr = &scanbuf[0];
const char *mappedaddr = NULL;
size_t i = 0;
if (*foundstr == 'T' || *foundstr == 'P')
foundstr++;
@@ -593,6 +676,13 @@ modem_do_command(modem_t* modem)
}
foundstr = trim(foundstr);
mappedaddr = modem_get_address_from_phonebook(modem, foundstr);
if (mappedaddr) {
modem_dial(modem, mappedaddr);
return;
}
if (strlen(foundstr) >= 12) {
// Check if supplied parameter only consists of digits
bool isNum = true;
@@ -860,6 +950,9 @@ modem_rx(void *priv, uint8_t *buf, int io_len)
uint8_t c = 0;
uint32_t i = 0;
if (modem->tcpIpMode)
return 0;
if (!modem->connected) {
/* Drop packet. */
pclog("Dropping %d bytes\n", io_len - 14);
@@ -914,12 +1007,127 @@ modem_rcr_cb(UNUSED(struct serial_s *serial), void *priv)
#endif
}
static void
modem_accept_incoming_call(modem_t* modem)
{
if (modem->waitingclientsocket != -1) {
modem->clientsocket = modem->waitingclientsocket;
modem->waitingclientsocket = -1;
modem_enter_connected_state(modem);
modem->in_warmup = 250;
} else {
modem_enter_idle_state(modem);
}
}
static void
modem_cmdpause_timer_callback(void *priv)
{
modem_t *dev = (modem_t *) priv;
uint32_t guard_threashold = 0;
if (dev->tcpIpConnInProgress) {
int status = plat_netsocket_connected(dev->clientsocket);
if (status == -1) {
plat_netsocket_close(dev->clientsocket);
dev->clientsocket = -1;
modem_enter_idle_state(dev);
modem_send_res(dev, ResNOCARRIER);
dev->tcpIpConnInProgress = 0;
} else if (status == 1) {
modem_enter_connected_state(dev);
dev->tcpIpConnInProgress = 0;
}
dev->tcpIpConnCounter++;
if (status <= 0 && dev->tcpIpConnCounter >= 5000) {
plat_netsocket_close(dev->clientsocket);
dev->clientsocket = -1;
modem_enter_idle_state(dev);
modem_send_res(dev, ResNOANSWER);
dev->tcpIpConnInProgress = 0;
dev->tcpIpMode = 0;
}
}
if (!dev->connected && dev->waitingclientsocket == -1 && dev->serversocket != -1) {
dev->waitingclientsocket = plat_netsocket_accept(dev->serversocket);
if (dev->waitingclientsocket != -1) {
if (!(dev->serial->mctrl & 1) && dev->dtrmode != 0) {
modem_enter_idle_state(dev);
} else {
dev->ringing = true;
modem_send_res(dev, ResRING);
serial_set_ri(dev->serial, !serial_get_ri(dev->serial));
dev->ringtimer = 3000;
dev->reg[MREG_RING_COUNT] = 0;
}
}
}
if (dev->ringing) {
if (dev->ringtimer <= 0) {
dev->reg[MREG_RING_COUNT]++;
if ((dev->reg[MREG_AUTOANSWER_COUNT] > 0) &&
(dev->reg[MREG_RING_COUNT] >= dev->reg[MREG_AUTOANSWER_COUNT])) {
modem_accept_incoming_call(dev);
return;
}
modem_send_res(dev, ResRING);
serial_set_ri(dev->serial, !serial_get_ri(dev->serial));
//MIXER_Enable(mhd.chan,true);
dev->ringtimer = 3000;
}
--dev->ringtimer;
}
if (dev->in_warmup) {
dev->in_warmup--;
if (dev->in_warmup == 0) {
dev->tx_count = 0;
fifo8_reset(&dev->rx_data);
}
}
else if (dev->connected && dev->tcpIpMode) {
if (dev->tx_count) {
int wouldblock = 0;
int res = plat_netsocket_send(dev->clientsocket, dev->tx_pkt_ser_line, dev->tx_count, &wouldblock);
if (res <= 0 && !wouldblock) {
/* No bytes sent or error. */
dev->tx_count = 0;
modem_enter_idle_state(dev);
modem_send_res(dev, ResNOCARRIER);
} else if (res > 0) {
if (res == dev->tx_count) {
dev->tx_count = 0;
} else {
memmove(dev->tx_pkt_ser_line, &dev->tx_pkt_ser_line[res], dev->tx_count - res);
dev->tx_count -= res;
}
}
}
if (dev->connected) {
uint8_t buffer[16];
int wouldblock = 0;
int res = plat_netsocket_receive(dev->clientsocket, buffer, sizeof(buffer), &wouldblock);
if (res > 0) {
fifo8_push_all(&dev->rx_data, buffer, res);
} else if (res == 0) {
dev->tx_count = 0;
modem_enter_idle_state(dev);
modem_send_res(dev, ResNOCARRIER);
} else if (!wouldblock) {
dev->tx_count = 0;
modem_enter_idle_state(dev);
modem_send_res(dev, ResNOCARRIER);
}
}
}
dev->cmdpause++;
guard_threashold = (uint32_t)(dev->reg[MREG_GUARD_TIME] * 20);
if (dev->cmdpause > guard_threashold) {
@@ -938,11 +1146,13 @@ static void *
modem_init(const device_t *info)
{
modem_t* modem = (modem_t*)calloc(1, sizeof(modem_t));
const char* phonebook_file = NULL;
memset(modem->mac, 0xfc, 6);
modem->port = device_get_config_int("port");
modem->baudrate = device_get_config_int("baudrate");
modem->listen_port = device_get_config_int("listen_port");
fifo8_create(&modem->data_pending, 0x10000);
fifo8_create(&modem->rx_data, 0x10000);
@@ -955,12 +1165,20 @@ modem_init(const device_t *info)
modem_reset(modem);
modem->card = network_attach(modem, modem->mac, modem_rx, NULL);
phonebook_file = device_get_config_string("phonebook_file");
if (phonebook_file && phonebook_file[0] != 0) {
modem_read_phonebook_file(modem, phonebook_file);
}
return modem;
}
void modem_close(void *priv)
{
modem_t* modem = (modem_t*)priv;
modem->listen_port = 0;
modem_reset(modem);
fifo8_destroy(&modem->data_pending);
fifo8_destroy(&modem->rx_data);
netcard_close(modem->card);
@@ -1009,6 +1227,23 @@ static const device_config_t modem_config[] = {
{ .description = "300", .value = 300 },
}
},
{
.name = "listen_port",
.description = "TCP/IP listening port",
.type = CONFIG_INT,
.default_string = "",
.default_int = 5000,
.file_filter = NULL,
.spinner = { 0 },
.selection = {}
},
{
.name = "phonebook_file",
.description = "Phonebook File",
.type = CONFIG_FNAME,
.default_string = "",
.file_filter = "Text files (*.txt)|*.txt"
},
{ .name = "", .description = "", .type = CONFIG_END }
};

View File

@@ -223,7 +223,7 @@ endif()
if(WIN32)
target_sources(plat PRIVATE ../win/win_serial_passthrough.c ../win/win_netsocket.c)
else()
target_sources(plat PRIVATE ../unix/unix_serial_passthrough.c)
target_sources(plat PRIVATE ../unix/unix_serial_passthrough.c ../unix/unix_netsocket.c)
endif()
if (APPLE)

194
src/unix/unix_netsocket.c Normal file
View File

@@ -0,0 +1,194 @@
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/log.h>
#include <86box/timer.h>
#include <86box/plat.h>
#include <86box/device.h>
#include <86box/plat_netsocket.h>
#include <86box/ui.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
SOCKET plat_netsocket_create(int type)
{
SOCKET fd = -1;
u_long yes = 1;
if (type != NET_SOCKET_TCP)
return -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return -1;
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
return fd;
}
SOCKET plat_netsocket_create_server(int type, unsigned short port)
{
struct sockaddr_in sock_addr;
SOCKET fd = -1;
u_long yes = 1;
if (type != NET_SOCKET_TCP)
return -1;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
return -1;
memset(&sock_addr, 0, sizeof(struct sockaddr_in));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = INADDR_ANY;
sock_addr.sin_port = port;
if (bind(fd, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) == -1) {
plat_netsocket_close(fd);
return (SOCKET)-1;
}
if (listen(fd, 5) == -1) {
plat_netsocket_close(fd);
return (SOCKET)-1;
}
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
return fd;
}
void plat_netsocket_close(SOCKET socket)
{
close((SOCKET)socket);
}
SOCKET plat_netsocket_accept(SOCKET socket)
{
SOCKET clientsocket = accept(socket, NULL, NULL);
if (clientsocket == -1)
return -1;
return clientsocket;
}
int plat_netsocket_connected(SOCKET socket)
{
struct sockaddr addr;
socklen_t len = sizeof(struct sockaddr);
fd_set wrfds;
struct timeval tv;
int res = -1;
int status = 0;
int optlen = 4;
FD_ZERO(&wrfds);
FD_SET(socket, &wrfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
res = select(socket + 1, NULL, &wrfds, NULL, &tv);
if (res == -1)
return -1;
if (res == 0 || !(res >= 1 && FD_ISSET(socket, &wrfds)))
return 0;
res = getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&status, &optlen);
if (res == -1)
return -1;
if (status != 0)
return -1;
if (getpeername(socket, &addr, &len) == -1)
return -1;
return 1;
}
int plat_netsocket_connect(SOCKET socket, const char* hostname, unsigned short port)
{
struct sockaddr_in sock_addr;
int res = -1;
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = inet_addr(hostname);
sock_addr.sin_port = htons(port);
if (sock_addr.sin_addr.s_addr == INADDR_ANY || sock_addr.sin_addr.s_addr == INADDR_NONE) {
struct hostent *hp;
hp = gethostbyname(hostname);
if (hp)
memcpy(&sock_addr.sin_addr.s_addr, hp->h_addr_list[0], hp->h_length);
else
return -1;
}
res = connect(socket, (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in));
if (res == -1) {
int error = errno;
if (error == EISCONN)
return 0;
res = -1;
}
return res;
}
int plat_netsocket_send(SOCKET socket, const unsigned char* data, unsigned int size, int *wouldblock)
{
int res = send(socket, (const char*)data, size, 0);
if (res == -1) {
int error = errno;
if (wouldblock)
*wouldblock = !!(error == EWOULDBLOCK || error == EAGAIN);
return -1;
}
return res;
}
int plat_netsocket_receive(SOCKET socket, unsigned char* data, unsigned int size, int *wouldblock)
{
int res = recv(socket, (char*)data, size, 0);
if (res == -1) {
int error = errno;
if (wouldblock)
*wouldblock = !!(error == EWOULDBLOCK || error == EAGAIN);
return -1;
}
return res;
}

View File

@@ -38,9 +38,15 @@ SOCKET plat_netsocket_create(int type)
SOCKET plat_netsocket_create_server(int type, unsigned short port)
{
struct sockaddr_in sock_addr;
SOCKET socket = plat_netsocket_create(type);
SOCKET socket = -1;
u_long yes = 1;
if (type != NET_SOCKET_TCP)
return -1;
socket = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (socket == INVALID_SOCKET)
return (SOCKET)-1;
return -1;
memset(&sock_addr, 0, sizeof(struct sockaddr_in));
@@ -58,6 +64,8 @@ SOCKET plat_netsocket_create_server(int type, unsigned short port)
return (SOCKET)-1;
}
ioctlsocket(socket, FIONBIO, &yes);
return socket;
}
@@ -79,12 +87,37 @@ SOCKET plat_netsocket_accept(SOCKET socket)
int plat_netsocket_connected(SOCKET socket)
{
struct sockaddr addr;
socklen_t len = sizeof(struct sockaddr);
socklen_t len = sizeof(struct sockaddr);
fd_set wrfds;
struct timeval tv;
int res = SOCKET_ERROR;
int status = 0;
int optlen = 4;
FD_ZERO(&wrfds);
FD_SET(socket, &wrfds);
tv.tv_sec = 0;
tv.tv_usec = 0;
res = select(1, NULL, &wrfds, NULL, &tv);
if (res == SOCKET_ERROR)
return -1;
if (res == 0 || !(res >= 1 && FD_ISSET(socket, &wrfds)))
return 0;
res = getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&status, &optlen);
if (res == SOCKET_ERROR)
return -1;
if (status != 0)
return -1;
if (getpeername(socket, &addr, &len) == SOCKET_ERROR)
return 0;
return -1;
return 1;
}
@@ -98,7 +131,7 @@ int plat_netsocket_connect(SOCKET socket, const char* hostname, unsigned short p
sock_addr.sin_addr.s_addr = inet_addr(hostname);
sock_addr.sin_port = htons(port);
if (sock_addr.sin_addr.s_addr == -1 || sock_addr.sin_addr.s_addr == 0) {
if (sock_addr.sin_addr.s_addr == INADDR_ANY || sock_addr.sin_addr.s_addr == INADDR_NONE) {
struct hostent *hp;
hp = gethostbyname(hostname);