diff --git a/driver.c b/driver.c new file mode 100644 index 0000000..0df86b2 --- /dev/null +++ b/driver.c @@ -0,0 +1,165 @@ +#include "marignotti.h" +#include +#include +#include "net.h" + +#pragma noroot +#pragma optimize 79 + +int block(int sem) +{ + int xerrno = 0; + Kswait(sem, &xerrno); + return xerrno; +} + +int queue_command(Entry *e, word command, LongWord cookie, LongWord timeout) +{ + int xerrno; + + SEI(); + e->command = kCommandRead; + e->cookie = cookie; + e->timeout = timeout; + CLI(); + + xerrno = 0; + Kswait(e->semaphore, &xerrno); + return xerrno; +} + + + + + + + +#pragma databank 1 + +int driver( + int socknum, int req, + void *p1, void *p2, + void *p3, void *p4, void *p5) +{ + int rv; + Entry *e; + + if (req == PRU_ATTACH) + { + return mattach(socknum, p1, p2, p3, p4, p5); + } + + e = find_entry(socknum); + if (!e) + { + if (req == PRU_RCVD || req == PRU_SEND) + *(LongWord *)p2 = 0; + + return EBADF; + } + + switch (req) + { + case PRU_ABORT: + break; + + case PRU_ACCEPT: + break; + + case PRU_ATTACH: + // KERNsocket(int domain, int type, int protocol, int *ERRNO); + // handled above. + break; + + case PRU_BIND: + // KERNbind(int fd, struct sockaddr *my_addr, int addrlen, int *ERRNO) + //return do_bind(socknum, m, m_len, addr, addrlen, rights); + return 0; + break; + + case PRU_CONNECT: + // KERNconnect(int fd, struct sockaddr *serv_addr, + // int addrlen, int *ERRNO) + return mconnect(e, p1, p2, p3, p4, p5); + break; + + case PRU_CONNECT2: + break; + + case PRU_CONTROL: + break; + + case PRU_DETACH: + // called from GS/OS + // int SOCKclose(int sock) part 2 + DecBusy(); + rv = mdetach(e, p1, p2, p3, p4, p5); + IncBusy(); + return rv; + break; + + case PRU_DISCONNECT: + // called from GS/OS + // int SOCKclose(int sock) part 1 + //return do_disconnect(socknum, m, m_len, addr, addrlen, rights); + return 0; + break; + + case PRU_LISTEN: + break; + + case PRU_PEERADDR: + break; + + case PRU_RCVD: + // this may be called from GSOS (in which case IncBusy() + // is in effect + // or from KERNrecvfrom (in which case it isn't). + // + // may block, so be nice. + // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) + DecBusy(); + rv = mread(e, p1, p2, p3, p4, p5); + IncBusy(); + return rv; + break; + + case PRU_RCVOOB: + break; + + case PRU_SEND: + // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) + // same as above. + DecBusy(); + rv = mwrite(e, p1, p2, p3, p4, p5); + IncBusy(); + return rv; + 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: + // int SOCKselect(int pid, int fl, int sock) + break; + } + + return EINVAL; +} + +#pragma databank 0 diff --git a/main.c b/main.c new file mode 100644 index 0000000..e00ecf1 --- /dev/null +++ b/main.c @@ -0,0 +1,150 @@ +#include "marignotti.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#pragma optimize 79 + +int semID = 0; +Word MyID; +Word QuitFlag; + +#pragma databank 0 +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 1 + // require 3.0b3 + if (TCPIPLongVersion() < 0x03006003) + { + if (fx) fx("Marinetti 3.0b3 is required."); + 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); + + if (flags == -1) exit(1); + + semID = screate(1); + + InstallNetDriver(driver, 0); + + QuitFlag = 0; + + signal(SIGQUIT, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGHUP, signal_handler); + + // SIGUSR to dump table ala netstat? + while (!QuitFlag) + { + + IncBusy(); + + TCPIPPoll(); + + DecBusy(); + + process_table(); + + asm { cop 0x7f } + } + + InstallNetDriver(NULL, 0); + sdelete(semID); + + destroy_table(); + + ShutDown(flags, 0, DisplayMessage); + + return 0; +} diff --git a/makefile.mk b/makefile.mk index bc668c8..4f76f42 100644 --- a/makefile.mk +++ b/makefile.mk @@ -1,14 +1,25 @@ CFLAGS += $(DEFINES) -v -w -OBJS = marignotti.o +OBJS = main.o table.o driver.o s16debug.o mattach.o mconnect.o \ +mread.o mwrite.o mdetach.o + TARGET = marignotti $(TARGET): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) $(LDLIBS) -o $@ -marignotti.o: marignotti.c net.h -pull: - gopher gopher://192.168.1.117:7070/0/marignotti.c > marignotti.c + +s16debug.o: s16debug.c s16debug.h + +main.o: main.c marignotti.h +table.o: table.c marignotti.h +driver.o: driver.c marignotti.h net.h +mread.o: mread.c marignotti.h +mwrite.o: mwrite.c marignotti.h +mattach.o: mattach.c marignotti.h +mconnect.o: mconnect.c marignotti.h +mdetach.o: mdetach.c marignotti.h + clean: $(RM) *.o *.root diff --git a/marignotti.h b/marignotti.h new file mode 100644 index 0000000..bb5c50e --- /dev/null +++ b/marignotti.h @@ -0,0 +1,97 @@ +#include +#include + + +enum { + kCommandNone = 0, + kCommandConnect, + kCommandDisconnect, + kCommandDisconnectAndLogout, + kCommandRead, + kCommandWrite, + kCommandAbortAndLogout +}; + +typedef struct Entry { + struct Entry *next; + + Word ipid; + int semaphore; + + srBuff sr; + Word terr; + + Word command; + LongWord cookie; + LongWord timeout; + + // shutdown(2) + unsigned _SHUT_RD:1; + unsigned _SHUT_WR:1; + + // fcntl(2) + unsigned _NONBLOCK:1; + + //setsockopt(2) + unsigned _OOBINLINE:1; + unsigned _LINGER:1; + unsigned _NOSIGPIPE:1; + + LongWord _SNDLOWAT; + LongWord _RCVLOWAT; + Word _RCVTIMEO; + Word _LINGER_SEC; + + +} Entry; + +extern Word MyID; + +typedef struct xsockaddr_in { + short sin_family; + unsigned short sin_port; + unsigned long sin_addr; + char sin_zero[8]; +} xsockaddr_in; + + +#define IncBusy() asm { jsl 0xE10064 } +#define DecBusy() asm { jsl 0xE10068 } +#define Resched() asm { cop 0x7f } + +#define SEI() asm { sei } +#define CLI() asm { cli } + +int block(int sem); +int queue_command(Entry *e, word command, LongWord cookie, LongWord timeout); + +void init_table(void); +void destroy_table(void); +void process_table(void); + +Entry *find_entry(Word ipid); +Entry *create_entry(Word ipid); + + + +// driver stuff. + +int driver(int, int, void *, void *, void *, void *, void *); + +int mattach(int ipid, void *p1, void *p2, void *p3, void *p4, void *p5); + +int mread(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int mwrite(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int mconnect(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int mbind(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int mdetach(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int mdisconnect(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); + +int mgetsockopt(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); +int msetsockopt(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); + +int mioctl(Entry *, void *p1, void *p2, void *p3, void *p4, void *p5); + + + + diff --git a/mattach.c b/mattach.c new file mode 100644 index 0000000..70c62f8 --- /dev/null +++ b/mattach.c @@ -0,0 +1,40 @@ +#include "marignotti.h" +#include +#include +#include + + +#pragma noroot +#pragma optimize 79 + +// better known as socket(2) +int mattach(int type, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + Word t; + Word ipid; + Entry *e; + + // p2 = selwakeup. + int protocol = *(int *)p3; + + if (type != SOCK_STREAM) return ESOCKTNOSUPPORT; + if (protocol != 6) return EPROTONOSUPPORT; + // TODO -- check protocol? 6 = tcp, 1 = icmp, 17 = udp. + + IncBusy(); + ipid = TCPIPLogin(MyID, 0, 0, 0, 0x0040); + t = _toolErr; + DecBusy(); + + if (t) return ENETDOWN; + + e = create_entry(ipid); + if (!e) + { + TCPIPLogout(ipid); + return ENOMEM; + } + *(Word *)p1 = ipid; + + return 0; +} diff --git a/mconnect.c b/mconnect.c new file mode 100644 index 0000000..4f7f1f9 --- /dev/null +++ b/mconnect.c @@ -0,0 +1,114 @@ +#include "marignotti.h" +#include +#include +#include + +#pragma noroot +#pragma optimize 79 + +int mconnect(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + Word port; + Word t; + Word terr; + int xerrno; + LongWord timeout; + + // todo -- if non-blocking, + // return EINPROGRESS + // + + xsockaddr_in *sin = (xsockaddr_in *)p3; + int addrlen = *(int *)p4; + + port = sin->sin_port; + asm { + lda ipid, &e->sr); + t = _toolErr; + if (t) terr = t; + DecBusy(); + + // todo -- if non-blocking, + // return EINPROGRESS first time, + // return EALREADY on subsequent calls. + + if (e->sr.srState != TCPSCLOSED) + return EISCONN; + + + IncBusy(); + TCPIPSetNewDestination(e->ipid, sin->sin_addr, port); + t = _toolErr; + DecBusy(); + + if (t) + { + return ENETDOWN; + } + + IncBusy(); + terr = TCPIPOpenTCP(e->ipid); + t = _toolErr; + if (t) terr = t; + DecBusy(); + + // todo -- better errors. + if (terr) + { + return ENETDOWN; + } + + + timeout = GetTick() + 60 * 30; + + for (;;) + { + + int xerrno; + int state; + + xerrno = queue_command(e, kCommandConnect, 0, timeout); + + // hmmm .. should these abort? + if (xerrno == EINTR) + { + IncBusy(); + e->command = kCommandNone; + TCPIPAbortTCP(e->ipid); + DecBusy(); + + return EINTR; // ? + } + if (xerrno) return EIO; // semaphore destroyed? + + if (e->command) continue; // reset to 0 if processed. + + state = e->sr.srState; + if (state == TCPSESTABLISHED) + return 0; + + if (state == TCPSCLOSED) + // todo -- differentiate ECONNREFUSED vs EHOSTUNREACH + return ECONNREFUSED; + + if (timeout && timeout > GetTick()) + { + IncBusy(); + TCPIPAbortTCP(e->ipid); + DecBusy(); + + return ETIMEDOUT; + } + } + + + return 0; // should never hit. + +} diff --git a/mdetach.c b/mdetach.c new file mode 100644 index 0000000..571f3ea --- /dev/null +++ b/mdetach.c @@ -0,0 +1,22 @@ +#include "marignotti.h" +#include +#include + + +#pragma noroot +#pragma optimize 79 + +// +int mdetach(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + + // TODO -- SO_LINGER/SO_LINGER_SEC + + SEI(); + e->command = kCommandDisconnectAndLogout; + e->cookie = 0; + e->timeout = 0; + CLI(); + + return 0; +} \ No newline at end of file diff --git a/table.c b/table.c new file mode 100644 index 0000000..f638bfa --- /dev/null +++ b/table.c @@ -0,0 +1,202 @@ +#include "marignotti.h" + +#include +#include + +#pragma optimize 79 +#pragma noroot + +#define TABLE_SIZE 16 +#define TABLE_MASK 15 +static struct Entry *table[TABLE_SIZE]; + +void init_table(void) +{ + memset(table, 0, sizeof(table)); +} + +void destroy_table(void) +{ + + Entry *e; + unsigned i; + + for (i = 0; i < TABLE_SIZE; ++i) + { + SEI(); + e = table[i]; + table[i] = 0; + CLI(); + + while (e) + { + Entry *next; + + IncBusy(); + + next = e->next; + + TCPIPAbortTCP(e->ipid); + TCPIPLogout(e->ipid); + + sdelete(e->semaphore); + free(e); + + e = next; + + DecBusy(); + } + + } +} + +Entry *find_entry(Word ipid) +{ + Entry *e; + + IncBusy(); + e = table[ipid & TABLE_MASK]; + + while (e) + { + if (e->ipid == ipid) break; + e = e->next; + } + DecBusy(); + + return e; +} + +Entry *create_entry(Word ipid) +{ + Entry *e; + e = NULL; + IncBusy(); + e = calloc(sizeof(Entry), 1); + DecBusy(); + + if (!e) return NULL; + e->semaphore = screate(0); + if (e->semaphore < 0) + { + IncBusy(); + free(e); + DecBusy(); + return NULL; + } + + e->ipid = ipid; + e->_OOBINLINE = 1; + e->_SNDLOWAT = 1024; + e->_RCVLOWAT = 1; + + SEI(); + e->next = table[ipid & TABLE_MASK]; + table[ipid & TABLE_MASK] = e; + CLI(); + + return e; +} + +void process_table(void) +{ + Word terr; + Word t; + LongWord tick; + + unsigned i; + Entry *e; + Entry *next; + Entry *prev; + + tick = GetTick(); + + for (i = 0; i < TABLE_SIZE; ++i) + { + prev = NULL; + e = table[i]; + while (e) + { + next = e->next; + + if (e->command) + { + Word expired = 0; + Word sig = 0; + Word state; + + IncBusy(); + + + if (e->timeout && tick > e->timeout) + expired = 1; + + terr = TCPIPStatusTCP(e->ipid, &e->sr); + t = _toolErr; + if (t) terr = t; + e->terr = terr; + + state = e->sr.srState; + + switch(e->command) + { + case kCommandRead: + if (e->sr.srRcvQueued >= e->cookie + || expired + || terr) + { + sig = 1; + } + break; + + case kCommandConnect: + if (state >= TCPSESTABLISHED || state == TCPSCLOSED) + { + sig = 1; + } + break; + + case kCommandDisconnect: + if (state == TCPSCLOSED) + { + sig = 1; + } + break; + + case kCommandDisconnectAndLogout: + // logout and remove entry. + if (state == TCPSCLOSED) + { + TCPIPLogout(e->ipid); + sdelete(e->semaphore); + free(e); + e = NULL; + if (prev) + { + prev->next = next; + } + else + { + table[i] = next; + } + } + break; + + } + + if (sig) + { + e->command = kCommandNone; + ssignal(e->semaphore); + } + + DecBusy(); + } // e->command + + e = next; + } + + + } + +} \ No newline at end of file