H316: Rewrote h316_udp to use TMXR lines for UDP transport of data. Changed h316_mi to leverage built-in loopback mode in TMXR.

This gives UDP transport on all simh host platforms.
This commit is contained in:
Mark Pizzolato 2013-11-26 13:30:11 -08:00
parent 378e3e03a3
commit c9f73eac90
6 changed files with 126 additions and 313 deletions

View file

@ -192,7 +192,7 @@ extern t_stat mi_tx_service (uint32 quantum);
t_stat udp_create (DEVICE *pdtr, char *premote, int32 *plink);
t_stat udp_release (DEVICE *dptr, int32 link);
t_stat udp_send (DEVICE *pdtr, int32 link, uint16 *pdata, uint16 count);
t_stat udp_send_self (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count);
t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback);
int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbufg);
#endif // #ifndef _H316_IMP_H_

View file

@ -319,6 +319,7 @@ MIDB *const mi_midbs [MI_NUM] = {&mi1_db, &mi2_db, &mi3_db, &mi4_db,
void mi_reset_rx (uint16 line)
{
PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE;
udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE);
PMIDB(line)->rxerror = PMIDB(line)->rxpending = FALSE;
PMIDB(line)->rxtotal = 0;
CLR_RX_IRQ(line); CLR_RX_IEN(line);
@ -328,6 +329,7 @@ void mi_reset_rx (uint16 line)
void mi_reset_tx (uint16 line)
{
PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE;
udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE);
PMIDB(line)->txtotal = PMIDB(line)->txdelay = 0;
CLR_TX_IRQ(line); CLR_TX_IEN(line);
}
@ -424,9 +426,6 @@ void mi_start_tx (uint16 line)
if (PMIDB(line)->iloop) {
mi_rx_local(line, next, count);
} else if (PMIDB(line)->link != NOLINK) {
if (PMIDB(line)->lloop)
ret = udp_send_self(PDEVICE(line), PMIDB(line)->link, &M[next], count);
else
ret = udp_send(PDEVICE(line), PMIDB(line)->link, &M[next], count);
if (ret != SCPE_OK) mi_link_error(line);
}
@ -581,15 +580,21 @@ int32 mi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev)
case 001:
// MnUNXP - un-cross patch modem ...
sim_debug(IMP_DBG_IOT,PDEVICE(line),"un-cross patch modem (PC=%06o)\n", PC-1);
PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; return dat;
PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE;
udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE);
return dat;
case 002:
// MnLXP - enable line cross patch ...
sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable line cross patch (PC=%06o)\n", PC-1);
PMIDB(line)->lloop = TRUE; PMIDB(line)->iloop = FALSE; return dat;
PMIDB(line)->lloop = TRUE;
udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, TRUE);
PMIDB(line)->iloop = FALSE; return dat;
case 003:
// MnIXP - enable interface cross patch ...
sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable interface cross patch (PC=%06o)\n", PC-1);
PMIDB(line)->iloop = TRUE; PMIDB(line)->lloop = FALSE; return dat;
PMIDB(line)->iloop = TRUE; PMIDB(line)->lloop = FALSE;
udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE);
return dat;
case 004:
// MnIN - start modem input ...
mi_debug_mio(line, PDIB(line)->rxdmc, "input");

View file

