1 | /* |
2 | This file is part of Mtproto-proxy Library. |
3 | |
4 | Mtproto-proxy Library is free software: you can redistribute it and/or modify |
5 | it under the terms of the GNU Lesser General Public License as published by |
6 | the Free Software Foundation, either version 2 of the License, or |
7 | (at your option) any later version. |
8 | |
9 | Mtproto-proxy Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | GNU Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with Mtproto-proxy Library. If not, see <http://www.gnu.org/licenses/>. |
16 | |
17 | Copyright 2012-2013 Vkontakte Ltd |
18 | 2012-2013 Vitaliy Valtman |
19 | |
20 | Copyright 2014 Telegram Messenger Inc |
21 | 2014 Vitaly Valtman |
22 | */ |
23 | |
24 | #pragma once |
25 | |
26 | #include <assert.h> |
27 | #include <string.h> |
28 | |
29 | #include "net/net-connections.h" |
30 | |
31 | #include "rpc-const.h" |
32 | #include "jobs/jobs.h" |
33 | |
34 | //#define RPC_INVOKE_REQ 0x2374df3d |
35 | //#define RPC_REQ_RESULT 0x63aeda4e |
36 | //#define RPC_REQ_ERROR 0x7ae432f5 |
37 | |
38 | #define TL_FETCH_FLAG_ALLOW_DATA_AFTER_QUERY 1 |
39 | |
40 | #define TL_ENGINE_NOP 0x166bb7c6 |
41 | |
42 | #define TLF_CRC32 1 |
43 | #define TLF_PERMANENT 2 |
44 | #define TLF_ALLOW_PREPEND 4 |
45 | #define TLF_DISABLE_PREPEND 8 |
46 | #define TLF_NOALIGN 16 |
47 | #define TLF_NO_AUTOFLUSH 32 |
48 | |
49 | |
50 | struct tl_query_header; |
51 | struct tl_query_header * (struct tl_query_header *h); |
52 | struct tl_query_header * (struct tl_query_header *h_old); |
53 | void (struct tl_query_header *h); |
54 | |
55 | |
56 | #define RPC_REQ_ERROR_WRAPPED (RPC_REQ_ERROR + 1) |
57 | |
58 | extern long long rpc_queries_received, rpc_queries_ok, rpc_queries_error; |
59 | |
60 | struct tl_in_state; |
61 | struct tl_out_state; |
62 | struct tl_in_methods { |
63 | void (*fetch_raw_data)(struct tl_in_state *tlio, void *buf, int len); |
64 | void (*fetch_move)(struct tl_in_state *tlio, int len); |
65 | void (*fetch_lookup)(struct tl_in_state *tlio, void *buf, int len); |
66 | void (*fetch_clear)(struct tl_in_state *tlio); |
67 | void (*fetch_mark)(struct tl_in_state *tlio); |
68 | void (*fetch_mark_restore)(struct tl_in_state *tlio); |
69 | void (*fetch_mark_delete)(struct tl_in_state *tlio); |
70 | void (*fetch_raw_message)(struct tl_in_state *tlio, struct raw_message *raw, int len); |
71 | void (*fetch_lookup_raw_message)(struct tl_in_state *tlio, struct raw_message *raw, int len); |
72 | int flags; |
73 | int prepend_bytes; |
74 | }; |
75 | |
76 | struct tl_out_methods { |
77 | void *(*store_get_ptr)(struct tl_out_state *tlio, int len); |
78 | void *(*store_get_prepend_ptr)(struct tl_out_state *tlio, int len); |
79 | void (*store_raw_data)(struct tl_out_state *tlio, const void *buf, int len); |
80 | void (*store_raw_msg)(struct tl_out_state *tlio, struct raw_message *raw); |
81 | void (*store_read_back)(struct tl_out_state *tlio, int len); |
82 | void (*store_read_back_nondestruct)(struct tl_out_state *tlio, void *buf, int len); |
83 | unsigned (*store_crc32_partial)(struct tl_out_state *tlio, int len, unsigned start); |
84 | void (*store_flush)(struct tl_out_state *tlio); |
85 | void (*store_clear)(struct tl_out_state *tlio); |
86 | void (*copy_through[10])(struct tl_in_state *tlio_src, struct tl_out_state *tlio_dst, int len, int advance); |
87 | void (*store_prefix)(struct tl_out_state *tlio); |
88 | int flags; |
89 | int prepend_bytes; |
90 | }; |
91 | |
92 | enum tl_type { |
93 | tl_type_none, |
94 | tl_type_str, |
95 | //tl_type_conn, |
96 | //tl_type_nbit, |
97 | tl_type_raw_msg, |
98 | tl_type_tcp_raw_msg, |
99 | }; |
100 | |
101 | struct tl_in_state { |
102 | enum tl_type in_type; |
103 | const struct tl_in_methods *in_methods; |
104 | |
105 | void *in; |
106 | void *in_mark; |
107 | |
108 | int in_remaining; |
109 | int in_pos; |
110 | int in_mark_pos; |
111 | int in_flags; |
112 | |
113 | char *error; |
114 | int errnum; |
115 | |
116 | struct process_id in_pid_buf; |
117 | struct process_id *in_pid; |
118 | }; |
119 | |
120 | struct tl_out_state { |
121 | enum tl_type out_type; |
122 | const struct tl_out_methods *out_methods; |
123 | void *out; |
124 | void *; |
125 | int out_pos; |
126 | int out_remaining; |
127 | int *out_size; |
128 | |
129 | char *error; |
130 | int errnum; |
131 | |
132 | long long out_qid; |
133 | |
134 | struct process_id out_pid_buf; |
135 | struct process_id *out_pid; |
136 | }; |
137 | |
138 | struct query_work_params; |
139 | |
140 | struct { |
141 | long long ; |
142 | long long ; |
143 | int ; |
144 | int ; |
145 | int ; |
146 | int ; |
147 | struct query_work_params *; |
148 | }; |
149 | |
150 | extern const struct tl_in_methods tl_in_conn_methods; |
151 | extern const struct tl_in_methods tl_in_nbit_methods; |
152 | extern const struct tl_in_methods tl_in_raw_msg_methods; |
153 | extern const struct tl_out_methods tl_out_conn_methods; |
154 | extern const struct tl_out_methods tl_out_raw_msg_methods; |
155 | |
156 | #define TL_IN (tlio_in->in) |
157 | #define TL_IN_CONN ((connection_job_t)(tlio_in->in)) |
158 | #define TL_IN_NBIT ((nb_iterator_t *)(tlio_in->in)) |
159 | #define TL_IN_RAW_MSG ((struct raw_message *)(tlio_in->in)) |
160 | #define TL_IN_STR ((char *)(tlio_in->in)) |
161 | #define TL_IN_TYPE (tlio_in->in_type) |
162 | #define TL_IN_REMAINING (tlio_in->in_remaining) |
163 | #define TL_IN_POS (tlio_in->in_pos) |
164 | #define TL_IN_METHODS (tlio_in->in_methods) |
165 | #define TL_IN_MARK (tlio_in->in_mark) |
166 | #define TL_IN_MARK_POS (tlio_in->in_mark_pos) |
167 | #define TL_IN_PID (tlio_in->in_pid) |
168 | #define TL_IN_FLAGS (tlio_in->in_methods->flags) |
169 | #define TL_IN_CUR_FLAGS (tlio_in->in_flags) |
170 | |
171 | #define TL_OUT ((tlio_out->out)) |
172 | #define TL_OUT_TYPE (tlio_out->out_type) |
173 | #define TL_OUT_SIZE (tlio_out->out_size) |
174 | #define TL_OUT_CONN ((connection_job_t)(tlio_out->out)) |
175 | #define TL_OUT_RAW_MSG ((struct raw_message *)(tlio_out->out)) |
176 | #define TL_OUT_STR ((char *)(tlio_out->out)) |
177 | #define TL_OUT_POS (tlio_out->out_pos) |
178 | #define TL_OUT_REMAINING (tlio_out->out_remaining) |
179 | #define TL_OUT_METHODS (tlio_out->out_methods) |
180 | #define TL_OUT_QID (tlio_out->out_qid) |
181 | #define (tlio_out->out_extra) |
182 | #define TL_OUT_PID (tlio_out->out_pid) |
183 | #define TL_OUT_FLAGS (tlio_out->out_methods->flags) |
184 | |
185 | #define TL_ERROR (tlio_in->error) |
186 | #define TL_ERRNUM (tlio_in->errnum) |
187 | |
188 | //#define TL_COPY_THROUGH (tlio->copy_through) |
189 | |
190 | //#define TL_ATTEMPT_NUM (tlio)->attempt_num |
191 | |
192 | |
193 | int tlf_set_error_format (struct tl_in_state *tlio_in, int errnum, const char *format, ...) __attribute__ (( format(printf,3,4) )); |
194 | #define tl_fetch_set_error_format(...) tlf_set_error_format (tlio_in, ## __VA_ARGS__) |
195 | int tlf_set_error (struct tl_in_state *tlio_in, int errnum, const char *s); |
196 | #define tl_fetch_set_error(...) tlf_set_error (tlio_in, ## __VA_ARGS__) |
197 | |
198 | int tls_set_error_format (struct tl_out_state *tlio_out, int errnum, const char *format, ...) __attribute__ (( format(printf,3,4) )); |
199 | #define tl_store_set_error_format(...) tls_set_error_format (tlio_out, ## __VA_ARGS__) |
200 | |
201 | //int tlf_init_connection (struct tl_in_state *tlio_in, connection_job_t c, int size); |
202 | //int tlf_init_iterator (struct tl_in_state *tlio_in, nb_iterator_t *it, int size); |
203 | //int tlf_init_iterator_noskip (struct tl_in_state *tlio_in, nb_iterator_t *it, int size); |
204 | // dup = 0 - delete reference |
205 | // dup = 1 - make msg valid raw message of size 0 |
206 | // dup = 2 - clone message |
207 | int tlf_init_raw_message (struct tl_in_state *tlio_in, struct raw_message *msg, int size, int dup); |
208 | |
209 | int tlf_init_str (struct tl_in_state *tlio_in, const char *s, int size); |
210 | |
211 | //int tls_init_connection (struct tl_out_state *tlio_out, connection_job_t c, long long qid); |
212 | //int tls_init_connection_keep_error (struct tl_out_state *tlio_out, connection_job_t c, long long qid); |
213 | int tls_init_raw_msg (struct tl_out_state *tlio_out, struct process_id *pid, long long qid); |
214 | //int tls_init_raw_msg_keep_error (struct tl_out_state *tlio_out, struct process_id *pid, long long qid); |
215 | int tls_init_tcp_raw_msg (struct tl_out_state *tlio_out, JOB_REF_ARG (c), long long qid); |
216 | int tls_init_tcp_raw_msg_unaligned (struct tl_out_state *tlio_out, JOB_REF_ARG (c), long long qid); |
217 | //int tls_init_tcp_raw_msg_keep_error (struct tl_out_state *tlio_out, connection_job_t c, long long qid); |
218 | //int tls_init_simple (struct tl_out_state *tlio_out, connection_job_t c); |
219 | int tls_init_str (struct tl_out_state *tlio_out, char *s, long long qid, int size); |
220 | //int tls_init_str_keep_error (struct tl_out_state *tlio_out, char *s, long long qid, int size); |
221 | //int tls_init_any_keep_error (struct tl_out_state *tlio_out, enum tl_type type, void *out, long long qid); |
222 | int tls_init_raw_msg_nosend (struct tl_out_state *tlio_out); |
223 | //int tls_init_any (struct tl_out_state *tlio, enum tl_type type, void *out, long long qid); |
224 | int tls_init (struct tl_out_state *tlio_out, enum tl_type type, struct process_id *pid, long long qid); |
225 | //int tls_init_keep_error (struct tl_out_state *tlio_out, enum tl_type type, struct process_id *pid, long long qid); |
226 | |
227 | |
228 | int tlf_query_flags (struct tl_in_state *tlio_in, struct tl_query_header *); |
229 | int (struct tl_in_state *tlio_in, struct tl_query_header *); |
230 | int tlf_query_answer_flags (struct tl_in_state *tlio_in, struct tl_query_header *); |
231 | int (struct tl_in_state *tlio_in, struct tl_query_header *); |
232 | int (struct tl_out_state *tlio_out, struct tl_query_header *); |
233 | |
234 | int tls_end_ext (struct tl_out_state *tlio_out, int op); |
235 | |
236 | static inline int tlf_init_empty (struct tl_in_state *tlio_in) { |
237 | return tlf_init_str (tlio_in, "" , 0); |
238 | } |
239 | |
240 | static inline int tl_store_end_simple (struct tl_out_state *tlio_out) { |
241 | return tls_end_ext (tlio_out, 0); |
242 | } |
243 | #define tl_store_end_ext(type) tls_end_ext(tlio_out,type) |
244 | |
245 | static inline int tlf_check (struct tl_in_state *tlio_in, int nbytes) /* {{{ */ { |
246 | if (!TL_IN_TYPE) { |
247 | tlf_set_error (tlio_in, TL_ERROR_INTERNAL, "Trying to read from unitialized in buffer" ); |
248 | return -1; |
249 | } |
250 | if (nbytes >= 0) { |
251 | if (TL_IN_REMAINING < nbytes) { |
252 | tlf_set_error_format (tlio_in, TL_ERROR_NOT_ENOUGH_DATA, "Trying to read %d bytes at position %d (size = %d)" , nbytes, TL_IN_POS, TL_IN_POS + TL_IN_REMAINING); |
253 | return -1; |
254 | } |
255 | } else { |
256 | if (TL_IN_POS < -nbytes) { |
257 | tlf_set_error_format (tlio_in, TL_ERROR_NOT_ENOUGH_DATA, "Trying to read %d bytes at position %d (size = %d)" , nbytes, TL_IN_POS, TL_IN_POS + TL_IN_REMAINING); |
258 | return -1; |
259 | } |
260 | } |
261 | if (TL_ERROR) { |
262 | return -1; |
263 | } |
264 | return 0; |
265 | } |
266 | /* }}} */ |
267 | |
268 | inline static void __tlf_raw_data (struct tl_in_state *tlio_in, void *buf, int size) /* {{{ */ { |
269 | TL_IN_METHODS->fetch_raw_data (tlio_in, buf, size); |
270 | TL_IN_POS += size; |
271 | TL_IN_REMAINING -= size; |
272 | } |
273 | /* }}} */ |
274 | |
275 | inline static void __tlf_skip_raw_data (struct tl_in_state *tlio_in, int size) /* {{{ */ { |
276 | TL_IN_METHODS->fetch_move (tlio_in, size); |
277 | TL_IN_POS += size; |
278 | TL_IN_REMAINING -= size; |
279 | } |
280 | /* }}} */ |
281 | |
282 | static inline int tlf_lookup_int (struct tl_in_state *tlio_in) /* {{{ */ { |
283 | if (tlf_check (tlio_in, 4) < 0) { |
284 | return -1; |
285 | } |
286 | int x; |
287 | TL_IN_METHODS->fetch_lookup (tlio_in, &x, 4); |
288 | return x; |
289 | } |
290 | /* }}} */ |
291 | #define tl_fetch_lookup_int(...) tlf_lookup_int (tlio_in, ## __VA_ARGS__) |
292 | |
293 | static inline int tlf_lookup_second_int (struct tl_in_state *tlio_in) /* {{{ */ { |
294 | if (tlf_check (tlio_in, 8) < 0) { |
295 | return -1; |
296 | } |
297 | int x[2]; |
298 | TL_IN_METHODS->fetch_lookup (tlio_in, x, 8); |
299 | return x[1]; |
300 | } |
301 | /* }}} */ |
302 | #define tl_fetch_lookup_second_int(...) tlf_lookup_second_int (tlio_in, ## __VA_ARGS__) |
303 | |
304 | static inline long long tlf_lookup_long (struct tl_in_state *tlio_in) /* {{{ */ { |
305 | if (tlf_check (tlio_in, 8) < 0) { |
306 | return -1; |
307 | } |
308 | long long x; |
309 | TL_IN_METHODS->fetch_lookup (tlio_in, &x, 8); |
310 | return x; |
311 | } |
312 | /* }}} */ |
313 | #define tl_fetch_lookup_long(...) tlf_lookup_long (tlio_in, ## __VA_ARGS__) |
314 | |
315 | static inline int tlf_lookup_data (struct tl_in_state *tlio_in, void *data, int len) /* {{{ */ { |
316 | if (tlf_check (tlio_in, len) < 0) { |
317 | return -1; |
318 | } |
319 | TL_IN_METHODS->fetch_lookup (tlio_in, data, len); |
320 | return len; |
321 | } |
322 | /* }}} */ |
323 | #define tl_fetch_lookup_data(...) tlf_lookup_data (tlio_in, ## __VA_ARGS__) |
324 | |
325 | static inline int tlf_int (struct tl_in_state *tlio_in) /* {{{ */ { |
326 | if (__builtin_expect (tlf_check (tlio_in, 4) < 0, 0)) { |
327 | return -1; |
328 | } |
329 | int x; |
330 | __tlf_raw_data (tlio_in, &x, 4); |
331 | return x; |
332 | } |
333 | /* }}} */ |
334 | #define tl_fetch_int(...) tlf_int (tlio_in, ## __VA_ARGS__) |
335 | |
336 | static inline double tlf_double (struct tl_in_state *tlio_in) /* {{{ */ { |
337 | if (__builtin_expect (tlf_check (tlio_in, sizeof (double)) < 0, 0)) { |
338 | return -1; |
339 | } |
340 | double x; |
341 | __tlf_raw_data (tlio_in, &x, sizeof (x)); |
342 | return x; |
343 | } |
344 | /* }}} */ |
345 | #define tl_fetch_double(...) tlf_double (tlio_in, ## __VA_ARGS__) |
346 | |
347 | static inline long long tlf_long (struct tl_in_state *tlio_in) /* {{{ */ { |
348 | if (__builtin_expect (tlf_check (tlio_in, 8) < 0, 0)) { |
349 | return -1; |
350 | } |
351 | long long x; |
352 | __tlf_raw_data (tlio_in, &x, 8); |
353 | return x; |
354 | } |
355 | /* }}} */ |
356 | #define tl_fetch_long(...) tlf_long (tlio_in, ## __VA_ARGS__) |
357 | |
358 | static inline void tlf_mark (struct tl_in_state *tlio_in) /* {{{ */ { |
359 | TL_IN_METHODS->fetch_mark (tlio_in); |
360 | } |
361 | /* }}} */ |
362 | #define tl_fetch_mark(...) tlf_mark (tlio_in, ## __VA_ARGS__) |
363 | |
364 | static inline void tlf_mark_restore (struct tl_in_state *tlio_in) /* {{{ */ { |
365 | TL_IN_METHODS->fetch_mark_restore (tlio_in); |
366 | } |
367 | /* }}} */ |
368 | #define tl_fetch_mark_restore(...) tlf_mark_restore (tlio_in, ## __VA_ARGS__) |
369 | |
370 | static inline void tlf_mark_delete (struct tl_in_state *tlio_in) /* {{{ */ { |
371 | TL_IN_METHODS->fetch_mark_delete (tlio_in); |
372 | } |
373 | /* }}} */ |
374 | #define tl_fetch_mark_delete(...) tlf_mark_delete (tlio_in, ## __VA_ARGS__) |
375 | |
376 | static inline int tlf_string_len (struct tl_in_state *tlio_in, int max_len) /* {{{ */ { |
377 | if (tlf_check (tlio_in, 4) < 0) { |
378 | return -1; |
379 | } |
380 | int x = 0; |
381 | __tlf_raw_data (tlio_in, &x, 1); |
382 | if (x == 255) { |
383 | tlf_set_error (tlio_in, TL_ERROR_SYNTAX, "String len can not start with 0xff" ); |
384 | return -1; |
385 | } |
386 | if (x == 254) { |
387 | __tlf_raw_data (tlio_in, &x, 3); |
388 | } |
389 | if (x > max_len) { |
390 | tlf_set_error_format (tlio_in, TL_ERROR_TOO_LONG_STRING, "string is too long: max_len = %d, len = %d" , max_len, x); |
391 | return -1; |
392 | } |
393 | if (x > TL_IN_REMAINING) { |
394 | tlf_set_error_format (tlio_in, TL_ERROR_NOT_ENOUGH_DATA, "string is too long: remaining_bytes = %d, len = %d" , TL_IN_REMAINING, x); |
395 | return -1; |
396 | } |
397 | return x; |
398 | } |
399 | /* }}} */ |
400 | #define tl_fetch_string_len(...) tlf_string_len (tlio_in, ## __VA_ARGS__) |
401 | |
402 | static inline int tlf_pad (struct tl_in_state *tlio_in) /* {{{ */ { |
403 | int pad = (-TL_IN_POS) & 3; |
404 | if (tlf_check (tlio_in, pad) < 0) { |
405 | return -1; |
406 | } |
407 | int t = 0; |
408 | assert (TL_IN_REMAINING >= pad); |
409 | __tlf_raw_data (tlio_in, &t, pad); |
410 | if (t) { |
411 | tlf_set_error (tlio_in, TL_ERROR_SYNTAX, "Padding with non-zeroes" ); |
412 | return -1; |
413 | } |
414 | return pad; |
415 | } |
416 | /* }}} */ |
417 | #define tl_fetch_pad(...) tlf_pad (tlio_in, ## __VA_ARGS__) |
418 | |
419 | static inline int tlf_raw_data (struct tl_in_state *tlio_in, void *buf, int len) /* {{{ */ { |
420 | assert (!(len & 3)); |
421 | if (tlf_check (tlio_in, len) < 0) { |
422 | return -1; |
423 | } |
424 | __tlf_raw_data (tlio_in, buf, len); |
425 | return len; |
426 | } |
427 | /* }}} */ |
428 | #define tl_fetch_raw_data(...) tlf_raw_data (tlio_in, ## __VA_ARGS__) |
429 | |
430 | static inline int tlf_string_data (struct tl_in_state *tlio_in, char *buf, int len) /* {{{ */ { |
431 | if (tlf_check (tlio_in, len) < 0) { |
432 | return -1; |
433 | } |
434 | __tlf_raw_data (tlio_in, buf, len); |
435 | if (tlf_pad (tlio_in) < 0) { |
436 | return -1; |
437 | } |
438 | return len; |
439 | } |
440 | /* }}} */ |
441 | #define tl_fetch_string_data(...) tlf_string_data (tlio_in, ## __VA_ARGS__) |
442 | |
443 | static inline int tlf_skip_string_data (struct tl_in_state *tlio_in, int len) /* {{{ */ { |
444 | if (tlf_check (tlio_in, len) < 0) { |
445 | return -1; |
446 | } |
447 | __tlf_skip_raw_data (tlio_in, len); |
448 | if (tlf_pad (tlio_in) < 0) { |
449 | return -1; |
450 | } |
451 | return len; |
452 | } |
453 | /* }}} */ |
454 | #define tl_fetch_skip_string_data(...) tlf_skip_string_data (tlio_in, ## __VA_ARGS__) |
455 | |
456 | static inline int tlf_string (struct tl_in_state *tlio_in, char *buf, int max_len) /* {{{ */ { |
457 | int l = tlf_string_len (tlio_in, max_len); |
458 | if (l < 0) { |
459 | return -1; |
460 | } |
461 | if (tlf_string_data (tlio_in, buf, l) < 0) { |
462 | return -1; |
463 | } |
464 | return l; |
465 | } |
466 | /* }}} */ |
467 | #define tl_fetch_string(...) tlf_string (tlio_in, ## __VA_ARGS__) |
468 | |
469 | static inline int tlf_skip_string (struct tl_in_state *tlio_in, int max_len) /* {{{ */ { |
470 | int l = tlf_string_len (tlio_in, max_len); |
471 | if (l < 0) { |
472 | return -1; |
473 | } |
474 | if (tlf_skip_string_data (tlio_in, l) < 0) { |
475 | return -1; |
476 | } |
477 | return l; |
478 | } |
479 | /* }}} */ |
480 | #define tl_fetch_skip_string(...) tlf_skip_string (tlio_in, ## __VA_ARGS__) |
481 | |
482 | static inline int tlf_string0 (struct tl_in_state *tlio_in, char *buf, int max_len) /* {{{ */ { |
483 | int l = tlf_string_len (tlio_in, max_len); |
484 | if (l < 0) { |
485 | return -1; |
486 | } |
487 | if (tlf_string_data (tlio_in, buf, l) < 0) { |
488 | return -1; |
489 | } |
490 | buf[l] = 0; |
491 | return l; |
492 | } |
493 | /* }}} */ |
494 | #define tl_fetch_string0(...) tlf_string0 (tlio_in, ## __VA_ARGS__) |
495 | |
496 | static inline int tlf_error (struct tl_in_state *tlio_in) /* {{{ */{ |
497 | return TL_ERROR != 0; |
498 | } |
499 | /* }}} */ |
500 | #define tl_fetch_error(...) tlf_error (tlio_in, ## __VA_ARGS__) |
501 | |
502 | static inline int tlf_end (struct tl_in_state *tlio_in) /* {{{ */ { |
503 | if (TL_IN_REMAINING && !(TL_IN_CUR_FLAGS & (TL_FETCH_FLAG_ALLOW_DATA_AFTER_QUERY))) { |
504 | tlf_set_error_format (tlio_in, TL_ERROR_EXTRA_DATA, "extra %d bytes after query" , TL_IN_REMAINING); |
505 | return -1; |
506 | } |
507 | return 1; |
508 | } |
509 | /* }}} */ |
510 | #define tl_fetch_end(...) tlf_end (tlio_in, ## __VA_ARGS__) |
511 | |
512 | static inline int tlf_check_str_end (struct tl_in_state *tlio_in, int size) /* {{{ */ { |
513 | if (TL_IN_REMAINING != size + ((-size - TL_IN_POS) & 3)) { |
514 | tlf_set_error_format (tlio_in, TL_ERROR_EXTRA_DATA, "extra %d bytes after query" , TL_IN_REMAINING - size - ((-size - TL_IN_POS) & 3)); |
515 | return -1; |
516 | } |
517 | return 1; |
518 | } |
519 | /* }}} */ |
520 | #define tl_fetch_check_str_end(...) tlf_check_str_end (tlio_in, ## __VA_ARGS__) |
521 | |
522 | static inline int tlf_unread (struct tl_in_state *tlio_in) /* {{{ */ { |
523 | return TL_IN_REMAINING; |
524 | } |
525 | /* }}} */ |
526 | #define tl_fetch_unread(...) tlf_unread (tlio_in, ## __VA_ARGS__) |
527 | |
528 | static inline int tlf_skip (struct tl_in_state *tlio_in, int len) /* {{{ */ { |
529 | if (tlf_check (tlio_in, len) < 0) { |
530 | return -1; |
531 | } |
532 | __tlf_skip_raw_data (tlio_in, len); |
533 | return len; |
534 | } |
535 | /* }}} */ |
536 | #define tl_fetch_skip(...) tlf_skip (tlio_in, ## __VA_ARGS__) |
537 | /* |
538 | static inline int tl_fetch_move (int offset) { |
539 | if (tl_fetch_check (offset) < 0) { |
540 | return -1; |
541 | } |
542 | TL_IN_METHODS->fetch_move (offset); |
543 | TL_IN_POS += offset; |
544 | TL_IN_REMAINING -= offset; |
545 | return offset; |
546 | }*/ |
547 | |
548 | static inline int tls_check (struct tl_out_state *tlio_out, int size) /* {{{ */ { |
549 | if (TL_OUT_TYPE == tl_type_none) { return -1; } |
550 | if (TL_OUT_REMAINING < size) { return -1; } |
551 | return 0; |
552 | } |
553 | /* }}} */ |
554 | |
555 | static inline void __tls_raw_data (struct tl_out_state *tlio_out, const void *buf, int len) /* {{{ */ { |
556 | TL_OUT_METHODS->store_raw_data (tlio_out, buf, len); |
557 | TL_OUT_POS += len; |
558 | TL_OUT_REMAINING -= len; |
559 | } |
560 | /* }}} */ |
561 | |
562 | static inline void *tls_get_ptr (struct tl_out_state *tlio_out, int size) /* {{{ */ { |
563 | assert (tls_check (tlio_out, size) >= 0); |
564 | if (!size) { return 0; } |
565 | assert (size >= 0); |
566 | void *x = TL_OUT_METHODS->store_get_ptr (tlio_out, size); |
567 | TL_OUT_POS += size; |
568 | TL_OUT_REMAINING -= size; |
569 | return x; |
570 | } |
571 | /* }}} */ |
572 | #define tl_store_get_ptr(...) tls_get_ptr (tlio_out, ## __VA_ARGS__) |
573 | |
574 | static inline void *tls_get_prepend_ptr (struct tl_out_state *tlio_out, int size) /* {{{ */ { |
575 | assert (tls_check (tlio_out, size) >= 0); |
576 | if (!size) { return 0; } |
577 | assert (size >= 0); |
578 | void *x = TL_OUT_METHODS->store_get_prepend_ptr (tlio_out, size); |
579 | TL_OUT_POS += size; |
580 | TL_OUT_REMAINING -= size; |
581 | return x; |
582 | } |
583 | /* }}} */ |
584 | #define tl_store_get_prepend_ptr(...) tls_get_prepend_ptr (tlio_out, ## __VA_ARGS__) |
585 | |
586 | static inline int tls_int (struct tl_out_state *tlio_out, int x) /* {{{ */ { |
587 | assert (tls_check (tlio_out, 4) >= 0); |
588 | __tls_raw_data (tlio_out, &x, 4); |
589 | return 0; |
590 | } |
591 | /* }}} */ |
592 | #define tl_store_int(...) tls_int (tlio_out, ## __VA_ARGS__) |
593 | |
594 | static inline int tls_long (struct tl_out_state *tlio_out, long long x) /* {{{ */ { |
595 | assert (tls_check (tlio_out, 8) >= 0); |
596 | __tls_raw_data (tlio_out, &x, 8); |
597 | return 0; |
598 | } |
599 | /* }}} */ |
600 | #define tl_store_long(...) tls_long (tlio_out, ## __VA_ARGS__) |
601 | |
602 | static inline int tls_double (struct tl_out_state *tlio_out, double x) /* {{{ */ { |
603 | assert (tls_check (tlio_out, 8) >= 0); |
604 | __tls_raw_data (tlio_out, &x, 8); |
605 | return 0; |
606 | } |
607 | /* }}} */ |
608 | #define tl_store_double(...) tls_double (tlio_out, ## __VA_ARGS__) |
609 | |
610 | static inline int tls_string_len (struct tl_out_state *tlio_out, int len) /* {{{ */ { |
611 | assert (tls_check (tlio_out, 4) >= 0); |
612 | assert (len >= 0); |
613 | if (len < 254) { |
614 | __tls_raw_data (tlio_out, &len, 1); |
615 | } else { |
616 | assert (len < (1 << 24)); |
617 | int x = (len << 8) + 0xfe; |
618 | __tls_raw_data (tlio_out, &x, 4); |
619 | } |
620 | return 0; |
621 | } |
622 | /* }}} */ |
623 | #define tl_store_string_len(...) tls_string_len (tlio_out, ## __VA_ARGS__) |
624 | |
625 | static inline int tls_raw_msg (struct tl_out_state *tlio_out, struct raw_message *raw, int dup) /* {{{ */ { |
626 | assert (tls_check (tlio_out, raw->total_bytes) >= 0); |
627 | int len = raw->total_bytes; |
628 | if (!dup) { |
629 | TL_OUT_METHODS->store_raw_msg (tlio_out, raw); |
630 | } else { |
631 | struct raw_message r; |
632 | rwm_clone (&r, raw); |
633 | TL_OUT_METHODS->store_raw_msg (tlio_out, &r); |
634 | } |
635 | TL_OUT_POS += len; |
636 | TL_OUT_REMAINING -= len; |
637 | return 0; |
638 | } |
639 | /* }}} */ |
640 | #define tl_store_raw_msg(...) tls_raw_msg (tlio_out, ## __VA_ARGS__) |
641 | |
642 | static inline int tls_pad (struct tl_out_state *tlio_out) /* {{{ */ { |
643 | assert (tls_check (tlio_out, 0) >= 0); |
644 | int x = 0; |
645 | int pad = (-TL_OUT_POS) & 3; |
646 | __tls_raw_data (tlio_out, &x, pad); |
647 | return 0; |
648 | } |
649 | /* }}} */ |
650 | #define tl_store_pad(...) tls_pad (tlio_out, ## __VA_ARGS__) |
651 | |
652 | static inline int tls_raw_data (struct tl_out_state *tlio_out, const void *s, int len) /* {{{ */ { |
653 | //assert (!(len & 3)); |
654 | assert (tls_check (tlio_out, len) >= 0); |
655 | __tls_raw_data (tlio_out, s, len); |
656 | return len; |
657 | } |
658 | /* }}} */ |
659 | #define tl_store_raw_data(...) tls_raw_data (tlio_out, ## __VA_ARGS__) |
660 | |
661 | static inline int tls_string_data (struct tl_out_state *tlio_out, const char *s, int len) /* {{{ */ { |
662 | assert (tls_check (tlio_out, len) >= 0); |
663 | __tls_raw_data (tlio_out, s, len); |
664 | tls_pad (tlio_out); |
665 | return 0; |
666 | } |
667 | /* }}} */ |
668 | #define tl_store_string_data(...) tls_string_data (tlio_out, ## __VA_ARGS__) |
669 | |
670 | static inline int tls_string (struct tl_out_state *tlio_out, const char *s, int len) /* {{{ */ { |
671 | tls_string_len (tlio_out, len); |
672 | tls_string_data (tlio_out, s, len); |
673 | return 0; |
674 | } |
675 | /* }}} */ |
676 | #define tls_string0(tlio_out,_s) tls_string (tlio_out, _s, strlen (_s)) |
677 | #define tl_store_string(...) tls_string (tlio_out, ## __VA_ARGS__) |
678 | #define tl_store_string0(s) tl_store_string(s, strlen (s)) |
679 | |
680 | static inline int tls_clear (struct tl_out_state *tlio_out) /* {{{ */ { |
681 | assert (TL_OUT); |
682 | TL_OUT_METHODS->store_clear (tlio_out); |
683 | TL_OUT = 0; |
684 | TL_OUT_TYPE = tl_type_none; |
685 | TL_OUT_EXTRA = 0; |
686 | return 0; |
687 | } |
688 | /* }}} */ |
689 | #define tl_store_clear(...) tls_clear (tlio_out, ## __VA_ARGS__) |
690 | |
691 | static inline int tls_clean (struct tl_out_state *tlio_out) /* {{{ */ { |
692 | assert (TL_OUT); |
693 | TL_OUT_METHODS->store_read_back (tlio_out, TL_OUT_POS); |
694 | TL_OUT_REMAINING += TL_OUT_POS; |
695 | TL_OUT_POS = 0; |
696 | return 0; |
697 | } |
698 | /* }}} */ |
699 | #define tl_store_clean(...) tls_clean (tlio_out, ## __VA_ARGS__) |
700 | |
701 | /*static inline int tl_store_read_back_nondestruct (struct tchar *buf, int size) { |
702 | assert (size <= TL_OUT_POS); |
703 | TL_OUT_METHODS->store_read_back_nondestruct (buf, size); |
704 | return size; |
705 | }*/ |
706 | |
707 | #define tl_store_end() tl_store_end_ext(RPC_REQ_RESULT) |
708 | |
709 | static inline int tl_copy_through (struct tl_in_state *tlio_in, struct tl_out_state *tlio_out, int len, int advance) /* {{{ */ { |
710 | if (TL_IN_TYPE == tl_type_none || TL_OUT_TYPE == tl_type_none) { |
711 | return -1; |
712 | } |
713 | if (tlf_check (tlio_in, len) < 0 || tls_check (tlio_out, len) < 0) { |
714 | return -1; |
715 | } |
716 | tlio_out->out_methods->copy_through[tlio_in->in_type](tlio_in, tlio_out, len, advance); |
717 | if (advance) { |
718 | TL_IN_POS += len; |
719 | TL_IN_REMAINING -= len; |
720 | } |
721 | TL_OUT_POS += len; |
722 | TL_OUT_REMAINING -= len; |
723 | return len; |
724 | } |
725 | /* }}} */ |
726 | |
727 | static inline int tlf_int_range (struct tl_in_state *tlio_in, int min, int max) /* {{{ */ { |
728 | int x = tlf_int (tlio_in); |
729 | if (x < min || x > max) { |
730 | tlf_set_error_format (tlio_in, TL_ERROR_VALUE_NOT_IN_RANGE, "Expected int32 in range [%d,%d], %d presented" , min, max, x); |
731 | } |
732 | return x; |
733 | } |
734 | /* }}} */ |
735 | #define tl_fetch_int_range(...) tlf_int_range (tlio_in, ## __VA_ARGS__) |
736 | |
737 | static inline int tlf_positive_int (struct tl_in_state *tlio_in) { |
738 | return tlf_int_range (tlio_in, 1, 0x7fffffff); |
739 | } |
740 | #define tl_fetch_positive_int(...) tlf_positive_int (tlio_in, ## __VA_ARGS__) |
741 | |
742 | static inline int tlf_nonnegative_int (struct tl_in_state *tlio_in) { |
743 | return tlf_int_range (tlio_in, 0, 0x7fffffff); |
744 | } |
745 | #define tl_fetch_nonnegative_int(...) tlf_nonnegative_int (tlio_in, ## __VA_ARGS__) |
746 | |
747 | static inline int tlf_int_subset (struct tl_in_state *tlio_in, int set) /* {{{ */ { |
748 | int x = tlf_int (tlio_in); |
749 | if (x & ~set) { |
750 | tlf_set_error_format (tlio_in, TL_ERROR_VALUE_NOT_IN_RANGE, "Expected int32 with only bits 0x%02x allowed, 0x%02x presented" , set, x); |
751 | } |
752 | return x; |
753 | } |
754 | /* }}} */ |
755 | #define tl_fetch_int_subset(...) tlf_int_subset (tlio_in, ## __VA_ARGS__) |
756 | |
757 | static inline long long tlf_long_range (struct tl_in_state *tlio_in, long long min, long long max) /* {{{ */ { |
758 | long long x = tlf_long (tlio_in); |
759 | if (x < min || x > max) { |
760 | tlf_set_error_format (tlio_in, TL_ERROR_VALUE_NOT_IN_RANGE, "Expected int64 in range [%lld,%lld], %lld presented" , min, max, x); |
761 | } |
762 | return x; |
763 | } |
764 | /* }}} */ |
765 | |
766 | static inline long long tlf_positive_long (struct tl_in_state *tlio_in) { |
767 | return tlf_long_range (tlio_in, 1, 0x7fffffffffffffffll); |
768 | } |
769 | #define tl_fetch_positive_long(...) tlf_positive_long (tlio_in, ## __VA_ARGS__) |
770 | |
771 | static inline long long tlf_nonnegative_long (struct tl_in_state *tlio_in) { |
772 | return tlf_long_range (tlio_in, 0, 0x7fffffffffffffffll); |
773 | } |
774 | #define tl_fetch_nonnegative_long(...) tlf_nonnegative_long (tlio_in, ## __VA_ARGS__) |
775 | |
776 | static int _tlf_raw_message (struct tl_in_state *tlio_in, struct raw_message *raw, int len, int advance) { |
777 | if (__builtin_expect (tlf_check (tlio_in, len) < 0, 0)) { |
778 | return -1; |
779 | } |
780 | |
781 | if (advance) { |
782 | TL_IN_METHODS->fetch_raw_message (tlio_in, raw, len); |
783 | TL_IN_POS += len; |
784 | TL_IN_REMAINING -= len; |
785 | } else { |
786 | TL_IN_METHODS->fetch_lookup_raw_message (tlio_in, raw, len); |
787 | } |
788 | |
789 | return 0; |
790 | } |
791 | |
792 | static inline int tlf_raw_message (struct tl_in_state *tlio_in, struct raw_message *raw, int bytes) { |
793 | return _tlf_raw_message (tlio_in, raw, bytes, 1); |
794 | } |
795 | #define tl_fetch_raw_message(...) tlf_raw_message (tlio_in, ## __VA_ARGS__) |
796 | |
797 | static inline int tlf_lookup_raw_message (struct tl_in_state *tlio_in, struct raw_message *raw, int bytes) { |
798 | return _tlf_raw_message (tlio_in, raw, bytes, 0); |
799 | } |
800 | #define tl_fetch_lookup_raw_message(...) tlf_lookup_raw_message (tlio_in, ## __VA_ARGS__) |
801 | |
802 | static inline void tlf_copy_error (struct tl_in_state *tlio_in, struct tl_out_state *tlio_out) { |
803 | if (!tlio_out->error) { |
804 | if (tlio_in->error) { |
805 | tlio_out->error = strdup (tlio_in->error); |
806 | tlio_out->errnum = tlio_in->errnum; |
807 | } |
808 | } |
809 | } |
810 | #define tl_copy_error(...) tlf_copy_error (tlio_in, tlio_out, ## __VA_ARGS__) |
811 | |
812 | struct tl_in_state *tl_in_state_alloc (void); |
813 | void tl_in_state_free (struct tl_in_state *tlio_in); |
814 | struct tl_out_state *tl_out_state_alloc (void); |
815 | void tl_out_state_free (struct tl_out_state *tlio_out); |
816 | |