New upstream version 8.1.0
This commit is contained in:
660
client_module/source/common/net/sock/StandardSocket.c
Normal file
660
client_module/source/common/net/sock/StandardSocket.c
Normal file
@@ -0,0 +1,660 @@
|
||||
#include <common/net/sock/StandardSocket.h>
|
||||
#include <common/toolkit/Serialization.h>
|
||||
#include <common/toolkit/SocketTk.h>
|
||||
#include <common/Common.h>
|
||||
|
||||
#include <linux/in.h>
|
||||
#include <linux/tcp.h>
|
||||
|
||||
|
||||
#define SOCKET_LISTEN_BACKLOG 32
|
||||
#define SOCKET_SHUTDOWN_RECV_BUF_LEN 32
|
||||
#define STANDARDSOCKET_CONNECT_TIMEOUT_MS 5000
|
||||
|
||||
static const struct SocketOps standardOps = {
|
||||
.uninit = _StandardSocket_uninit,
|
||||
|
||||
.connectByIP = _StandardSocket_connectByIP,
|
||||
.bindToAddr = _StandardSocket_bindToAddr,
|
||||
.listen = _StandardSocket_listen,
|
||||
.shutdown = _StandardSocket_shutdown,
|
||||
.shutdownAndRecvDisconnect = _StandardSocket_shutdownAndRecvDisconnect,
|
||||
|
||||
.sendto = _StandardSocket_sendto,
|
||||
.recvT = _StandardSocket_recvT,
|
||||
};
|
||||
|
||||
#ifdef KERNEL_HAS_SKWQ_HAS_SLEEPER
|
||||
# define __sock_has_sleeper(wq) (skwq_has_sleeper(wq))
|
||||
#else
|
||||
# define __sock_has_sleeper(wq) (wq_has_sleeper(wq))
|
||||
#endif
|
||||
|
||||
#if defined(KERNEL_HAS_SK_SLEEP) && !defined(KERNEL_HAS_SK_HAS_SLEEPER)
|
||||
static inline int sk_has_sleeper(struct sock* sk)
|
||||
{
|
||||
return sk->sk_sleep && waitqueue_active(sk->sk_sleep);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(KERNEL_WAKE_UP_SYNC_KEY_HAS_3_ARGUMENTS)
|
||||
# define __wake_up_sync_key_m(wq, state, key) __wake_up_sync_key(wq, state, key)
|
||||
#else
|
||||
# define __wake_up_sync_key_m(wq, state, key) __wake_up_sync_key(wq, state, 1, key)
|
||||
#endif
|
||||
|
||||
|
||||
/* unlike linux sock_def_readable, this will also wake TASK_KILLABLE threads. we need this
|
||||
* for SocketTk_poll, which wants to wait for fatal signals only. */
|
||||
#ifdef KERNEL_HAS_SK_DATA_READY_2
|
||||
static void sock_readable(struct sock *sk, int len)
|
||||
#else
|
||||
static void sock_readable(struct sock *sk)
|
||||
#endif
|
||||
{
|
||||
#ifdef KERNEL_HAS_SK_SLEEP
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
if (sk_has_sleeper(sk))
|
||||
{
|
||||
__wake_up_sync_key_m(sk->sk_sleep, TASK_NORMAL,
|
||||
(void*) (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND));
|
||||
}
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
#else
|
||||
struct socket_wq *wq;
|
||||
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (__sock_has_sleeper(wq))
|
||||
{
|
||||
__wake_up_sync_key_m(&wq->wait, TASK_NORMAL,
|
||||
(void*) (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND));
|
||||
}
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* sock_def_write_space will also not wake uninterruptible threads. additionally, in newer kernels
|
||||
* it uses refcount_t for an optimization we will do not need: linux does not want to wake up
|
||||
* many writers if many of them cannot make progress. we have only a single writer. */
|
||||
static void sock_write_space(struct sock *sk)
|
||||
{
|
||||
#ifdef KERNEL_HAS_SK_SLEEP
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
|
||||
if (sk_has_sleeper(sk))
|
||||
{
|
||||
__wake_up_sync_key_m(sk->sk_sleep, TASK_NORMAL,
|
||||
(void*) (POLLOUT | POLLWRNORM | POLLWRBAND));
|
||||
}
|
||||
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
#else
|
||||
struct socket_wq *wq;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (__sock_has_sleeper(wq))
|
||||
__wake_up_sync_key_m(&wq->wait, TASK_NORMAL, (void*) (POLLOUT | POLLWRNORM | POLLWRBAND));
|
||||
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* sock_def_wakeup, which is called for disconnects, has the same problem. */
|
||||
static void sock_wakeup(struct sock *sk)
|
||||
{
|
||||
#ifdef KERNEL_HAS_SK_SLEEP
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
if (sk_has_sleeper(sk))
|
||||
wake_up_all(sk->sk_sleep);
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
#else
|
||||
struct socket_wq *wq;
|
||||
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (__sock_has_sleeper(wq))
|
||||
wake_up_all(&wq->wait);
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* as does sock_def_error_report */
|
||||
static void sock_error_report(struct sock *sk)
|
||||
{
|
||||
#ifdef KERNEL_HAS_SK_SLEEP
|
||||
read_lock(&sk->sk_callback_lock);
|
||||
if (sk_has_sleeper(sk))
|
||||
__wake_up_sync_key_m(sk->sk_sleep, TASK_NORMAL, (void*) (POLLERR));
|
||||
read_unlock(&sk->sk_callback_lock);
|
||||
#else
|
||||
struct socket_wq *wq;
|
||||
|
||||
rcu_read_lock();
|
||||
wq = rcu_dereference(sk->sk_wq);
|
||||
if (__sock_has_sleeper(wq))
|
||||
__wake_up_sync_key_m(&wq->wait, TASK_NORMAL, (void*) (POLLERR));
|
||||
rcu_read_unlock();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool StandardSocket_init(StandardSocket* this, int domain, int type, int protocol)
|
||||
{
|
||||
Socket* thisBase = (Socket*)this;
|
||||
|
||||
NicAddrType_t nicType = NICADDRTYPE_STANDARD;
|
||||
|
||||
// init super class
|
||||
_PooledSocket_init( (PooledSocket*)this, nicType);
|
||||
|
||||
thisBase->ops = &standardOps;
|
||||
|
||||
// normal init part
|
||||
|
||||
this->sock = NULL;
|
||||
|
||||
this->sockDomain = domain;
|
||||
|
||||
return _StandardSocket_initSock(this, domain, type, protocol);
|
||||
}
|
||||
|
||||
StandardSocket* StandardSocket_construct(int domain, int type, int protocol)
|
||||
{
|
||||
StandardSocket* this = kmalloc(sizeof(*this), GFP_NOFS);
|
||||
|
||||
if(!this ||
|
||||
!StandardSocket_init(this, domain, type, protocol) )
|
||||
{
|
||||
kfree(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
StandardSocket* StandardSocket_constructUDP(void)
|
||||
{
|
||||
return StandardSocket_construct(PF_INET, SOCK_DGRAM, 0);
|
||||
}
|
||||
|
||||
StandardSocket* StandardSocket_constructTCP(void)
|
||||
{
|
||||
return StandardSocket_construct(PF_INET, SOCK_STREAM, 0);
|
||||
}
|
||||
|
||||
void _StandardSocket_uninit(Socket* this)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
|
||||
_PooledSocket_uninit(this);
|
||||
|
||||
if(thisCast->sock)
|
||||
sock_release(thisCast->sock);
|
||||
}
|
||||
|
||||
bool _StandardSocket_initSock(StandardSocket* this, int domain, int type, int protocol)
|
||||
{
|
||||
int createRes;
|
||||
|
||||
// prepare/create socket
|
||||
#ifndef KERNEL_HAS_SOCK_CREATE_KERN_NS
|
||||
createRes = sock_create_kern(domain, type, protocol, &this->sock);
|
||||
#else
|
||||
createRes = sock_create_kern(&init_net, domain, type, protocol, &this->sock);
|
||||
#endif
|
||||
if(createRes < 0)
|
||||
{
|
||||
//printk_fhgfs(KERN_WARNING, "Failed to create socket\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
__StandardSocket_setAllocMode(this, GFP_NOFS);
|
||||
this->sock->sk->sk_data_ready = sock_readable;
|
||||
this->sock->sk->sk_write_space = sock_write_space;
|
||||
this->sock->sk->sk_state_change = sock_wakeup;
|
||||
this->sock->sk->sk_error_report = sock_error_report;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void __StandardSocket_setAllocMode(StandardSocket* this, gfp_t flags)
|
||||
{
|
||||
this->sock->sk->sk_allocation = flags;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use this to change socket options.
|
||||
* Note: Behaves (almost) like user-space setsockopt.
|
||||
*
|
||||
* @return 0 on success, error code otherwise (=> different from userspace version)
|
||||
*/
|
||||
int _StandardSocket_setsockopt(StandardSocket* this, int level,
|
||||
int optname, char* optval, int optlen)
|
||||
{
|
||||
struct socket *sock = this->sock;
|
||||
|
||||
#if defined(KERNEL_HAS_SOCK_SETSOCKOPT_SOCKPTR_T_PARAM)
|
||||
|
||||
sockptr_t ptr = KERNEL_SOCKPTR(optval);
|
||||
|
||||
if (level == SOL_SOCKET)
|
||||
return sock_setsockopt(sock, level, optname, ptr, optlen);
|
||||
else
|
||||
return sock->ops->setsockopt(sock, level, optname, ptr, optlen);
|
||||
|
||||
#elif defined(KERNEL_HAS_GET_FS)
|
||||
|
||||
char __user *ptr = (char __user __force *) optval;
|
||||
int r;
|
||||
|
||||
WITH_PROCESS_CONTEXT
|
||||
if (level == SOL_SOCKET)
|
||||
r = sock_setsockopt(sock, level, optname, ptr, optlen);
|
||||
else
|
||||
r = sock->ops->setsockopt(sock, level, optname, ptr, optlen);
|
||||
return r;
|
||||
|
||||
#else
|
||||
#error need set_fs()/get_fs() if sockptr_t is not available.
|
||||
#endif
|
||||
|
||||
// unreachable
|
||||
BUG();
|
||||
}
|
||||
|
||||
bool StandardSocket_setSoKeepAlive(StandardSocket* this, bool enable)
|
||||
{
|
||||
int val = (enable ? 1 : 0);
|
||||
|
||||
int r = _StandardSocket_setsockopt(this, SOL_SOCKET, SO_KEEPALIVE, (char *) &val, sizeof val);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
bool StandardSocket_setSoBroadcast(StandardSocket* this, bool enable)
|
||||
{
|
||||
int val = (enable ? 1 : 0);
|
||||
|
||||
int r = _StandardSocket_setsockopt(this, SOL_SOCKET, SO_BROADCAST, (char *) &val, sizeof val);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
int StandardSocket_getSoRcvBuf(StandardSocket* this)
|
||||
{
|
||||
//TODO: should this be READ_ONCE()? There are different uses in the Linux kernel
|
||||
return this->sock->sk->sk_rcvbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Increase only (buffer will not be set to a smaller value).
|
||||
*
|
||||
* @return false on error, true otherwise (decrease skipping is not an error)
|
||||
*/
|
||||
bool StandardSocket_setSoRcvBuf(StandardSocket* this, int size)
|
||||
{
|
||||
int origBufLen = StandardSocket_getSoRcvBuf(this);
|
||||
|
||||
if (origBufLen >= size)
|
||||
{
|
||||
// we don't decrease buf sizes (but this is not an error)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* note: according to socket(7) man page, the value given to setsockopt()
|
||||
* is doubled and the doubled value is returned by getsockopt()
|
||||
*
|
||||
* update 2022-05-13: the kernel doubles the value passed to
|
||||
* setsockopt(SO_RCVBUF) to allow for bookkeeping overhead. Halving the
|
||||
* value is probably "not correct" but it's been this way since 2010 and
|
||||
* changing it will potentially do more harm than good at this point.
|
||||
*/
|
||||
|
||||
int val = size/2;
|
||||
|
||||
int r = _StandardSocket_setsockopt(this, SOL_SOCKET, SO_RCVBUF, (char *)
|
||||
&val, sizeof val);
|
||||
|
||||
if(r != 0)
|
||||
printk_fhgfs_debug(KERN_INFO, "%s: setSoRcvBuf error: %d;\n", __func__, r);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool StandardSocket_setTcpNoDelay(StandardSocket* this, bool enable)
|
||||
{
|
||||
int val = (enable ? 1 : 0);
|
||||
|
||||
int r = _StandardSocket_setsockopt(this, SOL_TCP, TCP_NODELAY, (char*) &val, sizeof val);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
bool StandardSocket_setTcpCork(StandardSocket* this, bool enable)
|
||||
{
|
||||
int val = (enable ? 1 : 0);
|
||||
|
||||
int r = _StandardSocket_setsockopt(this, SOL_TCP, TCP_CORK, (char*) &val, sizeof val);
|
||||
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
bool _StandardSocket_connectByIP(Socket* this, struct in_addr ipaddress, unsigned short port)
|
||||
{
|
||||
// note: this might look a bit strange (it's kept similar to the c++ version)
|
||||
|
||||
// note: error messages here would flood the log if hosts are unreachable on primary interface
|
||||
|
||||
|
||||
const int timeoutMS = STANDARDSOCKET_CONNECT_TIMEOUT_MS;
|
||||
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
|
||||
int connRes;
|
||||
|
||||
struct sockaddr_in serveraddr =
|
||||
{
|
||||
.sin_family = AF_INET,
|
||||
.sin_addr = ipaddress,
|
||||
.sin_port = htons(port),
|
||||
};
|
||||
|
||||
connRes = kernel_connect(thisCast->sock,
|
||||
(struct sockaddr*) &serveraddr,
|
||||
sizeof(serveraddr),
|
||||
O_NONBLOCK);
|
||||
|
||||
if(connRes)
|
||||
{
|
||||
if(connRes == -EINPROGRESS)
|
||||
{ // wait for "ready to send data"
|
||||
PollState state;
|
||||
int pollRes;
|
||||
|
||||
PollState_init(&state);
|
||||
PollState_addSocket(&state, this, POLLOUT);
|
||||
|
||||
pollRes = SocketTk_poll(&state, timeoutMS);
|
||||
|
||||
if(pollRes > 0)
|
||||
{ // we got something (could also be an error)
|
||||
|
||||
/* note: it's important to test ERR/HUP/NVAL here instead of POLLOUT only, because
|
||||
POLLOUT and POLLERR can be returned together. */
|
||||
|
||||
if(this->poll.revents & (POLLERR | POLLHUP | POLLNVAL) )
|
||||
return false;
|
||||
|
||||
// connection successfully established
|
||||
|
||||
if(!this->peername[0])
|
||||
{
|
||||
SocketTk_endpointAddrToStrNoAlloc(this->peername, SOCKET_PEERNAME_LEN, ipaddress, port);
|
||||
this->peerIP = ipaddress;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if(!pollRes)
|
||||
return false; // timeout
|
||||
else
|
||||
return false; // connection error
|
||||
|
||||
} // end of "EINPROGRESS"
|
||||
}
|
||||
else
|
||||
{ // connected immediately
|
||||
|
||||
// set peername if not done so already (e.g. by connect(hostname) )
|
||||
if(!this->peername[0])
|
||||
{
|
||||
SocketTk_endpointAddrToStrNoAlloc(this->peername, SOCKET_PEERNAME_LEN, ipaddress, port);
|
||||
this->peerIP = ipaddress;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool _StandardSocket_bindToAddr(Socket* this, struct in_addr ipaddress, unsigned short port)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
|
||||
struct sockaddr_in bindAddr;
|
||||
int bindRes;
|
||||
|
||||
bindAddr.sin_family = thisCast->sockDomain;
|
||||
bindAddr.sin_addr = ipaddress;
|
||||
bindAddr.sin_port = htons(port);
|
||||
|
||||
bindRes = kernel_bind(thisCast->sock, (struct sockaddr*)&bindAddr, sizeof(bindAddr) );
|
||||
|
||||
if(bindRes)
|
||||
{
|
||||
printk_fhgfs(KERN_WARNING, "Failed to bind socket. ErrCode: %d\n", bindRes);
|
||||
return false;
|
||||
}
|
||||
|
||||
this->boundPort = port;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _StandardSocket_listen(Socket* this)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
int r;
|
||||
|
||||
r = kernel_listen(thisCast->sock, SOCKET_LISTEN_BACKLOG);
|
||||
if(r)
|
||||
{
|
||||
printk_fhgfs(KERN_WARNING, "Failed to set socket to listening mode. ErrCode: %d\n",
|
||||
r);
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(this->peername, SOCKET_PEERNAME_LEN, "Listen(Port: %d)", this->boundPort);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _StandardSocket_shutdown(Socket* this)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
|
||||
int sendshutRes;
|
||||
|
||||
sendshutRes = kernel_sock_shutdown(thisCast->sock, SEND_SHUTDOWN);
|
||||
|
||||
if( (sendshutRes < 0) && (sendshutRes != -ENOTCONN) )
|
||||
{
|
||||
printk_fhgfs(KERN_WARNING, "Failed to send shutdown. ErrCode: %d\n", sendshutRes);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _StandardSocket_shutdownAndRecvDisconnect(Socket* this, int timeoutMS)
|
||||
{
|
||||
bool shutRes;
|
||||
char buf[SOCKET_SHUTDOWN_RECV_BUF_LEN];
|
||||
int recvRes;
|
||||
|
||||
shutRes = this->ops->shutdown(this);
|
||||
if(!shutRes)
|
||||
return false;
|
||||
|
||||
// receive until shutdown arrives
|
||||
do
|
||||
{
|
||||
recvRes = Socket_recvT_kernel(this, buf, SOCKET_SHUTDOWN_RECV_BUF_LEN, 0, timeoutMS);
|
||||
} while(recvRes > 0);
|
||||
|
||||
if(recvRes &&
|
||||
(recvRes != -ECONNRESET) )
|
||||
{ // error occurred (but we're disconnecting, so we don't really care about errors)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Compatibility wrappers for sock_sendmsg / sock_recvmsg. At some point in the
|
||||
* 4.x series, the size argument disappeared. */
|
||||
static int beegfs_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags)
|
||||
{
|
||||
#ifdef KERNEL_HAS_RECVMSG_SIZE
|
||||
return sock_recvmsg(sock, msg, len, flags);
|
||||
#else
|
||||
return sock_recvmsg(sock, msg, flags);
|
||||
#endif
|
||||
}
|
||||
static int beegfs_sendmsg(struct socket *sock, struct msghdr *msg, size_t len)
|
||||
{
|
||||
#ifdef KERNEL_HAS_RECVMSG_SIZE
|
||||
return sock_sendmsg(sock, msg, len);
|
||||
#else
|
||||
return sock_sendmsg(sock, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return -ETIMEDOUT on timeout
|
||||
*/
|
||||
ssize_t _StandardSocket_recvT(Socket* this, struct iov_iter* iter, int flags, int timeoutMS)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
|
||||
return StandardSocket_recvfromT(thisCast, iter, flags, NULL, timeoutMS);
|
||||
}
|
||||
|
||||
|
||||
ssize_t _StandardSocket_sendto(Socket* this, struct iov_iter* iter, int flags,
|
||||
fhgfs_sockaddr_in *to)
|
||||
{
|
||||
StandardSocket* thisCast = (StandardSocket*)this;
|
||||
struct socket *sock = thisCast->sock;
|
||||
|
||||
int sendRes;
|
||||
size_t len;
|
||||
struct sockaddr_in toSockAddr;
|
||||
|
||||
struct msghdr msg =
|
||||
{
|
||||
.msg_control = NULL,
|
||||
.msg_controllen = 0,
|
||||
.msg_flags = flags | MSG_NOSIGNAL,
|
||||
.msg_name = (struct sockaddr*)(to ? &toSockAddr : NULL),
|
||||
.msg_namelen = sizeof(toSockAddr),
|
||||
.msg_iter = *iter,
|
||||
};
|
||||
|
||||
len = iov_iter_count(iter);
|
||||
|
||||
if (to)
|
||||
{
|
||||
toSockAddr.sin_family = thisCast->sockDomain;
|
||||
toSockAddr.sin_addr = to->addr;
|
||||
toSockAddr.sin_port = to->port;
|
||||
}
|
||||
|
||||
sendRes = beegfs_sendmsg(sock, &msg, len);
|
||||
|
||||
if(sendRes >= 0)
|
||||
iov_iter_advance(iter, sendRes);
|
||||
|
||||
return sendRes;
|
||||
}
|
||||
|
||||
ssize_t StandardSocket_recvfrom(StandardSocket* this, struct iov_iter* iter, int flags,
|
||||
fhgfs_sockaddr_in *from)
|
||||
{
|
||||
int recvRes;
|
||||
size_t len;
|
||||
struct sockaddr_in fromSockAddr;
|
||||
struct socket *sock = this->sock;
|
||||
|
||||
struct msghdr msg =
|
||||
{
|
||||
.msg_control = NULL,
|
||||
.msg_controllen = 0,
|
||||
.msg_flags = flags,
|
||||
.msg_name = (struct sockaddr*)&fromSockAddr,
|
||||
.msg_namelen = sizeof(fromSockAddr),
|
||||
.msg_iter = *iter,
|
||||
};
|
||||
|
||||
len = iov_iter_count(iter);
|
||||
|
||||
recvRes = beegfs_recvmsg(sock, &msg, len, flags);
|
||||
|
||||
if(recvRes > 0)
|
||||
iov_iter_advance(iter, recvRes);
|
||||
|
||||
if(from)
|
||||
{
|
||||
from->addr = fromSockAddr.sin_addr;
|
||||
from->port = fromSockAddr.sin_port;
|
||||
}
|
||||
|
||||
return recvRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return -ETIMEDOUT on timeout
|
||||
*/
|
||||
ssize_t StandardSocket_recvfromT(StandardSocket* this, struct iov_iter* iter, int flags,
|
||||
fhgfs_sockaddr_in *from, int timeoutMS)
|
||||
{
|
||||
Socket* thisBase = (Socket*)this;
|
||||
|
||||
int pollRes;
|
||||
PollState state;
|
||||
|
||||
if(timeoutMS < 0)
|
||||
return StandardSocket_recvfrom(this, iter, flags, from);
|
||||
|
||||
PollState_init(&state);
|
||||
PollState_addSocket(&state, thisBase, POLLIN);
|
||||
|
||||
pollRes = SocketTk_poll(&state, timeoutMS);
|
||||
|
||||
if( (pollRes > 0) && (thisBase->poll.revents & POLLIN) )
|
||||
return StandardSocket_recvfrom(this, iter, flags, from);
|
||||
|
||||
if(!pollRes)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
if(thisBase->poll.revents & POLLERR)
|
||||
printk_fhgfs_debug(KERN_DEBUG, "StandardSocket_recvfromT: poll(): %s: Error condition\n",
|
||||
thisBase->peername);
|
||||
else
|
||||
if(thisBase->poll.revents & POLLHUP)
|
||||
printk_fhgfs_debug(KERN_DEBUG, "StandardSocket_recvfromT: poll(): %s: Hung up\n",
|
||||
thisBase->peername);
|
||||
else
|
||||
if(thisBase->poll.revents & POLLNVAL)
|
||||
printk_fhgfs(KERN_DEBUG, "StandardSocket_recvfromT: poll(): %s: Invalid request\n",
|
||||
thisBase->peername);
|
||||
else
|
||||
printk_fhgfs(KERN_DEBUG, "StandardSocket_recvfromT: poll(): %s: ErrCode: %d\n",
|
||||
thisBase->peername, pollRes);
|
||||
|
||||
return -ECOMM;
|
||||
}
|
||||
Reference in New Issue
Block a user