ceph中的s3cmd 消息解析代碼走讀

之前介紹了civetweb作爲radosgw的agent的運行機制,請看下面鏈接

http://blog.csdn.net/zrs19800702/article/details/53081444


那麼S3的消息如何解析的呢?

下面介紹下消息解析

在civetweb的子線程運行的函數中可以看出存在一個  struct mg_connection *conn指針,這個就是保持解析後消息的

static void *worker_thread_run(void *thread_func_param)

{

    struct mg_context *ctx = (struct mg_context *) thread_func_param;

    struct mg_connection *conn;

    struct mg_workerTLS tls;

    tls.is_master = 0;

#if defined(_WIN32) && !defined(__SYMBIAN32__)

    tls.pthread_cond_helper_mutex = CreateEvent(NULL, FALSE, FALSE, NULL);

#endif

    conn = (struct mg_connection *) mg_calloc(1, sizeof(*conn) + MAX_REQUEST_SIZE);

    if (conn == NULL) {

        mg_cry(fc(ctx), "%s", "Cannot create new connection struct, OOM");

    } else {

        pthread_setspecific(sTlsKey, &tls);

        conn->buf_size = MAX_REQUEST_SIZE;------設置buff大小

        conn->buf = (char *) (conn + 1);

        conn->ctx = ctx;

        conn->request_info.user_data = ctx->user_data;----------此處將消息指針賦值過去

        /* Allocate a mutex for this connection to allow communication both

           within the request handler and from elsewhere in the application */

        (void) pthread_mutex_init(&conn->mutex, NULL);

 

        /* Call consume_socket() even when ctx->stop_flag > 0, to let it

           signal sq_empty condvar to wake up the master waiting in

           produce_socket() */

        while (consume_socket(ctx, &conn->client)) {

            conn->birth_time = time(NULL);

 

            /* Fill in IP, port info early so even if SSL setup below fails,

               error handler would have the corresponding info.

               Thanks to Johannes Winkelmann for the patch.

               TODO(lsm): Fix IPv6 case */

            conn->request_info.remote_port = ntohs(conn->client.rsa.sin.sin_port);

            memcpy(&conn->request_info.remote_ip,

                   &conn->client.rsa.sin.sin_addr.s_addr, 4);

            conn->request_info.remote_ip = ntohl(conn->request_info.remote_ip);

            conn->request_info.is_ssl = conn->client.is_ssl;

 

            if (!conn->client.is_ssl

#ifndef NO_SSL

                || sslize(conn, conn->ctx->ssl_ctx, SSL_accept)

#endif

               ) {

                process_new_connection(conn);-------------------------處理消息

            }

            close_connection(conn);

        }

    }

 

    /* Signal master that we're done with connection and exiting */

    (void) pthread_mutex_lock(&ctx->thread_mutex);

    ctx->num_threads--;

    (void) pthread_cond_signal(&ctx->thread_cond);

    assert(ctx->num_threads >= 0);

    (void) pthread_mutex_unlock(&ctx->thread_mutex);

 

    pthread_setspecific(sTlsKey, NULL);

#if defined(_WIN32) && !defined(__SYMBIAN32__)

    CloseHandle(tls.pthread_cond_helper_mutex);

#endif

    mg_free(conn);

 

    DEBUG_TRACE("exiting");

    return NULL;

}

在static void process_new_connection(struct mg_connection *conn)中將消息轉換成一個mg_request_info類型的結構,

 struct mg_request_info *ri = &conn->request_info;

------

下面開始讀取消息內容

    conn->data_len = 0;

    do {

    int err;

        if (!getreq(conn, ebuf, sizeof(ebuf), &err)) {

            if (err > 0) {

              send_http_error(conn, err, "Bad Request", "%s", ebuf);

        }

            conn->must_close = 1;

        } else if (!is_valid_uri(conn->request_info.uri)) {

            snprintf(ebuf, sizeof(ebuf), "Invalid URI: [%s]", ri->uri);

            send_http_error(conn, 400, "Bad Request", "%s", ebuf);

        } else if (strcmp(ri->http_version, "1.0") &&

                   strcmp(ri->http_version, "1.1")) {

            snprintf(ebuf, sizeof(ebuf), "Bad HTTP version: [%s]", ri->http_version);

            send_http_error(conn, 505, "Bad HTTP version", "%s", ebuf);

        }

        if (ebuf[0] == '\0') {

            handle_request(conn);-----開始處理消息,這裏會進入函數

----------------------------------------------------------------------------------

    } else if (conn->ctx->callbacks.begin_request != NULL &&

               conn->ctx->callbacks.begin_request(conn)) {-------------------------------------此處進入回調函數civetweb_callback()------------->process_request()進行消息處理

process_request()之前會聲明一個類RGWMongoose繼承了 RGWStreamIO,這個類裏面有兩個bufflist

   bufferlist header_data;---數據頭內容

  bufferlist data;----數據內容

採用以下兩個方法讀取數據和寫數據

  int write_data(const char *buf, int len);

  int read_data(char *buf, int len);

以下拿put object方法舉例子:

process_request()中的

client_io->init(g_ceph_context);----初始化env_map,獲取相關參數

void RGWMongoose::init_env(CephContext *cct)中獲取request_info的http_headers信息存入緩存

RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr, &init_error);----new RGWHandler_REST_Obj_S3

......

op = handler->get_op(store);----------new RGWPutObj_ObjStore_S3; 這時候RGWMongoose的指針已經存入到struct req_state *s中了,

這裏的op類型是RGWPutObj_ObjStore_S3,然後調用op->init(store, s, this);保存了三個變量到RGWPutObj_ObjStore_S3的父類RGWOp中

this->store = store;

this->s = s;

this->dialect_handler = dialect_handler;

......

op->execute();---------執行具體業務,這裏面會調用get_data方法如下:

do {

    bufferlist data;

    len = get_data(data);-----------循環讀取數據,按照配置文件的塊大小讀取

    ......

    ofs += len;

  } while (len > 0);

......

 先調用RGWPutObj_ObjStore_S3中 get_data(bufferlist& bl);---->int ret = RGWPutObj_ObjStore::get_data(bl)中詳細如下

int RGWPutObj_ObjStore::get_data(bufferlist& bl)

{

  size_t cl;

  uint64_t chunk_size = s->cct->_conf->rgw_max_chunk_size;--------------獲取配置文件的塊大小,RGWOp中保存了struct req_state *s(裏面有RGWClientIO *cio,調用到RGWMongoose的read方法讀取數據)

  if (s->length) {

    cl = atoll(s->length) - ofs;

    if (cl > chunk_size)

      cl = chunk_size;

  } else {

    cl = chunk_size;

  }

  int len = 0;

  if (cl) {

    bufferptr bp(cl);------初始化每個bufferptr的塊大小

    int read_len; /* cio->read() expects int * */

    int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len, s->aws4_auth_needs_complete);--------讀取數據到bp,這裏調用的是RGWMongoose的read

    if (r < 0) {

      return r;

    }

    len = read_len;

    bl.append(bp, 0, len);---------添加到bl中

  }

  if ((uint64_t)ofs + len > s->cct->_conf->rgw_max_put_size) {

    return -ERR_TOO_LARGE;

  }

  if (!ofs)

    supplied_md5_b64 = s->info.env->get("HTTP_CONTENT_MD5");

  return len;

}

.....

---------------------------------------------------------------------------------

            if (conn->ctx->callbacks.end_request != NULL) {

                conn->ctx->callbacks.end_request(conn, conn->status_code);------------------處理完消息後的回調函數,這裏的回調函數end_request在運行前爲NULL

            }

            log_access(conn);---------------------------處理日誌

        }

 下面是gdb調試打印出來的conn內容,關注紅色字段

S3的命令是gettorrent,後面有一個put object的內容

Breakpoint 2, process_new_connection (conn=0x7fdebc0009b0) at civetweb/src/civetweb.c:6577

