UniSet  2.6.0
UDPPacket.h
00001 /*
00002  * Copyright (c) 2015 Pavel Vainerman.
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU Lesser General Public License as
00006  * published by the Free Software Foundation, version 2.1.
00007  *
00008  * This program is distributed in the hope that it will be useful, but
00009  * WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00011  * Lesser General Lesser Public License for more details.
00012  *
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00015  */
00016 // -----------------------------------------------------------------------------
00017 #ifndef UDPPacket_H_
00018 #define UDPPacket_H_
00019 // -----------------------------------------------------------------------------
00020 #include <list>
00021 #include <limits>
00022 #include <ostream>
00023 #include "UniSetTypes.h"
00024 // --------------------------------------------------------------------------
00025 namespace uniset
00026 {
00027 // -----------------------------------------------------------------------------
00028 namespace UniSetUDP
00029 {
00043 const uint32_t UNETUDP_MAGICNUM = 0x1337A1D; // идентификатор протокола
00044 
00045 struct UDPHeader
00046 {
00047     UDPHeader() noexcept: magic(UNETUDP_MAGICNUM), num(0), nodeID(0), procID(0), dcount(0), acount(0) {}
00048     uint32_t magic;
00049     size_t num;
00050     long nodeID;
00051     long procID;
00052 
00053     size_t dcount; 
00054     size_t acount; 
00056     friend std::ostream& operator<<( std::ostream& os, UDPHeader& p );
00057     friend std::ostream& operator<<( std::ostream& os, UDPHeader* p );
00058 } __attribute__((packed));
00059 
00060 const size_t MaxPacketNum = std::numeric_limits<size_t>::max();
00061 
00062 struct UDPAData
00063 {
00064     UDPAData() noexcept: id(uniset::DefaultObjectId), val(0) {}
00065     UDPAData(long id, long val) noexcept: id(id), val(val) {}
00066 
00067     long id;
00068     long val;
00069 
00070     friend std::ostream& operator<<( std::ostream& os, UDPAData& p );
00071 } __attribute__((packed));
00072 
00073 
00074 // Теоретический размер данных в UDP пакете (исключая заголовки) 65507
00075 // Фактически желательно не вылезать за размер MTU (обычно 1500) - заголовки = 1432 байта
00076 // т.е. надо чтобы sizeof(UDPPacket) < 1432
00077 
00078 // При текущих настройках sizeof(UDPPacket) = 32654 (!)
00079 static const size_t MaxACount = 1500;
00080 static const size_t MaxDCount = 5000;
00081 static const size_t MaxDDataCount = 1 + MaxDCount / 8 * sizeof(unsigned char);
00082 
00083 struct UDPPacket
00084 {
00085     UDPPacket() noexcept: len(0) {}
00086 
00087     size_t len;
00088     uint8_t data[ sizeof(UDPHeader) + MaxDCount * sizeof(long) + MaxDDataCount + MaxACount * sizeof(UDPAData) ];
00089 } __attribute__((packed));
00090 
00091 static const size_t MaxDataLen = sizeof(UDPPacket);
00092 
00093 struct UDPMessage:
00094     public UDPHeader
00095 {
00096     UDPMessage() noexcept;
00097 
00098     UDPMessage(UDPMessage&& m) noexcept = default;
00099     UDPMessage& operator=(UDPMessage&&) noexcept = default;
00100 
00101     UDPMessage( const UDPMessage& m ) noexcept = default;
00102     UDPMessage& operator=(const UDPMessage&) noexcept = default;
00103 
00104     explicit UDPMessage( UDPPacket& p ) noexcept;
00105     size_t transport_msg( UDPPacket& p ) const noexcept;
00106 
00107     static size_t getMessage( UDPMessage& m, UDPPacket& p ) noexcept;
00108 
00109     // \warning в случае переполнения возвращается MaxDCount
00110     size_t addDData( long id, bool val ) noexcept;
00111 
00113     bool setDData( size_t index, bool val ) noexcept;
00114 
00116     long dID( size_t index ) const noexcept;
00117 
00119     bool dValue( size_t index ) const noexcept;
00120 
00121     // функции addAData возвращают индекс, по которому потом можно напрямую писать при помощи setAData(index)
00122     // \warning в случае переполнения возвращается MaxACount
00123     size_t addAData( const UDPAData& dat ) noexcept;
00124     size_t addAData( long id, long val ) noexcept;
00125 
00127     bool setAData( size_t index, long val ) noexcept;
00128 
00129     long getDataID( ) const noexcept; 
00131     inline bool isAFull() const noexcept
00132     {
00133         return (acount >= MaxACount);
00134     }
00135     inline bool isDFull() const noexcept
00136     {
00137         return (dcount >= MaxDCount);
00138     }
00139 
00140     inline bool isFull() const noexcept
00141     {
00142         return !((dcount < MaxDCount) && (acount < MaxACount));
00143     }
00144 
00145     inline size_t dsize() const noexcept
00146     {
00147         return dcount;
00148     }
00149 
00150     inline size_t asize() const noexcept
00151     {
00152         return acount;
00153     }
00154 
00155     // размер итогового пакета в байтах
00156     size_t sizeOf() const noexcept;
00157 
00158     uint16_t getDataCRC() const noexcept;
00159 
00160     // количество байт в пакете с булевыми переменными...
00161     size_t d_byte() const noexcept
00162     {
00163         return dcount * sizeof(long) + dcount;
00164     }
00165 
00166     UDPAData a_dat[MaxACount]; 
00167     long d_id[MaxDCount];      
00168     uint8_t d_dat[MaxDDataCount];  
00170     friend std::ostream& operator<<( std::ostream& os, UDPMessage& p );
00171 };
00172 
00173 uint16_t makeCRC( unsigned char* buf, size_t len ) noexcept;
00174 }
00175 // --------------------------------------------------------------------------
00176 } // end of namespace uniset
00177 // -----------------------------------------------------------------------------
00178 #endif // UDPPacket_H_
00179 // -----------------------------------------------------------------------------