基于nghttp2的apns HTTP2 C++ 测试程序

来源:互联网 发布:linux挂载光盘 编辑:程序博客网 时间:2024/06/06 02:03

http2 nghttp2 apns openssl 测试程序, 版权所有! 不得转载!

http://blog.csdn.net/ll352071639/article/details/77868482

/* * nghttp2 - HTTP/2 C Library
 http://write.blog.csdn.net/postedit/77868482 */#ifdef HAVE_CONFIG_H#include <config.h>#endif /* HAVE_CONFIG_H */#include <inttypes.h>#include <stdlib.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#ifdef HAVE_FCNTL_H#include <fcntl.h>#endif /* HAVE_FCNTL_H */#include <sys/types.h>#ifdef HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif /* HAVE_SYS_SOCKET_H */#ifdef HAVE_NETDB_H#include <netdb.h>#endif /* HAVE_NETDB_H */#ifdef HAVE_NETINET_IN_H#include <netinet/in.h>#endif /* HAVE_NETINET_IN_H */#include <netinet/tcp.h>#include <poll.h>#include <signal.h>#include <stdio.h>#include <assert.h>#include <string.h>#include <errno.h>#include <linux/sockios.h> //ioctl#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <sys/resource.h>#include <poll.h>#include <memory.h>#include <netdb.h>#include <nghttp2/nghttp2.h>#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/conf.h>#ifdef NGHTTP2_NORETURN#define NGHTTP2_NORETURN#endifenum { IO_NONE, WANT_READ, WANT_WRITE };#define MAKE_NV(NAME, VALUE)                                                   \  {                                                                            \    (uint8_t *)NAME, (uint8_t *)VALUE, strlen(NAME), strlen(VALUE),    \        NGHTTP2_NV_FLAG_NONE                                                   \  }#define MAKE_NV_CS(NAME, VALUE)                                                \  {                                                                            \    (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, strlen(VALUE),        \        NGHTTP2_NV_FLAG_NONE                                                   \  }static void deflate(nghttp2_hd_deflater *deflater,                    nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,                    size_t nvlen);static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,                                size_t inlen, int final);int hpackInit(nghttp2_hd_deflater *deflater, nghttp2_hd_inflater *inflater) {  int rv;  rv = nghttp2_hd_deflate_new(&deflater, 4096);  if (rv != 0) {    fprintf(stderr, "nghttp2_hd_deflate_init failed with error: %s\n",            nghttp2_strerror(rv));    exit(EXIT_FAILURE);  }  rv = nghttp2_hd_inflate_new(&inflater);  if (rv != 0) {    fprintf(stderr, "nghttp2_hd_inflate_init failed with error: %s\n",            nghttp2_strerror(rv));    exit(EXIT_FAILURE);  }  return 0;}int hpackUnInit(nghttp2_hd_deflater *deflater, nghttp2_hd_inflater *inflater) {nghttp2_hd_inflate_del(inflater);nghttp2_hd_deflate_del(deflater);}static void deflate(nghttp2_hd_deflater *deflater,                    nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,                    size_t nvlen) {  ssize_t rv;  uint8_t *buf;  size_t buflen;  size_t outlen;  size_t i;  size_t sum;  sum = 0;  for (i = 0; i < nvlen; ++i) {    sum += nva[i].namelen + nva[i].valuelen;  }  printf("Input (%zu byte(s)):\n\n", sum);  for (i = 0; i < nvlen; ++i) {    fwrite(nva[i].name, 1, nva[i].namelen, stdout);    printf(": ");    fwrite(nva[i].value, 1, nva[i].valuelen, stdout);    printf("\n");  }  buflen = nghttp2_hd_deflate_bound(deflater, nva, nvlen);  buf = malloc(buflen);  rv = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, nvlen);  if (rv < 0) {    fprintf(stderr, "nghttp2_hd_deflate_hd() failed with error: %s\n",            nghttp2_strerror((int)rv));    free(buf);    exit(EXIT_FAILURE);  }  outlen = (size_t)rv;  printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n", outlen,         sum == 0 ? 0 : (double)outlen / (double)sum);  for (i = 0; i < outlen; ++i) {    if ((i & 0x0fu) == 0) {      printf("%08zX: ", i);    }    printf("%02X ", buf[i]);    if (((i + 1) & 0x0fu) == 0) {      printf("\n");    }  }  printf("\n\nInflate:\n\n");  /* We pass 1 to final parameter, because buf contains whole deflated     header data. */  rv = inflate_header_block(inflater, buf, outlen, 1);  if (rv != 0) {    free(buf);    exit(EXIT_FAILURE);  }  printf("\n-----------------------------------------------------------"         "--------------------\n");  free(buf);}int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,                         size_t inlen, int final) {  ssize_t rv;  for (;;) {    nghttp2_nv nv;    int inflate_flags = 0;    size_t proclen;    rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, final);    if (rv < 0) {      fprintf(stderr, "inflate failed with error code %zd", rv);      return -1;    }    proclen = (size_t)rv;    in += proclen;    inlen -= proclen;    if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {      fwrite(nv.name, 1, nv.namelen, stderr);      fprintf(stderr, ": ");      fwrite(nv.value, 1, nv.valuelen, stderr);      fprintf(stderr, "\n");    }    if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {      nghttp2_hd_inflate_end_headers(inflater);      break;    }    if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {      break;    }  }  return 0;}struct Connection {  SSL *ssl;  nghttp2_session *session;  /* WANT_READ if SSL/TLS connection needs more input; or WANT_WRITE     if it needs more output; or IO_NONE. This is necessary because     SSL/TLS re-negotiation is possible at any time. nghttp2 API     offers similar functions like nghttp2_session_want_read() and     nghttp2_session_want_write() but they do not take into account     SSL/TSL connection. */  int want_io;};struct Request {  char *host;  /* In this program, path contains query component as well. */  char *path;  /* This is the concatenation of host and port with ":" in     between. */  char *hostport;  /* Stream ID for this request. */  int32_t stream_id;  uint16_t port;  struct Connection *connect;};struct URI {  const char *host;  /* In this program, path contains query component as well. */  const char *path;  size_t pathlen;  const char *hostport;  size_t hostlen;  size_t hostportlen;  uint16_t port;};/* * Returns copy of string |s| with the length |len|. The returned * string is NULL-terminated. */static char *strcopy(const char *s, size_t len) {  char *dst;  dst = malloc(len + 1);  memcpy(dst, s, len);  dst[len] = '\0';  return dst;}/* * Prints error message |msg| and exit. *///NGHTTP2_NORETURNstatic void die(const char *msg) {  fprintf(stderr, "FATAL: %s\n", msg);  exit(EXIT_FAILURE);}/* * Prints error containing the function name |func| and message |msg| * and exit. *///NGHTTP2_NORETURNstatic void dief(const char *func, const char *msg) {  fprintf(stderr, "FATAL: %s: %s\n", func, msg);  exit(EXIT_FAILURE);}/* * Prints error containing the function name |func| and error code * |error_code| and exit. *///NGHTTP2_NORETURNstatic void diec(const char *func, int error_code) {  fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,          nghttp2_strerror(error_code));  exit(EXIT_FAILURE);}/* * The implementation of nghttp2_send_callback type. Here we write * |data| with size |length| to the network and return the number of * bytes actually written. See the documentation of * nghttp2_send_callback for the details. */static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,                             size_t length, int flags, void *user_data) {   struct Connection *connection;  int rv;  (void)session;  (void)flags;  struct Request *req =  (struct Request *)user_data;  //(1); connection = req->connect;  printf("send_callback:%s, length:%d\n", data, length);  //printf("sslsslsslssl recv_callback length:%d\n", rv);/*  if (length < 30)                  {                                     int i = 0;                          for(;i < length; i++)             {                                     printf("%x", data[i]);        }                                 printf("\n");                                                 }                               */ // connection = (struct Connection *)user_data;  connection->want_io = IO_NONE;  ERR_clear_error();  rv = SSL_write(connection->ssl, data, (int)length);  if (rv <= 0) {    int err = SSL_get_error(connection->ssl, rv);    if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {      connection->want_io =          (err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);      rv = NGHTTP2_ERR_WOULDBLOCK;    } else {      rv = NGHTTP2_ERR_CALLBACK_FAILURE;    }  }  return rv;}/* * The implementation of nghttp2_recv_callback type. Here we read data * from the network and write them in |buf|. The capacity of |buf| is * |length| bytes. Returns the number of bytes stored in |buf|. See * the documentation of nghttp2_recv_callback for the details. */static ssize_t recv_callback(nghttp2_session *session, uint8_t *buf,                             size_t length, int flags, void *user_data) {  struct Connection *connection;  int rv;  (void)session;  (void)flags;  struct Request *req =  (struct Request *)user_data;  //(1);  memset(buf, 0, length); printf("sslsslsslssl recv_callback length:%d\n", length); connection = req->connect;  connection->want_io = IO_NONE;  ERR_clear_error();  rv = SSL_read(connection->ssl, buf, (int)length);  if (rv < 0) {    int err = SSL_get_error(connection->ssl, rv);    if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {      connection->want_io =          (err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);      rv = NGHTTP2_ERR_WOULDBLOCK;    } else {      rv = NGHTTP2_ERR_CALLBACK_FAILURE;    }  } else if (rv == 0) {    rv = NGHTTP2_ERR_EOF;  }   //printf("sslsslsslssl recv_callback length:%d\n", rv);/*   if (rv > 0)                      {                                    int i = 0;                        for(;i < rv; i++)                {                                    printf("%x", buf[i]);        }                                printf("\n");               }                             */  return rv;}static int on_frame_send_callback(nghttp2_session *session,                                  const nghttp2_frame *frame, void *user_data) {  size_t i;  (void)user_data;printf("frame send callback!\n");  switch (frame->hd.type) {  case NGHTTP2_HEADERS:    if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {return 0;      const nghttp2_nv *nva = frame->headers.nva;      printf("[INFO] C ----------------------------> S (HEADERS)\n");      for (i = 0; i < frame->headers.nvlen; ++i) {        fwrite(nva[i].name, 1, nva[i].namelen, stdout);        printf(": ");        fwrite(nva[i].value, 1, nva[i].valuelen, stdout);        printf("\n");      }    }    break;  case NGHTTP2_RST_STREAM:    printf("[INFO] C ----------------------------> S (RST_STREAM)\n");    break;  case NGHTTP2_GOAWAY:    printf("[INFO] C ----------------------------> S (GOAWAY)\n");    break;  }  return 0;}static int decode_status_code(const uint8_t *value, size_t len){  int i;  int res;  if(len != 3) {    return -1;  }  res = 0;  for(i = 0; i < 3; ++i) {    char c = value[i];    if(c < '0' || c > '9') {      return -1;    }    res *= 10;    res += c - '0';  }  return res;}static int on_header(nghttp2_session *session, const nghttp2_frame *frame,                     const uint8_t *name, size_t namelen,                     const uint8_t *value, size_t valuelen,                     uint8_t flags,                     void *userp){  //printf("on_header call back");//printf("on_header type :%d\n", frame->hd.type);  int32_t stream_id = frame->hd.stream_id;  //DEBUGASSERT(stream_id); /* should never be a zero stream ID here */  /* get the stream from the hash based on Stream ID */   //nghttp2_session_get_stream_user_data(session, stream_id);  /* Store received PUSH_PROMISE headers to be used when the subsequent     PUSH_PROMISE callback comes */  if(frame->hd.type == NGHTTP2_HEADERS)  {    char *h;int i  = decode_status_code(value, valuelen);printf("%s: %s\n", name, value);  }  else  {  printf("on_header type:%d, %s: %s\n", name, value);  }  return 0;}static int on_frame_recv_callback(nghttp2_session *session,                                  const nghttp2_frame *frame, void *user_data) {  size_t i;printf("[INFO] C<-------- S (HEADERS)nghttp2_frame_type:%d,stream_id:%d\n", frame->hd.type, frame->hd.stream_id);  switch (frame->hd.type) {  case NGHTTP2_SETTINGS:    printf("iframe->settings.niv:%d\n", frame->settings.niv);  break;  case NGHTTP2_HEADERS:    if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) { struct Request *req;req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);      const nghttp2_nv *nva = frame->headers.nva;      if (req) {        printf("[INFO] C <---------------------------- S (HEADERS)\n");//printf("padlen: %d\n", frame->headers.);//printf("head size:%d, %s, nvlen:%d\n", strlen((char *)frame), (char*)frame, frame->headers.nvlen);printf("frame->headers.cat:%d \nframe->headers.hd.flags:%d \nframe->headers.hd.length:%d \nframe->headers.hd.reserved:%d \nframe->headers.hd.stream_id:%d \nframe->headers.hd.type:%d\n",    frame->headers.cat, frame->headers.hd.flags, frame->headers.hd.length, frame->headers.hd.reserved,    frame->headers.hd.stream_id, frame->headers.hd.type);printf("frame->headers.nvlen:%d \nframe->headers.padlen:%d \nframe->headers.pri_spec.stream_id:%d \nframe->headers.pri_spec.exclusive:%d \nframe->headers.pri_spec.weight:%d \n",    frame->headers.nvlen, frame->headers.padlen, frame->headers.pri_spec.stream_id,    frame->headers.pri_spec.exclusive, frame->headers.pri_spec.weight);        for (i = 0; nva; nva++, i++) {          fwrite(nva->name, 1, nva->namelen, stdout);          printf(": ");          fwrite(nva->value, 1, nva->valuelen, stdout);          printf("\n");        }      }    }    break;  case NGHTTP2_RST_STREAM:    printf("[INFO] C <---------------------------- S (RST_STREAM)\n");    break;  case NGHTTP2_GOAWAY:    printf("[INFO] C <---------------------------- S (GOAWAY)\n");    break;  case NGHTTP2_DATA:  printf("frame->data.hd.flags:%d \nframe->data.hd.length:%d \nframe->data.hd.reserved:%d \nframe->data.hd.stream_id:%d \nframe->data.hd.type:%d\n",  frame->data.hd.flags, frame->data.hd.length, frame->data.hd.reserved,    frame->data.hd.stream_id, frame->data.hd.type);  printf("frame->data.padlen:%d\n", frame->data.padlen);  break;  default:  printf("[INFO] C <-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---S\n");  break;  }  return 0;}/* * The implementation of nghttp2_on_stream_close_callback type. We use * this function to know the response is fully received. Since we just * fetch 1 resource in this program, after reception of the response, * we submit GOAWAY and close the session. */static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,                                    uint32_t error_code, void *user_data) {  struct Request *req =  (struct Request *)user_data;     printf("on_stream_close_callback\n");//return 0;  req = nghttp2_session_get_stream_user_data(session, stream_id);  if (req) {    int rv = 0;    //rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);    if (rv != 0) {      diec("nghttp2_session_terminate_session", rv);    }  }  //sleep(3);  return 0;}/* * The implementation of nghttp2_on_data_chunk_recv_callback type. We * use this function to print the received response body. */static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,                                       int32_t stream_id, const uint8_t *data,                                       size_t len, void *user_data) {  struct Request *req;  (void)flags;  (void)user_data;  printf("on_data_chunk_recv_callback\n");  req = nghttp2_session_get_stream_user_data(session, stream_id);  if (req) {    printf("[INFO] C <---------------------------- S (DATA chunk)\n"           "%lu bytes\n",           (unsigned long int)len);    fwrite(data, 1, len, stdout);    printf("\n");  }  return 0;}int on_unpack_extension_callback(nghttp2_session *session,                                                 void **payload,                                                 const nghttp2_frame_hd *hd,                                                 void *user_data){printf("on_frame_send_callback, type:%d\n", hd->type);}int onextension_chunk_recv_callback(nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,    size_t len, void *user_data){printf("on_extension_chunk_recv_callback, type:%d\n", hd->type);}/* * Setup callback functions. nghttp2 API offers many callback * functions, but most of them are optional. The send_callback is * always required. Since we use nghttp2_session_recv(), the * recv_callback is also required. */static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {  nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);  nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);   //nghttp2_session_callbacks_set_on_frame_send_callback(callbacks, on_frame_send_callback);  //nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, //                                                      on_frame_recv_callback);    //nghttp2_session_callbacks_set_on_stream_close_callback(   //   callbacks, on_stream_close_callback);  nghttp2_session_callbacks_set_on_data_chunk_recv_callback(      callbacks, on_data_chunk_recv_callback);  nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);//nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(//callbacks, onextension_chunk_recv_callback);//nghttp2_session_callbacks_set_unpack_extension_callback(//callbacks, on_unpack_extension_callback);}/* * Callback function for TLS NPN. Since this program only supports * HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2 * library supports, we terminate program. */static int select_next_proto_cb(SSL *ssl, unsigned char **out,                                unsigned char *outlen, const unsigned char *in,                                unsigned int inlen, void *arg) {  int rv;  (void)ssl;  (void)arg;  /* nghttp2_select_next_protocol() selects HTTP/2 protocol the     nghttp2 library supports. */  rv = nghttp2_select_next_protocol(out, outlen, in, inlen);  if (rv <= 0) {    die("Server did not advertise HTTP/2 protocol");  }  return SSL_TLSEXT_ERR_OK;}/* * Setup SSL/TLS context. */static void init_ssl_ctx(SSL_CTX *ssl_ctx) {  /* Disable SSLv2 and enable all workarounds for buggy servers */  SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);  SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);  /* Set NPN callback */  SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);}static void ssl_handshake(SSL *ssl, int fd) {  int rv;  if (SSL_set_fd(ssl, fd) == 0) {    dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));  }  ERR_clear_error();  rv = SSL_connect(ssl);  if (rv <= 0) {    dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));  }}/* * Connects to the host |host| and port |port|.  This function returns * the file descriptor of the client socket. */static int connect_to(const char *host, uint16_t port) {  struct addrinfo hints;  int fd = -1;  int rv;  char service[NI_MAXSERV];  struct addrinfo *res, *rp;  snprintf(service, sizeof(service), "%u", port);  memset(&hints, 0, sizeof(struct addrinfo));  hints.ai_family = AF_UNSPEC;  hints.ai_socktype = SOCK_STREAM;  rv = getaddrinfo(host, service, &hints, &res);  if (rv != 0) {    dief("getaddrinfo", gai_strerror(rv));  }  for (rp = res; rp; rp = rp->ai_next) {    fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);    if (fd == -1) {      continue;    }    while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&           errno == EINTR)      ;    if (rv == 0) {      break;    }    close(fd);    fd = -1;  }  freeaddrinfo(res);  return fd;}static void make_non_block(int fd) {  int flags, rv;  while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)    ;  if (flags == -1) {    dief("fcntl", strerror(errno));  }  while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)    ;  if (rv == -1) {    dief("fcntl", strerror(errno));  }}static void set_tcp_nodelay(int fd) {  int val = 1;  int rv;  rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));  if (rv == -1) {    dief("setsockopt", strerror(errno));  }}/* * Update |pollfd| based on the state of |connection|. */static void ctl_poll(struct pollfd *pollfd, struct Connection *connection) {  pollfd->events = 0;  if (nghttp2_session_want_read(connection->session) ||      connection->want_io == WANT_READ) {    pollfd->events |= POLLIN;  }  if (nghttp2_session_want_write(connection->session) ||      connection->want_io == WANT_WRITE) {    pollfd->events |= POLLOUT;  }}static char payload[1024] = "{\"aps\": {\"badge\": 2,\"category\": \"mycategory\",\"alert\": {\"title\": \"liulang test title\",\"body\": \" liulang text message\"}}}\r\n\n";struct request_t {uint8_t *data;size_t data_len;};ssize_t data_prd_read_callback(nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,uint32_t *data_flags, nghttp2_data_source *source, void *user_data) {memcpy(buf, payload, strlen(payload));*data_flags = *data_flags | NGHTTP2_DATA_FLAG_EOF;printf("[INFO] C ----------------------------> S (DATA post body)\n");return strlen(payload);}/* *  * Submits the request |req| to the connection |connection|.  This *   * function does not send packets; just append the request to the *    * internal queue in |connection->session|. *     */static void submit_request(struct Connection *connection, struct Request *req) {  int32_t stream_id;  /* Make sure that the last item is NULL */  //int len = strlen(payload);  char slen[10] = {0};  sprintf(slen, "%d", strlen(payload));  const nghttp2_nv nva[] = {  MAKE_NV(":method", "POST"),MAKE_NV(":scheme", "https"),MAKE_NV(":path", "/3/device/6d48f191c76a88d2e817831916199adfccdb278c2ae46379a64650b11305118f"),                            MAKE_NV("host", "api.development.push.apple.com"),MAKE_NV("User-Agent", "nghttp2"),MAKE_NV("accept", "*/*"),    MAKE_NV("apns-id", "******************f10298b3bcc"),                        MAKE_NV("content-type", "application/json"),   MAKE_NV("apns-topic", "com.****.******"),MAKE_NV("authorization", "bearer eyAiYWxnIjogIkVTMjU2IiwgImtpZCI6ICI1UzdXODI5WFlFIiB9.eyAiaXNzIjogIlBGOUhRSldMMjQiLCAiaWF0IjogMTUwMTczMDM2NCB9.b3fTq16hPoXxvZPqkTrByCkZ4YmbGLyCQGoHQTWCkdVz0iowzFOTK7sF2o3_5n8OpJCr8saiC6S_7umSN1GaEBA")};//"bearer eyAiYWxnIjogIkVTMjU2IiwgImtpZCI6ICI1UzdXODI5WFlFIiB9.eyAiaXNzIjogIlBGOUhRSldMMjQiLCAiaWF0IjogMTUwMTY1OTg0MyB9.Qux1dO7aFXbp16z1bW8M1Z0i187vtLXwXA")};//MAKE_NV_CS("Content-Length", slen)};  struct request_t t;  nghttp2_data_provider provider;  provider.source.ptr = &t;  provider.read_callback = data_prd_read_callback;  stream_id = nghttp2_submit_request(connection->session, NULL, nva,                                     sizeof(nva) / sizeof(nva[0]), &provider, req);  if (stream_id < 0) {    diec("nghttp2_submit_request", stream_id);  }  req->stream_id = stream_id;  printf("[INFO] Stream ID = %d\n", stream_id);}int i=0;int t = 0;/* * Performs the network I/O. */static void exec_io(struct Connection *connection) {  int rv;  rv = nghttp2_session_recv(connection->session);  //printf("nghttp2_session_recv\n");  if (rv != 0) {    diec("nghttp2_session_recv", rv);  }    rv = nghttp2_session_send(connection->session);  //printf("nghttp2_session_send\n");  if (rv != 0) {diec("nghttp2_session_send", rv);  }  //nghttp2_submit_request();  //nghttp2_submit_response()}static void exec_i(struct Request *req) {/*    char buf[1024];                                                                                                int t = SSL_read(connection->ssl, buf, (int)1024);                                                            printf("buf:%s, %d\n", buf, strlen(buf));                                                                                                                       */  int rv;  rv = nghttp2_session_recv(req->connect->session);  //printf("nghttp2_session_recv\n");  if (rv != 0) {    diec("nghttp2_session_recv", rv);  }}static void exec_o(struct Request *req) {//sleep(1);  int rv = 0; rv = nghttp2_session_send(req->connect->session);  printf("nghttp2_session_send\n");  if (rv != 0) {//diec("nghttp2_session_send", rv);  }  submit_request(req->connect, req);}static void request_init(struct Request *req, const struct URI *uri) {  req->host = strcopy(uri->host, uri->hostlen);  req->port = uri->port;  req->path = strcopy(uri->path, uri->pathlen);  req->hostport = strcopy(uri->hostport, uri->hostportlen);  req->stream_id = -1;}static void request_free(struct Request *req) {  free(req->host);  free(req->path);  free(req->hostport);}char *cert_file = "cer.pem";char *key_file = "rsapk.pem";/* * Fetches the resource denoted by |uri|. */int testbool = 0;static void fetch_uri(const struct URI *uri) {  nghttp2_session_callbacks *callbacks;  int fd;  SSL_CTX *ssl_ctx;  SSL *ssl;  struct Request req;  struct Connection connection;  int rv;  nfds_t npollfds = 1;  struct pollfd pollfds[1];  request_init(&req, uri);  /* Establish connection and setup SSL */  fd = connect_to(req.host, req.port);  if (fd == -1) {    die("Could not open file descriptor");  }  ssl_ctx = SSL_CTX_new(SSLv23_client_method());  if (ssl_ctx == NULL) {    dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));  }  init_ssl_ctx(ssl_ctx);  ssl = SSL_new(ssl_ctx);  if (ssl == NULL) {    dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));  }  int nRet;      if(!(nRet = SSL_CTX_use_certificate_file         (ssl_ctx, cert_file, SSL_FILETYPE_PEM)))    {        int32_t nErrorCode = SSL_get_error(ssl_ctx, nRet);        printf("init ssl: use certificate file failed.errno: %d.", nErrorCode);        SSL_CTX_free(ssl_ctx);        ssl_ctx = NULL;        return ;    }    //SSL_CTX_use_PrivateKey_file()        //为SSL会话加载本应用的私钥    //SSL_CTX_set_default_passwd_cb_userdata(GetSSLCTX(),(void *) key_password);    nRet = SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM);    if(!nRet)    {        int32_t nErrorCode = SSL_get_error(ssl_ctx, nRet);        printf("init ssl: use PrivateKey file failed.errno: %d.", nErrorCode);        SSL_CTX_free(ssl_ctx);        ssl_ctx = NULL;        return ;    }  /* To simplify the program, we perform SSL/TLS handshake in blocking     I/O. */  ssl_handshake(ssl, fd);  connection.ssl = ssl;  connection.want_io = IO_NONE;  /* Here make file descriptor non-block */  make_non_block(fd);  set_tcp_nodelay(fd);  printf("[INFO] SSL/TLS handshake completed\n");  rv = nghttp2_session_callbacks_new(&callbacks);  if (rv != 0) {    diec("nghttp2_session_callbacks_new", rv);  }    setup_nghttp2_callbacks(callbacks);/*  nghttp2_option *option;nghttp2_option_new(&option);  //option->no_closed_streams = 1000;  //nghttp2_option_set_max_reserved_remote_streams(option, 100); nghttp2_option_set_no_closed_streams(option, 2);  //nghttp2_option_set_peer_max_concurrent_streams(option, 1000);  rv = nghttp2_session_client_new2(&connection.session, callbacks, &connection, option);*/req.connect = &connection;  rv = nghttp2_session_client_new(&connection.session, callbacks, &req);  nghttp2_session_callbacks_del(callbacks);  if (rv != 0) {    diec("nghttp2_session_client_new", rv);  }  //nghttp2_settings_entry  rv = nghttp2_submit_settings(connection.session, NGHTTP2_FLAG_ACK, NULL, 0);  if (rv != 0) {    diec("nghttp2_submit_settings", rv);  }  /* Submit the HTTP request to the outbound queue. */  submit_request(&connection, &req);  pollfds[0].fd = fd;  ctl_poll(pollfds, &connection);  //sleep(1111);  /* Event loop */  while (nghttp2_session_want_read(connection.session) ||         nghttp2_session_want_write(connection.session))  {    int nfds = poll(pollfds, npollfds, 50); if (0 == nfds){//submit_request(&connection, &req);printf("time out!\n");testbool = 1;}if (nfds == -1){      dief("poll", strerror(errno));    }    if (pollfds[0].revents & (POLLIN)) {      exec_i(&req);    }if (pollfds[0].revents & POLLOUT){//testif (1){int t;int value = 0;int size = 0;int iRet = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *)&size, (socklen_t *)&t);if (iRet != 0){printf("getsockopt error\n");}//iRet = ioctl(fd, SIOCOUTQ, &value);if (iRet != 0){printf("ioctl error\n");}//printf("totle:%d, cache:%d, send:%d\n", size, size-value, value);//printf("totle:%d, cache:%d, send:%d\n", size, size-value, value);printf("totle:%d, cache:%d, send:%d\n", size, size-value, value);}exec_o(&req);if (testbool){//sleep(1);//sleep(20);}}    if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {      die("Connection error");    }    ctl_poll(pollfds, &connection);  }  /* Resource cleanup */  nghttp2_session_del(connection.session);  SSL_shutdown(ssl);  SSL_free(ssl);  SSL_CTX_free(ssl_ctx);  shutdown(fd, SHUT_WR);  close(fd);  request_free(&req);}static int parse_uri(struct URI *res, const char *uri) {  /* We only interested in https */  size_t len, i, offset;  int ipv6addr = 0;  memset(res, 0, sizeof(struct URI));  len = strlen(uri);  if (len < 9 || memcmp("https://", uri, 8) != 0) {    return -1;  }  offset = 8;  res->host = res->hostport = &uri[offset];  res->hostlen = 0;  if (uri[offset] == '[') {    /* IPv6 literal address */    ++offset;    ++res->host;    ipv6addr = 1;    for (i = offset; i < len; ++i) {      if (uri[i] == ']') {        res->hostlen = i - offset;        offset = i + 1;        break;      }    }  } else {    const char delims[] = ":/?#";    for (i = offset; i < len; ++i) {      if (strchr(delims, uri[i]) != NULL) {        break;      }    }    res->hostlen = i - offset;    offset = i;  }  if (res->hostlen == 0) {    return -1;  }  /* Assuming https */  res->port = 443;  if (offset < len) {    if (uri[offset] == ':') {      /* port */      const char delims[] = "/?#";      int port = 0;      ++offset;      for (i = offset; i < len; ++i) {        if (strchr(delims, uri[i]) != NULL) {          break;        }        if ('0' <= uri[i] && uri[i] <= '9') {          port *= 10;          port += uri[i] - '0';          if (port > 65535) {            return -1;          }        } else {          return -1;        }      }      if (port == 0) {        return -1;      }      offset = i;      res->port = (uint16_t)port;    }  }  res->hostportlen = (size_t)(uri + offset + ipv6addr - res->host);  for (i = offset; i < len; ++i) {    if (uri[i] == '#') {      break;    }  }  if (i - offset == 0) {    res->path = "/";    res->pathlen = 1;  } else {    res->path = &uri[offset];    res->pathlen = i - offset;  }  return 0;}int main(int argc, char **argv) {  struct URI uri;  struct sigaction act;  int rv;  if (argc < 2) {    die("Specify a https URI");  }  memset(&act, 0, sizeof(struct sigaction));  act.sa_handler = SIG_IGN;  sigaction(SIGPIPE, &act, 0);  SSL_load_error_strings();  SSL_library_init();  rv = parse_uri(&uri, argv[1]);  if (rv != 0) {    die("parse_uri failed");  }  fetch_uri(&uri);  return EXIT_SUCCESS;}



原创粉丝点击