/* uipc_socket.c 6.4 84/04/30 */
#include "../h/protosw.h"
#include "../h/socketvar.h"
#include "../net/route.h"
#include "../netinet/in.h"
* Socket operation routines.
* These routines are called by the routines in
* sys_socket.c or from a system process, and
* implement the semantics of socket operations by
* switching out to the protocol specific routines.
* out-of-band is a kludge
socreate(dom
, aso
, type
, proto
)
register struct protosw
*prp
;
register struct socket
*so
;
prp
= pffindproto(dom
, proto
);
prp
= pffindtype(dom
, type
);
return (EPROTONOSUPPORT
);
if (prp
->pr_type
!= type
)
m
= m_getclr(M_WAIT
, MT_SOCKET
);
so
= mtod(m
, struct socket
*);
(*prp
->pr_usrreq
)(so
, PRU_ATTACH
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0);
so
->so_state
|= SS_NOFDREF
;
(*so
->so_proto
->pr_usrreq
)(so
, PRU_BIND
,
(struct mbuf
*)0, nam
, (struct mbuf
*)0);
register struct socket
*so
;
(*so
->so_proto
->pr_usrreq
)(so
, PRU_LISTEN
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0);
so
->so_options
|= SO_ACCEPTCONN
;
so
->so_qlimit
= MIN(backlog
, SOMAXCONN
);
register struct socket
*so
;
if (!soqremque(so
, 0) && !soqremque(so
, 1))
if (so
->so_pcb
|| (so
->so_state
& SS_NOFDREF
) == 0)
* Close a socket on last file table reference removal.
* Initiate disconnect if connected.
* Free socket when disconnect complete.
register struct socket
*so
;
int s
= splnet(); /* conservative */
if (so
->so_options
& SO_ACCEPTCONN
) {
(void) soabort(so
->so_q0
);
(void) soabort(so
->so_q
);
if (so
->so_state
& SS_ISCONNECTED
) {
if ((so
->so_state
& SS_ISDISCONNECTING
) == 0) {
error
= sodisconnect(so
, (struct mbuf
*)0);
if (so
->so_options
& SO_LINGER
) {
if ((so
->so_state
& SS_ISDISCONNECTING
) &&
(so
->so_state
& SS_NBIO
))
while (so
->so_state
& SS_ISCONNECTED
)
sleep((caddr_t
)&so
->so_timeo
, PZERO
+1);
(*so
->so_proto
->pr_usrreq
)(so
, PRU_DETACH
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0);
if (so
->so_state
& SS_NOFDREF
)
panic("soclose: NOFDREF");
so
->so_state
|= SS_NOFDREF
;
* Must be called at splnet...
(*so
->so_proto
->pr_usrreq
)(so
, PRU_ABORT
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0));
register struct socket
*so
;
if ((so
->so_state
& SS_NOFDREF
) == 0)
panic("soaccept: !NOFDREF");
so
->so_state
&= ~SS_NOFDREF
;
error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_ACCEPT
,
(struct mbuf
*)0, nam
, (struct mbuf
*)0);
register struct socket
*so
;
if (so
->so_state
& (SS_ISCONNECTED
|SS_ISCONNECTING
)) {
error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_CONNECT
,
(struct mbuf
*)0, nam
, (struct mbuf
*)0);
register struct socket
*so1
;
error
= (*so1
->so_proto
->pr_usrreq
)(so1
, PRU_CONNECT2
,
(struct mbuf
*)0, (struct mbuf
*)so2
, (struct mbuf
*)0);
register struct socket
*so
;
if ((so
->so_state
& SS_ISCONNECTED
) == 0) {
if (so
->so_state
& SS_ISDISCONNECTING
) {
error
= (*so
->so_proto
->pr_usrreq
)(so
, PRU_DISCONNECT
,
(struct mbuf
*)0, nam
, (struct mbuf
*)0);
* If send must go all at once and message is larger than
* send buffering, then hard error.
* Lock against other senders.
* If must go all at once and not enough room now, then
* inform user that this would block and do nothing.
* Otherwise, if nonblocking, send as much as possible.
sosend(so
, nam
, uio
, flags
, rights
)
register struct socket
*so
;
register struct uio
*uio
;
register struct mbuf
*m
, **mp
;
int len
, error
= 0, s
, dontroute
, first
= 1;
if (sosendallatonce(so
) && uio
->uio_resid
> so
->so_snd
.sb_hiwat
)
(flags
& MSG_DONTROUTE
) && (so
->so_options
& SO_DONTROUTE
) == 0 &&
(so
->so_proto
->pr_flags
& PR_ATOMIC
);
#define snderr(errno) { error = errno; splx(s); goto release; }
if (so
->so_state
& SS_CANTSENDMORE
) {
psignal(u
.u_procp
, SIGPIPE
);
so
->so_error
= 0; /* ??? */
if ((so
->so_state
& SS_ISCONNECTED
) == 0) {
if (so
->so_proto
->pr_flags
& PR_CONNREQUIRED
)
space
= sbspace(&so
->so_snd
);
sosendallatonce(so
) && space
< uio
->uio_resid
) {
if (so
->so_state
& SS_NBIO
) {
while (uio
->uio_resid
> 0 && space
> 0) {
register struct iovec
*iov
= uio
->uio_iov
;
MGET(m
, M_WAIT
, MT_DATA
);
error
= ENOBUFS
; /* SIGPIPE? */
if (iov
->iov_len
>= CLBYTES
&& space
>= CLBYTES
) {
m
->m_off
= (int)p
- (int)m
;
len
= MIN(MLEN
, iov
->iov_len
);
error
= uiomove(mtod(m
, caddr_t
), len
, UIO_WRITE
, uio
);
so
->so_options
|= SO_DONTROUTE
;
error
= (*so
->so_proto
->pr_usrreq
)(so
,
(flags
& MSG_OOB
) ? PRU_SENDOOB
: PRU_SEND
,
top
, (caddr_t
)nam
, rights
);
so
->so_options
&= ~SO_DONTROUTE
;
} while (uio
->uio_resid
);
soreceive(so
, aname
, uio
, flags
, rightsp
)
register struct socket
*so
;
register struct uio
*uio
;
register struct mbuf
*m
, *n
;
register int len
, error
= 0, s
, eor
, tomark
;
struct protosw
*pr
= so
->so_proto
;
m
= m_get(M_WAIT
, MT_DATA
);
error
= (*pr
->pr_usrreq
)(so
, PRU_RCVOOB
,
m
, (struct mbuf
*)0, (struct mbuf
*)0);
uiomove(mtod(m
, caddr_t
), (int)len
, UIO_READ
, uio
);
} while (uio
->uio_resid
&& error
== 0 && m
);
#define rcverr(errno) { error = errno; splx(s); goto release; }
if (so
->so_rcv
.sb_cc
== 0) {
if (so
->so_state
& SS_CANTRCVMORE
) {
if ((so
->so_state
& SS_ISCONNECTED
) == 0 &&
(so
->so_proto
->pr_flags
& PR_CONNREQUIRED
))
if (so
->so_state
& SS_NBIO
)
if (pr
->pr_flags
& PR_ADDR
) {
if ((flags
& MSG_PEEK
) == 0) {
so
->so_rcv
.sb_cc
-= m
->m_len
;
so
->so_rcv
.sb_mbcnt
-= MSIZE
;
*aname
= m_copy(m
, 0, m
->m_len
);
*rightsp
= m_copy(m
, 0, m
->m_len
);
*rightsp
= m_get(M_DONTWAIT
, MT_SONAME
);
so
->so_rcv
.sb_cc
-= m
->m_len
;
so
->so_rcv
.sb_mbcnt
-= MSIZE
;
if ((flags
& MSG_PEEK
) == 0)
so
->so_state
&= ~SS_RCVATMARK
;
if (tomark
&& len
> tomark
)
if (moff
+len
> m
->m_len
- moff
)
uiomove(mtod(m
, caddr_t
) + moff
, (int)len
, UIO_READ
, uio
);
if ((flags
& MSG_PEEK
) == 0 && so
->so_oobmark
) {
if (so
->so_oobmark
== 0) {
so
->so_state
|= SS_RCVATMARK
;
} while (m
&& error
== 0 && !eor
);
if ((so
->so_proto
->pr_flags
& PR_ATOMIC
) && eor
== 0)
so
->so_rcv
.sb_mb
= m
->m_next
;
if ((so
->so_proto
->pr_flags
& PR_WANTRCVD
) && so
->so_pcb
)
(*so
->so_proto
->pr_usrreq
)(so
, PRU_RCVD
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0);
if (error
== 0 && rightsp
&&
*rightsp
&& so
->so_proto
->pr_family
== AF_UNIX
)
error
= unp_externalize(*rightsp
);
register struct socket
*so
;
register struct protosw
*pr
= so
->so_proto
;
return ((*pr
->pr_usrreq
)(so
, PRU_SHUTDOWN
,
(struct mbuf
*)0, (struct mbuf
*)0, (struct mbuf
*)0));
register struct socket
*so
;
register struct sockbuf
*sb
= &so
->so_rcv
;
register struct protosw
*pr
= so
->so_proto
;
bzero((caddr_t
)sb
, sizeof (*sb
));
if (pr
->pr_family
== AF_UNIX
&& (pr
->pr_flags
& PR_RIGHTS
))
unp_scan(asb
.sb_mb
, unp_discard
);
sosetopt(so
, level
, optname
, m
)
register struct socket
*so
;
return (EINVAL
); /* XXX */
so
->so_options
|= optname
;
if (m
== NULL
|| m
->m_len
!= sizeof (int))
so
->so_options
|= SO_LINGER
;
so
->so_linger
= *mtod(m
, int *);
so
->so_options
&= ~SO_LINGER
;
sogetopt(so
, level
, optname
, m
)
register struct socket
*so
;
return (EINVAL
); /* XXX */
if ((so
->so_options
& optname
) == 0)
if (optname
== SO_LINGER
&& m
!= NULL
) {
*mtod(m
, int *) = so
->so_linger
;
m
->m_len
= sizeof (so
->so_linger
);
register struct socket
*so
;
gsignal(so
->so_pgrp
, SIGURG
);
struct proc
*p
= pfind(-so
->so_pgrp
);