📄 bsdsocklib.c
字号:
bsdSockAddrRevert (from); } } if (mfrom != NULL) m_freem (mfrom); splx (spl); if (status) { if (usrIo.uio_resid != len && (status == EINTR || status == EWOULDBLOCK)) status = OK; } return (status == OK ? (len - usrIo.uio_resid) : ERROR); }/********************************************************************************* bsdRecv - receive data from a socket** This routine receives data from a connection-based (stream) socket.** The maximum length of <buf> is subject to the limits on TCP buffer* size; see the discussion of SO_RCVBUF in the setsockopt() manual* entry.* * RETURNS* The number of bytes received, or ERROR if the call fails.* * SEE ALSO* setsockopt()** NOMANUAL*/int recv ( FAST int s, /* socket to receive data from */ FAST char *buf, /* buffer to write data to */ FAST int bufLen, /* length of buffer */ FAST int flags /* flags to underlying protocols */ ) { FAST struct socket *so; FAST int spl; FAST int status; int len; struct uio usrIo; /* user IO structure */ struct iovec ioVec; /* IO vector structure */ int soFlags; struct mbuf ** ppRcvMbuf = NULL; /* for zero copy interface */ /* extract the socket from the fd */ if ((so = (struct socket *) iosFdValue (s)) == (struct socket *) ERROR) return (ERROR);#ifdef VIRTUAL_STACK if (stackInstFromSockVsidSet (s) != OK) return (ERROR);#endif /* VIRTUAL_STACK */ spl = splnet (); usrIo.uio_iov = &ioVec; usrIo.uio_iovcnt = 1; usrIo.uio_offset = 0; usrIo.uio_resid = bufLen; usrIo.uio_segflg = UIO_USERSPACE; usrIo.uio_rw = UIO_READ; ioVec.iov_base = (caddr_t) buf; ioVec.iov_len = bufLen; soFlags = flags; if (flags & MSG_MBUF) /* if zero copy interface enabled */ ppRcvMbuf = (struct mbuf **)buf; len = usrIo.uio_resid; status = soreceive (so, (struct mbuf **)NULL, &usrIo, ppRcvMbuf, (struct mbuf **)0, &soFlags); splx (spl); if (status) { if (usrIo.uio_resid != len && (status == EINTR || status == EWOULDBLOCK)) status = OK; } return (status == OK ? (len - usrIo.uio_resid) : ERROR); }/********************************************************************************* bsdSockRead - read from a socket** bsdSockRead is called by the I/O system to do a read on a socket.*/LOCAL int bsdSockRead ( FAST struct socket *so, FAST caddr_t buf, FAST int bufLen ) { FAST int spl; FAST int status; int len; struct uio usrIo; /* user IO structure */ struct iovec ioVec; /* IO vector structure */ int soFlags = 0;#ifdef VIRTUAL_STACK if (stackInstFromSockVsidSet (so->so_fd) != OK) return (ERROR);#endif /* VIRTUAL_STACK */ spl = splnet (); usrIo.uio_iov = &ioVec; usrIo.uio_iovcnt = 1; usrIo.uio_offset = 0; usrIo.uio_resid = bufLen; usrIo.uio_segflg = UIO_USERSPACE; usrIo.uio_rw = UIO_READ; ioVec.iov_base = (caddr_t) buf; ioVec.iov_len = bufLen; len = usrIo.uio_resid; status = soreceive (so, (struct mbuf **)NULL, &usrIo, (struct mbuf **)0, (struct mbuf **)0, &soFlags); splx (spl); if (status) { if (usrIo.uio_resid != len && (status == EINTR || status == EWOULDBLOCK)) status = OK; } return (status == OK ? (len - usrIo.uio_resid) : ERROR); }/********************************************************************************* bsdRecvmsg - receive a message from a socket** This routine receives a message from a datagram socket. It may be used in* place of recvfrom() to decrease the overhead of breaking down the* message-header structure `msghdr' for each message.** RETURNS* The number of bytes received, or ERROR if the call fails.** NOMANUAL*/int recvmsg ( int sd, /* socket to receive from */ struct msghdr *mp, /* scatter-gather message header */ int flags /* flags to underlying protocols */ ) { FAST struct iovec *iov; FAST struct iovec * pIovCopy; /* kernel copy of user iov */ FAST int ix; caddr_t namelenp; caddr_t controllenp; struct socket *so; struct uio auio; struct iovec aiov [UIO_SMALLIOV]; /* use stack for small user iov */ struct mbuf *from = NULL; struct mbuf *control = NULL; int len; int status; int slev; BOOL mallocedIov; /* TRUE if kernel iov copy malloced */ /* from system pool */ int recvLen; /* length of received message */ if (flags & MSG_MBUF) { netErrnoSet (EINVAL); return (ERROR); /* mbuf uio not supported */ } /* extract the socket from the fd */ if ((so = (struct socket *) iosFdValue (sd)) == (struct socket *) ERROR) return (ERROR);#ifdef VIRTUAL_STACK if (stackInstFromSockVsidSet (sd) != OK) return (ERROR);#endif /* VIRTUAL_STACK */ /* allocate space to copy user struct iovec */ if (mp->msg_iovlen >= UIO_SMALLIOV) { if (mp->msg_iovlen >= UIO_MAXIOV) { netErrnoSet (EMSGSIZE); return (ERROR); } MALLOC (pIovCopy, struct iovec *, sizeof (struct iovec) * mp->msg_iovlen, MT_DATA, M_WAIT); if (pIovCopy == NULL) { netErrnoSet (ENOBUFS); return (ERROR); } mallocedIov = TRUE; } else { pIovCopy = aiov; mallocedIov = FALSE; } slev = splnet (); namelenp = (caddr_t) &mp->msg_namelen; controllenp = (caddr_t) &mp->msg_controllen; mp->msg_flags = flags; auio.uio_iov = pIovCopy; auio.uio_iovcnt = mp->msg_iovlen; auio.uio_segflg = UIO_USERSPACE; auio.uio_offset = 0; auio.uio_resid = 0; auio.uio_rw = UIO_READ; iov = mp->msg_iov; for (ix = 0; ix < mp->msg_iovlen; ix++, iov++) { if (iov->iov_len < 0) { netErrnoSet (EINVAL); splx (slev); if (mallocedIov) { FREE (pIovCopy, MT_DATA); } return (ERROR); } if (iov->iov_len == 0) continue; pIovCopy->iov_len = iov->iov_len; pIovCopy->iov_base = iov->iov_base; pIovCopy++; auio.uio_resid += iov->iov_len; } /* Save a pointer to struct iovec copy */ pIovCopy = auio.uio_iov; len = auio.uio_resid; status = soreceive (so, &from, &auio, (struct mbuf **)0, mp->msg_control ? &control : (struct mbuf **)0, &mp->msg_flags); recvLen = len - auio.uio_resid; if (mp->msg_name) { len = mp->msg_namelen; if (len <= 0 || from == 0) len = 0; else { if (len > from->m_len) len = from->m_len; (void) copyout((caddr_t) mtod(from, caddr_t), (caddr_t) mp->msg_name, len); } (void) copyout ((caddr_t) &len, namelenp, sizeof (int)); if (bsdSock43ApiFlag) { /* Convert the address structure contents to the BSD 4.3 format. */ bsdSockAddrRevert ((struct sockaddr *)mp->msg_name); } } if (mp->msg_control) { len = mp->msg_controllen; if (len <= 0 || control == 0) len = 0; else { if (len > control->m_len) len = control->m_len; (void) copyout ((caddr_t) mtod(control, caddr_t), (caddr_t) mp->msg_control, len); } (void) copyout ((caddr_t) &len, controllenp, sizeof (int)); } /* If status has been set to EINVAL in TCP, then TCP has freed the * mbufs. We do not free the mbufs, we return the errno * to the application. */ if (status == EINVAL) { netErrnoSet (status); splx (slev); if (mallocedIov) { FREE (pIovCopy, MT_DATA); } return (ERROR); } /* if status is not EINVAL, we free the mbufs as TCP has not freed it */ if (control) m_freem(control); if (from) m_freem(from); splx (slev); if (mallocedIov) { FREE (pIovCopy, MT_DATA); } if (status) { if (auio.uio_resid != len && (status == EINTR || status == EWOULDBLOCK)) status = OK; } return (status == OK ? recvLen : ERROR); }/********************************************************************************* bsdSetsockopt - set socket options** This routine sets the options associated with a socket.* To manipulate options at the "socket" level, <level> should be SOL_SOCKET.* Any other levels should use the appropriate protocol number.** OPTIONS FOR STREAM SOCKETS* The following sections discuss the socket options available for* stream (TCP) sockets.** .SS "SO_KEEPALIVE -- Detecting a Dead Connection"* Specify the SO_KEEPALIVE option to make the transport protocol (TCP)* initiate a timer to detect a dead connection:* .CS* setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof (optval));* .CE* This prevents an application from hanging on an invalid connection. * The value at <optval> for this option is an integer (type `int'),* either 1 (on) or 0 (off).* * The integrity of a connection is verified by transmitting* zero-length TCP segments triggered by a timer, to force a response* from a peer node. If the peer does not respond after repeated* transmissions of the KEEPALIVE segments, the connection is dropped,* all protocol data structures are reclaimed, and processes sleeping* on the connection are awakened with an ETIMEDOUT error.* * The ETIMEDOUT timeout can happen in two ways. If the connection is* not yet established, the KEEPALIVE timer expires after idling* for TCPTV_KEEP_INIT. If the connection is established, the* KEEPALIVE timer starts up when there is no traffic for* TCPTV_KEEP_IDLE. If no response is received from the peer after* sending the KEEPALIVE segment TCPTV_KEEPCNT times with interval* TCPTV_KEEPINTVL, TCP assumes that the connection is invalid.* The parameters TCPTV_KEEP_INIT, TCPTV_KEEP_IDLE, TCPTV_KEEPCNT, and* TCPTV_KEEPINTVL are defined in the file vw/h/net/tcp_timer.h.** .SS "SO_LINGER -- Closing a Connection"* Specify the SO_LINGER option to determine whether TCP should perform a * "graceful" close:* .CS* setsockopt (sock, SOL_SOCKET, SO_LINGER, &optval, sizeof (optval));* .CE* For a "graceful" close, when a connection is shut down TCP tries* to make sure that all the unacknowledged data in transmission channel* are acknowledged, and the peer is shut down properly, by going through an* elaborate set of state transitions.* * The value at <optval> indicates the amount of time to linger if* there is unacknowledged data, using `struct linger' in* vw/h/sys/socket.h. The `linger' structure has two members:* `l_onoff' and `l_linger'. `l_onoff' can be set to 1 to turn on the* SO_LINGER option, or set to 0 to turn off the SO_LINGER option.* `l_linger' indicates the amount of time to linger. If `l_onoff' is* turned on and `l_linger' is set to 0, a default value TCP_LINGERTIME* (specified in netinet/tcp_timer.h) is used for incoming* connections accepted on the socket.* * When SO_LINGER is turned on and the `l_linger' field is set to 0,* TCP simply drops the connection by sending out an RST if a* connection is already established; frees up the space for the TCP* protocol control block; and wakes up all tasks sleeping on the* socket.* * For the client side socket, the value of `l_linger' is not changed* if it is set to 0. To make sure that the value of `l_linger' is 0* on a newly accepted socket connection, issue another setsockopt()* after the accept() call.* * Currently the exact value of `l_linger' time is actually ignored* (other than checking for 0); that is, TCP performs the state* transitions if `l_linger' is not 0, but does not explicitly use its* value.* * .SS "TCP_NODELAY -- Delivering Messages Immediately"* Specify the TCP_NODELAY option for real-time protocols, such as the X* Window System Protocol, that require immediate delivery of many small* messages:* .CS* setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof (optval));* .CE* The value at <optval> is an integer (type `int') set to either 1* (on) or 0 (off).* * By default, the VxWorks TCP implementation employs an algorithm that* attempts to avoid the congestion that can be produced by a large number* of small TCP segments. This typically arises with virtual terminal* applications (such as telnet or rlogin) across networks that have* low bandwidth and long delays. The algorithm attempts to have no* more than one outstanding unacknowledged segment in the transmission* channel while queueing up the rest of the smaller segments for later* transmission. Another segment is sent only if enough new data is* available to make up a maximum sized segment, or if the outstanding* data is acknowledged.* * This congestion-avoidance algorithm works well for virtual terminal* protocols and bulk data transfer protocols such as FTP without any* noticeable side effects. However, real-time protocols that require* immediate delivery of many small messages, such as the X Window* System Protocol, need to defeat this facility to guarantee proper* responsiveness in their operation.* * TCP_NODELAY is a mechanism to turn off the use of this algorithm.* If this option is turned on and there is data to be sent out, TCP* bypasses the congestion-avoidance algorithm: any available data* segments are sent out if there is enough space in the send window.* * OPTION FOR DATAGRAM SOCKETS* The following section discusses an option for datagram (UDP) sockets.* * .SS "SO_BROADCAST -- Sending to Multiple Destinations"* Specify the SO_BROADCAST option when an application needs to send* data to more than one destination:* .CS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -