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
50struct tl_query_header;
51struct tl_query_header *tl_query_header_dup (struct tl_query_header *h);
52struct tl_query_header *tl_query_header_clone (struct tl_query_header *h_old);
53void tl_query_header_delete (struct tl_query_header *h);
54
55
56#define RPC_REQ_ERROR_WRAPPED (RPC_REQ_ERROR + 1)
57
58extern long long rpc_queries_received, rpc_queries_ok, rpc_queries_error;
59
60struct tl_in_state;
61struct tl_out_state;
62struct 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
76struct 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
92enum 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
101struct 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
120struct tl_out_state {
121 enum tl_type out_type;
122 const struct tl_out_methods *out_methods;
123 void *out;
124 void *out_extra;
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
138struct query_work_params;
139
140struct tl_query_header {
141 long long qid;
142 long long actor_id;
143 int flags;
144 int op;
145 int real_op;
146 int ref_cnt;
147 struct query_work_params *qw_params;
148};
149
150extern const struct tl_in_methods tl_in_conn_methods;
151extern const struct tl_in_methods tl_in_nbit_methods;
152extern const struct tl_in_methods tl_in_raw_msg_methods;
153extern const struct tl_out_methods tl_out_conn_methods;
154extern 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 TL_OUT_EXTRA (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
193int 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__)
195int 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
198int 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
207int tlf_init_raw_message (struct tl_in_state *tlio_in, struct raw_message *msg, int size, int dup);
208
209int 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);
213int 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);
215int tls_init_tcp_raw_msg (struct tl_out_state *tlio_out, JOB_REF_ARG (c), long long qid);
216int 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);
219int 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);
222int 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);
224int 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
228int tlf_query_flags (struct tl_in_state *tlio_in, struct tl_query_header *header);
229int tlf_query_header (struct tl_in_state *tlio_in, struct tl_query_header *header);
230int tlf_query_answer_flags (struct tl_in_state *tlio_in, struct tl_query_header *header);
231int tlf_query_answer_header (struct tl_in_state *tlio_in, struct tl_query_header *header);
232int tls_header (struct tl_out_state *tlio_out, struct tl_query_header *header);
233
234int tls_end_ext (struct tl_out_state *tlio_out, int op);
235
236static inline int tlf_init_empty (struct tl_in_state *tlio_in) {
237 return tlf_init_str (tlio_in, "", 0);
238}
239
240static 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
245static 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
268inline 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
275inline 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
282static 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
293static 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
304static 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
315static 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
325static 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
336static 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
347static 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
358static 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
364static 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
370static 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
376static 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
402static 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
419static 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
430static 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
443static 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
456static 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
469static 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
482static 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
496static 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
502static 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
512static 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
522static 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
528static 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/*
538static 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
548static 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
555static 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
562static 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
574static 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
586static 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
594static 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
602static 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
610static 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
625static 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
642static 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
652static 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
661static 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
670static 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
680static 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
691static 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
709static 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
727static 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
737static 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
742static 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
747static 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
757static 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
766static 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
771static 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
776static 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
792static 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
797static 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
802static 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
812struct tl_in_state *tl_in_state_alloc (void);
813void tl_in_state_free (struct tl_in_state *tlio_in);
814struct tl_out_state *tl_out_state_alloc (void);
815void tl_out_state_free (struct tl_out_state *tlio_out);
816