From 8ad5053c668ea0eaed518dcda6a64dc0c896a197 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Fri, 15 Nov 2013 04:08:24 +0400 Subject: [PATCH] Partial support for binlog. It now can track user, secret chat and auth updates. --- Makefile | 2 +- Makefile.in | 2 +- binlog.c | 220 +++++++++++++++++++++++++++++++++++++++++++++-- binlog.h | 17 ++++ loop.c | 19 +++- mtproto-client.c | 48 ++++++++++- mtproto-common.h | 47 ++++++++++ queries.c | 111 +++++++++++++++++++++--- queries.h | 1 + structures.c | 205 ++++++++++++++++++++++++++++--------------- structures.h | 13 ++- 11 files changed, 589 insertions(+), 96 deletions(-) diff --git a/Makefile b/Makefile index 3765171..c7e68f3 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DEFS=-DHAVE_CONFIG_H COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS= -lreadline -lrt -lconfig -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/Makefile.in b/Makefile.in index ba23e05..1bf9014 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,7 @@ DEFS=@DEFS@ COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Werror -Wno-deprecated -fno-strict-aliasing -fno-omit-frame-pointer -ggdb EXTRA_LIBS=@EXTRA_LIBS@ -LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic ${EXTRA_LIBS} +LOCAL_LDFLAGS=-lm -lcrypto -lz -lssl -rdynamic -ggdb ${EXTRA_LIBS} LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS} HEADERS= ${srcdir}/constants.h ${srcdir}/include.h ${srcdir}/interface.h ${srcdir}/LICENSE.h ${srcdir}/loop.h ${srcdir}/mtproto-client.h ${srcdir}/mtproto-common.h ${srcdir}/net.h ${srcdir}/no-preview.h ${srcdir}/queries.h ${srcdir}/structures.h ${srcdir}/telegram.h ${srcdir}/tree.h ${srcdir}/config.h ${srcdir}/binlog.h diff --git a/binlog.c b/binlog.c index ec905d8..73d543c 100644 --- a/binlog.c +++ b/binlog.c @@ -11,10 +11,7 @@ #include "binlog.h" #include "mtproto-common.h" #include "net.h" - -#define LOG_START 0x8948329a -#define LOG_AUTH_KEY 0x984932aa -#define LOG_DEFAULT_DC 0x95382908 +#include "include.h" #define BINLOG_BUFFER_SIZE (1 << 20) int binlog_buffer[BINLOG_BUFFER_SIZE]; @@ -28,6 +25,14 @@ char *get_binlog_file_name (void); extern struct dc *DC_list[]; extern struct dc *DC_working; extern int dc_working_num; +extern int our_id; +extern int binlog_enabled; + +int in_replay_log; + +void *alloc_log_event (int l UU) { + return binlog_buffer; +} void replay_log_event (void) { assert (rptr < wptr); @@ -41,6 +46,7 @@ void replay_log_event (void) { return; case CODE_dc_option: fetch_dc_option (); + rptr = in_ptr; return; case LOG_AUTH_KEY: rptr ++; @@ -52,6 +58,7 @@ void replay_log_event (void) { rptr += 2; memcpy (DC_list[num]->auth_key, rptr, 256); rptr += 64; + DC_list[num]->flags |= 1; }; return; case LOG_DEFAULT_DC: @@ -63,6 +70,180 @@ void replay_log_event (void) { dc_working_num = num; } return; + case LOG_OUR_ID: + rptr ++; + { + our_id = *(rptr ++); + } + break; + case LOG_DC_SIGNED: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->has_auth = 1; + } + break; + case LOG_DC_SALT: + rptr ++; + { + int num = *(rptr ++); + assert (num >= 0 && num <= MAX_DC_ID); + assert (DC_list[num]); + DC_list[num]->server_salt = *(long long *)rptr; + rptr += 2; + }; + break; + case CODE_user_empty: + case CODE_user_self: + case CODE_user_contact: + case CODE_user_request: + case CODE_user_foreign: + case CODE_user_deleted: + fetch_alloc_user (); + rptr = in_ptr; + return; + case LOG_DH_CONFIG: + get_dh_config_on_answer (0); + rptr = in_ptr; + return; + case LOG_ENCR_CHAT_KEY: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + memcpy (U->key, rptr, 256); + rptr += 64; + }; + return; + case LOG_ENCR_CHAT_SEND_ACCEPT: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->key_fingerprint = *(long long *)rptr; + rptr += 2; + memcpy (U->key, rptr, 256); + rptr += 64; + if (!U->g_key) { + U->g_key = malloc (256); + } + memcpy (U->g_key, rptr, 256); + rptr += 64; + }; + return; + case LOG_ENCR_CHAT_SEND_CREATE: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (!U || (U->flags & FLAG_EMPTY)); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->user_id = *(rptr ++); + memcpy (U->key, rptr, 256); + rptr += 64; + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } + } + }; + return; + case LOG_ENCR_CHAT_DELETED: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->state = sc_deleted; + }; + return; + case LOG_ENCR_CHAT_WAITING: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->state = sc_waiting; + U->date = *(rptr ++); + U->admin_id = *(rptr ++); + U->user_id = *(rptr ++); + U->access_hash = *(long long *)rptr; + rptr += 2; + }; + return; + case LOG_ENCR_CHAT_REQUESTED: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + if (!U) { + U = malloc (sizeof (peer_t)); + memset (U, 0, sizeof (peer_t)); + U->id = id; + insert_encrypted_chat ((void *)U); + } else { + U->flags &= ~FLAG_EMPTY; + } + U->flags |= FLAG_CREATED; + U->state = sc_request; + U->date = *(rptr ++); + U->admin_id = *(rptr ++); + U->user_id = *(rptr ++); + U->access_hash = *(long long *)rptr; + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } + } + rptr += 2; + }; + return; + case LOG_ENCR_CHAT_OK: + rptr ++; + { + peer_id_t id = MK_ENCR_CHAT (*(rptr ++)); + struct secret_chat *U = (void *)user_chat_get (id); + assert (U); + U->state = sc_ok; + } + return; + + default: + logprintf ("Unknown logevent [0x%08x] 0x%08x [0x%08x]\n", *(rptr - 1), op, *(rptr + 1)); + + assert (0); } } @@ -71,20 +252,27 @@ void create_new_binlog (void) { packet_ptr = s; out_int (LOG_START); out_int (CODE_dc_option); - out_int (0); + out_int (1); out_string (""); out_string (test_dc ? TG_SERVER_TEST : TG_SERVER); out_int (443); + out_int (LOG_DEFAULT_DC); + out_int (1); - int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL); + int fd = open (get_binlog_file_name (), O_WRONLY | O_EXCL | O_CREAT, 0600); + if (fd < 0) { + perror ("Write new binlog"); + exit (2); + } assert (write (fd, s, (packet_ptr - s) * 4) == (packet_ptr - s) * 4); close (fd); } void replay_log (void) { + in_replay_log = 1; if (access (get_binlog_file_name (), F_OK) < 0) { - printf ("No binlog found. Creating new one"); + printf ("No binlog found. Creating new one\n"); create_new_binlog (); } int fd = open (get_binlog_file_name (), O_RDONLY); @@ -92,7 +280,7 @@ void replay_log (void) { perror ("binlog open"); exit (2); } - int end; + int end = 0; while (1) { if (!end && wptr - rptr < MAX_LOG_EVENT_SIZE / 4) { if (wptr == rptr) { @@ -119,4 +307,20 @@ void replay_log (void) { replay_log_event (); } close (fd); + in_replay_log = 0; +} + +int binlog_fd; +void write_binlog (void) { + binlog_fd = open (get_binlog_file_name (), O_WRONLY); + if (binlog_fd < 0) { + perror ("binlog open"); + exit (2); + } + lseek (binlog_fd, 0, SEEK_END); +} + +void add_log_event (const int *data, int len) { + if (in_replay_log) { return; } + assert (write (binlog_fd, data, len) == len); } diff --git a/binlog.h b/binlog.h index a950682..9c77d78 100644 --- a/binlog.h +++ b/binlog.h @@ -1,6 +1,23 @@ #ifndef __BINLOG_H__ #define __BINLOG_H__ +#define LOG_START 0x8948329a +#define LOG_AUTH_KEY 0x984932aa +#define LOG_DEFAULT_DC 0x95382908 +#define LOG_OUR_ID 0x8943211a +#define LOG_DC_SIGNED 0x234f9893 +#define LOG_DC_SALT 0x92192ffa +#define LOG_DH_CONFIG 0x8983402b +#define LOG_ENCR_CHAT_KEY 0x894320aa +#define LOG_ENCR_CHAT_SEND_ACCEPT 0x12ab01c4 +#define LOG_ENCR_CHAT_SEND_CREATE 0xab091e24 +#define LOG_ENCR_CHAT_DELETED 0x99481230 +#define LOG_ENCR_CHAT_WAITING 0x7102100a +#define LOG_ENCR_CHAT_REQUESTED 0x9011011a +#define LOG_ENCR_CHAT_OK 0x7612ce13 + void *alloc_log_event (int l); void replay_log (void); +void add_log_event (const int *data, int l); +void write_binlog (void); #endif diff --git a/loop.c b/loop.c index 5cfcdb3..fa93451 100644 --- a/loop.c +++ b/loop.c @@ -160,6 +160,7 @@ void write_dc (int auth_file_fd, struct dc *DC) { int our_id; void write_auth_file (void) { + if (binlog_enabled) { return; } int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); assert (auth_file_fd >= 0); int x = DC_SERIALIZED_MAGIC_V2; @@ -216,6 +217,7 @@ void empty_auth_file (void) { int need_dc_list_update; void read_auth_file (void) { + if (binlog_enabled) { return; } int auth_file_fd = open (get_auth_key_filename (), O_CREAT | O_RDWR, 0600); if (auth_file_fd < 0) { empty_auth_file (); @@ -308,6 +310,7 @@ extern unsigned char *encr_prime; extern int encr_param_version; void read_secret_chat_file (void) { + if (binlog_enabled) { return; } int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -364,6 +367,7 @@ void read_secret_chat_file (void) { } void write_secret_chat_file (void) { + if (binlog_enabled) { return; } int fd = open (get_secret_chat_filename (), O_CREAT | O_RDWR, 0600); if (fd < 0) { return; @@ -430,12 +434,15 @@ int loop (void) { on_start (); if (binlog_enabled) { replay_log (); + write_binlog (); + } else { + read_auth_file (); } - read_auth_file (); update_prompt (); assert (DC_list[dc_working_num]); - if (auth_state == 0) { + if (!DC_working || !DC_working->auth_key_id) { +// if (auth_state == 0) { DC_working = DC_list[dc_working_num]; assert (!DC_working->auth_key_id); dc_authorize (DC_working); @@ -459,7 +466,7 @@ int loop (void) { write_auth_file (); } - if (auth_state == 100) { + if (auth_state == 100 || !(DC_working->has_auth)) { if (!default_username) { size_t size = 0; char *user = 0; @@ -546,6 +553,12 @@ int loop (void) { do_export_auth (i); do_import_auth (i); DC_list[i]->has_auth = 1; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = i; + add_log_event (ev, 8); + } write_auth_file (); } write_auth_file (); diff --git a/mtproto-client.c b/mtproto-client.c index 32e9567..4c1c1c0 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -44,6 +44,7 @@ #include "loop.h" #include "interface.h" #include "structures.h" +#include "binlog.h" #define sha1 SHA1 @@ -57,6 +58,7 @@ enum dc_state c_state; char nonce[256]; char new_nonce[256]; char server_nonce[256]; +extern int binlog_enabled; int rpc_execute (struct connection *c, int op, int len); int rpc_becomes_ready (struct connection *c); @@ -509,6 +511,13 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { sha1 (tmp, 41, sha1_buffer); assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); GET_DC(c)->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ if (verbosity >= 3) { logprintf ( "auth_key_id=%016llx\n", GET_DC(c)->auth_key_id); } @@ -525,6 +534,15 @@ int process_auth_complete (struct connection *c UU, char *packet, int len) { auth_success ++; GET_DC(c)->flags |= 1; write_auth_file (); + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_AUTH_KEY; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->auth_key_id; + memcpy (ev + 4, GET_DC(c)->auth_key, 256); + add_log_event (ev, 8 + 8 + 256); + } + return 1; } @@ -559,7 +577,7 @@ void init_enc_msg (struct session *S, int useful) { struct dc *DC = S->dc; assert (DC->auth_key_id); enc_msg.auth_key_id = DC->auth_key_id; - assert (DC->server_salt); +// assert (DC->server_salt); enc_msg.server_salt = DC->server_salt; if (!S->session_id) { assert (RAND_pseudo_bytes ((unsigned char *) &S->session_id, 8) >= 0); @@ -1213,6 +1231,14 @@ void work_new_session_created (struct connection *c, long long msg_id UU) { //DC->session_id = fetch_long (); fetch_long (); // unique_id GET_DC(c)->server_salt = fetch_long (); + +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ } void work_msgs_ack (struct connection *c UU, long long msg_id UU) { @@ -1294,6 +1320,13 @@ void work_bad_server_salt (struct connection *c UU, long long msg_id UU) { fetch_int (); // error_code long long new_server_salt = fetch_long (); GET_DC(c)->server_salt = new_server_salt; +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = GET_DC(c)->id; + *(long long *)(ev + 2) = GET_DC(c)->server_salt; + add_log_event (ev, 16); + }*/ } void work_pong (struct connection *c UU, long long msg_id UU) { @@ -1389,6 +1422,13 @@ int process_rpc_message (struct connection *c UU, struct encrypted_message *enc, if (DC->server_salt != enc->server_salt) { DC->server_salt = enc->server_salt; write_auth_file (); +/* if (binlog_enabled) { + int *ev = alloc_log_event (16); + ev[0] = LOG_DC_SALT; + ev[1] = DC->id; + *(long long *)(ev + 2) = DC->server_salt; + add_log_event (ev, 16); + }*/ } int this_server_time = enc->msg_id >> 32LL; @@ -1475,7 +1515,11 @@ int rpc_execute (struct connection *c, int op, int len) { #endif return 0; case st_authorized: - process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + if (op < 0 && op >= -999) { + logprintf ("Server error %d\n", op); + } else { + process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); + } #ifndef __MACH__ setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); #endif diff --git a/mtproto-common.h b/mtproto-common.h index df696cc..ee6cf9d 100644 --- a/mtproto-common.h +++ b/mtproto-common.h @@ -307,6 +307,53 @@ static inline char *fetch_str_dup (void) { return s; } +static inline int fetch_update_str (char **s) { + if (!*s) { + *s = fetch_str_dup (); + return 1; + } + int l = prefetch_strlen (); + char *r = fetch_str (l); + if (memcmp (*s, r, l) || (*s)[l]) { + free (*s); + *s = malloc (l + 1); + memcpy (*s, r, l); + (*s)[l] = 0; + return 1; + } + return 0; +} + +static inline int fetch_update_int (int *value) { + if (*value == *in_ptr) { + in_ptr ++; + return 0; + } else { + *value = *(in_ptr ++); + return 1; + } +} + +static inline int fetch_update_long (long long *value) { + if (*value == *(long long *)in_ptr) { + in_ptr += 2; + return 0; + } else { + *value = *(long long *)(in_ptr); + in_ptr += 2; + return 1; + } +} + +static inline int set_update_int (int *value, int new_value) { + if (*value == new_value) { + return 0; + } else { + *value = new_value; + return 1; + } +} + static inline void fetch_skip (int n) { in_ptr += n; } diff --git a/queries.c b/queries.c index 7b58fb2..8c91003 100644 --- a/queries.c +++ b/queries.c @@ -44,6 +44,7 @@ #include #include "no-preview.h" +#include "binlog.h" #define sha1 SHA1 @@ -55,6 +56,8 @@ long long cur_uploaded_bytes; long long cur_downloading_bytes; long long cur_downloaded_bytes; +extern int binlog_enabled; + void out_peer_id (peer_id_t id); #define QUERY_TIMEOUT 6.0 @@ -303,6 +306,7 @@ void out_random (int n) { /* {{{ Get config */ void fetch_dc_option (void) { + int *start = in_ptr; assert (fetch_int () == CODE_dc_option); int id = fetch_int (); int l1 = prefetch_strlen (); @@ -316,6 +320,9 @@ void fetch_dc_option (void) { if (!DC_list[id]) { alloc_dc (id, strndup (ip, l2), port); new_dc_num ++; + if (binlog_enabled) { + add_log_event (start, 4 * (in_ptr - start)); + } } } @@ -424,6 +431,13 @@ void do_send_code (const char *user) { dc_create_session (DC_working); } dc_working_num = want_dc_num; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = dc_working_num; + add_log_event (ev, 8); + } + logprintf ("send_code: dc_num = %d\n", dc_working_num); want_dc_num = 0; clear_packet (); @@ -463,11 +477,27 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error dc_working_num = i; DC_working = DC_list[i]; write_auth_file (); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = i; + add_log_event (ev, 8); + } + check_phone_result = 1; } else if (l >= s2 && !memcmp (error, "NETWORK_MIGRATE_", s2)) { int i = error[s2] - '0'; assert (DC_list[i]); dc_working_num = i; + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DEFAULT_DC; + ev[1] = i; + add_log_event (ev, 8); + } + DC_working = DC_list[i]; write_auth_file (); check_phone_result = 1; @@ -536,6 +566,7 @@ int do_get_nearest_dc (void) { /* {{{ Sign in / Sign up */ int sign_in_ok; +int our_id; int sign_in_is_ok (void) { return sign_in_ok; } @@ -546,11 +577,28 @@ int sign_in_on_answer (struct query *q UU) { assert (fetch_int () == (int)CODE_auth_authorization); int expires = fetch_int (); fetch_user (&User); + if (!our_id) { + our_id = get_peer_id (User.id); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = our_id; + add_log_event (ev, 8); + } + } sign_in_ok = 1; if (verbosity) { logprintf ( "authorized successfully: name = '%s %s', phone = '%s', expires = %d\n", User.first_name, User.last_name, User.phone, (int)(expires - get_double_time ())); } DC_working->has_auth = 1; + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_DC_SIGNED; + ev[1] = DC_working->id; + add_log_event (ev, 8); + } + return 0; } @@ -734,7 +782,7 @@ void encr_finish (struct secret_chat *E) { /* {{{ Seng msg (plain text) */ int msg_send_encr_on_answer (struct query *q UU) { assert (fetch_int () == CODE_messages_sent_encrypted_message); - logprintf ("Sent\n"); + rprintf ("Sent\n"); struct message *M = q->extra; M->date = fetch_int (); message_insert (M); @@ -790,7 +838,7 @@ int msg_send_on_answer (struct query *q UU) { print_end (); } } - logprintf ("Sent: id = %d\n", id); + rprintf ("Sent: id = %d\n", id); return 0; } @@ -2113,6 +2161,8 @@ int send_encr_request_on_answer (struct query *q UU) { printf ("\n"); pop_color (); print_end (); + + assert (E->state == sc_waiting); } return 0; } @@ -2156,10 +2206,18 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { sha1 ((void *)E->key, 256, sha_buffer); E->key_fingerprint = *(long long *)(sha_buffer + 12); + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_ENCR_CHAT_KEY; + ev[1] = get_peer_id (E->id); + *(long long *)(ev + 2) = E->key_fingerprint; + memcpy (ev + 4, E->key, 256); + add_log_event (ev, 8 + 8 + 256); + } + clear_packet (); out_int (CODE_messages_accept_encryption); out_int (CODE_input_encrypted_chat); - logprintf ("id = %d\n", get_peer_id (E->id)); out_int (get_peer_id (E->id)); out_long (E->access_hash); @@ -2175,15 +2233,22 @@ void do_send_accept_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (g_a); BN_clear_free (p); BN_clear_free (r); + + if (binlog_enabled) { + int *ev = alloc_log_event (16 + 512); + ev[0] = LOG_ENCR_CHAT_SEND_ACCEPT; + ev[1] = get_peer_id (E->id); + *(long long *)(ev + 2) = E->key_fingerprint; + memcpy (ev + 4, E->key, 256); + memcpy (ev + 68, buf, 256); + add_log_event (ev, 16 + 512); + } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_accept_methods, E); } void do_create_keys_end (struct secret_chat *U) { - if (!encr_prime) { - rprintf (COLOR_YELLOW "Something failed in bad moment. Did not fail\n"COLOR_NORMAL); - return; - } + assert (encr_prime); BIGNUM *g_b = BN_bin2bn (U->g_key, 256, 0); assert (g_b); if (!ctx) { @@ -2212,6 +2277,15 @@ void do_create_keys_end (struct secret_chat *U) { BN_clear_free (g_b); BN_clear_free (r); BN_clear_free (a); + + if (binlog_enabled) { + int *ev = alloc_log_event (8 + 8 + 256); + ev[0] = LOG_ENCR_CHAT_KEY; + ev[1] = get_peer_id (U->id); + *(long long *)(ev + 2) = U->key_fingerprint; + memcpy (ev + 4, U->key, 256); + add_log_event (ev, 8 + 8 + 256); + } } void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { @@ -2264,20 +2338,36 @@ void do_send_create_encr_chat (struct secret_chat *E, unsigned char *random) { BN_clear_free (p); BN_clear_free (r); + if (binlog_enabled) { + int *ev = alloc_log_event (12 + 256); + ev[0] = LOG_ENCR_CHAT_SEND_CREATE; + ev[1] = get_peer_id (E->id); + ev[2] = E->user_id; + memcpy (ev + 3, E->key, 256); + add_log_event (ev, 12 + 256); + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E); } int get_dh_config_on_answer (struct query *q UU) { + int *start = in_ptr; unsigned x = fetch_int (); - assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified); - if (x == CODE_messages_dh_config) { + assert (x == CODE_messages_dh_config || x == CODE_messages_dh_config_not_modified || LOG_DH_CONFIG); + if (x == CODE_messages_dh_config || x == LOG_DH_CONFIG) { encr_root = fetch_int (); if (encr_prime) { free (encr_prime); } int l = prefetch_strlen (); assert (l == 256); encr_prime = (void *)fetch_str_dup (); encr_param_version = fetch_int (); + if (binlog_enabled) { + *start = LOG_DH_CONFIG; + add_log_event (start, 4 * (in_ptr - start)); + *start = CODE_messages_dh_config; + } } + if (x == LOG_DH_CONFIG) { return 0; } int l = prefetch_strlen (); assert (l == 256); unsigned char *random = (void *)fetch_str_dup (); @@ -2411,7 +2501,7 @@ struct query_methods get_difference_methods = { void do_get_difference (void) { difference_got = 0; clear_packet (); - out_int (CODE_invoke_with_layer10); + out_int (CODE_invoke_with_layer9); out_int (CODE_init_connection); out_int (TG_APP_ID); if (allow_send_linux_version) { @@ -2568,6 +2658,7 @@ void do_create_secret_chat (peer_id_t id) { peer_t *U = user_chat_get (id); if (!U) { rprintf ("Can not create chat with unknown user\n"); + return; } peer_t *P = malloc (sizeof (*P)); diff --git a/queries.h b/queries.h index 32a613e..20015ca 100644 --- a/queries.h +++ b/queries.h @@ -111,5 +111,6 @@ void do_contacts_search (int limit, const char *s); // For binlog +int get_dh_config_on_answer (struct query *q); void fetch_dc_option (void); #endif diff --git a/structures.c b/structures.c index 2e7788f..334d65b 100644 --- a/structures.c +++ b/structures.c @@ -30,6 +30,7 @@ #include #include #include "queries.h" +#include "binlog.h" #define sha1 SHA1 @@ -40,24 +41,37 @@ int peer_num; int encr_chats_allocated; int geo_chats_allocated; -void fetch_file_location (struct file_location *loc) { - int x = fetch_int (); - if (x == CODE_file_location_unavailable) { - loc->dc = -1; - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); - } else { - assert (x == CODE_file_location); - loc->dc = fetch_int ();; - loc->volume = fetch_long (); - loc->local_id = fetch_int (); - loc->secret = fetch_long (); +extern int binlog_enabled; + +void fetch_add_alloc_log_event (void *obj, int (*f)(void *)) { + int *start = in_ptr; + int r = f (obj); + if (binlog_enabled && r) { + add_log_event (start, 4 * (in_ptr - start)); } } -void fetch_user_status (struct user_status *S) { +int fetch_file_location (struct file_location *loc) { int x = fetch_int (); + int new = 0; + if (x == CODE_file_location_unavailable) { + new |= set_update_int (&loc->dc, -1); + new |= fetch_update_long (&loc->volume); + new |= fetch_update_int (&loc->local_id); + new |= fetch_update_long (&loc->secret); + } else { + assert (x == CODE_file_location); + new |= fetch_update_int (&loc->dc); + new |= fetch_update_long (&loc->volume); + new |= fetch_update_int (&loc->local_id); + new |= fetch_update_long (&loc->secret); + } + return new; +} + +int fetch_user_status (struct user_status *S) { + int x = fetch_int (); + int old = S->online; switch (x) { case CODE_user_status_empty: S->online = 0; @@ -73,6 +87,7 @@ void fetch_user_status (struct user_status *S) { default: assert (0); } + return (old == S->online); } int our_id; @@ -134,72 +149,83 @@ char *create_print_name (peer_id_t id, const char *a1, const char *a2, const cha return strdup (s); } -void fetch_user (struct user *U) { +int fetch_user (struct user *U) { unsigned x = fetch_int (); assert (x == CODE_user_empty || x == CODE_user_self || x == CODE_user_contact || x == CODE_user_request || x == CODE_user_foreign || x == CODE_user_deleted); U->id = MK_USER (fetch_int ()); - U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT); + if ((U->flags & FLAG_CREATED) && x == CODE_user_empty) { + return 0; + } + int old_flags = U->flags; + U->flags &= ~(FLAG_EMPTY | FLAG_DELETED | FLAG_USER_SELF | FLAG_USER_FOREIGN | FLAG_USER_CONTACT | FLAG_CREATED); if (x == CODE_user_empty) { U->flags |= FLAG_EMPTY; - return; + return 0; } + U->flags |= FLAG_CREATED; if (x == CODE_user_self) { assert (!our_id || (our_id == get_peer_id (U->id))); if (!our_id) { our_id = get_peer_id (U->id); write_auth_file (); + + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_OUR_ID; + ev[1] = our_id; + add_log_event (ev, 8); + } } } - if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->last_name); } - if (U->print_name) { free (U->print_name); } - U->first_name = fetch_str_dup (); - U->last_name = fetch_str_dup (); - - U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + int need_update = 0; + need_update |= fetch_update_str (&U->first_name); + need_update |= fetch_update_str (&U->last_name); + if (need_update) { + if (U->print_name) { free (U->print_name); } + U->print_name = create_print_name (U->id, U->first_name, U->last_name, 0, 0); + } if (x == CODE_user_deleted) { U->flags |= FLAG_DELETED; - return; - } - if (x == CODE_user_self) { - U->flags |= FLAG_USER_SELF; } else { - U->access_hash = fetch_long (); - } - if (x == CODE_user_foreign) { - U->flags |= FLAG_USER_FOREIGN; - U->phone = 0; - } else { - if (U->phone) { free (U->phone); } - U->phone = fetch_str_dup (); - } - //logprintf ("name = %s, surname = %s, phone = %s\n", U->first_name, U->last_name, U->phone); - unsigned y = fetch_int (); - //fprintf (stderr, "y = 0x%08x\n", y); - if (y == CODE_user_profile_photo_empty) { - U->photo_small.dc = -2; - U->photo_big.dc = -2; - } else { - assert (y == CODE_user_profile_photo || y == 0x990d1493); - if (y == CODE_user_profile_photo) { - fetch_long (); + if (x == CODE_user_self) { + U->flags |= FLAG_USER_SELF; + } else { + need_update |= fetch_update_long (&U->access_hash); + } + if (x == CODE_user_foreign) { + U->flags |= FLAG_USER_FOREIGN; + } else { + need_update |= fetch_update_str (&U->phone); + } + unsigned y = fetch_int (); + if (y == CODE_user_profile_photo_empty) { + need_update |= set_update_int (&U->photo_small.dc, -2); + need_update |= set_update_int (&U->photo_big.dc, -2); + } else { + assert (y == CODE_user_profile_photo); + fetch_long (); + need_update |= fetch_file_location (&U->photo_small); + need_update |= fetch_file_location (&U->photo_big); + } + fetch_user_status (&U->status); + if (x == CODE_user_self) { + fetch_bool (); + } + if (x == CODE_user_contact) { + U->flags |= FLAG_USER_CONTACT; } - fetch_file_location (&U->photo_small); - fetch_file_location (&U->photo_big); - } - fetch_user_status (&U->status); - if (x == CODE_user_self) { - fetch_bool (); - } - if (x == CODE_user_contact) { - U->flags |= FLAG_USER_CONTACT; } + need_update |= (old_flags != U->flags); + return need_update; } void fetch_encrypted_chat (struct secret_chat *U) { unsigned x = fetch_int (); assert (x == CODE_encrypted_chat_empty || x == CODE_encrypted_chat_waiting || x == CODE_encrypted_chat_requested || x == CODE_encrypted_chat || x == CODE_encrypted_chat_discarded); U->id = MK_ENCR_CHAT (fetch_int ()); + if ((U->flags & FLAG_CREATED) && x == CODE_encrypted_chat_empty) { + return; + } U->flags &= ~(FLAG_EMPTY | FLAG_DELETED); enum secret_chat_state old_state = U->state; if (x == CODE_encrypted_chat_empty) { @@ -210,11 +236,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { } return; } + U->flags |= FLAG_CREATED; if (x == CODE_encrypted_chat_discarded) { U->state = sc_deleted; U->flags |= FLAG_DELETED; if (U->state != old_state) { write_secret_chat_file (); + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_ENCR_CHAT_DELETED; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); + } } return; } @@ -222,19 +255,31 @@ void fetch_encrypted_chat (struct secret_chat *U) { U->date = fetch_int (); U->admin_id = fetch_int (); U->user_id = fetch_int () + U->admin_id - our_id; - if (U->print_name) { free (U->print_name); } - - peer_t *P = user_chat_get (MK_USER (U->user_id)); - if (P) { - U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); - } else { - static char buf[100]; - sprintf (buf, "user#%d", U->user_id); - U->print_name = create_print_name (U->id, "!", buf, 0, 0); + if (!U->print_name) { + peer_t *P = user_chat_get (MK_USER (U->user_id)); + if (P) { + U->print_name = create_print_name (U->id, "!", P->user.first_name, P->user.last_name, 0); + } else { + static char buf[100]; + sprintf (buf, "user#%d", U->user_id); + U->print_name = create_print_name (U->id, "!", buf, 0, 0); + } } if (x == CODE_encrypted_chat_waiting) { U->state = sc_waiting; + if (old_state != sc_waiting) { + if (binlog_enabled) { + int *ev = alloc_log_event (28); + ev[0] = LOG_ENCR_CHAT_WAITING; + ev[1] = get_peer_id (U->id); + ev[2] = U->date; + ev[3] = U->admin_id; + ev[4] = U->user_id; + *(long long *)(ev + 5) = U->access_hash; + add_log_event (ev, 28); + } + } } else if (x == CODE_encrypted_chat_requested) { U->state = sc_request; if (!U->g_key) { @@ -259,6 +304,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { } else { memcpy (U->nonce, s + (l - 256), 256); } + if (old_state != sc_request) { + if (binlog_enabled) { + int *ev = alloc_log_event (28); + ev[0] = LOG_ENCR_CHAT_REQUESTED; + ev[1] = get_peer_id (U->id); + ev[2] = U->date; + ev[3] = U->admin_id; + ev[4] = U->user_id; + *(long long *)(ev + 5) = U->access_hash; + add_log_event (ev, 28); + } + } } else { U->state = sc_ok; if (!U->g_key) { @@ -291,6 +348,18 @@ void fetch_encrypted_chat (struct secret_chat *U) { if (old_state == sc_waiting) { do_create_keys_end (U); } + free (U->g_key); + U->g_key = 0; + free (U->nonce); + U->nonce = 0; + if (old_state != sc_ok) { + if (binlog_enabled) { + int *ev = alloc_log_event (8); + ev[0] = LOG_ENCR_CHAT_OK; + ev[1] = get_peer_id (U->id); + add_log_event (ev, 8); + } + } } if (U->state != old_state) { write_secret_chat_file (); @@ -941,13 +1010,13 @@ struct user *fetch_alloc_user (void) { prefetch_data (data, 8); peer_t *U = user_chat_get (MK_USER (data[1])); if (U) { - fetch_user (&U->user); + fetch_add_alloc_log_event (&U->user, (void *)fetch_user); return &U->user; } else { users_allocated ++; U = malloc (sizeof (*U)); memset (U, 0, sizeof (*U)); - fetch_user (&U->user); + fetch_add_alloc_log_event (&U->user, (void *)fetch_user); peer_tree = tree_insert_peer (peer_tree, U, lrand48 ()); Peers[peer_num ++] = U; return &U->user; @@ -1343,7 +1412,7 @@ int print_stat (char *s, int len) { } peer_t *user_chat_get (peer_id_t id) { - peer_t U; + static peer_t U; U.id = id; return tree_lookup_peer (peer_tree, &U); } diff --git a/structures.h b/structures.h index fe34654..a06627a 100644 --- a/structures.h +++ b/structures.h @@ -26,6 +26,7 @@ typedef struct { int type; int id; } peer_id_t; #define FLAG_DELETED 2 #define FLAG_FORBIDDEN 4 #define FLAG_HAS_PHOTO 8 +#define FLAG_CREATED 16 #define FLAG_USER_SELF 128 #define FLAG_USER_FOREIGN 256 @@ -113,6 +114,7 @@ struct user { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -137,6 +139,7 @@ struct chat { int flags; struct message *last; char *print_title; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -161,6 +164,7 @@ struct secret_chat { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -183,6 +187,7 @@ typedef union peer { int flags; struct message *last; char *print_name; + int structure_version; struct file_location photo_big; struct file_location photo_small; struct photo photo; @@ -262,9 +267,9 @@ struct message { }; }; -void fetch_file_location (struct file_location *loc); -void fetch_user_status (struct user_status *S); -void fetch_user (struct user *U); +int fetch_file_location (struct file_location *loc); +int fetch_user_status (struct user_status *S); +int fetch_user (struct user *U); struct user *fetch_alloc_user (void); struct user *fetch_alloc_user_full (void); struct chat *fetch_alloc_chat (void); @@ -281,6 +286,8 @@ peer_id_t fetch_peer_id (void); void free_user (struct user *U); void free_chat (struct chat *U); +char *create_print_name (peer_id_t id, const char *a1, const char *a2, const char *a3, const char *a4); + int print_stat (char *s, int len); peer_t *user_chat_get (peer_id_t id); struct message *message_get (long long id);