3 * Routines for Couchbase Protocol
5 * Copyright 2019, Trond Norbye <trond@couchbase.com>
6 * Copyright 2018, Jim Walker <jim@couchbase.com>
7 * Copyright 2015-2016, Dave Rigby <daver@couchbase.com>
8 * Copyright 2011, Sergey Avseyev <sergey.avseyev@gmail.com>
10 * With contributions from Mark Woosey <mark@markwoosey.com>
13 * Based on packet-memcache.c: mecmcache binary protocol.
15 * Routines for Memcache Binary Protocol
16 * http://code.google.com/p/memcached/wiki/MemcacheBinaryProtocol
18 * Copyright 2009, Stig Bjorlykke <stig@bjorlykke.org>
20 * Routines for Memcache Textual Protocol
21 * https://github.com/memcached/memcached/blob/master/doc/protocol.txt
23 * Copyright 2009, Rama Chitta <rama@gear6.com>
25 * Wireshark - Network traffic analyzer
26 * By Gerald Combs <gerald@wireshark.org>
27 * Copyright 1998 Gerald Combs
29 * SPDX-License-Identifier: GPL-2.0-or-later
35 #include <epan/packet.h>
36 #include <epan/prefs.h>
37 #include <epan/expert.h>
39 #include <epan/unit_strings.h>
45 #include "packet-tcp.h"
46 #include "packet-tls.h"
50 #define PNAME "Couchbase Protocol"
51 #define PSNAME "Couchbase"
52 #define PFNAME "couchbase"
54 #define COUCHBASE_DEFAULT_PORT "11210"
55 #define COUCHBASE_HEADER_LEN 24
60 * The magic used for a normal request sent from the client to the
61 * server. Layout described in:
62 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header
64 MAGIC_CLIENT_REQUEST
= 0x80,
66 * The magic used for a normal response sent from the server to
67 * the client. Layout described in:
68 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#response-header
70 MAGIC_CLIENT_RESPONSE
= 0x81,
72 * The magic used when the client want to inject a set of extensions
73 * to the command sent to the server. Layout described in:
74 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header-with-flexible-framing-extras
76 MAGIC_CLIENT_RESPONSE_FLEX
= 0x18,
78 * The magic used by the server when the server needs to inject a set of
79 * extensions in the response packet. Layout described in:
80 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#response-header-with-flexible-framing-extras
82 MAGIC_CLIENT_REQUEST_FLEX
= 0x08,
84 * The magic used for server initiated push requests. These packets
85 * use the same layout as client flex request packets (with a different
86 * namespace for the frame id's)
88 MAGIC_SERVER_REQUEST
= 0x82,
90 * The magic used for responses to server initiated push requests. These
91 * packets use the same layout as client flex response packet (with
92 * a different namespace for the frame id's)
94 MAGIC_SERVER_RESPONSE
= 0x83
97 /** Does the magic represent a flex encoded packet type */
98 static bool is_flex_encoded(uint8_t magic
) {
100 case MAGIC_CLIENT_RESPONSE_FLEX
:
101 case MAGIC_CLIENT_REQUEST_FLEX
:
102 case MAGIC_SERVER_REQUEST
:
103 case MAGIC_SERVER_RESPONSE
:
106 case MAGIC_CLIENT_REQUEST
:
107 case MAGIC_CLIENT_RESPONSE
:
113 /** Does the magic represent server initiated packet types */
114 static bool is_server_magic(uint8_t magic
) {
116 case MAGIC_SERVER_REQUEST
:
117 case MAGIC_SERVER_RESPONSE
:
120 case MAGIC_CLIENT_RESPONSE_FLEX
:
121 case MAGIC_CLIENT_REQUEST_FLEX
:
122 case MAGIC_CLIENT_REQUEST
:
123 case MAGIC_CLIENT_RESPONSE
:
129 /** Does the magic represent a request or a response */
130 static bool is_request_magic(uint8_t magic
) {
132 case MAGIC_SERVER_REQUEST
:
133 case MAGIC_CLIENT_REQUEST_FLEX
:
134 case MAGIC_CLIENT_REQUEST
:
137 case MAGIC_SERVER_RESPONSE
:
138 case MAGIC_CLIENT_RESPONSE_FLEX
:
139 case MAGIC_CLIENT_RESPONSE
:
145 /* Response Status */
146 #define STATUS_SUCCESS 0x00
147 #define STATUS_KEY_ENOENT 0x01
148 #define STATUS_KEY_EEXISTS 0x02
149 #define STATUS_E2BIG 0x03
150 #define STATUS_EINVAL 0x04
151 #define STATUS_NOT_STORED 0x05
152 #define STATUS_DELTA_BADVAL 0x06
153 #define STATUS_NOT_MY_VBUCKET 0x07
154 #define STATUS_NO_VBUCKET 0x08
155 #define STATUS_LOCKED 0x09
156 #define STATUS_DCP_STREAM_NOT_FOUND 0x0a
157 #define STATUS_OPAQUE_NO_MATCH 0x0b
158 #define STATUS_EWOULDTHROTTLE 0x0c
159 #define STATUS_ECONFIGONLY 0x0d
160 #define STATUS_NOT_LOCKED 0x0e
161 #define STATUS_AUTH_STALE 0x1f
162 #define STATUS_AUTH_ERROR 0x20
163 #define STATUS_AUTH_CONTINUE 0x21
164 #define STATUS_ERANGE 0x22
165 #define STATUS_ROLLBACK 0x23
166 #define STATUS_EACCESS 0x24
167 #define STATUS_NOT_INITIALIZED 0x25
168 #define STATUS_RATELIMITED_NETWORK_INGRESS 0x30
169 #define STATUS_RATELIMITED_NETWORK_EGRESS 0x31
170 #define STATUS_RATELIMITED_MAX_CONNECTIONS 0x32
171 #define STATUS_RATELIMITED_MAX_COMMANDS 0x33
172 #define STATUS_SCOPE_SIZE_LIMIT_EXCEEDED 0x34
173 #define STATUS_UNKNOWN_COMMAND 0x81
174 #define STATUS_ENOMEM 0x82
175 #define STATUS_NOT_SUPPORTED 0x83
176 #define STATUS_EINTERNAL 0x84
177 #define STATUS_EBUSY 0x85
178 #define STATUS_ETMPFAIL 0x86
179 #define STATUS_XATTR_EINVAL 0x87
180 #define STATUS_UNKNOWN_COLLECTION 0x88
181 #define STATUS_NO_COLLECTIONS_MANIFEST 0x89
182 #define STATUS_CANNOT_APPLY_MANIFEST 0x8a
183 #define STATUS_MANIFEST_IS_AHEAD 0x8b
184 #define STATUS_UNKNOWN_SCOPE 0x8c
185 #define STATUS_DCP_STREAMID_INVALID 0x8d
186 #define STATUS_DURABILITY_INVALID_LEVEL 0xa0
187 #define STATUS_DURABILITY_IMPOSSIBLE 0xa1
188 #define STATUS_SYNC_WRITE_IN_PROGRESS 0xa2
189 #define STATUS_SYNC_WRITE_AMBIGUOUS 0xa3
190 #define STATUS_SYNC_WRITE_RECOMMIT_IN_PROGRESS 0xa4
191 #define STATUS_RANGE_SCAN_CANCELLED 0xa5
192 #define STATUS_RANGE_SCAN_MORE 0xa6
193 #define STATUS_RANGE_SCAN_COMPLETE 0xa7
194 #define STATUS_VBUUID_NOT_EQUAL 0xa8
195 #define STATUS_SUBDOC_PATH_ENOENT 0xc0
196 #define STATUS_SUBDOC_PATH_MISMATCH 0xc1
197 #define STATUS_SUBDOC_PATH_EINVAL 0xc2
198 #define STATUS_SUBDOC_PATH_E2BIG 0xc3
199 #define STATUS_SUBDOC_DOC_E2DEEP 0xc4
200 #define STATUS_SUBDOC_VALUE_CANTINSERT 0xc5
201 #define STATUS_SUBDOC_DOC_NOTJSON 0xc6
202 #define STATUS_SUBDOC_NUM_ERANGE 0xc7
203 #define STATUS_SUBDOC_DELTA_ERANGE 0xc8
204 #define STATUS_SUBDOC_PATH_EEXISTS 0xc9
205 #define STATUS_SUBDOC_VALUE_ETOODEEP 0xca
206 #define STATUS_SUBDOC_INVALID_COMBO 0xcb
207 #define STATUS_SUBDOC_MULTI_PATH_FAILURE 0xcc
208 #define STATUS_SUBDOC_SUCCESS_DELETED 0xcd
209 #define STATUS_SUBDOC_XATTR_INVALID_FLAG_COMBO 0xce
210 #define STATUS_SUBDOC_XATTR_INVALID_KEY_COMBO 0xcf
211 #define STATUS_SUBDOC_XATTR_UNKNOWN_MACRO 0xd0
212 #define STATUS_SUBDOC_XATTR_UNKNOWN_VATTR 0xd1
213 #define STATUS_SUBDOC_XATTR_CANT_MODIFY_VATTR 0xd2
214 #define STATUS_SUBDOC_MULTI_PATH_FAILURE_DELETED 0xd3
215 #define STATUS_SUBDOC_INVALID_XATTR_ORDER 0xd4
216 #define STATUS_SUBDOC_XATTR_UNKNOWN_VATTR_MACRO 0xd5
217 #define STATUS_SUBDOC_CAN_ONLY_REVIVE_DELETED_DOCUMENTS 0xd6
218 #define STATUS_SUBDOC_DELETED_DOCUMENT_CANT_HAVE_VALUE 0xd7
220 /* Command Opcodes */
221 #define CLIENT_OPCODE_GET 0x00
222 #define CLIENT_OPCODE_SET 0x01
223 #define CLIENT_OPCODE_ADD 0x02
224 #define CLIENT_OPCODE_REPLACE 0x03
225 #define CLIENT_OPCODE_DELETE 0x04
226 #define CLIENT_OPCODE_INCREMENT 0x05
227 #define CLIENT_OPCODE_DECREMENT 0x06
228 #define CLIENT_OPCODE_QUIT 0x07
229 #define CLIENT_OPCODE_FLUSH 0x08
230 #define CLIENT_OPCODE_GETQ 0x09
231 #define CLIENT_OPCODE_NOOP 0x0a
232 #define CLIENT_OPCODE_VERSION 0x0b
233 #define CLIENT_OPCODE_GETK 0x0c
234 #define CLIENT_OPCODE_GETKQ 0x0d
235 #define CLIENT_OPCODE_APPEND 0x0e
236 #define CLIENT_OPCODE_PREPEND 0x0f
237 #define CLIENT_OPCODE_STAT 0x10
238 #define CLIENT_OPCODE_SETQ 0x11
239 #define CLIENT_OPCODE_ADDQ 0x12
240 #define CLIENT_OPCODE_REPLACEQ 0x13
241 #define CLIENT_OPCODE_DELETEQ 0x14
242 #define CLIENT_OPCODE_INCREMENTQ 0x15
243 #define CLIENT_OPCODE_DECREMENTQ 0x16
244 #define CLIENT_OPCODE_QUITQ 0x17
245 #define CLIENT_OPCODE_FLUSHQ 0x18
246 #define CLIENT_OPCODE_APPENDQ 0x19
247 #define CLIENT_OPCODE_PREPENDQ 0x1a
248 #define CLIENT_OPCODE_VERBOSITY 0x1b
249 #define CLIENT_OPCODE_TOUCH 0x1c
250 #define CLIENT_OPCODE_GAT 0x1d
251 #define CLIENT_OPCODE_GATQ 0x1e
252 #define CLIENT_OPCODE_HELLO 0x1f
254 /* SASL operations */
255 #define CLIENT_OPCODE_SASL_LIST_MECHS 0x20
256 #define CLIENT_OPCODE_SASL_AUTH 0x21
257 #define CLIENT_OPCODE_SASL_STEP 0x22
260 #define CLIENT_OPCODE_IOCTL_GET 0x23
261 #define CLIENT_OPCODE_IOCTL_SET 0x24
262 #define CLIENT_OPCODE_CONFIG_VALIDATE 0x25
263 #define CLIENT_OPCODE_CONFIG_RELOAD 0x26
264 #define CLIENT_OPCODE_AUDIT_PUT 0x27
265 #define CLIENT_OPCODE_AUDIT_CONFIG_RELOAD 0x28
266 #define CLIENT_OPCODE_SHUTDOWN 0x29
269 * These commands are used for range operations and exist within
270 * protocol_binary.h for use in other projects. Range operations are
271 * not expected to be implemented in the memcached server itself.
273 #define CLIENT_OPCODE_RGET 0x30
274 #define CLIENT_OPCODE_RSET 0x31
275 #define CLIENT_OPCODE_RSETQ 0x32
276 #define CLIENT_OPCODE_RAPPEND 0x33
277 #define CLIENT_OPCODE_RAPPENDQ 0x34
278 #define CLIENT_OPCODE_RPREPEND 0x35
279 #define CLIENT_OPCODE_RPREPENDQ 0x36
280 #define CLIENT_OPCODE_RDELETE 0x37
281 #define CLIENT_OPCODE_RDELETEQ 0x38
282 #define CLIENT_OPCODE_RINCR 0x39
283 #define CLIENT_OPCODE_RINCRQ 0x3a
284 #define CLIENT_OPCODE_RDECR 0x3b
285 #define CLIENT_OPCODE_RDECRQ 0x3c
288 /* VBucket commands */
289 #define CLIENT_OPCODE_SET_VBUCKET 0x3d
290 #define CLIENT_OPCODE_GET_VBUCKET 0x3e
291 #define CLIENT_OPCODE_DEL_VBUCKET 0x3f
294 #define CLIENT_OPCODE_TAP_CONNECT 0x40
295 #define CLIENT_OPCODE_TAP_MUTATION 0x41
296 #define CLIENT_OPCODE_TAP_DELETE 0x42
297 #define CLIENT_OPCODE_TAP_FLUSH 0x43
298 #define CLIENT_OPCODE_TAP_OPAQUE 0x44
299 #define CLIENT_OPCODE_TAP_VBUCKET_SET 0x45
300 #define CLIENT_OPCODE_TAP_CHECKPOINT_START 0x46
301 #define CLIENT_OPCODE_TAP_CHECKPOINT_END 0x47
303 #define CLIENT_OPCODE_GET_ALL_VB_SEQNOS 0x48
306 #define CLIENT_OPCODE_DCP_OPEN_CONNECTION 0x50
307 #define CLIENT_OPCODE_DCP_ADD_STREAM 0x51
308 #define CLIENT_OPCODE_DCP_CLOSE_STREAM 0x52
309 #define CLIENT_OPCODE_DCP_STREAM_REQUEST 0x53
310 #define CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST 0x54
311 #define CLIENT_OPCODE_DCP_STREAM_END 0x55
312 #define CLIENT_OPCODE_DCP_SNAPSHOT_MARKER 0x56
313 #define CLIENT_OPCODE_DCP_MUTATION 0x57
314 #define CLIENT_OPCODE_DCP_DELETION 0x58
315 #define CLIENT_OPCODE_DCP_EXPIRATION 0x59
316 #define CLIENT_OPCODE_DCP_FLUSH 0x5a
317 #define CLIENT_OPCODE_DCP_SET_VBUCKET_STATE 0x5b
318 #define CLIENT_OPCODE_DCP_NOOP 0x5c
319 #define CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT 0x5d
320 #define CLIENT_OPCODE_DCP_CONTROL 0x5e
321 #define CLIENT_OPCODE_DCP_SYSTEM_EVENT 0x5f
322 #define CLIENT_OPCODE_DCP_PREPARE 0x60
323 #define CLIENT_OPCODE_DCP_SEQNO_ACK 0x61
324 #define CLIENT_OPCODE_DCP_COMMIT 0x62
325 #define CLIENT_OPCODE_DCP_ABORT 0x63
326 #define CLIENT_OPCODE_DCP_SEQNO_ADVANCED 0x64
327 #define CLIENT_OPCODE_DCP_OSO_SNAPSHOT 0x65
329 /* Commands from EP (eventually persistent) and bucket engines */
330 #define CLIENT_OPCODE_STOP_PERSISTENCE 0x80
331 #define CLIENT_OPCODE_START_PERSISTENCE 0x81
332 #define CLIENT_OPCODE_SET_PARAM 0x82
333 #define CLIENT_OPCODE_GET_REPLICA 0x83
334 #define CLIENT_OPCODE_CREATE_BUCKET 0x85
335 #define CLIENT_OPCODE_DELETE_BUCKET 0x86
336 #define CLIENT_OPCODE_LIST_BUCKETS 0x87
337 #define CLIENT_OPCODE_EXPAND_BUCKET 0x88
338 #define CLIENT_OPCODE_SELECT_BUCKET 0x89
339 #define CLIENT_OPCODE_START_REPLICATION 0x90
340 #define CLIENT_OPCODE_OBSERVE_SEQNO 0x91
341 #define CLIENT_OPCODE_OBSERVE 0x92
342 #define CLIENT_OPCODE_EVICT_KEY 0x93
343 #define CLIENT_OPCODE_GET_LOCKED 0x94
344 #define CLIENT_OPCODE_UNLOCK_KEY 0x95
345 #define CLIENT_OPCODE_SYNC 0x96
346 #define CLIENT_OPCODE_LAST_CLOSED_CHECKPOINT 0x97
347 #define CLIENT_OPCODE_RESTORE_FILE 0x98
348 #define CLIENT_OPCODE_RESTORE_ABORT 0x99
349 #define CLIENT_OPCODE_RESTORE_COMPLETE 0x9a
350 #define CLIENT_OPCODE_ONLINE_UPDATE_START 0x9b
351 #define CLIENT_OPCODE_ONLINE_UPDATE_COMPLETE 0x9c
352 #define CLIENT_OPCODE_ONLINE_UPDATE_REVERT 0x9d
353 #define CLIENT_OPCODE_DEREGISTER_TAP_CLIENT 0x9e
354 #define CLIENT_OPCODE_RESET_REPLICATION_CHAIN 0x9f
355 #define CLIENT_OPCODE_GET_META 0xa0
356 #define CLIENT_OPCODE_GETQ_META 0xa1
357 #define CLIENT_OPCODE_SET_WITH_META 0xa2
358 #define CLIENT_OPCODE_SETQ_WITH_META 0xa3
359 #define CLIENT_OPCODE_ADD_WITH_META 0xa4
360 #define CLIENT_OPCODE_ADDQ_WITH_META 0xa5
361 #define CLIENT_OPCODE_SNAPSHOT_VB_STATES 0xa6
362 #define CLIENT_OPCODE_VBUCKET_BATCH_COUNT 0xa7
363 #define CLIENT_OPCODE_DEL_WITH_META 0xa8
364 #define CLIENT_OPCODE_DELQ_WITH_META 0xa9
365 #define CLIENT_OPCODE_CREATE_CHECKPOINT 0xaa
366 #define CLIENT_OPCODE_NOTIFY_VBUCKET_UPDATE 0xac
367 #define CLIENT_OPCODE_ENABLE_TRAFFIC 0xad
368 #define CLIENT_OPCODE_DISABLE_TRAFFIC 0xae
369 #define CLIENT_OPCODE_IFCONFIG 0xaf
370 #define CLIENT_OPCODE_CHANGE_VB_FILTER 0xb0
371 #define CLIENT_OPCODE_CHECKPOINT_PERSISTENCE 0xb1
372 #define CLIENT_OPCODE_RETURN_META 0xb2
373 #define CLIENT_OPCODE_COMPACT_DB 0xb3
376 #define CLIENT_OPCODE_SET_CLUSTER_CONFIG 0xb4
377 #define CLIENT_OPCODE_GET_CLUSTER_CONFIG 0xb5
378 #define CLIENT_OPCODE_GET_RANDOM_KEY 0xb6
379 #define CLIENT_OPCODE_SEQNO_PERSISTENCE 0xb7
380 #define CLIENT_OPCODE_GET_KEYS 0xb8
381 #define CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST 0xb9
382 #define CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST 0xba
383 #define CLIENT_OPCODE_COLLECTIONS_GET_ID 0xbb
384 #define CLIENT_OPCODE_COLLECTIONS_GET_SCOPE_ID 0xbc
386 #define CLIENT_OPCODE_SET_DRIFT_COUNTER_STATE 0xc1
387 #define CLIENT_OPCODE_GET_ADJUSTED_TIME 0xc2
389 /* Sub-document API commands */
390 #define CLIENT_OPCODE_SUBDOC_GET 0xc5
391 #define CLIENT_OPCODE_SUBDOC_EXISTS 0xc6
392 #define CLIENT_OPCODE_SUBDOC_DICT_ADD 0xc7
393 #define CLIENT_OPCODE_SUBDOC_DICT_UPSERT 0xc8
394 #define CLIENT_OPCODE_SUBDOC_DELETE 0xc9
395 #define CLIENT_OPCODE_SUBDOC_REPLACE 0xca
396 #define CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST 0xcb
397 #define CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST 0xcc
398 #define CLIENT_OPCODE_SUBDOC_ARRAY_INSERT 0xcd
399 #define CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE 0xce
400 #define CLIENT_OPCODE_SUBDOC_COUNTER 0xcf
401 #define CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP 0xd0
402 #define CLIENT_OPCODE_SUBDOC_MULTI_MUTATION 0xd1
403 #define CLIENT_OPCODE_SUBDOC_GET_COUNT 0xd2
404 #define CLIENT_OPCODE_SUBDOC_REPLACE_BODY_WITH_XATTR 0xd3
406 #define CLIENT_OPCODE_RANGE_SCAN_CREATE 0xda
407 #define CLIENT_OPCODE_RANGE_SCAN_CONTINUE 0xdb
408 #define CLIENT_OPCODE_RANGE_SCAN_CANCEL 0xdc
410 #define CLIENT_OPCODE_SCRUB 0xf0
411 #define CLIENT_OPCODE_ISASL_REFRESH 0xf1
412 #define CLIENT_OPCODE_SSL_CERTS_REFRESH 0xf2
413 #define CLIENT_OPCODE_GET_CMD_TIMER 0xf3
414 #define CLIENT_OPCODE_SET_CTRL_TOKEN 0xf4
415 #define CLIENT_OPCODE_GET_CTRL_TOKEN 0xf5
416 #define CLIENT_OPCODE_UPDATE_EXTERNAL_USER_PERMISSIONS 0xf6
417 #define CLIENT_OPCODE_RBAC_REFRESH 0xf7
418 #define CLIENT_OPCODE_AUTH_PROVIDER 0xf8
419 #define CLIENT_OPCODE_DROP_PRIVILEGE 0xfb
420 #define CLIENT_OPCODE_ADJUST_TIMEOFDAY 0xfc
421 #define CLIENT_OPCODE_EWOULDBLOCK_CTL 0xfd
422 #define CLIENT_OPCODE_GET_ERROR_MAP 0xfe
425 #define VBUCKET_ACTIVE 0x01
426 #define VBUCKET_PENDING 0x02
427 #define VBUCKET_REPLICA 0x03
428 #define VBUCKET_DEAD 0x04
431 #define DT_RAW_BYTES 0x00
433 #define DT_SNAPPY 0x02
434 #define DT_XATTR 0x04
436 void proto_register_couchbase(void);
437 void proto_reg_handoff_couchbase(void);
439 static int proto_couchbase
;
442 static int hf_opcode
;
443 static int hf_server_opcode
;
444 static int hf_extlength
;
445 static int hf_keylength
;
446 static int hf_value_length
;
447 static int hf_datatype
;
448 static int hf_datatype_json
;
449 static int hf_datatype_snappy
;
450 static int hf_datatype_xattr
;
451 static int hf_vbucket
;
452 static int hf_status
;
453 static int hf_total_bodylength
;
454 static int hf_opaque
;
458 static int hf_collection_key_id
;
459 static int hf_collection_key_logical
;
460 static int hf_collection_manifest_id
;
462 static int hf_flex_extras_length
;
463 static int hf_flex_keylength
;
464 static int hf_extras
;
465 static int hf_extras_flags
;
466 static int hf_extras_flags_backfill
;
467 static int hf_extras_flags_dump
;
468 static int hf_extras_flags_list_vbuckets
;
469 static int hf_extras_flags_takeover_vbuckets
;
470 static int hf_extras_flags_support_ack
;
471 static int hf_extras_flags_request_keys_only
;
472 static int hf_extras_flags_checkpoint
;
473 static int hf_extras_flags_dcp_connection_type
;
474 static int hf_extras_flags_dcp_add_stream_takeover
;
475 static int hf_extras_flags_dcp_add_stream_diskonly
;
476 static int hf_extras_flags_dcp_add_stream_latest
;
477 static int hf_extras_flags_dcp_snapshot_marker_memory
;
478 static int hf_extras_flags_dcp_snapshot_marker_disk
;
479 static int hf_extras_flags_dcp_snapshot_marker_chk
;
480 static int hf_extras_flags_dcp_snapshot_marker_ack
;
481 static int hf_extras_flags_dcp_snapshot_marker_history
;
482 static int hf_extras_flags_dcp_snapshot_marker_may_contain_dups
;
483 static int hf_extras_flags_dcp_include_xattrs
;
484 static int hf_extras_flags_dcp_no_value
;
485 static int hf_extras_flags_dcp_include_delete_times
;
486 static int hf_extras_flags_dcp_collections
;
487 static int hf_extras_flags_dcp_oso_snapshot_begin
;
488 static int hf_extras_flags_dcp_oso_snapshot_end
;
489 static int hf_subdoc_doc_flags
;
490 static int hf_subdoc_doc_flags_mkdoc
;
491 static int hf_subdoc_doc_flags_add
;
492 static int hf_subdoc_doc_flags_accessdeleted
;
493 static int hf_subdoc_doc_flags_createasdeleted
;
494 static int hf_subdoc_doc_flags_revivedocument
;
495 static int hf_subdoc_doc_flags_replicaread
;
496 static int hf_subdoc_doc_flags_reserved
;
497 static int hf_subdoc_flags
;
498 static int hf_subdoc_flags_mkdirp
;
499 static int hf_subdoc_flags_xattrpath
;
500 static int hf_subdoc_flags_expandmacros
;
501 static int hf_subdoc_flags_reserved
;
502 static int hf_extras_seqno
;
503 static int hf_extras_mutation_seqno
;
504 static int hf_extras_opaque
;
505 static int hf_extras_reserved
;
506 static int hf_extras_start_seqno
;
507 static int hf_extras_end_seqno
;
508 static int hf_extras_high_completed_seqno
;
509 static int hf_extras_max_visible_seqno
;
510 static int hf_extras_timestamp
;
511 static int hf_extras_marker_version
;
512 static int hf_extras_vbucket_uuid
;
513 static int hf_extras_snap_start_seqno
;
514 static int hf_extras_snap_end_seqno
;
515 static int hf_extras_expiration
;
516 static int hf_extras_delta
;
517 static int hf_extras_initial
;
518 static int hf_extras_unknown
;
519 static int hf_extras_by_seqno
;
520 static int hf_extras_rev_seqno
;
521 static int hf_extras_prepared_seqno
;
522 static int hf_extras_commit_seqno
;
523 static int hf_extras_abort_seqno
;
524 static int hf_extras_deleted
;
525 static int hf_extras_lock_time
;
526 static int hf_extras_nmeta
;
527 static int hf_extras_nru
;
528 static int hf_extras_bytes_to_ack
;
529 static int hf_extras_delete_time
;
530 static int hf_extras_delete_unused
;
531 static int hf_extras_system_event_id
;
532 static int hf_extras_system_event_version
;
533 static int hf_extras_pathlen
;
534 static int hf_extras_dcp_oso_snapshot_flags
;
535 static int hf_server_extras_cccp_epoch
;
536 static int hf_server_extras_cccp_revno
;
537 static int hf_server_clustermap_value
;
538 static int hf_server_authentication
;
539 static int hf_server_external_users
;
540 static int hf_server_get_authorization
;
545 static int hf_uint64_response
;
546 static int hf_observe
;
547 static int hf_observe_vbucket
;
548 static int hf_observe_keylength
;
549 static int hf_observe_key
;
550 static int hf_observe_status
;
551 static int hf_observe_cas
;
552 static int hf_observe_vbucket_uuid
;
553 static int hf_observe_failed_over
;
554 static int hf_observe_last_persisted_seqno
;
555 static int hf_observe_current_seqno
;
556 static int hf_observe_old_vbucket_uuid
;
557 static int hf_observe_last_received_seqno
;
559 static int hf_get_errmap_version
;
561 static int hf_failover_log
;
562 static int hf_failover_log_size
;
563 static int hf_failover_log_vbucket_uuid
;
564 static int hf_failover_log_vbucket_seqno
;
566 static int hf_vbucket_states
;
567 static int hf_vbucket_states_state
;
568 static int hf_vbucket_states_size
;
569 static int hf_vbucket_states_id
;
570 static int hf_vbucket_states_seqno
;
572 static int hf_bucket_type
;
573 static int hf_bucket_config
;
574 static int hf_config_key
;
575 static int hf_config_value
;
577 static int hf_multipath_opcode
;
578 static int hf_multipath_index
;
579 static int hf_multipath_pathlen
;
580 static int hf_multipath_path
;
581 static int hf_multipath_valuelen
;
582 static int hf_multipath_value
;
584 static int hf_meta_flags
;
585 static int hf_meta_expiration
;
586 static int hf_meta_revseqno
;
587 static int hf_meta_cas
;
588 static int hf_skip_conflict
;
589 static int hf_force_accept
;
590 static int hf_regenerate_cas
;
591 static int hf_force_meta
;
592 static int hf_is_expiration
;
593 static int hf_meta_options
;
594 static int hf_metalen
;
595 static int hf_meta_reqextmeta
;
596 static int hf_meta_deleted
;
597 static int hf_exptime
;
598 static int hf_extras_meta_seqno
;
599 static int hf_confres
;
600 static int hf_hello_features
;
601 static int hf_hello_features_feature
;
603 static int hf_xattr_length
;
604 static int hf_xattr_pair_length
;
605 static int hf_xattr_key
;
606 static int hf_xattr_value
;
607 static int hf_xattrs
;
609 static int hf_flex_extras
;
610 static int hf_flex_extras_n
;
611 static int hf_flex_frame_id_byte0
;
612 static int hf_flex_frame_id_req
;
613 static int hf_flex_frame_id_res
;
614 static int hf_flex_frame_id_req_esc
;
615 static int hf_flex_frame_id_res_esc
;
616 static int hf_flex_frame_len
;
617 static int hf_flex_frame_len_esc
;
618 static int hf_flex_frame_tracing_duration
;
619 static int hf_flex_frame_ru_count
;
620 static int hf_flex_frame_wu_count
;
621 static int hf_flex_frame_durability_req
;
622 static int hf_flex_frame_dcp_stream_id
;
623 static int hf_flex_frame_impersonated_user
;
625 static int hf_range_scan_uuid
;
626 static int hf_range_scan_item_limit
;
627 static int hf_range_scan_time_limit
;
628 static int hf_range_scan_byte_limit
;
630 static expert_field ei_warn_shall_not_have_value
;
631 static expert_field ei_warn_shall_not_have_extras
;
632 static expert_field ei_warn_shall_not_have_key
;
633 static expert_field ei_compression_error
;
634 static expert_field ei_warn_unknown_flex_unsupported
;
635 static expert_field ei_warn_unknown_flex_id
;
636 static expert_field ei_warn_unknown_flex_len
;
638 static expert_field ei_value_missing
;
639 static expert_field ei_warn_must_have_extras
;
640 static expert_field ei_warn_must_have_key
;
641 static expert_field ei_warn_illegal_extras_length
;
642 static expert_field ei_warn_illegal_value_length
;
643 static expert_field ei_warn_unknown_magic_byte
;
644 static expert_field ei_warn_unknown_opcode
;
645 static expert_field ei_warn_unknown_extras
;
646 static expert_field ei_note_status_code
;
647 static expert_field ei_separator_not_found
;
648 static expert_field ei_illegal_value
;
650 static int ett_couchbase
;
651 static int ett_extras
;
652 static int ett_extras_flags
;
653 static int ett_observe
;
654 static int ett_failover_log
;
655 static int ett_vbucket_states
;
656 static int ett_multipath
;
657 static int ett_config
;
658 static int ett_config_key
;
659 static int ett_hello_features
;
660 static int ett_datatype
;
661 static int ett_xattrs
;
662 static int ett_xattr_pair
;
663 static int ett_flex_frame_extras
;
664 static int ett_collection_key
;
666 static const value_string magic_vals
[] = {
667 { MAGIC_CLIENT_REQUEST
, "Request" },
668 { MAGIC_CLIENT_RESPONSE
, "Response" },
669 { MAGIC_CLIENT_RESPONSE_FLEX
, "Response with flexible framing extras" },
670 { MAGIC_CLIENT_REQUEST_FLEX
, "Request with flexible framing extras" },
671 { MAGIC_SERVER_REQUEST
, "Server Request"},
672 { MAGIC_SERVER_RESPONSE
, "Server Response"},
676 #define FLEX_ESCAPE 0x0F
679 The flex extension identifiers are different for request/response
680 i.e. 0 in a response is not 0 in a request
683 #define FLEX_RESPONSE_ID_RX_TX_DURATION 0
684 #define FLEX_RESPONSE_ID_RU_USAGE 1
685 #define FLEX_RESPONSE_ID_WU_USAGE 2
688 #define FLEX_REQUEST_ID_REORDER 0
689 #define FLEX_REQUEST_ID_DURABILITY 1
690 #define FLEX_REQUEST_ID_DCP_STREAM_ID 2
691 #define FLEX_REQUEST_ID_OPEN_TRACING 3
692 #define FLEX_REQUEST_ID_IMPERSONATE 4
693 #define FLEX_REQUEST_ID_PRESERVE_TTL 5
695 static const value_string flex_frame_response_ids
[] = {
696 { FLEX_RESPONSE_ID_RX_TX_DURATION
, "Server Recv->Send duration"},
697 { FLEX_RESPONSE_ID_RU_USAGE
, "Read units"},
698 { FLEX_RESPONSE_ID_WU_USAGE
, "Write units"},
702 static const value_string flex_frame_request_ids
[] = {
703 { FLEX_REQUEST_ID_REORDER
, "Out of order Execution"},
704 { FLEX_REQUEST_ID_DURABILITY
, "Durability Requirements"},
705 { FLEX_REQUEST_ID_DCP_STREAM_ID
, "DCP Stream Identifier"},
706 { FLEX_REQUEST_ID_OPEN_TRACING
, "Open Tracing"},
707 { FLEX_REQUEST_ID_IMPERSONATE
, "Impersonate User"},
708 { FLEX_REQUEST_ID_PRESERVE_TTL
, "Preserve TTL"},
712 static const value_string flex_frame_durability_req
[] = {
714 { 2, "Majority and persist on active"},
715 { 3, "Persist to majority"},
719 static const value_string status_vals
[] = {
720 { STATUS_SUCCESS
, "Success" },
721 { STATUS_KEY_ENOENT
, "Key not found" },
722 { STATUS_KEY_EEXISTS
, "Key exists" },
723 { STATUS_E2BIG
, "Value too big" },
724 { STATUS_EINVAL
, "Invalid arguments" },
725 { STATUS_NOT_STORED
, "Key not stored" },
726 { STATUS_DELTA_BADVAL
, "Bad value to incr/decr" },
727 { STATUS_NOT_MY_VBUCKET
, "Not my vBucket" },
728 { STATUS_NO_VBUCKET
, "Not connected to a bucket" },
729 { STATUS_LOCKED
, "The requested resource is locked" },
730 { STATUS_DCP_STREAM_NOT_FOUND
, "No DCP Stream for this request" },
731 { STATUS_OPAQUE_NO_MATCH
, "Opaque does not match" },
732 { STATUS_EWOULDTHROTTLE
, "Command would have been throttled" },
733 { STATUS_ECONFIGONLY
, "Command can't be executed in config-only bucket" },
734 { STATUS_NOT_LOCKED
, "Unlock request for an unlocked document" },
735 { STATUS_AUTH_STALE
, "Authentication context is stale. Should reauthenticate." },
736 { STATUS_AUTH_ERROR
, "Authentication error" },
737 { STATUS_AUTH_CONTINUE
, "Authentication continue" },
738 { STATUS_ERANGE
, "Range error" },
739 { STATUS_ROLLBACK
, "Rollback" },
740 { STATUS_EACCESS
, "Access error" },
741 { STATUS_NOT_INITIALIZED
,
742 "The Couchbase cluster is currently initializing this node, and "
743 "the Cluster manager has not yet granted all users access to the cluster."},
744 { STATUS_RATELIMITED_NETWORK_INGRESS
, "Rate limit: Network ingress"},
745 { STATUS_RATELIMITED_NETWORK_EGRESS
, "Rate limit: Network Egress"},
746 { STATUS_RATELIMITED_MAX_CONNECTIONS
, "Rate limit: Max Connections"},
747 { STATUS_RATELIMITED_MAX_COMMANDS
, "Rate limit: Max Commands"},
748 {STATUS_SCOPE_SIZE_LIMIT_EXCEEDED
, "To much data in Scope"},
749 { STATUS_UNKNOWN_COMMAND
, "Unknown command" },
750 { STATUS_ENOMEM
, "Out of memory" },
751 { STATUS_NOT_SUPPORTED
, "Command isn't supported" },
752 { STATUS_EINTERNAL
, "Internal error" },
753 { STATUS_EBUSY
, "Server is busy" },
754 { STATUS_ETMPFAIL
, "Temporary failure" },
755 { STATUS_XATTR_EINVAL
,
756 "There is something wrong with the syntax of the provided XATTR."},
757 { STATUS_UNKNOWN_COLLECTION
,
758 "Operation attempted with an unknown collection."},
759 { STATUS_NO_COLLECTIONS_MANIFEST
,
760 "No collections manifest has been set"},
761 { STATUS_CANNOT_APPLY_MANIFEST
,
762 "Cannot apply the given manifest"},
763 { STATUS_MANIFEST_IS_AHEAD
,
764 "Operation attempted with a manifest ahead of the server"},
765 { STATUS_UNKNOWN_SCOPE
,
766 "Operation attempted with an unknown scope."},
767 { STATUS_DCP_STREAMID_INVALID
,
768 "DCP Stream ID is invalid"},
769 { STATUS_DURABILITY_INVALID_LEVEL
,
770 "The specified durability level is invalid" },
771 { STATUS_DURABILITY_IMPOSSIBLE
,
772 "The specified durability requirements are not currently possible" },
773 { STATUS_SYNC_WRITE_IN_PROGRESS
,
774 "A SyncWrite is already in progress on the specified key"},
775 { STATUS_SYNC_WRITE_AMBIGUOUS
,
776 "The SyncWrite request has not completed in the specified time and has ambiguous result"},
777 { STATUS_SYNC_WRITE_RECOMMIT_IN_PROGRESS
,
778 "The SyncWrite is being re-committed after a change in active node"},
779 { STATUS_RANGE_SCAN_CANCELLED
, "RangeScan was cancelled"},
780 { STATUS_RANGE_SCAN_MORE
, "RangeScan has more data available"},
781 { STATUS_RANGE_SCAN_COMPLETE
, "RangeScan has completed"},
782 { STATUS_VBUUID_NOT_EQUAL
, "VB UUID does not equal server value"},
783 { STATUS_SUBDOC_PATH_ENOENT
,
784 "Subdoc: Path not does not exist"},
785 { STATUS_SUBDOC_PATH_MISMATCH
,
786 "Subdoc: Path mismatch"},
787 { STATUS_SUBDOC_PATH_EINVAL
,
788 "Subdoc: Invalid path"},
789 { STATUS_SUBDOC_PATH_E2BIG
,
790 "Subdoc: Path too large"},
791 { STATUS_SUBDOC_DOC_E2DEEP
,
792 "Subdoc: Document too deep"},
793 { STATUS_SUBDOC_VALUE_CANTINSERT
,
794 "Subdoc: Cannot insert specified value"},
795 { STATUS_SUBDOC_DOC_NOTJSON
,
796 "Subdoc: Existing document not JSON"},
797 { STATUS_SUBDOC_NUM_ERANGE
,
798 "Subdoc: Existing number outside valid arithmetic range"},
799 { STATUS_SUBDOC_DELTA_ERANGE
,
800 "Subdoc: Delta outside valid arithmetic range"},
801 { STATUS_SUBDOC_PATH_EEXISTS
,
802 "Subdoc: Document path already exists"},
803 { STATUS_SUBDOC_VALUE_ETOODEEP
,
804 "Subdoc: Inserting value would make document too deep"},
805 { STATUS_SUBDOC_INVALID_COMBO
,
806 "Subdoc: Invalid combination for multi-path command"},
807 { STATUS_SUBDOC_MULTI_PATH_FAILURE
,
808 "Subdoc: One or more paths in a multi-path command failed"},
809 { STATUS_SUBDOC_SUCCESS_DELETED
,
810 "Subdoc: The operation completed successfully, but operated on a deleted document."},
811 { STATUS_SUBDOC_XATTR_INVALID_FLAG_COMBO
,
812 "Subdoc: The combination of the subdoc flags for the xattrs doesn't make any sense."},
813 { STATUS_SUBDOC_XATTR_INVALID_KEY_COMBO
,
814 "Subdoc: Only a single xattr key may be accessed at the same time."},
815 { STATUS_SUBDOC_XATTR_UNKNOWN_MACRO
,
816 "Subdoc: The server has no knowledge of the requested macro."},
817 { STATUS_SUBDOC_XATTR_UNKNOWN_VATTR
,
818 "Subdoc: The server has no knowledge of the requested virtual xattr."},
819 { STATUS_SUBDOC_XATTR_CANT_MODIFY_VATTR
,
820 "Subdoc: Virtual xattrs can't be modified."},
821 { STATUS_SUBDOC_MULTI_PATH_FAILURE_DELETED
,
822 "Subdoc: Specified key was found as a deleted document, but one or more path operations failed."},
823 { STATUS_SUBDOC_INVALID_XATTR_ORDER
,
824 "Subdoc: According to the spec all xattr commands should come first, followed by the commands for the document body."},
825 { STATUS_SUBDOC_XATTR_UNKNOWN_VATTR_MACRO
,
826 "Subdoc: The server does not know about this virtual macro."},
827 { STATUS_SUBDOC_CAN_ONLY_REVIVE_DELETED_DOCUMENTS
,
828 "Subdoc: The document isn't dead (and we wanted to revive the document)."},
829 { STATUS_SUBDOC_DELETED_DOCUMENT_CANT_HAVE_VALUE
,
830 "Subdoc: A deleted document can't have a user value."},
834 static value_string_ext status_vals_ext
= VALUE_STRING_EXT_INIT(status_vals
);
836 static const value_string client_opcode_vals
[] = {
837 { CLIENT_OPCODE_GET
, "Get" },
838 { CLIENT_OPCODE_SET
, "Set" },
839 { CLIENT_OPCODE_ADD
, "Add" },
840 { CLIENT_OPCODE_REPLACE
, "Replace" },
841 { CLIENT_OPCODE_DELETE
, "Delete" },
842 { CLIENT_OPCODE_INCREMENT
, "Increment" },
843 { CLIENT_OPCODE_DECREMENT
, "Decrement" },
844 { CLIENT_OPCODE_QUIT
, "Quit" },
845 { CLIENT_OPCODE_FLUSH
, "Flush" },
846 { CLIENT_OPCODE_GETQ
, "Get Quietly" },
847 { CLIENT_OPCODE_NOOP
, "NOOP" },
848 { CLIENT_OPCODE_VERSION
, "Version" },
849 { CLIENT_OPCODE_GETK
, "Get Key" },
850 { CLIENT_OPCODE_GETKQ
, "Get Key Quietly" },
851 { CLIENT_OPCODE_APPEND
, "Append" },
852 { CLIENT_OPCODE_PREPEND
, "Prepend" },
853 { CLIENT_OPCODE_STAT
, "Statistics" },
854 { CLIENT_OPCODE_SETQ
, "Set Quietly" },
855 { CLIENT_OPCODE_ADDQ
, "Add Quietly" },
856 { CLIENT_OPCODE_REPLACEQ
, "Replace Quietly" },
857 { CLIENT_OPCODE_DELETEQ
, "Delete Quietly" },
858 { CLIENT_OPCODE_INCREMENTQ
, "Increment Quietly" },
859 { CLIENT_OPCODE_DECREMENTQ
, "Decrement Quietly" },
860 { CLIENT_OPCODE_QUITQ
, "Quit Quietly" },
861 { CLIENT_OPCODE_FLUSHQ
, "Flush Quietly" },
862 { CLIENT_OPCODE_APPENDQ
, "Append Quietly" },
863 { CLIENT_OPCODE_PREPENDQ
, "Prepend Quietly" },
864 { CLIENT_OPCODE_VERBOSITY
, "Verbosity" },
865 { CLIENT_OPCODE_TOUCH
, "Touch" },
866 { CLIENT_OPCODE_GAT
, "Get and Touch" },
867 { CLIENT_OPCODE_GATQ
, "Gat and Touch Quietly" },
868 { CLIENT_OPCODE_HELLO
, "Hello" },
869 { CLIENT_OPCODE_SASL_LIST_MECHS
, "List SASL Mechanisms" },
870 { CLIENT_OPCODE_SASL_AUTH
, "SASL Authenticate" },
871 { CLIENT_OPCODE_SASL_STEP
, "SASL Step" },
872 { CLIENT_OPCODE_IOCTL_GET
, "IOCTL Get" },
873 { CLIENT_OPCODE_IOCTL_SET
, "IOCTL Set" },
874 { CLIENT_OPCODE_CONFIG_VALIDATE
, "Config Validate" },
875 { CLIENT_OPCODE_CONFIG_RELOAD
, "Config Reload" },
876 { CLIENT_OPCODE_AUDIT_PUT
, "Audit Put" },
877 { CLIENT_OPCODE_AUDIT_CONFIG_RELOAD
, "Audit Config Reload" },
878 { CLIENT_OPCODE_SHUTDOWN
, "Shutdown" },
879 { CLIENT_OPCODE_RGET
, "Range Get" },
880 { CLIENT_OPCODE_RSET
, "Range Set" },
881 { CLIENT_OPCODE_RSETQ
, "Range Set Quietly" },
882 { CLIENT_OPCODE_RAPPEND
, "Range Append" },
883 { CLIENT_OPCODE_RAPPENDQ
, "Range Append Quietly" },
884 { CLIENT_OPCODE_RPREPEND
, "Range Prepend" },
885 { CLIENT_OPCODE_RPREPENDQ
, "Range Prepend Quietly" },
886 { CLIENT_OPCODE_RDELETE
, "Range Delete" },
887 { CLIENT_OPCODE_RDELETEQ
, "Range Delete Quietly" },
888 { CLIENT_OPCODE_RINCR
, "Range Increment" },
889 { CLIENT_OPCODE_RINCRQ
, "Range Increment Quietly" },
890 { CLIENT_OPCODE_RDECR
, "Range Decrement" },
891 { CLIENT_OPCODE_RDECRQ
, "Range Decrement Quietly" },
892 { CLIENT_OPCODE_SET_VBUCKET
, "Set VBucket" },
893 { CLIENT_OPCODE_GET_VBUCKET
, "Get VBucket" },
894 { CLIENT_OPCODE_DEL_VBUCKET
, "Delete VBucket" },
895 { CLIENT_OPCODE_TAP_CONNECT
, "TAP Connect" },
896 { CLIENT_OPCODE_TAP_MUTATION
, "TAP Mutation" },
897 { CLIENT_OPCODE_TAP_DELETE
, "TAP Delete" },
898 { CLIENT_OPCODE_TAP_FLUSH
, "TAP Flush" },
899 { CLIENT_OPCODE_TAP_OPAQUE
, "TAP Opaque" },
900 { CLIENT_OPCODE_TAP_VBUCKET_SET
, "TAP VBucket Set" },
901 { CLIENT_OPCODE_TAP_CHECKPOINT_START
, "TAP Checkpoint Start" },
902 { CLIENT_OPCODE_TAP_CHECKPOINT_END
, "TAP Checkpoint End" },
903 { CLIENT_OPCODE_GET_ALL_VB_SEQNOS
, "Get All VBucket Seqnos" },
904 { CLIENT_OPCODE_DCP_OPEN_CONNECTION
, "DCP Open Connection" },
905 { CLIENT_OPCODE_DCP_ADD_STREAM
, "DCP Add Stream" },
906 { CLIENT_OPCODE_DCP_CLOSE_STREAM
, "DCP Close Stream" },
907 { CLIENT_OPCODE_DCP_STREAM_REQUEST
, "DCP Stream Request" },
908 { CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST
, "DCP Get Failover Log" },
909 { CLIENT_OPCODE_DCP_STREAM_END
, "DCP Stream End" },
910 { CLIENT_OPCODE_DCP_SNAPSHOT_MARKER
, "DCP Snapshot Marker" },
911 { CLIENT_OPCODE_DCP_MUTATION
, "DCP (Key) Mutation" },
912 { CLIENT_OPCODE_DCP_DELETION
, "DCP (Key) Deletion" },
913 { CLIENT_OPCODE_DCP_EXPIRATION
, "DCP (Key) Expiration" },
914 { CLIENT_OPCODE_DCP_FLUSH
, "DCP Flush" },
915 { CLIENT_OPCODE_DCP_SET_VBUCKET_STATE
, "DCP Set VBucket State" },
916 { CLIENT_OPCODE_DCP_NOOP
, "DCP NOOP" },
917 { CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT
, "DCP Buffer Acknowledgement"},
918 { CLIENT_OPCODE_DCP_CONTROL
, "DCP Control" },
919 { CLIENT_OPCODE_DCP_SYSTEM_EVENT
, "DCP System Event" },
920 { CLIENT_OPCODE_DCP_PREPARE
, "DCP Prepare" },
921 { CLIENT_OPCODE_DCP_SEQNO_ACK
, "DCP Seqno Acknowledgement"},
922 { CLIENT_OPCODE_DCP_COMMIT
, "DCP Commit" },
923 { CLIENT_OPCODE_DCP_ABORT
, "DCP Abort" },
924 { CLIENT_OPCODE_DCP_SEQNO_ADVANCED
, "DCP Seqno Advanced" },
925 { CLIENT_OPCODE_DCP_OSO_SNAPSHOT
, "DCP Out of Sequence Order Snapshot"},
926 { CLIENT_OPCODE_STOP_PERSISTENCE
, "Stop Persistence" },
927 { CLIENT_OPCODE_START_PERSISTENCE
, "Start Persistence" },
928 { CLIENT_OPCODE_SET_PARAM
, "Set Parameter" },
929 { CLIENT_OPCODE_GET_REPLICA
, "Get Replica" },
930 { CLIENT_OPCODE_CREATE_BUCKET
, "Create Bucket" },
931 { CLIENT_OPCODE_DELETE_BUCKET
, "Delete Bucket" },
932 { CLIENT_OPCODE_LIST_BUCKETS
, "List Buckets" },
933 { CLIENT_OPCODE_EXPAND_BUCKET
, "Expand Bucket" },
934 { CLIENT_OPCODE_SELECT_BUCKET
, "Select Bucket" },
935 { CLIENT_OPCODE_START_REPLICATION
, "Start Replication" },
936 { CLIENT_OPCODE_OBSERVE_SEQNO
, "Observe Sequence Number" },
937 { CLIENT_OPCODE_OBSERVE
, "Observe" },
938 { CLIENT_OPCODE_EVICT_KEY
, "Evict Key" },
939 { CLIENT_OPCODE_GET_LOCKED
, "Get Locked" },
940 { CLIENT_OPCODE_UNLOCK_KEY
, "Unlock Key" },
941 { CLIENT_OPCODE_SYNC
, "Sync" },
942 { CLIENT_OPCODE_LAST_CLOSED_CHECKPOINT
, "Last Closed Checkpoint" },
943 { CLIENT_OPCODE_RESTORE_FILE
, "Restore File" },
944 { CLIENT_OPCODE_RESTORE_ABORT
, "Restore Abort" },
945 { CLIENT_OPCODE_RESTORE_COMPLETE
, "Restore Complete" },
946 { CLIENT_OPCODE_ONLINE_UPDATE_START
, "Online Update Start" },
947 { CLIENT_OPCODE_ONLINE_UPDATE_COMPLETE
, "Online Update Complete" },
948 { CLIENT_OPCODE_ONLINE_UPDATE_REVERT
, "Online Update Revert" },
949 { CLIENT_OPCODE_DEREGISTER_TAP_CLIENT
, "Deregister TAP Client" },
950 { CLIENT_OPCODE_RESET_REPLICATION_CHAIN
, "Reset Replication Chain" },
951 { CLIENT_OPCODE_GET_META
, "Get Meta" },
952 { CLIENT_OPCODE_GETQ_META
, "Get Meta Quietly" },
953 { CLIENT_OPCODE_SET_WITH_META
, "Set with Meta" },
954 { CLIENT_OPCODE_SETQ_WITH_META
, "Set with Meta Quietly" },
955 { CLIENT_OPCODE_ADD_WITH_META
, "Add with Meta" },
956 { CLIENT_OPCODE_ADDQ_WITH_META
, "Add with Meta Quietly" },
957 { CLIENT_OPCODE_SNAPSHOT_VB_STATES
, "Snapshot VBuckets States" },
958 { CLIENT_OPCODE_VBUCKET_BATCH_COUNT
, "VBucket Batch Count" },
959 { CLIENT_OPCODE_DEL_WITH_META
, "Delete with Meta" },
960 { CLIENT_OPCODE_DELQ_WITH_META
, "Delete with Meta Quietly" },
961 { CLIENT_OPCODE_CREATE_CHECKPOINT
, "Create Checkpoint" },
962 { CLIENT_OPCODE_NOTIFY_VBUCKET_UPDATE
, "Notify VBucket Update" },
963 { CLIENT_OPCODE_ENABLE_TRAFFIC
, "Enable Traffic" },
964 { CLIENT_OPCODE_DISABLE_TRAFFIC
, "Disable Traffic" },
965 { CLIENT_OPCODE_IFCONFIG
, "Ifconfig" },
966 { CLIENT_OPCODE_CHANGE_VB_FILTER
, "Change VBucket Filter" },
967 { CLIENT_OPCODE_CHECKPOINT_PERSISTENCE
, "Checkpoint Persistence" },
968 { CLIENT_OPCODE_RETURN_META
, "Return Meta" },
969 { CLIENT_OPCODE_COMPACT_DB
, "Compact Database" },
970 { CLIENT_OPCODE_SET_CLUSTER_CONFIG
, "Set Cluster Config" },
971 { CLIENT_OPCODE_GET_CLUSTER_CONFIG
, "Get Cluster Config" },
972 { CLIENT_OPCODE_GET_RANDOM_KEY
, "Get Random Key" },
973 { CLIENT_OPCODE_SEQNO_PERSISTENCE
, "Seqno Persistence" },
974 { CLIENT_OPCODE_GET_KEYS
, "Get Keys" },
975 { CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST
, "Set Collection's Manifest" },
976 { CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST
, "Get Collection's Manifest" },
977 { CLIENT_OPCODE_COLLECTIONS_GET_ID
, "Get Collection ID" },
978 { CLIENT_OPCODE_COLLECTIONS_GET_SCOPE_ID
, "Get Scope ID" },
979 { CLIENT_OPCODE_SET_DRIFT_COUNTER_STATE
, "Set Drift Counter State" },
980 { CLIENT_OPCODE_GET_ADJUSTED_TIME
, "Get Adjusted Time" },
981 { CLIENT_OPCODE_SUBDOC_GET
, "Subdoc Get" },
982 { CLIENT_OPCODE_SUBDOC_EXISTS
, "Subdoc Exists" },
983 { CLIENT_OPCODE_SUBDOC_DICT_ADD
, "Subdoc Dictionary Add" },
984 { CLIENT_OPCODE_SUBDOC_DICT_UPSERT
, "Subdoc Dictionary Upsert" },
985 { CLIENT_OPCODE_SUBDOC_DELETE
, "Subdoc Delete" },
986 { CLIENT_OPCODE_SUBDOC_REPLACE
, "Subdoc Replace" },
987 { CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST
, "Subdoc Array Push Last" },
988 { CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST
, "Subdoc Array Push First" },
989 { CLIENT_OPCODE_SUBDOC_ARRAY_INSERT
, "Subdoc Array Insert" },
990 { CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE
, "Subdoc Array Add Unique" },
991 { CLIENT_OPCODE_SUBDOC_COUNTER
, "Subdoc Counter" },
992 { CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP
, "Subdoc Multipath Lookup" },
993 { CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
, "Subdoc Multipath Mutation"},
994 { CLIENT_OPCODE_SUBDOC_GET_COUNT
, "Subdoc Get Count" },
995 { CLIENT_OPCODE_SUBDOC_REPLACE_BODY_WITH_XATTR
, "Subdoc Replace Body With Xattr"},
996 { CLIENT_OPCODE_RANGE_SCAN_CREATE
, "RangeScan Create" },
997 { CLIENT_OPCODE_RANGE_SCAN_CONTINUE
, "RangeScan Continue" },
998 { CLIENT_OPCODE_RANGE_SCAN_CANCEL
, "RangeScan Cancel" },
999 { CLIENT_OPCODE_SCRUB
, "Scrub" },
1000 { CLIENT_OPCODE_ISASL_REFRESH
, "isasl Refresh" },
1001 { CLIENT_OPCODE_SSL_CERTS_REFRESH
, "SSL Certificates Refresh" },
1002 { CLIENT_OPCODE_GET_CMD_TIMER
, "Internal Timer Control" },
1003 { CLIENT_OPCODE_SET_CTRL_TOKEN
, "Set Control Token" },
1004 { CLIENT_OPCODE_GET_CTRL_TOKEN
, "Get Control Token" },
1005 { CLIENT_OPCODE_UPDATE_EXTERNAL_USER_PERMISSIONS
, "Update External User Permissions"},
1006 { CLIENT_OPCODE_RBAC_REFRESH
, "RBAC Refresh" },
1007 { CLIENT_OPCODE_AUTH_PROVIDER
, "Auth Provider" },
1008 { CLIENT_OPCODE_DROP_PRIVILEGE
, "Drop Privilege" },
1009 { CLIENT_OPCODE_ADJUST_TIMEOFDAY
, "Adjust Timeofday" },
1010 { CLIENT_OPCODE_EWOULDBLOCK_CTL
, "EWOULDBLOCK Control" },
1011 { CLIENT_OPCODE_GET_ERROR_MAP
, "Get Error Map" },
1013 /* Internally defined values not valid here */
1017 static value_string_ext client_opcode_vals_ext
= VALUE_STRING_EXT_INIT(client_opcode_vals
);
1020 SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
= 0x01,
1021 SERVER_OPCODE_AUTHENTICATE
= 0x02,
1022 SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
= 0x03,
1023 SERVER_OPCODE_GET_AUTHORIZATION
= 0x04
1026 static const value_string server_opcode_vals
[] = {
1027 { SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
, "ClustermapChangeNotification"},
1028 { SERVER_OPCODE_AUTHENTICATE
, "Authenticate"},
1029 { SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
, "ActiveExternalUsers"},
1030 { SERVER_OPCODE_GET_AUTHORIZATION
, "GetAuthorization"},
1033 static value_string_ext server_opcode_vals_ext
= VALUE_STRING_EXT_INIT(server_opcode_vals
);
1035 static const value_string dcp_connection_type_vals
[] = {
1042 static const value_string vbucket_states_vals
[] = {
1050 static int * const datatype_vals
[] = {
1052 &hf_datatype_snappy
,
1057 static int * const subdoc_flags
[] = {
1058 &hf_subdoc_flags_mkdirp
,
1059 &hf_subdoc_flags_xattrpath
,
1060 &hf_subdoc_flags_expandmacros
,
1061 &hf_subdoc_flags_reserved
,
1065 static int * const subdoc_doc_flags
[] = {
1066 &hf_subdoc_doc_flags_mkdoc
,
1067 &hf_subdoc_doc_flags_add
,
1068 &hf_subdoc_doc_flags_accessdeleted
,
1069 &hf_subdoc_doc_flags_createasdeleted
,
1070 &hf_subdoc_doc_flags_revivedocument
,
1071 &hf_subdoc_doc_flags_replicaread
,
1072 &hf_subdoc_doc_flags_reserved
,
1076 static int * const set_with_meta_extra_flags
[] = {
1084 static int * const del_with_meta_extra_flags
[] = {
1093 static const value_string feature_vals
[] = {
1094 {0x01, "Datatype (deprecated)"},
1096 {0x03, "TCP Nodelay"},
1097 {0x04, "Mutation Seqno"},
1098 {0x05, "TCP Delay"},
1100 {0x07, "Error Map"},
1101 {0x08, "Select Bucket"},
1102 {0x09, "Collections (deprecated)"},
1106 {0x0d, "Clustermap Change Notification"},
1107 {0x0e, "Unordered Execution"},
1109 {0x10, "AltRequestSupport"},
1110 {0x11, "SyncReplication"},
1111 {0x12, "Collections"},
1112 {0x13, "OpenTracing"},
1113 {0x14, "PreserveTtl"},
1115 {0x16, "Point in Time Recovery"},
1116 {0x17, "SubdocCreateAsDeleted"},
1117 {0x18, "SubdocDocumentMacroSupport"},
1118 {0x19, "SubdocReplaceBodyWithXattr"},
1119 {0x1a, "ReportUnitUsage"},
1120 {0x1b, "NonBlockingThrottlingMode"},
1121 {0x1c, "SubdocReplicaRead"},
1122 {0x1d, "GetClusterConfigWithKnownVersion"},
1123 {0x1e, "DedupeNotMyVbucketClustermap"},
1124 {0x1f, "ClustermapChangeNotificationBrief"},
1125 {0x20, "SubdocAllowsAccessOnMultipleXattrKeys"},
1129 static const value_string dcp_system_event_id_vals
[] = {
1130 {0, "CreateCollection"},
1131 {1, "DropCollection"},
1135 {5, "ModifyCollection"},
1139 static int * const snapshot_marker_flags
[] = {
1140 &hf_extras_flags_dcp_snapshot_marker_memory
,
1141 &hf_extras_flags_dcp_snapshot_marker_disk
,
1142 &hf_extras_flags_dcp_snapshot_marker_chk
,
1143 &hf_extras_flags_dcp_snapshot_marker_ack
,
1144 &hf_extras_flags_dcp_snapshot_marker_history
,
1145 &hf_extras_flags_dcp_snapshot_marker_may_contain_dups
,
1149 static dissector_handle_t couchbase_handle
;
1150 static dissector_handle_t json_handle
;
1152 /* desegmentation of COUCHBASE payload */
1153 static bool couchbase_desegment_body
= true;
1154 static unsigned couchbase_ssl_port
= 11207;
1155 static unsigned couchbase_ssl_port_pref
= 11207;
1157 /** Read out the magic byte (located at offset 0 in the header) */
1158 static uint8_t get_magic(tvbuff_t
*tvb
) {
1159 return tvb_get_uint8(tvb
, 0);
1162 /** Read out the opcode (located at offset 1 in the header) */
1163 static uint8_t get_opcode(tvbuff_t
*tvb
) {
1164 return tvb_get_uint8(tvb
, 1);
1167 /** Read out the status code from the header (only "valid" for response packets) */
1168 static uint16_t get_status(tvbuff_t
*tvb
) {
1169 return tvb_get_ntohs(tvb
, 6);
1172 /** Read out flex size (using the upper bits of the key length when using flex encoding) */
1173 static uint8_t get_flex_framing_extras_length(tvbuff_t
*tvb
) {
1174 if (is_flex_encoded(get_magic(tvb
))) {
1175 return tvb_get_uint8(tvb
, 2);
1180 /** Read out the size of the extras section (located at offset 4) */
1181 static uint8_t get_extras_length(tvbuff_t
*tvb
) {
1182 return tvb_get_uint8(tvb
, 4);
1185 /** Read out the datatype section (located at offset 5) */
1186 static uint8_t get_datatype(tvbuff_t
*tvb
) {
1187 return tvb_get_uint8(tvb
, 5);
1190 /** Read out the length of the key (1 or 2 bytes depending on the encoding) */
1191 static uint16_t get_key_length(tvbuff_t
*tvb
) {
1192 if (is_flex_encoded(get_magic(tvb
))) {
1193 return tvb_get_uint8(tvb
, 3);
1195 return tvb_get_ntohs(tvb
, 2);
1198 /** Read out the size for the rest of the frame data */
1199 static uint32_t get_body_length(tvbuff_t
*tvb
) {
1200 return tvb_get_ntohl(tvb
, 8);
1203 /* Returns true if the specified opcode's response value is JSON. */
1205 has_json_value(bool is_request
, uint8_t opcode
)
1209 case CLIENT_OPCODE_AUDIT_PUT
:
1210 case CLIENT_OPCODE_RANGE_SCAN_CREATE
:
1218 case CLIENT_OPCODE_GET_CLUSTER_CONFIG
:
1219 case CLIENT_OPCODE_SUBDOC_GET
:
1220 case CLIENT_OPCODE_COLLECTIONS_GET_MANIFEST
:
1221 case CLIENT_OPCODE_COLLECTIONS_SET_MANIFEST
:
1230 static void dissect_dcp_xattrs(tvbuff_t
*tvb
, proto_tree
*tree
,
1231 uint32_t value_len
, int offset
,
1232 packet_info
*pinfo
) {
1233 uint32_t xattr_size
, pair_len
;
1235 proto_tree
*xattr_tree
, *pair_tree
;
1238 proto_tree_add_item_ret_uint(tree
, hf_xattr_length
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &xattr_size
);
1239 value_len
= value_len
- (xattr_size
+ 4);
1242 ti
= proto_tree_add_item(tree
, hf_xattrs
, tvb
, offset
, xattr_size
, ENC_NA
);
1243 xattr_tree
= proto_item_add_subtree(ti
, ett_xattrs
);
1245 while (xattr_size
> 0) {
1247 ti
= proto_tree_add_item_ret_uint(xattr_tree
, hf_xattr_pair_length
, tvb
, offset
, 4, ENC_BIG_ENDIAN
, &pair_len
);
1248 pair_tree
= proto_item_add_subtree(ti
, ett_xattr_pair
);
1252 mark
= tvb_find_uint8(tvb
, offset
, pair_len
, 0x00);
1254 expert_add_info_format(pinfo
, ti
, &ei_separator_not_found
, "Null byte not found");
1258 ti
= proto_tree_add_item(pair_tree
, hf_xattr_key
, tvb
, offset
, mark
- offset
, ENC_ASCII
| ENC_NA
);
1259 xattr_size
-= (mark
- offset
) + 1;
1260 pair_len
-= (mark
- offset
) + 1;
1263 mark
= tvb_find_uint8(tvb
, offset
, pair_len
, 0x00);
1265 expert_add_info_format(pinfo
, ti
, &ei_separator_not_found
, "Null byte not found");
1269 proto_tree_add_item(pair_tree
, hf_xattr_value
, tvb
, offset
, mark
- offset
, ENC_ASCII
| ENC_NA
);
1270 xattr_size
-= (mark
- offset
) + 1;
1275 proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
1278 /* Dissects the required extras for subdoc single-path packets */
1280 dissect_subdoc_spath_required_extras(tvbuff_t
*tvb
, proto_tree
*extras_tree
,
1281 uint8_t extlen
, bool request
, int* offset
,
1282 uint16_t *path_len
, bool *illegal
)
1286 *path_len
= tvb_get_ntohs(tvb
, *offset
);
1287 proto_tree_add_item(extras_tree
, hf_extras_pathlen
, tvb
, *offset
, 2,
1291 proto_tree_add_bitmask(extras_tree
, tvb
, *offset
, hf_subdoc_flags
,
1292 ett_extras_flags
, subdoc_flags
, ENC_BIG_ENDIAN
);
1295 /* Must always have at least 3 bytes of extras */
1301 static void dissect_server_request_extras(tvbuff_t
*tvb _U_
, packet_info
*pinfo _U_
, proto_tree
*tree
, int offset
, uint8_t extlen
, uint8_t opcode
) {
1304 case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
:
1305 proto_tree_add_expert_format(tree
, pinfo
, &ei_warn_must_have_extras
, tvb
, offset
, 0,
1306 "ClustermapChangeNotification request must have extras");
1309 case SERVER_OPCODE_GET_AUTHORIZATION
:
1310 case SERVER_OPCODE_AUTHENTICATE
:
1311 case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
:
1312 // Success! none of these commands use extras
1315 // Probably ok as we don't know about the opcode
1321 proto_item
*extras_item
= proto_tree_add_item(tree
, hf_extras
, tvb
, offset
, extlen
, ENC_NA
);
1322 proto_tree
*extras_tree
= proto_item_add_subtree(extras_item
, ett_extras
);
1324 if (opcode
== SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
) {
1325 // Expected 16 bytes of extras!
1327 proto_tree_add_expert_format(extras_tree
, pinfo
,
1328 &ei_warn_illegal_extras_length
, tvb
,
1330 "ClustermapChangeNotification should have 16 bytes of extras");
1334 proto_tree_add_item(extras_tree
, hf_server_extras_cccp_epoch
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1336 proto_tree_add_item(extras_tree
, hf_server_extras_cccp_revno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1339 proto_tree_add_expert_format(extras_tree
, pinfo
,
1340 &ei_warn_illegal_extras_length
, tvb
,
1341 offset
+ 16, extlen
- 16,
1342 "Unexpected amount of extras");
1347 // we don't know how to decode this!
1348 proto_tree_add_item(extras_tree
, hf_extras_unknown
, tvb
, offset
, extlen
, ENC_NA
);
1352 dissect_server_response_extras(tvbuff_t
*tvb
, packet_info
*pinfo
,
1353 proto_tree
*tree
, int offset
, uint8_t extlen
,
1354 uint8_t opcode _U_
) {
1356 // Success! none of the known commands use extras
1360 proto_item
*extras_item
= proto_tree_add_item(tree
, hf_extras
, tvb
, offset
,
1362 proto_tree
*extras_tree
= proto_item_add_subtree(extras_item
, ett_extras
);
1363 proto_tree_add_expert_format(extras_tree
, pinfo
,
1364 &ei_warn_illegal_extras_length
, tvb
,
1366 "Unexpected amount of extras");
1370 dissect_client_extras(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
1371 int offset
, uint8_t extlen
, uint8_t opcode
, bool request
,
1374 proto_tree
*extras_tree
= NULL
;
1375 proto_item
*extras_item
= NULL
;
1376 int save_offset
= offset
, ii
;
1378 bool illegal
= false; /* Set when extras shall not be present */
1379 bool missing
= false; /* Set when extras is missing */
1383 const char *tap_connect_flags
[] = {
1384 "BACKFILL", "DUMP", "LIST_VBUCKETS", "TAKEOVER_VBUCKETS",
1385 "SUPPORT_ACK", "REQUEST_KEYS_ONLY", "CHECKPOINT", "REGISTERED_CLIENT"
1391 extras_item
= proto_tree_add_item(tree
, hf_extras
, tvb
, offset
, extlen
, ENC_NA
);
1392 extras_tree
= proto_item_add_subtree(extras_item
, ett_extras
);
1397 case CLIENT_OPCODE_GET
:
1398 case CLIENT_OPCODE_GETQ
:
1399 case CLIENT_OPCODE_GETK
:
1400 case CLIENT_OPCODE_GETKQ
:
1403 /* Request shall not have extras */
1406 proto_tree_add_item(extras_tree
, hf_extras_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1409 } else if (!request
) {
1410 /* Response must have extras */
1415 case CLIENT_OPCODE_SET
:
1416 case CLIENT_OPCODE_SETQ
:
1417 case CLIENT_OPCODE_ADD
:
1418 case CLIENT_OPCODE_ADDQ
:
1419 case CLIENT_OPCODE_REPLACE
:
1420 case CLIENT_OPCODE_REPLACEQ
:
1423 proto_tree_add_item(extras_tree
, hf_extras_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1426 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1429 proto_tree_add_item(extras_tree
, hf_extras_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1432 proto_tree_add_item(extras_tree
, hf_extras_mutation_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1435 } else if (request
) {
1436 /* Request must have extras */
1441 case CLIENT_OPCODE_INCREMENT
:
1442 case CLIENT_OPCODE_INCREMENTQ
:
1443 case CLIENT_OPCODE_DECREMENT
:
1444 case CLIENT_OPCODE_DECREMENTQ
:
1447 proto_tree_add_item(extras_tree
, hf_extras_delta
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1450 proto_tree_add_item(extras_tree
, hf_extras_initial
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1453 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1456 proto_tree_add_item(extras_tree
, hf_extras_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1459 proto_tree_add_item(extras_tree
, hf_extras_mutation_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1462 } else if (request
) {
1463 /* Request must have extras */
1468 case CLIENT_OPCODE_FLUSH
:
1469 case CLIENT_OPCODE_FLUSHQ
:
1471 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1476 case CLIENT_OPCODE_DELETE
:
1477 case CLIENT_OPCODE_DELETEQ
:
1478 case CLIENT_OPCODE_APPEND
:
1479 case CLIENT_OPCODE_APPENDQ
:
1480 case CLIENT_OPCODE_PREPEND
:
1481 case CLIENT_OPCODE_PREPENDQ
:
1484 /* Must not have extras */
1487 proto_tree_add_item(extras_tree
, hf_extras_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1490 proto_tree_add_item(extras_tree
, hf_extras_mutation_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1496 case CLIENT_OPCODE_QUIT
:
1497 case CLIENT_OPCODE_QUITQ
:
1498 case CLIENT_OPCODE_VERSION
:
1499 case CLIENT_OPCODE_STAT
:
1500 case CLIENT_OPCODE_OBSERVE
:
1501 case CLIENT_OPCODE_OBSERVE_SEQNO
:
1502 /* Must not have extras */
1508 case CLIENT_OPCODE_GET_ALL_VB_SEQNOS
:
1511 /* May have extras */
1512 proto_tree_add_item(extras_tree
, hf_vbucket_states_state
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1515 /* Must not have extras */
1521 case CLIENT_OPCODE_TAP_CONNECT
:
1523 static int * const extra_flags
[] = {
1524 &hf_extras_flags_backfill
,
1525 &hf_extras_flags_dump
,
1526 &hf_extras_flags_list_vbuckets
,
1527 &hf_extras_flags_takeover_vbuckets
,
1528 &hf_extras_flags_support_ack
,
1529 &hf_extras_flags_request_keys_only
,
1530 &hf_extras_flags_checkpoint
,
1534 /* TODO: extra_flags fields are 16-bits wide, whereas flags is 4 bytes? */
1535 tf
= proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_extras_flags
, ett_extras_flags
, extra_flags
, ENC_BIG_ENDIAN
);
1537 flags
= tvb_get_ntohl(tvb
, offset
);
1539 for (ii
= 0; ii
< 8; ii
++) {
1543 proto_item_append_text(tf
, " (");
1545 proto_item_append_text(tf
, "%s%s",
1546 first_flag
? "" : ", ",
1547 tap_connect_flags
[ii
]);
1551 if (first_flag
== true) {
1552 proto_item_append_text(tf
, " <None>");
1554 proto_item_append_text(tf
, ")");
1561 case CLIENT_OPCODE_TAP_MUTATION
:
1562 case CLIENT_OPCODE_TAP_DELETE
:
1563 case CLIENT_OPCODE_TAP_FLUSH
:
1564 case CLIENT_OPCODE_TAP_OPAQUE
:
1565 case CLIENT_OPCODE_TAP_VBUCKET_SET
:
1566 case CLIENT_OPCODE_TAP_CHECKPOINT_START
:
1567 case CLIENT_OPCODE_TAP_CHECKPOINT_END
:
1570 case CLIENT_OPCODE_DCP_OPEN_CONNECTION
:
1573 static int * const extra_flags
[] = {
1574 &hf_extras_flags_dcp_connection_type
,
1575 &hf_extras_flags_dcp_include_xattrs
,
1576 &hf_extras_flags_dcp_no_value
,
1577 &hf_extras_flags_dcp_collections
,
1578 &hf_extras_flags_dcp_include_delete_times
,
1582 proto_tree_add_item(extras_tree
, hf_extras_seqno
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1584 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_extras_flags
, ett_extras_flags
, extra_flags
, ENC_BIG_ENDIAN
);
1587 /* Response must not have extras (response is in Value) */
1590 } else if (request
) {
1591 /* Request must have extras */
1596 case CLIENT_OPCODE_DCP_ADD_STREAM
:
1599 static int * const extra_flags
[] = {
1600 &hf_extras_flags_dcp_add_stream_takeover
,
1601 &hf_extras_flags_dcp_add_stream_diskonly
,
1602 &hf_extras_flags_dcp_add_stream_latest
,
1606 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_extras_flags
, ett_extras_flags
, extra_flags
, ENC_BIG_ENDIAN
);
1609 proto_tree_add_item(extras_tree
, hf_extras_opaque
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1617 case CLIENT_OPCODE_DCP_STREAM_REQUEST
:
1620 /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1621 static int * const extra_flags[] = {
1625 proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1627 proto_tree_add_item(extras_tree
, hf_extras_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1629 proto_tree_add_item(extras_tree
, hf_extras_reserved
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1631 proto_tree_add_item(extras_tree
, hf_extras_start_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1633 proto_tree_add_item(extras_tree
, hf_extras_end_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1635 proto_tree_add_item(extras_tree
, hf_extras_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1637 proto_tree_add_item(extras_tree
, hf_extras_snap_start_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1639 proto_tree_add_item(extras_tree
, hf_extras_snap_end_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1642 } else if (request
) {
1643 /* Request must have extras */
1648 case CLIENT_OPCODE_DCP_SNAPSHOT_MARKER
:
1651 // Two formats exist and the extlen allows us to know which is which
1653 proto_tree_add_item(extras_tree
, hf_extras_marker_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1655 } else if (extlen
== 20){
1656 proto_tree_add_item(extras_tree
, hf_extras_start_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1658 proto_tree_add_item(extras_tree
, hf_extras_end_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1660 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_extras_flags
, ett_extras_flags
, snapshot_marker_flags
, ENC_BIG_ENDIAN
);
1668 } else if (request
) {
1669 /* Request must have extras */
1674 case CLIENT_OPCODE_DCP_MUTATION
:
1677 /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1678 static int * const extra_flags[] = {
1683 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1685 proto_tree_add_item(extras_tree
, hf_extras_rev_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1688 proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1690 proto_tree_add_item(extras_tree
, hf_extras_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1692 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1694 proto_tree_add_item(extras_tree
, hf_extras_lock_time
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1696 proto_tree_add_item(extras_tree
, hf_extras_nmeta
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1698 proto_tree_add_item(extras_tree
, hf_extras_nru
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1703 } else if (request
) {
1704 /* Request must have extras */
1709 case CLIENT_OPCODE_DCP_DELETION
:
1711 if (extlen
== 18 || extlen
== 21) {
1712 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1714 proto_tree_add_item(extras_tree
, hf_extras_rev_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1717 // Is this a delete with delete_time (21 bytes) or not (18 bytes)?
1719 proto_tree_add_item(extras_tree
, hf_extras_nmeta
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1721 } else if (extlen
== 21) {
1722 proto_tree_add_item(extras_tree
, hf_extras_delete_time
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1724 proto_tree_add_item(extras_tree
, hf_extras_delete_unused
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1727 } else if (extlen
== 0) {
1728 missing
= true; // request with no extras
1730 } else if (extlen
) {
1731 illegal
= true; // response with extras
1734 case CLIENT_OPCODE_DCP_EXPIRATION
:
1737 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1739 proto_tree_add_item(extras_tree
, hf_extras_rev_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1742 proto_tree_add_item(extras_tree
, hf_extras_delete_time
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1745 // Handle legacy expiration packet (despite its lack of use)
1746 proto_tree_add_item(extras_tree
, hf_extras_nmeta
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1752 } else if (request
) {
1753 /* Request must have extras */
1757 case CLIENT_OPCODE_DCP_FLUSH
:
1760 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1762 proto_tree_add_item(extras_tree
, hf_extras_rev_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1764 proto_tree_add_item(extras_tree
, hf_extras_nmeta
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
1769 } else if (request
) {
1770 /* Request must have extras */
1775 case CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT
:
1778 proto_tree_add_item(extras_tree
, hf_extras_bytes_to_ack
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1783 } else if (request
) {
1784 /* Request must have extras */
1788 case CLIENT_OPCODE_DCP_SYSTEM_EVENT
: {
1789 if (request
&& extlen
== 13) {
1790 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1792 proto_tree_add_item(extras_tree
, hf_extras_system_event_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1794 proto_tree_add_item(extras_tree
, hf_extras_system_event_version
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1799 case CLIENT_OPCODE_DCP_PREPARE
: {
1802 /* No extra_flags and proto_tree_add_bitmask don't work with empty flags See Bug:17890
1803 static int * const extra_flags[] = {
1808 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1810 proto_tree_add_item(extras_tree
, hf_extras_rev_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1813 proto_tree_add_bitmask(extras_tree, tvb, offset, hf_extras_flags, ett_extras_flags, extra_flags, ENC_BIG_ENDIAN);
1815 proto_tree_add_item(extras_tree
, hf_extras_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1817 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1819 proto_tree_add_item(extras_tree
, hf_extras_lock_time
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
1821 proto_tree_add_item(extras_tree
, hf_extras_nru
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1823 proto_tree_add_item(extras_tree
, hf_extras_deleted
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1825 proto_tree_add_item(extras_tree
, hf_flex_frame_durability_req
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
1830 } else if (request
) {
1831 /* Request must have extras */
1836 case CLIENT_OPCODE_DCP_SEQNO_ACK
: {
1839 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1844 } else if (request
) {
1845 /* Request must have extras */
1850 case CLIENT_OPCODE_DCP_COMMIT
: {
1853 proto_tree_add_item(extras_tree
, hf_extras_prepared_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1855 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1860 } else if (request
) {
1861 /* Request must have extras */
1866 case CLIENT_OPCODE_DCP_ABORT
: {
1869 proto_tree_add_item(extras_tree
, hf_extras_prepared_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1871 proto_tree_add_item(extras_tree
, hf_extras_abort_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1876 } else if (request
) {
1877 /* Request must have extras */
1882 case CLIENT_OPCODE_DCP_SEQNO_ADVANCED
: {
1885 proto_tree_add_item(extras_tree
, hf_extras_by_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
1890 } else if (request
) {
1891 /* Request must have extras */
1896 case CLIENT_OPCODE_DCP_OSO_SNAPSHOT
: {
1899 static int * const extra_flags
[] = {
1900 &hf_extras_flags_dcp_oso_snapshot_begin
,
1901 &hf_extras_flags_dcp_oso_snapshot_end
,
1904 proto_tree_add_bitmask(extras_tree
,
1907 hf_extras_dcp_oso_snapshot_flags
,
1915 } else if (request
) {
1916 /* Request must have extras */
1921 case CLIENT_OPCODE_SUBDOC_GET
:
1922 case CLIENT_OPCODE_SUBDOC_EXISTS
:
1923 dissect_subdoc_spath_required_extras(tvb
, extras_tree
, extlen
, request
,
1924 &offset
, path_len
, &illegal
);
1926 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_subdoc_doc_flags
,
1927 ett_extras_flags
, subdoc_doc_flags
, ENC_BIG_ENDIAN
);
1932 case CLIENT_OPCODE_SUBDOC_DICT_ADD
:
1933 case CLIENT_OPCODE_SUBDOC_DICT_UPSERT
:
1934 case CLIENT_OPCODE_SUBDOC_DELETE
:
1935 case CLIENT_OPCODE_SUBDOC_REPLACE
:
1936 case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST
:
1937 case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST
:
1938 case CLIENT_OPCODE_SUBDOC_ARRAY_INSERT
:
1939 case CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE
:
1940 case CLIENT_OPCODE_SUBDOC_COUNTER
:
1941 dissect_subdoc_spath_required_extras(tvb
, extras_tree
, extlen
, request
,
1942 &offset
, path_len
, &illegal
);
1944 /* optional expiry only permitted for mutation requests,
1945 if and only if (extlen == 7 || extlen == 8) */
1946 if (extlen
== 7 || extlen
== 8) {
1947 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
,
1951 /* optional doc flags only permitted if and only if
1952 (extlen == 4 || extlen == 8) */
1953 if (extlen
== 4 || extlen
== 8) {
1954 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_subdoc_doc_flags
,
1955 ett_extras_flags
, subdoc_doc_flags
,
1959 if (extlen
!= 3 && extlen
!= 7 && extlen
!= 4 && extlen
!= 8) {
1965 case CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP
:
1968 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_subdoc_doc_flags
,
1969 ett_extras_flags
, subdoc_doc_flags
,
1978 case CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
:
1980 if (extlen
== 4 || extlen
== 5) {
1981 proto_tree_add_item(extras_tree
, hf_extras_expiration
, tvb
, offset
, 4,
1985 if (extlen
== 1 || extlen
== 5) {
1986 proto_tree_add_bitmask(extras_tree
, tvb
, offset
, hf_subdoc_doc_flags
,
1987 ett_extras_flags
, subdoc_doc_flags
, ENC_BIG_ENDIAN
);
1990 if (extlen
!= 1 && extlen
!= 4 && extlen
!= 5) {
1996 case CLIENT_OPCODE_DEL_WITH_META
:
1997 case CLIENT_OPCODE_SET_WITH_META
:
1999 proto_tree_add_item(extras_tree
, hf_meta_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2001 proto_tree_add_item(extras_tree
, hf_meta_expiration
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2003 proto_tree_add_item(extras_tree
, hf_meta_revseqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2005 proto_tree_add_item(extras_tree
, hf_meta_cas
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2008 /*The previous 24 bytes are required. The next two fields are optional,
2009 * hence we are checking the extlen to see what fields we have. As they
2010 * are different lengths we can do this by just checking the length.*/
2012 // Options field (4 bytes)
2013 if (extlen
== 28 || extlen
== 30) {
2014 /* TODO: these fields are all 16 bits wide, but field is 32 bits? */
2015 proto_tree_add_bitmask(
2021 (opcode
== CLIENT_OPCODE_DEL_WITH_META
) ?
2022 del_with_meta_extra_flags
: set_with_meta_extra_flags
,
2026 // Meta Length field (2 bytes)
2027 if (extlen
== 26 || extlen
== 30) {
2028 proto_tree_add_item(extras_tree
, hf_metalen
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2034 case CLIENT_OPCODE_GET_META
:
2037 proto_tree_add_item(extras_tree
, hf_meta_reqextmeta
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2041 proto_tree_add_item(extras_tree
, hf_meta_deleted
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2043 proto_tree_add_item(extras_tree
, hf_meta_flags
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2045 proto_tree_add_item(extras_tree
, hf_exptime
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2047 proto_tree_add_item(extras_tree
, hf_extras_meta_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2050 proto_tree_add_item(extras_tree
, hf_confres
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2055 case CLIENT_OPCODE_COLLECTIONS_GET_ID
:
2057 proto_tree_add_item(extras_tree
, hf_collection_manifest_id
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2059 proto_tree_add_item(extras_tree
, hf_collection_key_id
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2063 case CLIENT_OPCODE_RANGE_SCAN_CONTINUE
:
2064 // https://github.com/couchbase/kv_engine/blob/master/docs/range_scans/range_scan_continue.md
2066 proto_tree_add_item(extras_tree
, hf_range_scan_uuid
, tvb
, offset
, 16, ENC_BIG_ENDIAN
);
2068 proto_tree_add_item(extras_tree
, hf_range_scan_item_limit
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2070 proto_tree_add_item(extras_tree
, hf_range_scan_time_limit
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2072 proto_tree_add_item(extras_tree
, hf_range_scan_byte_limit
, tvb
, offset
, 4, ENC_BIG_ENDIAN
);
2076 case CLIENT_OPCODE_RANGE_SCAN_CANCEL
:
2077 // https://github.com/couchbase/kv_engine/blob/master/docs/range_scans/range_scan_cancel.md
2079 proto_tree_add_item(extras_tree
, hf_range_scan_uuid
, tvb
, offset
, 16, ENC_BIG_ENDIAN
);
2085 /* Decode as unknown extras */
2086 proto_tree_add_item(extras_tree
, hf_extras_unknown
, tvb
, offset
, extlen
, ENC_NA
);
2092 proto_tree_add_expert_format(extras_tree
, pinfo
, &ei_warn_shall_not_have_extras
, tvb
, offset
, 0,
2093 "%s %s should not have extras",
2094 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode 0x%x"),
2095 request
? "Request" : "Response");
2097 } else if (missing
) {
2099 proto_tree_add_expert_format(tree
, pinfo
, &ei_warn_must_have_extras
, tvb
, offset
, 0,
2100 "%s %s must have Extras",
2101 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode Ox%x"),
2102 request
? "Request" : "Response");
2105 if ((offset
- save_offset
) != extlen
) {
2106 expert_add_info_format(pinfo
, extras_item
, &ei_warn_illegal_extras_length
,
2107 "Illegal Extras length, should be %d", offset
- save_offset
);
2112 Decode an unsigned leb128 int from a slice within a tvbuff_t
2113 @param tvb buffer to read from
2114 @param start index of the first byte of 'slice'
2115 @param end index of the last byte of the buffer 'slice'
2116 @param [out] value the decoded value
2117 @returns next byte after the leb128 bytes or -1 if we failed to decode
2120 dissect_unsigned_leb128(tvbuff_t
*tvb
, int start
, int end
, uint32_t* value
) {
2121 uint8_t byte
= tvb_get_uint8(tvb
, start
);
2122 *value
= byte
& 0x7f;
2125 if ((byte
& 0x80) == 0x80) {
2128 for (byte_idx
= start
+1; byte_idx
< end
; byte_idx
++) {
2129 byte
= tvb_get_uint8(tvb
, byte_idx
);
2130 /* Ensure we are using a valid shift */
2133 *value
|= (byte
& 0x7f) << shift
;
2134 if ((byte
& 0x80) == 0) {
2139 return (byte_idx
== end
) ? -1 : byte_idx
+ 1;
2144 static void dissect_server_key(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, int offset
, int keylen
, uint8_t opcode
, bool request
) {
2147 case SERVER_OPCODE_GET_AUTHORIZATION
:
2149 proto_tree_add_expert_format(tree
, pinfo
, &ei_warn_must_have_key
,
2151 "GetAuthorization request must have key");
2154 case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
:
2156 proto_tree_add_expert_format(tree
, pinfo
, &ei_warn_must_have_key
,
2158 "ClustermapChangeNotification request must have key");
2160 case SERVER_OPCODE_AUTHENTICATE
:
2161 case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
:
2162 // Success! none of these commands want a key
2164 // Probably ok as we don't know about the opcode
2169 proto_item
*ti
= proto_tree_add_item(tree
, hf_key
, tvb
, offset
, keylen
, ENC_UTF_8
| ENC_STR_HEX
);
2172 case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
:
2174 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_key
,
2175 "ClustermapChangeNotification response shall not have key");
2179 case SERVER_OPCODE_AUTHENTICATE
:
2180 case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
:
2181 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_key
,
2182 "%s %s shall not have Key",
2183 val_to_str_ext(opcode
,
2184 &server_opcode_vals_ext
,
2186 request
? "Request" : "Response");
2189 case SERVER_OPCODE_GET_AUTHORIZATION
:
2191 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_key
,
2192 "GetAuthorization response shall not have key");
2201 dissect_client_key(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
2202 int offset
, int keylen
, uint8_t opcode
, bool request
)
2204 proto_item
*ti
= NULL
;
2205 bool illegal
= false; /* Set when key shall not be present */
2206 bool missing
= false; /* Set when key is missing */
2209 bool collection_encoded_key
= true;
2211 case CLIENT_OPCODE_STAT
:
2212 case CLIENT_OPCODE_HELLO
:
2213 case CLIENT_OPCODE_SASL_AUTH
:
2214 case CLIENT_OPCODE_SASL_STEP
:
2215 case CLIENT_OPCODE_IOCTL_GET
:
2216 case CLIENT_OPCODE_IOCTL_SET
:
2217 case CLIENT_OPCODE_DCP_CONTROL
:
2218 case CLIENT_OPCODE_SET_PARAM
:
2219 case CLIENT_OPCODE_CREATE_BUCKET
:
2220 case CLIENT_OPCODE_DELETE_BUCKET
:
2221 case CLIENT_OPCODE_SELECT_BUCKET
:
2222 case CLIENT_OPCODE_IFCONFIG
:
2223 collection_encoded_key
= false;
2229 ti
= proto_tree_add_item(tree
, hf_key
, tvb
, offset
, keylen
, ENC_UTF_8
|ENC_STR_HEX
);
2231 if (collection_encoded_key
) {
2232 /* assume collections are enabled and add a field for the CID */
2234 int ok
= dissect_unsigned_leb128(tvb
, offset
, offset
+ keylen
, &cid
);
2236 /* Add collection info to a subtree */
2237 proto_tree
*cid_tree
= proto_item_add_subtree(ti
, ett_collection_key
);
2240 /* cid decode issue, could just be a non-collection stream, don't warn
2241 just add some info */
2242 proto_tree_add_string_format(cid_tree
,
2243 hf_collection_key_logical
,
2248 "Collection ID didn't decode, maybe no CID.");
2250 proto_tree_add_uint(cid_tree
, hf_collection_key_id
, tvb
, offset
,
2251 (ok
- offset
), cid
);
2252 proto_tree_add_item(cid_tree
, hf_collection_key_logical
, tvb
,
2253 ok
, keylen
- (ok
- offset
), ENC_UTF_8
| ENC_STR_HEX
);
2259 /* inSanity check */
2262 case CLIENT_OPCODE_QUIT
:
2263 case CLIENT_OPCODE_QUITQ
:
2264 case CLIENT_OPCODE_NOOP
:
2265 case CLIENT_OPCODE_VERSION
:
2266 case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST
:
2267 case CLIENT_OPCODE_DCP_BUFFER_ACKNOWLEDGEMENT
:
2268 case CLIENT_OPCODE_GET_ALL_VB_SEQNOS
:
2269 /* Request and Response must not have key */
2273 case CLIENT_OPCODE_SET
:
2274 case CLIENT_OPCODE_ADD
:
2275 case CLIENT_OPCODE_REPLACE
:
2276 case CLIENT_OPCODE_DELETE
:
2277 case CLIENT_OPCODE_SETQ
:
2278 case CLIENT_OPCODE_ADDQ
:
2279 case CLIENT_OPCODE_REPLACEQ
:
2280 case CLIENT_OPCODE_DELETEQ
:
2281 case CLIENT_OPCODE_FLUSH
:
2282 case CLIENT_OPCODE_APPEND
:
2283 case CLIENT_OPCODE_PREPEND
:
2284 case CLIENT_OPCODE_FLUSHQ
:
2285 case CLIENT_OPCODE_APPENDQ
:
2286 case CLIENT_OPCODE_PREPENDQ
:
2287 /* Response must not have a key */
2293 case CLIENT_OPCODE_DCP_ADD_STREAM
:
2294 case CLIENT_OPCODE_DCP_CLOSE_STREAM
:
2295 case CLIENT_OPCODE_DCP_STREAM_END
:
2296 case CLIENT_OPCODE_DCP_SNAPSHOT_MARKER
:
2297 case CLIENT_OPCODE_DCP_FLUSH
:
2298 case CLIENT_OPCODE_DCP_SET_VBUCKET_STATE
:
2299 /* Request must not have a key */
2307 case CLIENT_OPCODE_GET
:
2308 case CLIENT_OPCODE_GETQ
:
2309 case CLIENT_OPCODE_GETK
:
2310 case CLIENT_OPCODE_GETKQ
:
2311 case CLIENT_OPCODE_SET
:
2312 case CLIENT_OPCODE_ADD
:
2313 case CLIENT_OPCODE_REPLACE
:
2314 case CLIENT_OPCODE_DELETE
:
2315 case CLIENT_OPCODE_SETQ
:
2316 case CLIENT_OPCODE_ADDQ
:
2317 case CLIENT_OPCODE_REPLACEQ
:
2318 case CLIENT_OPCODE_DELETEQ
:
2319 case CLIENT_OPCODE_INCREMENT
:
2320 case CLIENT_OPCODE_DECREMENT
:
2321 case CLIENT_OPCODE_INCREMENTQ
:
2322 case CLIENT_OPCODE_DECREMENTQ
:
2323 case CLIENT_OPCODE_DCP_OPEN_CONNECTION
:
2324 case CLIENT_OPCODE_DCP_MUTATION
:
2325 case CLIENT_OPCODE_DCP_DELETION
:
2326 case CLIENT_OPCODE_DCP_EXPIRATION
:
2327 case CLIENT_OPCODE_DCP_SYSTEM_EVENT
:
2328 /* Request must have key */
2337 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_key
, "%s %s shall not have Key",
2338 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode 0x%x"),
2339 request
? "Request" : "Response");
2340 } else if (missing
) {
2341 proto_tree_add_expert_format(tree
, pinfo
, &ei_warn_must_have_key
, tvb
, offset
, 0,
2342 "%s %s must have Key",
2343 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode Ox%x"),
2344 request
? "Request" : "Response");
2349 dissect_multipath_lookup_response(tvbuff_t
*tvb
, packet_info
*pinfo
,
2350 proto_tree
*tree
, int offset
, uint32_t value_len
)
2352 int end
= offset
+ value_len
;
2355 while (offset
< end
) {
2357 proto_tree
*multipath_tree
;
2359 uint32_t result_len
;
2360 int start_offset
= offset
;
2362 ti
= proto_tree_add_subtree_format(tree
, tvb
, offset
, -1, ett_multipath
,
2363 &multipath_tree
, "Lookup Result [ %u ]",
2366 proto_tree_add_item(multipath_tree
, hf_status
, tvb
, offset
, 2,
2369 proto_tree_add_item_ret_uint(multipath_tree
, hf_value_length
, tvb
, offset
,
2370 4, ENC_BIG_ENDIAN
, &result_len
);
2373 proto_tree_add_item(multipath_tree
, hf_value
, tvb
, offset
, result_len
,
2374 ENC_ASCII
| ENC_NA
);
2375 if (result_len
> 0) {
2376 json_tvb
= tvb_new_subset_length(tvb
, offset
, result_len
);
2377 call_dissector(json_handle
, json_tvb
, pinfo
, multipath_tree
);
2379 offset
+= result_len
;
2381 proto_item_set_len(ti
, offset
- start_offset
);
2388 dissect_multipath_mutation_response(tvbuff_t
*tvb
, packet_info
*pinfo
,
2389 proto_tree
*tree
, int offset
, uint32_t value_len
)
2391 int end
= offset
+ value_len
;
2394 /* Expect a variable number of mutation responses:
2395 * - If response.status == SUCCESS, zero to N responses, one for each mutation
2396 * spec which returns a value.
2397 * - If response.status != SUCCESS, exactly 1 response, for first failing
2400 while (offset
< end
) {
2402 proto_tree
*multipath_tree
;
2405 int start_offset
= offset
;
2407 ti
= proto_tree_add_subtree_format(tree
, tvb
, offset
, -1, ett_multipath
,
2408 &multipath_tree
, "Mutation Result [ %u ]",
2411 proto_tree_add_item(multipath_tree
, hf_multipath_index
, tvb
, offset
, 1,
2414 proto_tree_add_item_ret_uint(multipath_tree
, hf_status
, tvb
, offset
, 2,
2415 ENC_BIG_ENDIAN
, &status
);
2417 if (status
== STATUS_SUCCESS
) {
2418 uint32_t result_len
;
2419 proto_tree_add_item_ret_uint(multipath_tree
, hf_value_length
, tvb
,
2420 offset
, 4, ENC_BIG_ENDIAN
, &result_len
);
2423 proto_tree_add_item(multipath_tree
, hf_value
, tvb
, offset
, result_len
,
2424 ENC_ASCII
| ENC_NA
);
2425 if (result_len
> 0) {
2426 json_tvb
= tvb_new_subset_length(tvb
, offset
, result_len
);
2427 call_dissector(json_handle
, json_tvb
, pinfo
, multipath_tree
);
2429 offset
+= result_len
;
2431 proto_item_set_len(ti
, offset
- start_offset
);
2438 dissect_multipath_value(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
2439 int offset
, uint32_t value_len
, bool is_mutation
,
2442 int end
= offset
+ value_len
;
2445 proto_tree
*multipath_tree
;
2450 /* Minimum size is the fixed header. */
2451 min_spec_size
= (is_mutation
? 8 : 4);
2453 while (offset
+ min_spec_size
<= end
) {
2455 uint32_t spec_value_len
= 0;
2456 int start_offset
= offset
;
2458 ti
= proto_tree_add_subtree_format(tree
, tvb
, offset
, -1, ett_multipath
,
2460 (is_mutation
? "Mutation spec [ %u ]"
2461 : "Lookup spec [ %u ]"),
2464 proto_tree_add_item(multipath_tree
, hf_multipath_opcode
, tvb
, offset
, 1,
2467 proto_tree_add_bitmask(multipath_tree
, tvb
, offset
, hf_subdoc_flags
,
2468 ett_extras_flags
, subdoc_flags
, ENC_BIG_ENDIAN
);
2471 proto_tree_add_item_ret_uint(multipath_tree
, hf_multipath_pathlen
, tvb
,
2472 offset
, 2, ENC_BIG_ENDIAN
, &path_len
);
2476 proto_tree_add_item_ret_uint(multipath_tree
, hf_multipath_valuelen
,
2477 tvb
, offset
, 4, ENC_BIG_ENDIAN
,
2483 proto_tree_add_item(multipath_tree
, hf_multipath_path
, tvb
, offset
, path_len
,
2484 ENC_ASCII
| ENC_NA
);
2488 if (spec_value_len
> 0) {
2489 proto_tree_add_item(multipath_tree
, hf_multipath_value
, tvb
, offset
,
2490 spec_value_len
, ENC_ASCII
| ENC_NA
);
2491 offset
+= spec_value_len
;
2494 proto_item_set_len(ti
, offset
- start_offset
);
2500 dissect_multipath_mutation_response(tvb
, pinfo
, tree
, offset
, value_len
);
2502 dissect_multipath_lookup_response(tvb
, pinfo
, tree
, offset
, value_len
);
2508 dissect_value(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
2509 int offset
, uint32_t value_len
, uint16_t path_len
, uint8_t opcode
,
2510 bool request
, uint8_t datatype
)
2512 proto_item
*ti
= NULL
;
2513 bool illegal
= false; /* Set when value shall not be present */
2514 bool missing
= false; /* Set when value is missing */
2516 if (value_len
> 0) {
2517 if (opcode
== CLIENT_OPCODE_OBSERVE
) {
2518 proto_tree
*observe_tree
;
2519 int oo
= offset
, end
= offset
+ value_len
;
2520 ti
= proto_tree_add_item(tree
, hf_observe
, tvb
, offset
, value_len
, ENC_ASCII
);
2521 observe_tree
= proto_item_add_subtree(ti
, ett_observe
);
2523 uint16_t kl
; /* keylength */
2524 proto_tree_add_item(observe_tree
, hf_observe_vbucket
, tvb
, oo
, 2, ENC_BIG_ENDIAN
);
2526 kl
= tvb_get_ntohs(tvb
, oo
);
2527 proto_tree_add_item(observe_tree
, hf_observe_keylength
, tvb
, oo
, 2, ENC_BIG_ENDIAN
);
2529 proto_tree_add_item(observe_tree
, hf_observe_key
, tvb
, oo
, kl
, ENC_ASCII
);
2532 proto_tree_add_item(observe_tree
, hf_observe_status
, tvb
, oo
, 1, ENC_BIG_ENDIAN
);
2534 proto_tree_add_item(observe_tree
, hf_observe_cas
, tvb
, oo
, 8, ENC_BIG_ENDIAN
);
2538 } else if (opcode
== CLIENT_OPCODE_OBSERVE_SEQNO
) {
2540 ti
= proto_tree_add_item(tree
, hf_observe_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2541 if (value_len
!= 8) {
2542 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be 8");
2546 * <format_type, vbucket id, vbucket uuid, last_persisted_seqno, current_seqno>
2548 * - format_type is of type uint8_t and it describes whether
2549 * the vbucket has failed over or not. 1 indicates a hard
2550 * failover, 0 indicates otherwise.
2551 * - vbucket id is of type uint16_t and it is the identifier for
2553 * - vbucket uuid is of type uint64_t and it represents a UUID for
2555 * - last_persisted_seqno is of type uint64_t and it is the
2556 * last sequence number that was persisted for this
2558 * - current_seqno is of the type uint64_t and it is the
2559 * sequence number of the latest mutation in the vbucket.
2561 * In the case of a hard failover, the tuple is of the form
2562 * <format_type, vbucket id, vbucket uuid, last_persisted_seqno, current_seqno,
2563 * old vbucket uuid, last_received_seqno>
2565 * - old vbucket uuid is of type uint64_t and it is the
2566 * vbucket UUID of the vbucket prior to the hard failover.
2568 * - last_received_seqno is of type uint64_t and it is the
2569 * last received sequence number in the old vbucket uuid.
2571 * The other fields are the same as that mentioned in the normal case.
2573 uint8_t failed_over
;
2575 proto_tree_add_item(tree
, hf_observe_failed_over
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2576 failed_over
= tvb_get_uint8(tvb
, offset
);
2578 proto_tree_add_item(tree
, hf_observe_vbucket
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
2580 proto_tree_add_item(tree
, hf_observe_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2582 proto_tree_add_item(tree
, hf_observe_last_persisted_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2584 proto_tree_add_item(tree
, hf_observe_current_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2587 proto_tree_add_item(tree
, hf_observe_old_vbucket_uuid
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2589 proto_tree_add_item(tree
, hf_observe_last_received_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2592 } else if (!request
&& (opcode
== CLIENT_OPCODE_DCP_STREAM_REQUEST
|| opcode
== CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST
)) {
2593 if (value_len
% 16 != 0) {
2594 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Response with bad failover log length");
2596 proto_tree
*failover_log_tree
;
2597 int cur
= offset
, end
= offset
+ value_len
;
2598 ti
= proto_tree_add_item(tree
, hf_failover_log
, tvb
, offset
, value_len
, ENC_ASCII
);
2599 failover_log_tree
= proto_item_add_subtree(ti
, ett_failover_log
);
2600 ti
= proto_tree_add_uint(failover_log_tree
, hf_failover_log_size
, tvb
, offset
, 0, (end
- cur
) / 16);
2601 proto_item_set_generated(ti
);
2603 proto_tree_add_item(failover_log_tree
, hf_failover_log_vbucket_uuid
, tvb
, cur
, 8, ENC_BIG_ENDIAN
);
2605 proto_tree_add_item(failover_log_tree
, hf_failover_log_vbucket_seqno
, tvb
, cur
, 8, ENC_BIG_ENDIAN
);
2609 } else if (!request
&& opcode
== CLIENT_OPCODE_GET_ALL_VB_SEQNOS
) {
2610 if (value_len
% 10 != 0) {
2611 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Response with bad body length");
2613 proto_tree
*vbucket_states_tree
;
2614 int cur
= offset
, end
= offset
+ value_len
;
2615 ti
= proto_tree_add_item(tree
, hf_vbucket_states
, tvb
, offset
, value_len
, ENC_ASCII
);
2616 vbucket_states_tree
= proto_item_add_subtree(ti
, ett_vbucket_states
);
2617 ti
= proto_tree_add_uint(vbucket_states_tree
, hf_vbucket_states_size
, tvb
, offset
, 0, (end
- cur
) / 10);
2618 proto_item_set_generated(ti
);
2620 proto_tree_add_item(vbucket_states_tree
, hf_vbucket_states_id
, tvb
, cur
, 2, ENC_BIG_ENDIAN
);
2622 proto_tree_add_item(vbucket_states_tree
, hf_vbucket_states_seqno
, tvb
, cur
, 8, ENC_BIG_ENDIAN
);
2626 } else if (!request
&& (opcode
== CLIENT_OPCODE_INCREMENT
|| opcode
== CLIENT_OPCODE_DECREMENT
)) {
2627 ti
= proto_tree_add_item(tree
, hf_uint64_response
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2628 if (value_len
!= 8) {
2629 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be 8");
2631 } else if (has_json_value(request
, opcode
)) {
2633 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2634 json_tvb
= tvb_new_subset_length(tvb
, offset
, value_len
);
2635 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
2637 } else if (opcode
== CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP
||
2638 opcode
== CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
) {
2639 dissect_multipath_value(tvb
, pinfo
, tree
, offset
, value_len
,
2640 (opcode
== CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
),
2643 } else if (opcode
== CLIENT_OPCODE_HELLO
) {
2644 int curr
= offset
, end
= offset
+ value_len
;
2645 proto_tree
*hello_features_tree
;
2646 ti
= proto_tree_add_item(tree
, hf_hello_features
, tvb
, offset
, value_len
, ENC_ASCII
);
2647 hello_features_tree
= proto_item_add_subtree(ti
, ett_hello_features
);
2648 while (curr
< end
) {
2649 proto_tree_add_item(hello_features_tree
, hf_hello_features_feature
, tvb
, curr
, 2, ENC_BIG_ENDIAN
);
2652 } else if (!request
&& opcode
== CLIENT_OPCODE_RANGE_SCAN_CREATE
) {
2653 proto_tree_add_item(tree
, hf_range_scan_uuid
, tvb
, offset
, 16, ENC_BIG_ENDIAN
);
2654 } else if (path_len
!= 0) {
2655 ti
= proto_tree_add_item(tree
, hf_path
, tvb
, offset
, path_len
, ENC_ASCII
| ENC_NA
);
2656 value_len
-= path_len
;
2657 if (value_len
> 0) {
2658 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
+ path_len
,
2659 value_len
, ENC_ASCII
| ENC_NA
);
2661 } else if (request
&& opcode
== CLIENT_OPCODE_CREATE_BUCKET
) {
2662 int sep
, equals_pos
, sep_pos
, config_len
;
2663 proto_tree
*key_tree
, *config_tree
= NULL
;
2665 /* There are 2 main items stored in the value. The bucket type (represented by a path to the engine) and the
2666 * bucket config. These are separated by a NULL byte with the bucket type coming first.*/
2668 sep
= tvb_find_uint8(tvb
, offset
, value_len
, 0x00);
2670 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
);
2671 expert_add_info_format(pinfo
, ti
, &ei_separator_not_found
, "Null byte not found");
2673 proto_tree_add_item(tree
, hf_bucket_type
, tvb
, offset
, sep
- offset
, ENC_ASCII
| ENC_NA
);
2674 config_len
= value_len
- (sep
- offset
) - 1; //Don't include NULL byte in length
2675 if(config_len
<= 0) {
2676 expert_add_info_format(pinfo
, ti
, &ei_separator_not_found
, "Separator not found in expected location");
2678 offset
= sep
+ 1;// Ignore NULL byte
2680 ti
= proto_tree_add_item(tree
, hf_bucket_config
, tvb
, offset
, config_len
, ENC_ASCII
| ENC_NA
);
2681 config_tree
= proto_item_add_subtree(ti
, ett_config
);
2684 /* The config is arranged as "key=value;key=value..."*/
2685 while (config_len
> 0) {
2687 equals_pos
= tvb_find_uint8(tvb
, offset
, config_len
, 0x3d);
2688 if (equals_pos
== -1) {
2689 expert_add_info_format(pinfo
, ti
, &ei_illegal_value
, "Each key needs a value");
2690 break; // Break out the while loop
2692 ti
= proto_tree_add_item(config_tree
, hf_config_key
, tvb
, offset
, equals_pos
- offset
, ENC_ASCII
| ENC_NA
);
2693 key_tree
= proto_item_add_subtree(ti
, ett_config_key
);
2694 config_len
-= (equals_pos
- offset
+ 1);
2695 offset
= equals_pos
+ 1;
2696 if (config_len
<= 0) {
2697 expert_add_info_format(pinfo
, ti
, &ei_illegal_value
, "Corresponding value missing");
2698 break;//Break out of while loop
2702 sep_pos
= tvb_find_uint8(tvb
, offset
, config_len
, 0x3b);
2703 if (sep_pos
== -1) {
2704 expert_add_info_format(pinfo
, ti
, &ei_separator_not_found
, "Each key-value pair must be terminated by semi-colon");
2705 break; // Break out the while loop
2707 proto_tree_add_item(key_tree
, hf_config_value
, tvb
, offset
, sep_pos
- offset
, ENC_ASCII
| ENC_NA
);
2708 config_len
-= (sep_pos
- offset
+ 1);
2709 offset
= sep_pos
+ 1;
2712 } else if ((datatype
& DT_XATTR
) && (opcode
== CLIENT_OPCODE_SET_WITH_META
||
2713 opcode
== CLIENT_OPCODE_DCP_MUTATION
|| opcode
== CLIENT_OPCODE_DCP_DELETION
||
2714 opcode
== CLIENT_OPCODE_DCP_EXPIRATION
|| opcode
== CLIENT_OPCODE_DCP_PREPARE
||
2715 opcode
== CLIENT_OPCODE_DEL_WITH_META
|| opcode
== CLIENT_OPCODE_ADD_WITH_META
||
2716 opcode
== CLIENT_OPCODE_SETQ_WITH_META
|| opcode
== CLIENT_OPCODE_DELQ_WITH_META
||
2717 opcode
== CLIENT_OPCODE_ADDQ_WITH_META
)) {
2719 dissect_dcp_xattrs(tvb
, tree
, value_len
, offset
, pinfo
);
2720 } else if (request
&& opcode
== CLIENT_OPCODE_GET_ERROR_MAP
) {
2721 if (value_len
!= 2) {
2722 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be 2");
2723 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2725 ti
= proto_tree_add_item(tree
, hf_get_errmap_version
, tvb
, offset
, value_len
, ENC_BIG_ENDIAN
);
2727 } else if (request
&& opcode
== CLIENT_OPCODE_DCP_SNAPSHOT_MARKER
) {
2728 if (value_len
< 20) {
2729 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be at least 20");
2730 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2733 proto_tree_add_item(tree
, hf_extras_start_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2735 proto_tree_add_item(tree
, hf_extras_end_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2737 proto_tree_add_bitmask(tree
, tvb
, offset
, hf_extras_flags
, ett_extras_flags
, snapshot_marker_flags
, ENC_BIG_ENDIAN
);
2740 if (value_len
> 20) {
2741 if (value_len
< 36) {
2742 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be at least 36");
2743 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2746 proto_tree_add_item(tree
, hf_extras_max_visible_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2748 proto_tree_add_item(tree
, hf_extras_high_completed_seqno
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2751 if (value_len
> 36) {
2752 if (value_len
!= 44) {
2753 expert_add_info_format(pinfo
, ti
, &ei_warn_illegal_value_length
, "Illegal Value length, should be 44");
2754 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2757 proto_tree_add_item(tree
, hf_extras_timestamp
, tvb
, offset
, 8, ENC_BIG_ENDIAN
);
2761 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, value_len
, ENC_ASCII
| ENC_NA
);
2763 if (datatype
& DT_SNAPPY
) {
2764 tvbuff_t
* decompressed_tvb
= tvb_child_uncompress_snappy(tvb
, tvb
, offset
, tvb_captured_length_remaining(tvb
, offset
));
2765 if (decompressed_tvb
!= NULL
) {
2766 add_new_data_source(pinfo
, decompressed_tvb
, "Decompressed Data");
2767 if (datatype
& DT_JSON
) {
2768 call_dissector(json_handle
, decompressed_tvb
, pinfo
, tree
);
2771 expert_add_info_format(pinfo
, ti
, &ei_compression_error
, "Error uncompressing snappy data");
2781 case CLIENT_OPCODE_GET
:
2782 case CLIENT_OPCODE_GETQ
:
2783 case CLIENT_OPCODE_GETK
:
2784 case CLIENT_OPCODE_GETKQ
:
2785 case CLIENT_OPCODE_INCREMENT
:
2786 case CLIENT_OPCODE_DECREMENT
:
2787 case CLIENT_OPCODE_VERSION
:
2788 case CLIENT_OPCODE_INCREMENTQ
:
2789 case CLIENT_OPCODE_DECREMENTQ
:
2790 case CLIENT_OPCODE_DCP_OPEN_CONNECTION
:
2791 case CLIENT_OPCODE_DCP_ADD_STREAM
:
2792 case CLIENT_OPCODE_DCP_CLOSE_STREAM
:
2793 case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST
:
2794 case CLIENT_OPCODE_DCP_STREAM_END
:
2795 case CLIENT_OPCODE_DCP_DELETION
:
2796 case CLIENT_OPCODE_DCP_EXPIRATION
:
2797 case CLIENT_OPCODE_DCP_FLUSH
:
2798 case CLIENT_OPCODE_DCP_SET_VBUCKET_STATE
:
2799 /* Request must not have value */
2804 case CLIENT_OPCODE_DELETE
:
2805 case CLIENT_OPCODE_QUIT
:
2806 case CLIENT_OPCODE_FLUSH
:
2807 case CLIENT_OPCODE_NOOP
:
2808 case CLIENT_OPCODE_DELETEQ
:
2809 case CLIENT_OPCODE_QUITQ
:
2810 case CLIENT_OPCODE_FLUSHQ
:
2811 /* Request and Response must not have value */
2814 case CLIENT_OPCODE_SET
:
2815 case CLIENT_OPCODE_ADD
:
2816 case CLIENT_OPCODE_REPLACE
:
2817 case CLIENT_OPCODE_SETQ
:
2818 case CLIENT_OPCODE_ADDQ
:
2819 case CLIENT_OPCODE_REPLACEQ
:
2820 case CLIENT_OPCODE_APPEND
:
2821 case CLIENT_OPCODE_PREPEND
:
2822 case CLIENT_OPCODE_APPENDQ
:
2823 case CLIENT_OPCODE_PREPENDQ
:
2824 /* Response must not have value */
2832 case CLIENT_OPCODE_DCP_FAILOVER_LOG_REQUEST
:
2833 /* Successful response must have value */
2842 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_value
, "%s %s shall not have Value",
2843 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode 0x%x"),
2844 request
? "Request" : "Response");
2845 } else if (missing
) {
2846 expert_add_info_format(pinfo
, ti
, &ei_value_missing
, "%s %s must have Value",
2847 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Opcode 0x%x"),
2848 request
? "Request" : "Response");
2852 static void flex_frame_duration_dissect(tvbuff_t
* tvb
,
2853 proto_tree
* frame_tree
,
2858 proto_tree_add_expert_format(frame_tree
,
2860 &ei_warn_unknown_flex_len
,
2864 "FlexFrame: RX/TX Duration with illegal length %d", length
);
2866 uint16_t encoded_micros
= tvb_get_ntohs(tvb
, offset
);
2867 proto_tree_add_double(frame_tree
,
2868 hf_flex_frame_tracing_duration
,
2872 pow(encoded_micros
, 1.74) / 2);
2876 static void flex_frame_ru_usage_dissect(tvbuff_t
* tvb
,
2877 proto_tree
* frame_tree
,
2882 proto_tree_add_expert_format(frame_tree
,
2884 &ei_warn_unknown_flex_len
,
2888 "Read unit illegal length %d", length
);
2890 uint16_t units
= tvb_get_ntohs(tvb
, offset
);
2891 proto_tree_add_uint(frame_tree
, hf_flex_frame_ru_count
, tvb
, offset
, 2, units
);
2895 static void flex_frame_wu_usage_dissect(tvbuff_t
* tvb
,
2896 proto_tree
* frame_tree
,
2901 proto_tree_add_expert_format(frame_tree
,
2903 &ei_warn_unknown_flex_len
,
2907 "Write unit illegal length %d", length
);
2909 uint16_t units
= tvb_get_ntohs(tvb
, offset
);
2910 proto_tree_add_uint(frame_tree
, hf_flex_frame_wu_count
, tvb
, offset
, 2, units
);
2914 static void flex_frame_reorder_dissect(tvbuff_t
* tvb
,
2915 proto_tree
* frame_tree
,
2918 /* Expects no data, so just check len */
2920 proto_tree_add_expert_format(frame_tree
,
2922 &ei_warn_unknown_flex_len
,
2926 "FlexFrame: Out Of Order with illegal length %d", length
);
2930 static void flex_frame_durability_dissect(tvbuff_t
* tvb
,
2931 proto_tree
* frame_tree
,
2934 if (!(length
== 1 || length
== 3)) {
2935 proto_tree_add_expert_format(frame_tree
,
2937 &ei_warn_unknown_flex_len
,
2941 "FlexFrame: Durability with illegal length %d", length
);
2944 proto_tree_add_item(frame_tree
, hf_flex_frame_durability_req
, tvb
, offset
, 1, ENC_BIG_ENDIAN
);
2947 static void flex_frame_dcp_stream_id_dissect(tvbuff_t
* tvb
,
2948 proto_tree
* frame_tree
,
2952 proto_tree_add_expert_format(frame_tree
,
2954 &ei_warn_unknown_flex_len
,
2958 "FlexFrame: DCP Stream ID with illegal length %d", length
);
2960 uint16_t sid
= tvb_get_ntohs(tvb
, offset
);
2961 proto_tree_add_uint(frame_tree
, hf_flex_frame_dcp_stream_id
, tvb
, offset
, 2, sid
);
2965 static void flex_frame_impersonate_dissect(tvbuff_t
* tvb
,
2966 proto_tree
* frame_tree
,
2969 proto_tree_add_item(frame_tree
,
2970 hf_flex_frame_impersonated_user
,
2974 ENC_UTF_8
|ENC_STR_HEX
);
2977 static void flex_frame_preserve_ttl(tvbuff_t
* tvb
,
2978 proto_tree
* frame_tree
,
2981 /* Expects no data, so just check len */
2983 proto_tree_add_expert_format(frame_tree
,
2985 &ei_warn_unknown_flex_len
,
2989 "FlexFrame: Preserve TTL with illegal length %d", length
);
2993 typedef void (*flex_frame_by_id_dissect_fn
)(tvbuff_t
*,
2998 struct flex_frame_by_id_dissect
{
3000 flex_frame_by_id_dissect_fn handler
;
3003 static const struct flex_frame_by_id_dissect flex_frame_response_dissect
[] = {
3004 {FLEX_RESPONSE_ID_RX_TX_DURATION
, &flex_frame_duration_dissect
},
3005 {FLEX_RESPONSE_ID_RU_USAGE
, &flex_frame_ru_usage_dissect
},
3006 {FLEX_RESPONSE_ID_WU_USAGE
, &flex_frame_wu_usage_dissect
},
3010 static const struct flex_frame_by_id_dissect flex_frame_request_dissect
[] = {
3011 { FLEX_REQUEST_ID_REORDER
, &flex_frame_reorder_dissect
},
3012 { FLEX_REQUEST_ID_DURABILITY
, &flex_frame_durability_dissect
},
3013 { FLEX_REQUEST_ID_DCP_STREAM_ID
, &flex_frame_dcp_stream_id_dissect
},
3014 { FLEX_REQUEST_ID_IMPERSONATE
, &flex_frame_impersonate_dissect
},
3015 { FLEX_REQUEST_ID_PRESERVE_TTL
, &flex_frame_preserve_ttl
},
3020 Flexible Framing Extras:
3021 https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md
3023 static void dissect_flexible_framing_extras(tvbuff_t
* tvb
,
3027 uint8_t flex_frame_extra_len
,
3030 /* select some request/response ID decoders */
3031 const struct flex_frame_by_id_dissect
* id_dissectors
= flex_frame_response_dissect
;
3032 int info_id
= hf_flex_frame_id_res
;
3033 int info_id_esc
= hf_flex_frame_id_res_esc
;
3034 int info_len_id
= hf_flex_frame_len
;
3036 id_dissectors
= flex_frame_request_dissect
;
3037 info_id
= hf_flex_frame_id_req
;
3038 info_id_esc
= hf_flex_frame_id_req_esc
;
3041 /* This first item shows the entire extent of all frame extras.
3042 If we have multiple frames, we will add them in the iteration */
3043 proto_tree_add_uint(tree
,
3047 flex_frame_extra_len
,
3048 flex_frame_extra_len
);
3050 /* iterate until we've consumed the flex_frame_extra_len */
3051 int bytes_remaining
= flex_frame_extra_len
;
3052 int frame_index
= 0;
3054 while (bytes_remaining
> 0) {
3056 /* FrameInfo starts with a 'tag' byte which is formed from 2 nibbles */
3057 uint8_t tag_byte
= tvb_get_uint8(tvb
, offset
);
3059 /* 0xff isn't defined yet in the spec as to what it should do */
3060 if (tag_byte
== 0xFF) {
3061 proto_tree_add_expert_format(tree
,
3063 &ei_warn_unknown_flex_unsupported
,
3067 "Cannot decode 0xFF id/len byte");
3071 /* extract the nibbles into u16, if the id/len nibbles are escapes, their
3072 true values come from following bytes and can be larger than u8 */
3073 uint16_t id
= tag_byte
>> 4;
3074 uint16_t len
= tag_byte
& 0x0F;
3077 /* Calculate the id/len and add to the tree */
3078 if (id
== FLEX_ESCAPE
) {
3079 id
= id
+ tvb_get_uint8(tvb
, offset
+ 1);
3081 info_id
= info_id_esc
;
3085 if (len
== FLEX_ESCAPE
) {
3086 len
= len
+ tvb_get_uint8(tvb
, offset
+ 1);
3088 info_len_id
= hf_flex_frame_len_esc
;
3091 /* add a new sub-tree for this FrameInfo */
3092 proto_item
* flex_item
= proto_tree_add_string_format(tree
,
3098 "Flexible Frame %d",
3101 proto_tree
* frame_tree
= proto_item_add_subtree(flex_item
,
3102 ett_flex_frame_extras
);
3104 /* Now add the info under the sub-tree */
3105 proto_tree_add_uint(frame_tree
, info_id
, tvb
, offset
, id_size
, id
);
3106 proto_tree_add_uint(frame_tree
, info_len_id
, tvb
, offset
, len_size
, len
);
3108 /* this is broken if both len and id are escaped, but we've returned earlier
3109 for that case (with a warning) */
3110 offset
= offset
+ 1 + (len_size
- 1) + (id_size
- 1);
3111 bytes_remaining
= bytes_remaining
- 1 - (len_size
- 1) - (id_size
- 1);
3113 /* lookup a dissector function by id */
3114 int id_index
= 0, found
= 0;
3115 while (id_dissectors
[id_index
].handler
) {
3116 if (id_dissectors
[id_index
].id
== id
) {
3117 id_dissectors
[id_index
].handler(tvb
, frame_tree
, offset
, len
);
3125 proto_tree_add_expert_format(frame_tree
,
3127 &ei_warn_unknown_flex_id
,
3131 "FlexFrame: no dissector function for %d", id
);
3135 bytes_remaining
-= len
;
3141 is_xerror(uint8_t datatype
, uint16_t status
)
3143 if ((datatype
& DT_JSON
) && status
!= STATUS_SUBDOC_MULTI_PATH_FAILURE
) {
3149 /// The following section contains dissector functions for the various
3150 /// server initiated push messages (and responses for them).
3151 /// It's easier to understand the logic with a single function per opcode
3152 /// than a long function with a ton of if/else statements
3154 static void d_s_o_clustermap_change_notification_req(tvbuff_t
*tvb
,
3160 // this is an error!
3161 expert_add_info_format(pinfo
, tree
, &ei_warn_illegal_value_length
,
3162 "Clustermap not present");
3165 // The payload is the clustermap in JSON
3166 proto_tree_add_item(tree
, hf_server_clustermap_value
, tvb
, offset
, size
,
3167 ENC_ASCII
| ENC_NA
);
3168 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3169 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3172 static void d_s_o_authenticate_req(tvbuff_t
*tvb
,
3178 // this is an error!
3179 expert_add_info_format(pinfo
, tree
, &ei_warn_illegal_value_length
,
3180 "Authentication payload not present");
3183 // The payload is an JSON object with the authentication request
3184 proto_tree_add_item(tree
, hf_server_authentication
, tvb
, offset
, size
,
3185 ENC_ASCII
| ENC_NA
);
3186 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3187 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3190 static void d_s_o_active_external_users_req(tvbuff_t
*tvb
,
3196 // this is an error!
3197 expert_add_info_format(pinfo
, tree
, &ei_warn_illegal_value_length
,
3198 "ActiveExternalUsers payload not present");
3201 // The payload is an JSON array with the list of the users
3202 proto_tree_add_item(tree
, hf_server_external_users
, tvb
, offset
, size
,
3203 ENC_ASCII
| ENC_NA
);
3204 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3205 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3208 static void d_s_o_get_authorization_req(tvbuff_t
*tvb
,
3214 // this is an error!
3215 proto_item
*ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, size
,
3216 ENC_ASCII
| ENC_NA
);
3217 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_value
,
3218 "GetAuthorization shall not have a value");
3222 /// Dissect the response to a server initiated push message which
3223 /// don't require a response (the client may send it, but the server
3224 /// will silently just ignore the response).
3225 /// If sent the body should not contain value unless the status code
3226 /// is an error and if so it shall be a JSON payload following the
3227 /// standard error format.
3228 static void d_s_o_server_ignored_response(tvbuff_t
*tvb
,
3236 proto_item
*ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, size
,
3237 ENC_ASCII
| ENC_NA
);
3238 if (get_status(tvb
) == STATUS_SUCCESS
) {
3239 expert_add_info_format(pinfo
, ti
, &ei_warn_shall_not_have_value
,
3240 "Success should not carry value");
3242 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3243 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3247 static void d_s_o_authenticate_res(tvbuff_t
*tvb
,
3248 packet_info
*pinfo
,
3256 // Payload is JSON (for success and if there is an error)
3257 proto_tree_add_item(tree
, hf_server_authentication
, tvb
, offset
, size
,
3258 ENC_ASCII
| ENC_NA
);
3259 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3260 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3263 static void d_s_o_get_authorization_res(tvbuff_t
*tvb
,
3272 // Payload is JSON (for success and if there is an error)
3273 proto_tree_add_item(tree
, hf_server_get_authorization
, tvb
, offset
, size
,
3274 ENC_ASCII
| ENC_NA
);
3275 tvbuff_t
*json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3276 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3281 * Does the opcode use the vbucket or not? (does it make any sense to
3282 * add the vbucket to the info)
3284 static bool opcode_use_vbucket(uint8_t magic _U_
, uint8_t opcode
) {
3286 case CLIENT_OPCODE_OBSERVE
:
3287 case CLIENT_OPCODE_COLLECTIONS_GET_ID
:
3288 case CLIENT_OPCODE_IFCONFIG
:
3289 case CLIENT_OPCODE_SASL_LIST_MECHS
:
3290 case CLIENT_OPCODE_SASL_AUTH
:
3291 case CLIENT_OPCODE_SASL_STEP
:
3292 case CLIENT_OPCODE_SHUTDOWN
:
3293 case CLIENT_OPCODE_AUDIT_CONFIG_RELOAD
:
3294 case CLIENT_OPCODE_AUDIT_PUT
:
3295 case CLIENT_OPCODE_CONFIG_RELOAD
:
3296 case CLIENT_OPCODE_CONFIG_VALIDATE
:
3297 case CLIENT_OPCODE_IOCTL_SET
:
3298 case CLIENT_OPCODE_IOCTL_GET
:
3299 case CLIENT_OPCODE_HELLO
:
3300 case CLIENT_OPCODE_VERBOSITY
:
3301 case CLIENT_OPCODE_VERSION
:
3302 case CLIENT_OPCODE_NOOP
:
3303 case CLIENT_OPCODE_QUIT
:
3304 case CLIENT_OPCODE_LIST_BUCKETS
:
3305 case CLIENT_OPCODE_CREATE_BUCKET
:
3306 case CLIENT_OPCODE_DELETE_BUCKET
:
3307 case CLIENT_OPCODE_SELECT_BUCKET
:
3316 * Each frame header consist of 24 bytes in two slightly different formats
3317 * (byte 6 and 7 is vbucket id in a request and status in a response).
3319 * This method dissect the frame header. Please refer to
3320 * https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#request-header
3321 * for the layout of the frame header.
3323 static void dissect_frame_header(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*couchbase_tree
, proto_item
*couchbase_item
) {
3324 uint8_t magic
= get_magic(tvb
);
3325 proto_item
*ti
= proto_tree_add_item(couchbase_tree
, hf_magic
, tvb
, 0, 1, ENC_BIG_ENDIAN
);
3326 if (try_val_to_str(magic
, magic_vals
) == NULL
) {
3327 expert_add_info_format(pinfo
, ti
, &ei_warn_unknown_magic_byte
, "Unknown magic byte: 0x%x", magic
);
3330 uint8_t opcode
= get_opcode(tvb
);
3332 const char *opcode_name
;
3333 if (is_server_magic(magic
)) {
3334 ti
= proto_tree_add_item(couchbase_tree
, hf_server_opcode
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
3335 opcode_name
= try_val_to_str_ext(opcode
, &server_opcode_vals_ext
);
3337 ti
= proto_tree_add_item(couchbase_tree
, hf_opcode
, tvb
, 1, 1, ENC_BIG_ENDIAN
);
3338 opcode_name
= try_val_to_str_ext(opcode
, &client_opcode_vals_ext
);
3341 if (opcode_name
== NULL
) {
3342 expert_add_info_format(pinfo
, ti
, &ei_warn_unknown_opcode
, "Unknown opcode: 0x%x", opcode
);
3343 opcode_name
= "Unknown opcode";
3345 proto_item_append_text(couchbase_item
, ", %s %s, Opcode: 0x%x",
3347 val_to_str(magic
, magic_vals
, "Unknown magic (0x%x)"),
3349 col_append_fstr(pinfo
->cinfo
, COL_INFO
, "%s %s, Opcode: 0x%x",
3351 val_to_str(magic
, magic_vals
, "Unknown magic (0x%x)"),
3354 /* Check for flex magic, which changes the header format */
3356 uint8_t flex_frame_extras
= get_flex_framing_extras_length(tvb
);
3357 if (is_flex_encoded(magic
)) {
3358 /* 2 separate bytes for the flex_extras and keylen */
3359 proto_tree_add_item(couchbase_tree
, hf_flex_extras_length
, tvb
, 2, 1, ENC_BIG_ENDIAN
);
3360 proto_tree_add_item(couchbase_tree
, hf_flex_keylength
, tvb
, 3, 1, ENC_BIG_ENDIAN
);
3362 /* 2 bytes for the key */
3363 proto_tree_add_item(couchbase_tree
, hf_keylength
, tvb
, 2, 2, ENC_BIG_ENDIAN
);
3365 keylen
= get_key_length(tvb
);
3367 uint8_t extlen
= get_extras_length(tvb
);
3368 proto_tree_add_item(couchbase_tree
, hf_extlength
, tvb
, 4, 1, ENC_BIG_ENDIAN
);
3370 proto_tree_add_bitmask(couchbase_tree
, tvb
, 5, hf_datatype
, ett_datatype
, datatype_vals
, ENC_BIG_ENDIAN
);
3372 if (is_request_magic(magic
)) {
3373 uint16_t vbucket
= tvb_get_ntohs(tvb
, 6);
3374 proto_tree_add_item(couchbase_tree
, hf_vbucket
, tvb
, 6, 2, ENC_BIG_ENDIAN
);
3375 if (opcode_use_vbucket(magic
, opcode
)) {
3376 proto_item_append_text(couchbase_item
, ", vb:%d", vbucket
);
3377 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", vb:%d", vbucket
);
3380 /* This is a response or invalid magic... */
3381 uint16_t status
= get_status(tvb
);
3382 ti
= proto_tree_add_item(couchbase_tree
, hf_status
, tvb
, 6, 2, ENC_BIG_ENDIAN
);
3384 expert_add_info_format(pinfo
, ti
, &ei_warn_unknown_opcode
, "%s: %s",
3385 val_to_str_ext(opcode
, &client_opcode_vals_ext
, "Unknown opcode (0x%x)"),
3386 val_to_str_ext(status
, &status_vals_ext
, "Status: 0x%x"));
3390 uint32_t bodylen
= get_body_length(tvb
);
3391 uint32_t value_len
= bodylen
- extlen
- keylen
- flex_frame_extras
;
3392 ti
= proto_tree_add_uint(couchbase_tree
, hf_value_length
, tvb
, 8, 0, value_len
);
3393 proto_item_set_generated(ti
);
3395 proto_tree_add_item(couchbase_tree
, hf_total_bodylength
, tvb
, 8, 4, ENC_BIG_ENDIAN
);
3398 * use little endian (network) encoding for the opaque as this is an opaque
3399 * field the client could use for whatever they want
3401 proto_tree_add_item(couchbase_tree
, hf_opaque
, tvb
, 12, 4, ENC_LITTLE_ENDIAN
);
3403 // Finally we've got the CAS (which observe has a special use for)
3404 if (opcode
== CLIENT_OPCODE_OBSERVE
) {
3405 proto_tree_add_item(couchbase_tree
, hf_ttp
, tvb
, 16, 4, ENC_BIG_ENDIAN
);
3406 proto_tree_add_item(couchbase_tree
, hf_ttr
, tvb
, 20, 4, ENC_BIG_ENDIAN
);
3408 proto_tree_add_item(couchbase_tree
, hf_cas
, tvb
, 16, 8, ENC_BIG_ENDIAN
);
3413 * Dissect the flexible frame info's encoded in the packet
3415 static void dissect_frame_flex_info_section(tvbuff_t
*tvb
,
3426 case MAGIC_SERVER_RESPONSE
:
3427 case MAGIC_SERVER_REQUEST
:
3428 // None of the server initiated messages use flex frame encoding!
3429 proto_tree_add_item(tree
, hf_flex_extras
, tvb
, offset
, size
, ENC_UTF_8
|ENC_STR_HEX
);
3430 proto_tree_add_expert_format(tree
,
3432 &ei_warn_unknown_flex_unsupported
,
3436 "Server initiated messages don't use flex framing");
3439 case MAGIC_CLIENT_REQUEST_FLEX
:
3440 case MAGIC_CLIENT_RESPONSE_FLEX
:
3441 dissect_flexible_framing_extras(tvb
,
3446 is_request_magic(magic
));
3449 proto_tree_add_item(tree
, hf_flex_extras
, tvb
, offset
, size
, ENC_UTF_8
|ENC_STR_HEX
);
3450 proto_tree_add_expert_format(tree
,
3452 &ei_warn_unknown_flex_unsupported
,
3456 "According to the magic we should not have flex encoding");
3461 * Dissect the extras section in the frame
3463 static void dissect_frame_extras(tvbuff_t
*tvb
,
3470 uint16_t *subdoc_path_len
) {
3472 case MAGIC_SERVER_RESPONSE
:
3473 dissect_server_response_extras(tvb
, pinfo
, tree
, offset
, size
, opcode
);
3475 case MAGIC_SERVER_REQUEST
:
3476 dissect_server_request_extras(tvb
, pinfo
, tree
, offset
, size
, opcode
);
3478 case MAGIC_CLIENT_REQUEST_FLEX
:
3479 case MAGIC_CLIENT_RESPONSE_FLEX
:
3480 case MAGIC_CLIENT_REQUEST
:
3481 case MAGIC_CLIENT_RESPONSE
:
3482 dissect_client_extras(tvb
, pinfo
, tree
, offset
, size
,
3483 opcode
, is_request_magic(magic
), subdoc_path_len
);
3486 proto_tree_add_item(tree
, hf_extras
, tvb
, offset
, size
, ENC_UTF_8
|ENC_STR_HEX
);
3487 proto_tree_add_expert_format(tree
,
3489 &ei_warn_unknown_extras
,
3493 "Invalid magic so we can't interpret extras");
3498 * Dissect the key section in the frame
3500 static void dissect_frame_key(tvbuff_t
*tvb
,
3507 if (is_server_magic(magic
)) {
3508 dissect_server_key(tvb
, pinfo
, tree
, offset
, size
, opcode
,
3509 is_request_magic(magic
));
3511 dissect_client_key(tvb
, pinfo
, tree
, offset
, size
, opcode
,
3512 is_request_magic(magic
));
3516 static void dissect_client_value(tvbuff_t
*tvb
,
3523 uint16_t subdoc_path_len
) {
3524 uint8_t datatype
= get_datatype(tvb
);
3525 if (is_request_magic(magic
)) {
3526 dissect_value(tvb
, pinfo
, tree
, offset
, size
, subdoc_path_len
, opcode
, true, datatype
);
3528 uint16_t status
= get_status(tvb
);
3530 dissect_value(tvb
, pinfo
, tree
, offset
, size
, subdoc_path_len
, opcode
, false, datatype
);
3532 proto_tree_add_item(tree
, hf_value
, tvb
, offset
, size
, ENC_ASCII
| ENC_NA
);
3533 if (status
== STATUS_NOT_MY_VBUCKET
|| is_xerror(datatype
, status
)) {
3535 json_tvb
= tvb_new_subset_length(tvb
, offset
, size
);
3536 call_dissector(json_handle
, json_tvb
, pinfo
, tree
);
3537 } else if (opcode
== CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP
) {
3538 dissect_multipath_lookup_response(tvb
, pinfo
, tree
, offset
, size
);
3539 } else if (opcode
== CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
) {
3540 dissect_multipath_mutation_response(tvb
, pinfo
, tree
, offset
, size
);
3542 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
3543 val_to_str_ext(status
, &status_vals_ext
,
3544 "Unknown status: 0x%x"));
3546 /* Newer opcodes do not include a value in non-SUCCESS responses. */
3549 case CLIENT_OPCODE_SUBDOC_GET
:
3550 case CLIENT_OPCODE_SUBDOC_EXISTS
:
3551 case CLIENT_OPCODE_SUBDOC_DICT_ADD
:
3552 case CLIENT_OPCODE_SUBDOC_DICT_UPSERT
:
3553 case CLIENT_OPCODE_SUBDOC_DELETE
:
3554 case CLIENT_OPCODE_SUBDOC_REPLACE
:
3555 case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_LAST
:
3556 case CLIENT_OPCODE_SUBDOC_ARRAY_PUSH_FIRST
:
3557 case CLIENT_OPCODE_SUBDOC_ARRAY_INSERT
:
3558 case CLIENT_OPCODE_SUBDOC_ARRAY_ADD_UNIQUE
:
3559 case CLIENT_OPCODE_SUBDOC_COUNTER
:
3560 case CLIENT_OPCODE_SUBDOC_MULTI_LOOKUP
:
3561 case CLIENT_OPCODE_SUBDOC_MULTI_MUTATION
:
3565 ti
= proto_tree_add_item(tree
, hf_value
, tvb
, offset
, 0,
3566 ENC_ASCII
| ENC_NA
);
3567 expert_add_info_format(pinfo
, ti
, &ei_value_missing
,
3568 "%s with status %s (0x%x) must have Value",
3569 val_to_str_ext(opcode
,
3570 &client_opcode_vals_ext
,
3572 val_to_str_ext(status
,
3581 static void dissect_server_request_value(tvbuff_t
*tvb
,
3586 switch (get_opcode(tvb
)) {
3587 case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
:
3588 d_s_o_clustermap_change_notification_req(tvb
, pinfo
, tree
, offset
, size
);
3590 case SERVER_OPCODE_AUTHENTICATE
:
3591 d_s_o_authenticate_req(tvb
, pinfo
, tree
, offset
, size
);
3593 case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
:
3594 d_s_o_active_external_users_req(tvb
, pinfo
, tree
, offset
, size
);
3596 case SERVER_OPCODE_GET_AUTHORIZATION
:
3597 d_s_o_get_authorization_req(tvb
, pinfo
, tree
, offset
, size
);
3600 // Unknown packet type.. just dump the data
3602 proto_tree_add_item(tree
, hf_value
, tvb
, offset
, size
,
3603 ENC_ASCII
| ENC_NA
);
3609 static void dissect_server_response_value(tvbuff_t
*tvb
,
3614 col_append_fstr(pinfo
->cinfo
, COL_INFO
, ", %s",
3615 val_to_str_ext(get_status(tvb
), &status_vals_ext
,
3616 "Unknown status: 0x%x"));
3618 switch (get_opcode(tvb
)) {
3619 case SERVER_OPCODE_CLUSTERMAP_CHANGE_NOTIFICATION
:
3620 d_s_o_server_ignored_response(tvb
, pinfo
, tree
, offset
, size
);
3622 case SERVER_OPCODE_AUTHENTICATE
:
3623 d_s_o_authenticate_res(tvb
, pinfo
, tree
, offset
, size
);
3625 case SERVER_OPCODE_ACTIVE_EXTERNAL_USERS
:
3626 d_s_o_server_ignored_response(tvb
, pinfo
, tree
, offset
, size
);
3628 case SERVER_OPCODE_GET_AUTHORIZATION
:
3629 d_s_o_get_authorization_res(tvb
, pinfo
, tree
, offset
, size
);
3632 // Unknown packet type.. just dump the data
3634 proto_tree_add_item(tree
, hf_value
, tvb
, offset
, size
,
3635 ENC_ASCII
| ENC_NA
);
3642 * Dissect the value section in the frame
3644 static void dissect_frame_value(tvbuff_t
*tvb
,
3651 uint16_t subdoc_path_len
) {
3652 if (size
> INT32_MAX
) {
3653 // The packet size isn't supported
3657 case MAGIC_CLIENT_REQUEST
:
3658 case MAGIC_CLIENT_RESPONSE
:
3659 case MAGIC_CLIENT_REQUEST_FLEX
:
3660 case MAGIC_CLIENT_RESPONSE_FLEX
:
3661 dissect_client_value(tvb
, pinfo
, tree
, offset
, size
, magic
, opcode
, subdoc_path_len
);
3663 case MAGIC_SERVER_REQUEST
:
3664 dissect_server_request_value(tvb
, pinfo
, tree
, offset
, (int)size
);
3666 case MAGIC_SERVER_RESPONSE
:
3667 dissect_server_response_value(tvb
, pinfo
, tree
, offset
, (int)size
);
3670 // Unknown magic... just dump the data
3672 proto_tree_add_item(tree
, hf_value
, tvb
, offset
, (int)size
, ENC_ASCII
| ENC_NA
);
3679 * Each frame in the protocol consists of a 24 byte header, followed by
3680 * a variable number of sections (all of the sizes is located in the
3681 * first 24 byte header):
3683 * |---------------------------------------|
3684 * | Fixed 24 byte frame header |
3685 * |---------------------------------------|
3686 * | n bytes flex frame info |
3687 * |---------------------------------------|
3688 * | n bytes extras |
3689 * |---------------------------------------|
3691 * |---------------------------------------|
3693 * |---------------------------------------|
3695 * Call each function responsible for printing the segment
3698 dissect_couchbase(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void* data _U_
)
3700 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PSNAME
);
3701 col_clear(pinfo
->cinfo
, COL_INFO
);
3703 proto_item
*couchbase_item
= proto_tree_add_item(tree
, proto_couchbase
, tvb
, 0, -1, ENC_NA
);
3704 proto_tree
*couchbase_tree
= proto_item_add_subtree(couchbase_item
, ett_couchbase
);
3706 dissect_frame_header(tvb
, pinfo
, couchbase_tree
, couchbase_item
);
3707 uint8_t magic
= get_magic(tvb
);
3710 uint8_t flex_frame_extra_len
= get_flex_framing_extras_length(tvb
);
3711 uint8_t opcode
= get_opcode(tvb
);
3712 uint8_t extras_length
= get_extras_length(tvb
);
3713 uint16_t key_length
= get_key_length(tvb
);
3714 uint32_t body_length
= get_body_length(tvb
);
3715 uint32_t value_len
= body_length
- key_length
- extras_length
- flex_frame_extra_len
;
3717 dissect_frame_flex_info_section(tvb
, pinfo
, couchbase_tree
, offset
, flex_frame_extra_len
, magic
);
3718 offset
+= flex_frame_extra_len
;
3720 uint16_t subdoc_path_len
= 0;
3721 // Dissect the extras section
3722 dissect_frame_extras(tvb
, pinfo
, couchbase_tree
, offset
, extras_length
, magic
, opcode
, &subdoc_path_len
);
3723 offset
+= extras_length
;
3726 dissect_frame_key(tvb
, pinfo
, couchbase_tree
, offset
, key_length
, magic
, opcode
);
3727 offset
+= key_length
;
3729 dissect_frame_value(tvb
, pinfo
, couchbase_tree
, offset
, value_len
, magic
, opcode
, subdoc_path_len
);
3730 return tvb_reported_length(tvb
);
3734 get_couchbase_pdu_length(packet_info
*pinfo _U_
, tvbuff_t
*tvb
, int offset
,
3736 // See https://github.com/couchbase/kv_engine/blob/master/docs/BinaryProtocol.md#packet-structure
3737 // for a description of each packet.
3738 // The "length" field is located at offset 8 within the frame and does
3739 // not include the fixed header.
3740 return tvb_get_ntohl(tvb
, offset
+ 8) + COUCHBASE_HEADER_LEN
;
3743 /* Dissect the couchbase packet */
3745 dissect_couchbase_pdu(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
,
3747 if (try_val_to_str(tvb_get_uint8(tvb
, 0), magic_vals
) == NULL
) {
3748 // Magic isn't one of the know magics used by the Couchbase dissector
3752 tcp_dissect_pdus(tvb
, pinfo
, tree
, couchbase_desegment_body
,
3753 COUCHBASE_HEADER_LEN
,
3754 get_couchbase_pdu_length
, dissect_couchbase
, data
);
3755 return tvb_captured_length(tvb
);
3759 /* Registration functions; register couchbase protocol,
3760 * its configuration options and also register the tcp dissectors.
3763 proto_register_couchbase(void)
3765 static hf_register_info hf
[] = {
3766 { &hf_magic
, { "Magic", "couchbase.magic", FT_UINT8
, BASE_HEX
, VALS(magic_vals
), 0x0, "Magic number", HFILL
} },
3767 { &hf_opcode
, { "Opcode", "couchbase.opcode", FT_UINT8
, BASE_HEX
|BASE_EXT_STRING
, &client_opcode_vals_ext
, 0x0, "Command code", HFILL
} },
3768 { &hf_server_opcode
, { "Server Opcode", "couchbase.server.opcode", FT_UINT8
, BASE_HEX
|BASE_EXT_STRING
, &server_opcode_vals_ext
, 0x0, "Command code", HFILL
} },
3769 { &hf_extlength
, { "Extras Length", "couchbase.extras.length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, "Length in bytes of the command extras", HFILL
} },
3770 { &hf_keylength
, { "Key Length", "couchbase.key.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, "Length in bytes of the text key that follows the command extras", HFILL
} },
3771 { &hf_value_length
, { "Value Length", "couchbase.value.length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Length in bytes of the value that follows the key", HFILL
} },
3772 { &hf_datatype
, { "Data Type", "couchbase.datatype", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3773 { &hf_datatype_json
, { "JSON", "couchbase.datatype.json", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DT_JSON
, "JSON datatype", HFILL
} },
3774 { &hf_datatype_snappy
, { "Snappy", "couchbase.datatype.snappy", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DT_SNAPPY
, "Snappy Compressed", HFILL
} },
3775 { &hf_datatype_xattr
, { "XATTR", "couchbase.datatype.xattr", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), DT_XATTR
, "Xattrs included", HFILL
} },
3776 { &hf_vbucket
, { "VBucket", "couchbase.vbucket", FT_UINT16
, BASE_DEC_HEX
, NULL
, 0x0, "VBucket ID", HFILL
} },
3777 { &hf_status
, { "Status", "couchbase.status", FT_UINT16
, BASE_HEX
|BASE_EXT_STRING
, &status_vals_ext
, 0x0, "Status of the response", HFILL
} },
3778 { &hf_total_bodylength
, { "Total Body Length", "couchbase.total_bodylength", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Length in bytes of extra + key + value", HFILL
} },
3779 { &hf_opaque
, { "Opaque", "couchbase.opaque", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3780 { &hf_cas
, { "CAS", "couchbase.cas", FT_UINT64
, BASE_HEX
, NULL
, 0x0, "Data version check", HFILL
} },
3781 { &hf_ttp
, { "Time to Persist", "couchbase.ttp", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Approximate time needed to persist the key (milliseconds)", HFILL
} },
3782 { &hf_ttr
, { "Time to Replicate", "couchbase.ttr", FT_UINT32
, BASE_DEC
, NULL
, 0x0, "Approximate time needed to replicate the key (milliseconds)", HFILL
} },
3784 { &hf_collection_key_id
, { "Collection ID", "couchbase.key.collection_id", FT_UINT32
, BASE_HEX
, NULL
, 0x0, "If this a collection stream, this is the collection-ID", HFILL
} },
3785 { &hf_collection_key_logical
, { "Collection Logical Key", "couchbase.key.logical_key", FT_STRING
, BASE_NONE
, NULL
, 0x0, "If this a collection stream, this is the key in the collection", HFILL
} },
3786 { &hf_collection_manifest_id
, { "Collections Manifest ID", "couchbase.key.collection_manifest_id", FT_UINT64
, BASE_HEX
, NULL
, 0x0, "The collections manifest id", HFILL
} },
3788 { &hf_flex_keylength
, { "Key Length", "couchbase.key.length", FT_UINT8
, BASE_DEC
, NULL
, 0x0, "Length in bytes of the text key that follows the command extras", HFILL
} },
3789 { &hf_flex_extras_length
, { "Flexible Framing Extras Length", "couchbase.flex_extras", FT_UINT8
, BASE_DEC
, NULL
, 0x0, "Length in bytes of the flexible framing extras that follows the response header", HFILL
} },
3790 { &hf_flex_extras
, {"Flexible Framing Extras", "couchbase.flex_frame_extras", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3791 { &hf_flex_extras_n
, {"Flexible Framing Extras", "couchbase.flex_frame_extras.string", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3793 { &hf_flex_frame_id_byte0
, {"Flexible Frame Byte0", "couchbase.flex_frame.byte0", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3795 { &hf_flex_frame_id_req
, {"Flexible Frame ID (request)", "couchbase.flex_frame.frame.id", FT_UINT8
, BASE_DEC
, VALS(flex_frame_request_ids
), 0x0, NULL
, HFILL
} },
3796 { &hf_flex_frame_id_res
, {"Flexible Frame ID (response)", "couchbase.flex_frame.frame.id", FT_UINT8
, BASE_DEC
, VALS(flex_frame_response_ids
), 0x0, NULL
, HFILL
} },
3797 { &hf_flex_frame_id_req_esc
, {"Flexible Frame ID esc (request)", "couchbase.flex_frame.frame.id", FT_UINT16
, BASE_DEC
, VALS(flex_frame_request_ids
), 0x0, NULL
, HFILL
} },
3798 { &hf_flex_frame_id_res_esc
, {"Flexible Frame ID esc (response)", "couchbase.flex_frame.frame.id", FT_UINT16
, BASE_DEC
, VALS(flex_frame_response_ids
), 0x0, NULL
, HFILL
} },
3801 { &hf_flex_frame_len
, {"Flexible Frame Len", "couchbase.flex_frame.frame.len", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3802 { &hf_flex_frame_len_esc
, {"Flexible Frame Len (esc)", "couchbase.flex_frame.frame.len", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3804 { &hf_flex_frame_tracing_duration
, {"Server Recv->Send duration", "couchbase.flex_frame.frame.duration", FT_DOUBLE
, BASE_NONE
|BASE_UNIT_STRING
, UNS(&units_microseconds
), 0, NULL
, HFILL
} },
3805 { &hf_flex_frame_ru_count
, {"Read unit count", "couchbase.flex_frame.frame.ru_count", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3806 { &hf_flex_frame_wu_count
, {"Write unit count", "couchbase.flex_frame.frame.wu_count", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3807 { &hf_flex_frame_durability_req
, {"Durability Requirement", "couchbase.flex_frame.frame.durability_req", FT_UINT8
, BASE_DEC
, VALS(flex_frame_durability_req
), 0, NULL
, HFILL
} },
3808 { &hf_flex_frame_dcp_stream_id
, {"DCP Stream Identifier", "couchbase.flex_frame.frame.dcp_stream_id", FT_UINT16
, BASE_DEC
, NULL
, 0, NULL
, HFILL
} },
3809 { &hf_flex_frame_impersonated_user
, {"Impersonated User", "couchbase.flex_frame.frame.impersonated_user", FT_STRING
, BASE_NONE
, NULL
, 0, NULL
, HFILL
} },
3811 { &hf_extras
, { "Extras", "couchbase.extras", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3812 { &hf_extras_flags
, { "Flags", "couchbase.extras.flags", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3813 { &hf_extras_flags_backfill
, { "Backfill Age", "couchbase.extras.flags.backfill", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
} },
3814 { &hf_extras_flags_dump
, { "Dump", "couchbase.extras.flags.dump", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
} },
3815 { &hf_extras_flags_list_vbuckets
, { "List VBuckets", "couchbase.extras.flags.list_vbuckets", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0004, NULL
, HFILL
} },
3816 { &hf_extras_flags_takeover_vbuckets
, { "Takeover VBuckets", "couchbase.extras.flags.takeover_vbuckets", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0008, NULL
, HFILL
} },
3817 { &hf_extras_flags_support_ack
, { "Support ACK", "couchbase.extras.flags.support_ack", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0010, NULL
, HFILL
} },
3818 { &hf_extras_flags_request_keys_only
, { "Request Keys Only", "couchbase.extras.flags.request_keys_only", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0020, NULL
, HFILL
} },
3819 { &hf_extras_flags_checkpoint
, { "Checkpoint", "couchbase.extras.flags.checkpoint", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0040, NULL
, HFILL
} },
3822 { &hf_subdoc_flags
, { "Subdoc flags", "couchbase.extras.subdoc.flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3823 { &hf_subdoc_flags_mkdirp
, { "MKDIR_P", "couchbase.extras.subdoc.flags.mkdir_p", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x01, "Create non-existent intermediate paths", HFILL
} },
3824 { &hf_subdoc_flags_xattrpath
, { "XATTR_PATH", "couchbase.extras.subdoc.flags.xattr_path", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x04, "If set path refers to extended attribute (XATTR)", HFILL
} },
3825 { &hf_subdoc_flags_expandmacros
, { "EXPAND_MACROS", "couchbase.extras.subdoc.flags.expand_macros", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x10, "Expand macro values inside XATTRs", HFILL
} },
3826 { &hf_subdoc_flags_reserved
, {"Reserved fields", "couchbase.extras.subdoc.flags.reserved", FT_UINT8
, BASE_HEX
, NULL
, 0xEA, "A reserved field", HFILL
} },
3827 { &hf_subdoc_doc_flags
, { "Subdoc Doc flags", "couchbase.extras.subdoc.doc_flags", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3828 { &hf_subdoc_doc_flags_mkdoc
, { "MKDOC", "couchbase.extras.subdoc.doc_flags.mkdoc", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x01, "Create document if it does not exist, implies mkdir_p", HFILL
} },
3829 { &hf_subdoc_doc_flags_add
, { "ADD", "couchbase.extras.subdoc.doc_flags.add", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x02, "Fail if doc already exists", HFILL
} },
3830 { &hf_subdoc_doc_flags_accessdeleted
, { "ACCESS_DELETED", "couchbase.extras.subdoc.doc_flags.access_deleted", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x04, "Allow access to XATTRs for deleted documents", HFILL
} },
3831 { &hf_subdoc_doc_flags_createasdeleted
, { "CREATE_AS_DELETED", "couchbase.extras.subdoc.doc_flags.create_as_deleted", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x08, "If the document does not exist then create it in the Deleted state, instead of the normal Alive state", HFILL
} },
3832 { &hf_subdoc_doc_flags_revivedocument
, { "REVIVE_DOCUMENT", "couchbase.extras.subdoc.doc_flags.revive_document", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x10, "If the document exists in the Deleted state, revive it to the normal Alive state", HFILL
} },
3833 { &hf_subdoc_doc_flags_replicaread
, { "REPLICA_READ", "couchbase.extras.subdoc.doc_flags.replica_read", FT_BOOLEAN
, 8, TFS(&tfs_set_notset
), 0x20, "Operate on a replica vbucket instead of an active one", HFILL
} },
3834 { &hf_subdoc_doc_flags_reserved
, {"Reserved fields", "couchbase.extras.subdoc.doc_flags.reserved", FT_UINT8
, BASE_HEX
, NULL
, 0xC0, "A reserved field", HFILL
} },
3835 { &hf_extras_pathlen
, { "Path Length", "couchbase.extras.pathlen", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3838 { &hf_extras_flags_dcp_connection_type
, {"Connection Type", "couchbase.extras.flags.dcp_connection_type", FT_UINT32
, BASE_HEX
, VALS(dcp_connection_type_vals
), 0x00000003, NULL
, HFILL
} },
3839 { &hf_extras_flags_dcp_add_stream_takeover
, {"Take Over", "couchbase.extras.flags.dcp_add_stream_takeover", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
} },
3840 { &hf_extras_flags_dcp_add_stream_diskonly
, {"Disk Only", "couchbase.extras.flags.dcp_add_stream_diskonly", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
} },
3841 { &hf_extras_flags_dcp_add_stream_latest
, {"Latest", "couchbase.extras.flags.dcp_add_stream_latest", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0004, NULL
, HFILL
} },
3842 { &hf_extras_flags_dcp_snapshot_marker_memory
, {"Memory", "couchbase.extras.flags.dcp_snapshot_marker_memory", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
} },
3843 { &hf_extras_flags_dcp_snapshot_marker_disk
, {"Disk", "couchbase.extras.flags.dcp_snapshot_marker_disk", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
} },
3844 { &hf_extras_flags_dcp_snapshot_marker_chk
, {"Chk", "couchbase.extras.flags.dcp_snapshot_marker_chk", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0004, NULL
, HFILL
} },
3845 { &hf_extras_flags_dcp_snapshot_marker_ack
, {"Ack", "couchbase.extras.flags.dcp_snapshot_marker_ack", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0008, NULL
, HFILL
} },
3846 { &hf_extras_flags_dcp_snapshot_marker_history
, {"History", "couchbase.extras.flags.dcp_snapshot_marker_history", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0010, NULL
, HFILL
} },
3847 { &hf_extras_flags_dcp_snapshot_marker_may_contain_dups
, {"May Contain Duplicates", "couchbase.extras.flags.dcp_snapshot_marker_may_contain_duplicates", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0020, NULL
, HFILL
} },
3848 { &hf_extras_flags_dcp_include_xattrs
, {"Include XATTRs", "couchbase.extras.flags.dcp_include_xattrs", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0004, "Indicates the server should include documents XATTRs", HFILL
} },
3849 { &hf_extras_flags_dcp_no_value
, {"No Value", "couchbase.extras.flags.dcp_no_value", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0008, "Indicates the server should strip off values", HFILL
} },
3850 { &hf_extras_flags_dcp_collections
, {"Enable Collections", "couchbase.extras.flags.dcp_collections", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0010, "Indicates the server should stream collections", HFILL
} },
3851 { &hf_extras_flags_dcp_include_delete_times
, {"Include Delete Times", "couchbase.extras.flags.dcp_include_delete_times", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0020, "Indicates the server should include delete timestamps", HFILL
} },
3852 { &hf_extras_flags_dcp_oso_snapshot_begin
, {"OSO Begin", "couchbase.extras.flags.dcp_oso_snapshot_begin", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0001, "The start of an OSO snapshot", HFILL
} },
3853 { &hf_extras_flags_dcp_oso_snapshot_end
, {"OSO End", "couchbase.extras.flags.dcp_oso_snapshot_end", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0002, "The end of an OSO snapshot", HFILL
} },
3855 { &hf_extras_seqno
, { "Sequence number", "couchbase.extras.seqno", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3856 { &hf_extras_mutation_seqno
, { "Mutation Sequence Number", "couchbase.extras.mutation_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3857 { &hf_extras_opaque
, { "Opaque (vBucket identifier)", "couchbase.extras.opaque", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3858 { &hf_extras_reserved
, { "Reserved", "couchbase.extras.reserved", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3859 { &hf_extras_start_seqno
, { "Start Sequence Number", "couchbase.extras.start_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3860 { &hf_extras_end_seqno
, { "End Sequence Number", "couchbase.extras.end_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3861 { &hf_extras_high_completed_seqno
, { "High Completed Sequence Number", "couchbase.extras.high_completed_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3862 { &hf_extras_max_visible_seqno
, { "Max Visible Seqno", "couchbase.extras.max_visible_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3863 { &hf_extras_timestamp
, { "PiTR timestamp", "couchbase.extras.timestamp", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3864 { &hf_extras_marker_version
, { "Snapshot Marker Version", "couchbase.extras.marker_version", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3865 { &hf_extras_vbucket_uuid
, { "VBucket UUID", "couchbase.extras.vbucket_uuid", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3866 { &hf_extras_snap_start_seqno
, { "Snapshot Start Sequence Number", "couchbase.extras.snap_start_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3867 { &hf_extras_snap_end_seqno
, { "Snapshot End Sequence Number", "couchbase.extras.snap_end_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3868 { &hf_extras_by_seqno
, { "by_seqno", "couchbase.extras.by_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3869 { &hf_extras_prepared_seqno
, { "by_seqno (prepared)", "couchbase.extras.by_seqno_prepared", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3870 { &hf_extras_commit_seqno
, { "by_seqno (commit)", "couchbase.extras.by_seqno_commit", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3871 { &hf_extras_abort_seqno
, { "by_seqno (abort)", "couchbase.extras.by_seqno_abort", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3872 { &hf_extras_rev_seqno
, { "rev_seqno", "couchbase.extras.rev_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3873 { &hf_extras_lock_time
, { "lock_time", "couchbase.extras.lock_time", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3874 { &hf_extras_nmeta
, { "nmeta", "couchbase.extras.nmeta", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3875 { &hf_extras_nru
, { "nru", "couchbase.extras.nru", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3876 { &hf_extras_deleted
, { "deleted", "couchbase.extras.deleted", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3877 { &hf_extras_bytes_to_ack
, { "bytes_to_ack", "couchbase.extras.bytes_to_ack", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3878 { &hf_extras_delete_time
, { "delete_time", "couchbase.extras.delete_time", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3879 { &hf_extras_delete_unused
, { "unused", "couchbase.extras.delete_unused", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3880 { &hf_extras_system_event_id
, { "system_event_id", "couchbase.extras.system_event_id", FT_UINT32
, BASE_DEC
, VALS(dcp_system_event_id_vals
), 0x0, NULL
, HFILL
} },
3881 { &hf_extras_system_event_version
, { "system_event_version", "couchbase.extras.system_event_version", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3882 { &hf_extras_dcp_oso_snapshot_flags
, { "OSO snapshot flags", "couchbase.extras.dcp_oso_snapshot_flags", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3884 { &hf_failover_log
, { "Failover Log", "couchbase.dcp.failover_log", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3885 { &hf_failover_log_size
, { "Size", "couchbase.dcp.failover_log.size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3886 { &hf_failover_log_vbucket_uuid
, { "VBucket UUID", "couchbase.dcp.failover_log.vbucket_uuid", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3887 { &hf_failover_log_vbucket_seqno
, { "Sequence Number", "couchbase.dcp.failover_log.seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3889 { &hf_vbucket_states
, { "VBucket States", "couchbase.vbucket_states", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3890 { &hf_vbucket_states_state
, { "State", "couchbase.vbucket_states.state", FT_UINT32
, BASE_HEX
, VALS(vbucket_states_vals
), 0x0, NULL
, HFILL
} },
3891 { &hf_vbucket_states_size
, { "Size", "couchbase.vbucket_states.size", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3892 { &hf_vbucket_states_id
, { "VBucket", "couchbase.vbucket_states.id", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3893 { &hf_vbucket_states_seqno
, { "Sequence Number", "couchbase.vbucket_states.seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3895 { &hf_extras_expiration
, { "Expiration", "couchbase.extras.expiration", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3896 { &hf_extras_delta
, { "Amount to Add", "couchbase.extras.delta", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3897 { &hf_extras_initial
, { "Initial Value", "couchbase.extras.initial", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3898 { &hf_extras_unknown
, { "Unknown", "couchbase.extras.unknown", FT_BYTES
, BASE_NONE
, NULL
, 0x0, "Unknown Extras", HFILL
} },
3899 { &hf_key
, { "Key", "couchbase.key", FT_STRING
, BASE_NONE
, NULL
, 0x0, "If this is a collection stream, the key is formed of a leb128 prefix and then the key", HFILL
} },
3900 { &hf_path
, { "Path", "couchbase.path", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3901 { &hf_value
, { "Value", "couchbase.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3902 { &hf_uint64_response
, { "Response", "couchbase.extras.response", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3903 { &hf_observe
, { "Observe", "couchbase.observe", FT_STRING
, BASE_NONE
, NULL
, 0x0, "The observe properties", HFILL
} },
3904 { &hf_observe_key
, { "Key", "couchbase.observe.key", FT_STRING
, BASE_NONE
, NULL
, 0x0, "The observable key", HFILL
} },
3905 { &hf_observe_keylength
, { "Key Length", "couchbase.observe.keylength", FT_UINT16
, BASE_DEC
, NULL
, 0x0, "The length of the observable key", HFILL
} },
3906 { &hf_observe_vbucket
, { "VBucket", "couchbase.observe.vbucket", FT_UINT16
, BASE_HEX
, NULL
, 0x0, "VBucket of the observable key", HFILL
} },
3907 { &hf_observe_status
, { "Status", "couchbase.observe.status", FT_UINT8
, BASE_HEX
, NULL
, 0x0, "Status of the observable key", HFILL
} },
3908 { &hf_observe_cas
, { "CAS", "couchbase.observe.cas", FT_UINT64
, BASE_HEX
, NULL
, 0x0, "CAS value of the observable key", HFILL
} },
3909 { &hf_observe_vbucket_uuid
, { "VBucket UUID", "couchbase.observe.vbucket_uuid", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3910 { &hf_observe_last_persisted_seqno
, { "Last persisted sequence number", "couchbase.observe.last_persisted_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3911 { &hf_observe_current_seqno
, { "Current sequence number", "couchbase.observe.current_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3912 { &hf_observe_old_vbucket_uuid
, { "Old VBucket UUID", "couchbase.observe.old_vbucket_uuid", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3913 { &hf_observe_last_received_seqno
, { "Last received sequence number", "couchbase.observe.last_received_seqno", FT_UINT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3914 { &hf_observe_failed_over
, { "Failed over", "couchbase.observe.failed_over", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3916 { &hf_get_errmap_version
, {"Version", "couchbase.geterrmap.version", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3918 { &hf_multipath_opcode
, { "Opcode", "couchbase.multipath.opcode", FT_UINT8
, BASE_HEX
|BASE_EXT_STRING
, &client_opcode_vals_ext
, 0x0, "Command code", HFILL
} },
3919 { &hf_multipath_index
, { "Index", "couchbase.multipath.index", FT_UINT8
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3920 { &hf_multipath_pathlen
, { "Path Length", "couchbase.multipath.path.length", FT_UINT16
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3921 { &hf_multipath_path
, { "Path", "couchbase.multipath.path", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3922 { &hf_multipath_valuelen
, { "Value Length", "couchbase.multipath.value.length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3923 { &hf_multipath_value
, { "Value", "couchbase.multipath.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3925 { &hf_meta_flags
, {"Flags", "couchbase.extras.flags", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3926 { &hf_meta_expiration
, {"Expiration", "couchbase.extras.expiration", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3927 { &hf_meta_revseqno
, {"RevSeqno", "couchbase.extras.revseqno", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3928 { &hf_meta_cas
, {"CAS", "couchbase.extras.cas", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3929 { &hf_meta_options
, {"Options", "couchbase.extras.options", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3930 { &hf_force_meta
, {"FORCE_WITH_META_OP", "couchbase.extras.options.force_with_meta_op", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0001, NULL
, HFILL
} },
3931 { &hf_force_accept
, {"FORCE_ACCEPT_WITH_META_OPS", "couchbase.extras.options.force_accept_with_meta_ops", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0002, NULL
, HFILL
} },
3932 { &hf_regenerate_cas
, {"REGENERATE_CAS", "couchbase.extras.option.regenerate_cas", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0004, NULL
, HFILL
} },
3933 { &hf_skip_conflict
, {"SKIP_CONFLICT_RESOLUTION", "couchbase.extras.options.skip_conflict_resolution", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0008, NULL
, HFILL
} },
3934 { &hf_is_expiration
, {"IS_EXPIRATION", "couchbase.extras.options.is_expiration", FT_BOOLEAN
, 16, TFS(&tfs_set_notset
), 0x0010, NULL
, HFILL
} },
3935 { &hf_metalen
, {"Meta Length", "couchbase.extras.meta_length", FT_UINT16
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3936 { &hf_meta_reqextmeta
, {"ReqExtMeta", "couchbase.extras.reqextmeta", FT_UINT8
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3937 { &hf_meta_deleted
, {"Deleted", "couchbase.extras.deleted", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3938 { &hf_exptime
, {"Expiry", "couchbase.extras.expiry", FT_UINT32
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3939 { &hf_extras_meta_seqno
, {"Seqno", "couchbase.extras.meta.seqno", FT_UINT64
, BASE_HEX
, NULL
, 0x0, NULL
, HFILL
} },
3940 { &hf_confres
, {"ConfRes", "couchbase.extras.confres", FT_UINT8
, BASE_HEX
, NULL
, 0x0, "Conflict Resolution Mode", HFILL
} },
3942 { &hf_bucket_type
, {"Bucket Type", "couchbase.bucket.type", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3943 { &hf_bucket_config
, {"Bucket Config", "couchbase.bucket.config", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3944 { &hf_config_key
, {"Key", "couchbase.bucket.config.key", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3945 { &hf_config_value
, {"Value", "couchbase.bucket.config.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3946 { &hf_hello_features
, {"Hello Features", "couchbase.hello.features", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3947 { &hf_hello_features_feature
, {"Feature", "couchbase.hello.features.feature", FT_UINT16
, BASE_HEX
, VALS(feature_vals
), 0x0, NULL
, HFILL
} },
3949 { &hf_xattrs
, { "XATTRs", "couchbase.xattrs", FT_NONE
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3950 { &hf_xattr_length
, { "XATTR Length", "couchbase.xattrs.length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3951 { &hf_xattr_pair_length
, { "XATTR Pair Length", "couchbase.xattrs.pair.length", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3952 { &hf_xattr_key
, { "Key", "couchbase.xattrs.pair.key", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3953 { &hf_xattr_value
, { "Value", "couchbase.xattrs.pair.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3956 { &hf_server_extras_cccp_epoch
, { "Epoch", "couchbase.server.extras.cccp.epoch", FT_INT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3957 { &hf_server_extras_cccp_revno
, { "Revision", "couchbase.server.extras.cccp.revision", FT_INT64
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3958 { &hf_server_clustermap_value
, { "Clustermap", "couchbase.server.clustermap.value", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3959 { &hf_server_authentication
, { "Authentication", "couchbase.server.authentication", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3960 { &hf_server_external_users
, { "External users", "couchbase.server.external_users", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3961 { &hf_server_get_authorization
, { "Authorization", "couchbase.server.authorization", FT_STRING
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3963 { &hf_range_scan_uuid
, { "Range Scan UUID", "couchbase.range_scan.uuid", FT_GUID
, BASE_NONE
, NULL
, 0x0, NULL
, HFILL
} },
3964 { &hf_range_scan_item_limit
, { "Range Scan item limit", "couchbase.range_scan.item_limit", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3965 { &hf_range_scan_time_limit
, { "Range Scan time limit", "couchbase.range_scan.time_limit", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} },
3966 { &hf_range_scan_byte_limit
, { "Range Scan byte limit", "couchbase.range_scan.byte_limit", FT_UINT32
, BASE_DEC
, NULL
, 0x0, NULL
, HFILL
} }
3969 static ei_register_info ei
[] = {
3970 { &ei_value_missing
, { "couchbase.value_missing", PI_PROTOCOL
, PI_WARN
, "Value is mandatory for this command", EXPFILL
}},
3971 { &ei_warn_shall_not_have_value
, { "couchbase.warn.shall_not_have_value", PI_UNDECODED
, PI_WARN
, "Packet shall not have value", EXPFILL
}},
3972 { &ei_warn_shall_not_have_extras
, { "couchbase.warn.shall_not_have_extras", PI_UNDECODED
, PI_WARN
, "Packet shall not have extras", EXPFILL
}},
3973 { &ei_warn_shall_not_have_key
, { "couchbase.warn.shall_not_have_key", PI_UNDECODED
, PI_WARN
, "Packet shall not have key", EXPFILL
}},
3974 { &ei_warn_must_have_extras
, { "couchbase.warn.must_have_extras", PI_UNDECODED
, PI_WARN
, "Packet must have extras", EXPFILL
}},
3975 { &ei_warn_must_have_key
, { "couchbase.warn.must_have_key", PI_UNDECODED
, PI_WARN
, "Message must have Key", EXPFILL
}},
3976 { &ei_warn_illegal_extras_length
, { "couchbase.warn.illegal_extras_length", PI_UNDECODED
, PI_WARN
, "Illegal Extras length", EXPFILL
}},
3977 { &ei_warn_illegal_value_length
, { "couchbase.warn.illegal_value_length", PI_UNDECODED
, PI_WARN
, "Illegal Value length", EXPFILL
}},
3978 { &ei_warn_unknown_magic_byte
, { "couchbase.warn.unknown_magic_byte", PI_UNDECODED
, PI_WARN
, "Unknown magic byte", EXPFILL
}},
3979 { &ei_warn_unknown_opcode
, { "couchbase.warn.unknown_opcode", PI_UNDECODED
, PI_WARN
, "Unknown opcode", EXPFILL
}},
3980 { &ei_warn_unknown_extras
, { "couchbase.warn.unknown_extras", PI_UNDECODED
, PI_WARN
, "Unknown extras", EXPFILL
}},
3981 { &ei_note_status_code
, { "couchbase.note.status_code", PI_RESPONSE_CODE
, PI_NOTE
, "Status", EXPFILL
}},
3982 { &ei_separator_not_found
, { "couchbase.warn.separator_not_found", PI_UNDECODED
, PI_WARN
, "Separator not found", EXPFILL
}},
3983 { &ei_illegal_value
, { "couchbase.warn.illegal_value", PI_UNDECODED
, PI_WARN
, "Illegal value for command", EXPFILL
}},
3984 { &ei_compression_error
, { "couchbase.error.compression", PI_UNDECODED
, PI_WARN
, "Compression error", EXPFILL
}},
3985 { &ei_warn_unknown_flex_unsupported
, { "couchbase.warn.unsupported_flexible_frame", PI_UNDECODED
, PI_WARN
, "Unsupported Flexible encoding", EXPFILL
}},
3986 { &ei_warn_unknown_flex_id
, { "couchbase.warn.unknown_flexible_frame_id", PI_UNDECODED
, PI_WARN
, "Flexible Response ID warning", EXPFILL
}},
3987 { &ei_warn_unknown_flex_len
, { "couchbase.warn.unknown_flexible_frame_len", PI_UNDECODED
, PI_WARN
, "Flexible Response Length warning", EXPFILL
}}
3990 static int *ett
[] = {
3993 &ett_flex_frame_extras
,
3997 &ett_vbucket_states
,
4001 &ett_hello_features
,
4008 module_t
*couchbase_module
;
4009 expert_module_t
* expert_couchbase
;
4011 proto_couchbase
= proto_register_protocol(PNAME
, PSNAME
, PFNAME
);
4013 proto_register_field_array(proto_couchbase
, hf
, array_length(hf
));
4014 proto_register_subtree_array(ett
, array_length(ett
));
4016 expert_couchbase
= expert_register_protocol(proto_couchbase
);
4017 expert_register_field_array(expert_couchbase
, ei
, array_length(ei
));
4019 /* Register our configuration options */
4020 couchbase_module
= prefs_register_protocol(proto_couchbase
, &proto_reg_handoff_couchbase
);
4022 couchbase_handle
= register_dissector("couchbase", dissect_couchbase_pdu
, proto_couchbase
);
4024 prefs_register_bool_preference(couchbase_module
, "desegment_pdus",
4025 "Reassemble PDUs spanning multiple TCP segments",
4026 "Whether the Couchbase dissector should reassemble PDUs"
4027 " spanning multiple TCP segments."
4028 " To use this option, you must also enable \"Allow subdissectors"
4029 " to reassemble TCP streams\" in the TCP protocol settings.",
4030 &couchbase_desegment_body
);
4032 prefs_register_uint_preference(couchbase_module
, "tls.port", "SSL/TLS Data Port",
4033 "The port used for communicating with the data service via SSL/TLS",
4034 10, &couchbase_ssl_port_pref
);
4035 prefs_register_obsolete_preference(couchbase_module
, "ssl_port");
4038 /* Register the tcp couchbase dissector. */
4040 proto_reg_handoff_couchbase(void)
4042 static bool initialized
= false;
4045 json_handle
= find_dissector_add_dependency("json", proto_couchbase
);
4046 dissector_add_uint_range_with_preference("tcp.port", COUCHBASE_DEFAULT_PORT
, couchbase_handle
);
4049 ssl_dissector_delete(couchbase_ssl_port
, couchbase_handle
);
4051 couchbase_ssl_port
= couchbase_ssl_port_pref
;
4052 ssl_dissector_add(couchbase_ssl_port
, couchbase_handle
);
4061 * indent-tabs-mode: nil
4064 * ex: set shiftwidth=2 tabstop=8 expandtab:
4065 * :indentSize=2:tabSize=8:noTabs=true: