int secure_send_on_answer (void **IP, void **Data) {
  vkprintf (2, "fun %s\n", __func__);
  struct rpc_query *q = *Data;
  struct secure_send_extra *E = q->extra;
  if (E->state == 1) {
    //resend_answer_ack (q, &E->pid);
    q->ev.wakeup_time = precise_now + E->timeout;
    insert_event_timer (&q->ev);
    return 1;
  }
  secure_send_s0 --;
  secure_send_s1 ++;
  E->state ++;
  free (E->data);
  E->data_size = 0;
  E->data = 0;
  if (!tl_fetch_error ()) {
    tl_init_store (CQ->in_type, CQ->remote_pid, q->qid);
    //tl_store_init (CQ->in, q->qid);
    tl_store_end_ext (RPC_REQ_RESULT_ACK);
    sent_answer_ack ++;
  }
  if (E->binlog) {
    struct lev_answer_rx *L = alloc_log_event (LEV_ANSWER_RX, sizeof (*L), 0);
    L->qid = q->qid;
    if (binlog_mode_on & 2) {
      flush_cbinlog (0);
    }
  }
  int r = ((rpc_fun_t)(*IP))(IP + 1, Data);
  if (r < 0) { return r; }
  q->ev.wakeup_time = precise_now + E->timeout;
  insert_event_timer (&q->ev);
  return 1;
}
static void try_change_zone (void) {
  if (cur_zone == NULL) { return; }
  vkprintf (3, "%s: %.*s\n", __func__, cur_zone->origin_len, cur_zone->origin);
  struct lev_dns_change_zone *E = alloc_log_event (LEV_DNS_CHANGE_ZONE + cur_zone->origin_len, sizeof (struct lev_dns_change_zone) + cur_zone->origin_len, 0);
  memcpy (E->origin, cur_zone->origin, cur_zone->origin_len);
  cur_zone = NULL;
}
static void record_add (record_t *r) {
  try_change_zone ();
  assert (r->data_len >= 4);
  void *E = alloc_log_event (0, r->data_len, 0);
  memcpy (E, r->data, r->data_len);
  if (compute_uncommitted_log_bytes () > (1 << 23)) {
    flush_binlog_forced (0);
  }
  add_logevents++;
}
int _secure_send_on_net_fail (void **IP, void **Data, int binlog) {
  long long new_qid = get_free_rpc_qid (0); //*(long long *)(Data[1]);
  struct rpc_query *q = default_create_rpc_query (new_qid);
  assert (q);
  struct secure_send_extra *E = zmalloc (sizeof (*E));
  static int buf[10000];
  
  struct tl_query_header *h = CQ->h;
  long long qid = h->qid;
  assert (h->actor_id == CC->id);
  h->qid = new_qid;
  h->actor_id = CC->new_id;
  int len = tl_write_header (CQ->h, buf, 10000);
  h->qid = qid;
  h->actor_id = CC->id;
  assert (len >= 0);

  E->state = 0;
  E->data_size = tl_fetch_unread () + len;
  E->data = malloc (E->data_size);
  memset (E->data, 0, E->data_size);
  struct rpc_cluster_bucket *B = *Data;
  assert (B);
  E->pid.ip = B->methods->get_host (B);
  E->pid.port = B->methods->get_port (B);
  E->timeout = CC->timeout;
  E->binlog = 0;

  memcpy (E->data, buf, len);
  tl_fetch_raw_data (E->data + len, E->data_size - len);
  secure_send_s0 ++;
  q->extra = E;
  if (binlog) {
    E->binlog_pos = log_last_pos ();
    insert_binlog_pos (E->binlog_pos, 0);
    struct lev_query_tx *L = alloc_log_event (LEV_QUERY_TX, sizeof (*L) + E->data_size, 0);
    L->qid = q->qid;
    L->old_qid = q->old_qid;
    L->cluster_id = CC->id;    
    L->data_size = E->data_size;
    L->pid = E->pid;
    L->timeout = E->timeout;
    memcpy (L->data, E->data, E->data_size);
    E->binlog = 1;
    if (binlog_mode_on & 2) {
      flush_cbinlog (0);
    }
  }
  return 0;
}
static void record_delete (record_t *r) {
  if (last_deleted_record && !cmp_str (last_deleted_record->name, last_deleted_record->name_len, r->name, r->name_len) && last_deleted_record->qtype == r->qtype) {
    return;
  }

  try_change_zone ();
  vkprintf (3, "Delete records for name '%.*s' of type %d.\n", r->name_len, r->name, r->qtype);
  struct lev_dns_delete_records *E = alloc_log_event (LEV_DNS_DELETE_RECORDS + r->name_len, sizeof (struct lev_dns_delete_records) + r->name_len, r->qtype);
  memcpy (E->name, r->name, r->name_len);
  last_deleted_record = r;
  if (compute_uncommitted_log_bytes () > (1 << 23)) {
    flush_binlog_forced (0);
  }
  delete_logevents++;
}
int secure_receive_answer_ack (void **IP, void **Data) {
  int op = (long)*Data;
  if (op == RPC_REQ_RESULT_ACK) {
    vkprintf (2, "fun %s\n", __func__);
    tl_fetch_move (12);
    received_answer_ack ++;
    //struct connection *c = CQ->in;
    struct secure_receive_answer t;
    t.qid = tl_fetch_long ();
//    tl_fetch_raw_data (&t, 8);
    if (tl_fetch_error ()) {
      return -1;
    }
    t.pid = *CQ->remote_pid;
    //t.pid = RPCC_DATA(c)->remote_pid;
    struct tree_secure_receive_answer *T = tree_lookup_secure_receive_answer (secure_receive_answer_tree, &t);
    if (T) {
      secure_receive_answer_tree = tree_delete_secure_receive_answer (secure_receive_answer_tree, T->x);
      struct secure_receive_answer *A = T->x;
      secure_answer_allocated --;
      free (A->answer);
      if (A->h) {
        tl_query_header_delete (A->h);
      }
      if (A->binlog) {
        struct lev_answer_forget *L = alloc_log_event (LEV_ANSWER_FORGET, sizeof (*L), 0);
        L->qid = t.qid;
        L->pid = t.pid;
        delete_binlog_pos (A->binlog_pos, 0);
        if (binlog_mode_on & 2) {
          flush_cbinlog (0);
        }
      }
      zfree (A, sizeof (*A));
    }
    //tl_store_init (c, t.qid);
    tl_init_store (CQ->in_type, CQ->remote_pid, t.qid);
    tl_store_end_ext (RPC_REQ_RESULT_ACK_ACK);
    sent_answer_ack_ack ++;
    return -1;
  }
  RPC_FUN_NEXT;
}
int _secure_receive_on_alarm (void **IP, void **Data, int binlog) {
  struct rpc_query *q = *Data;
  struct secure_receive_answer *A = zmalloc (sizeof (*A));
  A->h = 0;
  A->qid = q->old_qid;
  A->pid = q->pid;
  A->answer_op = RPC_REQ_ERROR_WRAPPED;
  static char buf [1000];
  sprintf (buf + 1, "Query timeout: working_time = %lf", precise_now - q->start_time);
  tl_fetch_set_error (buf + 1, TL_ERROR_QUERY_TIMEOUT);
  int len = strlen (buf + 1) + 1;
  int pad = ((len + 3) & ~3) - len;
  memset (buf + len, 0, pad);
  buf[0] = len;
  len += pad;
  assert (len % 4 == 0);
  A->answer_len = 4 + len;
  A->answer = malloc (A->answer_len);
  A->binlog = 0;
  *(int *)A->answer = TL_ERROR_QUERY_TIMEOUT;
  memcpy (((char *)(A->answer)) + 4, buf, len);
  secure_receive_answer_tree = tree_insert_secure_receive_answer (secure_receive_answer_tree, A, lrand48 ());
  secure_answer_allocated ++;
  if (binlog) {
    A->binlog_pos  = log_last_pos ();
    insert_binlog_pos (A->binlog_pos, 0);
    struct lev_answer_tx *L = alloc_log_event (LEV_ANSWER_TX, sizeof (*L) + A->answer_len, 0);
    L->qid = A->qid;
    L->pid = A->pid;
    L->op = A->answer_op;
    L->answer_len = A->answer_len;
    memcpy (L->answer, A->answer, A->answer_len);
    A->binlog = 1;
    if (binlog_mode_on & 2) {
      flush_cbinlog (0);
    }
  }
  RPC_FUN_NEXT;
}
struct rpc_query *_secure_send_create_rpc_query (long long new_qid, int binlog) {
  struct rpc_query *q = default_create_rpc_query (new_qid);
  if (!q) { return q; }
  struct secure_send_extra *E = zmalloc (sizeof (*E));
  E->state = 0;
  E->data_size = tl.out_pos;
  E->data = malloc (E->data_size);
  memset (E->data, 0, E->data_size);
  assert (TL_OUT_TYPE == tl_type_conn);
  E->pid = RPCS_DATA(TL_OUT_CONN)->remote_pid;
  E->timeout = CC->timeout;
  E->binlog = 0;
  assert (tl_store_read_back_nondestruct (E->data, E->data_size) == E->data_size);
  secure_send_s0 ++;
/*  int i;
  for (i = 0; i < E->data_size / 4; i++) {
    fprintf (stderr, "%08x ", ((int *)E->data)[i]);
  }
  fprintf (stderr, "\n");*/
  q->extra = E;
  if (binlog) {
    E->binlog_pos = log_last_pos ();
    insert_binlog_pos (E->binlog_pos, 0);
    struct lev_query_tx *L = alloc_log_event (LEV_QUERY_TX, sizeof (*L) + E->data_size, 0);
    L->qid = q->qid;
    L->old_qid = q->old_qid;
    L->cluster_id = CC->id;    
    L->data_size = E->data_size;
    L->pid = E->pid;
    L->timeout = E->timeout;
    memcpy (L->data, E->data, E->data_size);
    E->binlog = 1;
    if (binlog_mode_on & 2) {
      flush_cbinlog (0);
    }
  }
  return q;
}
int secure_send_answer_ack_ack (void **IP, void **Data) {
  vkprintf (2, "fun %s\n", __func__);
  int op = (long)*Data;
  if (op == RPC_REQ_RESULT_ACK_ACK) {
    received_answer_ack_ack ++;
    tl_fetch_move (12);
    long long qid = tl_fetch_long ();
    struct rpc_query *q = get_rpc_query (qid);    
    if (!q) { return 0; }
    struct secure_send_extra *E = q->extra;
    if (E->binlog) {
      struct lev_query_forget *L = alloc_log_event (LEV_QUERY_FORGET, sizeof (*L), 0);
      L->qid = qid;
      delete_binlog_pos (E->binlog_pos, 0);
      if (binlog_mode_on & 2) {
        flush_cbinlog (0);
      }
    }
    query_on_free (q);
    return -1;
  }
  RPC_FUN_NEXT;
}
int _secure_receive_on_answer (void **IP, void **Data, int binlog) {
  struct rpc_query *q = *Data;
  struct secure_receive_answer *A = zmalloc (sizeof (*A));
  A->qid = q->old_qid;
  A->pid = q->pid;
  //A->h = tl_query_header_dup (CQ->h);
  A->h = 0;
  static char buf[(1 << 17)];
  int r = tl_write_header (CQ->h, (int *)buf, (1 << 17));
  assert (r >= 0);
  A->answer_op = CQ->h->real_op;
  A->answer_len = tl_fetch_unread () + r;
  A->answer = malloc (A->answer_len);
  A->binlog = 0;
  memcpy (A->answer, buf, r);

  //int t = 
  tl_fetch_lookup_data (A->answer + r, A->answer_len - r);
  secure_receive_answer_tree = tree_insert_secure_receive_answer (secure_receive_answer_tree, A, lrand48 ());
  secure_answer_allocated ++;
  if (binlog) {
    A->binlog_pos  = log_last_pos ();
    insert_binlog_pos (A->binlog_pos, 0);
    struct lev_answer_tx *L = alloc_log_event (LEV_ANSWER_TX, sizeof (*L) + A->answer_len, 0);
    L->qid = A->qid;
    L->pid = A->pid;
    L->op = A->answer_op;
    L->answer_len = A->answer_len;
    memcpy (L->answer, A->answer, A->answer_len);
    A->binlog = 1;
    if (binlog_mode_on & 2) {
      flush_cbinlog (0);
    }
  }
  RPC_FUN_NEXT;
}
Example #11
0
int loop (void) {
  on_start ();
  if (binlog_enabled) {
    replay_log ();
    write_binlog ();
  } else {
    read_auth_file ();
  }
  update_prompt ();

  assert (DC_list[dc_working_num]);
  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);
    assert (DC_working->auth_key_id);
    auth_state = 100;
    write_auth_file ();
  }
  
  if (verbosity) {
    logprintf ("Requesting info about DC...\n");
  }
  do_help_get_config ();
  net_loop (0, mcs);
  if (verbosity) {
    logprintf ("DC_info: %d new DC got\n", new_dc_num);
  }
  int i;
  for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->auth_key_id) {
    dc_authorize (DC_list[i]);
    assert (DC_list[i]->auth_key_id);
    write_auth_file ();
  }

  if (auth_state == 100 || !(DC_working->has_auth)) {
    if (!default_username) {
      size_t size = 0;
      char *user = 0;

      if (!user) {
        printf ("Telephone number (with '+' sign): ");         
        if (net_getline (&user, &size) == -1) {
          perror ("getline()");
          exit (EXIT_FAILURE);
        }
        set_default_username (user);
      }
    }
    int res = do_auth_check_phone (default_username);
    assert (res >= 0);
    logprintf ("%s\n", res > 0 ? "phone registered" : "phone not registered");
    if (res > 0) {
      do_send_code (default_username);
      char *code = 0;
      size_t size = 0;
      printf ("Code from sms: ");
      while (1) {
        if (net_getline (&code, &size) == -1) {
          perror ("getline()");
          exit (EXIT_FAILURE);
        }
        if (do_send_code_result (code) >= 0) {
          break;
        }
        printf ("Invalid code. Try again: ");
        free (code);
      }
      auth_state = 300;
    } else {
      printf ("User is not registered. Do you want to register? [Y/n] ");
      char *code;
      size_t size;
      if (net_getline (&code, &size) == -1) {
        perror ("getline()");
        exit (EXIT_FAILURE);
      }
      if (!*code || *code == 'y' || *code == 'Y') {
        printf ("Ok, starting registartion.\n");
      } else {
        printf ("Then try again\n");
        exit (EXIT_SUCCESS);
      }
      char *first_name;
      printf ("Name: ");
      if (net_getline (&first_name, &size) == -1) {
        perror ("getline()");
        exit (EXIT_FAILURE);
      }
      char *last_name;
      printf ("Name: ");
      if (net_getline (&last_name, &size) == -1) {
        perror ("getline()");
        exit (EXIT_FAILURE);
      }

      int dc_num = do_get_nearest_dc ();
      assert (dc_num >= 0 && dc_num <= MAX_DC_NUM && DC_list[dc_num]);
      dc_working_num = dc_num;
      DC_working = DC_list[dc_working_num];
      
      do_send_code (default_username);
      printf ("Code from sms: ");
      while (1) {
        if (net_getline (&code, &size) == -1) {
          perror ("getline()");
          exit (EXIT_FAILURE);
        }
        if (do_send_code_result_auth (code, first_name, last_name) >= 0) {
          break;
        }
        printf ("Invalid code. Try again: ");
        free (code);
      }
      auth_state = 300;
    }
  }

  for (i = 0; i <= MAX_DC_NUM; i++) if (DC_list[i] && !DC_list[i]->has_auth) {
    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 ();

  fflush (stdin);
  fflush (stdout);
  fflush (stderr);

  read_state_file ();
  read_secret_chat_file ();

  set_interface_callbacks ();

  do_get_difference ();
  net_loop (0, dgot);
  do_get_dialog_list ();

  return main_loop ();
}