| // ================================================================================== |
| // Copyright (c) 2000-2019 Ericsson Telecom AB AB |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v2.0 |
| // which accompanies this distribution, and is available at |
| // https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html |
| // ================================================================================== |
| // Contributors: |
| // Krisztian Gulyas - initial implementation and initial documentation |
| // |
| // File: MongoDBProtocol.ttcn |
| // Rev: R1A |
| // Prodnr: CNL 0 |
| // ================================================================================== |
| module MongoDB_Types |
| { |
| // ============================================================================== |
| // |
| // mongoDB wire protocol definitions |
| // reference: https://docs.mongodb.com/manual/reference/mongodb-wire-protocol/ |
| // version: mongoDB version 3.4 |
| // |
| // ============================================================================== |
| |
| // ------------------------------------------------------------------------------ |
| // general definitions |
| // ------------------------------------------------------------------------------ |
| |
| // 32 bit integer (little endian encoding) and decoding function |
| type integer int32 with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| // decoding int32 value from octetstring |
| external function decInt32 (in octetstring stream) return int32 with { extension "prototype(convert) decode(RAW)" } |
| |
| // 64 bit integer (little endian encoding) |
| type integer int64 with { variant "FIELDLENGTH(64), COMP(signbit), BYTEORDER(first)" }; |
| |
| // record of int64 type |
| type record of int64 roInt64; |
| |
| /// null terminaged string |
| type universal charstring cstring with { variant "FIELDLENGTH(null_terminated)"}; |
| |
| // different size of bit fields |
| type bitstring BIT1 with { variant "BITORDER(lsb), FIELDLENGTH(1)" }; |
| type bitstring BIT24 with { variant "BITORDER(lsb), FIELDLENGTH(24)" }; |
| type bitstring BIT28 with { variant "BITORDER(lsb), FIELDLENGTH(28)" }; |
| type bitstring BIT30 with { variant "BITORDER(lsb), FIELDLENGTH(30)" }; |
| type bitstring BIT31 with { variant "BITORDER(lsb), FIELDLENGTH(31)" }; |
| |
| // record of JSON documents |
| type record of universal charstring JSONRecords; |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB message header definitions (common part of the message) |
| // ------------------------------------------------------------------------------ |
| |
| // code of the operations: 32 bit integer (little endian encoding) |
| type enumerated OpCode |
| { |
| OP_REPLY (1), // Reply to a client request. responseTo is set. |
| OP_MSG (1000), // Generic msg command followed by a string. |
| OP_UPDATE (2001), // Update document. |
| OP_INSERT (2002), // Insert new document. |
| OP_QUERY (2004), // Query a collection. |
| OP_GET_MORE (2005), // Get more data from a query. See Cursors. |
| OP_DELETE (2006), // Delete documents. |
| OP_KILL_CURSORS (2007), // Notify database that the client has finished with the cursor. |
| OP_COMMAND (2010), // Cluster internal protocol representing a command request. |
| OP_COMMANDREPLY (2011), // Cluster internal protocol representing a reply to an OP_COMMAND. |
| OP_UNDEFINED (0) // Undefined value for ttcn test cases |
| } with { variant "BYTEORDER(first), FIELDLENGTH(32)" }; |
| |
| // header structure |
| type record MsgHeader |
| { |
| // The total size of the message in bytes. This total includes the 4 bytes that holds the message length. |
| int32 messageLength, |
| |
| // A client or database-generated identifier that uniquely identifies this message. |
| // For the case of client-generated messages (e.g. OP_QUERY and OP_GET_MORE), it will be returned in the responseTo |
| // field of the OP_REPLY message. Clients can use the requestID and the responseTo fields to associate query |
| // responses with the originating query. |
| int32 requestId, |
| |
| // In the case of a message from the database, this will be the requestID taken from the OP_QUERY or OP_GET_MORE |
| // messages from the client. Clients can use the requestID and the responseTo fields to associate query responses |
| // with the originating query. |
| int32 responseTo, |
| |
| // Type of message. See Request Opcodes above |
| OpCode opCode |
| } with { variant "" } |
| |
| // ============================================================================== |
| // |
| // mongoDB client request messages |
| // |
| // ============================================================================== |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB insert message, |
| // ------------------------------------------------------------------------------ |
| |
| // flags: definitions of bits |
| type record InsertMsgFlagsBits { |
| // If set, the database will not stop processing a bulk insert if one fails (eg due to duplicate IDs). |
| // This makes bulk insert behave similarly to a series of single inserts, except lastError will be set |
| // if any insert fails, not just the last one. If multiple errors occur, only the most recent will be |
| // reported by getLastError. (new in 1.9.1) |
| BIT1 ContinueOnError, |
| // 1-31 bits are reserved. Must be set to 0 |
| BIT31 Reserved0 |
| } with { variant "" } |
| |
| // flags can be accessed via bits or value |
| type union InsertMsgFlags { |
| InsertMsgFlagsBits bits, |
| int32 bytes |
| } with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| // message structure |
| type record InsertMsg |
| { |
| MsgHeader header, // standard message header |
| InsertMsgFlags flags, // bit vector of insert options. |
| cstring fullCollectionName, // "dbname.collectionname" |
| octetstring documents // one or more BSON documents to insert into the collection |
| } with { |
| variant "TAG (header, opCode = OP_INSERT)"; |
| variant (header) "LENGTHTO(header, flags, fullCollectionName, documents)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB update message, |
| // ------------------------------------------------------------------------------ |
| |
| // flags: definitions of bits |
| type record UpdateMsgFlagsBits { |
| // If set, the database will insert the supplied object into the collection if no matching document is found. |
| BIT1 Upsert, |
| |
| // If set, the database will update all matching objects in the collection. Otherwise only updates first matching document. |
| BIT1 MultiUpdate, |
| |
| // 2-31 bits are reserved. Must be set to 0 |
| BIT30 Reserved0 |
| } with { variant "" } |
| |
| // flags can be accessed via bits or value |
| type union UpdateMsgFlags { |
| UpdateMsgFlagsBits bits, |
| int32 bytes |
| } with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| // message structure |
| type record UpdateMsg |
| { |
| MsgHeader header, // standard message header |
| int32 ZERO, // 0 - reserved for future use |
| cstring fullCollectionName, // "dbname.collectionname" |
| UpdateMsgFlags flags, // bit vector of update options. |
| octetstring selector, // BSON document that specifies the query for selection of the document to update |
| octetstring update // BSON document that specifies the update to be performed |
| } with { |
| variant "TAG (header, opCode = OP_UPDATE)"; |
| variant (header) "LENGTHTO(header, ZERO, fullCollectionName, flags, selector, update)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB query message, |
| // ------------------------------------------------------------------------------ |
| |
| // flags: definitions of bits |
| type record QueryMsgFlagsBits { |
| // Reserved. Must be set to 0. |
| BIT1 Reserved0, |
| |
| // Tailable means cursor is not closed when the last data is retrieved. Rather, the cursor marks the final |
| // object’s position. You can resume using the cursor later, from where it was located, if more data were received. |
| // Like any “latent cursor”, the cursor may become invalid at some point (CursorNotFound) – for example if the |
| // final object it references were deleted. |
| BIT1 TailableCursor, |
| |
| // Allow query of replica slave. Normally these return an error except for namespace “local”. |
| BIT1 SlaveOK, |
| |
| // Internal replication use only - driver should not set. |
| BIT1 OplogReplay, |
| |
| // The server normally times out idle cursors after an inactivity period (10 minutes) to prevent excess memory use. |
| // Set this option to prevent that.The server normally times out idle cursors after an inactivity period (10 minutes) |
| // to prevent excess memory use. Set this option to prevent that. |
| BIT1 NoCursorTimeout, |
| |
| // Use with TailableCursor. If we are at the end of the data, block for a while rather than returning no data. |
| // After a timeout period, we do return as normal. |
| BIT1 AwaitData, |
| |
| // Stream the data down full blast in multiple “more” packages, on the assumption that the client will fully read all |
| // data queried. Faster when you are pulling a lot of data and know you want to pull it all down. Note: the client is |
| // not allowed to not read all the data unless it closes the connection.Stream the data down full blast in multiple “more” packages, |
| // on the assumption that the client will fully read all data queried. Faster when you are pulling a lot of data and know you want |
| // to pull it all down. Note: the client is not allowed to not read all the data unless it closes the connection. |
| BIT1 Exhaust, |
| |
| // Get partial results from a mongos if some shards are down (instead of throwing an error) |
| BIT1 Partial, |
| |
| // 8-31 bits are reserved. Must be set to 0. |
| BIT24 Reserved1 |
| } with { variant "" } |
| |
| // flags can be accessed via bits or value |
| type union QueryMsgFlags { |
| QueryMsgFlagsBits bits, |
| int32 bytes |
| } with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| // message structure |
| type record QueryMsg |
| { |
| MsgHeader header, // standard message header |
| QueryMsgFlags flags, // bit vector of query options. |
| cstring fullCollectionName, // "dbname.collectionname" |
| int32 numberToSkip, // number of documents to skip |
| int32 numberToReturn, // number of documents to return in the first OP_REPLY batch |
| octetstring query, // BSON document that represents the query |
| octetstring returnFieldsSelector optional // BSON document that limits the fields in the returned documents. |
| } with { |
| variant "TAG (header, opCode = OP_QUERY)"; |
| variant (header) "LENGTHTO(header, flags, fullCollectionName, numberToSkip, numberToReturn, query, returnFieldsSelector)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB get more message, |
| // ------------------------------------------------------------------------------ |
| |
| // message structure |
| type record GetMoreMsg |
| { |
| MsgHeader header, // standard message header |
| int32 ZERO, // 0 - reserved for future use |
| cstring fullCollectionName, // "dbname.collectionname" |
| int32 numberToReturn, // number of documents to return |
| int64 cursorID // cursor id from OP_REPLY |
| } with { |
| variant "TAG (header, opCode = OP_GET_MORE)"; |
| variant (header) "LENGTHTO(header, ZERO, fullCollectionName, numberToReturn, cursorID)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB delete message, |
| // ------------------------------------------------------------------------------ |
| |
| // flags: definitions of bits |
| type record DeleteMsgFlagsBits { |
| // If set, the database will remove only the first matching document in the collection. |
| // Otherwise all matching documents will be removed. |
| BIT1 SingleRemove, |
| |
| // 1-31 bits are reserved. Must be set to 0. |
| BIT31 Reserved1 |
| } with { variant "" } |
| |
| // flags can be accessed via bits or value |
| type union DeleteMsgFlags { |
| DeleteMsgFlagsBits bits, |
| int32 bytes |
| } with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| // message structure |
| type record DeleteMsg |
| { |
| MsgHeader header, // standard message header |
| int32 ZERO, // 0 - reserved for future use |
| cstring fullCollectionName, // "dbname.collectionname" |
| DeleteMsgFlags flags, // bit vector of delete options. |
| octetstring selector // BSON document that represent the query used to select the documents to be removed |
| } with { |
| variant "TAG (header, opCode = OP_DELETE)"; |
| variant (header) "LENGTHTO(header, ZERO, fullCollectionName, flags, selector)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB kill cursor message |
| // ------------------------------------------------------------------------------ |
| |
| // message structure |
| type record KillCursorMsg |
| { |
| MsgHeader header, // standard message header |
| int32 ZERO, // 0 - reserved for future use |
| int32 numberOfCursorIDs, // number of cursorIDs in message |
| roInt64 cursorIDs // sequence of cursorIDs |
| } with { |
| variant "TAG (header, opCode = OP_KILL_CURSORS)"; |
| variant (header) "LENGTHTO(header, ZERO, numberOfCursorIDs, cursorIDs)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB command message, |
| // ------------------------------------------------------------------------------ |
| |
| // command message structure |
| type record CommandMsg |
| { |
| MsgHeader header, // standard message header |
| cstring database, |
| cstring commandName, |
| octetstring metadata, |
| octetstring commandArgs, |
| octetstring inputDocs optional |
| } |
| with { |
| variant "TAG (header, opCode = OP_COMMAND)"; |
| variant (header) "LENGTHTO(header, database, commandName, metadata, commandArgs, inputDocs)"; |
| variant (header) "LENGTHINDEX(messageLength)" |
| } |
| |
| |
| // ============================================================================== |
| // |
| // mongoDB response messages |
| // |
| // ============================================================================== |
| |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB reply message, |
| // ------------------------------------------------------------------------------ |
| |
| // flags: definitions of bits |
| type record ReplyMsgFlagsBits { |
| // Is set when getMore is called but the cursor id is not valid at the server. Returned with zero results. |
| BIT1 CursorNotFound, |
| |
| // Is set when query failed. Results consist of one document containing an “$err” field describing the failure. |
| BIT1 QueryFailure, |
| |
| // Drivers should ignore this. Only mongos will ever see this set, in which case, it needs to update config from the server. |
| BIT1 ShardConfigStale, |
| |
| // Is set when the server supports the AwaitData Query option. If it doesn’t, a client should sleep a little |
| // between getMore’s of a Tailable cursor. Mongod version 1.6 supports AwaitData and thus always sets AwaitCapable. |
| BIT1 AwaitCapable, |
| |
| // 4-31 bits are reserved. Ignore. |
| BIT28 Reserved |
| } with { variant "" } |
| |
| // flags can be accessed via bits or value |
| type union ReplyMsgFlags { |
| ReplyMsgFlagsBits bits, |
| int32 bytes |
| } with { variant "FIELDLENGTH(32), COMP(signbit), BYTEORDER(first)" }; |
| |
| type union ReplyMsgDocuments { |
| octetstring octets, |
| JSONRecords json |
| } with { variant "" }; |
| |
| // command message structure |
| type record ReplyMsg |
| { |
| MsgHeader header, // standard message header |
| ReplyMsgFlags responseFlags, // bit vector - see details below |
| int64 cursorID, // cursor id if client needs to do get more's |
| int32 startingFrom, // where in the cursor this reply is starting |
| int32 numberReturned, // number of documents in the reply |
| ReplyMsgDocuments documents // documents |
| } with { |
| variant "TAG (header, opCode = OP_REPLY)"; |
| } |
| |
| // ------------------------------------------------------------------------------ |
| // mongoDB command reply message |
| // ------------------------------------------------------------------------------ |
| type record CommandReplyMsg |
| { |
| MsgHeader header, // standard message header |
| octetstring metadata, // A BSON document containing any required metadata |
| octetstring commandArgs, // A BSON document containing the command reply |
| octetstring inputDocs optional // A variable number of BSON documents |
| } |
| with { variant "" } |
| |
| // ============================================================================== |
| // |
| // Generic mongoDB message definitions |
| // |
| // ============================================================================== |
| |
| // ------------------------------------------------------------------------------ |
| // generic mongoDB message (union of all message types) |
| // ------------------------------------------------------------------------------ |
| type union Msg { |
| InsertMsg insert, |
| UpdateMsg update, |
| QueryMsg query, |
| GetMoreMsg getMore, |
| DeleteMsg delete, |
| KillCursorMsg killCursor, |
| CommandMsg command, |
| ReplyMsg reply_, |
| CommandReplyMsg commandReply, |
| octetstring octects |
| } with { |
| variant (insert) "TAG (header, opCode = OP_INSERT)"; |
| variant (update) "TAG (header, opCode = OP_UPDATE)"; |
| variant (query) "TAG (header, opCode = OP_QUERY)"; |
| variant (getMore) "TAG (header, opCode = OP_GET_MORE)"; |
| variant (delete) "TAG (header, opCode = OP_DELETE)"; |
| variant (killCursor) "TAG (header, opCode = OP_KILL_CURSORS)"; |
| variant (command) "TAG (header, opCode = OP_COMMAND)"; |
| variant (reply_) "TAG (header, opCode = OP_REPLY)"; |
| variant (commandReply) "TAG (header, opCode = OP_COMMANDREPLY)"; |
| } |
| |
| // ------------------------------------------------------------------------------ |
| // generic encode and decode function for generic message type |
| // ------------------------------------------------------------------------------ |
| external function encMsg (in Msg msg) return octetstring |
| with { extension "prototype(convert) encode(RAW)" } |
| |
| external function decMsg (in octetstring octets) return Msg |
| with { extension "prototype(convert) decode(RAW)" } |
| |
| } with { encode "RAW" } |