6577            if (ebuf[0] == '\0') {

$3 = {

  request_info = {

    request_method = 0x7fdebc000ed0 "GET",

    uri = 0x7fdebc000ed4 "/ZHOU/ceph-0.87.2.tar.gz?get_torrent",

    http_version = 0x7fdebc000efe "1.1",

    query_string = 0x7fdebc000eed "get_torrent",

    remote_user = 0x0,

    remote_ip = 2130706433,

    remote_port = 48716,

    is_ssl = 0,

    user_data = 0x7fdeeaff6328,

    conn_data = 0x0,

    num_headers = 4,

    http_headers = {{

        name = 0x7fdebc000f03 "Host",

        value = 0x7fdebc000f09 "localhost:8000"

      }, {

        name = 0x7fdebc000f19 "Accept-Encoding",

        value = 0x7fdebc000f2a "identity"

      }, {

        name = 0x7fdebc000f34 "Authorization",

        value = 0x7fdebc000f43 "AWS 0555b35654ad1656d804:RIAZqLoZnSVotvWOCGi2dcXlAsU="

      }, {

        name = 0x7fdebc000f7a "x-amz-date",

        value = 0x7fdebc000f86 "Thu, 19 May 2016 06:54:39 +0000"

      }, {

        name = 0x7fdebc000fa8 "",

        value = 0x7fdebc000fa8 ""

      }, {

        name = 0x7fdebc000fa9 "",

        value = 0x7fdebc000fa9 ""

      }, {

        name = 0x0,

        value = 0x0

      } <repeats 58 times>}

  },

  ctx = 0x7fdeeaff6800,

  ssl = 0x0,

  client_ssl_ctx = 0x0,

  client = {

    sock = 7,

    lsa = {

      sa = {

        sa_family = 2,

        sa_data = "\037@\177\000\000\001\000\000\000\000\000\000\000"

      },

      sin = {

        sin_family = 2,

        sin_port = 16415,

        sin_addr = {

          s_addr = 16777343

        },

        sin_zero = "\000\000\000\000\000\000\000"

      }

    },

    rsa = {

      sa = {

        sa_family = 2,

        sa_data = "\276L\177\000\000\001\000\000\000\000\000\000\000"

      },

      sin = {

        sin_family = 2,

        sin_port = 19646,

        sin_addr = {

          s_addr = 16777343

        },

        sin_zero = "\000\000\000\000\000\000\000"

      }

    },

    is_ssl = 0,

    ssl_redir = 0

  },

  birth_time = 1463640879,

  num_bytes_sent = 0,

  content_len = 0,

  consumed_content = 0,

  buf = 0x7fdebc000ed0 "GET",

  path_info = 0x0,

  must_close = 0,

---Type <return> to continue, or q <return> to quit---

  in_error_handler = 0,

  buf_size = 16384,

  request_len = 217,

  data_len = 217,

  status_code = -1,

  throttle = 0,

  last_throttle_time = 0,

  last_throttle_bytes = 0,

  mutex = {

    __data = {

      __lock = 0,

      __count = 0,

      __owner = 0,

      __nusers = 0,

      __kind = 0,

      __spins = 0,

      __list = {

        __prev = 0x0,

        __next = 0x0

      }

    },

    __size = '\000' <repeats 39 times>,

    __align = 0

  },

  is_chunked = 0

}

 

put objject消息,此處設置mutipart=false

Breakpoint 2, process_new_connection (conn=0x7fdecc000e40) at civetweb/src/civetweb.c:6577

6577            if (ebuf[0] == '\0') {

$23 = {

  request_info = {

    request_method = 0x7fdecc001360 "PUT",

    uri = 0x7fdecc001364 "/ZHOU/pydev.tar.gz",

    http_version = 0x7fdecc00137c "1.1",

    query_string = 0x0,

    remote_user = 0x0,

    remote_ip = 2130706433,

    remote_port = 48730,

    is_ssl = 0,

    user_data = 0x7fdeeaff6328,

    conn_data = 0x0,

    num_headers = 8,

    http_headers = {{

        name = 0x7fdecc001381 "Host",

        value = 0x7fdecc001387 "localhost:8000"

      }, {

        name = 0x7fdecc001397 "Accept-Encoding",

        value = 0x7fdecc0013a8 "identity"

      }, {

        name = 0x7fdecc0013b2 "Authorization",

        value = 0x7fdecc0013c1 "AWS 0555b35654ad1656d804:B7/sdrvLeTnuaom5+TM7meN/BCU="

      }, {

        name = 0x7fdecc0013f8 "content-length",

        value = 0x7fdecc001408 "46857122"

      }, {

        name = 0x7fdecc001412 "content-type",

        value = 0x7fdecc001420 "application/x-gzip"

      }, {

        name = 0x7fdecc001434 "x-amz-date",

        value = 0x7fdecc001440 "Thu, 19 May 2016 07:08:42 +0000"

      }, {

        name = 0x7fdecc001461 "x-amz-meta-s3cmd-attrs",

        value = 0x7fdecc001479 "uid:0/gname:root/uname:root/gid:0/mode:33188/mtime:1463637551/atime:1463637588/md5:54d762d04b2f22368855a20f91154c53/ctime:1463637551"

      }, {

        name = 0x7fdecc0014ff "x-amz-storage-class",

        value = 0x7fdecc001514 "STANDARD"

      }, {

        name = 0x7fdecc00151f "",

        value = 0x7fdecc00151f ""

      }, {

        name = 0x0,

        value = 0x0

      } <repeats 55 times>}

  },

  ctx = 0x7fdeeaff6800,

  ssl = 0x0,

  client_ssl_ctx = 0x0,

  client = {

    sock = 7,

    lsa = {

      sa = {

        sa_family = 2,

        sa_data = "\037@\177\000\000\001\000\000\000\000\000\000\000"

      },

      sin = {

        sin_family = 2,

        sin_port = 16415,

        sin_addr = {

          s_addr = 16777343

        },

        sin_zero = "\000\000\000\000\000\000\000"

      }

    },

    rsa = {

      sa = {

        sa_family = 2,

        sa_data = "\276Z\177\000\000\001\000\000\000\000\000\000\000"

      },

      sin = {

        sin_family = 2,

        sin_port = 23230,

        sin_addr = {

          s_addr = 16777343

        },

        sin_zero = "\000\000\000\000\000\000\000"

      }

    },

    is_ssl = 0,

    ssl_redir = 0

  },

  birth_time = 1463641722,

  num_bytes_sent = 0,

  content_len = 46857122,

  consumed_content = 0,

  buf = 0x7fdecc001360 "PUT",

  path_info = 0x0,

  must_close = 0,

  in_error_handler = 0,

  buf_size = 16384,

  request_len = 448,

  data_len = 16384,

  status_code = -1,

  throttle = 0,

  last_throttle_time = 0,

  last_throttle_bytes = 0,

  mutex = {

    __data = {

      __lock = 0,

      __count = 0,

      __owner = 0,

      __nusers = 0,

      __kind = 0,

      __spins = 0,

      __list = {

        __prev = 0x0,

        __next = 0x0

      }

    },

    __size = '\000' <repeats 39 times>,

    __align = 0

  },

  is_chunked = 0

}

發佈了21 篇原創文章 · 獲贊 6 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章