Implement state machine for dc discovery and login.

This commit is contained in:
mjentsch 2014-08-08 08:45:58 +02:00
parent f1a2738783
commit 1170ae5710
8 changed files with 139 additions and 84 deletions

View file

@ -238,6 +238,9 @@ int rpc_send_message (struct connection *c, void *data, int len) {
self->total_packets_sent ++;
self->total_data_sent += total_len;
self->queries_num ++;
logprintf("queries_num=%d\n", self->queries_num);
return 1;
}
@ -1787,6 +1790,7 @@ int tc_becomes_ready (struct connection *c) {
break;
case st_authorized:
auth_work_start (c);
telegram_change_state(c->instance, STATE_AUTHORIZED, NULL);
break;
default:
logprintf ( "c_state = %d\n", c->mtconnection->c_state);
@ -1890,3 +1894,4 @@ void mtproto_close(struct mtproto_connection *c)
// stop_ping_timer (c->connection);
fd_close_connection(c->connection);
}

3
net.c
View file

@ -722,10 +722,11 @@ struct connection *fd_create_connection (struct dc *DC, int fd,
S->c = c;
DC->sessions[0] = S;
}
// add backreference to session
c->session = DC->sessions[0];
// add backreference to used mtproto-connection
c->mtconnection = mtp;
return c;
}

View file

@ -203,18 +203,18 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d
do_send_code_result_auth (instance, code, hash, first_name, last_name);
break;
case STATE_PHONE_CODE_NOT_ENTERED:
purple_connection_set_state(_gc, PURPLE_CONNECTED);
case STATE_PHONE_CODE_NOT_ENTERED: {
char *hash = data;
const char *code = purple_account_get_string(conn->pa, "verification_key", NULL);
do_send_code_result(instance, code, hash);
// TODO: Request SMS code
break;
case STATE_CLIENT_NOT_REGISTERED:
// ask for registration type
}
break;
case STATE_CLIENT_CODE_NOT_ENTERED: {
char *hash = data;
const char *code = purple_account_get_string(conn->pa, "verification_key", NULL);
const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL);
//const char *hash = purple_account_get_string(conn->pa, "verification_hash", NULL);
do_send_code_result(instance, code, hash);
// enter SMS code
}
@ -248,7 +248,9 @@ static void tgprpl_on_state_change(struct telegram *instance, int state, void *d
// get new messages
purple_debug_info(PLUGIN_ID, "Fetching new messages...\n");
do_get_difference(instance);
telegram_flush_queries(instance);
tgprpl_has_output(instance);
//telegram_flush_queries(instance);
break;
case STATE_ERROR: {
@ -302,15 +304,12 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa
purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n");
struct telegram *tg = (struct telegram*) data;
telegram_conn *conn = tg->extra;
//running_for_first_time();
if (fd == -1) {
logprintf("purple_proxy_connect failed: %s\n", error_message);
telegram_free(tg);
return;
}
purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n");
conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg);
conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg);

View file

