#ifndef SOCKET_H_ #define SOCKET_H_ #include #include #include #include #include #include #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(©, length); { ssize_t nread = this->ops->recvT(this, ©, 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_*/