209 lines
6.4 KiB
C
209 lines
6.4 KiB
C
#ifndef MESSAGINGTK_H_
|
|
#define MESSAGINGTK_H_
|
|
|
|
#include <app/log/Logger.h>
|
|
#include <app/App.h>
|
|
#include <app/config/Config.h>
|
|
#include <common/net/message/NetMessage.h>
|
|
#include <common/net/sock/Socket.h>
|
|
#include <common/nodes/MirrorBuddyGroup.h>
|
|
#include <common/nodes/Node.h>
|
|
#include <common/threading/Thread.h>
|
|
#include <common/toolkit/MessagingTkArgs.h>
|
|
#include <common/storage/StorageErrors.h>
|
|
#include <common/Common.h>
|
|
#include <net/message/NetMessageFactory.h>
|
|
|
|
struct Socket;
|
|
|
|
extern FhgfsOpsErr MessagingTk_requestResponseWithRRArgsSock(App* app,
|
|
RequestResponseArgs* rrArgs, Socket* sock);
|
|
extern FhgfsOpsErr MessagingTk_requestResponseKMalloc(App* app, Node* node,
|
|
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
|
extern FhgfsOpsErr MessagingTk_requestResponseSock(App* app, Node* node,
|
|
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg,
|
|
Socket* sock);
|
|
|
|
extern FhgfsOpsErr MessagingTk_requestResponseRetry(App* app, Node* node,
|
|
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
|
|
|
extern FhgfsOpsErr MessagingTk_requestResponseNode(App* app,
|
|
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
|
extern FhgfsOpsErr MessagingTk_requestResponseNodeRetryAutoIntr(App* app,
|
|
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
|
|
|
// private
|
|
|
|
extern FhgfsOpsErr __MessagingTk_requestResponseWithRRArgsComm(App* app,
|
|
RequestResponseArgs* rrArgs, MirrorBuddyGroup* group, bool* wasIndirectCommErr, Socket* sock);
|
|
extern FhgfsOpsErr __MessagingTk_handleGenericResponse(App* app, RequestResponseArgs* rrArgs,
|
|
MirrorBuddyGroup* group, bool* wasIndirectCommErr);
|
|
|
|
extern FhgfsOpsErr __MessagingTk_requestResponseNodeRetry(App* app,
|
|
RequestResponseNode* rrNode, RequestResponseArgs* rrArgs);
|
|
|
|
// inliners
|
|
|
|
static inline char* MessagingTk_createMsgBuf(NetMessage* msg);
|
|
static inline ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen);
|
|
|
|
static inline void MessagingTk_waitBeforeRetry(unsigned currentNumRetry);
|
|
static inline int MessagingTk_getRetryWaitMS(unsigned currentNumRetry);
|
|
static inline FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app,
|
|
RequestResponseArgs* rrArgs);
|
|
static inline FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node,
|
|
NetMessage* requestMsg, unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg);
|
|
|
|
|
|
|
|
/**
|
|
* Creates a message buffer of the required size and serializes the message to it.
|
|
* Note: Uses kmalloc, so this is only safe for messages < 128kB
|
|
*
|
|
* @return buffer must be kfreed by the caller
|
|
*/
|
|
char* MessagingTk_createMsgBuf(NetMessage* msg)
|
|
{
|
|
size_t bufLen = NetMessage_getMsgLength(msg);
|
|
char* buf = (char*)os_kmalloc(bufLen);
|
|
|
|
NetMessage_serialize(msg, buf, buf ? bufLen : 0);
|
|
|
|
return buf;
|
|
}
|
|
|
|
/**
|
|
* Receive a complete message into given buffer, extended version.
|
|
*
|
|
* Note: This is the version for pre-allocated buffers.
|
|
*
|
|
* @param bufIn incoming message buffer.
|
|
* @return positive message length on success, <=0 on error (e.g. -ETIMEDOUT on recv timeout,
|
|
* -EMSGSIZE if msg too large for buffer).
|
|
*/
|
|
ssize_t MessagingTk_recvMsgBuf(App* app, Socket* sock, char* bufIn, size_t bufInLen)
|
|
{
|
|
const char* logContext = "MessagingTk (recv msg)";
|
|
|
|
size_t numReceived = 0;
|
|
ssize_t recvRes;
|
|
size_t msgLength;
|
|
Config* cfg = App_getConfig(app);
|
|
|
|
// receive at least the message header
|
|
|
|
recvRes = Socket_recvExactTEx_kernel(sock, bufIn, NETMSG_MIN_LENGTH, 0, cfg->connMsgLongTimeout,
|
|
&numReceived);
|
|
|
|
if(unlikely(recvRes <= 0) )
|
|
{ // socket error
|
|
Logger* log = App_getLogger(app);
|
|
Logger_logFormatted(log, Log_DEBUG, logContext, "Failed to receive message header from: %s",
|
|
Socket_getPeername(sock) );
|
|
|
|
goto socket_exception;
|
|
}
|
|
|
|
msgLength = NetMessage_extractMsgLengthFromBuf(bufIn);
|
|
|
|
if(msgLength <= numReceived)
|
|
return msgLength; // success (msg had no additional payload)
|
|
|
|
|
|
// receive the message payload part
|
|
|
|
if(unlikely(msgLength > bufInLen) )
|
|
{ // message too big to be accepted
|
|
Logger* log = App_getLogger(app);
|
|
Logger_logFormatted(log, Log_WARNING, logContext,
|
|
"Received a message that is too large from: %s (bufLen: %lld, msgLen: %lld)",
|
|
Socket_getPeername(sock), (long long)bufInLen, (long long)msgLength);
|
|
|
|
return -EMSGSIZE;
|
|
}
|
|
|
|
recvRes = Socket_recvExactTEx_kernel(sock, &bufIn[numReceived], msgLength-numReceived, 0,
|
|
cfg->connMsgLongTimeout, &numReceived);
|
|
|
|
if(unlikely(recvRes <= 0) )
|
|
goto socket_exception;
|
|
|
|
// success
|
|
return msgLength;
|
|
|
|
|
|
socket_exception:
|
|
{
|
|
Logger* log = App_getLogger(app);
|
|
|
|
if (fatal_signal_pending(current))
|
|
Logger_logFormatted(log, Log_DEBUG, logContext,
|
|
"Receive interrupted by signal");
|
|
else
|
|
Logger_logFormatted(log, Log_DEBUG, logContext,
|
|
"Receive failed from: %s (ErrCode: %lld)",
|
|
Socket_getPeername(sock), (long long)recvRes);
|
|
}
|
|
|
|
return recvRes;
|
|
}
|
|
|
|
void MessagingTk_waitBeforeRetry(unsigned currentNumRetry)
|
|
{
|
|
int retryWaitMS = MessagingTk_getRetryWaitMS(currentNumRetry);
|
|
|
|
if(retryWaitMS)
|
|
Thread_sleep(retryWaitMS);
|
|
}
|
|
|
|
int MessagingTk_getRetryWaitMS(unsigned currentNumRetry)
|
|
{
|
|
// note: keep in sync with __Config_initConnNumCommRetries()
|
|
|
|
int retryWaitMS ;
|
|
|
|
if(!currentNumRetry)
|
|
{
|
|
retryWaitMS = 0;
|
|
}
|
|
else
|
|
if(currentNumRetry <= 12) // 1st minute
|
|
{
|
|
retryWaitMS = 5000;
|
|
}
|
|
else
|
|
if(currentNumRetry <= 24) // 2nd to 5th minute
|
|
{
|
|
retryWaitMS = 20000;
|
|
}
|
|
else // after 5th minute
|
|
{
|
|
retryWaitMS = 60000;
|
|
}
|
|
|
|
return retryWaitMS;
|
|
}
|
|
|
|
/**
|
|
* Note: rrArgs->outRespBuf must be returned/freed by the caller (depending on respBufType)
|
|
*/
|
|
FhgfsOpsErr MessagingTk_requestResponseWithRRArgs(App* app, RequestResponseArgs* rrArgs)
|
|
{
|
|
return MessagingTk_requestResponseWithRRArgsSock(app, rrArgs, NULL);
|
|
}
|
|
|
|
/**
|
|
* Note: Allows only a single retry. (One retry allowed because we might have gotten an already
|
|
* broken connection from the conn pool.)
|
|
*
|
|
* @param outRespBuf must be returned to the store - not freed!
|
|
*/
|
|
FhgfsOpsErr MessagingTk_requestResponse(App* app, Node* node, NetMessage* requestMsg,
|
|
unsigned respMsgType, char** outRespBuf, NetMessage** outRespMsg)
|
|
{
|
|
return MessagingTk_requestResponseSock(app, node, requestMsg, respMsgType,
|
|
outRespBuf, outRespMsg, NULL);
|
|
}
|
|
|
|
#endif /*MESSAGINGTK_H_*/
|