FreeBSD/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
/*
 * Send on a socket.  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.  The data to be sent is described by "uio" if nonzero, otherwise
 * by the mbuf chain "top" (which must be null if uio is not).  Data provided
 * in mbuf chain must be small enough to send all at once.
 *
 * Returns nonzero on error, timeout or signal; callers must check for short
 * counts if EINTR/ERESTART are returned.  Data and control buffers are freed
 * on return.
 */
Send on a socket.  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.  The data to be sent is described by "uio" if nonzero, otherwise
by the mbuf chain "top" (which must be null if uio is not).  Data provided
in mbuf chain must be small enough to send all at once.

Returns nonzero on error, timeout or signal; callers must check for short
counts if EINTR/ERESTART are returned.  Data and control buffers are freed
on return.
Send on a socket . 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 . The data to be sent is described by " uio " if nonzero otherwise by the mbuf chain " top " ( which must be null if uio is not ) . Data provided in mbuf chain must be small enough to send all at once . Returns nonzero on error timeout or signal ; callers must check for short counts if EINTR / ERESTART are returned . Data and control buffers are freed on return .
static int
sdp_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,
    struct mbuf *top, struct mbuf *control, int flags, struct thread *td)
{
	struct sdp_sock *ssk;
	long space, resid;
	int atomic;
	int error;
	int copy;
	if (uio != NULL)
		resid = uio->uio_resid;
	else
		resid = top->m_pkthdr.len;
	atomic = top != NULL;
	if (control != NULL) {
		if (control->m_len) {
			m_freem(control);
			if (top)
				m_freem(top);
			return (EINVAL);
		}
		m_freem(control);
		control = NULL;
	}
	if (resid < 0 || (so->so_type == SOCK_STREAM && (flags & MSG_EOR))) {
		error = EINVAL;
		goto out;
	}
	if (td != NULL)
		td->td_ru.ru_msgsnd++;
	ssk = sdp_sk(so);
	error = sblock(&so->so_snd, SBLOCKWAIT(flags));
	if (error)
		goto out;
restart:
	do {
		SOCKBUF_LOCK(&so->so_snd);
		if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
			SOCKBUF_UNLOCK(&so->so_snd);
			error = EPIPE;
			goto release;
		}
		if (so->so_error) {
			error = so->so_error;
			so->so_error = 0;
			SOCKBUF_UNLOCK(&so->so_snd);
			goto release;
		}
		if ((so->so_state & SS_ISCONNECTED) == 0 && addr == NULL) {
			SOCKBUF_UNLOCK(&so->so_snd);
			error = ENOTCONN;
			goto release;
		}
		space = sbspace(&so->so_snd);
		if (flags & MSG_OOB)
			space += 1024;
		if (atomic && resid > ssk->xmit_size_goal - SDP_HEAD_SIZE) {
			SOCKBUF_UNLOCK(&so->so_snd);
			error = EMSGSIZE;
			goto release;
		}
		if (space < resid &&
		    (atomic || space < so->so_snd.sb_lowat)) {
			if ((so->so_state & SS_NBIO) || (flags & MSG_NBIO)) {
				SOCKBUF_UNLOCK(&so->so_snd);
				error = EWOULDBLOCK;
				goto release;
			}
			error = sbwait(&so->so_snd);
			SOCKBUF_UNLOCK(&so->so_snd);
			if (error)
				goto release;
			goto restart;
		}
		SOCKBUF_UNLOCK(&so->so_snd);
		do {
			if (uio == NULL) {
				resid = 0;
				if (flags & MSG_EOR)
					top->m_flags |= M_EOR;
			} else {
				copy = min(space,
				    ssk->xmit_size_goal - SDP_HEAD_SIZE);
				top = m_uiotombuf(uio, M_WAITOK, copy,
				    0, M_PKTHDR |
				    ((flags & MSG_EOR) ? M_EOR : 0));
				if (top == NULL) {
					error = EFAULT;
					goto release;
				}
				space -= resid - uio->uio_resid;
				resid = uio->uio_resid;
			}
			error = sdp_send(so, (flags & MSG_OOB) ? PRUS_OOB :
			    ((flags & MSG_EOF) && (resid <= 0)) ? PRUS_EOF :
			    (resid > 0 && space > 0) ? PRUS_MORETOCOME : 0,
			    top, addr, NULL, td);
			top = NULL;
			if (error)
				goto release;
		} while (resid && space > 0);
	} while (resid);
release:
	sbunlock(&so->so_snd);
