diff --git a/mread.c b/mread.c new file mode 100644 index 0000000..4a21bb7 --- /dev/null +++ b/mread.c @@ -0,0 +1,123 @@ +#include "marignotti.h" +#include +#include + +#include + +#pragma noroot +#pragma optimize 79 + +// called through GSOS. +int mread(int ipid, void *p1, void *p2, void *p3, void *p4, void *p5) +{ + rrBuff rr; + + Entry *e; + int xerrno = 0; + LongWord count; + LongWord timeout; + Word terr; + Word t; + + char *buffer = (char *)p1; + LongWord nbytes = *(LongWord *)p2; + *(LongWord *)p2 = 0; + + + e = find_entry(ipid); + + if (!e) + { + return EBADF; + } + + count = e->_RCVLOWAT; + if (count > nbytes) count = nbytes; + + // call immediately if possible, otherwise queue it up. + IncBusy(); + terr = TCPIPStatusTCP(ipid, &e->sr); + t = _toolErr; + DecBusy(); + if (t) terr = t; + + if (t || terr == tcperrBadConnection || terr == tcperrNoResources) + { + return ENOTCONN; + } + + // 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(ipid, 0, (Ref)buffer, count, &rr); + t = _toolErr; + DecBusy(); + if (t) terr = t; + + *(LongWord *)p2 = rr.rrBuffCount; + } + return 0; + } + + if (e->_NONBLOCK) return EAGAIN; + + + if (e->_RCVTIMEO) + timeout = GetTick() + e->_RCVTIMEO; + else + timeout = 0; + + for(;;) + { + xerrno = queue_command(e, kCommandRead, count, 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. + + + if (e->sr.srRcvQueued >= count || terr == tcperrConClosing) + { + count = e->sr.srRcvQueued; + if (count > nbytes) count = nbytes; + + if (count) + { + IncBusy(); + terr = TCPIPReadTCP(ipid, 0, (Ref)buffer, count, &rr); + t = _toolErr; + DecBusy(); + + *(LongWord *)p2 = rr.rrBuffCount; + } + return 0; + } + + if (timeout && timeout > GetTick()) + return EAGAIN; + + } + + // should not hit... + return 0; +} +