Пример #1
0
void http_exec(void)
{
  switch(http.state)
  {
  case HTTP_SEND_HEADERS:
    http_start_get();
    break;
  case HTTP_SEND_PAGE:
    http_get_pumping(0xff);
    break;
  case HTTP_COMPLETE:
    if(TCP_CONN_IS_CLOSED(http.tcp_session)) http.state = HTTP_IDLE;
    break;
  }
  // sse keep alive
  if(sys_clock_100ms > sse_ping_timer && http_can_send_sse())
  {
    unsigned pkt = tcp_create_packet_sized(sse_sock, 256);
    if(pkt != 0xff)
    {
      unsigned len = sprintf( (char*)tcp_ref(pkt, 0), "event: sse_ping\n""data: -\n\n" );
      tcp_send_packet(sse_sock, pkt, len);
      sse_ping_timer = sys_clock_100ms + 90; // 9s
    }
  }
}
Пример #2
0
// result code is unused now. always 200 OK
void http_reply(int code, char *data) // rewrite with tcp_ref() 16.12.2014
{
  unsigned pkt = tcp_create_packet(http.tcp_session);
  if(pkt != 0xFF)
  {
    unsigned dlen = strlen(data);
    if(dlen > 1024) dlen = 1024;
    char *p = tcp_ref(pkt, 0);
    char *s = p;
    p += sprintf(p,
      "HTTP/1.1 200 Ok\r\n"
      "Connection: Close\r\n"
      "Cache-Control: no-store, no-cache, must-revalidate\r\n"
      "Expires: Fri, 13 Oct 2000 00:00:00 GMT\r\n"
        );
    if(req_origin[0] != 0)
      p += sprintf(p,
      "Access-Control-Allow-Origin: %s\r\n"
      "Access-Control-Allow-Credentials: true\r\n",
        req_origin );
    p += sprintf(p,
      "Content-Type: %s\r\n"
      "Content-Length: %u\r\n"
      "\r\n",
         http.page->mime,
         dlen
         );
    memcpy(p, data, dlen); p += dlen;
    tcp_send_packet(http.tcp_session, pkt, (unsigned)(p - s));
  }
  tcp_close_session(http.tcp_session);
  http.state = HTTP_COMPLETE;
}
Пример #3
0
static void win_notify_on_read(grpc_endpoint *ep,
                               grpc_endpoint_read_cb cb, void *arg) {
  grpc_tcp *tcp = (grpc_tcp *) ep;
  grpc_winsocket *handle = tcp->socket;
  grpc_winsocket_callback_info *info = &handle->read_info;
  int status;
  DWORD bytes_read = 0;
  DWORD flags = 0;
  WSABUF buffer;

  GPR_ASSERT(!tcp->socket->read_info.outstanding);
  if (tcp->shutting_down) {
    cb(arg, NULL, 0, GRPC_ENDPOINT_CB_SHUTDOWN);
    return;
  }
  tcp_ref(tcp);
  tcp->socket->read_info.outstanding = 1;
  tcp->read_cb = cb;
  tcp->read_user_data = arg;

  tcp->read_slice = gpr_slice_malloc(8192);

  buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
  buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);

  /* First let's try a synchronous, non-blocking read. */
  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
                   NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* Did we get data immediately ? Yay. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    info->bytes_transfered = bytes_read;
    /* This might heavily recurse. */
    on_read(tcp, 1);
    return;
  }

  /* Otherwise, let's retry, by queuing a read. */
  memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
                   &info->overlapped, NULL);

  if (status != 0) {
    int wsa_error = WSAGetLastError();
    if (wsa_error != WSA_IO_PENDING) {
      info->wsa_error = wsa_error;
      on_read(tcp, 1);
      return;
    }
  }

  grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
}
Пример #4
0
/* Initiates a shutdown of the TCP endpoint. This will queue abort callbacks
   for the potential read and write operations. It is up to the caller to
   guarantee this isn't called in parallel to a read or write request, so
   we're not going to protect against these. However the IO Completion Port
   callback will happen from another thread, so we need to protect against
   concurrent access of the data structure in that regard. */
static void win_shutdown(grpc_endpoint *ep) {
  grpc_tcp *tcp = (grpc_tcp *) ep;
  int extra_refs = 0;
  gpr_mu_lock(&tcp->mu);
  /* At that point, what may happen is that we're already inside the IOCP
     callback. See the comments in on_read and on_write. */
  tcp->shutting_down = 1;
  extra_refs = grpc_winsocket_shutdown(tcp->socket);
  while (extra_refs--) tcp_ref(tcp);
  gpr_mu_unlock(&tcp->mu);
}
Пример #5
0
/* Initiates a write. */
static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
                                            gpr_slice *slices, size_t nslices,
                                            grpc_endpoint_write_cb cb,
                                            void *arg) {
  grpc_tcp *tcp = (grpc_tcp *) ep;
  grpc_winsocket *socket = tcp->socket;
  grpc_winsocket_callback_info *info = &socket->write_info;
  unsigned i;
  DWORD bytes_sent;
  int status;
  WSABUF local_buffers[16];
  WSABUF *allocated = NULL;
  WSABUF *buffers = local_buffers;

  GPR_ASSERT(!tcp->outstanding_write);
  GPR_ASSERT(!tcp->shutting_down);
  tcp_ref(tcp);

  tcp->outstanding_write = 1;
  tcp->write_cb = cb;
  tcp->write_user_data = arg;

  gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);

  if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
    buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
    allocated = buffers;
  }

  for (i = 0; i < tcp->write_slices.count; i++) {
    buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
    buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
  }

  /* First, let's try a synchronous, non-blocking write. */
  status = WSASend(socket->socket, buffers, tcp->write_slices.count,
                   &bytes_sent, 0, NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
     connection that has its send queue filled up. But if we don't, then we can
     avoid doing an async write operation at all. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
    if (status == 0) {
      ret = GRPC_ENDPOINT_WRITE_DONE;
      GPR_ASSERT(bytes_sent == tcp->write_slices.length);
    } else {
      char *utf8_message = gpr_format_message(info->wsa_error);
      gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
      gpr_free(utf8_message);
    }
    if (allocated) gpr_free(allocated);
    gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
    tcp->outstanding_write = 0;
    tcp_unref(tcp);
    return ret;
  }

  /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
     operation, this time asynchronously. */
  memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSASend(socket->socket, buffers, tcp->write_slices.count,
                   &bytes_sent, 0, &socket->write_info.overlapped, NULL);
  if (allocated) gpr_free(allocated);

  /* It is possible the operation completed then. But we'd still get an IOCP
     notification. So let's ignore it and wait for the IOCP. */
  if (status != 0) {
    int error = WSAGetLastError();
    if (error != WSA_IO_PENDING) {
      char *utf8_message = gpr_format_message(WSAGetLastError());
      gpr_log(GPR_ERROR, "WSASend error: %s - this means we're going to leak.",
              utf8_message);
      gpr_free(utf8_message);
    /* I'm pretty sure this is a very bad situation there. Hence the log.
       What will happen now is that the socket will neither wait for read
       or write, unless the caller retry, which is unlikely, but I am not
       sure if that's guaranteed. And there might also be a read pending.
       This means that the future orphanage of that socket will be in limbo,
       and we're going to leak it. I have no idea what could cause this
       specific case however, aside from a parameter error from our call.
       Normal read errors would actually happen during the overlapped
       operation, which is the supported way to go for that. */
      tcp->outstanding_write = 0;
      tcp_unref(tcp);
      /* Per the comment above, I'm going to treat that case as a hard failure
         for now, and leave the option to catch that and debug. */
      __debugbreak();
      return GRPC_ENDPOINT_WRITE_ERROR;
    }
  }

  /* As all is now setup, we can now ask for the IOCP notification. It may
     trigger the callback immediately however, but no matter. */
  grpc_socket_notify_on_write(socket, on_write, tcp);
  return GRPC_ENDPOINT_WRITE_PENDING;
}
Пример #6
0
static void win_notify_on_read(grpc_endpoint *ep,
                               grpc_endpoint_read_cb cb, void *arg) {
  grpc_tcp *tcp = (grpc_tcp *) ep;
  grpc_winsocket *handle = tcp->socket;
  grpc_winsocket_callback_info *info = &handle->read_info;
  int status;
  DWORD bytes_read = 0;
  DWORD flags = 0;
  int error;
  WSABUF buffer;

  GPR_ASSERT(!tcp->outstanding_read);
  GPR_ASSERT(!tcp->shutting_down);
  tcp_ref(tcp);
  tcp->outstanding_read = 1;
  tcp->read_cb = cb;
  tcp->read_user_data = arg;

  tcp->read_slice = gpr_slice_malloc(8192);

  buffer.len = GPR_SLICE_LENGTH(tcp->read_slice);
  buffer.buf = (char *)GPR_SLICE_START_PTR(tcp->read_slice);

  /* First let's try a synchronous, non-blocking read. */
  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
                   NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* Did we get data immediately ? Yay. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    info->bytes_transfered = bytes_read;
    /* This might heavily recurse. */
    on_read(tcp, 1);
    return;
  }

  /* Otherwise, let's retry, by queuing a read. */
  memset(&tcp->socket->read_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSARecv(tcp->socket->socket, &buffer, 1, &bytes_read, &flags,
                   &info->overlapped, NULL);

  if (status == 0) {
    grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
    return;
  }

  error = WSAGetLastError();

  if (error != WSA_IO_PENDING) {
    char *utf8_message = gpr_format_message(WSAGetLastError());
    gpr_log(GPR_ERROR, "WSARecv error: %s - this means we're going to leak.",
            utf8_message);
    gpr_free(utf8_message);
    /* I'm pretty sure this is a very bad situation there. Hence the log.
       What will happen now is that the socket will neither wait for read
       or write, unless the caller retry, which is unlikely, but I am not
       sure if that's guaranteed. And there might also be a write pending.
       This means that the future orphanage of that socket will be in limbo,
       and we're going to leak it. I have no idea what could cause this
       specific case however, aside from a parameter error from our call.
       Normal read errors would actually happen during the overlapped
       operation, which is the supported way to go for that. */
    tcp->outstanding_read = 0;
    tcp_unref(tcp);
    cb(arg, NULL, 0, GRPC_ENDPOINT_CB_ERROR);
    /* Per the comment above, I'm going to treat that case as a hard failure
       for now, and leave the option to catch that and debug. */
    __debugbreak();
    return;
  }

  grpc_socket_notify_on_read(tcp->socket, on_read, tcp);
}
Пример #7
0
/* Initiates a write. */
static grpc_endpoint_write_status win_write(grpc_endpoint *ep,
                                            gpr_slice *slices, size_t nslices,
                                            grpc_endpoint_write_cb cb,
                                            void *arg) {
  grpc_tcp *tcp = (grpc_tcp *) ep;
  grpc_winsocket *socket = tcp->socket;
  grpc_winsocket_callback_info *info = &socket->write_info;
  unsigned i;
  DWORD bytes_sent;
  int status;
  WSABUF local_buffers[16];
  WSABUF *allocated = NULL;
  WSABUF *buffers = local_buffers;

  GPR_ASSERT(!tcp->socket->write_info.outstanding);
  if (tcp->shutting_down) {
    return GRPC_ENDPOINT_WRITE_ERROR;
  }
  tcp_ref(tcp);

  tcp->socket->write_info.outstanding = 1;
  tcp->write_cb = cb;
  tcp->write_user_data = arg;

  gpr_slice_buffer_addn(&tcp->write_slices, slices, nslices);

  if (tcp->write_slices.count > GPR_ARRAY_SIZE(local_buffers)) {
    buffers = (WSABUF *) gpr_malloc(sizeof(WSABUF) * tcp->write_slices.count);
    allocated = buffers;
  }

  for (i = 0; i < tcp->write_slices.count; i++) {
    buffers[i].len = GPR_SLICE_LENGTH(tcp->write_slices.slices[i]);
    buffers[i].buf = (char *)GPR_SLICE_START_PTR(tcp->write_slices.slices[i]);
  }

  /* First, let's try a synchronous, non-blocking write. */
  status = WSASend(socket->socket, buffers, tcp->write_slices.count,
                   &bytes_sent, 0, NULL, NULL);
  info->wsa_error = status == 0 ? 0 : WSAGetLastError();

  /* We would kind of expect to get a WSAEWOULDBLOCK here, especially on a busy
     connection that has its send queue filled up. But if we don't, then we can
     avoid doing an async write operation at all. */
  if (info->wsa_error != WSAEWOULDBLOCK) {
    grpc_endpoint_write_status ret = GRPC_ENDPOINT_WRITE_ERROR;
    if (status == 0) {
      ret = GRPC_ENDPOINT_WRITE_DONE;
      GPR_ASSERT(bytes_sent == tcp->write_slices.length);
    } else {
      char *utf8_message = gpr_format_message(info->wsa_error);
      gpr_log(GPR_ERROR, "WSASend error: %s", utf8_message);
      gpr_free(utf8_message);
    }
    if (allocated) gpr_free(allocated);
    gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
    tcp->socket->write_info.outstanding = 0;
    tcp_unref(tcp);
    return ret;
  }

  /* If we got a WSAEWOULDBLOCK earlier, then we need to re-do the same
     operation, this time asynchronously. */
  memset(&socket->write_info.overlapped, 0, sizeof(OVERLAPPED));
  status = WSASend(socket->socket, buffers, tcp->write_slices.count,
                   &bytes_sent, 0, &socket->write_info.overlapped, NULL);
  if (allocated) gpr_free(allocated);

  if (status != 0) {
    int wsa_error = WSAGetLastError();
    if (wsa_error != WSA_IO_PENDING) {
      gpr_slice_buffer_reset_and_unref(&tcp->write_slices);
      tcp->socket->write_info.outstanding = 0;
      tcp_unref(tcp);
      return GRPC_ENDPOINT_WRITE_ERROR;
    }
  }

  /* As all is now setup, we can now ask for the IOCP notification. It may
     trigger the callback immediately however, but no matter. */
  grpc_socket_notify_on_write(socket, on_write, tcp);
  return GRPC_ENDPOINT_WRITE_PENDING;
}
Пример #8
0
void http_start_get(void)
{
  http.state = HTTP_SEND_HEADERS;
  unsigned pkt = tcp_create_packet(http.tcp_session);
  if(pkt == 0xff) return;
  tcp_tx_body_pointer=0;
  ADD_HTTP_STRING(pkt,
    "HTTP/1.1 200 Ok\r\n"
    "Connection: Close\r\n");
  if(http.page->flags & HTML_FLG_NOCACHE)
  {
    ADD_HTTP_STRING(pkt,
    "Cache-Control: no-store, no-cache, must-revalidate\r\n"
    "Expires: Fri, 28 Apr 2000 00:00:00 GMT\r\n");
  }
  else
  {
    ADD_HTTP_STRING(pkt,
    "Cache-Control: max-age=10000, private\r\n");
  }
  if(http.page->flags & HTML_FLG_COMPRESSED)
  {
    ADD_HTTP_STRING(pkt,
    "Content-Encoding: gzip\r\n");
  }
  char *p = tcp_ref(pkt, tcp_tx_body_pointer);
  char *s = p;
  p += sprintf(p, "Content-Type: %s\r\n", http.page->mime);
  if(req_origin[0] != 0)
  {
    p += sprintf(p, "Access-Control-Allow-Origin: %s\r\n", req_origin);
    p += sprintf(p, "Access-Control-Allow-Credentials: true\r\n");
  }
  p += sprintf(p, "\r\n"); // end of headers
  tcp_tx_body_pointer += (unsigned)(p - s);
  if(http.page->flags & HTML_FLG_SS_EVENT)
  {
    if(sse_sock != 0xff)
    {
      // prepare old SSE socket to work as new http socket
      if(tcp_socket[sse_sock].tcp_state != TCP_RESERVED)
      {
        tcp_send_flags(TCP_MSK_ACK | TCP_MSK_RST | TCP_MSK_PSH, sse_sock);
        tcp_send_flags(TCP_MSK_ACK | TCP_MSK_RST | TCP_MSK_PSH, sse_sock);
        tcp_clear_connection(sse_sock);
      }
      // pass current http socket to SSE use
      unsigned swap_sock = sse_sock;
      sse_sock = http.tcp_session;
      http.tcp_session = swap_sock;
      // add initial data on SSE channel
      static char sse_retry_cmd[] = "retry: 2000\n\n";
      tcp_put_tx_body(pkt, (void*)sse_retry_cmd, strlen(sse_retry_cmd));
      ((unsigned(*)(unsigned, unsigned))(http.page->addr))(pkt, 0);
      // send 1st reply on SSE channel
      tcp_send_packet(sse_sock, pkt, tcp_tx_body_pointer);
      // start listening on alternative socket
      tcp_socket[http.tcp_session].tcp_state = TCP_LISTEN;
      http.state = HTTP_IDLE;
    }
  }
  else
  {
    http.state = HTTP_SEND_PAGE;
    http.sent = 0;
    http.more_data = 0;
    http_get_pumping(pkt);
  }
}