void ClientTCP() { TcpClient client; Packet data; data.SetByteOrder(CX_PACKET_BIG_ENDIAN); if(!client.InitializeSocket(HOSTNAME, PORT)) { cout << "Unable to connect to host " << HOSTNAME << endl; return; } cout << "Initialized TCP Client Socket\n"; char key = 0; while(key != 27) { if((key = GetChar()) > 0) { data.Clear(); // Clear packet and encode data. data.Write(key); client.Send(data); // Send data (could send character array also if desired /* Alternative way to send: client.Send(&key, 1); // Send buffer/array. */ data.Clear(); if(client.Recv(data, 50, 0)) { cout << *data.Ptr() << endl; } //cout << key; } } }
//////////////////////////////////////////////////////////////////////////////////// /// /// \brief If the IsLargeDataSet method returns true, then this method is used /// to convert message payload data into a multi-packet stream /// according to rules defined by the JAUS standards documents. /// /// This method should only be overloaded if your message contains data /// larger than Header::MaxSize - Header::MinSize (e.g. image data) and you wish /// to optimize how data is written. By default, this method calls the /// WriteMessageBody method to generate a single large byte array, which is then /// broken up into a Packet::List for the transport layer. /// /// \param[out] stream Multi-packet stream containing serialized message /// following rules of large data sets. /// \param[out] streamHeaders Headers for packet in the stream. /// \param[in] maxPayloadSize This is the maximum packet size including /// payload, does not include transport, General /// Transport Header, or Message Code (USHORT). /// \param[in] transportHeader Additional transport header data to precede /// the general transport header of each packet. /// \param[in] startingSequenceNumber Sequence number to use for packets. /// \param[in] broadcastFlags Values to use to signify if message should be /// sent using any broadcast options (e.g. /// multicast). 0 = no options, 1 = local broadcast, /// 2 = global broadcast. /// /// \return FAILURE on error, otherwise number of packets written. /// //////////////////////////////////////////////////////////////////////////////////// int Message::WriteLargeDataSet(Packet::List& stream, Header::List& streamHeaders, const UShort maxPayloadSize, const Packet* transportHeader, const UShort startingSequenceNumber, const Byte broadcastFlags) const { Header header; header.mDestinationID = mDestinationID; header.mSourceID = mSourceID; header.mPriorityFlag = mPriority; header.mBroadcastFlag = broadcastFlags; stream.clear(); streamHeaders.clear(); Packet* temp = ((Packet *)(&mStreamPayload)); temp->Clear(); if(IsLargeDataSet() && WriteMessageBody(*temp) >= 0) { LargeDataSet::CreateLargeDataSet(header, mMessageCode, *temp, stream, streamHeaders, transportHeader, maxPayloadSize, startingSequenceNumber); return (int)stream.size(); } return FAILURE; }
void MulticastClientUDP() { UdpClient client; IP4Address::List hosts; client.GetHostAddresses(hosts); cout << "IP Address for Host Machine\n"; for(int i = 0; i < (int)hosts.size(); i++ ) { cout << hosts[i].mString << endl; } Packet data; data.SetByteOrder(CX_PACKET_BIG_ENDIAN); if(!client.InitializeMulticastSocket(MULTICAST_GROUP, PORT, 1)) { cout << "Unable to connect to host " << HOSTNAME << endl; return; } cout << "Initialized UDP Client Socket on port " << PORT << endl; char key = 0; while(key != 27) { if((key = GetChar()) > 0) { data.Write(key); cout << key; client.Send(data); // Send data (could send character array also if desired data.Clear(); // Clear packet and encode data. /* Alternative way to send: client.Send(&key, 1); // Send buffer/array. */ } } }
Socket::Status TcpSocket::Receive(Packet& packet) { // First clear the variables to fill packet.Clear(); // We start by getting the size of the incoming packet Uint32 packetSize = 0; std::size_t received = 0; if (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) { // Loop until we've received the entire size of the packet // (even a 4 bytes variable may be received in more than one call) while (myPendingPacket.SizeReceived < sizeof(myPendingPacket.Size)) { char* data = reinterpret_cast<char*>(&myPendingPacket.Size) + myPendingPacket.SizeReceived; Status status = Receive(data, sizeof(myPendingPacket.Size) - myPendingPacket.SizeReceived, received); myPendingPacket.SizeReceived += received; if (status != Done) return status; } // The packet size has been fully received packetSize = ntohl(myPendingPacket.Size); } else { // The packet size has already been received in a previous call packetSize = ntohl(myPendingPacket.Size); } // Loop until we receive all the packet data char buffer[1024]; while (myPendingPacket.Data.size() < packetSize) { // Receive a chunk of data std::size_t sizeToGet = std::min(static_cast<std::size_t>(packetSize - myPendingPacket.Data.size()), sizeof(buffer)); Status status = Receive(buffer, sizeToGet, received); if (status != Done) return status; // Append it into the packet if (received > 0) { myPendingPacket.Data.resize(myPendingPacket.Data.size() + received); char* begin = &myPendingPacket.Data[0] + myPendingPacket.Data.size() - received; std::memcpy(begin, buffer, received); } } // We have received all the packet data: we can copy it to the user packet if (!myPendingPacket.Data.empty()) packet.OnReceive(&myPendingPacket.Data[0], myPendingPacket.Data.size()); // Clear the pending packet data myPendingPacket = PendingPacket(); return Done; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \brief Reads a message out of the message box. /// /// This method will read the first message that has not been read yet by this /// instance of the MappedMessageBox. /// /// \param[in] message Packet data to read from message box. /// /// \return True on success, false on failure. /// //////////////////////////////////////////////////////////////////////////////////// bool MappedMessageBox::ReadMessage(Packet& message) const { bool result = false; message.Clear(); if(mMessageBox.IsOpen()) { Header header; if(mMessageBox.Lock() == 0) { return result; } header = ReadHeader(); if(header.mCount > 0 && header.mStartBytePos < header.mEndBytePos) { // Advance to the position of the next message we want to read. unsigned int messageSize = 0; unsigned int messagePosition = header.mStartBytePos; // Read the message size in the box. mMessageBox->Read(messageSize, messagePosition); if(messageSize + MessageHeaderSize + messagePosition <= header.mEndBytePos) { if(mMessageBox->Read(message, messageSize, messagePosition + MessageHeaderSize) == (int)messageSize) { (*( (unsigned *)(&mMessagesRead) ))++; // Advance the start byte position in the array. header.mStartBytePos = messagePosition + MessageHeaderSize + messageSize; // Decrease the number of messages in the box. header.mCount--; result = true; } } if(messageSize + MessageHeaderSize > mMessageBox->Length()) { assert("Corrupted Shared Memory Message Box" && 0); } } // Reset position values. if(header.mCount == 0) { header.mStartBytePos = header.mEndBytePos = Header::Size; } // Update the read time (shows we are actively checking for messages). header.mReadTimeMs = GetTimeMs(); // Save updated header data. WriteHeader(header); // Release critical section. mMessageBox.Unlock(); } return result; }
//////////////////////////////////////////////////////////// /// Receive a packet from the host (must be connected first). /// This function will block if the socket is blocking //////////////////////////////////////////////////////////// Socket::Status SocketTCP::Receive(Packet& PacketToReceive) { // We start by getting the size of the incoming packet Uint32 PacketSize = 0; std::size_t Received = 0; if (myPendingPacketSize < 0) { Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received); if (Status != Socket::Done) return Status; PacketSize = ntohl(PacketSize); } else { // There is a pending packet : we already know its size PacketSize = myPendingPacketSize; } // Then loop until we receive all the packet data char Buffer[1024]; while (myPendingPacket.size() < PacketSize) { // Receive a chunk of data std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer)); Socket::Status Status = Receive(Buffer, SizeToGet, Received); if (Status != Socket::Done) { // We must save the size of the pending packet until we can receive its content if (Status == Socket::NotReady) myPendingPacketSize = PacketSize; return Status; } // Append it into the packet if (Received > 0) { myPendingPacket.resize(myPendingPacket.size() + Received); char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; memcpy(Begin, Buffer, Received); } } // We have received all the datas : we can copy it to the user packet, and clear our internal packet PacketToReceive.Clear(); if (!myPendingPacket.empty()) PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); myPendingPacket.clear(); myPendingPacketSize = -1; return Socket::Done; }
//////////////////////////////////////////////////////////// /// Receive a packet from the host (must be connected first). /// This function will block if the socket is blocking //////////////////////////////////////////////////////////// Socket::Status SocketTCP::Receive(Packet& PacketToReceive) { // We start by getting the size of the incoming packet Uint32 PacketSize = 0; std::size_t Received = 0; if (myPendingPacketSize < 0) { Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received); if (Status != Socket::Done) return Status; PacketSize = ntohl(PacketSize); } else { // There is a pending packet : we already know its size PacketSize = myPendingPacketSize; } // Clear the user packet PacketToReceive.Clear(); // Then loop until we receive all the packet data char Buffer[1024]; while (myPendingPacket.GetDataSize() < PacketSize) { // Receive a chunk of data Uint32 SizeToGet = std::min(PacketSize - myPendingPacket.GetDataSize(), static_cast<Uint32>(sizeof(Buffer))); Socket::Status Status = Receive(Buffer, SizeToGet, Received); if (Status != Socket::Done) { // We must save the size of the pending packet until we can receive its content if (Status == Socket::NotReady) myPendingPacketSize = PacketSize; return Status; } // Append it into the packet myPendingPacket.Append(Buffer, Received); } // We have received all the datas : we can copy it to the user packet, and clear our internal packet PacketToReceive = myPendingPacket; myPendingPacket.Clear(); myPendingPacketSize = -1; // Let the packet do custom stuff after data reception PacketToReceive.OnReceive(); return Socket::Done; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \brief Thread used by the primary server (the active socket) to receive /// UDP datagrams and share to clients. /// //////////////////////////////////////////////////////////////////////////////////// void UdpSharedServer::UdpSocketThread(void* udpSharedServer) { UdpSharedServer* server = (UdpSharedServer*)udpSharedServer; Packet udpMessage; IP4Address sourceAddress; unsigned short sourcePort = 0; #ifdef WIN32 unsigned int loopCounter = 0; #endif while(server && (server->mUdpSocketThread.QuitThreadFlag() == false || server->mQuitServerFlag == false)) { // Try and read a new incomming message. udpMessage.Clear(false); sourcePort = 0; if(server->mpSocket->Recv(udpMessage, 5000, 100, &sourceAddress, &sourcePort) > 0) { // Add the IP address to the end of the message for shared memory clients. udpMessage.Write(sourceAddress.mData, 4, udpMessage.Length()); udpMessage.Write(sourcePort, udpMessage.Length()); // Send to non-primary UdpSharedServer instances. server->mpMessageServer->SendToAllClients(udpMessage); // Now process the data internally. This will add to the // queue of received messages, and generate callbacks. UdpSharedServer::ProcessUdpMessage(udpMessage, server); } server->mDelayMutex.Lock(); if(server->mUpdateDelayMs == 0) { #ifdef WIN32 // Only sleep every N loops if( loopCounter++ == 250) { loopCounter = 0; SleepMs(1); } #else usleep(500); #endif } else { CxUtils::SleepMs(server->mUpdateDelayMs); } server->mDelayMutex.Unlock(); } server->mConnectedFlag = false; }
void Connection::Update() { while (true) { this->RecvMutex.lock(); if (this->ToRecv.Count == 0) { this->RecvMutex.unlock(); break; } byte* buff = this->ToRecv.RemoveAt(0); this->RecvMutex.unlock(); Packet p; p.InBuffer = buff + 4; p.InSize = *(int*)buff; int pid; switch (this->PIDType) { case ConnectionPacketIDType::Byte: pid = p.ReadByte(); break; case ConnectionPacketIDType::Short: pid = p.ReadShort(); break; case ConnectionPacketIDType::Int: pid = p.ReadInt(); break; } if (pid < this->CallbacksSize && pid >= 0 && this->Callbacks[pid] != nullptr) { bool ret = this->Callbacks[pid](this->m_pTag, p); if (!ret) { this->Disconnect(); this->RecvMutex.lock(); while (this->ToRecv.Count > 0) delete this->ToRecv.RemoveAt(this->ToRecv.Count - 1); this->RecvMutex.unlock(); } if (p.InPos != p.InSize) { Utilities::Print("[col=%s]WARNING: Packet 0x%.4X(%d) was only read till %d, while the size is %d", Color::Orange.ToString().c_str(), pid, pid, p.InPos, p.InSize); } } else { Utilities::Print("[col=%s]Unknown packet: 0x%.4X(%d), size %d", Color::Red.ToString().c_str(), pid, pid, p.InSize); } this->LastReceivedPacket = time(nullptr); p.InBuffer = nullptr; p.InSize = 0; p.Clear(); delete[] buff; } }
//////////////////////////////////////////////////////////// /// Receive a packet. /// This function will block if the socket is blocking //////////////////////////////////////////////////////////// Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port) { // We start by getting the size of the incoming packet Uint32 PacketSize = 0; std::size_t Received = 0; if (myPendingPacketSize < 0) { // Loop until we've received the entire size of the packet // (even a 4 bytes variable may be received in more than one call) while (myPendingHeaderSize < sizeof(myPendingHeader)) { char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize; Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port); myPendingHeaderSize += Received; if (Status != Socket::Done) return Status; } PacketSize = ntohl(myPendingHeader); myPendingHeaderSize = 0; } else { // There is a pending packet : we already know its size PacketSize = myPendingPacketSize; } // Use another address instance for receiving the packet data ; // chunks of data coming from a different sender will be discarded (and lost...) IPAddress Sender; unsigned short SenderPort; // Then loop until we receive all the packet data char Buffer[1024]; while (myPendingPacket.size() < PacketSize) { // Receive a chunk of data std::size_t SizeToGet = std::min(static_cast<std::size_t>(PacketSize - myPendingPacket.size()), sizeof(Buffer)); Socket::Status Status = Receive(Buffer, SizeToGet, Received, Sender, SenderPort); if (Status != Socket::Done) { // We must save the size of the pending packet until we can receive its content if (Status == Socket::NotReady) myPendingPacketSize = PacketSize; return Status; } // Append it into the packet if ((Sender == Address) && (SenderPort == Port) && (Received > 0)) { myPendingPacket.resize(myPendingPacket.size() + Received); char* Begin = &myPendingPacket[0] + myPendingPacket.size() - Received; memcpy(Begin, Buffer, Received); } } // We have received all the datas : we can copy it to the user packet, and clear our internal packet PacketToReceive.Clear(); if (!myPendingPacket.empty()) PacketToReceive.OnReceive(&myPendingPacket[0], myPendingPacket.size()); myPendingPacket.clear(); myPendingPacketSize = -1; return Socket::Done; }
void SceneryManager::SendPageRequest(const SceneryPageRequest& request, std::list<PacketManager::PACKET_PAIR>& outgoingPackets) { TimeObject to("SceneryManager::SendPageRequest"); STRINGLIST queryRows; Packet data; int wpos = 0; char idBuf[32]; GetThread("SceneryManager::HandlePageRequests[page]"); SceneryPage *page = GetOrCreatePage(request.zone, request.x, request.y); if(page == NULL) { g_Log.AddMessageFormat("[ERROR] SendPageRequest retrieved NULL page"); wpos = PrepExt_QueryResponseNull(prepBuf, request.queryID); data.Assign(prepBuf, wpos); outgoingPackets.push_back(PacketManager::PACKET_PAIR(request.socket, data)); ReleaseThread(); return; } SceneryPage::SCENERY_IT it; for(it = page->mSceneryList.begin(); it != page->mSceneryList.end(); ++it) { //Build the list of scenery ID strings to form the response to the scenery.list query. //No need to save row data unless the query is required. if(request.skipQuery == false) { sprintf(idBuf, "%d", it->second.ID); queryRows.push_back(idBuf); } wpos += PrepExt_UpdateScenery(&prepBuf[wpos], &it->second); if(wpos > Global::MAX_SEND_CHUNK_SIZE) { data.Assign(prepBuf, wpos); outgoingPackets.push_back(PacketManager::PACKET_PAIR(request.socket, data)); wpos = 0; } } if(wpos > 0) { data.Assign(prepBuf, wpos); outgoingPackets.push_back(PacketManager::PACKET_PAIR(request.socket, data)); } //Done accessing the scenery data itself, no need to hold the thread any longer. //All the remaining stuff is using a resident list of query IDs to form into a response //packet. ReleaseThread(); //Now build the query response if the client has requested it. if(request.skipQuery == true) return; //Reset the packet buffer and data. wpos = 0; data.Clear(); //Get the size of the response int sizeReq = 6; //Query ID (4 bytes) + row count (2 bytes) for(size_t s = 0; s < queryRows.size(); s++) { sizeReq++; //1 string per row sizeReq += PutStringReq(queryRows[s].c_str()); } wpos += PutByte(&prepBuf[wpos], 1); //_handleQueryResultMsg wpos += PutShort(&prepBuf[wpos], sizeReq); //Message size wpos += PutInteger(&prepBuf[wpos], request.queryID); wpos += PutShort(&prepBuf[wpos], queryRows.size()); for(size_t s = 0; s < queryRows.size(); s++) { wpos += PutByte(&prepBuf[wpos], 1); wpos += PutStringUTF(&prepBuf[wpos], queryRows[s].c_str()); if(wpos > Global::MAX_SEND_CHUNK_SIZE) { data.Append(prepBuf, wpos); wpos = 0; } } if(wpos > 0) data.Append(prepBuf, wpos); outgoingPackets.push_back(PacketManager::PACKET_PAIR(request.socket, data)); }
//////////////////////////////////////////////////////////////////////////////////// /// /// \brief Writes message contents to packet for the transport layer to /// send. Begins writing from current write position in packet. /// /// Message contents are written to the packet following the JAUS standard. /// /// \param[out] packet Packet to write header and payload data to. /// \param[out] header Packet transport header data. /// \param[in] transportHeader Optional parameter for transport header data to /// write before the general transport header. /// \param[in] clearPacket If true, packet contents are cleared before /// writing takes place. /// \param[in] startingSequenceNumber Sequence number to use for packets. /// \param[in] broadcastFlag Values to use to signify if message should be /// sent using any broadcast options (e.g. /// multicast). 0 = no options, 1 = local broadcast, /// 2 = global broadcast. /// /// \return FAILURE on error, otherwise number of bytes written. /// //////////////////////////////////////////////////////////////////////////////////// int Message::Write(Packet& packet, Header& header, const Packet* transportHeader, const bool clearPacket, const UShort startingSequenceNumber, const Byte broadcastFlag) const { int total = 0; // Build JAUS header data. header.mSourceID = mSourceID; header.mDestinationID = mDestinationID; header.mPriorityFlag = mPriority; header.mControlFlag = Header::DataControl::Single; header.mCompressionFlag = Header::Compression::None; header.mSequenceNumber = startingSequenceNumber; header.mBroadcastFlag = broadcastFlag; // Clear out any previous message data. if(clearPacket) { packet.Clear(); packet.Reserve(Header::MinSize + USHORT_SIZE + 1); } unsigned int writePos = packet.GetWritePos(); if(transportHeader && transportHeader->Length() > 0) { writePos += (unsigned int)packet.Write(*transportHeader); } // The first thing we must do is advance // the write position to after the JAUS Header // data. The header is not written first because // we do not know how large the message body will // be yet. packet.SetLength(writePos + Header::PayloadOffset); packet.SetWritePos(writePos + Header::PayloadOffset); total += packet.Write(mMessageCode); int payloadSize = 0; if( (payloadSize = WriteMessageBody(packet)) >= 0) { total += payloadSize; // Check for large data set. if(total + Header::MinSize > Header::MaxPacketSize) { return FAILURE; } else { header.mSize = total + Header::MinSize; packet.SetWritePos(writePos); // Go back, and re-write the header since // we now know the size of the message. if(header.Write(packet)) { // Set the write position to the end of message we just wrote. packet.SetWritePos(writePos + header.mSize); // Return the number of bytes written. if(transportHeader) { return header.mSize + transportHeader->Length(); } else { return header.mSize; } } } } return FAILURE; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \brief Method for receiving UDP messages in a continuous loop. /// //////////////////////////////////////////////////////////////////////////////////// void JUDP::ReceiveThread(void* args) { JUDP* transport = (JUDP*)args; Packet udpMessage; CxUtils::IP4Address sourceAddress; unsigned short sourcePort = 0; long int timeoutMs = 100; #ifdef WIN32 int loopCounter = 0; #endif udpMessage.Reserve(5000); Thread* thread = NULL; bool primary = false; if(transport->mPrimaryThreadCreatedFlag == false) { primary = true; transport->mPrimaryThreadCreatedFlag = true; thread = &transport->mPrimaryThread; } else { thread = &transport->mSecondaryThread; } while(transport && thread->QuitThreadFlag() == false && transport->mShutdownServiceFlag == false) { udpMessage.Clear(false); sourcePort = 0; if(primary) { if(transport->mInput.Recv(udpMessage, 5000, timeoutMs, &sourceAddress, &sourcePort) > 0) { transport->ProcessUDP(udpMessage, sourceAddress, sourcePort); } } else { if(transport->mMulticast.GetSourcePort() > 0 && transport->mMulticast.Recv(udpMessage, 5000, timeoutMs, &sourceAddress, &sourcePort) > 0) { transport->ProcessUDP(udpMessage, sourceAddress, sourcePort); } } if(transport->mShutdownServiceFlag) { break; } if(transport->mDelayTimeMs == 0) { #ifdef WIN32 // Only sleep every N loops if( loopCounter++ == 250) { loopCounter = 0; CxUtils::SleepMs(1); } #else usleep(500); #endif } else { CxUtils::SleepMs(transport->mDelayTimeMs); } } //std::cout << "EXIT!\n"; }