static ngx_chain_t *
ngx_http_tfs_create_action_message(ngx_http_tfs_t *t, ngx_str_t *file_path_s,
    ngx_str_t *file_path_d)
{
    size_t                              size;
    u_char                             *p;
    ngx_buf_t                          *b;
    ngx_chain_t                        *cl;
    ngx_http_tfs_restful_ctx_t         *r_ctx;
    ngx_http_tfs_ms_base_msg_header_t  *req;

    r_ctx = &t->r_ctx;

    size = sizeof(ngx_http_tfs_ms_base_msg_header_t) +
        /* file path */
        file_path_s->len +
        /* version */
        sizeof(uint64_t) +
        /* new file path len */
        sizeof(uint32_t) +
        /* '/0' */
        1 +
        /* action */
        sizeof(uint8_t);

    if (file_path_d != NULL && file_path_d->data != NULL) {
        size += file_path_d->len + 1;
    }

    b = ngx_create_temp_buf(t->pool, size);
    if (b == NULL) {
        return NULL;
    }

    req = (ngx_http_tfs_ms_base_msg_header_t *) b->pos;
    req->header.type = NGX_HTTP_TFS_FILEPATH_ACTION_MESSAGE;
    req->header.len = size - sizeof(ngx_http_tfs_header_t);
    req->header.flag = NGX_HTTP_TFS_PACKET_FLAG;
    req->header.version = NGX_HTTP_TFS_PACKET_VERSION;
    req->header.id = ngx_http_tfs_generate_packet_id();
    req->app_id = r_ctx->app_id;
    req->user_id = r_ctx->user_id;
    req->file_len = file_path_s->len + 1;
    p = ngx_cpymem(req->file_path_s, file_path_s->data, file_path_s->len + 1);

    *((uint64_t *)p) = t->loc_conf->meta_server_table.version;
    p += sizeof(uint64_t);

    if (file_path_d != NULL && file_path_d->data != NULL) {
        /* new file path */
        *((uint32_t *)p) = file_path_d->len + 1;
        p += sizeof(uint32_t);
        p = ngx_cpymem(p, file_path_d->data, file_path_d->len + 1);

    } else {
        *((uint32_t *)p) = 0;
        p += sizeof(uint32_t);
    }

    /* start body */
    *p = r_ctx->action.code;

    req->header.crc = ngx_http_tfs_crc(NGX_HTTP_TFS_PACKET_FLAG,
                                       (const char *) (&req->header + 1),
                                       req->header.len);
    b->last += size;

    cl = ngx_alloc_chain_link(t->pool);
    if (cl == NULL) {
        return NULL;
    }

    cl->buf = b;
    cl->next = NULL;

    return cl;
}
static ngx_chain_t *
ngx_http_tfs_create_write_meta_message(ngx_http_tfs_t *t)
{
    u_char                             *p;
    size_t                              size, frag_size;
    ngx_buf_t                          *b;
    ngx_int_t                           need_write_frag_count, i;
    ngx_chain_t                        *cl;
    ngx_http_tfs_restful_ctx_t         *r_ctx;
    ngx_http_tfs_segment_data_t        *segment_data;
    ngx_http_tfs_meta_frag_info_t      *wfi;
    ngx_http_tfs_ms_base_msg_header_t  *req;

    r_ctx = &t->r_ctx;
    need_write_frag_count =
        t->file.segment_index - t->file.last_write_segment_index;
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, t->log, 0 ,
                   "last_write_segment_index: %uD, segment_index: %uD",
                   t->file.last_write_segment_index, t->file.segment_index);

    frag_size = sizeof(ngx_http_tfs_meta_frag_info_t) +
        sizeof(ngx_http_tfs_meta_frag_meta_info_t) * need_write_frag_count;

    size = sizeof(ngx_http_tfs_ms_base_msg_header_t) +
        r_ctx->file_path_s.len + 1 +
        /* version */
        sizeof(uint64_t) +
        frag_size;

    b = ngx_create_temp_buf(t->pool, size);
    if (b == NULL) {
        return NULL;
    }

    req = (ngx_http_tfs_ms_base_msg_header_t *) b->pos;
    req->header.type = NGX_HTTP_TFS_WRITE_FILEPATH_MESSAGE;
    req->header.flag = NGX_HTTP_TFS_PACKET_FLAG;
    req->header.version = NGX_HTTP_TFS_PACKET_VERSION;
    req->header.id = ngx_http_tfs_generate_packet_id();
    req->app_id = r_ctx->app_id;
    req->user_id = r_ctx->user_id;
    req->file_len = r_ctx->file_path_s.len + 1;
    p = ngx_cpymem(req->file_path_s, r_ctx->file_path_s.data,
                   r_ctx->file_path_s.len + 1);

    *((uint64_t *)p) = t->loc_conf->meta_server_table.version;

    wfi = (ngx_http_tfs_meta_frag_info_t*)(p + sizeof(uint64_t));
    wfi->cluster_id = t->file.cluster_id;
    wfi->frag_count = need_write_frag_count;
    segment_data = &t->file.segment_data[t->file.last_write_segment_index];
    for (i = 0; i < need_write_frag_count; i++) {
#if (NGX_DEBUG)
        ngx_http_tfs_dump_segment_data(segment_data, t->log);
#endif
        wfi->frag_meta[i].block_id = segment_data->segment_info.block_id;
        wfi->frag_meta[i].file_id = segment_data->segment_info.file_id;
        wfi->frag_meta[i].offset = segment_data->segment_info.offset;
        wfi->frag_meta[i].size = segment_data->segment_info.size;
        segment_data++;
    }
    t->file.last_write_segment_index += need_write_frag_count;

    b->last += size;

    req->header.len = size - sizeof(ngx_http_tfs_header_t);
    req->header.crc = ngx_http_tfs_crc(NGX_HTTP_TFS_PACKET_FLAG,
                                       (const char *) (&req->header + 1),
                                       size - sizeof(ngx_http_tfs_header_t));

    cl = ngx_alloc_chain_link(t->pool);
    if (cl == NULL) {
        return NULL;
    }

    cl->buf = b;
    cl->next = NULL;

    return cl;
}
static ngx_chain_t *
ngx_http_tfs_create_read_meta_message(ngx_http_tfs_t *t, int64_t req_offset,
    uint64_t req_size)
{
    u_char                             *p;
    size_t                              size, max_frag_count, req_frag_count;
    ngx_buf_t                          *b;
    ngx_chain_t                        *cl;
    ngx_http_tfs_restful_ctx_t         *r_ctx;
    ngx_http_tfs_ms_base_msg_header_t  *req;

    r_ctx = &t->r_ctx;

    size = sizeof(ngx_http_tfs_ms_base_msg_header_t) +
        /* file */
        r_ctx->file_path_s.len +
        /* \0 */
        1 +
        /* version */
        sizeof(uint64_t) +
        /* offset */
        sizeof(uint64_t) +
        /* size */
        sizeof(uint64_t);

    b = ngx_create_temp_buf(t->pool, size);
    if (b == NULL) {
        return NULL;
    }

    req = (ngx_http_tfs_ms_base_msg_header_t *) b->pos;
    req->header.type = NGX_HTTP_TFS_READ_FILEPATH_MESSAGE;
    req->header.len = size - sizeof(ngx_http_tfs_header_t);
    req->header.flag = NGX_HTTP_TFS_PACKET_FLAG;
    req->header.version = NGX_HTTP_TFS_PACKET_VERSION;
    req->header.id = ngx_http_tfs_generate_packet_id();
    req->app_id = r_ctx->app_id;
    req->user_id = r_ctx->user_id;
    req->file_len = r_ctx->file_path_s.len + 1;
    p = ngx_cpymem(req->file_path_s, r_ctx->file_path_s.data,
                   r_ctx->file_path_s.len + 1);

    *((uint64_t *)p) = t->loc_conf->meta_server_table.version;
    p += sizeof(uint64_t);

    *((uint64_t *) p) = req_offset;
    p += sizeof(uint64_t);

    max_frag_count = (t->main_conf->body_buffer_size
                      - sizeof(ngx_http_tfs_ms_read_response_t))
        / sizeof(ngx_http_tfs_meta_frag_meta_info_t);
    req_frag_count = req_size / (NGX_HTTP_TFS_MAX_FRAGMENT_SIZE);

    ngx_log_error(NGX_LOG_INFO, t->log, 0 ,
                  "max_frag_count: %uz, req_frag_count: %uz, data size: %uz",
                  max_frag_count, req_frag_count, req_size);

    if (req_frag_count > max_frag_count) {
        *((uint64_t *) p) =
            (max_frag_count - 1) * NGX_HTTP_TFS_MAX_FRAGMENT_SIZE;
        t->has_split_frag = NGX_HTTP_TFS_YES;

    } else {
        *((uint64_t *) p) = req_size;
        t->has_split_frag = NGX_HTTP_TFS_NO;
    }

    req->header.crc = ngx_http_tfs_crc(NGX_HTTP_TFS_PACKET_FLAG,
                                       (const char *) (&req->header + 1),
                                       req->header.len);

    b->last += size;

    cl = ngx_alloc_chain_link(t->pool);
    if (cl == NULL) {
        return NULL;
    }

    cl->buf = b;
    cl->next = NULL;

    return cl;
}
ngx_chain_t *
ngx_http_tfs_create_keepalive_message(ngx_http_tfs_t *t)
{
    u_char                         *p;
    ssize_t                         size, base_size;
    ngx_buf_t                      *b;
    ngx_queue_t                    *q, *queue;
    ngx_chain_t                    *cl, **ll;
    ngx_http_tfs_rc_ctx_t          *rc_ctx;
    ngx_http_tfs_header_t          *header;
    ngx_http_tfs_rcs_info_t        *rc_info;

    rc_ctx = t->main_conf->rc_ctx;
    ll = NULL;
    cl = NULL;

    base_size = sizeof(ngx_http_tfs_header_t)
        /* session id and client version len */
        + sizeof(uint32_t) * 2
        /* client version */
        + sizeof(NGX_HTTP_TFS_CLIENT_VERSION)
        /* cache_size cache_time modify_time */
        + sizeof(uint64_t) * 3
        /* is_logout */
        + sizeof(uint8_t)
        /* stat info */
        + sizeof(uint32_t)
        + sizeof(uint64_t)
        /* last_report_time */
        + sizeof(uint64_t);

    queue = &rc_ctx->sh->kp_queue;
    if (ngx_queue_empty(queue)) {
        ngx_shmtx_unlock(&rc_ctx->shpool->mutex);
        return NULL;
    }

    q = t->curr_ka_queue;
    if (q == NULL) {
        q = ngx_queue_head(queue);
        t->curr_ka_queue = q;
    }

    rc_info = ngx_queue_data(q, ngx_http_tfs_rcs_info_t, kp_queue);

    ngx_log_error(NGX_LOG_INFO, t->log, 0,
        "will do keepalive for appkey: %V", &rc_info->appkey);

    size = base_size + rc_info->session_id.len + 1;
    b = ngx_create_temp_buf(t->pool, size);
    if (b == NULL) {
        goto keepalive_create_error;
    }

    header = (ngx_http_tfs_header_t *) b->pos;
    header->flag = NGX_HTTP_TFS_PACKET_FLAG;
    header->len = size - sizeof(ngx_http_tfs_header_t);
    header->type = NGX_HTTP_TFS_REQ_RC_KEEPALIVE_MESSAGE;
    header->version = NGX_HTTP_TFS_PACKET_VERSION;
    header->id = ngx_http_tfs_generate_packet_id();

    p = (u_char *)(header + 1);

    /* include '\0' */
    *((uint32_t *) p) = rc_info->session_id.len + 1;
    p += sizeof(uint32_t);

    p = ngx_cpymem(p, rc_info->session_id.data, rc_info->session_id.len);
    *p = '\0';
    p += sizeof(uint8_t);

    *((uint32_t *) p) = sizeof(NGX_HTTP_TFS_CLIENT_VERSION);
    p += sizeof(uint32_t);

    p = ngx_cpymem(p, NGX_HTTP_TFS_CLIENT_VERSION, sizeof(NGX_HTTP_TFS_CLIENT_VERSION));

    ngx_memzero(p, sizeof(uint64_t) * 4 + sizeof(uint32_t) + sizeof(uint8_t));

    /* cache_size cache_time */
    p += sizeof(uint64_t) * 2;

    *((uint64_t *) p) = rc_info->modify_time;

    /* modify_time is_logout stat_info */
    p += sizeof(uint64_t) * 3 + sizeof(uint32_t) + sizeof(uint8_t);

    header->crc = ngx_http_tfs_crc(NGX_HTTP_TFS_PACKET_FLAG,
        (const char *) (header + 1), header->len);

    b->last += size;

    if (ll == NULL) {
        cl = ngx_alloc_chain_link(t->pool);
        if (cl == NULL) {
            goto keepalive_create_error;
        }

        cl->next = NULL;
        ll = &cl->next;
        cl->buf = b;

    } else {
        *ll = ngx_alloc_chain_link(t->pool);
        if (*ll == NULL) {
            goto keepalive_create_error;
        }

        (*ll)->next = NULL;
        (*ll)->buf = b;
        ll = &((*ll)->next);
    }

    return cl;

keepalive_create_error:
    return NULL;
}