new read function

This commit is contained in:
Kelvin Sherlock 2012-05-04 20:10:49 -04:00
parent f14c62511b
commit 1f6030f867
1 changed files with 123 additions and 0 deletions

123
mread.c Normal file
View File

@ -0,0 +1,123 @@
#include "marignotti.h"
#include <gno/kerntool.h>
#include <errno.h>
#include <misctool.h>
#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;
}