2025-08-10 01:34:16 +02:00

195 lines
5.3 KiB
C

#ifndef SOCKET_H_
#define SOCKET_H_
#include <common/toolkit/StringTk.h>
#include <common/toolkit/Time.h>
#include <common/Common.h>
#include <common/net/sock/NicAddress.h>
#include <linux/socket.h>
#include <os/iov_iter.h>
#define SOCKET_PEERNAME_LEN 24
/*
* This is an abstract class.
*/
struct Socket;
typedef struct Socket Socket;
extern void _Socket_init(Socket* this);
extern void _Socket_uninit(Socket* this);
extern bool Socket_bind(Socket* this, unsigned short port);
extern bool Socket_bindToAddr(Socket* this, struct in_addr ipAddr, unsigned short port);
struct SocketOps
{
void (*uninit)(Socket* this);
bool (*connectByIP)(Socket* this, struct in_addr ipaddress, unsigned short port);
bool (*bindToAddr)(Socket* this, struct in_addr ipaddress, unsigned short port);
bool (*listen)(Socket* this);
bool (*shutdown)(Socket* this);
bool (*shutdownAndRecvDisconnect)(Socket* this, int timeoutMS);
ssize_t (*sendto)(Socket* this, struct iov_iter* iter, int flags, fhgfs_sockaddr_in *to);
ssize_t (*recvT)(Socket* this, struct iov_iter* iter, int flags, int timeoutMS);
};
struct Socket
{
NicAddrType_t sockType;
char peername[SOCKET_PEERNAME_LEN];
struct in_addr peerIP;
int boundPort;
const struct SocketOps* ops;
struct {
struct list_head _list;
short _events;
short revents;
} poll;
};
static inline NicAddrType_t Socket_getSockType(Socket* this)
{
return this->sockType;
}
static inline char* Socket_getPeername(Socket* this)
{
return this->peername;
}
static inline struct in_addr Socket_getPeerIP(Socket* this)
{
return this->peerIP;
}
/**
* Calls the virtual uninit method and kfrees the object.
*/
static inline void Socket_virtualDestruct(Socket* this)
{
this->ops->uninit(this);
kfree(this);
}
static inline ssize_t Socket_recvT(Socket* this, struct iov_iter *iter,
size_t length, int flags, int timeoutMS)
{
// TODO: implementation function should accept length as well.
struct iov_iter copy = *iter;
iov_iter_truncate(&copy, length);
{
ssize_t nread = this->ops->recvT(this, &copy, flags, timeoutMS);
if (nread >= 0)
{
// TODO: currently some parts of the project expect that we advance
// the iov_iter. But as it turns out, advancing here does not mesh
// well with how iov_iter is supposed to be used. A problem can be
// observed when advancing an iov_iter of type ITER_PIPE. This will
// result in mutation of external state (struct pipe_inode_info). IOW
// we can't just make a copy of any iov_iter and advance that in
// isolation.
//
// That means, the code should be changed such that we advance only in
// the outermost layers of the beegfs client module.
iov_iter_advance(iter, nread);
}
return nread;
}
}
static inline ssize_t Socket_recvT_kernel(Socket* this, void *buffer,
size_t length, int flags, int timeoutMS)
{
struct iov_iter *iter = STACK_ALLOC_BEEGFS_ITER_KVEC(buffer, length, READ);
return this->ops->recvT(this, iter, flags, timeoutMS);
}
/**
* Receive with timeout, extended version with numReceivedBeforeError.
*
* note: this uses a soft timeout that is being reset after each received data packet.
*
* @param outNumReceivedBeforeError number of bytes received before returning (also set in case of
* an error, e.g. timeout); given value will only be increased and is intentionally not set to 0
* initially.
* @return -ETIMEDOUT on timeout.
*/
static inline ssize_t Socket_recvExactTEx(Socket* this, struct iov_iter *iter, size_t len, int flags, int timeoutMS,
size_t* outNumReceivedBeforeError)
{
ssize_t missingLen = len;
do
{
ssize_t recvRes = this->ops->recvT(this, iter, flags, timeoutMS);
if(unlikely(recvRes <= 0) )
return recvRes;
missingLen -= recvRes;
*outNumReceivedBeforeError += recvRes;
} while(missingLen);
// all received if we got here
return len;
}
static inline ssize_t Socket_recvExactTEx_kernel(Socket* this, void *buf, size_t len, int flags, int timeoutMS,
size_t* outNumReceivedBeforeError)
{
struct iov_iter *iter = STACK_ALLOC_BEEGFS_ITER_KVEC(buf, len, READ);
return Socket_recvExactTEx(this, iter, len, flags, timeoutMS, outNumReceivedBeforeError);
}
/**
* Receive with timeout.
*
* @return -ETIMEDOUT on timeout.
*/
static inline ssize_t Socket_recvExactT(Socket* this, struct iov_iter *iter, size_t len, int flags, int timeoutMS)
{
size_t numReceivedBeforeError;
return Socket_recvExactTEx(this, iter, len, flags, timeoutMS, &numReceivedBeforeError);
}
static inline ssize_t Socket_recvExactT_kernel(Socket* this, void *buf, size_t len, int flags, int timeoutMS)
{
size_t numReceivedBeforeError;
return Socket_recvExactTEx_kernel(this, buf, len, flags, timeoutMS, &numReceivedBeforeError);
}
static inline ssize_t Socket_sendto_kernel(Socket *this, const void *buf, size_t len, int flags,
fhgfs_sockaddr_in *to)
{
struct iov_iter *iter = STACK_ALLOC_BEEGFS_ITER_KVEC(buf, len, WRITE);
return this->ops->sendto(this, iter, flags, to);
}
static inline ssize_t Socket_send_kernel(Socket *this, const void *buf, size_t len, int flags)
{
return Socket_sendto_kernel(this, buf, len, flags, NULL);
}
#endif /*SOCKET_H_*/