From f14c62511b1f34288458894dd930034a1a08fe89 Mon Sep 17 00:00:00 2001 From: Kelvin Sherlock Date: Thu, 3 May 2012 17:25:03 -0400 Subject: [PATCH] misc updates --- marignotti.c | 334 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 316 insertions(+), 18 deletions(-) diff --git a/marignotti.c b/marignotti.c index da1864d..566f7fc 100644 --- a/marignotti.c +++ b/marignotti.c @@ -36,9 +36,28 @@ int semID; // this will be used to hold extra info (sockopts, etc) // as well as to keep a list of ipids waiting to close. +struct flags { + // shutdown(2) + Word _SHUT_RD:1; + Word _SHUT_WR:1; + + // fcntl(2) + Word _NONBLOCK:1; + + // setsockopt() + Word _OOBINLINE:1; + Word _LINGER:1; + Word _NOSIGPIPE:1; + +}; + typedef struct ipidHash { Word ipid; - Word flags; + struct flags flags; + + Word _SNDLOWAT; + Word _RCVLOWAT; + struct ipidHash *next; } ipidHash; @@ -47,6 +66,20 @@ ipidHash *htable[64] = { }; ipidHash *dlist = NULL; +ipidHash *findIpidHash(Word ipid) +{ + ipidHash *e; + + e = htable[ipid & (64 - 1)]; + + while (e) + { + if (e->ipid == ipid) return e; + e = e->next; + } + + return NULL; +} // not yet sure what this is for... typedef void (*selwakeup)(int col_flag, int pid); @@ -177,9 +210,14 @@ int do_attach( // semaphore ... swait(semID); - e = (ipidHash *)malloc(sizeof(ipidHash)); + e = (ipidHash *)calloc(sizeof(ipidHash), 1); e->ipid = ipid; - e->flags = 0; + + e->_RCVLOWAT = 1; + e->_SNDLOWAT = 1024; + e->flags._OOBINLINE = 1; + + e->next = htable[ipid & (64-1)]; htable[ipid & (64 - 1)] = e; @@ -201,6 +239,40 @@ struct xsockaddr_in { char sin_zero[8]; }; + +int do_bind( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + // freebsd 2.0 whois does a bind before + // the connect. + // this was removed in freebsd 3.0 + + Word ipid = (Word)socknum; + struct xsockaddr_in *sin = (struct xsockaddr_in *)addr; + + port = sin->sin_port; + asm { + lda sin_addr, + port); + + if (_toolErr) return EPFNOSUPPORT; + + return 0; +} + + int do_connect( int socknum, void *m, size_t *m_len, @@ -284,6 +356,10 @@ int do_disconnect( debug_str("do_disconnect"); //WriteLine("\pdo_disconnect"); + // TODO -- SO_LINGER / SO_LINGER_SEC + // monitor the out queue and don't return until all + // data is sent (or it times out). + // return value ignored. return 0; @@ -374,7 +450,7 @@ int do_send( if (terr == tcperrConClosing) { *len = 0; - return ECONNRESET; + return ECONNRESET; // ? EPIPE? } return 0; @@ -389,15 +465,33 @@ int do_rcvd( { // called from GS/OS, busy flag is set. - // todo -- EWOULDBLOCK? + // todo -- EWOULDBLOCK / EAGAIN + + // Marinetti will not read less than the requested + // size unless there is a push or the connection is closing. + + // TODO -- SO_RCVLOWAT (default is 1?) + // if SO_RCVLOWAT < queued data < requested length, + // read SO_RCVLOWAT bytes Word terr; Word ipid = (Word)socknum; void *data = (void *)m; size_t *len = (size_t *)m_len; + ipidHash *e; rrBuff rr; + Word readCount; + Word minCount; + + if (!len || !data) return EFAULT; + + e = findIpidHash(ipid); + + readCount = *len; + minCount = e ? e->_RCVLOWAT; + //WriteLine("\pdo_rcvd"); { @@ -409,18 +503,35 @@ int do_rcvd( } // todo -- should block unless O_NONBLOCK set. - + + + // todo -- could the read return 0 if there was a push at byte 0 + // but data afterwards? for (;;) { - + srBuff sr; terr = TCPIPStatusTCP(ipid, &sr); dump_srbuff(&sr); + + + if (!sr.srRcvQueued && e && e->flags._NONBLOCK) + { + *len = 0; + return EAGAIN; + } + + // + if (sr.srRcvQueued < readCount && sr.srRcvQueued >= minCount) + { + readCount = minCount; + } - - terr = TCPIPReadTCP(ipid, 0, (Ref)data, *len, &rr); + + + terr = TCPIPReadTCP(ipid, 0, (Ref)data, readCount, &rr); if (rr.rrBuffCount) { @@ -448,22 +559,195 @@ int do_rcvd( // 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? + sleep(1); } return 0; } + +int do_select( + int socknum, + void *m, size_t *m_len, + struct sockaddr *addr, int *addrlen, + void *rights) +{ + + ipidHash *e; + srBuff sr; + Word terr; + + Word ipid = (Word)sock; + int *pid = (int *)m_len; + int *flag = (int *)(addr); + + // *flag is return value as well as input value + // (which select type) + // SEL_READ = 0 + // SEL_WRITE = 1 + // SEL_EXCEPT = 2 + + if (*flag == 0) + { + // sel read. + terr = TCPIPStatusTCP(ipid, &sr); + + if (sr.srRcvQueued) + *flag = 1; + else + *flag = 0; + + return 0; + } + + if (*flag == 1) + { + // sel write. + // check the high water mark. + terr = TCPIPStatusTCP(ipid, &sr); + + e = findIpidHash(ipid); + + if (e && sr.srSndQueued >= e->_SNDLOWAT) + *flag = 0; + else + *flag = 1; + + } + + if (*flag == 2) + { + // exceptions?? + *flag = 0; + } + + + return 0; +} + +int do_getsockopt( + Word ipid, + void *p1, void *p2, + void *p3, void *p4, + void *p5) +{ + + ipidHash *e; + int level = *(int *)p1; + int optname = *(int *)p2; + void *optval = (void *)p3; + int *optlen = (int *)p4; + + if (!optval) return EINVAL; + + e = findIpidHash(ipid); + + switch (optname) + { + case SO_NREAD: + // return the amount of data available to read. + break; + + case SO_NWRITE: + // return the amount of data queued for writing. + break; + + case SO_TYPE: + *(Word *)optval = SOCK_STREAM; + return 0; + + case SO_NOSIGPIPE: + if (e) *(Word *)optval = e->flags._NOSIGPIPE; + else *(Word *)optval = 0; + return 0; + break; + + case SO_RCVLOWAT: + if (e) *(Word)optval = e->_RCVLOWAT; + else *(Word)optval = 1; + return 0; + + case SO_SNDLOWAT: + if (e) *(Word)optval = e->_SNDLOWAT; + else *(Word)optval = 1024; + return 0; + + case SO_LINGER: + if (e) *(Word *)optval = e->flags._LINGER; + else *(Word *)optval = 0; + return 0; + break; + + case SO_OOBINLINE: + if (e) *(Word *)optval = e->flags._OOBINLINE; + else *(Word *)optval = 1; + return 0; + break; + + // unsupported ish. + case SO_SNDBUF: + case SO_RCVBUF: + // input/output buffer size + + case SO_RCVTIMEO: + case SO_SNDTIMEO: + // read/send timeout. + + case SO_ERROR: + // return any pending error and clear the error status. + + + default: + return ENOPROTOOPT; + } + + return ENOPROTOOPT; +} + + +int do_shutdown( + Word ipid, + void *p1, void *p2, + void *p3, void *p4, + void *p5) +{ + ipidHash *e = findIpidHash(ipid); + + int how = *(int *)p1; + + // mark the read/write op disabled + // TODO -- main thread should read & ignore any + // incoming data if SHUT_RD? + + if (!e) return EINVAL; + + switch(how) + { + case 0: + e->flags._SHUT_RD = 1; + break; + case 1: + e->flags._SHUT_WR = 1; + break; + case 2: + e->flags._SHUT_RD = 1; + e->flags._SHUT_WR = 1; + break; + + default: + return EINVAL; + } + + return 0; +} + #pragma databank 1 static int driver( int socknum, int req, @@ -493,9 +777,8 @@ static int driver( break; case PRU_BIND: - //WriteLine("\pbind!"); - // todo - return 0; + // KERNbind(int fd, struct sockaddr *my_addr, int addrlen, int *ERRNO) + return do_bind(socknum, m, m_len, addr, addrlen, rights); break; case PRU_CONNECT: @@ -571,6 +854,9 @@ static int driver( break; case PRU_SELECT: + // int SOCKselect(int pid, int fl, int sock) + return do_select(socknum, m, m_len, addr, addrlen, rights); + break; } @@ -616,10 +902,11 @@ Word StartUp(displayPtr fx) flags |= kLoaded; } -#if 0 +#if 1 // require 3.0b3 if (TCPIPLongVersion() < 0x03006003) { + if (fx) fx("Marinetti 3.0b3 is required."); if (flags & kLoaded) UnloadOneTool(54); return -1; @@ -671,6 +958,8 @@ int main(int argc, char **argv) flags = StartUp(DisplayMessage); + if (flags == -1) exit(1); + semID = screate(1); InstallNetDriver(driver, 0); @@ -687,6 +976,14 @@ int main(int argc, char **argv) ipidHash *prev; debug_str("TCPIPPoll() begin"); + if (dlist) + { + // suspend so we can be fg. + kill(getpid(),SIGSTOP); + asm { + brk 0xea + } + } TCPIPPoll(); debug_str("TCPIPPoll() end"); @@ -715,6 +1012,7 @@ int main(int argc, char **argv) if (sr.srState == TCPSCLOSED) { + debug_str("TCPLogout"); TCPIPLogout(e->ipid); free(e);