src/libmemcachedprotocol: apply clang-format
[awesomized/libmemcached] / src / libmemcachedprotocol / pedantic.c
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "libmemcachedprotocol/common.h"
17
18 #include <sys/types.h>
19
20 #define ensure(a) \
21 if (!(a)) { \
22 return false; \
23 }
24
25 bool memcached_binary_protocol_pedantic_check_request(
26 const protocol_binary_request_header *request) {
27 ensure(request->request.magic == PROTOCOL_BINARY_REQ);
28 ensure(request->request.datatype == PROTOCOL_BINARY_RAW_BYTES);
29
30 ensure(request->bytes[6] == 0);
31 ensure(request->bytes[7] == 0);
32
33 uint8_t opcode = request->request.opcode;
34 uint16_t keylen = ntohs(request->request.keylen);
35 uint8_t extlen = request->request.extlen;
36 uint32_t bodylen = ntohl(request->request.bodylen);
37
38 ensure(bodylen >= (keylen + extlen));
39
40 switch (opcode) {
41 case PROTOCOL_BINARY_CMD_GET:
42 case PROTOCOL_BINARY_CMD_GETK:
43 case PROTOCOL_BINARY_CMD_GETKQ:
44 case PROTOCOL_BINARY_CMD_GETQ:
45 ensure(extlen == 0);
46 ensure(keylen > 0);
47 ensure(keylen == bodylen);
48 ensure(request->request.cas == 0);
49 break;
50
51 case PROTOCOL_BINARY_CMD_ADD:
52 case PROTOCOL_BINARY_CMD_ADDQ:
53 /* it makes no sense to run add with a cas value */
54 ensure(request->request.cas == 0);
55 /* FALLTHROUGH */
56 case PROTOCOL_BINARY_CMD_SET:
57 case PROTOCOL_BINARY_CMD_SETQ:
58 case PROTOCOL_BINARY_CMD_REPLACE:
59 case PROTOCOL_BINARY_CMD_REPLACEQ:
60 ensure(keylen > 0);
61 ensure(extlen == 8);
62 break;
63
64 case PROTOCOL_BINARY_CMD_DELETE:
65 case PROTOCOL_BINARY_CMD_DELETEQ:
66 ensure(extlen == 0);
67 ensure(keylen > 0);
68 ensure(keylen == bodylen);
69 break;
70
71 case PROTOCOL_BINARY_CMD_INCREMENT:
72 case PROTOCOL_BINARY_CMD_INCREMENTQ:
73 case PROTOCOL_BINARY_CMD_DECREMENT:
74 case PROTOCOL_BINARY_CMD_DECREMENTQ:
75 ensure(extlen == 20);
76 ensure(keylen > 0);
77 ensure(keylen + extlen == bodylen);
78 break;
79
80 case PROTOCOL_BINARY_CMD_QUIT:
81 case PROTOCOL_BINARY_CMD_QUITQ:
82 case PROTOCOL_BINARY_CMD_NOOP:
83 case PROTOCOL_BINARY_CMD_VERSION:
84 ensure(extlen == 0);
85 ensure(keylen == 0);
86 ensure(bodylen == 0);
87 break;
88
89 case PROTOCOL_BINARY_CMD_FLUSH:
90 case PROTOCOL_BINARY_CMD_FLUSHQ:
91 ensure(extlen == 0 || extlen == 4);
92 ensure(keylen == 0);
93 ensure(bodylen == extlen);
94 break;
95
96 case PROTOCOL_BINARY_CMD_STAT:
97 ensure(extlen == 0);
98 /* May have key, but not value */
99 ensure(keylen == bodylen);
100 break;
101
102 case PROTOCOL_BINARY_CMD_APPEND:
103 case PROTOCOL_BINARY_CMD_APPENDQ:
104 case PROTOCOL_BINARY_CMD_PREPEND:
105 case PROTOCOL_BINARY_CMD_PREPENDQ:
106 ensure(extlen == 0);
107 ensure(keylen > 0);
108 break;
109 default
110 :
111 /* Unknown command */
112 ;
113 }
114
115 return true;
116 }
117
118 bool memcached_binary_protocol_pedantic_check_response(
119 const protocol_binary_request_header *request,
120 const protocol_binary_response_header *response) {
121 ensure(response->response.magic == PROTOCOL_BINARY_RES);
122 ensure(response->response.datatype == PROTOCOL_BINARY_RAW_BYTES);
123 ensure(response->response.opaque == request->request.opaque);
124
125 uint16_t status = ntohs(response->response.status);
126 uint8_t opcode = response->response.opcode;
127
128 if (status == PROTOCOL_BINARY_RESPONSE_SUCCESS) {
129 switch (opcode) {
130 case PROTOCOL_BINARY_CMD_ADDQ:
131 case PROTOCOL_BINARY_CMD_APPENDQ:
132 case PROTOCOL_BINARY_CMD_DECREMENTQ:
133 case PROTOCOL_BINARY_CMD_DELETEQ:
134 case PROTOCOL_BINARY_CMD_FLUSHQ:
135 case PROTOCOL_BINARY_CMD_INCREMENTQ:
136 case PROTOCOL_BINARY_CMD_PREPENDQ:
137 case PROTOCOL_BINARY_CMD_QUITQ:
138 case PROTOCOL_BINARY_CMD_REPLACEQ:
139 case PROTOCOL_BINARY_CMD_SETQ:
140 /* Quiet command shouldn't return on success */
141 return false;
142 default: break;
143 }
144
145 switch (opcode) {
146 case PROTOCOL_BINARY_CMD_ADD:
147 case PROTOCOL_BINARY_CMD_REPLACE:
148 case PROTOCOL_BINARY_CMD_SET:
149 case PROTOCOL_BINARY_CMD_APPEND:
150 case PROTOCOL_BINARY_CMD_PREPEND:
151 ensure(response->response.keylen == 0);
152 ensure(response->response.extlen == 0);
153 ensure(response->response.bodylen == 0);
154 ensure(response->response.cas != 0);
155 break;
156 case PROTOCOL_BINARY_CMD_FLUSH:
157 case PROTOCOL_BINARY_CMD_NOOP:
158 case PROTOCOL_BINARY_CMD_QUIT:
159 case PROTOCOL_BINARY_CMD_DELETE:
160 ensure(response->response.keylen == 0);
161 ensure(response->response.extlen == 0);
162 ensure(response->response.bodylen == 0);
163 ensure(response->response.cas == 0);
164 break;
165
166 case PROTOCOL_BINARY_CMD_DECREMENT:
167 case PROTOCOL_BINARY_CMD_INCREMENT:
168 ensure(response->response.keylen == 0);
169 ensure(response->response.extlen == 0);
170 ensure(ntohl(response->response.bodylen) == 8);
171 ensure(response->response.cas != 0);
172 break;
173
174 case PROTOCOL_BINARY_CMD_STAT:
175 ensure(response->response.extlen == 0);
176 /* key and value exists in all packets except in the terminating */
177 ensure(response->response.cas == 0);
178 break;
179
180 case PROTOCOL_BINARY_CMD_VERSION:
181 ensure(response->response.keylen == 0);
182 ensure(response->response.extlen == 0);
183 ensure(response->response.bodylen != 0);
184 ensure(response->response.cas == 0);
185 break;
186
187 case PROTOCOL_BINARY_CMD_GET:
188 case PROTOCOL_BINARY_CMD_GETQ:
189 ensure(response->response.keylen == 0);
190 ensure(response->response.extlen == 4);
191 ensure(response->response.cas != 0);
192 break;
193
194 case PROTOCOL_BINARY_CMD_GETK:
195 case PROTOCOL_BINARY_CMD_GETKQ:
196 ensure(response->response.keylen != 0);
197 ensure(response->response.extlen == 4);
198 ensure(response->response.cas != 0);
199 break;
200
201 default:
202 /* Undefined command code */
203 break;
204 }
205 } else {
206 ensure(response->response.cas == 0);
207 ensure(response->response.extlen == 0);
208 if (opcode != PROTOCOL_BINARY_CMD_GETK) {
209 ensure(response->response.keylen == 0);
210 }
211 }
212
213 return true;
214 }