Esempio n. 1
0
static void
handle_upload_ok (CcnetProcessor *processor, TransferTask *task,
                  char *content, int clen)
{
    if (clen == 0) {
        ccnet_processor_send_update (processor,
                                     SC_GET_TOKEN, SS_GET_TOKEN,
                                     NULL, 0);
        return;
    }

    if (clen != 41 || content[clen-1] != '\0') {
        g_warning ("Bad response content.\n");
        transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }
    memcpy (task->remote_head, content, 41);

    /* Check fast-forward here. */
    if (strcmp (task->head, task->remote_head) != 0 &&
        !is_fast_forward (task->head, task->remote_head)) {
        g_warning ("Upload is not fast-forward.\n");
        transfer_task_set_error (task, TASK_ERR_NOT_FAST_FORWARD);
        ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }
    ccnet_processor_send_update (processor,
                                 SC_GET_TOKEN, SS_GET_TOKEN,
                                 NULL, 0);
}
Esempio n. 2
0
static void
commit_write_cb (OSAsyncResult *res, void *data)
{
    CcnetProcessor *processor = data;
    TransferTask *task = ((SeafileGetcommitV3Proc *)processor)->tx_task;
    SeafCommit *commit;

    if (!res->success) {
        seaf_warning ("Failed to write commit %.8s.\n", res->obj_id);
        transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
        ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    commit = seaf_commit_from_data (res->obj_id, res->data, res->len);
    if (!commit) {
        seaf_warning ("[getcommit] Bad commit object received.\n");
        transfer_task_set_error (task, TASK_ERR_DOWNLOAD_COMMIT);
        ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
                                     NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
        object_list_insert (task->fs_roots, commit->root_id);
    seaf_commit_unref (commit);

    ccnet_processor_done (processor, TRUE);
}
Esempio n. 3
0
static void handle_response (CcnetProcessor *processor,
                             char *code, char *code_msg,
                             char *content, int clen)
{
    SeafileGetcommitProc *proc = (SeafileGetcommitProc *)processor;
    if (proc->tx_task->state != TASK_STATE_NORMAL) {
        /* TODO: not tested yet */
        ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN,
                                     NULL, 0);
        ccnet_processor_done (processor, TRUE);
        return;
    }

    switch (processor->state) {
    case INIT:
        if (strncmp(code, SC_OK, 3) == 0) {
            processor->state = RECV_IDS;
        } else {
            g_warning ("[getcommit] Bad response: %s %s\n", code, code_msg);
            transfer_task_set_error (proc->tx_task,
                                     TASK_ERR_DOWNLOAD_COMMIT);
            ccnet_processor_done (processor, FALSE);
        }
        break;
    case RECV_IDS:
        if (strncmp(code, SC_COMMIT_IDS, 3) == 0) {
            /* add to inspect queue */
            process_commit_list (processor, content, clen);
        } else if (strncmp(code, SC_END, 3) == 0) {
            /* change state to FETCH_OBJECT */
            processor->state = FETCH_OBJECT;
        } else {
            g_warning ("[getcommit] Bad response: %s %s\n", code, code_msg);
            transfer_task_set_error (proc->tx_task,
                                      TASK_ERR_DOWNLOAD_COMMIT);
            ccnet_processor_done (processor, FALSE);
        }
        break;
    case FETCH_OBJECT:
        if (strncmp(code, SC_OBJECT, 3) == 0) {
            receive_commit (processor, content, clen);
        } else {
            g_warning ("[getcommit] Bad response: %s %s\n", code, code_msg);
            /* Transfer the task state to error when an error ocurred */
            transfer_task_set_error (proc->tx_task,
                                     TASK_ERR_DOWNLOAD_COMMIT);
            ccnet_processor_done (processor, FALSE);
        }
        break;
    default:
        g_assert (0);
    }
}
Esempio n. 4
0
static void
receive_commit (CcnetProcessor *processor, char *content, int clen)
{
    ObjectPack *pack = (ObjectPack *)content;

    if (clen < sizeof(ObjectPack)) {
        seaf_warning ("[getcommit] invalid object id.\n");
        goto bad;
    }

    seaf_debug ("[getcommit] recv commit object %.8s\n", pack->id);

    if (save_commit (processor, pack, clen) < 0) {
        goto bad;
    }

    return;

bad:
    seaf_warning ("[getcommit] Bad commit object received.\n");
    transfer_task_set_error (((SeafileGetcommitV3Proc *)processor)->tx_task,
                             TASK_ERR_DOWNLOAD_COMMIT);
    ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
                                 NULL, 0);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 5
0
static void
fs_object_write_cb (OSAsyncResult *res, void *data)
{
    CcnetProcessor *processor = data;
    USE_PRIV;

    if (!res->success) {
        seaf_warning ("Failed to write object %.8s.\n", res->obj_id);
        transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
                                 TASK_ERR_DOWNLOAD_FS);
        ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    seaf_debug ("Written object %.8s.\n", res->obj_id);

    --(priv->pending_objects);

    int type = seaf_metadata_type_from_data (res->data, res->len);
    if (type == SEAF_METADATA_TYPE_DIR)
        g_queue_push_tail (priv->inspect_queue, g_strdup(res->obj_id));

    end_or_check_next_dir (processor, priv);
}
Esempio n. 6
0
static void
end_or_check_next_dir (CcnetProcessor *processor, SeafileGetfsProcPriv *priv)
{
    if (check_end_condition (priv)) {
        seaf_debug ("Get fs end.\n");
        ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
        ccnet_processor_done (processor, TRUE);
        return;
    }

    if (priv->worker_running) {
        return;
    }

    /* Trigger checking the next dir. */
    char *next_dir_id = g_queue_pop_head (priv->inspect_queue);
    if (next_dir_id) {
        if (check_fs_tree_from (processor, next_dir_id) < 0) {
            transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
                                     TASK_ERR_DOWNLOAD_FS);
            ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
            ccnet_processor_done (processor, FALSE);
        }
        g_free (next_dir_id);
    }
}
Esempio n. 7
0
static void handle_response (CcnetProcessor *processor,
                             char *code, char *code_msg,
                             char *content, int clen)
{
    SeafileSendcommitV3Proc *proc = (SeafileSendcommitV3Proc *)processor;
    TransferTask *task = proc->tx_task;
    if (task->state != TASK_STATE_NORMAL) {
        ccnet_processor_done (processor, TRUE);
        return;
    }

    switch (processor->state) {
    case INIT:
        if (memcmp (code, SC_OK, 3) == 0) {
            processor->state = SEND_OBJECT;
            send_commits (processor, task->head);
            return;
        }
        break;
    case SEND_OBJECT:
        if (memcmp (code, SC_ACK, 3) == 0) {
            send_one_commit (processor);
            return;
        }
        break;
    default:
        g_return_if_reached ();
    }

    g_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 8
0
static void
process_commit_list (CcnetProcessor *processor, char *content, int clen)
{
    USE_PRIV;
    char *object_id;
    int n_objects;
    int i;

    if (clen % 41 != 1 || content[clen-1] != '\0') {
        g_warning ("[getcommit] Bad commit id list.\n");
        ccnet_processor_send_update (processor, SC_BAD_OL, SS_BAD_OL, NULL, 0);
        transfer_task_set_error (((SeafileGetcommitProc *)processor)->tx_task,
                                 TASK_ERR_DOWNLOAD_COMMIT);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    n_objects = clen/41;

    request_object_batch_begin(priv);

    object_id = content;
    for (i = 0; i < n_objects; ++i) {
        object_id[40] = '\0';
        check_commit (processor, object_id);
        object_id += 41;
    }
    
    request_object_batch_flush (processor, priv);

    if (priv->pending_objects == 0) {
        ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
        ccnet_processor_done (processor, TRUE);
    }
}
Esempio n. 9
0
static void
receive_commit (CcnetProcessor *processor, char *content, int clen)
{
    USE_PRIV;
    ObjectPack *pack = (ObjectPack *)content;

    if (clen < sizeof(ObjectPack)) {
        g_warning ("[getcommit] invalid object id.\n");
        goto bad;
    }

    g_debug ("[getcommit] recv commit object %s\n", pack->id);
    --priv->pending_objects;

    if (save_commit (pack, clen) < 0) {
        goto bad;
    }

    if (priv->pending_objects == 0) {
        g_debug ("[getcommit] Receive commit completed.\n");
        ccnet_processor_send_update (processor, SC_END, SS_END, NULL, 0);
        ccnet_processor_done (processor, TRUE);
    }

    return;

bad:
    ccnet_processor_send_update (processor, SC_BAD_OBJECT,
                                   SS_BAD_OBJECT, NULL, 0);
    g_warning ("[getcommit] Bad commit object received.\n");
    transfer_task_set_error (((SeafileGetcommitProc *)processor)->tx_task,
                             TASK_ERR_DOWNLOAD_COMMIT);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 10
0
static void
handle_response (CcnetProcessor *processor,
                 char *code, char *code_msg,
                 char *content, int clen)
{
    SeafileSendfsProc *proc = (SeafileSendfsProc *)processor;
    TransferTask *task = proc->tx_task;

    switch (processor->state) {
    case SEND_ROOT:
        if (strncmp(code, SC_OK, 3) == 0) {
            send_fs_roots (processor);
            return;
        }
        break;
    case SEND_OBJECT:
        if (strncmp(code, SC_GET_OBJECT, 3) == 0) {
            send_fs_objects (processor, content, clen);
            return;
        } else if (strncmp(code, SC_END, 3) == 0) {
            seaf_debug ("Send fs objects end.\n");
            ccnet_processor_done (processor, TRUE);
            return;
        }
        break;
    default:
        g_assert (0);
    }

    g_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 11
0
static int
recv_fs_object (CcnetProcessor *processor, char *content, int clen)
{
    USE_PRIV;
    ObjectPack *pack = (ObjectPack *)content;
    uint32_t type;
    /* TransferTask *task = ((SeafileGetfsProc *)processor)->tx_task; */

    if (clen < sizeof(ObjectPack)) {
        g_warning ("[getfs] invalid object id.\n");
        goto bad;
    }

    --priv->pending_objects;

    type = seaf_metadata_type_from_data(pack->object, clen);
    if (type == SEAF_METADATA_TYPE_DIR) {
        SeafDir *dir;
        dir = seaf_dir_from_data (pack->id, pack->object, clen - 41);
        if (!dir) {
            g_warning ("[getfs] Bad directory object %s.\n", pack->id);
            goto bad;
        }
        g_queue_push_tail (priv->inspect_queue, g_strdup(dir->dir_id));
        seaf_dir_free (dir);
    } else if (type == SEAF_METADATA_TYPE_FILE) {
        /* TODO: check seafile format. */
#if 0
        int ret = seafile_check_data_format (pack->object, clen - 41);
        if (ret < 0) {
            goto bad;
        }
#endif
    } else {
        g_warning ("[getfs] Invalid object type.\n");
        goto bad;
    }

    if (save_fs_object (pack, clen) < 0) {
        goto bad;
    }

    g_hash_table_remove (priv->fs_objects, pack->id);
    return 0;

bad:
    g_warning ("Bad fs object received.\n");
    transfer_task_set_error (((SeafileGetfsProc *)processor)->tx_task,
                             TASK_ERR_DOWNLOAD_FS);
    ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
                                 NULL, 0);
    ccnet_processor_done (processor, FALSE);
    return -1;
}
Esempio n. 12
0
static void
handle_response (CcnetProcessor *processor,
                 char *code, char *code_msg,
                 char *content, int clen)
{
    SeafileCheckTxV3Proc *proc = (SeafileCheckTxV3Proc *)processor;
    TransferTask *task = proc->task;

    if (strncmp(code, SC_OK, 3) == 0) {
        if (proc->type == CHECK_TX_TYPE_UPLOAD)
            handle_upload_ok (processor, task, content, clen);
        else
            handle_download_ok (processor, task, content, clen);
    } else if (strncmp (code, SC_PUT_TOKEN, 3) == 0) {
        /* In LAN sync, we don't use session token. */
        if (clen == 0) {
            ccnet_processor_done (processor, TRUE);
            return;
        }

        if (content[clen-1] != '\0') {
            g_warning ("Bad response content.\n");
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
            ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS,
                                         NULL, 0);
            ccnet_processor_done (processor, FALSE);
            return;
        }
        task->session_token = g_strdup (content);

        ccnet_processor_send_update (processor, SC_GET_VERSION, SS_GET_VERSION,
                                     NULL, 0);
    } else if (strncmp (code, SC_VERSION, 3) == 0) {
        task->protocol_version = atoi(content);
        ccnet_processor_done (processor, TRUE);
    } else {
        g_warning ("[check tx v3] Bad response: %s %s", code, code_msg);
        if (strncmp(code, SC_ACCESS_DENIED, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
        else if (strncmp(code, SC_QUOTA_ERROR, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_CHECK_QUOTA);
        else if (strncmp(code, SC_QUOTA_FULL, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_QUOTA_FULL);
        else if (strncmp(code, SC_PROTOCOL_MISMATCH, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_PROTOCOL_VERSION);
        else if (strncmp(code, SC_BAD_REPO, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_BAD_REPO_ID);
        else
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_done (processor, FALSE);
    }
}
Esempio n. 13
0
static void
handle_download_ok (CcnetProcessor *processor, TransferTask *task,
                    char *content, int clen)
{
    if (clen != 41 || content[clen-1] != '\0') {
        g_warning ("Bad response content.\n");
        transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    memcpy (task->head, content, 41);
    ccnet_processor_send_update (processor,
                                 SC_GET_TOKEN, SS_GET_TOKEN,
                                 NULL, 0);
}
Esempio n. 14
0
static void handle_response (CcnetProcessor *processor,
                             char *code, char *code_msg,
                             char *content, int clen)
{
    SeafileSendblockV2Proc *proc = (SeafileSendblockV2Proc *)processor;
    USE_PRIV;

    if (proc->tx_task->state != TASK_STATE_NORMAL) {
        g_debug ("Task not running, send-block proc exits.\n");
        ccnet_processor_done (processor, TRUE);
        return;
    }

    switch (priv->tdata->state) {
    case REQUEST_SENT:
        if (memcmp (code, SC_OK, 3) == 0) {
            send_block_list (processor);
            priv->tdata->state = BLOCKLIST_SENT;
            return;
        }
        break;
    case BLOCKLIST_SENT:
        if (memcmp (code, SC_BBITMAP, 3) == 0) {
            process_block_bitmap (processor, content, clen);
            return;
        }
        break;
    case GET_PORT:
        if (memcmp (code, SC_SEND_PORT, 3) == 0) {
            get_port (processor, content, clen);
            return;
        }
        break;
    case READY:
        if (memcmp (code, SC_ACK, 3) == 0) {
            process_ack (processor, content, clen);
            return;
        }
    }

    g_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 15
0
static void
handle_response (CcnetProcessor *processor,
                 char *code, char *code_msg,
                 char *content, int clen)
{
    SeafileGetfsProc *proc = (SeafileGetfsProc *)processor;
    TransferTask *task = proc->tx_task;

    switch (processor->state) {
    case REQUEST_SENT:
        if (strncmp(code, SC_OK, 3) == 0) {
            load_fsroot_list (processor);
            processor->timer = ccnet_timer_new (
                (TimerCB)check_object, processor, CHECK_INTERVAL);
            processor->state = FETCH_OBJECT;
            return;
        }
        break;
    case FETCH_OBJECT:
        if (strncmp(code, SC_OBJ_SEG, 3) == 0) {
            recv_fs_object_seg (processor, content, clen);
            return;

        } else if (strncmp(code, SC_OBJ_SEG_END, 3) == 0) {
            recv_fs_object_seg (processor, content, clen);
            process_fs_object_seg (processor);
            return;
            
        } else if (strncmp(code, SC_OBJECT, 3) == 0) {
            recv_fs_object (processor, content, clen);
            return;
        }
        break;
    default:
        g_assert (0);
    }

    g_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 16
0
static void handle_response (CcnetProcessor *processor,
                             char *code, char *code_msg,
                             char *content, int clen)
{
    SeafileGetcommitV3Proc *proc = (SeafileGetcommitV3Proc *)processor;

    if (proc->tx_task->state != TASK_STATE_NORMAL) {
        ccnet_processor_done (processor, TRUE);
        return;
    }

    if (strncmp(code, SC_OK, 3) == 0) {
        receive_commit (processor, content, clen);
        return;
    }

    seaf_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 17
0
static void
handle_upload_ok (CcnetProcessor *processor, TransferTask *task,
                  char *content, int clen)
{
    if (clen == 0) {
        ccnet_processor_send_update (processor,
                                     SC_GET_TOKEN, SS_GET_TOKEN,
                                     NULL, 0);
        return;
    }

    if (clen != 41 || content[clen-1] != '\0') {
        seaf_warning ("Bad response content.\n");
        transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }

    /* Ignore the returned remote head id, just use the head of master branch.
     * For protocol version >= 6, the complete hitstory is not downloaded, so
     * there is no way to check fast forward on the client. For protocol version
     * < 6, the server will check fast forward anyway.
     */
    SeafBranch *master = seaf_branch_manager_get_branch (seaf->branch_mgr,
                                                         task->repo_id, "master");
    if (!master) {
        seaf_warning ("Cannot find branch master for repo %s.\n", task->repo_id);
        ccnet_processor_send_update (processor, SC_SHUTDOWN, SS_SHUTDOWN, NULL, 0);
        ccnet_processor_done (processor, FALSE);
        return;
    }
    memcpy (task->remote_head, master->commit_id, 40);
    seaf_branch_unref (master);

    ccnet_processor_send_update (processor,
                                 SC_GET_TOKEN, SS_GET_TOKEN,
                                 NULL, 0);
}
Esempio n. 18
0
static void
receive_commit (CcnetProcessor *processor, char *content, int clen)
{
    ObjectPack *pack = (ObjectPack *)content;
    TransferTask *task = ((SeafileGetcommitV2Proc *)processor)->tx_task;
    SeafCommit *commit;

    if (clen < sizeof(ObjectPack)) {
        g_warning ("[getcommit] invalid object id.\n");
        goto bad;
    }

    seaf_debug ("[getcommit] recv commit object %.8s\n", pack->id);

    if (save_commit (pack, clen) < 0) {
        goto bad;
    }

    commit = seaf_commit_manager_get_commit (seaf->commit_mgr, pack->id);
    if (!commit)
        goto bad;

    if (strcmp (commit->root_id, EMPTY_SHA1) != 0)
        object_list_insert (task->fs_roots, commit->root_id);
    seaf_commit_unref (commit);

    return;

bad:
    g_warning ("[getcommit] Bad commit object received.\n");
    transfer_task_set_error (((SeafileGetcommitV2Proc *)processor)->tx_task,
                             TASK_ERR_DOWNLOAD_COMMIT);
    ccnet_processor_send_update (processor, SC_BAD_OBJECT, SS_BAD_OBJECT,
                                 NULL, 0);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 19
0
static void handle_response (CcnetProcessor *processor,
                             char *code, char *code_msg,
                             char *content, int clen)
{
    SeafileGetcommitV2Proc *proc = (SeafileGetcommitV2Proc *)processor;
    if (proc->tx_task->state != TASK_STATE_NORMAL) {
        ccnet_processor_done (processor, TRUE);
        return;
    }

    switch (processor->state) {
    case INIT:
        if (strncmp(code, SC_OK, 3) == 0) {
            processor->state = RECV_OBJECT;
            return;
        }
        break;
    case RECV_OBJECT:
        if (strncmp(code, SC_OBJECT, 3) == 0) {
            receive_commit (processor, content, clen);
            return;
        } else if (strncmp (code, SC_END, 3) == 0) {
            seaf_debug ("[getcommit] Get commit end.\n");
            ccnet_processor_done (processor, TRUE);
            return;
        }
        break;
    default:
        g_return_if_reached ();
    }

    g_warning ("Bad response: %s %s.\n", code, code_msg);
    if (memcmp (code, SC_ACCESS_DENIED, 3) == 0)
        transfer_task_set_error (proc->tx_task, TASK_ERR_ACCESS_DENIED);
    ccnet_processor_done (processor, FALSE);
}
Esempio n. 20
0
static void
handle_response (CcnetProcessor *processor,
                 char *code, char *code_msg,
                 char *content, int clen)
{
    SeafileCheckTxV3Proc *proc = (SeafileCheckTxV3Proc *)processor;
    TransferTask *task = proc->task;

    if (strncmp(code, SC_OK, 3) == 0) {
        if (proc->type == CHECK_TX_TYPE_UPLOAD)
            handle_upload_ok (processor, task, content, clen);
        else
            handle_download_ok (processor, task, content, clen);
    } else if (strncmp (code, SC_PUT_TOKEN, 3) == 0) {
        /* In LAN sync, we don't use session token. */
        if (clen == 0) {
            ccnet_processor_done (processor, TRUE);
            return;
        }

        if (content[clen-1] != '\0') {
            seaf_warning ("Bad response content.\n");
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
            ccnet_processor_send_update (processor, SC_BAD_ARGS, SS_BAD_ARGS,
                                         NULL, 0);
            ccnet_processor_done (processor, FALSE);
            return;
        }
        task->session_token = g_strdup (content);

        ccnet_processor_send_update (processor, SC_GET_VERSION, SS_GET_VERSION,
                                     NULL, 0);
    } else if (strncmp (code, SC_VERSION, 3) == 0) {
        int server_version = atoi(content);
        /* There is a bug in block transfer in version 4, so it's not supported. */
        if (server_version == 4)
            server_version = 3;
        task->protocol_version = MIN (server_version, CURRENT_PROTO_VERSION);

        if (task->protocol_version < 5) {
            seaf_warning ("Deprecated server protocol version %d.\n",
                          task->protocol_version);
            transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
            ccnet_processor_done (processor, FALSE);
            return;
        }

        if (task->repo_version == 0)
            task->protocol_version = 5;
        else if (task->protocol_version == 5) {
            /* Syncing version 1 reop with 2.x server is not supported.
             * Actually version 1 repo can only be created by 3.x servers.
             * If version 1 repos exist on 2.x server, it means a down-grade
             * operation has been performed, which is not supported.
             */
            seaf_warning ("Syncing version %d repo with protocol version %d "
                          "is not supported.\n",
                          task->repo_version, task->protocol_version);
            transfer_task_set_error (task, TASK_ERR_DEPRECATED_SERVER);
            ccnet_processor_done (processor, FALSE);
            return;
        }

        if (task->protocol_version >= 7 && !task->server_side_merge)
            task->protocol_version = 6;

        if (task->protocol_version >= 7 && task->type == TASK_TYPE_DOWNLOAD)
            set_download_head_info (task);

        seaf_message ("repo version is %d, protocol version is %d.\n",
                      task->repo_version, task->protocol_version);
        ccnet_processor_done (processor, TRUE);
    } else {
        seaf_warning ("[check tx v3] Bad response: %s %s", code, code_msg);
        if (strncmp(code, SC_ACCESS_DENIED, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_ACCESS_DENIED);
        else if (strncmp(code, SC_QUOTA_ERROR, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_CHECK_QUOTA);
        else if (strncmp(code, SC_QUOTA_FULL, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_QUOTA_FULL);
        else if (strncmp(code, SC_PROTOCOL_MISMATCH, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_PROTOCOL_VERSION);
        else if (strncmp(code, SC_BAD_REPO, 3) == 0)
            transfer_task_set_error (task, TASK_ERR_BAD_REPO_ID);
        else
            transfer_task_set_error (task, TASK_ERR_UNKNOWN);
        ccnet_processor_done (processor, FALSE);
    }
}