UDP support (socket, read, write)

This commit is contained in:
Kelvin Sherlock 2012-05-12 19:44:10 -04:00
parent bd54abed5c
commit 750f8ab0e5
4 changed files with 220 additions and 87 deletions

View File

@ -25,8 +25,15 @@ int mattach(int type, void *p1, void *p2, void *p3, void *p4, void *p5)
type, protocol); type, protocol);
} }
switch (type)
if (type != SOCK_STREAM) return ESOCKTNOSUPPORT; {
case SOCK_STREAM:
case SOCK_DGRAM:
break;
default:
return ESOCKTNOSUPPORT;
break;
}
//if (protocol != 6) return EPROTONOSUPPORT; //if (protocol != 6) return EPROTONOSUPPORT;
// TODO -- check protocol? 6 = tcp, 1 = icmp, 17 = udp. // TODO -- check protocol? 6 = tcp, 1 = icmp, 17 = udp.

217
mread.c
View File

@ -1,7 +1,9 @@
#include "marignotti.h" #include "marignotti.h"
#include <gno/kerntool.h> #include <gno/kerntool.h>
#include <errno.h> #include <errno.h>
#include <sys/socket.h>
#include <memory.h>
#include <misctool.h> #include <misctool.h>
#include "s16debug.h" #include "s16debug.h"
@ -9,68 +11,181 @@
#pragma noroot #pragma noroot
#pragma optimize 79 #pragma optimize 79
// called through GSOS. typedef struct xipheader {
int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) 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; rrBuff rr;
int xerrno = 0;
LongWord count;
LongWord timeout;
Word terr;
Word t;
char *buffer = (char *)p1; if (e->_TYPE == SOCK_DGRAM)
LongWord nbytes = *(LongWord *)p2;
*(LongWord *)p2 = 0;
if (Debug > 0)
{ {
s16_debug_printf("read nbytes = %ld", nbytes); // 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;
} }
count = e->_RCVLOWAT; size -= offset;
if (count > nbytes) count = nbytes; 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...)
// call immediately if possible, otherwise queue it up.
IncBusy();
terr = TCPIPStatusTCP(e->ipid, &e->sr); terr = TCPIPStatusTCP(e->ipid, &e->sr);
t = _toolErr; t = _toolErr;
DecBusy();
if (t) terr = t; if (t) terr = t;
e->terr = terr;
if (t || terr == tcperrBadConnection || terr == tcperrNoResources) 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)
{ {
return ENOTCONN; lowat = 1;
if (!size) return 0; // eof
} }
// eof or data available? if (size < nbytes && size >= lowat)
nbytes = size;
if (e->sr.srRcvQueued >= count || terr == tcperrConClosing) if (size < nbytes) return EAGAIN;
{
count = e->sr.srRcvQueued;
if (count > nbytes) count = nbytes;
if (count) // size >= nbytes.
{ terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, nbytes, &rr);
IncBusy();
terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, count, &rr);
t = _toolErr; t = _toolErr;
DecBusy();
if (t) terr = t; if (t) terr = t;
e->terr = terr;
*(LongWord *)p2 = rr.rrBuffCount; // todo -- if there was a push, < nbyte will have been read.
// loop until nbytes have been read?
if (Debug > 1) if (Debug > 1)
{ {
s16_debug_dump(buffer, (Word)rr.rrBuffCount); s16_debug_dump(buffer, (Word)rr.rrBuffCount);
} }
} *outbytes = rr.rrBuffCount;
return 0; return 0;
} }
if (e->_NONBLOCK) return EAGAIN; // called through ReadGS, recv, recvfrom
int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5)
{
int xerrno = 0;
LongWord timeout;
char *buffer = (char *)p1;
LongWord nbytes = *(LongWord *)p2;
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);
}
IncBusy();
xerrno = sock_read(e, buffer, nbytes, outbytes);
DecBusy();
if (xerrno != EAGAIN || e->_NONBLOCK)
{
return xerrno;
}
if (e->_RCVTIMEO) if (e->_RCVTIMEO)
@ -80,51 +195,21 @@ int mread(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5)
for(;;) for(;;)
{ {
xerrno = queue_command(e, kCommandRead, count, timeout); xerrno = queue_command(e, kCommandRead, nbytes, timeout);
if (xerrno == EINTR) return EINTR; if (xerrno == EINTR) return EINTR;
if (xerrno) return EIO; if (xerrno) return EIO;
if (e->command) continue; // reset to 0 if processed. 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(); IncBusy();
terr = TCPIPReadTCP(e->ipid, 0, (Ref)buffer, count, &rr); xerrno = sock_read(e, buffer, nbytes, outbytes);
t = _toolErr;
DecBusy(); DecBusy();
*(LongWord *)p2 = rr.rrBuffCount; if (xerrno != EAGAIN) return xerrno;
if (Debug > 1)
{
s16_debug_dump(buffer, (Word)rr.rrBuffCount);
}
}
return 0;
}
if (timeout && timeout <= GetTick()) if (timeout && timeout <= GetTick())
return EAGAIN; return EAGAIN;
} }
// should not hit... // should not hit...

View File

@ -1,6 +1,7 @@
#include "marignotti.h" #include "marignotti.h"
#include <gno/kerntool.h> #include <gno/kerntool.h>
#include <sys/signal.h> #include <sys/signal.h>
#include <sys/socket.h>
#include <errno.h> #include <errno.h>
#include "s16debug.h" #include "s16debug.h"
@ -8,7 +9,7 @@
#pragma noroot #pragma noroot
#pragma optimize 79 #pragma optimize 79
// called through GSOS. // WriteGS, send, or sendto
int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5) int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5)
{ {
Word terr; Word terr;
@ -17,12 +18,48 @@ int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5)
char *buffer = (char *)p1; char *buffer = (char *)p1;
LongWord nbytes = *(LongWord *)p2; 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) if (Debug > 0)
{ {
s16_debug_printf("write nbytes = %ld", nbytes); 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? // 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(); IncBusy();
terr = TCPIPWriteTCP(e->ipid, buffer, nbytes, 0, 0); terr = TCPIPWriteTCP(e->ipid, buffer, nbytes, 0, 0);
t = _toolErr; t = _toolErr;
DecBusy();
if (t) terr = t; if (t) terr = t;
e->terr = terr;
DecBusy();
if (t || terr == tcperrBadConnection) if (t || terr == tcperrBadConnection)
return ENOTCONN; return ENOTCONN;
@ -42,14 +80,16 @@ int mwrite(Entry *e, void *p1, void *p2, void *p3, void *p4, void *p5)
if (terr == tcperrConClosing) if (terr == tcperrConClosing)
{ {
int xerrno;
if (!e->_NOSIGPIPE) if (!e->_NOSIGPIPE)
{
int xerrno;
Kkill(Kgetpid(), SIGPIPE, &xerrno); Kkill(Kgetpid(), SIGPIPE, &xerrno);
}
return EPIPE; return EPIPE;
} }
*(LongWord *)p2 = nbytes; *outbytes = nbytes;
return 0; return 0;
} }

View File

@ -208,8 +208,9 @@ void process_table(void)
{ {
case kCommandRead: case kCommandRead:
// block until data available. // block until data available.
if (e->sr.srRcvQueued >= e->cookie if (expired
|| expired || e->sr.srRcvQueued >= e->cookie
|| e->sr.srRcvQueued >= e->_RCVLOWAT
|| terr) || terr)
{ {
sig = 1; sig = 1;