use Network framework for LocalTalk over TCP

This commit is contained in:
Jesús A. Álvarez 2024-03-29 20:33:18 +01:00
parent c2f2622cb5
commit 54f6496031
2 changed files with 58 additions and 177 deletions

View File

@ -20,21 +20,6 @@
#define TCP_dolog (dbglog_HAVE && 0)
#ifndef use_winsock
#define use_winsock 0
#endif
#if use_winsock
#define my_INVALID_SOCKET INVALID_SOCKET
#define my_SOCKET SOCKET
#define my_closesocket closesocket
#define socklen_t int
#else
#define my_INVALID_SOCKET (-1)
#define my_SOCKET int
#define my_closesocket close
#endif
#if TCP_dolog
LOCALPROC dbglog_writeSockErr(char *s)
{
@ -55,52 +40,46 @@ LOCALPROC dbglog_writeSockErr(char *s)
/*
Transmit buffer for localtalk data and its metadata
*/
LOCALVAR ui3b tx_buffer[6 + LT_TxBfMxSz] =
"LLpppp";
LOCALVAR ui3b tx_buffer[6 + LT_TxBfMxSz] = "LLpppp";
/*
Receive buffer for LocalTalk data and its metadata
*/
LOCALVAR unsigned int rx_buffer_allocation = 1800;
LOCALVAR my_SOCKET sock_fd = my_INVALID_SOCKET;
LOCALVAR blnr tcp_ok = falseblnr;
LOCALVAR nw_connection_t connection = nil;
LOCALVAR NSData *nextPacket;
#if use_winsock
LOCALVAR blnr have_winsock = falseblnr;
#endif
void welcome_next_packet(void)
{
// schedule receiving length
nw_connection_receive(connection, 2, 2, ^(dispatch_data_t _Nullable content, nw_content_context_t _Nullable context, bool is_complete, nw_error_t _Nullable error) {
uint8_t buf[2];
if (error != nil) {
NSLog(@"ERROR RECEIVING LENGTH: %@", error);
return;
}
[(NSData*)content getBytes:buf length:2];
uint16_t length = (buf[0] << 8) | buf[1];
// schedule receiving packet
nw_connection_receive(connection, (uint32_t)length, (uint32_t)length, ^(dispatch_data_t _Nullable content, nw_content_context_t _Nullable context, bool is_complete, nw_error_t _Nullable error) {
if (error != nil) {
NSLog(@"ERROR RECEIVING DATA: %@", error);
return;
}
nextPacket = (NSData*)content;
});
});
}
LOCALPROC start_tcp(void)
{
#if use_winsock
WSADATA wsaData;
#endif
struct sockaddr_in addr;
#if use_winsock
if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) {
#if TCP_dolog
dbglog_writeln("WSAStartup fails");
#endif
return;
}
have_winsock = trueblnr;
#endif
if (my_INVALID_SOCKET == (sock_fd =
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
#if TCP_dolog
dbglog_writeSockErr("socket");
#endif
return;
}
/* find server from LTOVRTCP_SERVER env, should be in the form 1.2.3.4:12345 */
char *server = NULL;
char buf[32];
short port = 0;
char *portStr = NULL;
if ((server = getenv("LTOVRTCP_SERVER")) && strlen(server) < sizeof(buf)) {
strcpy(buf, server);
char *separator = strchr(buf, ':');
@ -111,6 +90,7 @@ LOCALPROC start_tcp(void)
separator++;
if (strlen(separator) > 1) {
port = (short)atoi(separator);
portStr = separator;
}
}
@ -119,42 +99,17 @@ LOCALPROC start_tcp(void)
}
/* connect to server */
memset((char*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(buf);
addr.sin_port = htons(port);
#if ! use_winsock
errno = 0;
#endif
if (0 != connect(sock_fd, (struct sockaddr*)&addr, sizeof(addr))) {
#if TCP_dolog
dbglog_writeSockErr("connect");
#endif
MacMsg("Could not connect to LocalTalk server", strerror(errno), falseblnr);
return;
}
#if TCP_dolog
dbglog_writeln("tcp connected");
#endif
/* non-blocking I/O is good for the soul */
#if use_winsock
{
int iResult;
u_long iMode = 1;
iResult = ioctlsocket(sock_fd, FIONBIO, &iMode);
if (iResult != NO_ERROR) {
/*
printf("ioctlsocket failed with error: %ld\n", iResult);
*/
}
}
#else
fcntl(sock_fd, F_SETFL, O_NONBLOCK);
#endif
tcp_ok = trueblnr;
nw_endpoint_t endpoint = nw_endpoint_create_host(buf, portStr);
nw_parameters_t params = nw_parameters_create_secure_tcp(NW_PARAMETERS_DISABLE_PROTOCOL, ^(nw_protocol_options_t _Nonnull options) {
nw_tcp_options_set_no_delay(options, true);
});
connection = nw_connection_create(endpoint, params);
nw_connection_set_state_changed_handler(connection, ^(nw_connection_state_t state, nw_error_t _Nullable error) {
NSLog(@"connection state %@: %@", @[@"invalid", @"waiting", @"preparing", @"ready", @"failed", @"cancelled"][state], error);
});
nw_connection_set_queue(connection, dispatch_get_main_queue());
nw_connection_start(connection);
welcome_next_packet();
}
LOCALVAR unsigned char *MyRxBuffer = NULL;
@ -166,7 +121,6 @@ LOCALVAR unsigned char *MyRxBuffer = NULL;
LOCALFUNC blnr InitLocalTalk(void)
{
LT_PickStampNodeHint();
LT_TxBuffer = &tx_buffer[6];
MyRxBuffer = malloc(rx_buffer_allocation);
@ -183,23 +137,7 @@ LOCALFUNC blnr InitLocalTalk(void)
LOCALPROC UnInitLocalTalk(void)
{
if (my_INVALID_SOCKET != sock_fd) {
if (0 != my_closesocket(sock_fd)) {
#if TCP_dolog
dbglog_writeSockErr("my_closesocket sock_fd");
#endif
}
}
#if use_winsock
if (have_winsock) {
if (0 != WSACleanup()) {
#if TCP_dolog
dbglog_writeSockErr("WSACleanup");
#endif
}
}
#endif
nw_connection_cancel(connection);
if (NULL != MyRxBuffer) {
free(MyRxBuffer);
@ -238,25 +176,19 @@ LOCALPROC embedMyPID(void)
GLOBALOSGLUPROC LT_TransmitPacket(void)
{
size_t bytes;
/* Write the packet to TCP */
#if TCP_dolog
dbglog_writeln("writing to tcp");
#endif
embedPacketLength(LT_TxBuffSz + 4);
embedMyPID();
if (tcp_ok) {
bytes = send(sock_fd,
(const void *)tx_buffer, LT_TxBuffSz + 6, 0);
#if TCP_dolog
dbglog_writeCStr("sent ");
dbglog_writeNum(bytes);
dbglog_writeCStr(" bytes");
dbglog_writeReturn();
#endif
(void) bytes; /* avoid warning about unused */
}
char *buf = malloc(LT_TxBfMxSz + 6);
memcpy(buf, tx_buffer, LT_TxBfMxSz + 6);
dispatch_data_t data = dispatch_data_create(buf, LT_TxBuffSz + 6, dispatch_get_main_queue(), DISPATCH_DATA_DESTRUCTOR_FREE);
nw_connection_send(connection, data, NW_CONNECTION_DEFAULT_MESSAGE_CONTEXT, true, ^(nw_error_t _Nullable error) {
if (error) {
NSLog(@"nw_connection_send error %@", error);
}
});
}
/*
@ -305,68 +237,18 @@ LOCALFUNC int packetIsOneISent(void)
LOCALFUNC int GetNextPacket(void)
{
unsigned char* device_buffer = MyRxBuffer;
if (tcp_ok == falseblnr)
{
if (nextPacket == nil) {
return 0;
}
#if ! use_winsock
errno = 0;
#endif
/* peek length */
ssize_t bytes = recv(sock_fd, (void *)device_buffer, 2, MSG_PEEK);
if (bytes == 2)
{
int incoming_length = (device_buffer[0] << 8) + device_buffer[1];
bytes = recv(sock_fd, (void*)device_buffer, 2 + incoming_length, MSG_PEEK);
if (bytes == 2 + incoming_length)
{
/* read the packet */
bytes = recv(sock_fd, (void*)device_buffer, 2 + incoming_length, 0);
}
}
if (bytes < 0) {
#if use_winsock
if (WSAEWOULDBLOCK != WSAGetLastError())
#else
if (ECONNRESET == errno || ETIMEDOUT == errno)
{
MacMsg("Lost connection to LocalTalk server", strerror(errno), falseblnr);
#if TCP_dolog
dbglog_writeCStr("tcp error ");
dbglog_writeCStr(strerror(errno));
dbglog_writeReturn();
#endif
tcp_ok = falseblnr;
my_closesocket(sock_fd);
sock_fd = my_INVALID_SOCKET;
}
else if (EAGAIN != errno)
#endif
{
#if TCP_dolog
dbglog_writeCStr("ret");
dbglog_writeNum(bytes);
dbglog_writeCStr(", bufsize ");
dbglog_writeNum(rx_buffer_allocation);
#if ! use_winsock
dbglog_writeCStr(", errno = ");
dbglog_writeCStr(strerror(errno));
#endif
dbglog_writeReturn();
#endif
}
int bytes = (int)nextPacket.length;
if (bytes <= rx_buffer_allocation) {
[nextPacket getBytes:MyRxBuffer length:bytes];
} else {
#if TCP_dolog
dbglog_writeCStr("got ");
dbglog_writeNum(bytes);
dbglog_writeCStr(", bufsize ");
dbglog_writeNum(rx_buffer_allocation);
dbglog_writeReturn();
#endif
bytes = 0;
}
nextPacket = nil;
welcome_next_packet();
return bytes;
}
@ -392,12 +274,12 @@ label_retry:
{
#if TCP_dolog
dbglog_writeCStr("passing ");
dbglog_writeNum(bytes - 6);
dbglog_writeNum(bytes - 4);
dbglog_writeCStr(" bytes to receiver");
dbglog_writeReturn();
#endif
LT_RxBuffer = MyRxBuffer + 6;
LT_RxBuffSz = bytes - 6;
LT_RxBuffer = MyRxBuffer + 4;
LT_RxBuffSz = bytes - 4;
}
}
}

View File

@ -112,8 +112,7 @@ LOCALPROC dbglog_close0(void) {
#include "PBUFSTDC.h"
#if EmLocalTalk
#include <sys/socket.h>
#include <arpa/inet.h>
#import <Network/Network.h>
#include "LTOVRTCP.h"
#endif