@ -29,7 +29,8 @@
udp socket routines
26-Jun-13 RLA Rewritten from TCP version
26-Nov-13 MP Rewritten to use TMXR layer packet semantics thus
allowing portability to all simh hosts.
OVERVIEW
@ -134,15 +135,7 @@
*/
#ifdef VM_IMPTIP
#include "sim_defs.h" // simh machine independent definitions
#ifdef _WIN32 // WINSOCK definitions
#include <winsock2.h> // at least Windows puts it all in one file!
#elif defined(__linux__) // Linux definitions
#include <sys/socket.h> // struct socketaddr_in, et al
#include <netinet/in.h> // INADDR_NONE, et al
#include <netdb.h> // gethostbyname()
#include <fcntl.h> // fcntl() (what else??)
#include <unistd.h> // getpid(), more?
#endif
#include "sim_tmxr.h" // The MUX layer exposes packet send and receive semantics
#include "h316_defs.h" // H316 emulator definitions
#include "h316_imp.h" // ARPAnet IMP/TIP definitions
@ -158,30 +151,15 @@
// the fragments arrive intact then the destination should reassemble them.
#define MAXDATA 16384 // longest possible IMP packet (in H316 words)
// Compatibility hacks for WINSOCK vs Linux ...
#ifdef __linux__
#define WSAGetLastError() errno
#define closesocket close
#define SOCKET int32
#define SOCKADDR struct sockaddr
#define WSAEWOULDBLOCK EWOULDBLOCK
#define INVALID_SOCKET ((SOCKET) (-1))
#define SOCKET_ERROR (-1)
#endif
// UDP connection data structure ...
// One of these blocks is allocated for every simulated modem link.
struct _UDP_LINK {
t_bool used; // TRUE if this UDP_LINK is in use
uint32 ipremote; // IP address of the remote system
uint16 rxport; // OUR receiving port number
uint16 txport; // HIS receiving port number (on ipremote)
struct sockaddr_in rxaddr; // OUR receiving address (goes with rxsock!)
struct sockaddr_in txaddr; // HIS transmitting address (pairs with txsock!)
SOCKET rxsock; // socket for receiving incoming packets
SOCKET txsock; // socket for sending outgoing packets
char rhostport[64]; // Remote host:port
char lport[64]; // Local port
uint32 rxsequence; // next message sequence number for receive
uint32 txsequence; // next message sequence number for transmit
DEVICE *dptr; // Device associated with link
};
typedef struct _UDP_LINK UDP_LINK;
@ -206,44 +184,9 @@ typedef struct _UDP_PACKET UDP_PACKET;
#define UDP_HEADER_LEN (2*sizeof(uint32) + sizeof(uint16))
// Locals ...
t_bool udp_wsa_started = FALSE; // TRUE if WSAStartup() has been called
UDP_LINK udp_links[MAXLINKS] = {0}; // data for every active connection
t_stat udp_startup (DEVICE *dptr)
{
// WINSOCK requires that WSAStartup be called exactly once before any other
// network calls are made. That's a bit inconvenient, but this routine deals
// with it by using a static variable to call WSAStartup the first time thru
// and then never again.
#ifdef _WIN32
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsaData; int32 ret;
if (!udp_wsa_started) {
ret = WSAStartup (wVersionRequested, &wsaData);
if (ret != 0) {
fprintf(stderr,"UDP - WINSOCK startup error %d\n", ret);
return SCPE_IERR;
} else
sim_debug(IMP_DBG_UDP, dptr, "WSAStartup() called\n");
udp_wsa_started = TRUE;
}
#endif
return SCPE_OK;
}
t_stat udp_shutdown (DEVICE *dptr)
{
// This routine calls WSACleanup() after the last socket has been closed.
// It's essentially the opposite of udp_startup() ...
#ifdef _WIN32
if (udp_wsa_started) {
WSACleanup(); udp_wsa_started = FALSE;
sim_debug(IMP_DBG_UDP, dptr, "WSACleanup() called\n");
}
#endif
return SCPE_OK;
}
TMLN udp_lines[MAXLINKS] = { 0 }; // line descriptors
TMXR udp_tmxr = { MAXLINKS, NULL, 0, udp_lines};// datagram mux
int32 udp_find_free_link (void)
{
@ -253,91 +196,12 @@ int32 udp_find_free_link (void)
for (i = 0; i < MAXLINKS; ++i) {
if (udp_links[i].used == 0) {
memset(&udp_links[i], 0, sizeof(UDP_LINK));
// Just in case these values aren't zero!
udp_links[i].rxsock = udp_links[i].txsock = INVALID_SOCKET;
return i;
}
}
return NOLINK;
}
char *udp_format_remote (int32 link)
{
// Format the remote address and port in the format "w.x.y.z:pppp" . It's
// a bit ugly (OK, it's a lot ugly!) but it's just for error messages...
static char buf[64];
sprintf(buf, "%d.%d.%d.%d:%d",
(udp_links[link].ipremote >> 24) & 0xFF,
(udp_links[link].ipremote >> 16) & 0xFF,
(udp_links[link].ipremote >> 8) & 0xFF,
udp_links[link].ipremote & 0xFF,
udp_links[link].txport);
return buf;
}
/* get_ipaddr IP address:port
Inputs:
cptr = pointer to input string
Outputs:
ipa = pointer to IP address (may be NULL), 0 = none
ipp = pointer to IP port (may be NULL), 0 = none
result = status
*/
static t_stat get_ipaddr (char *cptr, uint32 *ipa, uint32 *ipp)
{
char gbuf[CBUFSIZE];
char *addrp, *portp, *octetp;
uint32 i, addr, port, octet;
t_stat r;
if ((cptr == NULL) || (*cptr == 0))
return SCPE_ARG;
strncpy (gbuf, cptr, CBUFSIZE);
addrp = gbuf; /* default addr */
if ((portp = strchr (gbuf, ':'))) /* x:y? split */
*portp++ = 0;
else if (strchr (gbuf, '.')) /* x.y...? */
portp = NULL;
else {
portp = gbuf; /* port only */
addrp = NULL; /* no addr */
}
if (portp) { /* port string? */
if (ipp == NULL) /* not wanted? */
return SCPE_ARG;
port = (int32) get_uint (portp, 10, 65535, &r);
if ((r != SCPE_OK) || (port == 0))
return SCPE_ARG;
}
else port = 0;
if (addrp) { /* addr string? */
if (ipa == NULL) /* not wanted? */
return SCPE_ARG;
for (i = addr = 0; i < 4; i++) { /* four octets */
octetp = strchr (addrp, '.'); /* find octet end */
if (octetp != NULL) /* split string */
*octetp++ = 0;
else if (i < 3) /* except last */
return SCPE_ARG;
octet = (int32) get_uint (addrp, 10, 255, &r);
if (r != SCPE_OK)
return SCPE_ARG;
addr = (addr << 8) | octet;
addrp = octetp;
}
if (((addr & 0377) == 0) || ((addr & 0377) == 255))
return SCPE_ARG;
}
else addr = 0;
if (ipp) /* return req values */
*ipp = port;
if (ipa)
*ipa = addr;
return SCPE_OK;
}
t_stat udp_parse_remote (int32 link, char *premote)
{
// This routine will parse a remote address string in any of these forms -
@ -356,102 +220,46 @@ t_stat udp_parse_remote (int32 link, char *premote)
// yourself!! In both cases, "w.x.y.z" is a dotted IP for the remote machine
// and "name.domain.com" is its name (which will be looked up to get the IP).
// If the host name/IP is omitted then it defaults to "localhost".
char *end, *colon; int32 port; struct hostent *he;
char *end; int32 lport, rport; t_stat ret;
char host[64], port[16];
if (*premote == '\0') return SCPE_2FARG;
// Look for the local port number. If it's not there, set rxport to zero for now.
port = strtoul(premote, &end, 10); udp_links[link].rxport = 0;
if ((*end == ':') && (port > 0)) {
udp_links[link].rxport = port; premote = end+1;
memset (udp_links[link].lport, 0, sizeof(udp_links[link].lport));
memset (udp_links[link].rhostport, 0, sizeof(udp_links[link].rhostport));
// Handle the llll::rrrr case first
if (2 == sscanf (premote, "%d::%d", &lport, &rport)) {
if ((lport < 1) || (lport >65535) || (rport < 1) || (rport >65535)) return SCPE_ARG;
sprintf (udp_links[link].lport, "%d", lport);
sprintf (udp_links[link].rhostport, "localhost:%d", rport);
return SCPE_OK;
}
// Look for "name:port" and extract the remote port...
if ((colon = strchr(premote, ':')) == NULL) return SCPE_ARG;
*colon++ = '\0'; port = strtoul(colon, &end, 10);
if ((*end != '\0') || (port == 0)) return SCPE_ARG;
udp_links[link].txport = port;
if (udp_links[link].rxport == 0) udp_links[link].rxport = port;
// Look for the local port number and save it away.
lport = strtoul(premote, &end, 10);
if ((*end == ':') && (lport > 0)) {
sprintf (udp_links[link].lport, "%d", lport);
premote = end+1;
}
// Now try to parse the host as a dotted IP address ...
if (get_ipaddr(premote, &udp_links[link].ipremote, NULL) == SCPE_OK) return SCPE_OK;
ret = sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL);
if (ret != SCPE_OK) return SCPE_ARG;
sprintf (udp_links[link].rhostport, "%s:%s", host, port);
if (udp_links[link].lport[0] == '\0')
strcpy (udp_links[link].lport, port);
// Special kludge - allow just ":port" to mean "localhost:port" ...
if(*premote == '\0') {
if (udp_links[link].rxport == udp_links[link].txport)
if ((strcmp (udp_links[link].lport, port) == 0) &&
(strcmp ("localhost", host) == 0))
fprintf(stderr,"WARNING - use different transmit and receive ports!\n");
premote = "localhost";
}
// Not a dotted IP - try to lookup a host name ...
if ((he = gethostbyname(premote)) == NULL) return SCPE_OPENERR;
udp_links[link].ipremote = * (unsigned long *) he->h_addr_list[0];
if (udp_links[link].ipremote == INADDR_NONE) {
fprintf(stderr,"WARNING - unable to resolve \"%s\"\n", premote);
return SCPE_OPENERR;
}
udp_links[link].ipremote = ntohl(udp_links[link].ipremote);
return SCPE_OK;
}
t_stat udp_socket_error (int32 link, const char *msg)
t_stat udp_error (int32 link, const char *msg)
{
// This routine is called whenever a SOCKET_ERROR is returned for any I/O.
fprintf(stderr,"UDP%d - %s failed with error %d\n", link, msg, WSAGetLastError());
return SCPE_IOERR;
}
t_stat udp_create_rx_socket (int32 link)
{
// This routine will create the receiver socket for the virtual modem.
// Sockets are always UDP and, in the case of the receiver, bound to the port
// specified. Receiving sockets are also always set to NON BLOCKING mode.
int32 iret; uint32 flags = 1;
// Creating the socket works on both Windows and Linux ...
udp_links[link].rxsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_links[link].rxsock == INVALID_SOCKET)
return udp_socket_error(link, "RX socket()");
udp_links[link].rxaddr.sin_family = AF_INET;
udp_links[link].rxaddr.sin_port = htons(udp_links[link].rxport);
udp_links[link].rxaddr.sin_addr.s_addr = htonl(INADDR_ANY);
iret = bind(udp_links[link].rxsock, (SOCKADDR *) &udp_links[link].rxaddr, sizeof(struct sockaddr_in));
if (iret != 0)
return udp_socket_error(link, "bind()");
// But making it non-blocking is a problem ...
#ifdef _WIN32
iret = ioctlsocket(udp_links[link].rxsock, FIONBIO, (u_long *) &flags);
if (iret != 0)
return udp_socket_error(link, "ioctlsocket()");
#elif defined(__linux__)
flags = fcntl(udp_links[link].rxsock, F_GETFL, 0);
if (flags == -1) return udp_socket_error(link, "fcntl(F_GETFL)");
iret = fcntl(udp_links[link].rxsock, F_SETFL, flags | O_NONBLOCK);
if (iret == -1) return udp_socket_error(link, "fcntl(F_SETFL)");
iret = fcntl(udp_links[link].rxsock, F_SETOWN, getpid());
if (iret == -1) return udp_socket_error(link, "fcntl(F_SETOWN)");
#endif
return SCPE_OK;
}
t_stat udp_create_tx_socket (int32 link)
{
// This routine will create the transmitter socket for the virtual modem.
// In the case of the transmitter, we don't bind the socket at this time -
// WINSOCK will automatically bind it for us to a free port on the first IO.
// Also note that transmitting sockets are blocking; we don't have code (yet!)
// to allow them to be nonblocking.
udp_links[link].txsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (udp_links[link].txsock == INVALID_SOCKET)
return udp_socket_error(link, "TX socket()");
// Initialize the txaddr structure too - note that this isn't used now; it's
// the sockaddr we will use when we later do a sendto() the remote host!
udp_links[link].txaddr.sin_family = AF_INET;
udp_links[link].txaddr.sin_port = htons(udp_links[link].txport);
udp_links[link].txaddr.sin_addr.s_addr = htonl(udp_links[link].ipremote);
return SCPE_OK;
}
t_stat udp_create (DEVICE *dptr, char *premote, int32 *pln)
{
// Create a logical UDP link to the specified remote system. The "remote"
@ -467,22 +275,26 @@ t_stat udp_create (DEVICE *dptr, char *premote, int32 *pln)
// which is a handle used to identify this connection to all future udp_xyz()
// calls.
t_stat ret;
char linkinfo[128];
int32 link = udp_find_free_link();
if (link < 0) return SCPE_MEM;
// Make sure WINSOCK is initialized ...
if ((ret = udp_startup(dptr)) != SCPE_OK) return ret;
// Parse the remote name and set up the ipaddr and port ...
if ((ret = udp_parse_remote(link, premote)) != SCPE_OK) return ret;
// Create the sockets for the transmitter and receiver ...
if ((ret = udp_create_rx_socket(link)) != SCPE_OK) return ret;
if ((ret = udp_create_tx_socket(link)) != SCPE_OK) return ret;
// Create the socket connection to the destination ...
sprintf(linkinfo, "Line=%d,%s,UDP,Connect=%s", link, udp_links[link].lport, udp_links[link].rhostport);
ret = tmxr_open_master (&udp_tmxr, linkinfo);
if (ret != SCPE_OK) return ret;
// All done - mark the TCP_LINK data as "used" and return the index.
udp_links[link].used = TRUE; *pln = link;
sim_debug(IMP_DBG_UDP, dptr, "link %d - listening on port %d and sending to %s\n", link, udp_links[link].rxport, udp_format_remote(link));
udp_lines[link].dptr = udp_links[link].dptr = dptr; // save device
udp_tmxr.uptr = dptr->units;
udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects
tmxr_poll_conn (&udp_tmxr); // force connection initialization now
udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects
sim_debug(IMP_DBG_UDP, dptr, "link %d - listening on port %s and sending to %s\n", link, udp_links[link].lport, udp_links[link].rhostport);
return SCPE_OK;
}
@ -491,26 +303,18 @@ t_stat udp_release (DEVICE *dptr, int32 link)
// Close a link that was created by udp_create() and release any resources
// allocated to it. We always return SCPE_OK unless the link specified is
// already unused.
int32 iret, i;
if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR;
if (!udp_links[link].used) return SCPE_IERR;
if (dptr != udp_links[link].dptr) return SCPE_IERR;
// Close the sockets associated with this connection - that's easy ...
iret = closesocket(udp_links[link].rxsock);
if (iret != 0) udp_socket_error(link, "closesocket()");
iret = closesocket(udp_links[link].txsock);
if (iret != 0) udp_socket_error(link, "closesocket()");
tmxr_detach_ln (&udp_lines[link]);
udp_links[link].used = FALSE;
sim_debug(IMP_DBG_UDP, dptr, "link %d - closed\n", link);
// If we just closed the last link, then call udp_shutdown() ...
for (i = 0; i < MAXLINKS; ++i) {
if (udp_links[i].used) return SCPE_OK;
}
return udp_shutdown(dptr);
return SCPE_OK;
}
t_stat udp_send_to (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count, SOCKADDR *pdest)
t_stat udp_send (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count)
{
// This routine does all the work of sending an IMP data packet. pdata
// is a pointer (usually into H316 simulated memory) to the IMP packet data,
@ -520,10 +324,11 @@ t_stat udp_send_to (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count, SOCKA
// doesn't necessarily need to have the same endian-ness as this machine.
// Second, notice that transmitting sockets are NOT set to non blocking so
// this routine might wait, but we assume the wait will never be too long.
UDP_PACKET pkt; int pktlen; uint16 i; int32 iret;
UDP_PACKET pkt; int pktlen; uint16 i; t_stat iret;
if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR;
if (!udp_links[link].used) return SCPE_IERR;
if ((pdata == NULL) || (count == 0) || (count > MAXDATA)) return SCPE_IERR;
if (dptr != udp_links[link].dptr) return SCPE_IERR;
// Build the UDP packet, filling in our own header information and copying
// the H316 words from memory. REMEMBER THAT EVERYTHING IS IN NETWORK ORDER!
@ -534,28 +339,19 @@ t_stat udp_send_to (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count, SOCKA
pktlen = UDP_HEADER_LEN + count*sizeof(uint16);
// Send it and we're outta here ...
iret = sendto(udp_links[link].txsock, (const char *) &pkt, pktlen, 0, pdest, sizeof (struct sockaddr_in));
if (iret == SOCKET_ERROR) return udp_socket_error(link, "sendto()");
iret = tmxr_put_packet_ln (&udp_lines[link], (const uint8 *)&pkt, (size_t)pktlen);
if (iret != SCPE_OK) return udp_error(link, "tmxr_put_packet_ln()");
sim_debug(IMP_DBG_UDP, dptr, "link %d - packet sent (sequence=%d, length=%d)\n", link, ntohl(pkt.sequence), ntohs(pkt.count));
return SCPE_OK;
}
t_stat udp_send (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count)
t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback)
{
// Send an IMP packet to the remote simh. This is the usual case - the only
// reason there's any other options at all is so we can emulate loopback.
return udp_send_to (dptr, link, pdata, count, (SOCKADDR *) &(udp_links[link].txaddr));
}
if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR;
if (!udp_links[link].used) return SCPE_IERR;
if (dptr != udp_links[link].dptr) return SCPE_IERR;
t_stat udp_send_self (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count)
{
// Send an IMP packet to our own receiving socket. This might seem silly,
// but it's used to emulate the line loopback function...
struct sockaddr_in self;
self.sin_family = AF_INET;
self.sin_port = htons(udp_links[link].rxport);
self.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
return udp_send_to (dptr, link, pdata, count, (SOCKADDR *) &self);
return tmxr_set_line_loopback (&udp_lines[link], enable_loopback);
}
int32 udp_receive_packet (int32 link, UDP_PACKET *ppkt)
@ -568,27 +364,22 @@ int32 udp_receive_packet (int32 link, UDP_PACKET *ppkt)
// Note that this routine only receives the packet - it doesn't handle any
// of the checking for valid packets, unexpected packets, duplicate or out of
// sequence packets. That's strictly the caller's problem!
int32 pktsiz;
struct sockaddr_in sender;
#if defined (macintosh) || defined (__linux) || defined (__linux__) || \
defined (__APPLE__) || defined (__OpenBSD__) || \
defined(__NetBSD__) || defined(__FreeBSD__) || \
(defined(__hpux) && defined(_XOPEN_SOURCE_EXTENDED))
socklen_t sndsiz = (socklen_t)sizeof(sender);
#elif defined (_WIN32) || defined (__EMX__) || \
(defined (__ALPHA) && defined (__unix__)) || \
defined (__hpux)
int sndsiz = (int)sizeof(sender);
#else
size_t sndsiz = sizeof(sender);
#endif
size_t pktsiz;
uint8 *pbuf;
t_stat ret;
pktsiz = recvfrom(udp_links[link].rxsock, (char *) ppkt, sizeof(UDP_PACKET),
0, (SOCKADDR *) &sender, &sndsiz);
if (pktsiz >= 0) return pktsiz;
if (WSAGetLastError() == WSAEWOULDBLOCK) return 0;
udp_socket_error(link, "recvfrom()");
udp_lines[link].rcve = TRUE; // Enable receiver
tmxr_poll_rx (&udp_tmxr);
ret = tmxr_get_packet_ln (&udp_lines[link], &pbuf, &pktsiz);
udp_lines[link].rcve = FALSE; // Disable receiver
if (ret != SCPE_OK) {
udp_error(link, "tmxr_get_packet_ln()");
return NOLINK;
}
if (pbuf == NULL) return 0;
// Got a packet, so copy it to the packet buffer
memcpy (ppkt, pbuf, pktsiz);
return pktsiz;
}
int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbuf)
@ -611,6 +402,7 @@ int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbuf)
UDP_PACKET pkt; int32 pktlen, explen, implen, i; uint32 magic, pktseq;
if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR;
if (!udp_links[link].used) return SCPE_IERR;
if (dptr != udp_links[link].dptr) return SCPE_IERR;
while ((pktlen = udp_receive_packet(link, &pkt)) > 0) {
// First do some header checks for a valid UDP packet ...

View file

@ -599,7 +599,7 @@ if (hostp != NULL) {
hostp[strlen(hostp)-1] = '\0';
}
}
if (host) /* host wanted? */
if (host) { /* host wanted? */
if (hostp != NULL) {
if (strlen(hostp) >= host_len)
return SCPE_ARG; /* no room */
@ -613,12 +613,14 @@ if (host) /* host wanted? */
strcpy (host, default_host);
}
else {
if (default_host)
if (default_host) {
if (strlen(default_host) >= host_len)
return SCPE_ARG; /* no room */
else
strcpy (host, default_host);
}
}
}
if (validate_addr) {
struct addrinfo *ai_host, *ai_validate, *ai;
t_stat status;

View file

@ -664,6 +664,9 @@ else { /* Telnet connection */
written = sim_write_sock (lp->sock, &(lp->txb[i]), length);
if (written == SOCKET_ERROR) /* did an error occur? */
if (lp->datagram)
return written; /* ignore errors on datagram sockets */
else
return -1; /* return error indication */
else
return written;
@ -1543,19 +1546,19 @@ return val;
NULL, but success (SCPE_OK) is returned
*/
t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize)
t_stat tmxr_get_packet_ln (TMLN *lp, uint8 **pbuf, size_t *psize)
{
return tmxr_get_packet_ln_ex (lp, pbuf, psize, 0);
}
t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte)
t_stat tmxr_get_packet_ln_ex (TMLN *lp, uint8 **pbuf, size_t *psize, uint8 frame_byte)
{
int32 c;
size_t pktsize;
size_t fc_size = (frame_byte ? 1 : 0);
while (TMXR_VALID & (c = tmxr_getc_ln (lp))) {
if (lp->rxpboffset + 1 > lp->rxpbsize) {
if (lp->rxpboffset + 3 > lp->rxpbsize) {
lp->rxpbsize += 512;
lp->rxpb = (uint8 *)realloc (lp->rxpb, lp->rxpbsize);
}
@ -1563,8 +1566,15 @@ while (TMXR_VALID & (c = tmxr_getc_ln (lp))) {
tmxr_debug (TMXR_DBG_PRCV, lp, "Received Unexpected Framing Byte", (char *)&lp->rxpb[lp->rxpboffset], 1);
continue;
}
lp->rxpb[lp->rxpboffset] = c & 0xFF;
lp->rxpboffset += 1;
if ((lp->datagram) && (lp->rxpboffset == fc_size)) {
/* Datagram packet length is provided as a part of the natural datagram
delivery, for TCP lines, we read the packet length from the data stream.
So, here we stuff packet size into head of packet buffer so it looks like
it was delivered by TCP and the below return logic doesn't have to worry */
lp->rxpb[lp->rxpboffset++] = (uint8)(((1 + lp->rxbpi - lp->rxbpr) >> 8) & 0xFF);
lp->rxpb[lp->rxpboffset++] = (uint8)((1 + lp->rxbpi - lp->rxbpr) & 0xFF);
}
lp->rxpb[lp->rxpboffset++] = c & 0xFF;
if (lp->rxpboffset >= (2 + fc_size)) {
pktsize = (lp->rxpb[0+fc_size] << 8) | lp->rxpb[1+fc_size];
if (pktsize == (lp->rxpboffset - 2)) {
@ -1612,10 +1622,12 @@ for (i = 0; i < mp->lines; i++) { /* loop thru lines */
lp->rxbsz - lp->rxbpi);
if (nbytes < 0) { /* line error? */
if (!lp->datagram) { /* ignore errors reading UDP sockets */
if (!lp->txbfd || lp->notelnet)
lp->txbpi = lp->txbpr = 0; /* Drop the data we already know we can't send */
tmxr_close_ln (lp); /* disconnect line */
}
}
else if (nbytes > 0) { /* if data rcvd */
@ -1816,6 +1828,7 @@ t_stat tmxr_put_packet_ln_ex (TMLN *lp, const uint8 *buf, size_t size, uint8 fra
{
t_stat r;
size_t fc_size = (frame_byte ? 1 : 0);
size_t pktlen_size = (lp->datagram ? 0 : 2);
if (!lp->conn)
return SCPE_LOST;
@ -1823,17 +1836,19 @@ if (lp->txppoffset < lp->txppsize) {
tmxr_debug (TMXR_DBG_PXMT, lp, "Skipped Sending Packet - Transmit Busy", (char *)&lp->txpb[3], size);
return SCPE_STALL;
}
if (lp->txpbsize < size + 2 + fc_size) {
lp->txpbsize = size + 2 + fc_size;
if (lp->txpbsize < size + pktlen_size + fc_size) {
lp->txpbsize = size + pktlen_size + fc_size;
lp->txpb = (uint8 *)realloc (lp->txpb, lp->txpbsize);
}
lp->txpb[0] = frame_byte;
lp->txpb[0+fc_size] = (size >> 8) & 0xFF;
lp->txpb[1+fc_size] = size & 0xFF;
memcpy (lp->txpb + 2 + fc_size, buf, size);
lp->txppsize = size + 2 + fc_size;
if (!lp->datagram) {
lp->txpb[0+fc_size] = (size >> 8) & 0xFF;
lp->txpb[1+fc_size] = size & 0xFF;
}
memcpy (lp->txpb + pktlen_size + fc_size, buf, size);
lp->txppsize = size + pktlen_size + fc_size;
lp->txppoffset = 0;
tmxr_debug (TMXR_DBG_PXMT, lp, "Sending Packet", (char *)&lp->txpb[2+fc_size], size);
tmxr_debug (TMXR_DBG_PXMT, lp, "Sending Packet", (char *)&lp->txpb[pktlen_size+fc_size], size);
++lp->txpcnt;
while ((lp->txppoffset < lp->txppsize) &&
(SCPE_OK == (r = tmxr_putc_ln (lp, lp->txpb[lp->txppoffset]))))
@ -1896,7 +1911,6 @@ if (nbytes) { /* >0? write */
sbytes = tmxr_write (lp, nbytes); /* write all data */
else
sbytes = tmxr_write (lp, lp->txbsz - lp->txbpr);/* write to end buf */
if (sbytes >= 0) { /* ok? */
tmxr_debug (TMXR_DBG_XMT, lp, "Sent", &(lp->txb[lp->txbpr]), sbytes);
lp->txbpr = (lp->txbpr + sbytes); /* update remove ptr */

View file

@ -185,8 +185,8 @@ int32 tmxr_poll_conn (TMXR *mp);
t_stat tmxr_reset_ln (TMLN *lp);
t_stat tmxr_detach_ln (TMLN *lp);
int32 tmxr_getc_ln (TMLN *lp);
t_stat tmxr_get_packet_ln (TMLN *lp, const uint8 **pbuf, size_t *psize);
t_stat tmxr_get_packet_ln_ex (TMLN *lp, const uint8 **pbuf, size_t *psize, uint8 frame_byte);
t_stat tmxr_get_packet_ln (TMLN *lp, uint8 **pbuf, size_t *psize);
t_stat tmxr_get_packet_ln_ex (TMLN *lp, uint8 **pbuf, size_t *psize, uint8 frame_byte);
void tmxr_poll_rx (TMXR *mp);
t_stat tmxr_putc_ln (TMLN *lp, int32 chr);
t_stat tmxr_put_packet_ln (TMLN *lp, const uint8 *buf, size_t size);