(for v3.16.2, not interested in lower) Initial connection ------------------ Client sends bytes (signed char): 0 lib version (3) 1 lib subversion (16) 2 lib patchlevel (2) 3 flags: MEMB_SESSION 0x1 (wants group membership notifications) PRIORITY_CONN 0x10 (priority connection - recorded but ignored) 4 name length (0-MAX_PRIVATE_NAME(10)) 5-(5+namelength) name "myname" or empty, not nul-terminated Server may send back signed char of REJECT_VERSION(-7), REJECT_NO_NAME(-4), REJECT_ILLEGAL_NAME(-5), REJECT_NOT_UNIQUE(-6) and then close, otherwise, Server sends unsigned char of strlen of allowed auth methods (below). Server sends allowed auths (space-separated, *space-terminated*) Server may also immediately REJECT_AUTH(-9) and close (?!) (only on server config error?) Client sends a bytearray of strings char auth_methods_desired[MAX_AUTH_METHODS][MAX_AUTH_NAME] # MAX_AUTH_NAME=30 # MAX_AUTH_METHODS=3 [Client and server then exchange arbitrary octets for auth, null by default] If auth failed, server sends REJECT_AUTH(-9) and closes. Server sends bytes (one at a time) (signed chars): ACCEPT_SESSION(1) server version(3) server subversion(16) server patchlevel(2) Server then constructs private group name #sesname#servname. Server sends low-byte of the strlen of this name as a signed char. Server sends private group name string (not null-terminated) (end of initial chat) Multicasting ------------ Client sends a header: uint32_t type # a REGULAR_MESS or KILL_MESS, JOIN_MESS, LEAVE_MESS # via Set_endian char private_group_name[MAX_GROUP_NAME] int32_t num_groups # count of recipient groups int32_t hint # (passed through from app via # Set_endian((mess_type << 8) & 0x00ffff00) int32_t data_len # total length of message body Client sends groups: char groups[num_groups][MAX_GROUP_NAME] # array of receiving groups Client then sequentially sends each scatter block of message body. Receiving --------- Server sends a header: uint32_t type # SELF_DISCARD set if the original had it set # (iff this is a REJECT_MESS) char sender[MAX_GROUP_NAME] int32_t num_groups int32_t hint int32_t data_len If type & REJECT_MESS, then server sends uint32_t original type of rejected message Server sends char groups[num_groups][MAX_GROUP_NAME] # this will be modified in a REJECT_MESS # to append recipients private groupname Server sends message body. Received body specifics ----------------------- 1. If this is a transitional member message, that is (type & TRANSITION_MESS != 0) && (type & REJECT_MESS == 0), then in header: hint = 0 sender = the group for which this is a notification (nul-terminated string) num_groups = 0 groups is empty message body is: group_id gid # ident of the group view (from arch.h) 2. If this is a regular membership message, that is (type & REG_MEMB_MESS != 0) && (type & REJECT_MESS == 0), then in header: hint = 0 sender = the group for which this is a notification (nul-terminated string) num_groups = number of members groups = members' private names message body is: group_id gid # ident of the group view (from arch.h) int32 num_members # number of members in VS set char vs_members[num_members][MAX_GROUP_NAME] content of vs_members defined by by flags in type: CAUSED_BY_JOIN new member name CAUSED_BY_LEAVE leaving member name CAUSED_BY_DISCONNECT disconnecting member name CAUSED_BY_NETWORK only members from previous VS set 3. If this is a self-leave membership message, that is (type & MEMBERSHIP_MESS == CAUSED_BY_LEAVE) && (type & REJECT_MESS == 0), then in header: hint = 0 sender = the group for which this is a notification (nul-terminated string) num_groups = 0 groups is empty message body is: group_id gid # ident of the group view (from arch.h) int32 num_members = 1 char vs_members[1][MAX_GROUP_NAME]