diff --git a/mattach.c b/mattach.c index 583f3e5..d944fa9 100644 --- a/mattach.c +++ b/mattach.c @@ -25,8 +25,15 @@ int mattach(int type, void *p1, void *p2, void *p3, void *p4, void *p5) type, protocol); } - - if (type != SOCK_STREAM) return ESOCKTNOSUPPORT; + switch (type) + { + case SOCK_STREAM: + case SOCK_DGRAM: + break; + default: + return ESOCKTNOSUPPORT; + break; + } //if (protocol != 6) return EPROTONOSUPPORT; // TODO -- check protocol? 6 = tcp, 1 = icmp, 17 = udp. diff --git a/mread.c b/mread.c index acfd9a9..bfbb6b6 100644 --- a/mread.c +++ b/mread.c @@ -1,7 +1,9 @@ #include "marignotti.h" #include #include +#include +#include #include #include "s16debug.h" @@ -9,70 +11,183 @@ #pragma noroot #pragma optimize 79 -// called through GSOS. -int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +typedef struct xipheader { + byte verlen; + byte tos; + word len; + word id; + word fragoff; + byte ttl; + byte proto; + word cksum; + longword src; + longword dst; + // verlen & 0x0f is the number of 32-but words + // if > 5, extra data present and should be skipped. + + // data... + +} xipheader; + +typedef struct xudpheader { + word source; + word dst; + word len; + word cksum; + // data... +} xudpheader; + +// todo -- should have addr/addrlen for recvfrom. +static int sock_read( + Entry *e, + void *buffer, + LongWord nbytes, + LongWord *outbytes) { + LongWord size; + LongWord lowat; + Word t; + Word terr; rrBuff rr; + + if (e->_TYPE == SOCK_DGRAM) + { + // todo -- address support. + + // manually parse the ip header and udp header. + // + + + Handle h; + xipheader *ip; + Word offset = 0; + char *cp; + + + h = TCPIPGetNextDatagram(e->ipid, protocolUDP, 0); + t = _toolErr; + + if (t) return ENETDOWN; + if (!h) return EAGAIN; + + size = GetHandleSize(h); + + HLock(h); + cp = *(char **)h; + + ip = (xipheader *)cp; + offset = (ip->verlen & 0x0f) << 2; + + // would get the address here. + // ip->src + + offset += u_data; + + if (offset >= size) + { + // ??? + DisposeHandle(h); + return 0; + } + + size -= offset; + cp += offset; + + // nbytes is the max read... any overflow is discarded. + if (size > nbytes) size = nbytes; + BlockMove(cp, buffer, nbytes); + + if (Debug > 1) + { + s16_debug_dump(buffer, (Word)size); + } + + DisposeHandle(h); + + *outbytes = size; + return 0; + } + + // todo -- address support (which will always be the dest ip...) + + terr = TCPIPStatusTCP(e->ipid, &e->sr); + t = _toolErr; + if (t) terr = t; + e->terr = terr; + + if (t) return ENETDOWN; + + if (e->sr.srState < TCPSESTABLISHED) return ENOTCONN; + + size = e->sr.srRcvQueued; + lowat = e->_RCVLOWAT; + + // if the state is established, read LOWAT...nbytes. + // if the connection is closing, LOWAT is 1. + + if (e->sr.srState > TCPSESTABLISHED) + { + lowat = 1; + if (!size) return 0; // eof + } + + if (size < nbytes && size >= lowat) + nbytes = size; + + if (size < nbytes) return EAGAIN; + + // size >= nbytes. + terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, nbytes, &rr); + t = _toolErr; + if (t) terr = t; + e->terr = terr; + + // todo -- if there was a push, < nbyte will have been read. + // loop until nbytes have been read? + + if (Debug > 1) + { + s16_debug_dump(buffer, (Word)rr.rrBuffCount); + } + + *outbytes = rr.rrBuffCount; + return 0; + +} + +// called through ReadGS, recv, recvfrom +int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + int xerrno = 0; - LongWord count; LongWord timeout; - Word terr; - Word t; + char *buffer = (char *)p1; LongWord nbytes = *(LongWord *)p2; - *(LongWord *)p2 = 0; + xsockaddr *addr = (xsockaddr *)p3; + int addrlen = p4 ? *(int *)p4 : 0; + + LongWord *outbytes = (LongWord *)p2; + + *outbytes = 0; if (Debug > 0) { s16_debug_printf("read nbytes = %ld", nbytes); } - count = e->_RCVLOWAT; - if (count > nbytes) count = nbytes; - - // call immediately if possible, otherwise queue it up. IncBusy(); - terr = TCPIPStatusTCP(e->ipid, &e->sr); - t = _toolErr; + xerrno = sock_read(e, buffer, nbytes, outbytes); DecBusy(); - if (t) terr = t; - if (t || terr == tcperrBadConnection || terr == tcperrNoResources) + if (xerrno != EAGAIN || e->_NONBLOCK) { - return ENOTCONN; + return xerrno; } - // eof or data available? - if (e->sr.srRcvQueued >= count || terr == tcperrConClosing) - { - count = e->sr.srRcvQueued; - if (count > nbytes) count = nbytes; - - if (count) - { - IncBusy(); - terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, count, &rr); - t = _toolErr; - DecBusy(); - if (t) terr = t; - - *(LongWord *)p2 = rr.rrBuffCount; - - if (Debug > 1) - { - s16_debug_dump(buffer, (Word)rr.rrBuffCount); - } - - } - return 0; - } - - if (e->_NONBLOCK) return EAGAIN; - - if (e->_RCVTIMEO) timeout = GetTick() + e->_RCVTIMEO; else @@ -80,51 +195,21 @@ int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) for(;;) { - xerrno = queue_command(e, kCommandRead, count, timeout); + xerrno = queue_command(e, kCommandRead, nbytes, timeout); if (xerrno == EINTR) return EINTR; if (xerrno) return EIO; if (e->command) continue; // reset to 0 if processed. - terr = e->terr; - - if (terr && terr != tcperrConClosing) - { - return EIO; - } - - // 3 things may have happened. - // 1. sufficient data available. - // 2. connection closed. - // 3. timeout. + IncBusy(); + xerrno = sock_read(e, buffer, nbytes, outbytes); + DecBusy(); - if (e->sr.srRcvQueued >= count || terr == tcperrConClosing) - { - count = e->sr.srRcvQueued; - if (count > nbytes) count = nbytes; + if (xerrno != EAGAIN) return xerrno; - if (count) - { - IncBusy(); - terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, count, &rr); - t = _toolErr; - DecBusy(); - - *(LongWord *)p2 = rr.rrBuffCount; - - if (Debug > 1) - { - s16_debug_dump(buffer, (Word)rr.rrBuffCount); - } - - } - return 0; - } - if (timeout && timeout <= GetTick()) return EAGAIN; - } // should not hit... diff --git a/mwrite.c b/mwrite.c index 7b42a8d..b4e9bf0 100644 --- a/mwrite.c +++ b/mwrite.c @@ -1,6 +1,7 @@ #include "marignotti.h" #include #include +#include #include #include "s16debug.h" @@ -8,7 +9,7 @@ #pragma noroot #pragma optimize 79 -// called through GSOS. +// WriteGS, send, or sendto int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) { Word terr; @@ -17,12 +18,48 @@ int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) char *buffer = (char *)p1; LongWord nbytes = *(LongWord *)p2; + xsockaddr *addr = (xsockaddr *)p3; + int addrlen = p4 ? *(int *)p4 : 0; - *(LongWord *)p2 = 0; + LongWord *outbytes = (LongWord *)p2; + + *outbytes = 0; if (Debug > 0) { s16_debug_printf("write nbytes = %ld", nbytes); + if (addr) + { + s16_debug_puts(" to address..."); + s16_debug_dump(addr, addrlen); + } + } + if (Debug > 1) + { + s16_debug_puts(""); + s16_debug_dump(buffer, (Word)nbytes); + } + + if (e->_TYPE == SOCK_DGRAM) + { + // TCPIPSendUDP builds a header + // using the source port, my ip address, + // destination port and destination ip address. + + // mconnect should probably just set the destination + // address/port and exit. + + // if an address was specified, we would need to + // build the udp header here. + IncBusy(); + TCPIPSendUDP(e->ipid, buffer, nbytes); + t = _toolErr; + DecBusy(); + + if (t) return ENETDOWN; + + *outbytes = nbytes; + return 0; } // todo -- queue up if pending >= _SNDLOWAT? @@ -31,8 +68,9 @@ int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) IncBusy(); terr = TCPIPWriteTCP(e->ipid, buffer, nbytes, 0, 0); t = _toolErr; - DecBusy(); if (t) terr = t; + e->terr = terr; + DecBusy(); if (t || terr == tcperrBadConnection) return ENOTCONN; @@ -42,14 +80,16 @@ int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) if (terr == tcperrConClosing) { - int xerrno; if (!e->_NOSIGPIPE) + { + int xerrno; Kkill(Kgetpid(), SIGPIPE, &xerrno); + } return EPIPE; } - *(LongWord *)p2 = nbytes; + *outbytes = nbytes; return 0; } \ No newline at end of file diff --git a/table.c b/table.c index 3ae017b..4695be0 100644 --- a/table.c +++ b/table.c @@ -208,8 +208,9 @@ void process_table(void) { case kCommandRead: // block until data available. - if (e->sr.srRcvQueued >= e->cookie - || expired + if (expired + || e->sr.srRcvQueued >= e->cookie + || e->sr.srRcvQueued >= e->_RCVLOWAT || terr) { sig = 1;