Merge pull request #4248 from Cacodemon345/modem_emu
net_modem: TCP/IP support and Telnet emulation
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -59,3 +59,6 @@ CMakeLists.txt.user
|
|||||||
|
|
||||||
# MacOS Finder stuff
|
# MacOS Finder stuff
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
# clangd
|
||||||
|
.cache
|
||||||
|
@@ -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
|
void
|
||||||
serial_set_clock_src(serial_t *dev, double clock_src)
|
serial_set_clock_src(serial_t *dev, double clock_src)
|
||||||
{
|
{
|
||||||
|
@@ -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_dsr(serial_t *dev, uint8_t enabled);
|
||||||
extern void serial_set_dcd(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 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_device;
|
||||||
extern const device_t ns8250_pcjr_device;
|
extern const device_t ns8250_pcjr_device;
|
||||||
|
@@ -1,5 +1,22 @@
|
|||||||
|
|
||||||
/* TODO: SLIP support. */
|
/*
|
||||||
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
|
* running old operating systems and software designed for IBM
|
||||||
|
* PC systems and compatibles from 1981 through fairly recent
|
||||||
|
* system designs based on the PCI bus.
|
||||||
|
*
|
||||||
|
* This file is part of the 86Box distribution.
|
||||||
|
*
|
||||||
|
* Hayes AT-compliant modem emulation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Authors: Cacodemon345
|
||||||
|
* The DOSBox Team
|
||||||
|
*
|
||||||
|
* Copyright 2024 Cacodemon345
|
||||||
|
* Copyright 2002-2021 The DOSBox Team
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -20,6 +37,7 @@
|
|||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
#include <86box/network.h>
|
#include <86box/network.h>
|
||||||
#include <86box/plat_unused.h>
|
#include <86box/plat_unused.h>
|
||||||
|
#include <86box/plat_netsocket.h>
|
||||||
|
|
||||||
/* From RFC 1055. */
|
/* From RFC 1055. */
|
||||||
#define END 0300 /* indicates end of packet */
|
#define END 0300 /* indicates end of packet */
|
||||||
@@ -93,9 +111,18 @@ typedef struct modem_t
|
|||||||
|
|
||||||
bool connected, ringing;
|
bool connected, ringing;
|
||||||
bool echo, numericresponse;
|
bool echo, numericresponse;
|
||||||
|
bool tcpIpMode, tcpIpConnInProgress;
|
||||||
|
bool telnet_mode;
|
||||||
|
uint32_t tcpIpConnCounter;
|
||||||
|
|
||||||
int doresponse;
|
int doresponse;
|
||||||
int cmdpause;
|
int cmdpause;
|
||||||
|
int listen_port;
|
||||||
|
int ringtimer;
|
||||||
|
|
||||||
|
SOCKET serversocket;
|
||||||
|
SOCKET clientsocket;
|
||||||
|
SOCKET waitingclientsocket;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
bool binary[2];
|
bool binary[2];
|
||||||
@@ -151,6 +178,9 @@ modem_read_phonebook_file(modem_t* modem, const char* path)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (res == EOF)
|
||||||
|
break;
|
||||||
|
|
||||||
if (strspn(entry.phone, "01234567890*=,;#+>") != strlen(entry.phone)) {
|
if (strspn(entry.phone, "01234567890*=,;#+>") != strlen(entry.phone)) {
|
||||||
/* Invalid characters. */
|
/* Invalid characters. */
|
||||||
continue;
|
continue;
|
||||||
@@ -309,7 +339,7 @@ modem_data_mode_process_byte(modem_t* modem, uint8_t data)
|
|||||||
|
|
||||||
if (modem->tx_count < 0x10000 && modem->connected) {
|
if (modem->tx_count < 0x10000 && modem->connected) {
|
||||||
modem->tx_pkt_ser_line[modem->tx_count++] = data;
|
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);
|
process_tx_packet(modem, modem->tx_pkt_ser_line, (uint32_t)modem->tx_count);
|
||||||
modem->tx_count = 0;
|
modem->tx_count = 0;
|
||||||
}
|
}
|
||||||
@@ -321,6 +351,9 @@ host_to_modem_cb(void *priv)
|
|||||||
{
|
{
|
||||||
modem_t* modem = (modem_t*)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 ((modem->serial->type >= SERIAL_16550) && modem->serial->fifo_enabled) {
|
||||||
if (fifo_get_full(modem->serial->rcvr_fifo)) {
|
if (fifo_get_full(modem->serial->rcvr_fifo)) {
|
||||||
goto no_write_to_machine;
|
goto no_write_to_machine;
|
||||||
@@ -441,6 +474,40 @@ modem_enter_idle_state(modem_t* modem)
|
|||||||
modem->ringing = false;
|
modem->ringing = false;
|
||||||
modem->mode = MODEM_MODE_COMMAND;
|
modem->mode = MODEM_MODE_COMMAND;
|
||||||
modem->in_warmup = 0;
|
modem->in_warmup = 0;
|
||||||
|
modem->tcpIpConnInProgress = 0;
|
||||||
|
modem->tcpIpConnCounter = 0;
|
||||||
|
|
||||||
|
if (modem->waitingclientsocket != (SOCKET)-1)
|
||||||
|
plat_netsocket_close(modem->waitingclientsocket);
|
||||||
|
|
||||||
|
if (modem->clientsocket != (SOCKET)-1)
|
||||||
|
plat_netsocket_close(modem->clientsocket);
|
||||||
|
|
||||||
|
modem->clientsocket = modem->waitingclientsocket = (SOCKET)-1;
|
||||||
|
if (modem->serversocket != (SOCKET)-1) {
|
||||||
|
modem->waitingclientsocket = plat_netsocket_accept(modem->serversocket);
|
||||||
|
while (modem->waitingclientsocket != (SOCKET)-1) {
|
||||||
|
plat_netsocket_close(modem->waitingclientsocket);
|
||||||
|
modem->waitingclientsocket = plat_netsocket_accept(modem->serversocket);
|
||||||
|
}
|
||||||
|
plat_netsocket_close(modem->serversocket);
|
||||||
|
modem->serversocket = (SOCKET)-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modem->waitingclientsocket != (SOCKET)-1)
|
||||||
|
plat_netsocket_close(modem->waitingclientsocket);
|
||||||
|
|
||||||
|
modem->waitingclientsocket = (SOCKET)-1;
|
||||||
|
modem->tcpIpMode = false;
|
||||||
|
modem->tcpIpConnInProgress = false;
|
||||||
|
|
||||||
|
if (modem->listen_port) {
|
||||||
|
modem->serversocket = plat_netsocket_create_server(NET_SOCKET_TCP, modem->listen_port);
|
||||||
|
if (modem->serversocket == (SOCKET)-1) {
|
||||||
|
pclog("Failed to set up server on port %d\n", modem->listen_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
serial_set_cts(modem->serial, 1);
|
serial_set_cts(modem->serial, 1);
|
||||||
serial_set_dsr(modem->serial, 1);
|
serial_set_dsr(modem->serial, 1);
|
||||||
serial_set_dcd(modem->serial, 0);
|
serial_set_dcd(modem->serial, 0);
|
||||||
@@ -454,6 +521,9 @@ modem_enter_connected_state(modem_t* modem)
|
|||||||
modem->mode = MODEM_MODE_DATA;
|
modem->mode = MODEM_MODE_DATA;
|
||||||
modem->ringing = false;
|
modem->ringing = false;
|
||||||
modem->connected = true;
|
modem->connected = true;
|
||||||
|
modem->tcpIpMode = true;
|
||||||
|
plat_netsocket_close(modem->serversocket);
|
||||||
|
modem->serversocket = -1;
|
||||||
memset(&modem->telClient, 0, sizeof(modem->telClient));
|
memset(&modem->telClient, 0, sizeof(modem->telClient));
|
||||||
serial_set_dcd(modem->serial, 1);
|
serial_set_dcd(modem->serial, 1);
|
||||||
serial_set_ri(modem->serial, 0);
|
serial_set_ri(modem->serial, 0);
|
||||||
@@ -488,15 +558,46 @@ void
|
|||||||
modem_dial(modem_t* modem, const char* str)
|
modem_dial(modem_t* modem, const char* str)
|
||||||
{
|
{
|
||||||
/* TODO: Port TCP/IP support from DOSBox. */
|
/* 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))
|
if (!strncmp(str, "0.0.0.0", sizeof("0.0.0.0") - 1))
|
||||||
{
|
{
|
||||||
pclog("Turning on SLIP\n");
|
pclog("Turning on SLIP\n");
|
||||||
modem_enter_connected_state(modem);
|
modem_enter_connected_state(modem);
|
||||||
|
modem->tcpIpMode = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
modem_send_res(modem, ResNOCARRIER);
|
char buf[128] = "";
|
||||||
modem_enter_idle_state(modem);
|
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) {
|
||||||
|
pclog("Failed to create client socket\n");
|
||||||
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == plat_netsocket_connect(modem->clientsocket, buf, port)) {
|
||||||
|
pclog("Failed to connect to %s\n", buf);
|
||||||
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modem->tcpIpConnInProgress = 1;
|
||||||
|
modem->tcpIpConnCounter = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -551,6 +652,16 @@ char *trim(char *str)
|
|||||||
return 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
|
static void
|
||||||
modem_do_command(modem_t* modem)
|
modem_do_command(modem_t* modem)
|
||||||
{
|
{
|
||||||
@@ -576,14 +687,31 @@ modem_do_command(modem_t* modem)
|
|||||||
char chr = modem_fetch_character(&scanbuf);
|
char chr = modem_fetch_character(&scanbuf);
|
||||||
switch (chr) {
|
switch (chr) {
|
||||||
case '+':
|
case '+':
|
||||||
/* None supported yet. */
|
if (is_next_token("NET", sizeof("NET"), scanbuf)) {
|
||||||
|
// only walk the pointer ahead if the command matches
|
||||||
|
scanbuf += 3;
|
||||||
|
const uint32_t requested_mode = modem_scan_number(&scanbuf);
|
||||||
|
|
||||||
|
// If the mode isn't valid then stop parsing
|
||||||
|
if (requested_mode != 1 && requested_mode != 0) {
|
||||||
|
modem_send_res(modem, ResERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Inform the user on changes
|
||||||
|
if (modem->telnet_mode != !!requested_mode) {
|
||||||
|
modem->telnet_mode = !!requested_mode;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
modem_send_res(modem, ResERROR);
|
modem_send_res(modem, ResERROR);
|
||||||
return;
|
return;
|
||||||
case 'D': { // Dial.
|
case 'D': { // Dial.
|
||||||
char buffer[128];
|
char buffer[128];
|
||||||
char obuffer[128];
|
char obuffer[128];
|
||||||
char * foundstr = &scanbuf[0];
|
char * foundstr = &scanbuf[0];
|
||||||
|
const char *mappedaddr = NULL;
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
if (*foundstr == 'T' || *foundstr == 'P')
|
if (*foundstr == 'T' || *foundstr == 'P')
|
||||||
foundstr++;
|
foundstr++;
|
||||||
|
|
||||||
@@ -593,6 +721,13 @@ modem_do_command(modem_t* modem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
foundstr = trim(foundstr);
|
foundstr = trim(foundstr);
|
||||||
|
|
||||||
|
mappedaddr = modem_get_address_from_phonebook(modem, foundstr);
|
||||||
|
if (mappedaddr) {
|
||||||
|
modem_dial(modem, mappedaddr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (strlen(foundstr) >= 12) {
|
if (strlen(foundstr) >= 12) {
|
||||||
// Check if supplied parameter only consists of digits
|
// Check if supplied parameter only consists of digits
|
||||||
bool isNum = true;
|
bool isNum = true;
|
||||||
@@ -634,6 +769,7 @@ modem_do_command(modem_t* modem)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
modem_dial(modem, foundstr);
|
modem_dial(modem, foundstr);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
case 'I': // Some strings about firmware
|
case 'I': // Some strings about firmware
|
||||||
switch (modem_scan_number(&scanbuf)) {
|
switch (modem_scan_number(&scanbuf)) {
|
||||||
@@ -851,6 +987,106 @@ fifo8_resize_2x(Fifo8* fifo)
|
|||||||
free(temp_buf);
|
free(temp_buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define TEL_CLIENT 0
|
||||||
|
#define TEL_SERVER 1
|
||||||
|
void modem_process_telnet(modem_t* modem, uint8_t *data, uint32_t size)
|
||||||
|
{
|
||||||
|
uint32_t i = 0;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
uint8_t c = data[i];
|
||||||
|
if (modem->telClient.inIAC) {
|
||||||
|
if (modem->telClient.recCommand) {
|
||||||
|
if ((c != 0) && (c != 1) && (c != 3)) {
|
||||||
|
if (modem->telClient.command > 250) {
|
||||||
|
/* Reject anything we don't recognize */
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 252);
|
||||||
|
modem_data_mode_process_byte(modem, c); /* We won't do crap! */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (modem->telClient.command) {
|
||||||
|
case 251: /* Will */
|
||||||
|
if (c == 0) modem->telClient.binary[TEL_SERVER] = true;
|
||||||
|
if (c == 1) modem->telClient.echo[TEL_SERVER] = true;
|
||||||
|
if (c == 3) modem->telClient.supressGA[TEL_SERVER] = true;
|
||||||
|
break;
|
||||||
|
case 252: /* Won't */
|
||||||
|
if (c == 0) modem->telClient.binary[TEL_SERVER] = false;
|
||||||
|
if (c == 1) modem->telClient.echo[TEL_SERVER] = false;
|
||||||
|
if (c == 3) modem->telClient.supressGA[TEL_SERVER] = false;
|
||||||
|
break;
|
||||||
|
case 253: /* Do */
|
||||||
|
if (c == 0) {
|
||||||
|
modem->telClient.binary[TEL_CLIENT] = true;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 251);
|
||||||
|
modem_data_mode_process_byte(modem, 0); /* Will do binary transfer */
|
||||||
|
}
|
||||||
|
if (c == 1) {
|
||||||
|
modem->telClient.echo[TEL_CLIENT] = false;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 252);
|
||||||
|
modem_data_mode_process_byte(modem, 1); /* Won't echo (too lazy) */
|
||||||
|
}
|
||||||
|
if (c == 3) {
|
||||||
|
modem->telClient.supressGA[TEL_CLIENT] = true;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 251);
|
||||||
|
modem_data_mode_process_byte(modem, 3); /* Will Suppress GA */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 254: /* Don't */
|
||||||
|
if (c == 0) {
|
||||||
|
modem->telClient.binary[TEL_CLIENT] = false;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 252);
|
||||||
|
modem_data_mode_process_byte(modem, 0); /* Won't do binary transfer */
|
||||||
|
}
|
||||||
|
if (c == 1) {
|
||||||
|
modem->telClient.echo[TEL_CLIENT] = false;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 252);
|
||||||
|
modem_data_mode_process_byte(modem, 1); /* Won't echo (fine by me) */
|
||||||
|
}
|
||||||
|
if (c == 3) {
|
||||||
|
modem->telClient.supressGA[TEL_CLIENT] = true;
|
||||||
|
modem_data_mode_process_byte(modem, 0xff);
|
||||||
|
modem_data_mode_process_byte(modem, 251);
|
||||||
|
modem_data_mode_process_byte(modem, 3); /* Will Suppress GA (too lazy) */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
modem->telClient.inIAC = false;
|
||||||
|
modem->telClient.recCommand = false;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
if (c == 249) {
|
||||||
|
/* Go Ahead received */
|
||||||
|
modem->telClient.inIAC = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
modem->telClient.command = c;
|
||||||
|
modem->telClient.recCommand = true;
|
||||||
|
|
||||||
|
if ((modem->telClient.binary[TEL_SERVER]) && (c == 0xff)) {
|
||||||
|
/* Binary data with value of 255 */
|
||||||
|
modem->telClient.inIAC = false;
|
||||||
|
modem->telClient.recCommand = false;
|
||||||
|
fifo8_push(&modem->rx_data, 0xff);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (c == 0xff) {
|
||||||
|
modem->telClient.inIAC = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fifo8_push(&modem->rx_data, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
modem_rx(void *priv, uint8_t *buf, int io_len)
|
modem_rx(void *priv, uint8_t *buf, int io_len)
|
||||||
@@ -860,6 +1096,9 @@ modem_rx(void *priv, uint8_t *buf, int io_len)
|
|||||||
uint8_t c = 0;
|
uint8_t c = 0;
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
|
|
||||||
|
if (modem->tcpIpMode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!modem->connected) {
|
if (!modem->connected) {
|
||||||
/* Drop packet. */
|
/* Drop packet. */
|
||||||
pclog("Dropping %d bytes\n", io_len - 14);
|
pclog("Dropping %d bytes\n", io_len - 14);
|
||||||
@@ -914,21 +1153,144 @@ modem_rcr_cb(UNUSED(struct serial_s *serial), void *priv)
|
|||||||
#endif
|
#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
|
static void
|
||||||
modem_cmdpause_timer_callback(void *priv)
|
modem_cmdpause_timer_callback(void *priv)
|
||||||
{
|
{
|
||||||
modem_t *dev = (modem_t *) priv;
|
modem_t *modem = (modem_t *) priv;
|
||||||
uint32_t guard_threashold = 0;
|
uint32_t guard_threashold = 0;
|
||||||
|
timer_on_auto(&modem->cmdpause_timer, 1000);
|
||||||
|
|
||||||
dev->cmdpause++;
|
if (modem->tcpIpConnInProgress) {
|
||||||
guard_threashold = (uint32_t)(dev->reg[MREG_GUARD_TIME] * 20);
|
do {
|
||||||
if (dev->cmdpause > guard_threashold) {
|
int status = plat_netsocket_connected(modem->clientsocket);
|
||||||
if (dev->plusinc == 0) {
|
|
||||||
dev->plusinc = 1;
|
if (status == -1) {
|
||||||
} else if (dev->plusinc == 4) {
|
plat_netsocket_close(modem->clientsocket);
|
||||||
dev->mode = MODEM_MODE_COMMAND;
|
modem->clientsocket = -1;
|
||||||
modem_send_res(dev, ResOK);
|
modem_enter_idle_state(modem);
|
||||||
dev->plusinc = 0;
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
modem->tcpIpConnInProgress = 0;
|
||||||
|
break;
|
||||||
|
} else if (status == 1) {
|
||||||
|
modem_enter_connected_state(modem);
|
||||||
|
modem->tcpIpConnInProgress = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
modem->tcpIpConnCounter++;
|
||||||
|
|
||||||
|
if (status < 0 || (status == 0 && modem->tcpIpConnCounter >= 5000)) {
|
||||||
|
plat_netsocket_close(modem->clientsocket);
|
||||||
|
modem->clientsocket = -1;
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
modem_send_res(modem, ResNOANSWER);
|
||||||
|
modem->tcpIpConnInProgress = 0;
|
||||||
|
modem->tcpIpMode = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!modem->connected && modem->waitingclientsocket == -1 && modem->serversocket != -1) {
|
||||||
|
modem->waitingclientsocket = plat_netsocket_accept(modem->serversocket);
|
||||||
|
if (modem->waitingclientsocket != -1) {
|
||||||
|
if (!(modem->serial->mctrl & 1) && modem->dtrmode != 0) {
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
} else {
|
||||||
|
modem->ringing = true;
|
||||||
|
modem_send_res(modem, ResRING);
|
||||||
|
serial_set_ri(modem->serial, !serial_get_ri(modem->serial));
|
||||||
|
modem->ringtimer = 3000;
|
||||||
|
modem->reg[MREG_RING_COUNT] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modem->ringing) {
|
||||||
|
if (modem->ringtimer <= 0) {
|
||||||
|
modem->reg[MREG_RING_COUNT]++;
|
||||||
|
if ((modem->reg[MREG_AUTOANSWER_COUNT] > 0) &&
|
||||||
|
(modem->reg[MREG_RING_COUNT] >= modem->reg[MREG_AUTOANSWER_COUNT])) {
|
||||||
|
modem_accept_incoming_call(modem);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modem_send_res(modem, ResRING);
|
||||||
|
serial_set_ri(modem->serial, !serial_get_ri(modem->serial));
|
||||||
|
|
||||||
|
modem->ringtimer = 3000;
|
||||||
|
}
|
||||||
|
--modem->ringtimer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modem->in_warmup) {
|
||||||
|
modem->in_warmup--;
|
||||||
|
if (modem->in_warmup == 0) {
|
||||||
|
modem->tx_count = 0;
|
||||||
|
fifo8_reset(&modem->rx_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (modem->connected && modem->tcpIpMode) {
|
||||||
|
if (modem->tx_count) {
|
||||||
|
int wouldblock = 0;
|
||||||
|
int res = plat_netsocket_send(modem->clientsocket, modem->tx_pkt_ser_line, modem->tx_count, &wouldblock);
|
||||||
|
|
||||||
|
if (res <= 0 && !wouldblock) {
|
||||||
|
/* No bytes sent or error. */
|
||||||
|
modem->tx_count = 0;
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
} else if (res > 0) {
|
||||||
|
if (res == modem->tx_count) {
|
||||||
|
modem->tx_count = 0;
|
||||||
|
} else {
|
||||||
|
memmove(modem->tx_pkt_ser_line, &modem->tx_pkt_ser_line[res], modem->tx_count - res);
|
||||||
|
modem->tx_count -= res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modem->connected) {
|
||||||
|
uint8_t buffer[16];
|
||||||
|
int wouldblock = 0;
|
||||||
|
int res = plat_netsocket_receive(modem->clientsocket, buffer, sizeof(buffer), &wouldblock);
|
||||||
|
|
||||||
|
if (res > 0) {
|
||||||
|
if (modem->telnet_mode)
|
||||||
|
modem_process_telnet(modem, buffer, res);
|
||||||
|
else
|
||||||
|
fifo8_push_all(&modem->rx_data, buffer, res);
|
||||||
|
} else if (res == 0) {
|
||||||
|
modem->tx_count = 0;
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
} else if (!wouldblock) {
|
||||||
|
modem->tx_count = 0;
|
||||||
|
modem_enter_idle_state(modem);
|
||||||
|
modem_send_res(modem, ResNOCARRIER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modem->cmdpause++;
|
||||||
|
guard_threashold = (uint32_t)(modem->reg[MREG_GUARD_TIME] * 20);
|
||||||
|
if (modem->cmdpause > guard_threashold) {
|
||||||
|
if (modem->plusinc == 0) {
|
||||||
|
modem->plusinc = 1;
|
||||||
|
} else if (modem->plusinc == 4) {
|
||||||
|
modem->mode = MODEM_MODE_COMMAND;
|
||||||
|
modem_send_res(modem, ResOK);
|
||||||
|
modem->plusinc = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -938,11 +1300,16 @@ static void *
|
|||||||
modem_init(const device_t *info)
|
modem_init(const device_t *info)
|
||||||
{
|
{
|
||||||
modem_t* modem = (modem_t*)calloc(1, sizeof(modem_t));
|
modem_t* modem = (modem_t*)calloc(1, sizeof(modem_t));
|
||||||
|
const char* phonebook_file = NULL;
|
||||||
memset(modem->mac, 0xfc, 6);
|
memset(modem->mac, 0xfc, 6);
|
||||||
|
|
||||||
|
|
||||||
modem->port = device_get_config_int("port");
|
modem->port = device_get_config_int("port");
|
||||||
modem->baudrate = device_get_config_int("baudrate");
|
modem->baudrate = device_get_config_int("baudrate");
|
||||||
|
modem->listen_port = device_get_config_int("listen_port");
|
||||||
|
modem->telnet_mode = device_get_config_int("telnet_mode");
|
||||||
|
|
||||||
|
modem->clientsocket = modem->serversocket = modem->waitingclientsocket = -1;
|
||||||
|
|
||||||
fifo8_create(&modem->data_pending, 0x10000);
|
fifo8_create(&modem->data_pending, 0x10000);
|
||||||
fifo8_create(&modem->rx_data, 0x10000);
|
fifo8_create(&modem->rx_data, 0x10000);
|
||||||
@@ -955,12 +1322,20 @@ modem_init(const device_t *info)
|
|||||||
|
|
||||||
modem_reset(modem);
|
modem_reset(modem);
|
||||||
modem->card = network_attach(modem, modem->mac, modem_rx, NULL);
|
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;
|
return modem;
|
||||||
}
|
}
|
||||||
|
|
||||||
void modem_close(void *priv)
|
void modem_close(void *priv)
|
||||||
{
|
{
|
||||||
modem_t* modem = (modem_t*)priv;
|
modem_t* modem = (modem_t*)priv;
|
||||||
|
modem->listen_port = 0;
|
||||||
|
modem_reset(modem);
|
||||||
fifo8_destroy(&modem->data_pending);
|
fifo8_destroy(&modem->data_pending);
|
||||||
fifo8_destroy(&modem->rx_data);
|
fifo8_destroy(&modem->rx_data);
|
||||||
netcard_close(modem->card);
|
netcard_close(modem->card);
|
||||||
@@ -1009,6 +1384,31 @@ static const device_config_t modem_config[] = {
|
|||||||
{ .description = "300", .value = 300 },
|
{ .description = "300", .value = 300 },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "listen_port",
|
||||||
|
.description = "TCP/IP listening port",
|
||||||
|
.type = CONFIG_SPINNER,
|
||||||
|
.spinner =
|
||||||
|
{
|
||||||
|
.min = 0,
|
||||||
|
.max = 32767
|
||||||
|
},
|
||||||
|
.default_int = 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "phonebook_file",
|
||||||
|
.description = "Phonebook File",
|
||||||
|
.type = CONFIG_FNAME,
|
||||||
|
.default_string = "",
|
||||||
|
.file_filter = "Text files (*.txt)|*.txt"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "telnet_mode",
|
||||||
|
.description = "Telnet emulation",
|
||||||
|
.type = CONFIG_BINARY,
|
||||||
|
.default_string = "",
|
||||||
|
.default_int = 0
|
||||||
|
},
|
||||||
{ .name = "", .description = "", .type = CONFIG_END }
|
{ .name = "", .description = "", .type = CONFIG_END }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -223,7 +223,7 @@ endif()
|
|||||||
if(WIN32)
|
if(WIN32)
|
||||||
target_sources(plat PRIVATE ../win/win_serial_passthrough.c ../win/win_netsocket.c)
|
target_sources(plat PRIVATE ../win/win_serial_passthrough.c ../win/win_netsocket.c)
|
||||||
else()
|
else()
|
||||||
target_sources(plat PRIVATE ../unix/unix_serial_passthrough.c)
|
target_sources(plat PRIVATE ../unix/unix_serial_passthrough.c ../unix/unix_netsocket.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
# Copyright 2021-2022 Jasmine Iwanek.
|
# Copyright 2021-2022 Jasmine Iwanek.
|
||||||
#
|
#
|
||||||
|
|
||||||
add_library(plat OBJECT unix.c unix_serial_passthrough.c)
|
add_library(plat OBJECT unix.c unix_serial_passthrough.c unix_netsocket.c)
|
||||||
|
|
||||||
if (NOT CPPTHREADS)
|
if (NOT CPPTHREADS)
|
||||||
target_sources(plat PRIVATE unix_thread.c)
|
target_sources(plat PRIVATE unix_thread.c)
|
||||||
|
196
src/unix/unix_netsocket.c
Normal file
196
src/unix/unix_netsocket.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#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/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
SOCKET plat_netsocket_create(int type)
|
||||||
|
{
|
||||||
|
SOCKET fd = -1;
|
||||||
|
int 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;
|
||||||
|
int 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;
|
||||||
|
socklen_t 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 || error == EWOULDBLOCK || error == EAGAIN || error == EINPROGRESS)
|
||||||
|
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;
|
||||||
|
}
|
@@ -17,6 +17,7 @@
|
|||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <ws2tcpip.h>
|
#include <ws2tcpip.h>
|
||||||
|
#include <winerror.h>
|
||||||
|
|
||||||
SOCKET plat_netsocket_create(int type)
|
SOCKET plat_netsocket_create(int type)
|
||||||
{
|
{
|
||||||
@@ -38,9 +39,15 @@ SOCKET plat_netsocket_create(int type)
|
|||||||
SOCKET plat_netsocket_create_server(int type, unsigned short port)
|
SOCKET plat_netsocket_create_server(int type, unsigned short port)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sock_addr;
|
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)
|
if (socket == INVALID_SOCKET)
|
||||||
return (SOCKET)-1;
|
return -1;
|
||||||
|
|
||||||
memset(&sock_addr, 0, sizeof(struct sockaddr_in));
|
memset(&sock_addr, 0, sizeof(struct sockaddr_in));
|
||||||
|
|
||||||
@@ -58,6 +65,8 @@ SOCKET plat_netsocket_create_server(int type, unsigned short port)
|
|||||||
return (SOCKET)-1;
|
return (SOCKET)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ioctlsocket(socket, FIONBIO, &yes);
|
||||||
|
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,13 +88,46 @@ SOCKET plat_netsocket_accept(SOCKET socket)
|
|||||||
int plat_netsocket_connected(SOCKET socket)
|
int plat_netsocket_connected(SOCKET socket)
|
||||||
{
|
{
|
||||||
struct sockaddr addr;
|
struct sockaddr addr;
|
||||||
socklen_t len = sizeof(struct sockaddr);
|
socklen_t len = sizeof(struct sockaddr);
|
||||||
|
fd_set wrfds, exfds;
|
||||||
|
struct timeval tv;
|
||||||
|
int res = SOCKET_ERROR;
|
||||||
|
int status = 0;
|
||||||
|
int optlen = 4;
|
||||||
|
|
||||||
|
FD_ZERO(&wrfds);
|
||||||
|
FD_ZERO(&exfds);
|
||||||
|
FD_SET(socket, &wrfds);
|
||||||
|
FD_SET(socket, &exfds);
|
||||||
|
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
res = select(socket + 1, NULL, &wrfds, &exfds, &tv);
|
||||||
|
|
||||||
|
if (res == SOCKET_ERROR)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (res >= 1 && FD_ISSET(socket, &exfds)) {
|
||||||
|
res = getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&status, &optlen);
|
||||||
|
pclog("Socket error %d\n", status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (getpeername(socket, &addr, &len) == SOCKET_ERROR)
|
if (res == 0 || !(res >= 1 && FD_ISSET(socket, &wrfds)))
|
||||||
return 0;
|
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 -1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +140,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_addr.s_addr = inet_addr(hostname);
|
||||||
sock_addr.sin_port = htons(port);
|
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;
|
struct hostent *hp;
|
||||||
|
|
||||||
hp = gethostbyname(hostname);
|
hp = gethostbyname(hostname);
|
||||||
@@ -114,7 +156,7 @@ int plat_netsocket_connect(SOCKET socket, const char* hostname, unsigned short p
|
|||||||
if (res == SOCKET_ERROR) {
|
if (res == SOCKET_ERROR) {
|
||||||
int error = WSAGetLastError();
|
int error = WSAGetLastError();
|
||||||
|
|
||||||
if (error == WSAEISCONN)
|
if (error == WSAEISCONN || error == WSAEWOULDBLOCK)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
res = -1;
|
res = -1;
|
||||||
|
Reference in New Issue
Block a user