out:
	if (top != NULL)
		m_freem(top);
	return (error);
}
static int sdp_sosend ( struct socket * so , struct sockaddr * addr , struct uio * uio , struct mbuf * top , struct mbuf * control , int flags , struct thread * td ) { struct sdp_sock * ssk ; long space , resid ; int atomic ; int error ; int copy ; if ( uio != NULL ) resid = uio -> uio_resid ; else resid = top -> m_pkthdr . len ; atomic = top != NULL ; if ( control != NULL ) { if ( control -> m_len ) { m_freem ( control ) ; if ( top ) m_freem ( top ) ; return ( EINVAL ) ; } m_freem ( control ) ; control = NULL ; } if ( resid < 0 || ( so -> so_type == SOCK_STREAM && ( flags & MSG_EOR ) ) ) { error = EINVAL ; goto out ; } if ( td != NULL ) td -> td_ru . ru_msgsnd ++ ; ssk = sdp_sk ( so ) ; error = sblock ( & so -> so_snd , SBLOCKWAIT ( flags ) ) ; if ( error ) goto out ; restart : do { SOCKBUF_LOCK ( & so -> so_snd ) ; if ( so -> so_snd . sb_state & SBS_CANTSENDMORE ) { SOCKBUF_UNLOCK ( & so -> so_snd ) ; error = EPIPE ; goto release ; } if ( so -> so_error ) { error = so -> so_error ; so -> so_error = 0 ; SOCKBUF_UNLOCK ( & so -> so_snd ) ; goto release ; } if ( ( so -> so_state & SS_ISCONNECTED ) == 0 && addr == NULL ) { SOCKBUF_UNLOCK ( & so -> so_snd ) ; error = ENOTCONN ; goto release ; } space = sbspace ( & so -> so_snd ) ; if ( flags & MSG_OOB ) space += 1024 ; if ( atomic && resid > ssk -> xmit_size_goal - SDP_HEAD_SIZE ) { SOCKBUF_UNLOCK ( & so -> so_snd ) ; error = EMSGSIZE ; goto release ; } if ( space < resid && ( atomic || space < so -> so_snd . sb_lowat ) ) { if ( ( so -> so_state & SS_NBIO ) || ( flags & MSG_NBIO ) ) { SOCKBUF_UNLOCK ( & so -> so_snd ) ; error = EWOULDBLOCK ; goto release ; } error = sbwait ( & so -> so_snd ) ; SOCKBUF_UNLOCK ( & so -> so_snd ) ; if ( error ) goto release ; goto restart ; } SOCKBUF_UNLOCK ( & so -> so_snd ) ; do { if ( uio == NULL ) { resid = 0 ; if ( flags & MSG_EOR ) top -> m_flags |= M_EOR ; } else { copy = min ( space , ssk -> xmit_size_goal - SDP_HEAD_SIZE ) ; top = m_uiotombuf ( uio , M_WAITOK , copy , 0 , M_PKTHDR | ( ( flags & MSG_EOR ) ? M_EOR : 0 ) ) ; if ( top == NULL ) { error = EFAULT ; goto release ; } space -= resid - uio -> uio_resid ; resid = uio -> uio_resid ; } error = sdp_send ( so , ( flags & MSG_OOB ) ? PRUS_OOB : ( ( flags & MSG_EOF ) && ( resid <= 0 ) ) ? PRUS_EOF : ( resid > 0 && space > 0 ) ? PRUS_MORETOCOME : 0 , top , addr , NULL , td ) ; top = NULL ; if ( error ) goto release ; } while ( resid && space > 0 ) ; } while ( resid ) ; release : sbunlock ( & so -> so_snd ) ; out : if ( top != NULL ) m_freem ( top ) ; return ( error ) ; }
Send on a socket.
Send on a socket .
/*
	 * In theory resid should be unsigned.  However, space must be
	 * signed, as it might be less than 0 if we over-committed, and we
	 * must use a signed comparison of space and resid.  On the other
	 * hand, a negative resid causes us to loop sending 0-length
	 * segments to the protocol.
	 *
	 * Also check to make sure that MSG_EOR isn't used on SOCK_STREAM
	 * type sockets since that's an error.
	 */ /*
				 * Copy the data from userland into a mbuf
				 * chain.  If no data is to be copied in,
				 * a single empty mbuf is returned.
				 */ /* only possible error */ /*
			 * XXX all the SBS_CANTSENDMORE checks previously
			 * done could be out of date after dropping the
			 * socket lock.
			 */ /*
			 * Set EOF on the last send if the user specified
			 * MSG_EOF.
			 */ /* If there is more to send set PRUS_MORETOCOME. */