commit cc79ed4ededf349557f703ab11e6a8d7be3b04d9 Author: Kelvin Sherlock Date: Thu Apr 12 00:51:12 2012 -0400 initial version (it even works) diff --git a/marignotti.c b/marignotti.c new file mode 100644 index 0000000..3a361d5 --- /dev/null +++ b/marignotti.c @@ -0,0 +1,648 @@ +/* + * MariGNOtti + * + */ + +#pragma optimize 79 + +#include +#include +#include +#include +#include + +#include +#include +#include + +//#include +#include +#include +#include +#include +#include +//#include + +#include "net.h" + +volatile int QuitFlag; +static Word MyID; +int semID; + + +// this will be used to hold extra info (sockopts, etc) +// as well as to keep a list of ipids waiting to close. + +typedef struct ipidHash { + Word ipid; + Word flags; + struct ipidHash *next; +} ipidHash; + +ipidHash *htable[64] = { }; + +ipidHash *dlist = NULL; + + + +// not yet sure what this is for... +typedef void (*selwakeup)(int col_flag, int pid); + +void debug_str(const char *cp) +{ + asm { + ldx srState, + sb->srNetworkError, + sb->srSndQueued, + sb->srRcvQueued, + sb->srDestIP, + sb->srDestPort, + sb->srConnectType, + sb->srAcceptCount + ); + + asm { + ldx #^buffer + ldy #buffer + cop 0x84 + } + +} + +int do_attach( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights +) +{ + // returns errno or 0. + Word ipid; + ipidHash *e; + + int type = socknum; + int *sockptr = (int *)m; + selwakeup *fx = (selwakeup *)m_len; + int *protocol = (int *)addr; + + //WriteLine("\pdo_attach"); + debug_str("do_attach"); + + if (type != SOCK_STREAM) return EPROTONOSUPPORT; + + ipid = TCPIPLogin(MyID, 0, 0, 0, 0x0040); + if (_toolErr) return EPFNOSUPPORT; + + // semaphore ... + swait(semID); + + e = (ipidHash *)malloc(sizeof(ipidHash)); + e->ipid = ipid; + e->flags = 0; + e->next = htable[ipid & (64-1)]; + htable[ipid & (64 - 1)] = e; + + ssignal(semID); + // end semaphore + + *sockptr = ipid; + + return 0; +} + + +// netinet/in.h is giving me compile errors... + +struct xsockaddr_in { + short sin_family; + unsigned short sin_port; + unsigned long sin_addr; + char sin_zero[8]; +}; + +int do_connect( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + // returns errno or 0. + Word terr; + Longword tick, qtick; + Word port; + + + Word ipid = (Word)socknum; + struct xsockaddr_in *sin = (struct xsockaddr_in *)addr; + + //WriteLine("\pdo_connect"); + debug_str("do_connect"); + + // port is byte-swapped. + + port = sin->sin_port; + asm { + lda sin_addr, + port); + + if (_toolErr) return EPFNOSUPPORT; + + terr = TCPIPOpenTCP(ipid); + if (_toolErr || terr) + { + return EPFNOSUPPORT; + } + + // wait to loop until actually connected. + + // 30-second timeout. + qtick = GetTick() + 60 * 30; + for(;;) + { + srBuff sr; + + terr = TCPIPStatusTCP(ipid, &sr); + + dump_srbuff(&sr); + + if (sr.srState == TCPSESTABLISHED) + return 0; + + if (sr.srState == TCPSCLOSED) + return ECONNREFUSED; + + if (sr.srState > TCPSESTABLISHED) + return ECONNREFUSED; + + if (GetTick() >= qtick) + return ETIMEDOUT; + + // is this safe? + sleep(1); + } + + + return 0; +} + + +int do_disconnect( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + Word ipid = socknum; + + debug_str("do_disconnect"); + //WriteLine("\pdo_disconnect"); + + // return value ignored. + + return 0; +} + +int do_detach( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + Word ipid = socknum; + + Word terr; + ipidHash *e; + ipidHash *prev; + + // returns a GS/OS error. + + // remove from hashtable. + // begin disconnect sequence. + // add to dlist. + + // need to use semaphore to block other thread... + + //WriteLine("\pdo_detach"); + debug_str("do_detach"); + + terr = TCPIPCloseTCP(ipid); + + // semaphore... + swait(semID); + + prev = NULL; + e = htable[ipid & (64-1)]; + for(;;) + { + if (e->ipid == ipid) break; + prev = e; + e = e->next; + } + if (e) + { + if (prev) prev->next = e->next; + else htable[ipid & (64 - 1)] = e->next; + + e->next = dlist; + dlist = e; + } + + ssignal(semID); + // end semaphore. + + return 0; +} + +int do_send( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + // called from GS/OS, busyflag set + // (seems like a bug to me....) + + Word terr; + Word ipid = (Word)socknum; + void *data = (void *)m; + size_t *len = (size_t *)m_len; + + //WriteLine("\pdo_send"); + + { + static char buffer[64]; + sprintf(buffer, "do_send: ipid = %04x len = %04x", + ipid, (Word)*len + ); + debug_str(buffer); + } + + terr = TCPIPWriteTCP(ipid, data, *len, 0, 0); + + // closing == eof. + if (terr == tcperrConClosing) + { + *len = 0; + return ECONNRESET; + } + + return 0; +} + + +int do_rcvd( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + // called from GS/OS, busy flag is set. + + // todo -- EWOULDBLOCK? + + Word terr; + Word ipid = (Word)socknum; + void *data = (void *)m; + size_t *len = (size_t *)m_len; + + rrBuff rr; + + //WriteLine("\pdo_rcvd"); + + { + static char buffer[64]; + sprintf(buffer, "do_rcvd: ipid = %04x len = %04x", + ipid, (Word)*len + ); + debug_str(buffer); + } + + // todo -- should block unless O_NONBLOCK set. + + for (;;) + { + + srBuff sr; + + terr = TCPIPStatusTCP(ipid, &sr); + + dump_srbuff(&sr); + + + terr = TCPIPReadTCP(ipid, 0, (Ref)data, *len, &rr); + + if (rr.rrBuffCount) + { + *len = rr.rrBuffCount; + return 0; + } + + if (terr == tcperrBadConnection) + return ENOTCONN; + + // no data, no more data, then closing. + if (terr == tcperrConClosing && !rr.rrMoreFlag) + return ECONNRESET; + + + // if NON_BLOCKING, return EWOULDBLOCK. + + asm { + cop 0x7f + } + // poll in main loop not called, apparently. + + TCPIPPoll(); // + //sleep(1); // cop 0x7f? + } + + return 0; +} + +#pragma databank 1 +static int driver( + int socknum, int req, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + + { + static char buffer[64]; + sprintf(buffer, "driver: req = %d", req); + debug_str(buffer); + } + + switch (req) + { + case PRU_ABORT: + break; + + case PRU_ACCEPT: + break; + + case PRU_ATTACH: + // KERNsocket(int domain, int type, int protocol, int *ERRNO); + return do_attach(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_BIND: + //WriteLine("\pbind!"); + // todo + return 0; + break; + + case PRU_CONNECT: + // KERNconnect(int fd, struct sockaddr *serv_addr, + // int addrlen, int *ERRNO) + return do_connect(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_CONNECT2: + break; + + case PRU_CONTROL: + break; + + case PRU_DETACH: + // int SOCKclose(int sock) part 2 + return do_detach(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_DISCONNECT: + // int SOCKclose(int sock) part 1 + return do_disconnect(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_LISTEN: + break; + + case PRU_PEERADDR: + break; + + case PRU_RCVD: + // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) + return do_rcvd(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_RCVOOB: + break; + + case PRU_SEND: + // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) + return do_send(socknum, m, m_len, addr, addrlen, rights); + break; + + case PRU_SENDOOB: + break; + + case PRU_SENSE: + break; + + case PRU_SHUTDOWN: + break; + + case PRU_SOCKADDR: + break; + + case PRU_CO_GETOPT: + break; + + case PRU_CO_SETOPT: + break; + + case PRU_SELECT: + break; + } + + return EINVAL; +} + + +void signal_handler(int sig, int code) +{ + WriteLine("\pWe got signal!"); + QuitFlag = 1; +} + +void DisplayMessage(const char *string) +{ + if (string) WriteLine(string); +} + +#pragma databank 0 + +// startup/shutdown flags. +enum { + kLoaded = 1, + kStarted = 2, + kConnected = 4 +}; + +Word StartUp(displayPtr fx) +{ + word status; + word flags = 0; + + // TCPIP is an init, not a tool, so it should always + // be loaded. + + status = TCPIPStatus(); + if (_toolErr) + { + LoadOneTool(54, 0x0300); + if (_toolErr) return -1; + + status = 0; + flags |= kLoaded; + } + +#if 0 + // require 3.0b3 + if (TCPIPLongVersion() < 0x03006003) + { + if (flags & kLoaded) + UnloadOneTool(54); + return -1; + } +#endif + + if (!status) + { + TCPIPStartUp(); + if (_toolErr) return -1; + flags |= kStarted; + } + + status = TCPIPGetConnectStatus(); + if (!status) + { + TCPIPConnect(fx); + flags |= kConnected; + } + + return flags; +} + +void ShutDown(word flags, Boolean force, displayPtr fx) +{ + if (flags & kConnected) + { + TCPIPDisconnect(force, fx); + if (_toolErr) return; + } + if (flags & kStarted) + { + TCPIPShutDown(); + if (_toolErr) return; + } + if (flags & kLoaded) + { + UnloadOneTool(54); + } +} + + +int main(int argc, char **argv) +{ + + int flags; + + MyID = MMStartUp(); + + flags = StartUp(DisplayMessage); + + semID = screate(1); + + InstallNetDriver(driver, 0); + + QuitFlag = 0; + + signal(SIGQUIT, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGHUP, signal_handler); + + while(!QuitFlag) + { + ipidHash *e; + ipidHash *prev; + + debug_str("TCPIPPoll()"); + TCPIPPoll(); + + // monitor disconnects... + // semaphore ... + + swait(semID); + if (errno == EINTR) continue; + + e = dlist; + prev = NULL; + + while (e) + { + Word terr; + srBuff sr; + ipidHash *next; + + next = e->next; + + terr = TCPIPStatusTCP(e->ipid, &sr); + + dump_srbuff(&sr); + + // timed wait or closed ... + if (sr.srState == TCPSCLOSED) + { + + TCPIPLogout(e->ipid); + free(e); + + if (prev) + { + prev->next = next; + } + else + { + dlist = next; + } + } + else + { + prev = e; + } + + e = next; + } + + ssignal(semID); + // end semaphore. + + sleep(1); // need a sleep10 to match alarm10 + } + + InstallNetDriver(NULL, 0); + sdelete(semID); + + + ShutDown(flags, 0, DisplayMessage); + + return 0; +} diff --git a/net.h b/net.h new file mode 100644 index 0000000..237ab93 --- /dev/null +++ b/net.h @@ -0,0 +1,35 @@ +/* $Id$ */ + +/* + * GNO/ME Network Support + * + * Copyright 1994-1998, Procyon Enterprises Inc. + * + * Written by Derek Taubert and Jawaid Bazyar + * + */ + +/* Request types for pr_usrreq() */ + +#define PRU_ABORT 0 +#define PRU_ACCEPT 1 +#define PRU_ATTACH 2 +#define PRU_BIND 3 +#define PRU_CONNECT 4 +#define PRU_CONNECT2 5 +#define PRU_CONTROL 6 +#define PRU_DETACH 7 +#define PRU_DISCONNECT 8 +#define PRU_LISTEN 9 +#define PRU_PEERADDR 10 +#define PRU_RCVD 11 +#define PRU_RCVOOB 12 +#define PRU_SEND 13 +#define PRU_SENDOOB 14 +#define PRU_SENSE 15 +#define PRU_SHUTDOWN 16 +#define PRU_SOCKADDR 17 +#define PRU_CO_GETOPT 18 +#define PRU_CO_SETOPT 19 +#define PRU_SELECT 20 +