bool Connection::send( const Connections& connections, Packet& packet, const void* data, const uint64_t dataSize, const bool isLocked ) { if( connections.empty( )) return true; if( dataSize <= 8 ) // fits in existing packet { if( dataSize != 0 ) memcpy( (char*)(&packet) + packet.size-8, data, dataSize ); return send( connections, packet, isLocked ); } const uint64_t headerSize = packet.size - 8; const uint64_t size = headerSize + dataSize; if( size > EQ_ASSEMBLE_THRESHOLD ) { // OPT: lock the connection and use two send() to avoid big memcpy packet.size = size; bool success = true; for( Connections::const_iterator i= connections.begin(); i<connections.end(); ++i ) { ConnectionPtr connection = *i; if( !isLocked ) connection->lockSend(); if( !connection->send( &packet, headerSize, true ) || !connection->send( data, dataSize, true )) { success = false; } if( !isLocked ) connection->unlockSend(); } return success; } char* buffer = (char*)alloca( size ); memcpy( buffer, &packet, packet.size-8 ); memcpy( buffer + packet.size-8, data, dataSize ); ((Packet*)buffer)->size = size; bool success = true; for( Connections::const_iterator i = connections.begin(); i < connections.end(); ++i ) { ConnectionPtr connection = *i; if( !connection->send( buffer, size, isLocked )) success = false; } return success; }
int LuaChat::broadcastOps(lua_State* L) { luaL_checkany(L, 2); if (lua_type(L, 2) != LUA_TTABLE) return luaL_error(L, "broadcastOps requires a table as the second argument."); string message = luaL_checkstring(L, 1); message += " "; json_t* json = luaToJson(L); const char* jsonstr = json_dumps(json, JSON_COMPACT); message += jsonstr; free((void*) jsonstr); json_decref(json); lua_pop(L, 2); MessagePtr outMessage(MessageBuffer::FromString(message)); const oplist_t ops = ServerState::getOpList(); for (oplist_t::const_iterator i = ops.begin(); i != ops.end(); ++i) { string name(*i); int length = name.length(); for (int x = 0; x < length; ++x) { name[x] = tolower(name[x]); } ConnectionPtr con = ServerState::getConnection(name); if (con != 0) { con->send(outMessage); } } return 0; }
bool LocalNode::_connect( NodePtr node, ConnectionPtr connection ) { EQASSERT( connection.isValid( )); EQASSERT( node->getNodeID() != getNodeID( )); if( !node.isValid() || _state != STATE_LISTENING || !connection->isConnected() || node->_state != STATE_CLOSED ) { return false; } _addConnection( connection ); // send connect packet to peer NodeConnectPacket packet; packet.requestID = registerRequest( node.get( )); packet.nodeID = _id; packet.nodeType = getType(); connection->send( packet, serialize( )); bool connected = false; if( !waitRequest( packet.requestID, connected, 10000 /*ms*/ )) { EQWARN << "Node connection handshake timeout - peer not a Collage node?" << std::endl; return false; } if( !connected ) return false; EQASSERT( node->_id != NodeID::ZERO ); EQASSERTINFO( node->_id != _id, _id ); EQINFO << node << " connected to " << *(Node*)this << std::endl; return true; }
void Channel::sendToChannel(ConnectionPtr src, string& message) { MessagePtr outMessage(MessageBuffer::fromString(message)); for (chconlist_t::iterator i = participants.begin(); i != participants.end(); ++i) { ConnectionPtr p = *i; if (p != src) p->send(outMessage); } }
void BufferConnection::sendBuffer( ConnectionPtr connection ) { if( _buffer.isEmpty( )) return; if( !connection ) { EQWARN << "NULL connection during buffer write" << std::endl; return; } EQCHECK( connection->send( _buffer.getData(), _buffer.getSize() )); _buffer.setSize( 0 ); }
OCommand::~OCommand() { if( _impl->isLocked ) { LBASSERT( _impl->size > 0 ); const uint64_t size = _impl->size + getBuffer().getSize(); const size_t minSize = Buffer::getMinSize(); const Connections& connections = getConnections(); if( size < minSize ) // Fill send to minimal size { const size_t delta = minSize - size; void* padding = alloca( delta ); for( ConnectionsCIter i = connections.begin(); i != connections.end(); ++i ) { ConnectionPtr connection = *i; connection->send( padding, delta, true ); } } for( ConnectionsCIter i = connections.begin(); i != connections.end(); ++i ) { ConnectionPtr connection = *i; connection->unlockSend(); } _impl->isLocked = false; _impl->size = 0; reset(); } else disable(); if( _impl->dispatcher ) { LBASSERT( _impl->localNode ); // #145 proper local command dispatch? LBASSERT( _impl->size == 0 ); const uint64_t size = getBuffer().getSize(); BufferPtr buffer = _impl->localNode->allocBuffer( size ); buffer->swap( getBuffer( )); reinterpret_cast< uint64_t* >( buffer->getData( ))[ 0 ] = size; ICommand cmd( _impl->localNode, _impl->localNode, buffer, false ); _impl->dispatcher->dispatchCommand( cmd ); } delete _impl; }
bool Connection::send( const Connections& connections, Packet& packet, const void* const* items, const uint64_t* sizes, const size_t nItems ) { if( connections.empty( )) return true; packet.size -= 8; const uint64_t headerSize = packet.size; for( size_t i = 0; i < nItems; ++i ) { EQASSERT( sizes[i] > 0 ); packet.size += sizes[ i ] + sizeof( uint64_t ); } bool success = true; for( Connections::const_iterator i = connections.begin(); i < connections.end(); ++i ) { ConnectionPtr connection = *i; connection->lockSend(); if( !connection->send( &packet, headerSize, true )) success = false; for( size_t j = 0; j < nItems; ++j ) if( !connection->send( &sizes[j], sizeof(uint64_t), true ) || !connection->send( items[j], sizes[j], true )) { success = false; } connection->unlockSend(); } return success; }
bool Connection::send( const Connections& connections, const Packet& packet, const bool isLocked ) { if( connections.empty( )) return true; bool success = true; for( Connections::const_iterator i= connections.begin(); i<connections.end(); ++i ) { ConnectionPtr connection = *i; if( !connection->send( &packet, packet.size, isLocked )) success = false; } return success; }
void Instance::exit() { try { ConnectionPtr conn = getConnection("ua"); seq_t seq = conn->getNextSeq(); MsgBody body; user_access_server::client_methods::rpc::UnbindRequest unbind_req; body.addRequest(user_access_server::client_methods::rpc::CmdID_Unbind, seq, 0, unbind_req); conn->send(rpc::OP_REQUEST, body); } catch (...) { } closeAllConnections(); }
AckChatMsg::AckChatMsg(InstancePtr instance, const UserID& target_uid, msg_id_t msg_id, AckChatMsg::CallbackPtr cb) { if (!msg_id) throw AppException("msg id is null"); instant_messaging_server::methods::rpc::AckChatMsgRequest ack_chat_req; ack_chat_req.mutable_sender_usr_id()->set_uid(target_uid.uid); if (!target_uid.domain.empty()) ack_chat_req.mutable_sender_usr_id()->set_domain(target_uid.domain); ack_chat_req.set_msg_id(msg_id); ConnectionPtr conn = instance->getConnection("ua"); seq_t seq = conn->getNextSeq(); MsgBody body; body.addTarget("im"); body.addRequest(instant_messaging_server::methods::rpc::CmdID_AckChatMsg, seq, 0, ack_chat_req); conn->send(rpc::OP_REQUEST, body); conn->addRequest(seq, cb); }
void OCommand::sendData( const void* buffer, const uint64_t size, const bool last ) { LBASSERT( !_impl->dispatcher ); LBASSERT( last ); LBASSERTINFO( size >= 16, size ); LBASSERT( getBuffer().getData() == buffer ); LBASSERT( getBuffer().getSize() == size ); LBASSERT( getBuffer().getMaxSize() >= COMMAND_MINSIZE ); // Update size field uint8_t* bytes = getBuffer().getData(); reinterpret_cast< uint64_t* >( bytes )[ 0 ] = _impl->size + size; const uint64_t sendSize = _impl->isLocked ? size : LB_MAX( size, COMMAND_MINSIZE); const Connections& connections = getConnections(); for( ConnectionsCIter i = connections.begin(); i != connections.end(); ++i ) { ConnectionPtr connection = *i; connection->send( bytes, sendSize, _impl->isLocked ); } }
AckGroupSysMsg::AckGroupSysMsg(InstancePtr instance, const GroupID& group_id, const string& channel, msg_id_t sysmsg_id, AckGroupSysMsg::CallbackPtr cb) { if (!sysmsg_id) throw AppException("sysmsg id is null"); group_messaging_server::methods::rpc::AckGrpSysMsgRequest ack_sys_req; if (!channel.empty()) ack_sys_req.set_channel(channel); ack_sys_req.set_sysmsg_id(sysmsg_id); ConnectionPtr conn = instance->getConnection("ua"); seq_t seq = conn->getNextSeq(); Uri target; createUri(&target, "grp", group_id); MsgBody body; body.addTarget(target); body.addRequest(group_messaging_server::methods::rpc::CmdID_AckGrpSysMsg, seq, 0, ack_sys_req); conn->send(rpc::OP_REQUEST, body); conn->addRequest(seq, cb); }
bool LocalNode::_cmdConnect( Command& command ) { EQASSERT( !command.getNode().isValid( )); EQASSERT( _inReceiverThread( )); const NodeConnectPacket* packet = command.get< NodeConnectPacket >(); ConnectionPtr connection = _incoming.getConnection(); const NodeID& nodeID = packet->nodeID; EQVERB << "handle connect " << packet << std::endl; EQASSERT( nodeID != _id ); EQASSERT( _connectionNodes.find( connection ) == _connectionNodes.end( )); NodePtr remoteNode; // No locking needed, only recv thread modifies NodeHash::const_iterator i = _nodes->find( nodeID ); if( i != _nodes->end( )) { remoteNode = i->second; if( remoteNode->isConnected( )) { // Node exists, probably simultaneous connect from peer EQINFO << "Already got node " << nodeID << ", refusing connect" << std::endl; // refuse connection NodeConnectReplyPacket reply( packet ); connection->send( reply, serialize( )); // NOTE: There is no close() here. The reply packet above has to be // received by the peer first, before closing the connection. _removeConnection( connection ); return true; } } // create and add connected node if( !remoteNode ) remoteNode = createNode( packet->nodeType ); std::string data = packet->nodeData; if( !remoteNode->deserialize( data )) EQWARN << "Error during node initialization" << std::endl; EQASSERTINFO( data.empty(), data ); EQASSERTINFO( remoteNode->_id == nodeID, remoteNode->_id << "!=" << nodeID ); remoteNode->_outgoing = connection; remoteNode->_state = STATE_CONNECTED; _connectionNodes[ connection ] = remoteNode; { base::ScopedMutex< base::SpinLock > mutex( _nodes ); _nodes.data[ remoteNode->_id ] = remoteNode; } EQVERB << "Added node " << nodeID << std::endl; // send our information as reply NodeConnectReplyPacket reply( packet ); reply.nodeID = _id; reply.nodeType = getType(); connection->send( reply, serialize( )); return true; }