1# -*- coding: utf-8 -*- 2''' 3raeting module provides constants and values for the RAET protocol 4 5Production Ports for Raet 6Master 4505 7Minion(s) 4510 8 9Packet Data Format. 10The data used to initialize a packet is an ordered dict with several fields 11most of the fields are shared with the header data format below so only the 12unique fields are shown here. 13 14Unique Packet data fields 15 16 sh: source host ip address (ipv4) Default: '' 17 sp: source ip port Default: 7532 18 dh: destination host ip address (ipv4) Default: '127.0.0.1' 19 dp: destination host ip port Default 7532 20 21Header Data Format. 22The .data in the packet header is an ordered dict which is used to either 23create a packet to transmit 24or holds the field from a received packet. 25What fields are included in a header is dependent on the header kind. 26 27Header encoding. 28 When the head kind is json = 0, then certain optimizations are 29 used to minimize the header length. 30 The header field keys are two bytes long 31 If a header field value is the default then the field is not included 32 Lengths are encoded as hex strings 33 The flags are encoded as a double char hex string in field 'fg' 34 35header data = 36{ 37 ri: raet id Default 'RAET' 38 vn: Version (Version) Default 0 39 pk: Packet Kind (PcktKind) 40 pl: Packet Length (PcktLen) 41 hk: Header kind (HeadKind) Default 0 42 hl: Header length (HeadLen) Default 0 43 44 se: Source Estate ID (SEID) 45 de: Destination Estate ID (DEID) 46 cf: Correspondent Flag (CrdtFlag) Default 0 47 bf: BroadCast Flag (BcstFlag) Default 0 48 nf: NAT Flag (NatFlag) Default 0 49 df: Dynamic IP Flag (DynFlag) Default 0 50 vf: IPv6 Flag (IP) (Ipv6Flag) Default 0 51 52 si: Session ID (SID) Default 0 53 ti: Transaction ID (TID) Default 0 54 tk: Transaction Kind (TrnsKind) 55 56 dt: Datetime Stamp (Datetime) Default 0 57 oi: Order index (OrdrIndx) Default 0 58 59 wf: Waiting Ack Flag (WaitFlag) Default 0 60 Next segment or ordered packet is waiting for ack to this packet 61 ml: Message Length (MsgLen) Default 0 62 Length of message only (unsegmented) 63 sn: Segment Number (SgmtNum) Default 0 64 sc: Segment Count (SgmtCnt) Default 1 65 sf: Segment Flag (SgmtFlag) Default 0 66 This packet is part of a segmented message 67 af: Again Flag (AgnFlag) Default 0 68 This segment is being sent again 69 70 bk: Body kind (BodyKind) Default 0 71 ck: Coat kind (CoatKind) Default 0 72 fk: Footer kind (FootKind) Default 0 73 fl: Footer length (FootLen) Default 0 74 75 fg: flags packed (Flags) Default '00' hs 76 2 char Hex string with bits (vf, df, nf, af, sf, wf, bf, cf) 77 Zeros are TBD flags 78} 79 80Body Data Format 81The Body .data is a Mapping 82 83Body Encoding 84 When the body kind is json = 0, then the .data is json encoded 85 86Body Decoding 87 88 89''' 90 91# pylint: disable=C0103 92 93# Import python libs 94import struct 95import enum 96 97# Import ioflo libs 98from ioflo.aid.odicting import odict 99 100# Import raet libs 101# pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin 102from .abiding import * # import globals 103# pylint: enable=wildcard-import,unused-wildcard-import,redefined-builtin 104 105# Used to comput session id wrap around where valid sid is >= modulo N given by 106# (((new - old) % 0x100000000) < (0x100000000 // 2)) 107# N//2 = 0x80000000 108SID_WRAP_MODULO = 0x100000000 # session id wraps modulo N = 2^32 = 0x100000000 109SID_WRAP_DELTA = 0x80000000 # session id >= delta at N//2 = 0x80000000 110SID_ROLLOVER = 0xffffffff # session id rolls over at modulo (N-1) -= 2^32 -1 = 0xffffffff 111 112RAET_PORT = 7530 113RAET_TEST_PORT = 7531 114DEFAULT_SRC_HOST = '' 115DEFAULT_DST_HOST = '127.0.0.1' 116 117UDP_MAX_DATAGRAM_SIZE = (2 ** 16) - 1 # 65535 118UDP_MAX_SAFE_PAYLOAD = 548 # IPV4 MTU 576 - udp headers 28 119# IPV6 MTU is 1280 but headers are bigger 120UDP_MAX_PACKET_SIZE = min(1024, UDP_MAX_DATAGRAM_SIZE) # assumes IPV6 capable equipment 121UXD_MAX_PACKET_SIZE = (2 ** 16) - 1 # 65535 122MAX_SEGMENT_COUNT = (2 ** 16) - 1 # 65535 123MAX_MESSAGE_SIZE = min(67107840, UDP_MAX_PACKET_SIZE * MAX_SEGMENT_COUNT) 124MAX_HEAD_SIZE = 255 125 126JSON_END = b'\r\n\r\n' 127HEAD_END = b'\n\n' 128 129VERSIONS = odict([('0.1', 0)]) 130VERSION_NAMES = odict((v, k) for k, v in VERSIONS.iteritems()) 131VERSION = VERSIONS.values()[0] 132 133HELLO_PACKER = struct.Struct('!64s32s80s24s') # curvecp allow trans bodies 134COOKIESTUFF_PACKER = struct.Struct('!32sLL24s') 135COOKIE_PACKER = struct.Struct('!80s24s') 136INITIATESTUFF_PACKER = struct.Struct('!32s48s24s128s') 137INITIATE_PACKER = struct.Struct('!32s24s248s24s') 138 139 140def get_exception_error(ex): 141 ''' 142 Return the error code from an exception 143 ''' 144 if hasattr(ex, 'errno'): 145 return ex.errno 146 elif hasattr(ex, 'winerror'): 147 return ex.winerror 148 else: 149 emsg = "Cannot find error code in exception: {0}".format(ex) 150 raise TypeError(emsg) 151 152 153@enum.unique 154class HeadKind(enum.IntEnum): 155 ''' 156 Integer Enums of Head Kinds 157 ''' 158 raet = 0 159 json = 1 160 binary = 2 161 unknown = 255 162 163 164@enum.unique 165class BodyKind(enum.IntEnum): 166 ''' 167 Integer Enums of Body Kinds 168 ''' 169 nada = 0 170 json = 1 171 raw = 2 172 msgpack = 3 173 unknown = 255 174 175 176@enum.unique 177class FootKind(enum.IntEnum): 178 ''' 179 Integer Enums of Foot Kinds 180 ''' 181 nada = 0 182 nacl = 1 183 sha2 = 2 184 crc64 = 3 185 unknown = 255 186 187 188class FootSize(enum.IntEnum): 189 ''' 190 Integer Enums of Foot Sizes in bytes 191 ''' 192 nada = 0 193 nacl = 64 194 sha2 = 256 195 crc64 = 8 196 unknown = 0 197 198 199@enum.unique 200class CoatKind(enum.IntEnum): 201 ''' 202 Integer Enums of Coat Kinds 203 ''' 204 nada = 0 205 nacl = 1 206 crc16 = 2 207 crc64 = 3 208 unknown = 255 209 210 211class TailSize(enum.IntEnum): 212 ''' 213 Integer Enums of Tail Sizes in bytes 214 ''' 215 nada = 0 216 nacl = 24 217 crc16 = 2 218 crc64 = 8 219 unknown = 0 220 221 222@enum.unique 223class TrnsKind(enum.IntEnum): 224 ''' 225 Integer Enums of Transaction Kinds 226 ''' 227 message = 0 228 join = 1 229 bind = 2 230 allow = 3 231 alive = 4 232 unknown = 255 233 234 235@enum.unique 236class PcktKind(enum.IntEnum): 237 ''' 238 Integer Enums of Packet Kinds 239 ''' 240 message = 0 241 ack = 1 242 nack = 2 243 resend = 3 244 request = 4 245 response = 5 246 hello = 6 247 cookie = 7 248 initiate = 8 249 unjoined = 9 250 unallowed = 10 251 renew = 11 252 refuse = 12 253 reject = 13 254 pend = 14 255 done = 15 256 unknown = 255 257 258 259@enum.unique 260class Acceptance(enum.IntEnum): 261 ''' 262 Integer Enums of Acceptances 263 ''' 264 pending = 0 265 accepted = 1 266 rejected = 2 267 268 269@enum.unique 270class AutoMode(enum.IntEnum): 271 ''' 272 Integer Enums of Auto Modes 273 ''' 274 never = 0 275 once = 1 276 always = 2 277 278 279@enum.unique 280class PackKind(enum.IntEnum): 281 ''' 282 Integer Enums of Pack Kinds for Lane Pages 283 ''' 284 json = 0 285 pack = 1 286 287 288# head fields that may be included in packet header if not default value 289PACKET_DEFAULTS = odict([ 290 ('sh', DEFAULT_SRC_HOST), 291 ('sp', RAET_PORT), 292 ('dh', DEFAULT_DST_HOST), 293 ('dp', RAET_PORT), 294 ('ri', 'RAET'), 295 ('vn', 0), 296 ('pk', 0), 297 ('pl', 0), 298 ('hk', 0), 299 ('hl', 0), 300 ('se', 0), 301 ('de', 0), 302 ('cf', False), 303 ('bf', False), 304 ('nf', False), 305 ('df', False), 306 ('vf', False), 307 ('si', 0), 308 ('ti', 0), 309 ('tk', 0), 310 ('dt', 0), 311 ('oi', 0), 312 ('wf', False), 313 ('sn', 0), 314 ('sc', 1), 315 ('ml', 0), 316 ('sf', False), 317 ('af', False), 318 ('bk', 0), 319 ('ck', 0), 320 ('fk', 0), 321 ('fl', 0), 322 ('fg', '00'), 323 ]) 324 325PACKET_FIELDS = ['sh', 'sp', 'dh', 'dp', 326 'ri', 'vn', 'pk', 'pl', 'hk', 'hl', 327 'se', 'de', 'cf', 'bf', 'nf', 'df', 'vf', 'si', 'ti', 'tk', 328 'dt', 'oi', 'wf', 'sn', 'sc', 'ml', 'sf', 'af', 329 'bk', 'ck', 'fk', 'fl', 'fg'] 330 331PACKET_HEAD_FIELDS = ['ri', 'vn', 'pk', 'pl', 'hk', 'hl', 332 'se', 'de', 'cf', 'bf', 'nf', 'df', 'vf', 'si', 'ti', 'tk', 333 'dt', 'oi', 'wf', 'sn', 'sc', 'ml', 'sf', 'af', 334 'bk', 'bl', 'ck', 'cl', 'fk', 'fl', 'fg'] 335 336PACKET_FLAGS = ['vf', 'df', 'nf', 'af', 'sf', 'wf', 'bf', 'cf'] 337PACKET_FLAG_FIELDS = ['vf', 'df', 'nf', 'af', 'sf', 'wf', 'bf', 'cf'] 338 339PACKET_FIELD_FORMATS = odict([ 340 ('ri', '.4s'), 341 ('vn', 'x'), 342 ('pk', 'x'), 343 ('pl', '04x'), 344 ('hk', 'x'), 345 ('hl', '02x'), 346 ('se', 'x'), 347 ('de', 'x'), 348 ('cf', ''), 349 ('bf', ''), 350 ('nf', ''), 351 ('df', ''), 352 ('vf', ''), 353 ('si', 'x'), 354 ('ti', 'x'), 355 ('tk', 'x'), 356 ('dt', 'f'), 357 ('oi', 'x'), 358 ('wf', ''), 359 ('sn', 'x'), 360 ('sc', 'x'), 361 ('ml', 'x'), 362 ('sf', ''), 363 ('af', ''), 364 ('bk', 'x'), 365 ('ck', 'x'), 366 ('fk', 'x'), 367 ('fl', 'x'), 368 ('fg', '.2s'), 369 ]) 370 371# head fields that may be included in page header if not default value 372PAGE_DEFAULTS = odict([ 373 ('ri', 'RAET'), 374 ('vn', 0), 375 ('pk', 0), 376 ('sn', ''), 377 ('dn', ''), 378 ('si', '000000000000000000'), 379 ('bi', 0), 380 ('pn', 0), 381 ('pc', 1), 382 ]) 383 384PAGE_FIELD_FORMATS = odict([ 385 ('ri', '.4s'), 386 ('vn', 'x'), 387 ('pk', 'x'), 388 ('sn', 's'), 389 ('dn', 's'), 390 ('si', '.18s'), 391 ('bi', 'x'), 392 ('pn', '04x'), 393 ('pc', '04x'), 394 ]) 395 396PAGE_FIELDS = ['ri', 'vn', 'pk', 'sn', 'dn', 'si', 'bi', 'pn', 'pc'] 397 398 399class RaetError(Exception): 400 ''' 401 Exceptions in RAET Protocol processing 402 403 usage: 404 emsg = "Invalid unique id '{0}'".format(uid) 405 raise raeting.RaetError(emsg) 406 ''' 407 def __init__(self, message=None): 408 self.message = message # description of error 409 super(RaetError, self).__init__(message) 410 411 def __str__(self): 412 return "{0}: {1}.\n".format(self.__class__.__name__, self.message) 413 414 415class StackError(RaetError): 416 ''' 417 Exceptions in RAET stack processing 418 419 Usage: 420 emsg = "Invalid unique id '{0}'".format(uid) 421 raise raeting.StackError(emsg) 422 ''' 423 pass 424 425 426class EstateError(RaetError): 427 ''' 428 Exceptions in RAET estate processing 429 430 Usage: 431 emsg = "Invalid unique id '{0}'".format(uid) 432 raise raeting.EstateError(emsg) 433 ''' 434 pass 435 436 437class TransactionError(RaetError): 438 ''' 439 Exceptions in RAET transaction processing 440 441 Usage: 442 emsg = "Invalid uniqu id '{0}'".format(uid) 443 raise raeting.TransactionError(emsg) 444 ''' 445 pass 446 447 448class PacketError(RaetError): 449 ''' 450 Exceptions in RAET packet processing 451 452 Usage: 453 emsg = "Invalid unique id '{0}'".format(uid) 454 raise raeting.PacketError(emsg) 455 ''' 456 pass 457 458 459class PacketSizeError(PacketError): 460 ''' 461 Packet too large error needs to be segmented 462 463 Usage: 464 emsg = "Packet size {0} too large needs to be segmented".format(size) 465 raise raeting.PacketSizeError(emsg) 466 ''' 467 pass 468 469 470class KeepError(RaetError): 471 ''' 472 Exceptions in RAET keep processing 473 474 Usage: 475 emsg = "Invalid unique id '{0}'".format(uid) 476 raise raeting.KeepError(emsg) 477 ''' 478 pass 479 480 481class YardError(RaetError): 482 ''' 483 Exceptions in RAET yard processing 484 485 Usage: 486 emsg = "Invalid unique id '{0}'".format(uid) 487 raise raeting.YardError(emsg) 488 ''' 489 pass 490 491 492class PageError(RaetError): 493 ''' 494 Exceptions in RAET page processing 495 496 Usage: 497 emsg = "Invalid page kind '{0}'".format(kind) 498 raise raeting.PageError(emsg) 499 ''' 500 pass 501