1 /* -*- Mode: C; tab-width: 2; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2 #include "libmemcached/protocol/common.h"
5 #include <netinet/in.h>
8 #define ensure(a) if (!(a)) { return false; }
10 bool memcached_binary_protocol_pedantic_check_request(const protocol_binary_request_header
*request
)
12 ensure(request
->request
.magic
== PROTOCOL_BINARY_REQ
);
13 ensure(request
->request
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
15 ensure(request
->bytes
[6] == 0);
16 ensure(request
->bytes
[7] == 0);
18 uint8_t opcode
= request
->request
.opcode
;
19 uint16_t keylen
= ntohs(request
->request
.keylen
);
20 uint8_t extlen
= request
->request
.extlen
;
21 uint32_t bodylen
= ntohl(request
->request
.bodylen
);
23 ensure(bodylen
>= (keylen
+ extlen
));
26 case PROTOCOL_BINARY_CMD_GET
:
27 case PROTOCOL_BINARY_CMD_GETK
:
28 case PROTOCOL_BINARY_CMD_GETKQ
:
29 case PROTOCOL_BINARY_CMD_GETQ
:
32 ensure(keylen
== bodylen
);
33 ensure(request
->request
.cas
== 0);
36 case PROTOCOL_BINARY_CMD_ADD
:
37 case PROTOCOL_BINARY_CMD_ADDQ
:
38 /* it makes no sense to run add with a cas value */
39 ensure(request
->request
.cas
== 0);
41 case PROTOCOL_BINARY_CMD_SET
:
42 case PROTOCOL_BINARY_CMD_SETQ
:
43 case PROTOCOL_BINARY_CMD_REPLACE
:
44 case PROTOCOL_BINARY_CMD_REPLACEQ
:
49 case PROTOCOL_BINARY_CMD_DELETE
:
50 case PROTOCOL_BINARY_CMD_DELETEQ
:
53 ensure(keylen
== bodylen
);
56 case PROTOCOL_BINARY_CMD_INCREMENT
:
57 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
58 case PROTOCOL_BINARY_CMD_DECREMENT
:
59 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
62 ensure(keylen
+ extlen
== bodylen
);
65 case PROTOCOL_BINARY_CMD_QUIT
:
66 case PROTOCOL_BINARY_CMD_QUITQ
:
67 case PROTOCOL_BINARY_CMD_NOOP
:
68 case PROTOCOL_BINARY_CMD_VERSION
:
74 case PROTOCOL_BINARY_CMD_FLUSH
:
75 case PROTOCOL_BINARY_CMD_FLUSHQ
:
76 ensure(extlen
== 0 || extlen
== 4);
78 ensure(bodylen
== extlen
);
81 case PROTOCOL_BINARY_CMD_STAT
:
83 /* May have key, but not value */
84 ensure(keylen
== bodylen
);
87 case PROTOCOL_BINARY_CMD_APPEND
:
88 case PROTOCOL_BINARY_CMD_APPENDQ
:
89 case PROTOCOL_BINARY_CMD_PREPEND
:
90 case PROTOCOL_BINARY_CMD_PREPENDQ
:
102 bool memcached_binary_protocol_pedantic_check_response(const protocol_binary_request_header
*request
,
103 const protocol_binary_response_header
*response
)
105 ensure(response
->response
.magic
== PROTOCOL_BINARY_RES
);
106 ensure(response
->response
.datatype
== PROTOCOL_BINARY_RAW_BYTES
);
107 ensure(response
->response
.opaque
== request
->request
.opaque
);
109 uint16_t status
= ntohs(response
->response
.status
);
110 uint8_t opcode
= response
->response
.opcode
;
112 if (status
== PROTOCOL_BINARY_RESPONSE_SUCCESS
)
115 case PROTOCOL_BINARY_CMD_ADDQ
:
116 case PROTOCOL_BINARY_CMD_APPENDQ
:
117 case PROTOCOL_BINARY_CMD_DECREMENTQ
:
118 case PROTOCOL_BINARY_CMD_DELETEQ
:
119 case PROTOCOL_BINARY_CMD_FLUSHQ
:
120 case PROTOCOL_BINARY_CMD_INCREMENTQ
:
121 case PROTOCOL_BINARY_CMD_PREPENDQ
:
122 case PROTOCOL_BINARY_CMD_QUITQ
:
123 case PROTOCOL_BINARY_CMD_REPLACEQ
:
124 case PROTOCOL_BINARY_CMD_SETQ
:
125 /* Quiet command shouldn't return on success */
132 case PROTOCOL_BINARY_CMD_ADD
:
133 case PROTOCOL_BINARY_CMD_REPLACE
:
134 case PROTOCOL_BINARY_CMD_SET
:
135 case PROTOCOL_BINARY_CMD_APPEND
:
136 case PROTOCOL_BINARY_CMD_PREPEND
:
137 ensure(response
->response
.keylen
== 0);
138 ensure(response
->response
.extlen
== 0);
139 ensure(response
->response
.bodylen
== 0);
140 ensure(response
->response
.cas
!= 0);
142 case PROTOCOL_BINARY_CMD_FLUSH
:
143 case PROTOCOL_BINARY_CMD_NOOP
:
144 case PROTOCOL_BINARY_CMD_QUIT
:
145 case PROTOCOL_BINARY_CMD_DELETE
:
146 ensure(response
->response
.keylen
== 0);
147 ensure(response
->response
.extlen
== 0);
148 ensure(response
->response
.bodylen
== 0);
149 ensure(response
->response
.cas
== 0);
152 case PROTOCOL_BINARY_CMD_DECREMENT
:
153 case PROTOCOL_BINARY_CMD_INCREMENT
:
154 ensure(response
->response
.keylen
== 0);
155 ensure(response
->response
.extlen
== 0);
156 ensure(ntohl(response
->response
.bodylen
) == 8);
157 ensure(response
->response
.cas
!= 0);
160 case PROTOCOL_BINARY_CMD_STAT
:
161 ensure(response
->response
.extlen
== 0);
162 /* key and value exists in all packets except in the terminating */
163 ensure(response
->response
.cas
== 0);
166 case PROTOCOL_BINARY_CMD_VERSION
:
167 ensure(response
->response
.keylen
== 0);
168 ensure(response
->response
.extlen
== 0);
169 ensure(response
->response
.bodylen
!= 0);
170 ensure(response
->response
.cas
== 0);
173 case PROTOCOL_BINARY_CMD_GET
:
174 case PROTOCOL_BINARY_CMD_GETQ
:
175 ensure(response
->response
.keylen
== 0);
176 ensure(response
->response
.extlen
== 4);
177 ensure(response
->response
.cas
!= 0);
180 case PROTOCOL_BINARY_CMD_GETK
:
181 case PROTOCOL_BINARY_CMD_GETKQ
:
182 ensure(response
->response
.keylen
!= 0);
183 ensure(response
->response
.extlen
== 4);
184 ensure(response
->response
.cas
!= 0);
188 /* Undefined command code */
194 ensure(response
->response
.cas
== 0);
195 ensure(response
->response
.extlen
== 0);
196 if (opcode
!= PROTOCOL_BINARY_CMD_GETK
)
198 ensure(response
->response
.keylen
== 0);