@ -140,11 +140,6 @@ void query_restart (long long id) {
struct query *send_query (struct dc *DC, int ints, void *data, struct query_methods *methods, void *extra) {
logprintf("send_query(...)\n");
/*
if (!DC->sessions[0]) {
dc_create_session (DC);
}
*/
if (verbosity) {
logprintf ( "Sending query of size %d to DC (%s:%d)\n", 4 * ints, DC->ip, DC->port);
}
@ -173,8 +168,10 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth
insert_event_timer (&q->ev);
q->extra = extra;
//queries_num ++;
//logprintf("queries_num: %d\n", queries_num);
struct mtproto_connection *mtp = DC->sessions[0]->c->mtconnection;
mtp->queries_num ++;
logprintf("queries_num: %d\n", mtp->queries_num);
return q;
}
@ -211,8 +208,9 @@ void query_error (long long id) {
tfree (q->data, q->data_len * 4);
tfree (q, sizeof (*q));
}
//queries_num --;
//logprintf("queries_num: %d\n", queries_num);
mtp->queries_num --;
logprintf("queries_num: %d\n", mtp->queries_num);
}
#define MAX_PACKED_SIZE (1 << 24)
@ -355,9 +353,7 @@ void fetch_dc_option (struct telegram *instance) {
int l2 = prefetch_strlen (mtp);
char *ip = fetch_str (mtp, l2);
int port = fetch_int (mtp);
if (verbosity) {
logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port);
}
logprintf ( "id = %d, name = %.*s ip = %.*s port = %d\n", id, l1, name, l2, ip, port);
bl_do_dc_option (mtp, id, l1, name, l2, ip, port, instance);
}
@ -374,9 +370,7 @@ int help_get_config_on_answer (struct query *q UU) {
assert (test_mode == CODE_bool_true || test_mode == CODE_bool_false);
assert (test_mode == CODE_bool_false || test_mode == CODE_bool_true);
int this_dc = fetch_int (mtp);
if (verbosity) {
logprintf ( "this_dc = %d\n", this_dc);
}
logprintf ( "this_dc = %d\n", this_dc);
assert (fetch_int (mtp) == CODE_vector);
int n = fetch_int (mtp);
assert (n <= 10);
@ -388,10 +382,9 @@ int help_get_config_on_answer (struct query *q UU) {
if (op == CODE_config) {
max_bcast_size = fetch_int (mtp);
}
if (verbosity >= 2) {
logprintf ( "chat_size = %d\n", max_chat_size);
}
telegram_change_state(instance, STATE_CONNECTED, 0);
logprintf ( "max_chat_size = %d\n", max_chat_size);
telegram_change_state(instance, STATE_CONFIG_RECEIVED, NULL);
return 0;
}
@ -405,7 +398,8 @@ void do_help_get_config (struct telegram *instance) {
clear_packet (mtp);
out_int (mtp, CODE_help_get_config);
struct dc *DC_working = telegram_get_working_dc(instance);
send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer, mtp->packet_buffer, &help_get_config_methods, instance);
send_query (DC_working, mtp->packet_ptr - mtp->packet_buffer,
mtp->packet_buffer, &help_get_config_methods, instance);
}
/* }}} */
@ -567,6 +561,18 @@ int check_phone_on_answer (struct query *q UU) {
assert (fetch_int (mtp) == (int)CODE_auth_checked_phone);
check_phone_result = fetch_bool (mtp);
fetch_bool (mtp);
if (mtp->connection->instance->session_state != STATE_CONFIG_RECEIVED) {
logprintf("check_phone_on_answer(): invalid state: %d\n", mtp->connection->instance->session_state);
telegram_change_state(mtp->connection->instance, STATE_ERROR, NULL);
return -1;
}
logprintf("check_phone_result=%d\n", check_phone_result);
if (check_phone_result) {
telegram_change_state(mtp->connection->instance, STATE_CLIENT_NOT_REGISTERED, NULL);
} else {
telegram_change_state(mtp->connection->instance, STATE_PHONE_NOT_REGISTERED, NULL);
}
return 0;
}
@ -592,7 +598,7 @@ int check_phone_on_error (struct query *q UU, int error_code, int l, char *error
} else {
logprintf ( "error_code = %d, error = %.*s\n", error_code, l, error);
}
telegram_change_state(instance, STATE_ERROR, error);
telegram_change_state(instance, STATE_DISCONNECTED_SWITCH_DC, error);
return 0;
}
@ -601,7 +607,7 @@ struct query_methods check_phone_methods = {
.on_error = check_phone_on_error
};
int do_auth_check_phone (struct telegram *instance, const char *user) {
void do_auth_check_phone (struct telegram *instance, const char *user) {
struct mtproto_connection *mtp = instance->connection;
suser = tstrdup (user);
@ -617,7 +623,6 @@ int do_auth_check_phone (struct telegram *instance, const char *user) {
send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &check_phone_methods, instance);
net_loop (0, cr_f);
*/
return check_phone_result;
}
/* }}} */

View file

@ -103,7 +103,7 @@ void do_load_video (struct telegram *instance, struct video *V, int next);
void do_load_document (struct telegram *instance, struct document *V, int next);
void do_load_document_thumb (struct telegram *instance, struct document *video, int next);
void do_help_get_config (struct telegram *instance);
int do_auth_check_phone (struct telegram *instance, const char *user);
void do_auth_check_phone (struct telegram *instance, const char *user);
void do_get_nearest_dc (struct telegram*);
void do_send_code_result_auth (struct telegram *instance, const char *code, const char *sms_hash, const char *first_name, const char *last_name);
void do_import_auth (struct telegram *instance, int num);

View file

@ -1535,7 +1535,7 @@ static int id_cmp (struct message *M1, struct message *M2) {
}
struct user *fetch_alloc_user (struct mtproto_connection *mtp) {
logprintf("fetch_alloc_user()\n");
logprintf("fetch_alloc_user()\n");
int send_event = 0;
int data[2];
prefetch_data (mtp, data, 8);

View file

@ -55,8 +55,57 @@ void telegram_change_state(struct telegram *instance, int state, void *data)
logprintf("telegram connection state changed to: %d\n", state);
instance->session_state = state;
GList *curr = instance->change_state_listeners;
while ((curr = g_list_next(change_listeners)) != NULL) {
do {
((state_listener_t)curr->data)(instance, state, data);
} while ((curr = g_list_next(change_listeners)) != NULL);
}
void on_state_change(struct telegram *instance, int state, void *data)
{
logprintf("on_state_change: %d\n", state);
switch (state) {
case STATE_ERROR: {
const char* err = data;
logprintf("Telegram errored: %s \n", err);
}
break;
case STATE_AUTHORIZED:
logprintf("requesting configuration");
telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL);
do_help_get_config (instance);
break;
case STATE_CONFIG_RECEIVED:
logprintf("received network configuration, checking whether phone is registered.");
telegram_store_session(instance);
do_auth_check_phone(instance, instance->login);
break;
case STATE_PHONE_NOT_REGISTERED:
logprintf("phone is not registered, need to register phone number.\n");
do_send_code(instance, instance->login);
break;
case STATE_PHONE_CODE_REQUESTED:
logprintf("phone authenticion, user needs to enter code, first and last name.\n");
// wait for user input ...
break;
case STATE_CLIENT_NOT_REGISTERED:
logprintf("phone is already registered, need to register client.\n");
do_send_code(instance, instance->login);
break;
case STATE_CLIENT_CODE_NOT_ENTERED:
logprintf("client authentication, user needs to enter code");
// wait for user input ...
break;
case STATE_DISCONNECTED_SWITCH_DC:
logprintf("Have to migrate to other DC");
instance->connection
break;
}
}
@ -81,6 +130,7 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf
logprintf("%s\n", this->auth_path);
logprintf("%s\n", this->state_path);
telegram_add_state_change_listener(this, on_state_change);
telegram_change_state(this, STATE_INITIALISED, NULL);
return this;
}
@ -125,7 +175,6 @@ struct connection *telegram_get_connection(struct telegram *instance)
assert(DC);
assert(DC->sessions[0]);
assert(DC->sessions[0]->c);
//logprintf("get_connection() -> fd: %d\n", DC->sessions[0]->c->fd);
return DC->sessions[0]->c;
}
@ -171,51 +220,45 @@ char *telegram_get_config(struct telegram *instance, char *config)
return g_strdup_printf("%s/%s", instance->config_path, config);
}
void on_connected(struct mtproto_connection *c, void* data);
void on_authorized(struct mtproto_connection *c, void* data);
/**
* Connect to the currently active data center
*/
void telegram_network_connect(struct telegram *instance, int fd)
{
logprintf("telegram_network_connect()\n");
if (!instance->auth.DC_list) {
logprintf("telegram_network_connect(): cannot connect, restore / initialise a session first.\n");
logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n");
assert(0);
}
struct dc *DC_working = telegram_get_working_dc(instance);
instance->connection = mtproto_new(DC_working, fd, instance);
instance->connection->on_ready = on_connected;
instance->connection->on_ready = on_authorized;
instance->connection->on_ready_data = instance;
mtproto_connect(instance->connection);
}
void on_connected(struct mtproto_connection *c, void *data)
/**
* Login, and perform a registration when needed
*/
int telegram_login(struct telegram *instance)
{
struct telegram *instance = data;
logprintf("Authorized... storing current session.\n");
telegram_store_session(instance);
if (instance->session_state != STATE_AUTHORIZED) {
logprintf("Cannot log in, invalid state: %d \n", instance->session_state);
return -1;
}
do_help_get_config(instance);
telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL);
return 0;
}
void on_state_change(struct telegram *instance, int state, void *data)
void on_authorized(struct mtproto_connection *c, void *data)
{
switch (state) {
case STATE_CONNECTED:
break;
case STATE_ERROR: {
const char* err = data;
logprintf("Telegram errored: %s \n", err);
}
break;
case STATE_AUTH_DONE:
logprintf("requesting configuration");
telegram_change_state(instance, STATE_CONFIG_REQUESTED, NULL);
do_help_get_config (instance);
break;
case STATE_CONFIG_REQUESTED:
logprintf("switch: config_requested\n");
telegram_store_session(instance);
break;
}
struct telegram *instance = data;
logprintf("Authorized... storing current session %d.\n", c->connection->session[0]);
telegram_store_session(instance);
telegram_change_state(instance, STATE_AUTHORIZED, NULL);
}
void telegram_read_input (struct telegram *instance)

