Main changes: reimported uipc_socket.c which had lots of differences with

freebsd.
Fixed: OskitTCPReceive.  Now rely exclusively on uio as suggested.

svn path=/trunk/; revision=10992
This commit is contained in:
Art Yerkes 2004-09-23 06:39:16 +00:00
parent bb9e009623
commit 36cc9bb181
2 changed files with 319 additions and 97 deletions

View file

@ -108,35 +108,37 @@ int OskitTCPRecv( void *connection,
OSK_UINT Len,
OSK_UINT *OutLen,
OSK_UINT Flags ) {
struct mbuf *paddr = 0;
struct mbuf m, *mp;
char *output_ptr = Data;
struct uio uio = { 0 };
struct iovec iov = { 0 };
int error = 0;
int tcp_flags = 0;
int tocopy = 0;
*OutLen = 0;
if( Flags & OSK_MSG_OOB ) tcp_flags |= MSG_OOB;
if( Flags & OSK_MSG_DONTWAIT ) tcp_flags |= MSG_DONTWAIT;
if( Flags & OSK_MSG_PEEK ) tcp_flags |= MSG_PEEK;
uio.uio_resid = Len;
m.m_len = Len;
m.m_data = Data;
m.m_type = MT_DATA;
m.m_flags = M_PKTHDR | M_EOR;
mp = &m;
uio.uio_iov = &iov;
uio.uio_rw = UIO_READ;
uio.uio_iovcnt = 1;
iov.iov_len = Len;
iov.iov_base = Data;
OS_DbgPrint(OSK_MID_TRACE,("Reading %d bytes from TCP:\n", Len));
error = soreceive( connection, &paddr, &uio, &mp, NULL /* SCM_RIGHTS */,
error = soreceive( connection, NULL, &uio, NULL, NULL /* SCM_RIGHTS */,
&tcp_flags );
if( error == 0 ) {
OS_DbgPrint(OSK_MID_TRACE,("Successful read from TCP:\n"));
OskitDumpBuffer( m.m_data, uio.uio_resid );
*OutLen = Len - uio.uio_resid;
OskitDumpBuffer( Data, *OutLen );
}
*OutLen = uio.uio_resid;
return error;
}

View file

@ -76,8 +76,6 @@ socreate(dom, aso, type, proto)
register struct socket *so;
register int error;
printf("socreate(%d,%x,%d,%d)\n", dom, aso, type, proto);
if (proto)
prp = pffindproto(dom, proto, type);
else
@ -89,6 +87,10 @@ socreate(dom, aso, type, proto)
MALLOC(so, struct socket *, sizeof(*so), M_SOCKET, M_WAIT);
bzero((caddr_t)so, sizeof(*so));
so->so_type = type;
#ifndef __REACTOS__
if (p->p_ucred->cr_uid == 0)
so->so_state = SS_PRIV;
#endif
so->so_proto = prp;
error =
(*prp->pr_usrreq)(so, PRU_ATTACH,
@ -356,7 +358,9 @@ sosend(so, addr, uio, top, control, flags)
dontroute =
(flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
(so->so_proto->pr_flags & PR_ATOMIC);
/* p->p_stats->p_ru.ru_msgsnd++; */
#ifndef __REACTOS__
p->p_stats->p_ru.ru_msgsnd++;
#endif
if (control)
clen = control->m_len;
#define snderr(errno) { error = errno; splx(s); goto release; }
@ -486,13 +490,10 @@ nopages:
release:
sbunlock(so, &so->so_snd);
out:
#ifndef __REACTOS__
if (top)
m_freem(top);
m_freem(top);
if (control)
m_freem(control);
#endif /* The caller owns top and control */
OS_DbgPrint(OSK_MID_TRACE,("Leaving\n"));
m_freem(control);
return (error);
}
@ -513,91 +514,306 @@ out:
* only for the count in uio_resid.
*/
int
soreceive(so, paddr, uio, _mp0, controlp, flagsp)
soreceive(so, paddr, uio, mp0, controlp, flagsp)
register struct socket *so;
struct mbuf **paddr;
struct uio *uio;
struct mbuf **_mp0;
struct mbuf **mp0;
struct mbuf **controlp;
int *flagsp;
{
struct mbuf dummy = { 0 };
struct mbuf *mb = &dummy, *mn, *mp0 = *_mp0;
int total = 0, copyamt;
register struct mbuf *m, **mp;
register int flags, len, error, s, offset;
struct protosw *pr = so->so_proto;
struct mbuf *nextrecord;
int moff, type = 0;
int orig_resid = uio->uio_resid;
dummy.m_nextpkt = so->so_rcv.sb_mb;
uio->uio_resid = 0;
mp = mp0;
if (paddr)
*paddr = 0;
if (controlp)
*controlp = 0;
if (flagsp)
flags = *flagsp &~ MSG_EOR;
else
flags = 0;
if (flags & MSG_OOB) {
m = m_get(M_WAIT, MT_DATA);
error = (*pr->pr_usrreq)(so, PRU_RCVOOB,
m, (struct mbuf *)(flags & MSG_PEEK), (struct mbuf *)0);
if (error)
goto bad;
do {
error = uiomove(mtod(m, caddr_t),
(int) min(uio->uio_resid, m->m_len), uio);
m = m_free(m);
} while (uio->uio_resid && error == 0 && m);
bad:
if (m)
m_freem(m);
return (error);
}
if (mp)
*mp = (struct mbuf *)0;
if (so->so_state & SS_ISCONFIRMING && uio->uio_resid)
(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
(struct mbuf *)0, (struct mbuf *)0);
if( mp0->m_len == 0 )
return 0;
restart:
error = sblock(&so->so_rcv, SBLOCKWAIT(flags));
if (error)
return (error);
s = splnet();
if( so->so_rcv.sb_cc == 0 &&
/*so->so_rcv.sb_sel.si_flags & SEL_FIN*/
(so->so_state & SS_CANTRCVMORE) ) {
OS_DbgPrint(OSK_MID_TRACE, ("Receive: SEL_FIN\n"));
return OSK_ESHUTDOWN;
}
while( mb->m_nextpkt && total < mp0->m_len ) {
OS_DbgPrint(OSK_MID_TRACE, ("Looking at packet %x\n", mb));
if( *flagsp & MSG_OOB ) {
OS_DbgPrint(OSK_MID_TRACE, ("Searching for oob: %x\n", mb));
while( mb->m_nextpkt && mb->m_nextpkt->m_type != MT_OOBDATA )
mb = mb->m_nextpkt;
} else {
while( mb->m_nextpkt && mb->m_nextpkt->m_type != MT_DATA ) {
OS_DbgPrint
(OSK_MID_TRACE,
("Searching for data: %x (%x@%x)\n",
mb->m_nextpkt->m_type,
mb->m_nextpkt->m_len,
mb->m_nextpkt->m_data));
mb = mb->m_nextpkt;
}
m = so->so_rcv.sb_mb;
/*
* If we have less data than requested, block awaiting more
* (subject to any timeout) if:
* 1. the current count is less than the low water mark, or
* 2. MSG_WAITALL is set, and it is possible to do the entire
* receive operation at once if we block (resid <= hiwat).
* 3. MSG_DONTWAIT is not set
* If MSG_WAITALL is set but resid is larger than the receive buffer,
* we have to do the receive in sections, and thus risk returning
* a short count if a timeout or signal occurs after we start.
*/
if (m == 0 || (((flags & MSG_DONTWAIT) == 0 &&
so->so_rcv.sb_cc < uio->uio_resid) &&
(so->so_rcv.sb_cc < so->so_rcv.sb_lowat ||
((flags & MSG_WAITALL) && uio->uio_resid <= so->so_rcv.sb_hiwat)) &&
m->m_nextpkt == 0 && (pr->pr_flags & PR_ATOMIC) == 0)) {
#ifdef DIAGNOSTIC
if (m == 0 && so->so_rcv.sb_cc)
panic("receive 1");
#endif
if (so->so_error) {
if (m)
goto dontblock;
error = so->so_error;
if ((flags & MSG_PEEK) == 0)
so->so_error = 0;
goto release;
}
if (so->so_state & SS_CANTRCVMORE) {
if (m)
goto dontblock;
else
goto release;
}
for (; m; m = m->m_next)
if (m->m_type == MT_OOBDATA || (m->m_flags & M_EOR)) {
m = so->so_rcv.sb_mb;
goto dontblock;
}
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) == 0 &&
(so->so_proto->pr_flags & PR_CONNREQUIRED)) {
error = ENOTCONN;
goto release;
}
if (uio->uio_resid == 0)
goto release;
if ((so->so_state & SS_NBIO) || (flags & MSG_DONTWAIT)) {
error = EWOULDBLOCK;
goto release;
}
sbunlock(so, &so->so_rcv);
error = sbwait(&so->so_rcv);
splx(s);
if (error)
return (error);
goto restart;
}
dontblock:
if (uio->uio_procp)
uio->uio_procp->p_stats->p_ru.ru_msgrcv++;
nextrecord = m->m_nextpkt;
if (pr->pr_flags & PR_ADDR) {
#ifdef DIAGNOSTIC
if (m->m_type != MT_SONAME)
panic("receive 1a");
#endif
orig_resid = 0;
if (flags & MSG_PEEK) {
if (paddr)
*paddr = m_copy(m, 0, m->m_len);
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
if (paddr) {
*paddr = m;
so->so_rcv.sb_mb = m->m_next;
m->m_next = 0;
m = so->so_rcv.sb_mb;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
}
}
while (m && m->m_type == MT_CONTROL && error == 0) {
if (flags & MSG_PEEK) {
if (controlp)
*controlp = m_copy(m, 0, m->m_len);
m = m->m_next;
} else {
sbfree(&so->so_rcv, m);
#ifndef __REACTOS__
if (controlp) {
if (pr->pr_domain->dom_externalize &&
mtod(m, struct cmsghdr *)->cmsg_type ==
SCM_RIGHTS)
error = (*pr->pr_domain->dom_externalize)(m);
*controlp = m;
so->so_rcv.sb_mb = m->m_next;
m->m_next = 0;
m = so->so_rcv.sb_mb;
} else
#endif
{
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
}
if (controlp) {
orig_resid = 0;
controlp = &(*controlp)->m_next;
}
}
if (m) {
if ((flags & MSG_PEEK) == 0)
m->m_nextpkt = nextrecord;
type = m->m_type;
if (type == MT_OOBDATA)
flags |= MSG_OOB;
}
moff = 0;
offset = 0;
while (m && uio->uio_resid > 0 && error == 0) {
if (m->m_type == MT_OOBDATA) {
if (type != MT_OOBDATA)
break;
} else if (type == MT_OOBDATA)
break;
#ifdef DIAGNOSTIC
else if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
panic("receive 3");
#endif
so->so_state &= ~SS_RCVATMARK;
len = uio->uio_resid;
if (so->so_oobmark && len > so->so_oobmark - offset)
len = so->so_oobmark - offset;
if (len > m->m_len - moff)
len = m->m_len - moff;
/*
* If mp is set, just pass back the mbufs.
* Otherwise copy them out via the uio, then free.
* Sockbuf must be consistent here (points to current mbuf,
* it points to next record) when we drop priority;
* we must note any additions to the sockbuf when we
* block interrupts again.
*/
if (mp == 0) {
splx(s);
error = uiomove(mtod(m, caddr_t) + moff, (int)len, uio);
s = splnet();
} else
uio->uio_resid -= len;
if (len == m->m_len - moff) {
if (m->m_flags & M_EOR)
flags |= MSG_EOR;
if (flags & MSG_PEEK) {
m = m->m_next;
moff = 0;
} else {
nextrecord = m->m_nextpkt;
sbfree(&so->so_rcv, m);
if (mp) {
*mp = m;
mp = &m->m_next;
so->so_rcv.sb_mb = m = m->m_next;
*mp = (struct mbuf *)0;
} else {
MFREE(m, so->so_rcv.sb_mb);
m = so->so_rcv.sb_mb;
}
if (m)
m->m_nextpkt = nextrecord;
}
} else {
if (flags & MSG_PEEK)
moff += len;
else {
if (mp)
*mp = m_copym(m, 0, len, M_WAIT);
m->m_data += len;
m->m_len -= len;
so->so_rcv.sb_cc -= len;
}
}
if (so->so_oobmark) {
if ((flags & MSG_PEEK) == 0) {
so->so_oobmark -= len;
if (so->so_oobmark == 0) {
so->so_state |= SS_RCVATMARK;
break;
}
} else {
offset += len;
if (offset == so->so_oobmark)
break;
}
}
if (flags & MSG_EOR)
break;
/*
* If the MSG_WAITALL flag is set (for non-atomic socket),
* we must not quit until "uio->uio_resid == 0" or an error
* termination. If a signal/timeout occurs, return
* with a short count but without error.
* Keep sockbuf locked against other readers.
*/
while (flags & MSG_WAITALL && m == 0 && uio->uio_resid > 0 &&
!sosendallatonce(so) && !nextrecord) {
if (so->so_error || so->so_state & SS_CANTRCVMORE)
break;
error = sbwait(&so->so_rcv);
if (error) {
sbunlock(so, &so->so_rcv);
splx(s);
return (0);
}
m = so->so_rcv.sb_mb;
if (m)
nextrecord = m->m_nextpkt;
}
}
if( !mb->m_nextpkt ) break;
mn = mb->m_nextpkt;
if( !mn->m_next ) mn->m_next = mn->m_data;
copyamt = min(mn->m_len, mp0->m_len);
OS_DbgPrint(OSK_MID_TRACE,
("Copying %d bytes (%d,%d) (total is %d so far)\n",
copyamt, mn->m_len, mp0->m_len, total + copyamt));
memcpy( mp0->m_data + total, mn->m_next, copyamt );
total += copyamt;
mp0->m_len -= copyamt;
if( copyamt < mn->m_len ) {
if( !(*flagsp & MSG_PEEK) )
((caddr_t)mn->m_next) += copyamt;
break;
}
mb->m_nextpkt = mn->m_nextpkt;
}
/* Free previous buffers if not peek */
if( !(*flagsp & MSG_PEEK) ) {
while( dummy.m_nextpkt && dummy.m_nextpkt != mn ) {
mb = dummy.m_nextpkt;
dummy.m_nextpkt = mb->m_nextpkt;
OS_DbgPrint
(OSK_MID_TRACE,
("Deleting buf %x", mb));
m_free(mb);
if (m && pr->pr_flags & PR_ATOMIC) {
flags |= MSG_TRUNC;
if ((flags & MSG_PEEK) == 0)
(void) sbdroprecord(&so->so_rcv);
}
if ((flags & MSG_PEEK) == 0) {
if (m == 0)
so->so_rcv.sb_mb = nextrecord;
if (pr->pr_flags & PR_WANTRCVD && so->so_pcb)
(*pr->pr_usrreq)(so, PRU_RCVD, (struct mbuf *)0,
(struct mbuf *)flags, (struct mbuf *)0);
}
if (orig_resid == uio->uio_resid && orig_resid &&
(flags & MSG_EOR) == 0 && (so->so_state & SS_CANTRCVMORE) == 0) {
sbunlock(so, &so->so_rcv);
splx(s);
goto restart;
}
so->so_rcv.sb_cc -= total;
so->so_rcv.sb_mb = dummy.m_nextpkt;
}
uio->uio_resid = total;
OS_DbgPrint(OSK_MID_TRACE,("Leaving (success: %d bytes)\n", total));
return 0;
if (flagsp)
*flagsp |= flags;
release:
sbunlock(so, &so->so_rcv);
splx(s);
return (error);
}
int
@ -669,7 +885,7 @@ sosetopt(so, level, optname, m0)
case SO_USELOOPBACK:
case SO_BROADCAST:
case SO_REUSEADDR:
/*case SO_REUSEPORT:*/
case SO_REUSEPORT:
case SO_OOBINLINE:
if (m == NULL || m->m_len < sizeof (int)) {
error = EINVAL;
@ -751,7 +967,7 @@ sosetopt(so, level, optname, m0)
}
bad:
if (m)
(void) m_free(m);
(void) m_free(m);
return (error);
}
@ -787,7 +1003,7 @@ sogetopt(so, level, optname, mp)
case SO_DEBUG:
case SO_KEEPALIVE:
case SO_REUSEADDR:
/*case SO_REUSEPORT: */
case SO_REUSEPORT:
case SO_BROADCAST:
case SO_OOBINLINE:
*mtod(m, int *) = so->so_options & optname;
@ -832,8 +1048,8 @@ sogetopt(so, level, optname, mp)
}
default:
(void)m_free(m);
return (ENOPROTOOPT);
(void)m_free(m);
return (ENOPROTOOPT);
}
*mp = m;
return (0);
@ -850,5 +1066,9 @@ sohasoutofband(so)
gsignal(-so->so_pgid, SIGURG);
else if (so->so_pgid > 0 && (p = pfind(so->so_pgid)) != 0)
psignal(p, SIGURG);
wakeup(so, 0);
#ifndef __REACTOS__
selwakeup(so, &so->so_rcv.sb_sel);
#else
sorwakeup(so);
#endif
}