added NormStreamGetVacancy() and some NormSocket improvement

pull/9/head
bebopagogo 2020-04-29 22:38:59 -04:00
parent 1c6b5304c7
commit 88e600cedb
16 changed files with 507 additions and 61 deletions

View File

@ -203,7 +203,7 @@ ClientInfo NormGetClientInfo(NormNodeHandle client)
return ClientInfo(version, addr, port);
} // end NormGetClientInfo(NormNodeHandle)
ClientInfo NormGetSocketInfo(NormSocketHandle socket)
static ClientInfo NormGetSocketInfo(NormSocketHandle socket)
{
char addr[16]; // big enough for IPv6
unsigned int addrLen = 16;
@ -490,6 +490,11 @@ int main(int argc, char* argv[])
{
if (event.socket == serverSocket)
{
// TBD - now that the NormSocket code manages its own client_table by remote addr/port
// and should eliminate the 'duplicative' connect itself, we can just keep track
// of client sockets by their NormSocketHandle
// Possibly a new "client" connecting to our "server"
// First confirm that this really is a new client.
if (NORM_SOCKET_INVALID != FindClientSocket(clientMap, clientInfo))

View File

@ -4,6 +4,9 @@
#include <assert.h> // for assert()
#include <string.h> // for strlen()
#include "protoTree.h"
#include "protoAddress.h"
#ifdef WIN32
#include <Winsock2.h> // for inet_ntoa() (TBD - change to use Protolib routines?)
#include <Ws2tcpip.h> // for inet_ntop()
@ -64,6 +67,110 @@ const char* NormNodeGetAddressString(NormNodeHandle node)
}
} // end NormNodeGetAddressString()
class NormSocketInfo : public ProtoTree::Item
{
public:
NormSocketInfo(unsigned int remoteAddrLen, const char* remoteAddr, UINT16 remotePort)
: norm_socket(NULL)
{
info_keysize = MakeKey(info_key, remoteAddrLen, remoteAddr, remotePort);
}
// copy constructor
NormSocketInfo(const NormSocketInfo& s)
{*this = s;}
~NormSocketInfo() {}
void SetSocket(class NormSocket* theSocket)
{norm_socket = theSocket;}
class NormSocket* GetSocket()
{return norm_socket;}
static unsigned int MakeKey(unsigned char* key, unsigned int remoteAddrLen, const char* remoteAddr, UINT16 remotePort)
{
key[0] = remoteAddrLen;
memcpy(key + 1, remoteAddr, remoteAddrLen);
unsigned int keysize = remoteAddrLen + 1;
memcpy(key + keysize, &remotePort, 2);
keysize += 2;
keysize <<= 3; // to size in 'bits'
return keysize;
}
void GetRemoteAddress(ProtoAddress& theAddr) const
{
int remoteAddrLen = info_key[0];
const char* remoteAddrPtr = (char*)info_key + 1;
ProtoAddress::Type addrType;
switch (remoteAddrLen)
{
case 4:
addrType = ProtoAddress::IPv4;
break;
case 16:
addrType = ProtoAddress::IPv6;
break;
default:
theAddr.Invalidate();
ASSERT(0);
return;
}
theAddr.SetRawHostAddress(addrType, remoteAddrPtr, remoteAddrLen);
UINT16 remotePort;
memcpy(&remotePort, remoteAddrPtr + remoteAddrLen, 2);
theAddr.SetPort(remotePort);
}
const char* GetKey() const
{return (const char*)info_key;}
unsigned int GetKeysize() const
{return info_keysize;}
private:
// remoteAddrLen + remoteAddr + remotePort
// 1 + 16 max + 2
unsigned char info_key[19];
unsigned int info_keysize;
class NormSocket* norm_socket; // may be NULL if it is pending acceptance
}; // end class NormSocketInfo
// helper function
NormSocketInfo NormGetSocketInfo(NormNodeHandle client)
{
char remoteAddr[16]; // big enough for IPv6
unsigned int remoteAddrLen = 16;
UINT16 remotePort;
NormNodeGetAddress(client, remoteAddr, &remoteAddrLen, &remotePort);
return NormSocketInfo(remoteAddrLen, remoteAddr, remotePort);
} // end NormGetSocketInfo()
class NormSocketTable : public ProtoTreeTemplate<NormSocketInfo>
{
public:
NormSocketInfo* FindSocketInfo(UINT16 remotePort, unsigned int remoteAddrLen, const char* remoteAddr)
{
unsigned char key[19];
unsigned int keysize = NormSocketInfo::MakeKey(key, remoteAddrLen, remoteAddr, remotePort);
return Find((char*)key, keysize);
}
NormSocketInfo* FindSocketInfo(NormNodeHandle client)
{
NormSocketInfo socketInfo = NormGetSocketInfo(client);
return Find(socketInfo.GetKey(), socketInfo.GetKeysize());
}
void RemoveSocketInfo(NormSocketInfo& socketInfo)
{
// safety dance
if (NULL == Find(socketInfo.GetKey(), socketInfo.GetKeysize())) return; // not on the dance floor
Remove(socketInfo);
}
}; // end class NormSocketTable
class NormSocket
{
public:
@ -89,6 +196,9 @@ class NormSocket
{return (NULL != server_socket);}
bool IsClientSide() const
{return (NULL == server_socket);}
NormSocket* GetServerSocket()
{return server_socket;}
NormInstanceHandle GetInstance() const
{return NormGetInstance(norm_session);}
@ -134,6 +244,18 @@ class NormSocket
// hard, immediate closure
void Close();
void SetSocketInfo(NormSocketInfo* socketInfo) // for server-side, client sockets only
{socket_info = socketInfo;}
NormSocketInfo* FindSocketInfo(NormNodeHandle client)
{return client_table.FindSocketInfo(client);}
void RemoveSocketInfo(NormSocketInfo& socketInfo) // for server sockets only
{client_table.RemoveSocketInfo(socketInfo);}
void SetUserData(const void* userData)
{user_data = userData;}
const void* GetUserData() const
@ -169,6 +291,12 @@ class NormSocket
void RemoveAckingNode(NormNodeId nodeId)
{NormRemoveAckingNode(norm_session, nodeId);}
UINT16 GetLocalPort() const
{return (NORM_SESSION_INVALID != norm_session) ? NormGetRxPort(norm_session) : 0;}
//bool GetLocalAddress(char* addr, unsigned int& addrLen, UINT16& port)
// {return NormGetRxBindAddress(norm_session, addr, addrLen, port)}
void GetPeerName(char* addr, unsigned int* addrLen, UINT16* port)
{
if (NULL == addrLen) return;
@ -206,6 +334,8 @@ class NormSocket
NormSessionHandle norm_session;
NormSessionHandle mcast_session; // equals norm_session for a multicast server
NormSocket* server_socket; // only applies to server-side sockets
NormSocketTable client_table; // only applies to server sockets
NormSocketInfo* socket_info; // only applies to server-side, client sockets
unsigned int client_count; // only applies to mcast server sockets
NormNodeId client_id; // only applies to mcast client socket
NormNodeHandle remote_node; // client socket peer info
@ -227,10 +357,11 @@ class NormSocket
}; // end class NormSocket
NormSocket::NormSocket(NormSessionHandle normSession)
: socket_state(CLOSED), norm_session(normSession),
mcast_session(NORM_SESSION_INVALID), server_socket(NULL),
client_count(0), client_id(NORM_NODE_NONE),
socket_info(NULL), client_count(0), client_id(NORM_NODE_NONE),
remote_node(NORM_NODE_INVALID), remote_version(0), remote_port(0),
tx_stream(NORM_OBJECT_INVALID), tx_ready(false), tx_segment_size(0),
tx_stream_buffer_max(0), tx_stream_buffer_count(0),
@ -277,10 +408,30 @@ bool NormSocket::Listen(UINT16 serverPort, const char* groupAddr, const char* se
{
if (OPEN != socket_state)
{
fprintf(stderr, "NormSocket::Listen() error: socket not open?!\n");
return false;
/* This wasn't a good idea (yet and maybe never)
if ((CLOSED == socket_state) && (NORM_SESSION_INVALID != norm_session))
{
// closed socekt, not in use, so re-open socket ..
NormInstanceHandle instance = NormGetInstance(norm_session);
NormSessionHandle oldSession = norm_session;
if (!Open(instance))
{
norm_session = oldSession;
perror("NormSocket::Listen() error: unable to reopen socket");
return false;
}
else
{
NormDestroySession(oldSession);
}
}
else*/
{
fprintf(stderr, "NormSocket::Listen() error: socket not open!?\n");
return false;
}
}
// THe code below will be cleaned/tightened up somewhat once all is working
// The code below will be cleaned/tightened up somewhat once all is working
// Note that port reuse here lets us manage our "client" rx-only unicast connections the
// way we need, but does allow a second multicast server to be started on this group which leads
@ -479,6 +630,32 @@ bool NormSocket::Connect(const char* serverAddr,
const char* groupAddr,
NormNodeId clientId)
{
if (OPEN != socket_state)
{
/* Not a good idea (yet and maybe never)
if ((CLOSED == socket_state) && (NORM_SESSION_INVALID != norm_session))
{
// closed socekt, not in use, so re-open socket ..
NormInstanceHandle instance = NormGetInstance(norm_session);
NormSessionHandle oldSession = norm_session;
if (!Open(instance))
{
norm_session = oldSession;
perror("NormSocket::Connect() error: unable to reopen socket");
return false;
}
else
{
NormDestroySession(oldSession);
}
}
else
*/
{
fprintf(stderr, "NormSocket::Connect() error: socket not open!?\n");
return false;
}
}
// For unicast connections, the "client" manages a single NormSession for send and receive
// (For multicast connections, there are two sessions: The same unicast session that will
// be set to txOnly upon CONNECT and a separate NormSession for multicast reception)
@ -555,6 +732,7 @@ bool NormSocket::Connect(const char* serverAddr,
else
{
// Set timeout for connect attempt (for "heavyweight" mcast connect, this would also be done)
TRACE("NormSetUserTimer(1) session: %p\n", norm_session);
NormSetUserTimer(norm_session, NORM_DEFAULT_CONNECT_TIMEOUT);
}
server_socket = NULL; // this is a client-side socket
@ -700,6 +878,7 @@ void NormSocket::Shutdown()
if ((IsServerSide() && IsMulticastClient()) || (NORM_OBJECT_INVALID == tx_stream))
{
// Use a zero-timeout to immediately post NORM_SOCKET_CLOSE notification
TRACE("NormSetUserTimer(2) session: %p\n", norm_session);
NormSetUserTimer(norm_session, 0.0);
}
else if (NORM_OBJECT_INVALID != tx_stream)
@ -710,6 +889,12 @@ void NormSocket::Shutdown()
}
socket_state = CLOSING;
}
else
{
// Use a zero-timeout to immediately post NORM_SOCKET_CLOSE notification
TRACE("NormSetUserTimer(6) session: %p\n", norm_session);
NormSetUserTimer(norm_session, 0.0);
}
} // end NormSocket::Shutdown()
void NormSocket::Close()
@ -729,6 +914,7 @@ void NormSocket::Close()
NormNodeHandle node = NormGetAckingNodeHandle(mcast_session, nodeId);
assert(NORM_NODE_INVALID != node);
NormSocket* clientSocket = (NormSocket*)NormNodeGetUserData(node);
TRACE("NormSetUserTimer(3) session: %p\n", clientSocket->norm_session);
NormSetUserTimer(clientSocket->norm_session, 0.0);
}
// for mcast server mcast_session == norm_session so it's destroyed below
@ -750,9 +936,30 @@ void NormSocket::Close()
}
if (NORM_SESSION_INVALID != norm_session)
{
NormCancelUserTimer(norm_session);
NormStopSender(norm_session);
NormStopReceiver(norm_session);
}
if (NULL != socket_info)
{
if (NULL != server_socket)
server_socket->RemoveSocketInfo(*socket_info);
delete socket_info;
socket_info = NULL;
}
// Iterate through remaining socket info and disassociate from any clients remaining
NormSocketTable::Iterator iterator(client_table);
NormSocketInfo* socketInfo;
while (NULL != (socketInfo = iterator.GetNextItem()))
{
NormSocket* clientSocket = socketInfo->GetSocket();
if (NULL != clientSocket)
clientSocket->SetSocketInfo(NULL);
client_table.Remove(*socketInfo);
delete socketInfo;
}
server_socket = NULL;
remote_node = NORM_NODE_INVALID;
tx_stream = NORM_OBJECT_INVALID;
@ -861,6 +1068,7 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
// We use the session timer to dispatch a NORM_SOCKET_CLOSE per failed client
// (This will also remove the client from this server's acking list)
clientSocket->socket_state = CLOSING;
TRACE("NormSetUserTimer(4) session: %p\n", clientSocket->norm_session);
NormSetUserTimer(clientSocket->norm_session, 0.0);
}
}
@ -891,8 +1099,33 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
switch (socket_state)
{
case LISTENING:
socketEvent.type = NORM_SOCKET_ACCEPT;
{
NormSocketInfo* socketInfo = client_table.FindSocketInfo(event.sender);
if (NULL == socketInfo)
{
// Add info for client socket pending acceptance
socketInfo = new NormSocketInfo(NormGetSocketInfo(event.sender));
if (NULL != socketInfo)
{
client_table.Insert(*socketInfo);
socketEvent.type = NORM_SOCKET_ACCEPT;
}
else
{
perror("NormSocket::GetSocketEvent() error: unable to add pending client info to server socket:\n");
}
}
else // duplicative accept event for existing socket, so ignore
{
ProtoAddress remoteAddr;
socketInfo->GetRemoteAddress(remoteAddr);
fprintf(stderr, "NormSocket::GetSocketEvent() warning: duplicative %s from client %s/%hu...\n",
(NORM_REMOTE_SENDER_NEW == event.type) ? "new" : "reset",
remoteAddr.GetHostString(), remoteAddr.GetPort());
// TBD - should we go ahead and delete this event.sender???
}
break;
}
case ACCEPTING:
if (IsServerSide() && IsClientSocket() && (NORM_NODE_INVALID != remote_node))
{
@ -901,6 +1134,7 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
case CONNECTING:
// TBD - We should validate that it's the right remote sender
// (i.e., by source address and/or nodeId)
TRACE("NormCancelUserTimer(1) norm_session: %p\n", norm_session);
NormCancelUserTimer(norm_session);
socketEvent.type = NORM_SOCKET_CONNECT;
NormSetSynStatus(norm_session, false);
@ -983,6 +1217,7 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
case NORM_SEND_ERROR:
{
TRACE("NormSocket got SEND ERROR\n");
switch (socket_state)
{
case CONNECTING:
@ -1153,6 +1388,7 @@ void NormSocket::GetSocketEvent(const NormEvent& event, NormSocketEvent& socketE
else
{
// This still allows at least a chance of an ACK to be sent upon completion
TRACE("NormSetUserTimer(5) session: %p\n", norm_session);
NormSetUserTimer(norm_session, 0.0);
}
socketEvent.type = NORM_SOCKET_CLOSING;
@ -1224,10 +1460,44 @@ NormSocketHandle NormAccept(NormSocketHandle serverSocket, NormNodeHandle client
NormSuspendInstance(serverInstance);
NormSocketHandle clientSocket = s->Accept(client, instance);
NormResumeInstance(serverInstance);
if (NORM_SOCKET_INVALID != clientSocket)
{
// Keep track of this client socket in our serverSocket socket_table
NormSocketInfo* socketInfo = s->FindSocketInfo(client);
ASSERT(NULL != socketInfo);
NormSocket* c = (NormSocket*)clientSocket;
socketInfo->SetSocket(c);
c->SetSocketInfo(socketInfo);
}
return clientSocket;
} // end NormAccept()
NORM_API_LINKAGE
extern bool NormSendCommandTo(NormSessionHandle sessionHandle,
const char* cmdBuffer,
unsigned int cmdLength,
const char* addr,
UINT16 port);
void NormReject(NormSocketHandle serverSocket,
NormNodeHandle clientNode)
{
// Simple, single "reject" command for moment (TBD - do something more stateful so app will be bothered less)
// Send "reject" command to source
char buffer[2];
buffer[0] = NORM_SOCKET_VERSION;
buffer[1] = NORM_SOCKET_CMD_REJECT;
NormSocket* s = (NormSocket*)serverSocket;
NormSocketInfo socketInfo = NormGetSocketInfo(clientNode);
ProtoAddress dest;
socketInfo.GetRemoteAddress(dest);
char destString[64];
destString[63] = '\0';
dest.GetHostString(destString, 63);
NormSendCommandTo(s->GetSession(), buffer, 2,destString, dest.GetPort());
} // end NormReject()
// TBD - provide options for binding to a specific local address, interface, etc
bool NormConnect(NormSocketHandle normSocket, const char* serverAddr, UINT16 serverPort, UINT16 localPort, const char* groupAddr, NormNodeId clientId)
{
@ -1248,7 +1518,7 @@ ssize_t NormWrite(NormSocketHandle normSocket, const void *buf, size_t nbyte)
NormSocket* s = (NormSocket*)normSocket;
NormInstanceHandle instance = s->GetInstance();
NormSuspendInstance(instance);
ssize_t result = (ssize_t)s->Write((const char*)buf, nbyte);
ssize_t result = (ssize_t)s->Write((const char*)buf, (unsigned int)nbyte);
NormResumeInstance(instance);
return result;
} // end NormWrite()
@ -1271,7 +1541,7 @@ ssize_t NormRead(NormSocketHandle normSocket, void *buf, size_t nbyte)
NormInstanceHandle instance = s->GetInstance();
NormSuspendInstance(instance);
// TBD - make sure s->rx_stream is valid
unsigned int numBytes = nbyte;
unsigned int numBytes = (unsigned int)nbyte;
ssize_t result;
if (s->Read((char*)buf, numBytes))
result = numBytes;

View File

@ -78,6 +78,9 @@ bool NormConnect(NormSocketHandle normSocket,
NormSocketHandle NormAccept(NormSocketHandle serverSocket,
NormNodeHandle clientNode,
NormInstanceHandle instance = NORM_INSTANCE_INVALID);
void NormReject(NormSocketHandle serverSocket,
NormNodeHandle clientNode);
void NormShutdown(NormSocketHandle normSocket);

View File

@ -367,6 +367,9 @@ void NormSetRxPortReuse(NormSessionHandle sessionHandle,
NORM_API_LINKAGE
UINT16 NormGetRxPort(NormSessionHandle sessionHandle);
NORM_API_LINKAGE
bool NormGetRxBindAddress(NormSessionHandle sessionHandle, char* addr, unsigned int& addrLen, UINT16& port);
// TBD - We should probably have a "NormSetCCMode(NormCCMode ccMode)" function for users
NORM_API_LINKAGE
void NormSetEcnSupport(NormSessionHandle sessionHandle,
@ -580,6 +583,9 @@ void NormStreamSetPushEnable(NormObjectHandle streamHandle,
NORM_API_LINKAGE
bool NormStreamHasVacancy(NormObjectHandle streamHandle);
NORM_API_LINKAGE
unsigned int NormStreamGetVacancy(NormObjectHandle streamHandle, unsigned int bytesWanted = 0);
NORM_API_LINKAGE
void NormStreamMarkEom(NormObjectHandle streamHandle);

View File

@ -134,7 +134,7 @@ class NormLossEstimator2
history[1] = (unsigned int)((1.0 / lossFraction) + 0.5);
}
unsigned long CurrentLossInterval() {return history[0];}
unsigned int LastLossInterval() {return history[1];}
unsigned long LastLossInterval() {return history[1];}
void SetIgnoreLoss(bool state)
{ignore_loss = state;}

View File

@ -484,6 +484,10 @@ class NormStreamObject : public NormObject
bool HasVacancy()
{return (stream_closing ? false : write_vacancy);}
// Returns how many bytes can be written to stream without blocking
// (up to 'wanted' for non-zero 'wanted', otherwise max vacancy available)
unsigned int GetVacancy(unsigned int wanted = 0);
NormBlock* StreamBlockLo()
{return stream_buffer.Find(stream_buffer.RangeLo());}
void SetLastNackTime(NormBlockId blockId, const ProtoTime& theTime)

View File

@ -236,6 +236,9 @@ class NormSession
UINT16 GetRxPort() const;
const ProtoAddress& GetRxBindAddr() const
{return rx_bind_addr;}
// "SetEcnSupport(true)" sets up raw packet capture (pcap) so that incoming packet
// ECN status may be checked
// NOTE: only effective _before_ sndr/rcvr startup!
@ -428,6 +431,9 @@ class NormSession
bool SenderSendCmd(const char* cmdBuffer, unsigned int cmdLength, bool robust);
void SenderCancelCmd();
// The following method is currently only used for NormSocket purposes
bool SenderSendAppCmd(const char* buffer, unsigned int length, const ProtoAddress& dst);
void SenderSetSynStatus(bool state)
{syn_status = state;}
@ -697,8 +703,6 @@ class NormSession
bool SenderBuildRepairAdv(NormCmdRepairAdvMsg& cmd);
void SenderUpdateGroupSize();
bool SenderQueueAppCmd();
// The following method is only used for NormSocket purposes
bool SenderSendAppCmd(const char* buffer, unsigned int length, const ProtoAddress& dst);
// Receiver message handling routines
void ReceiverHandleObjectMessage(const struct timeval& currentTime,

View File

@ -187,7 +187,7 @@ normStreamer: $(STREAMER_OBJ) libnorm.a $(LIBPROTO)
mkdir -p ../bin
cp $@ ../bin/$@
# (nocmCast) file sender/receiver
# (normCast) file sender/receiver
CAST_SRC = $(EXAMPLE)/normCast.cpp
CAST_OBJ = $(CAST_SRC:.cpp=.o)
@ -195,6 +195,27 @@ normCast: $(CAST_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(CAST_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
mkdir -p ../bin
cp $@ ../bin/$@
# These are the new "NormSocket" API extension examples
SERVER_SRC = $(EXAMPLE)/normServer.cpp $(EXAMPLE)/normSocket.cpp
SERVER_OBJ = $(SERVER_SRC:.cpp=.o)
normServer: $(SERVER_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(SERVER_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
mkdir -p ../bin
cp $@ ../bin/$@
CLIENT_SRC = $(EXAMPLE)/normClient.cpp $(EXAMPLE)/normSocket.cpp
CLIENT_OBJ = $(CLIENT_SRC:.cpp=.o)
normClient: $(CLIENT_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(CLIENT_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
mkdir -p ../bin
cp $@ ../bin/$@
# (pcap2norm) - parses pcap (e.g. tcpdump) file and prints NORM trace
PCAP_SRC = $(COMMON)/pcap2norm.cpp

View File

@ -220,8 +220,11 @@ void NormInstance::Notify(NormController::Event event,
{
case SEND_OK:
// Purge any pending NORM_SEND_ERROR notifications for session
TRACE("purging SEND_ERROR ...\n");
PurgeNotifications(session, NORM_SEND_ERROR);
return;
case SEND_ERROR:
TRACE("got SEND_ERROR\n");
default:
break;
}
@ -554,6 +557,7 @@ bool NormInstance::GetNextEvent(NormEvent* theEvent)
case NORM_SEND_ERROR:
{
NormSession* session = (NormSession*)next->event.session;
TRACE("calling ClearSendError() ....\n");
session->ClearSendError();
break;
}
@ -1073,6 +1077,40 @@ UINT16 NormGetRxPort(NormSessionHandle sessionHandle)
} // end NormGetRxPort()
NORM_API_LINKAGE
bool NormGetRxBindAddress(NormSessionHandle sessionHandle, char* addr, unsigned int& addrLen, UINT16& port)
{
bool result = false;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if ((NULL != instance) && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
port = session->GetRxPort();
ProtoAddress bindAddr = session->GetRxBindAddr();
if (!bindAddr.IsValid())
{
addrLen = 0;
result = true;
}
else if (addrLen < bindAddr.GetLength())
{
addrLen = bindAddr.GetLength();
}
else
{
addrLen = bindAddr.GetLength();
memcpy(addr, bindAddr.GetRawHostAddress(), addrLen);
result = true;
}
instance->dispatcher.ResumeThread();
}
else
{
addrLen = port = 0;
}
return result;
} // end NormGetRxBindAddress()
NORM_API_LINKAGE
bool NormSetTxPort(NormSessionHandle sessionHandle,
UINT16 txPort,
@ -1132,7 +1170,7 @@ bool NormPresetObjectInfo(NormSessionHandle sessionHandle,
NormSession* session = (NormSession*)sessionHandle;
if (session)
{
result = session->SetPresetFtiData(objectSize, segmentSize, numData, numParity);
result = session->SetPresetFtiData((unsigned int)objectSize, segmentSize, numData, numParity);
if (result) session->SenderSetFtiMode(NormSession::FTI_PRESET);
}
instance->dispatcher.ResumeThread();
@ -1511,7 +1549,7 @@ NormSessionId NormGetRandomSessionId()
{
ProtoTime currentTime;
currentTime.GetCurrentTime();
srand(currentTime.usec()); // seed random number generator
srand((unsigned int)currentTime.usec()); // seed random number generator
return (NormSessionId)rand();
} // end NormGetRandomSessionId()
@ -1956,6 +1994,22 @@ bool NormStreamHasVacancy(NormObjectHandle streamHandle)
return result;
} // end NormStreamHasVacancy()
NORM_API_LINKAGE
unsigned int NormStreamGetVacancy(NormObjectHandle streamHandle, unsigned int bytesWanted)
{
bool result = false;
NormInstance* instance = NormInstance::GetInstanceFromObject(streamHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormStreamObject* stream =
static_cast<NormStreamObject*>((NormObject*)streamHandle);
if (NULL != stream)
result = stream->GetVacancy(bytesWanted);
instance->dispatcher.ResumeThread();
}
return result;
} // end NormStreamGetVacancy()
NORM_API_LINKAGE
void NormStreamMarkEom(NormObjectHandle streamHandle)
{
@ -2247,6 +2301,32 @@ void NormCancelCommand(NormSessionHandle sessionHandle)
}
} // end NormCancelCommand()
// This one is not part of the public API (for NormSocket use currently)
NORM_API_LINKAGE
bool NormSendCommandTo(NormSessionHandle sessionHandle,
const char* cmdBuffer,
unsigned int cmdLength,
const char* addr,
UINT16 port)
{
bool result = false;
NormInstance* instance = NormInstance::GetInstanceFromSession(sessionHandle);
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
ProtoAddress dest;
if (dest.ResolveFromString(addr))
{
dest.SetPort(port);
result = session->SenderSendAppCmd(cmdBuffer, cmdLength, dest);
}
instance->dispatcher.ResumeThread();
}
return result;
} // end NormSendCommandTo()
NORM_API_LINKAGE
void NormSetSynStatus(NormSessionHandle sessionHandle, bool state)
{
@ -2457,7 +2537,7 @@ bool NormPreallocateRemoteSender(NormSessionHandle sessionHandle,
if (instance && instance->dispatcher.SuspendThread())
{
NormSession* session = (NormSession*)sessionHandle;
result = session->PreallocateRemoteSender(bufferSize, segmentSize, numData, numParity, streamBufferSize);
result = session->PreallocateRemoteSender((unsigned int)bufferSize, segmentSize, numData, numParity, streamBufferSize);
instance->dispatcher.ResumeThread();
}
return result;
@ -2754,7 +2834,7 @@ NORM_API_LINKAGE
bool NormNodeGetAddress(NormNodeHandle nodeHandle,
char* addrBuffer,
unsigned int* bufferLen,
UINT16* port)
UINT16* port)
{
bool result = false;
if (NORM_NODE_INVALID != nodeHandle)

View File

@ -156,7 +156,7 @@ inline gf gf_mul(int x, int y)
}
#define init_mul_table()
#define USE_GF_MULC register gf * __gf_mulc_
#define USE_GF_MULC gf * __gf_mulc_
#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
@ -261,8 +261,8 @@ static void generate_gf()
static void addmul1(gf* dst1, gf* src1, gf c, int sz)
{
USE_GF_MULC ;
register gf* dst = dst1;
register gf* src = src1 ;
gf* dst = dst1;
gf* src = src1 ;
gf* lim = &dst[sz - UNROLL + 1] ;
GF_MULC0(c) ;

View File

@ -133,7 +133,7 @@ static inline gf modnn(int x)
static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
#define gf_mul(x,y) gf_mul_table[x][y]
#define USE_GF_MULC register gf * __gf_mulc_
#define USE_GF_MULC gf * __gf_mulc_
#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
@ -262,8 +262,8 @@ static void generate_gf()
static void addmul1(gf* dst1, gf* src1, gf c, int sz)
{
USE_GF_MULC ;
register gf* dst = dst1;
register gf* src = src1 ;
gf* dst = dst1;
gf* src = src1 ;
gf* lim = &dst[sz - UNROLL + 1] ;
GF_MULC0(c) ;

View File

@ -690,7 +690,7 @@ bool NormDirectoryIterator::GetNextFile(char* fileName)
NormFile::Type type = NormFile::GetType(fileName);
if (NormFile::NORMAL == type)
{
int nameLen = strlen(fileName);
size_t nameLen = strlen(fileName);
nameLen = MIN(PATH_MAX, nameLen);
nameLen -= path_len;
memmove(fileName, fileName+path_len, nameLen);

View File

@ -238,7 +238,7 @@ bool NormSenderNode::AllocateBuffers(unsigned int bufferSpace,
unsigned long numSegments = numBlocks * segPerBlock;
if (!block_pool.Init(numBlocks, blockSize))
if (!block_pool.Init((UINT32)numBlocks, blockSize))
{
PLOG(PL_FATAL, "NormSenderNode::AllocateBuffers() block_pool init error\n");
Close();
@ -246,7 +246,7 @@ bool NormSenderNode::AllocateBuffers(unsigned int bufferSpace,
}
// Segment buffers include space for NORM_OBJECT_STREAM stream payload header
if (!segment_pool.Init(numSegments, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()))
if (!segment_pool.Init((unsigned int)numSegments, segmentSize+NormDataMsg::GetStreamPayloadHeaderLength()))
{
PLOG(PL_FATAL, "NormSenderNode::AllocateBuffers() segment_pool init error\n");
Close();
@ -1571,8 +1571,12 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
}
// else wait for NORM_INFO message with sender FTI
}
if (gotFTI && !AllocateBuffers(session.RemoteSenderBufferSize(), fecId, ftiData.GetFecInstanceId(), ftiData.GetFecFieldSize(),
ftiData.GetSegmentSize(), ftiData.GetFecMaxBlockLen(), ftiData.GetFecNumParity()))
if (gotFTI && !AllocateBuffers((unsigned int)session.RemoteSenderBufferSize(),
fecId, ftiData.GetFecInstanceId(),
ftiData.GetFecFieldSize(),
ftiData.GetSegmentSize(),
ftiData.GetFecMaxBlockLen(),
ftiData.GetFecNumParity()))
{
PLOG(PL_ERROR, "NormSenderNode::HandleObjectMessage() node>%lu sender>%lu buffer allocation error\n",
(unsigned long)LocalNodeId(), (unsigned long)GetId());
@ -1980,7 +1984,7 @@ void NormSenderNode::Sync(NormObjectId objectId)
incrementResyncCount = true; // more than just a trim
}
unsigned long numBits = (UINT16)(objectId - firstPending);
rx_pending_mask.UnsetBits(firstPending, numBits);
rx_pending_mask.UnsetBits(firstPending, (UINT32)numBits);
if (incrementResyncCount) IncrementResyncCount();
}
}

View File

@ -3982,6 +3982,48 @@ void NormStreamObject::Terminate()
session.TouchSender();
} // end NormStreamObject::Terminate()
unsigned int NormStreamObject::GetVacancy(unsigned int wanted)
{
// Computes how many bytes are available for _immediate_ writing
ASSERT(Compare(write_index.block, tx_index.block) >= 0);
unsigned int maxDelta = block_pool.GetTotal() >> 1;
UINT32 blockDelta = (UINT32)Difference(write_index.block, tx_index.block);
if (blockDelta > maxDelta) return 0;
UINT32 nBytes = 0;
NormBlock* block = stream_buffer.Find(write_index.block);
if (NULL != block)
{
char* segment = block->GetSegment(write_index.segment);
if (NULL != segment)
{
UINT16 index = NormDataMsg::ReadStreamPayloadLength(segment);
nBytes += segment_size - index;
}
else
{
nBytes += segment_size;
}
nBytes += (ndata - write_index.segment - 1) * segment_size;
}
unsigned int blocksAllowed = maxDelta - blockDelta;
unsigned int poolCount = block_pool.GetCount();
if (poolCount >= blocksAllowed)
poolCount = blocksAllowed;
nBytes += poolCount * ndata * segment_size;
NormBlockBuffer::Iterator iterator(block_buffer);
while ((NULL != (block = iterator.GetNextBlock())) &&
(blocksAllowed > 0) &&
((0 == wanted) || (nBytes < wanted)))
{
double delay = session.GetFlowControlDelay() - block->GetNackAge();
if (block->IsPending() || (delay >= 1.0e-06)) break;
nBytes += (segment_size * ndata);
blocksAllowed--;
}
return nBytes;
} // end NormStreamObject::GetVacancy()
UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
{
UINT32 nBytes = 0;
@ -3999,7 +4041,7 @@ UINT32 NormStreamObject::Write(const char* buffer, UINT32 len, bool eom)
}
// This old code detected buffer "fullness" by offset instead of segment index
// but, the problem there was when apps wrote & flushed messages smaller than
// the segment_size, the buffer used up before this detected it.
// the segment_size, the buffer was used up before this detected it.
//INT32 deltaOffset = write_offset - tx_offset; // (TBD) deprecate tx_offset
//ASSERT(deltaOffset >= 0);
//if (deltaOffset >= (INT32)object_size.LSB())

View File

@ -789,7 +789,7 @@ NormBlockId NormBlockBuffer::RangeMin() const
if (range_max > 1)
{
NormBlockId rangeMin = range_hi;
Decrement(rangeMin, range_max - 1);
Decrement(rangeMin, (UINT32)range_max - 1);
return rangeMin;
}
else
@ -841,7 +841,7 @@ bool NormBlockBuffer::Insert(NormBlock* theBlock)
// else if (blockId < range_lo)
else if (Compare(blockId, range_lo) < 0)
{
UINT32 newRange = (UINT32)Difference(range_lo, blockId) + range;
UINT32 newRange = (UINT32)Difference(range_lo, blockId) + (UINT32)range;
if (newRange > range_max) return false;
range_lo = blockId;
range = newRange;
@ -849,7 +849,7 @@ bool NormBlockBuffer::Insert(NormBlock* theBlock)
// else if (blockId > range_hi)
else if (Compare(blockId, range_hi) > 0)
{
UINT32 newRange = (UINT32)Difference(blockId, range_hi) + range;
UINT32 newRange = (UINT32)Difference(blockId, range_hi) + (UINT32)range;
if (newRange > range_max) return false;
range_hi = blockId;
range = newRange;

View File

@ -254,6 +254,8 @@ bool NormSession::Open()
if (!tx_socket->SetFragmentation(fragmentation))
PLOG(PL_WARN, "NormSession::Open() warning: tx_socket.SetFragmentation() error\n");
TRACE("NormSession::Open() address %s\n", address.GetHostString());
if (address.IsMulticast())
{
if (!tx_socket->SetTTL(ttl))
@ -774,14 +776,14 @@ bool NormSession::StartSender(UINT16 instanceId,
if (numBlocks < 2) numBlocks = 2;
unsigned long numSegments = numBlocks * numParity;
if (!block_pool.Init(numBlocks, blockSize))
if (!block_pool.Init((UINT32)numBlocks, blockSize))
{
PLOG(PL_FATAL, "NormSession::StartSender() block_pool init error\n");
StopSender();
return false;
}
if (!segment_pool.Init(numSegments, segmentSize + NormDataMsg::GetStreamPayloadHeaderLength()))
if (!segment_pool.Init((unsigned int)numSegments, segmentSize + NormDataMsg::GetStreamPayloadHeaderLength()))
{
PLOG(PL_FATAL, "NormSession::StartSender() segment_pool init error\n");
StopSender();
@ -2098,9 +2100,9 @@ bool NormSession::SetTxCacheBounds(NormObjectSize sizeMax,
{
bool result = true;
tx_cache_size_max = sizeMax;
tx_cache_count_min = (countMin < countMax) ? countMin : countMax;
tx_cache_count_min = (unsigned int)((countMin < countMax) ? countMin : countMax);
if (tx_cache_count_min < 1) tx_cache_count_min = 1;
tx_cache_count_max = (countMax > countMin) ? countMax : countMin;
tx_cache_count_max = (unsigned int)((countMax > countMin) ? countMax : countMin);
if (tx_cache_count_max < 1) tx_cache_count_max = 1;
tx_cache_count_min &= 0x00007fff; // limited to one-half of 16-bit NormObjectId space
@ -2127,15 +2129,15 @@ bool NormSession::SetTxCacheBounds(NormObjectSize sizeMax,
if (countMax != tx_table.GetRangeMax())
{
tx_table.SetRangeMax((UINT16)countMax);
result = tx_pending_mask.Resize(countMax);
result &= tx_repair_mask.Resize(countMax);
result = tx_pending_mask.Resize((UINT32)countMax);
result &= tx_repair_mask.Resize((UINT32)countMax);
if (!result)
{
countMax = tx_pending_mask.GetSize();
if (tx_repair_mask.GetSize() < countMax)
countMax = tx_repair_mask.GetSize();
if (tx_cache_count_max > countMax)
tx_cache_count_max = countMax;
tx_cache_count_max = (unsigned int)countMax;
if (tx_cache_count_min > tx_cache_count_max)
tx_cache_count_min = tx_cache_count_max;
}
@ -2238,6 +2240,7 @@ void NormSession::TxSocketRecvHandler(ProtoSocket& theSocket,
}
else
{
TRACE("NormSession::TxSocketRecvHandler() RecvFrom error\n");
// Probably an ICMP "port unreachable" error
// Note we purposefull do _not_ set the "posted_send_error"
// status here because we do not want this notification
@ -2359,12 +2362,16 @@ void NormSession::RxSocketRecvHandler(ProtoSocket& theSocket,
}
else
{
TRACE("NormSession::RxSocketRecvHandler() RecvFrom error address:%s (unicast:%d)\n", Address().GetHostString(), Address().IsUnicast());
// Probably an ICMP "port unreachable" error
// Note we purposefull do _not_ set the "posted_send_error"
// status here because we do not want this notification
// cleared due to SEND_OK status since it's receiver driven
if (Address().IsUnicast())
{
TRACE("posting send error ...\n");
Notify(NormController::SEND_ERROR, NULL, NULL);
}
break;
}
}
@ -3324,7 +3331,7 @@ void NormSession::SenderHandleCCFeedback(struct timeval currentTime,
ccFlags = NormCC::RTT;
ccRtt = savedRtt;
ccLoss = savedLoss;
ccRate = savedRate,
ccRate = savedRate;
ccSequence = savedSequence;
currentTime = savedTime;
}
@ -4344,6 +4351,27 @@ void NormSession::SenderCancelCmd()
}
} // end NormSession::SenderCancelCmd()
bool NormSession::SenderSendAppCmd(const char* buffer, unsigned int length, const ProtoAddress& dst)
{
// Build/immediately send a NORM_CMD(APPLICATION) message
NormCmdAppMsg appMsg;
appMsg.Init();
appMsg.SetDestination(address);
appMsg.SetGrtt(grtt_quantized);
appMsg.SetBackoffFactor((unsigned char)backoff_factor);
appMsg.SetGroupSize(gsize_quantized);
// We use a surrogate segment_size in case sender not configured (e.g. server-listener)
appMsg.SetContent(buffer, length, segment_size ? segment_size : 64);
appMsg.SetDestination(dst);
if (MSG_SEND_OK != SendMessage(appMsg))
PLOG(PL_ERROR, "NormSession::SenderSendAppCmd() node>%lu sender unable to send app-defined cmd ...\n",
(unsigned long)LocalNodeId());
else
PLOG(PL_DEBUG, "NormSession::SenderSendAppCmd() node>%lu sender sending app-defined cmd len:%u...\n",
(unsigned long)LocalNodeId(), appMsg.GetLength());
return true;
} // end NormSession::SenderSendAppCmd()
bool NormSession::SenderQueueAppCmd()
{
if (0 == cmd_count) return false;
@ -4389,27 +4417,6 @@ bool NormSession::OnCmdTimeout(ProtoTimer& theTimer)
return true;
} // end NormSession::OnCmdTimeout()
bool NormSession::SenderSendAppCmd(const char* buffer, unsigned int length, const ProtoAddress& dst)
{
// Build/immediately send a NORM_CMD(APPLICATION) message
NormCmdAppMsg appMsg;
appMsg.Init();
appMsg.SetDestination(address);
appMsg.SetGrtt(grtt_quantized);
appMsg.SetBackoffFactor((unsigned char)backoff_factor);
appMsg.SetGroupSize(gsize_quantized);
// We use a surrogate segment_size in case sender not configured (e.g. server-listener)
appMsg.SetContent(buffer, length, segment_size ? segment_size : 64);
appMsg.SetDestination(dst);
if (MSG_SEND_OK != SendMessage(appMsg))
PLOG(PL_ERROR, "NormSession::SenderSendAppCmd() node>%lu sender unable to send app-defined cmd ...\n",
(unsigned long)LocalNodeId());
else
PLOG(PL_DEBUG, "NormSession::SenderSendAppCmd() node>%lu sender sending app-defined cmd len:%u...\n",
(unsigned long)LocalNodeId(), appMsg.GetLength());
return true;
} // end NormSession::SenderSendAppCmd()
void NormSession::ActivateFlowControl(double delay, NormObjectId objectId, NormController::Event event)
{
flow_control_object = objectId;