View file

@ -26,7 +26,7 @@ struct protocol_state;
struct authorization_state;
/*
* Libtelegram states
* telegram states
*/
#define STATE_INITIALISED 0
@ -35,35 +35,35 @@ struct authorization_state;
// Error
#define STATE_ERROR 2
// Authentication
#define STATE_PQ_REQUESTED 3
#define STATE_DH_REQUESTED 4
#define STATE_CDH_REQUESTED 5
#define STATE_AUTH_DONE 6
// intermediate authorization states already present and handled in mtproto-client.c
//#define STATE_PQ_REQUESTED 3
//#define STATE_DH_REQUESTED 4
//#define STATE_CDH_REQUESTED 5
#define STATE_AUTHORIZED 6
// dc discovery
#define STATE_CONFIG_REQUESTED 7
#define STATE_EXPORTING_CONFIG 8
#define STATE_DISCONNECTED_SWITCH_DC 9
#define STATE_CONFIG_RECEIVED 11
// Login
#define STATE_CONNECTED 10
// login
// - Phone Registration
#define STATE_PHONE_IS_REGISTERED_SENT 11
#define STATE_PHONE_IS_REGISTERED_SENT_2 12
#define STATE_PHONE_NOT_REGISTERED 13
#define STATE_PHONE_CODE_REQUESTED 14
#define STATE_PHONE_CODE_NOT_ENTERED 15
#define STATE_PHONE_CODE_ENTERED 16
// - Client Registration
#define STATE_CLIENT_IS_REGISTERED_SENT 16
#define STATE_CLIENT_NOT_REGISTERED 17
#define STATE_CLIENT_CODE_REQUESTED 18
#define STATE_CLIENT_CODE_NOT_ENTERED 19
#define STATE_CLIENT_CODE_ENTERED 20
#define STATE_CLIENT_IS_REGISTERED_SENT 17
#define STATE_CLIENT_NOT_REGISTERED 18
#define STATE_CLIENT_CODE_REQUESTED 19
#define STATE_CLIENT_CODE_NOT_ENTERED 20
#define STATE_CLIENT_CODE_ENTERED 21
// Ready for sending and receiving messages
#define STATE_READY 21
#define STATE_READY 22
/**
* A telegram session
@ -173,6 +173,8 @@ void telegram_change_state(struct telegram *instance, int state, void *data);
*/
void telegram_network_connect (struct telegram *instance, int fd);
int telegram_login (struct telegram *instance);
/**
* Read the authorization_state stored in the given file
*/