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 Nikolai Durov
19 2012-2013 Andrey Lopatin
20 2013 Vitaliy Valtman
21
22 Copyright 2014-2016 Telegram Messenger Inc
23 2014-2016 Vitaly Valtman
24*/
25
26#define _FILE_OFFSET_BITS 64
27
28#include <assert.h>
29#include <stddef.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <sys/uio.h>
35
36#include "sha1.h"
37#include "kprintf.h"
38
39#include "net/net-msg.h"
40#include "net/net-msg-buffers.h"
41#include "crc32c.h"
42#include "crc32.h"
43#include "crypto/aesni256.h"
44
45#include "jobs/jobs.h"
46#include "common/common-stats.h"
47#include "common/server-functions.h"
48
49struct raw_message empty_rwm = {
50 .first = NULL,
51 .last = NULL,
52 .total_bytes = 0,
53 .magic = RM_INIT_MAGIC,
54 .first_offset = 0,
55 .last_offset = 0
56};
57
58#define MODULE raw_msg
59
60MODULE_STAT_TYPE {
61 int rwm_total_msgs;
62 int rwm_total_msg_parts;
63};
64
65MODULE_INIT
66
67MODULE_STAT_FUNCTION
68 SB_SUM_ONE_I (rwm_total_msgs);
69 SB_SUM_ONE_I (rwm_total_msg_parts);
70MODULE_STAT_FUNCTION_END
71
72
73static inline struct msg_part *alloc_msg_part (void) { MODULE_STAT->rwm_total_msg_parts ++; struct msg_part *mp = (struct msg_part *) malloc (sizeof (struct msg_part)); mp->magic = MSG_PART_MAGIC; return mp; }
74static inline void free_msg_part (struct msg_part *mp) { MODULE_STAT->rwm_total_msg_parts --; assert (mp->magic == MSG_PART_MAGIC); free (mp); }
75
76struct msg_part *new_msg_part (struct msg_part *neighbor, struct msg_buffer *X) /* {{{ */{
77 struct msg_part *mp = alloc_msg_part ();
78 assert (mp);
79 assert (mp->magic == MSG_PART_MAGIC);
80 mp->refcnt = 1;
81 mp->next = 0;
82 mp->part = X;
83 mp->offset = 0;
84 mp->data_end = 0;
85 return mp;
86}
87/* }}} */
88
89#define check_msg_part_magic(x) \
90 {\
91 unsigned magic = (x)->magic;\
92 assert (magic == MSG_PART_MAGIC || magic == MSG_PART_LOCKED_MAGIC);\
93 }
94
95static int msg_part_decref (struct msg_part *mp) /* {{{ */{
96 struct msg_part *mpn;
97 int cnt = 0;
98 while (mp) {
99 check_msg_part_magic (mp);
100 if (mp->refcnt == 1) {
101 mp->refcnt = 0;
102 } else {
103 if (__sync_fetch_and_add (&mp->refcnt, -1) > 1) {
104 break;
105 }
106 }
107
108 assert (mp->magic == MSG_PART_MAGIC);
109 assert (!mp->refcnt);
110 msg_buffer_decref (mp->part);
111
112 mpn = mp->next;
113 mp->part = 0;
114 mp->next = 0;
115 free_msg_part (mp);
116 mp = mpn;
117
118 cnt ++;
119 }
120 return cnt;
121}
122/* }}} */
123
124
125// after this function non-empty raw message raw should have following properties:
126// raw->last_offset = raw->last->data_end
127// raw->last->next = NULL
128// raw->last is locked, unless refcnt is 1 in full msg_part chain
129struct msg_part *rwm_lock_last_part (struct raw_message *raw) /* {{{ */ {
130 assert (raw->magic == RM_INIT_MAGIC);
131
132 if (!raw->first) { return NULL; }
133
134 struct msg_part *locked = NULL;
135 struct msg_part *mp = raw->last;
136 if (mp->next || raw->last_offset != mp->data_end) {
137 assert (raw->last_offset <= mp->data_end);
138 // trying to append bytes to a sub-message of a longer chain, have to fork the chain
139 fork_message_chain (raw);
140 } else {
141 if (mp->magic != MSG_PART_MAGIC || !__sync_bool_compare_and_swap (&mp->magic, MSG_PART_MAGIC, MSG_PART_LOCKED_MAGIC)) {
142 fork_message_chain (raw);
143 } else {
144 locked = mp;
145 barrier ();
146 // rare case - somebody changed value mp between first check and lock
147 if (mp->next || raw->last_offset != mp->data_end) {
148 locked->magic = MSG_PART_MAGIC;
149 locked = NULL;
150 fork_message_chain (raw);
151 }
152 }
153 }
154 return locked;
155}
156/* }}} */
157
158// after this function non-empty raw message raw should have following properties:
159// raw->first_offset == raw->first->offset
160struct msg_part *rwm_lock_first_part (struct raw_message *raw) /* {{{ */ {
161 assert (raw->magic == RM_INIT_MAGIC);
162
163 if (!raw->first) { return NULL; }
164
165 if (raw->first->refcnt == 1) {
166 raw->first->offset = raw->first_offset;
167 return NULL;
168 }
169 if (raw->first->offset == raw->first_offset) {
170 return NULL;
171 }
172
173 __sync_fetch_and_add (&raw->first->part->refcnt, 1);
174 struct msg_part *mp = new_msg_part (raw->first, raw->first->part);
175 mp->offset = raw->first_offset;
176 mp->data_end = raw->first->data_end;
177 if (raw->last == raw->first) {
178 raw->last = mp;
179 mp->data_end = raw->last_offset;
180 } else {
181 mp->next = raw->first->next;
182 assert (mp->next);
183 __sync_fetch_and_add (&mp->next->refcnt, 1);
184 }
185 msg_part_decref (raw->first);
186 raw->first = mp;
187
188 return NULL;
189}
190/* }}} */
191
192// struct raw_message itself is not freed since it is usually part of a larger structure
193int rwm_free (struct raw_message *raw) /* {{{ */ {
194 struct msg_part *mp = raw->first;
195 int t = raw->magic;
196 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
197 MODULE_STAT->rwm_total_msgs --;
198 memset (raw, 0, sizeof (*raw));
199 return t == RM_TMP_MAGIC ? 0 : msg_part_decref (mp);
200}
201/* }}} */
202
203int rwm_compare (struct raw_message *l, struct raw_message *r) /* {{{ */ {
204 assert (l->magic == RM_INIT_MAGIC || l->magic == RM_TMP_MAGIC);
205 assert (r->magic == RM_INIT_MAGIC || r->magic == RM_TMP_MAGIC);
206 if (l && !l->total_bytes) { l = 0; }
207 if (r && !r->total_bytes) { r = 0; }
208 if (!l && !r) { return 0; }
209 if (!l) { return -1; }
210 if (!r) { return 1; }
211 struct msg_part *lp = l->first;
212 struct msg_part *rp = r->first;
213 int lo = l->first_offset;
214 int ro = r->first_offset;
215 int ls = (lp == l->last) ? l->last_offset - lo : lp->data_end - lo;
216 int rs = (rp == r->last) ? r->last_offset - ro : rp->data_end - ro;
217 while (1) {
218 if (ls && rs) {
219 int z = ls > rs ? rs : ls;
220 int x = memcmp (lp->part->data + lo, rp->part->data + ro, z);
221 if (x != 0) { return x; }
222 ls -= z;
223 rs -= z;
224 lo += z;
225 ro += z;
226 }
227 if (!ls) {
228 if (lp == l->last) {
229 return l->total_bytes == r->total_bytes ? 0 : -1;
230 }
231 lp = lp->next;
232 lo = lp->offset;
233 ls = (lp == l->last) ? l->last_offset - lo: lp->data_end - lo;
234 }
235 if (!rs) {
236 if (rp == r->last) {
237 return l->total_bytes == r->total_bytes ? 0 : 1;
238 }
239 rp = rp->next;
240 ro = rp->offset;
241 rs = (rp == r->last) ? r->last_offset - ro: rp->data_end - ro;
242 }
243 }
244}
245/* }}} */
246
247// after this function non-empty raw message raw should have following properties:
248// refcnt of all msg_parts in raw is 1
249// raw->first_offset = raw->first->offset
250// raw->last_offset = raw->last->offset
251// raw->last->next = NULL
252int fork_message_chain (struct raw_message *raw) /* {{{ */ {
253 assert (raw->magic == RM_INIT_MAGIC);
254 struct msg_part *mp = raw->first, **mpp = &raw->first, *mpl = 0;
255 int copy_last = 0, res = 0, total_bytes = raw->total_bytes;
256 if (!mp) {
257 return 0;
258 }
259 int ok = 1;
260 if (raw->first_offset != mp->offset) {
261 if (mp->refcnt == 1) {
262 mp->offset = raw->first_offset;
263 } else {
264 ok = 0;
265 }
266 }
267 while (ok && mp != raw->last && mp->refcnt == 1) {
268 // can not be locked, since we have only possible link
269 assert (mp->magic == MSG_PART_MAGIC);
270
271 total_bytes -= (mp->data_end - mp->offset);
272 mpp = &mp->next;
273 mpl = mp;
274 mp = mp->next;
275 assert (mp);
276 }
277 if (!ok || mp->refcnt != 1 || mp != raw->last) {
278 struct msg_part *np = mp;
279 while (!copy_last) {
280 assert (mp);
281 check_msg_part_magic (mp);
282 struct msg_part *mpc = new_msg_part (mpl, mp->part);
283
284 __sync_fetch_and_add (&mpc->part->refcnt, 1);
285 mpc->offset = mp->offset;
286 mpc->data_end = mp->data_end;
287
288 if (mp == raw->first && raw->first_offset != mp->offset) {
289 mpc->offset = raw->first_offset;
290 }
291
292 if (mp == raw->last) {
293 mpc->data_end = raw->last_offset;
294 copy_last = 1;
295 raw->last = mpc;
296 }
297 *mpp = mpc;
298 total_bytes -= (mpc->data_end - mpc->offset);
299 ++res;
300
301 mpp = &mpc->next;
302 mpl = mpc;
303 mp = mp->next;
304 }
305 msg_part_decref (np);
306 } else {
307 assert (mp == raw->last);
308 assert (mp->magic == MSG_PART_MAGIC);
309 if (raw->last_offset != mp->data_end) {
310 mp->data_end = raw->last_offset;
311 }
312 total_bytes -= (mp->data_end - mp->offset);
313 msg_part_decref (mp->next);
314 mp->next = NULL;
315 }
316 if (total_bytes) {
317 fprintf (stderr, "total_bytes = %d\n", total_bytes);
318 rwm_dump_sizes (raw);
319 }
320 assert (!total_bytes);
321 return res;
322}
323/* }}} */
324
325void rwm_clean (struct raw_message *raw) /* {{{ */{
326 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
327 raw->first = raw->last = 0;
328 raw->first_offset = raw->last_offset = 0;
329 raw->total_bytes = 0;
330}
331/* }}} */
332
333void rwm_clear (struct raw_message *raw) /* {{{ */{
334 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
335 if (raw->first && raw->magic == RM_INIT_MAGIC) {
336 msg_part_decref (raw->first);
337 }
338 rwm_clean (raw);
339}
340/* }}} */
341
342void rwm_clone (struct raw_message *dest_raw, struct raw_message *src_raw) /* {{{ */ {
343 assert (src_raw->magic == RM_INIT_MAGIC || src_raw->magic == RM_TMP_MAGIC);
344 memcpy (dest_raw, src_raw, sizeof (struct raw_message));
345 if (src_raw->magic == RM_INIT_MAGIC && src_raw->first) {
346 if (src_raw->first->refcnt == 1) {
347 src_raw->first->refcnt ++;
348 } else {
349 __sync_fetch_and_add (&src_raw->first->refcnt, 1);
350 }
351 }
352 MODULE_STAT->rwm_total_msgs ++;
353}
354/* }}} */
355
356void rwm_move (struct raw_message *dest_raw, struct raw_message *src_raw) /* {{{ */ {
357 assert (src_raw->magic == RM_INIT_MAGIC || src_raw->magic == RM_TMP_MAGIC);
358 *dest_raw = *src_raw;
359 memset (src_raw, 0, sizeof (*src_raw));
360}
361/* }}} */
362
363int rwm_push_data_ext (struct raw_message *raw, const void *data, int alloc_bytes, int prepend, int small_buffer, int std_buffer) /* {{{ */ {
364 assert (raw->magic == RM_INIT_MAGIC);
365 assert (alloc_bytes >= 0);
366 if (!alloc_bytes) {
367 return 0;
368 }
369 struct msg_part *mp, *mpl;
370 int res = 0;
371 struct msg_part *locked = NULL;
372
373 if (!raw->first) {
374 // create first part of empty message
375 // no need to lock in this case, because refcnt in chain is 1 in newly-created message
376 struct msg_buffer *X = alloc_msg_buffer (0, alloc_bytes >= small_buffer - prepend ? std_buffer : small_buffer);
377 if (!X) {
378 return 0;
379 }
380 mp = new_msg_part (0, X);
381 if (alloc_bytes <= std_buffer) {
382 if (prepend > std_buffer - alloc_bytes) {
383 prepend = std_buffer - alloc_bytes;
384 }
385 }
386 mp->offset = prepend;
387 int sz = X->chunk->buffer_size - prepend;
388 raw->first = raw->last = mp;
389 raw->first_offset = prepend;
390 if (sz >= alloc_bytes) {
391 mp->data_end = prepend + alloc_bytes;
392 raw->total_bytes = alloc_bytes;
393 raw->last_offset = alloc_bytes + prepend;
394 if (data) {
395 memcpy (X->data + prepend, data, alloc_bytes);
396 }
397 return alloc_bytes;
398 }
399 mp->data_end = sz + prepend;
400 alloc_bytes -= sz;
401 raw->total_bytes = sz;
402 raw->last_offset = sz + prepend;
403 res = sz;
404 if (data) {
405 memcpy (X->data + prepend, data, sz);
406 data += sz;
407 }
408 } else {
409 // lock last part and try to add data inside last it
410 locked = rwm_lock_last_part (raw);
411 mp = raw->last;
412 assert (mp);
413
414 assert (mp && !mp->next && raw->last_offset == mp->data_end);
415 struct msg_buffer *X = mp->part;
416
417 // try to expand msg part
418 // all other requirements are garanteed by rwm_lcok_last_part
419 if (X->refcnt == 1) {
420 int buffer_size = X->chunk->buffer_size;
421 int sz = buffer_size - raw->last_offset;
422 assert (sz >= 0 && sz <= buffer_size);
423 if (sz > 0) {
424 // can allocate sz bytes inside the last buffer in chain itself
425 if (sz >= alloc_bytes) {
426 if (data) {
427 memcpy (X->data + raw->last_offset, data, alloc_bytes);
428 }
429 raw->total_bytes += alloc_bytes;
430 raw->last_offset += alloc_bytes;
431 mp->data_end += alloc_bytes;
432 if (locked) { locked->magic = MSG_PART_MAGIC; }
433 return alloc_bytes;
434 }
435 if (data) {
436 memcpy (X->data + raw->last_offset, data, sz);
437 data += sz;
438 }
439 raw->total_bytes += sz;
440 raw->last_offset += sz;
441 mp->data_end += sz;
442 alloc_bytes -= sz;
443 }
444 res = sz;
445 }
446 }
447
448 while (alloc_bytes > 0) {
449 mpl = mp;
450 struct msg_buffer *X = alloc_msg_buffer (mpl->part, raw->total_bytes + alloc_bytes >= std_buffer ? std_buffer : small_buffer);
451 if (!X) {
452 break;
453 }
454 mp = new_msg_part (mpl, X);
455 mpl->next = raw->last = mp;
456 int buffer_size = X->chunk->buffer_size;
457 if (buffer_size >= alloc_bytes) {
458 mp->data_end = alloc_bytes;
459 raw->total_bytes += alloc_bytes;
460 raw->last_offset = alloc_bytes;
461 if (data) {
462 memcpy (X->data, data, alloc_bytes);
463 }
464 res += alloc_bytes;
465 break;
466 }
467 mp->data_end = buffer_size;
468 alloc_bytes -= buffer_size;
469 raw->total_bytes += buffer_size;
470 raw->last_offset = buffer_size;
471 res += buffer_size;
472 if (data) {
473 memcpy (X->data, data, buffer_size);
474 data += buffer_size;
475 }
476 }
477 if (locked) { locked->magic = MSG_PART_MAGIC; }
478 return res;
479}
480/* }}} */
481
482int rwm_push_data (struct raw_message *raw, const void *data, int alloc_bytes) /* {{{ */ {
483 return rwm_push_data_ext (raw, data, alloc_bytes, RM_PREPEND_RESERVE, MSG_SMALL_BUFFER, MSG_STD_BUFFER);
484}
485/* }}} */
486
487int rwm_push_data_front (struct raw_message *raw, const void *data, int alloc_bytes) /* {{{ */ {
488 assert (raw->magic == RM_INIT_MAGIC);
489 assert (alloc_bytes >= 0);
490 if (!alloc_bytes) {
491 return 0;
492 }
493 struct msg_part *mp = 0;
494 int r = alloc_bytes;
495 struct msg_part *locked = NULL;
496 if (raw->first) {
497 locked = rwm_lock_first_part (raw);
498 mp = raw->first;
499 struct msg_buffer *X = raw->first->part;
500 if (X->refcnt == 1 && mp->refcnt == 1) {
501 int size = raw->first_offset;
502 if (alloc_bytes > size) {
503 memcpy (X->data, data + (alloc_bytes - size), size);
504 alloc_bytes -= size;
505 raw->first_offset = raw->first->offset = 0;
506 raw->total_bytes += size;
507 } else {
508 memcpy (X->data + size - alloc_bytes, data, alloc_bytes);
509 raw->first->offset -= alloc_bytes;
510 raw->first_offset = raw->first->offset;
511 raw->total_bytes += alloc_bytes;
512 if (locked) { locked->magic = MSG_PART_MAGIC; }
513 return r;
514 }
515 }
516 }
517 while (alloc_bytes) {
518 struct msg_buffer *X = alloc_msg_buffer (raw->first ? raw->first->part : 0, alloc_bytes >= MSG_SMALL_BUFFER ? MSG_STD_BUFFER : MSG_SMALL_BUFFER);
519 assert (X);
520 int size = X->chunk->buffer_size;
521 mp = new_msg_part (raw->first, X);
522 mp->next = raw->first;
523 raw->first = mp;
524
525 if (alloc_bytes > size) {
526 memcpy (X->data, data + (alloc_bytes - size), size);
527 alloc_bytes -= size;
528 mp->data_end = size;
529 mp->offset = 0;
530 raw->total_bytes += size;
531 if (!raw->last) {
532 raw->last = mp;
533 raw->last_offset = mp->data_end;
534 }
535 } else {
536 memcpy (X->data + size - alloc_bytes, data, alloc_bytes);
537 mp->data_end = size;
538 mp->offset = (size - alloc_bytes);
539 raw->first_offset = mp->offset;
540 raw->total_bytes += alloc_bytes;
541 if (!raw->last) {
542 raw->last = mp;
543 raw->last_offset = mp->data_end;
544 }
545
546 if (locked) { locked->magic = MSG_PART_MAGIC; }
547 return r;
548 }
549 }
550 assert (0);
551 return r;
552}
553/* }}} */
554
555int rwm_create (struct raw_message *raw, const void *data, int alloc_bytes) /* {{{ */ {
556 MODULE_STAT->rwm_total_msgs ++;
557 memset (raw, 0, sizeof (*raw));
558 raw->magic = RM_INIT_MAGIC;
559 return rwm_push_data (raw, data, alloc_bytes);
560}
561/* }}} */
562
563int rwm_init (struct raw_message *raw, int alloc_bytes) /* {{{ */ {
564 return rwm_create (raw, 0, alloc_bytes);
565}
566/* }}} */
567
568void *rwm_prepend_alloc (struct raw_message *raw, int alloc_bytes) /* {{{ */ {
569 assert (raw->magic == RM_INIT_MAGIC);
570 assert (alloc_bytes >= 0);
571 if (!alloc_bytes || alloc_bytes > MSG_STD_BUFFER) {
572 return 0;
573 }
574 // struct msg_part *mp, *mpl;
575 // int res = 0;
576 if (!raw->first) {
577 rwm_push_data (raw, 0, alloc_bytes);
578 assert (raw->first == raw->last);
579 assert (raw->total_bytes == alloc_bytes);
580 return raw->first->part->data + raw->first_offset;
581 }
582
583 struct msg_part *locked = rwm_lock_first_part (raw);
584 assert (raw->first_offset == raw->first->offset);
585
586 if (raw->first->refcnt == 1 && raw->first->offset >= alloc_bytes && raw->first->part->refcnt == 1) {
587 raw->first->offset -= alloc_bytes;
588 raw->first_offset -= alloc_bytes;
589 raw->total_bytes += alloc_bytes;
590 if (locked) { locked->magic = MSG_PART_MAGIC; }
591 return raw->first->part->data + raw->first_offset;
592 }
593
594 assert (raw->first_offset == raw->first->offset);
595 struct msg_buffer *X = alloc_msg_buffer (raw->first ? raw->first->part : 0, alloc_bytes);
596 assert (X);
597 int size = X->chunk->buffer_size;
598 assert (size >= alloc_bytes);
599 struct msg_part *mp = new_msg_part (raw->first, X);
600 mp->next = raw->first;
601 raw->first = mp;
602 mp->data_end = size;
603 mp->offset = size - alloc_bytes;
604 raw->first_offset = mp->offset;
605 raw->total_bytes += alloc_bytes;
606 if (locked) { locked->magic = MSG_PART_MAGIC; }
607 return raw->first->part->data + mp->offset;
608}
609/* }}} */
610
611void *rwm_postpone_alloc (struct raw_message *raw, int alloc_bytes) /* {{{ */ {
612 assert (raw->magic == RM_INIT_MAGIC);
613 assert (alloc_bytes >= 0);
614 if (!alloc_bytes || alloc_bytes > MSG_STD_BUFFER) {
615 return 0;
616 }
617 // struct msg_part *mp, *mpl;
618 // int res = 0;
619 if (!raw->first) {
620 rwm_push_data (raw, 0, alloc_bytes);
621 assert (raw->first == raw->last);
622 assert (raw->total_bytes == alloc_bytes);
623 return raw->first->part->data + raw->first_offset;
624 }
625
626 struct msg_part *locked = rwm_lock_last_part (raw);
627 struct msg_part *mp = raw->last;
628
629 int size = mp->part->chunk->buffer_size;
630 if (size - mp->data_end >= alloc_bytes && mp->part->refcnt == 1) {
631 raw->total_bytes += alloc_bytes;
632 mp->data_end += alloc_bytes;
633 raw->last_offset += alloc_bytes;
634 if (locked) { locked->magic = MSG_PART_MAGIC; }
635 return mp->part->data + mp->data_end - alloc_bytes;
636 }
637 struct msg_buffer *X = alloc_msg_buffer (mp->part, alloc_bytes);
638 assert (X);
639 size = X->chunk->buffer_size;
640 assert (size >= alloc_bytes);
641
642 mp = new_msg_part (raw->first, X);
643 raw->last->next = mp;
644 raw->last = mp;
645
646 mp->data_end = alloc_bytes;
647 mp->offset = 0;
648 raw->last_offset = alloc_bytes;
649 raw->total_bytes += alloc_bytes;
650
651 if (locked) { locked->magic = MSG_PART_MAGIC; }
652 return mp->part->data;
653}
654/* }}} */
655
656int rwm_prepare_iovec (const struct raw_message *raw, struct iovec *iov, int iov_len, int bytes) /* {{{ */ {
657 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
658 if (bytes > raw->total_bytes) {
659 bytes = raw->total_bytes;
660 }
661 assert (bytes >= 0);
662 int res = 0, total_bytes = raw->total_bytes, first_offset = raw->first_offset;
663 struct msg_part *mp = raw->first;
664 while (bytes > 0) {
665 assert (mp);
666 if (res == iov_len) {
667 return -1;
668 }
669 int sz = (mp == raw->last ? raw->last_offset : mp->data_end) - first_offset;
670 if (bytes < sz) {
671 iov[res].iov_base = mp->part->data + first_offset;
672 iov[res++].iov_len = bytes;
673 return res;
674 }
675 iov[res].iov_base = mp->part->data + first_offset;
676 iov[res++].iov_len = sz;
677 bytes -= sz;
678 total_bytes -= sz;
679 if (!mp->next) {
680 assert (mp == raw->last && !bytes && !total_bytes);
681 return res;
682 }
683 mp = mp->next;
684 first_offset = mp->offset;
685 }
686 return res;
687}
688/* }}} */
689
690int rwm_process_memcpy (void *extra, const void *data, int len) /* {{{ */ {
691 if (extra) {
692 char **d = extra;
693 memcpy (*d, data, len);
694 *d += len;
695 }
696 return 0;
697}
698/* }}} */
699
700int rwm_fetch_data_back (struct raw_message *raw, void *data, int bytes) /* {{{ */ {
701 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
702 if (bytes > raw->total_bytes) {
703 bytes = raw->total_bytes;
704 }
705 assert (bytes >= 0);
706 if (!bytes) {
707 return 0;
708 }
709
710 return rwm_process_ex (raw, bytes, raw->total_bytes - bytes, RMPF_TRUNCATE, rwm_process_memcpy, data ? &data : NULL);
711}
712/* }}} */
713
714int rwm_fetch_lookup_back (struct raw_message *raw, void *data, int bytes) /* {{{ */ {
715 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
716 if (bytes > raw->total_bytes) {
717 bytes = raw->total_bytes;
718 }
719 assert (bytes >= 0);
720 if (!bytes) {
721 return 0;
722 }
723
724 return rwm_process_ex (raw, bytes, raw->total_bytes - bytes, 0, rwm_process_memcpy, data ? &data : NULL);
725}
726/* }}} */
727
728int rwm_trunc (struct raw_message *raw, int len) /* {{{ */ {
729 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
730 if (len >= raw->total_bytes) {
731 return raw->total_bytes;
732 }
733 rwm_fetch_data_back (raw, 0, raw->total_bytes - len);
734 return len;
735}
736/* }}} */
737
738int rwm_split (struct raw_message *raw, struct raw_message *tail, int bytes) /* {{{ */ {
739 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
740 assert (bytes >= 0);
741 MODULE_STAT->rwm_total_msgs ++;
742 tail->magic = raw->magic;
743 if (bytes >= raw->total_bytes) {
744 tail->first = tail->last = 0;
745 tail->first_offset = tail->last_offset = 0;
746 tail->total_bytes = 0;
747 return bytes == raw->total_bytes ? 0 : -1;
748 }
749 if (raw->total_bytes - bytes <= raw->last_offset - raw->last->offset) {
750 int s = raw->total_bytes - bytes;
751 raw->last_offset -= s;
752 raw->total_bytes -= s;
753 tail->first = tail->last = raw->last;
754 if (raw->magic == RM_INIT_MAGIC) {
755 __sync_fetch_and_add (&tail->first->refcnt, 1);
756 }
757
758 tail->first_offset = raw->last_offset;
759 tail->last_offset = raw->last_offset + s;
760 tail->total_bytes = s;
761 return 0;
762 }
763 tail->total_bytes = raw->total_bytes - bytes;
764 raw->total_bytes = bytes;
765 struct msg_part *mp = raw->first;
766 int ok = 1;
767 while (bytes) {
768 assert (mp);
769 int sz = (mp == raw->last ? raw->last_offset : mp->data_end) - (mp == raw->first ? raw->first_offset : mp->offset);
770 if (mp->refcnt != 1) { ok = 0; }
771 if (sz < bytes) {
772 bytes -= sz;
773 mp = mp->next;
774 } else {
775 tail->last = raw->last;
776 tail->last_offset = raw->last_offset;
777 raw->last = mp;
778 raw->last_offset = (mp == raw->first ? raw->first_offset : mp->offset) + bytes;
779 tail->first = mp;
780 tail->first_offset = raw->last_offset;
781
782 if (raw->magic == RM_INIT_MAGIC) {
783 if (ok) {
784 mp->refcnt ++;
785 } else {
786 __sync_fetch_and_add (&mp->refcnt, 1);
787 }
788 }
789 bytes = 0;
790 }
791 }
792 return 0;
793}
794/* }}} */
795
796int rwm_split_head (struct raw_message *head, struct raw_message *raw, int bytes) /* {{{ */ {
797 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
798 *head = *raw;
799 return rwm_split (head, raw, bytes);
800}
801/* }}} */
802
803int rwm_union (struct raw_message *raw, struct raw_message *tail) /* {{{ */ {
804 //rwm_check (raw);
805 //rwm_check (tail);
806 assert (raw->magic == RM_INIT_MAGIC);
807 struct msg_part *locked = NULL;
808// assert (raw != tail);
809 if (!raw->last) {
810 *raw = *tail;
811 MODULE_STAT->rwm_total_msgs --;
812 tail->magic = 0;
813 return 0;
814 } else if (tail->first) {
815 locked = rwm_lock_last_part (raw);
816
817 // this code ensures that this function will not create message with loop
818 // if there would be loop, that last msg_part in chains of raw and tail are same
819 // then they can not be simultaneously locked, so this call will make copy of chain
820 struct msg_part *l2 = rwm_lock_last_part (tail);
821 if (l2) { l2->magic = MSG_PART_MAGIC; }
822
823 l2 = rwm_lock_first_part (tail);
824 raw->last->next = tail->first;
825 __sync_fetch_and_add (&tail->first->refcnt, 1);
826
827 raw->last_offset = tail->last_offset;
828 raw->last = tail->last;
829 raw->total_bytes += tail->total_bytes;
830
831 if (l2) { l2->magic = MSG_PART_MAGIC; }
832 }
833 rwm_free (tail);
834 //rwm_check (raw);
835 if (locked) { locked->magic = MSG_PART_MAGIC; }
836 return 0;
837}
838/* }}} */
839
840int rwm_dump_sizes (struct raw_message *raw) /* {{{ */ {
841 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
842 if (!raw->first) {
843 fprintf (stderr, "( ) # %d\n", raw->total_bytes);
844 assert (!raw->total_bytes);
845 } else {
846 int total_size = 0;
847 struct msg_part *mp = raw->first;
848 fprintf (stderr, "(");
849 while (mp != 0) {
850 int size = (mp == raw->last ? raw->last_offset : mp->data_end) - (mp == raw->first ? raw->first_offset : mp->offset);
851 fprintf (stderr, " %d", size);
852 total_size += size;
853 if (mp == raw->last) { break; }
854 mp = mp->next;
855 }
856 assert (mp == raw->last);
857 fprintf (stderr, " ) # %d\n", raw->total_bytes);
858 assert (total_size == raw->total_bytes);
859 }
860 return 0;
861}
862/* }}} */
863
864int rwm_check (struct raw_message *raw) /* {{{ */ {
865 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
866 if (!raw->first) {
867 assert (!raw->total_bytes);
868 } else {
869 int total_size = 0;
870 struct msg_part *mp = raw->first;
871 assert (raw->first_offset >= raw->first->offset);
872 assert (raw->last_offset <= raw->last->data_end);
873 while (mp != 0) {
874 int size = (mp == raw->last ? raw->last_offset : mp->data_end) - (mp == raw->first ? raw->first_offset : mp->offset);
875 assert (mp->offset >= 0);
876 assert (mp->data_end <= mp->part->chunk->buffer_size);
877 total_size += size;
878 if (mp == raw->last) { break; }
879 mp = mp->next;
880 }
881 assert (mp == raw->last);
882 if (total_size != raw->total_bytes) {
883 fprintf (stderr, "total_size = %d, total_bytes = %d\n", total_size, raw->total_bytes);
884 rwm_dump_sizes (raw);
885 }
886 assert (total_size == raw->total_bytes);
887 }
888 return 0;
889}
890/* }}} */
891
892int rwm_dump (struct raw_message *raw) /* {{{ */ {
893 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
894 struct raw_message t;
895 rwm_clone (&t, raw);
896 static char R[10004];
897 int r = rwm_fetch_data (&t, R, 10004);
898 int x = (r > 10000) ? 10000 : r;
899 hexdump (R, R + x);
900 if (r > x) {
901 fprintf (stderr, "%d bytes not printed\n", raw->total_bytes - x);
902 }
903 rwm_free (&t);
904 return 0;
905}
906/* }}} */
907
908int rwm_process_ex (struct raw_message *raw, int bytes, int offset, int flags, int (*process_block)(void *extra, const void *data, int len), void *extra) /* {{{ */ {
909 //rwm_check (raw);
910 assert (raw->magic == RM_INIT_MAGIC || raw->magic == RM_TMP_MAGIC);
911
912 assert (bytes >= 0);
913 assert (offset >= 0);
914 if (bytes + offset > raw->total_bytes) {
915 bytes = raw->total_bytes - offset;
916 }
917 if (bytes <= 0) { return 0; }
918
919 // correct, because if raw->last == raw->first all bytes garanteed to be in this (only) msg part
920 if (raw->total_bytes - offset <= raw->last_offset - raw->last->offset) {
921 int x = raw->total_bytes - offset;
922 int r = process_block (extra, raw->last->part->data + raw->last_offset - x, bytes);
923
924 if (r >= 0) {
925 if (flags & RMPF_ADVANCE) {
926 if (raw->magic == RM_INIT_MAGIC) {
927 __sync_fetch_and_add (&raw->last->refcnt, 1);
928 msg_part_decref (raw->first);
929 }
930 raw->first = raw->last;
931 raw->first_offset = raw->last_offset - x + bytes;
932 raw->total_bytes -= offset + bytes;
933 }
934 if (flags & RMPF_TRUNCATE) {
935 raw->total_bytes -= x;
936 raw->last_offset -= x;
937 }
938 } else {
939 return r;
940 }
941
942 //rwm_check (raw);
943 return bytes;
944 }
945
946 int x = bytes, r;
947 struct msg_part *mp = raw->first;
948 int ok = 1;
949 int save_offset = offset;
950 while (mp) {
951 check_msg_part_magic (mp);
952 if (mp->refcnt != 1) { ok = 0; }
953 int start = (mp == raw->first) ? raw->first_offset : mp->offset;
954 int len = (mp == raw->last) ? raw->last_offset - start : mp->data_end - start;
955
956 if (len >= offset) {
957 start += offset;
958 len -= offset;
959
960 struct msg_part *np = mp;
961 int save_start = start;
962
963 int ok2 = ok;
964 while (bytes) {
965 if (len >= bytes) {
966 r = bytes > 0 ? process_block (extra, mp->part->data + start, bytes) : 0;
967 len = bytes; // to set last_offset
968 bytes = 0;
969 } else {
970 r = len > 0 ? process_block (extra, mp->part->data + start, len) : 0;
971 bytes -= len;
972 }
973 if (r < 0) {
974 //rwm_check (raw);
975 return r;
976 }
977
978 if (!bytes) { break; }
979 mp = mp->next;
980 assert (mp);
981 start = (mp == raw->first) ? raw->first_offset : mp->offset;
982 len = (mp == raw->last) ? raw->last_offset - start : mp->data_end - start;
983 assert (mp);
984 if (mp->refcnt != 1) { ok2 = 0; }
985 }
986
987 if (flags & RMPF_ADVANCE) {
988 if (save_offset + x == raw->total_bytes) {
989 rwm_clear (raw);
990 } else {
991 if (raw->magic == RM_INIT_MAGIC && mp != raw->first) {
992 if (ok2) {
993 mp->refcnt ++;
994 } else {
995 __sync_fetch_and_add (&mp->refcnt, 1);
996 }
997 msg_part_decref (raw->first);
998 }
999
1000 raw->first = mp;
1001 raw->first_offset = start + len;
1002
1003 if (ok2 && raw->magic == RM_INIT_MAGIC) {
1004 mp->offset = start + len;
1005 }
1006 raw->total_bytes -= save_offset + x;
1007 }
1008 }
1009
1010 if (flags & RMPF_TRUNCATE) {
1011 if (!save_offset) {
1012 rwm_clear (raw);
1013 } else {
1014 raw->total_bytes = save_offset;
1015
1016 raw->last = np;
1017 raw->last_offset = save_start;
1018
1019 if (ok) {
1020 raw->last->data_end = raw->last_offset;
1021 msg_part_decref (raw->last->next);
1022 raw->last->next = NULL;
1023 }
1024 }
1025 }
1026
1027 if (!raw->total_bytes) {
1028 rwm_clear (raw);
1029 }
1030 //rwm_check (raw);
1031 return x;
1032 }
1033 offset -= len;
1034 mp = mp->next;
1035 }
1036 assert (0);
1037 return 0;
1038}
1039/* }}} */
1040
1041int rwm_process_and_advance (struct raw_message *raw, int bytes, int (*process_block)(void *extra, const void *data, int len), void *extra) /* {{{ */ {
1042 return rwm_process_ex (raw, bytes, 0, RMPF_ADVANCE, process_block, extra);
1043}
1044/* }}} */
1045
1046int rwm_process (struct raw_message *raw, int bytes, int (*process_block)(void *extra, const void *data, int len), void *extra) /* {{{ */ {
1047 return rwm_process_ex (raw, bytes, 0, 0, process_block, extra);
1048}
1049/* }}} */
1050
1051int rwm_process_from_offset (struct raw_message *raw, int bytes, int offset, int (*process_block)(void *extra, const void *data, int len), void *extra) /* {{{ */{
1052 return rwm_process_ex (raw, bytes, offset, 0, process_block, extra);
1053}
1054/* }}} */
1055
1056int rwm_transform_from_offset (struct raw_message *raw, int bytes, int offset, int (*transform_block)(void *extra, void *data, int len), void *extra) /* {{{ */ {
1057 return rwm_process_ex (raw, bytes, offset, 0, (void *)transform_block, extra);
1058}
1059/* }}} */
1060
1061/* rwm_sha1 {{{ */
1062int sha1_wrap (void *extra, const void *data, int len) {
1063 sha1_update (extra, (void *)data, len);
1064 return 0;
1065}
1066
1067int rwm_sha1 (struct raw_message *raw, int bytes, unsigned char output[20]) {
1068 sha1_context *ctx = EVP_MD_CTX_new();
1069
1070 sha1_starts (ctx);
1071 int res = rwm_process (raw, bytes, sha1_wrap, ctx);
1072 sha1_finish (ctx, output);
1073 EVP_MD_CTX_free(ctx);
1074
1075 return res;
1076}
1077/* }}} */
1078
1079/* {{{ crc32c */
1080static int crc32c_process (void *extra, const void *data, int len) {
1081 unsigned crc32c = *(unsigned *)extra;
1082 *(unsigned *)extra = crc32c_partial (data, len, crc32c);
1083 return 0;
1084}
1085
1086unsigned rwm_crc32c (struct raw_message *raw, int bytes) {
1087 unsigned crc32c = ~0;
1088
1089 assert (rwm_process (raw, bytes, crc32c_process, &crc32c) == bytes);
1090
1091 return ~crc32c;
1092}
1093/* }}} */
1094
1095/* {{{ crc32 */
1096static int crc32_process (void *extra, const void *data, int len) {
1097 unsigned crc32 = *(unsigned *)extra;
1098 *(unsigned *)extra = crc32_partial (data, len, crc32);
1099 return 0;
1100}
1101
1102unsigned rwm_crc32 (struct raw_message *raw, int bytes) {
1103 unsigned crc32 = ~0;
1104
1105 assert (rwm_process (raw, bytes, crc32_process, &crc32) == bytes);
1106
1107 return ~crc32;
1108}
1109/* }}} */
1110
1111/* custom crc32 {{{ */
1112struct custom_crc32_data {
1113 crc32_partial_func_t partial;
1114 unsigned crc32;
1115};
1116
1117static int custom_crc32_process (void *extra, const void *data, int len) {
1118 struct custom_crc32_data *DP = extra;
1119 DP->crc32 = DP->partial (data, len, DP->crc32);
1120 return 0;
1121}
1122
1123unsigned rwm_custom_crc32 (struct raw_message *raw, int bytes, crc32_partial_func_t custom_crc32_partial) {
1124 struct custom_crc32_data D;
1125 D.partial = custom_crc32_partial;
1126 D.crc32 = -1;
1127
1128 assert (raw->total_bytes >= bytes);
1129 assert (rwm_process (raw, bytes, (void *)custom_crc32_process, &D) == bytes);
1130
1131 return ~D.crc32;
1132}
1133/* }}} */
1134
1135int rwm_process_nop (void *extra, const void *data, int len) /* {{{ */ {
1136 return 0;
1137}
1138/* }}} */
1139
1140int rwm_fetch_data (struct raw_message *raw, void *buf, int bytes) /* {{{ */ {
1141 if (buf) {
1142 return rwm_process_and_advance (raw, bytes, rwm_process_memcpy, &buf);
1143 } else {
1144 return rwm_process_and_advance (raw, bytes, rwm_process_nop, 0);
1145 }
1146}
1147/* }}} */
1148
1149int rwm_skip_data (struct raw_message *raw, int bytes) /* {{{ */ {
1150 return rwm_process_and_advance (raw, bytes, rwm_process_nop, 0);
1151}
1152/* }}} */
1153
1154int rwm_fetch_lookup (struct raw_message *raw, void *buf, int bytes) /* {{{ */ {
1155 if (buf) {
1156 return rwm_process (raw, bytes, rwm_process_memcpy, &buf);
1157 } else {
1158 return rwm_process (raw, bytes, rwm_process_nop, 0);
1159 }
1160}
1161/* }}} */
1162
1163int rwm_get_block_ptr_bytes (struct raw_message *raw) {
1164 if (!raw->total_bytes) {
1165 return 0;
1166 }
1167 struct msg_part *mp = raw->first;
1168 while (1) {
1169 assert (mp);
1170 int bytes = ((mp == raw->last) ? raw->last_offset : mp->data_end) - raw->first_offset;
1171 if (bytes) {
1172 return bytes;
1173 }
1174
1175 assert (mp != raw->last);
1176 if (mp->refcnt == 1) {
1177 raw->first = mp->next;
1178 mp->next = NULL;
1179 } else {
1180 raw->first = mp->next;
1181 __sync_fetch_and_add (&mp->next->refcnt, 1);
1182 }
1183 msg_part_decref (mp);
1184 raw->first_offset = raw->first->offset;
1185 mp = mp->next;
1186 }
1187}
1188
1189void *rwm_get_block_ptr (struct raw_message *raw) {
1190 if (!raw->first) { return NULL; }
1191 return raw->first->part->data + raw->first_offset;
1192}
1193
1194void rwm_to_tl_string (struct raw_message *raw) {
1195 assert (raw->magic == RM_INIT_MAGIC);
1196 if (raw->total_bytes < 0xfe) {
1197 assert (rwm_push_data_front (raw, &raw->total_bytes, 1) == 1);
1198 } else {
1199 assert (rwm_push_data_front (raw, &raw->total_bytes, 3) == 3);
1200 int b = 0xfe;
1201 assert (rwm_push_data_front (raw, &b, 1) == 1);
1202 }
1203
1204 int pad = (-raw->total_bytes) & 3;
1205 if (pad) {
1206 int zero = 0;
1207 assert (rwm_push_data (raw, &zero, pad) == pad);
1208 }
1209}
1210
1211void rwm_from_tl_string (struct raw_message *raw) {
1212 assert (raw->magic == RM_INIT_MAGIC);
1213 int x = 0;
1214 assert (raw->total_bytes > 0);
1215 assert (rwm_fetch_data (raw, &x, 1) == 1);
1216 assert (x != 0xff);
1217 if (x == 0xfe) {
1218 assert (raw->total_bytes >= 3);
1219 assert (rwm_fetch_data (raw, &x, 3) == 3);
1220 }
1221 assert (raw->total_bytes >= x);
1222 rwm_trunc (raw, x);
1223}
1224
1225/*{{{ encrypt_decrypt */
1226struct rwm_encrypt_decrypt_tmp {
1227 int bp;
1228 int buf_left;
1229 int left;
1230 int block_size;
1231 struct raw_message *raw;
1232 struct tg_aes_ctx *ctx;
1233 void (*crypt)(struct tg_aes_ctx *, const void *, void *, int, unsigned char *, void *, void *);
1234 unsigned char *iv;
1235 void *extra;
1236 void *extra2;
1237 char buf[16] __attribute__((aligned(16)));
1238};
1239
1240int rwm_process_encrypt_decrypt (struct rwm_encrypt_decrypt_tmp *x, const void *data, int len) {
1241 int bsize = x->block_size;
1242 struct raw_message *res = x->raw;
1243 if (!x->buf_left) {
1244 struct msg_buffer *X = alloc_msg_buffer (res->last->part, x->left >= MSG_STD_BUFFER ? MSG_STD_BUFFER : x->left);
1245 assert (X);
1246 struct msg_part *mp = new_msg_part (res->last, X);
1247 res->last->next = mp;
1248 res->last = mp;
1249 res->last_offset = 0;
1250 x->buf_left = X->chunk->buffer_size;
1251 }
1252 x->left -= len;
1253 assert (res->last_offset >= 0);
1254 assert (x->buf_left >= 0);
1255 assert (x->buf_left + res->last_offset <= res->last->part->chunk->buffer_size);
1256 if (x->bp) {
1257 int to_fill = bsize - x->bp;
1258 if (len >= to_fill) {
1259 memcpy (x->buf + x->bp, data, to_fill);
1260 len -= to_fill;
1261 data += to_fill;
1262 x->bp = 0;
1263 if (x->buf_left >= bsize) {
1264 x->crypt (x->ctx, x->buf, res->last->part->data + res->last_offset, bsize, x->iv, x->extra, x->extra2);
1265 res->last->data_end += bsize;
1266 res->last_offset += bsize;
1267 x->buf_left -= bsize;
1268 } else {
1269 x->crypt (x->ctx, x->buf, x->buf, bsize, x->iv, x->extra, x->extra2);
1270 memcpy (res->last->part->data + res->last_offset, x->buf, x->buf_left);
1271 int t = x->buf_left;
1272 res->last->data_end += t;
1273
1274 struct msg_buffer *X = alloc_msg_buffer (res->last->part, x->left + len + bsize >= MSG_STD_BUFFER ? MSG_STD_BUFFER : x->left + len + bsize);
1275 assert (X);
1276 struct msg_part *mp = new_msg_part (res->last, X);
1277 res->last->next = mp;
1278 res->last = mp;
1279 res->last_offset = 0;
1280 x->buf_left = X->chunk->buffer_size;
1281 assert (x->buf_left >= bsize - t);
1282
1283 memcpy (res->last->part->data, x->buf + t, bsize - t);
1284 res->last_offset = bsize - t;
1285 res->last->data_end = bsize - t;
1286 x->buf_left -= (bsize - t);
1287 }
1288 res->total_bytes += bsize;
1289 } else {
1290 memcpy (x->buf + x->bp, data, len);
1291 x->bp += len;
1292 return 0;
1293 }
1294 }
1295 if (len & (bsize - 1)) {
1296 int l = len & -bsize;
1297 memcpy (x->buf, data + l, len - l);
1298 x->bp = len - l;
1299 len = l;
1300 }
1301 assert (res->last_offset >= 0);
1302 assert (x->buf_left >= 0);
1303 assert (x->buf_left + res->last_offset <= res->last->part->chunk->buffer_size);
1304 while (1) {
1305 if (x->buf_left < bsize) {
1306 struct msg_buffer *X = alloc_msg_buffer (res->last->part, x->left + len >= MSG_STD_BUFFER ? MSG_STD_BUFFER : x->left + len);
1307 assert (X);
1308 struct msg_part *mp = new_msg_part (res->last, X);
1309 res->last->next = mp;
1310 res->last = mp;
1311 res->last_offset = 0;
1312 x->buf_left = X->chunk->buffer_size;
1313 }
1314 assert (res->last_offset >= 0);
1315 assert (x->buf_left >= 0);
1316 assert (x->buf_left + res->last_offset <= res->last->part->chunk->buffer_size);
1317 if (len <= x->buf_left) {
1318 assert (!(len & (bsize - 1)));
1319 x->crypt (x->ctx, data, (res->last->part->data + res->last_offset), len, x->iv, x->extra, x->extra2);
1320 res->last->data_end += len;
1321 res->last_offset += len;
1322 res->total_bytes += len;
1323 x->buf_left -= len;
1324 return 0;
1325 } else {
1326 int t = x->buf_left & -bsize;
1327 x->crypt (x->ctx, data, res->last->part->data + res->last_offset, t, x->iv, x->extra, x->extra2);
1328 res->last->data_end += t;
1329 res->last_offset += t;
1330 res->total_bytes += t;
1331 data += t;
1332 len -= t;
1333 x->buf_left -= t;
1334 }
1335 }
1336}
1337
1338
1339int rwm_encrypt_decrypt_to (struct raw_message *raw, struct raw_message *res, int bytes, struct tg_aes_ctx *ctx, void (*crypt)(struct tg_aes_ctx *ctx, const void *src, void *dst, int l, unsigned char *iv, void *extra, void *extra2), unsigned char *iv, int block_size, void *extra, void *extra2) {
1340 assert (bytes >= 0);
1341 assert (block_size && !(block_size & (block_size - 1)));
1342 if (bytes > raw->total_bytes) {
1343 bytes = raw->total_bytes;
1344 }
1345 bytes &= -block_size;
1346 if (!bytes) {
1347 return 0;
1348 }
1349
1350 struct msg_part *locked = rwm_lock_last_part (res);
1351
1352 if (!res->last || res->last->part->refcnt != 1) {
1353 int l = res->last ? bytes : bytes + RM_PREPEND_RESERVE;
1354 struct msg_buffer *X = alloc_msg_buffer (res->last ? res->last->part : 0, l >= MSG_STD_BUFFER ? MSG_STD_BUFFER : l);
1355 assert (X);
1356 struct msg_part *mp = new_msg_part (res->last, X);
1357 if (res->last) {
1358 res->last->next = mp;
1359 res->last = mp;
1360 res->last_offset = 0;
1361 } else {
1362 res->last = res->first = mp;
1363 res->last_offset = res->first_offset = mp->offset = mp->data_end = RM_PREPEND_RESERVE;
1364 }
1365 }
1366 struct rwm_encrypt_decrypt_tmp t;
1367 t.bp = 0;
1368 t.crypt = crypt;
1369 if (res->last->part->refcnt == 1) {
1370 t.buf_left = res->last->part->chunk->buffer_size - res->last_offset;
1371 } else {
1372 t.buf_left = 0;
1373 }
1374 t.raw = res;
1375 t.ctx = ctx;
1376 t.iv = iv;
1377 t.left = bytes;
1378 t.extra = extra;
1379 t.extra2 = extra2;
1380 t.block_size = block_size;
1381 int r = rwm_process_and_advance (raw, bytes, (void *)rwm_process_encrypt_decrypt, &t);
1382 if (locked) {
1383 locked->magic = MSG_PART_MAGIC;
1384 }
1385 return r;
1386}
1387/* }}} */
1388