⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 5 页
字号:
        (conn->transfered != conn->filesize))
    {
      /* close the connection */
      ht_destroyConnection(conn);
    }
    else
    {
      /* initialize next transfer */
      FD_CLR(conn->socket, &globalWrSocketSet);
      ht_initConnection(conn);
      log(conn->socket, "------ reuse connection ------\r\n");
      if (conn->rxbuflen > 0)
        ht_handleUpStream(conn);
      return;
    }
  }
}


/* temporarly disable socket writes
 */
static void ht_disableWrite(HTTPCONN_t *conn)
{
  /* disable write for the socket */
  conn->wrDisabled = 1;
  FD_CLR(conn->socket, &globalWrSocketSet);

  /* move connection to the head of the list */
  if (conn != FIRST_LIST_ELEM(&activeConnList_g, HTTPCONN_t*))
  {
    ht_listDel((lelem_t*)(void*)conn);
    ht_listAddHead(&activeConnList_g, (lelem_t*)(void*)conn);
  }
  blockedConns_g++;
}


/* handle the data that we shall send to the client
 */
static void ht_handleDownStream(HTTPCONN_t *conn)
{
  sint_t bytes, rc;

  if ((conn->state == STATE_DOWNSTREAM) &&
      ((conn->filehandle >= 0)
#if HTTP_SERVLETS
      || (conn->servlet != NULL)
#endif
     ))
  {
    /* handle downstream */

    /* get next block from file */
    if (conn->txbufptr == conn->txbuflen)
    {
      bytes = ht_readFile(conn, (char*)conn->txbuffer, HTTP_TXBUFSIZE);
      if (bytes <= 0)
      {
        /* end of transfer */
        ht_nextTransfer(conn);
        return;
      }
      conn->txbufptr = 0;
      conn->txbuflen = (uint_t) bytes;
    }

    /* send bytes to the socket */
    bytes = (sint_t) (conn->txbuflen - conn->txbufptr);
    rc = send(conn->socket, (char*)(conn->txbuffer + conn->txbufptr),
              bytes, 0);
    if (rc <= 0)
    {
      if (sysGetErrno() == EWOULDBLOCK)
      {
        /* disable write for the socket */
        ht_disableWrite(conn);
        return;
      }

      /* error, close the connection */
      ht_destroyConnection(conn);
      return;
    }

    if (rc > bytes) rc = bytes;  /* we ignore this error */
    conn->txbufptr += rc;
    conn->transfered += rc;
    conn->lasttransfer = COUNTERVAR;

#ifdef ENABLE_LOG
    sprintf((char*)tempbuf1_g, "%i bytes transfered\r\n", rc);
    log(conn->socket, (char*)tempbuf1_g);
#endif
  }
}


/* handle the data that is sent from the client to us
 */
static void ht_handleUpStream(HTTPCONN_t *conn)
{
  char *cmd;

  if (conn->state == STATE_DOWNSTREAM)
  {
    /* handle data that is streamed to us */

    ht_fillInputBuffer(conn);

    /* If we run out of buffer space, we let complete
       the current download but close the connection then.
       This is not nice but we hope the client will notice
       the error and will do the request again (HTTP/1.0 behaviour). */
    if (conn->rxbuflen == HTTP_RXBUFSIZE)
    {
      conn->keepalive = 0;
    }

    /* When download is in progress and connection will be closed,
       discard all incomming data. */
    if (conn->keepalive == 0)
    {
      conn->rxbufptr = 0;
      conn->rxbuflen = 0;
    }
    return;
  }
  else
  if (conn->state == STATE_UPSTREAM)
  {
    /* upstream (methods POST and PUT) is not yet implemented */
    return;
  }

  /* handle STATE_INIT */

  for(;;)
  {
    cmd = ht_readLine(conn);
    if (cmd == NULL)
      return;

    if (*cmd == 0)
    {
      /* header fully received */

      /* send "continue" if requested */
      if (conn->cont100 != 0)
      {
        conn->cont100 = 0;
        ht_sendStatus(conn, status_100);  /* Continue */
      }

      if ((conn->method == method_get) || (conn->method == method_head))
      {
        /* initialize file transfer */
        if (ht_openFile(conn, FSO_RDONLY | FSO_BINARY, &conn->filesize) < 0)
        {
          /* file not found */
          ht_sendStatus(conn, status_404);
          ht_nextTransfer(conn);
          return;
        }

#if HTTP_SERVLETS
        /* servlets are handled special */
        if (conn->servlet != NULL)
        {
          if (ht_assignSession(conn) != 0)
          {
            ht_sendStatus(conn, status_idtimeout);
            ht_nextTransfer(conn);
          }
          else
          {
            ht_handleServlet(conn);
          }
          return;
        }
#endif

        /* determine and set the type of file content */
        ht_setContentType(conn);

        /* if file is empty, handle next transfer */
        if (conn->filesize == 0)
        {
          ht_sendStatus(conn, status_204); /* No Content */
          ht_nextTransfer(conn);
          return;
        }

        ht_sendStatus(conn, status_200); /* OK */

        /* quit now if we shall only transmit the header */
        if (conn->method == method_head)
        {
          ht_nextTransfer(conn);
          return;
        }

        /* set up to download data */
        ht_addWrSocket(conn->socket);
        conn->state = STATE_DOWNSTREAM;

        return;
      }
      else
      if ((conn->method == method_put) || (conn->method == method_post))
      {
        conn->state = STATE_UPSTREAM;
      }
      else
      {
        /* Other methods were not implemented. We should never get here. */
        ht_sendStatus(conn, status_501); /* Not Implemented */
        return;
      }
    }
    else
    {
      log(conn->socket, "cmd='");
      log(-1, cmd);
      log(-1, "'\r\n");
      ht_parseCommandLine(conn, cmd);
    }
  }

}


/*-------------------------------------------------------------------------*/


/* initialize (reset) an existing connection
 */
static void ht_initConnection(HTTPCONN_t* conn)
{
  conn->http11       = 0;  /* defaults to HTTP/1.0 */
  conn->keepalive    = KEEPALIVE_PERDEFAULT;
  conn->lasttransfer = COUNTERVAR;
  conn->txbufptr     = 0;
  conn->txbuflen     = 0;
  conn->wrDisabled   = 0;
  conn->state        = STATE_INIT;
  conn->emptyline    = 1;
  conn->filehandle   = -1;
  conn->method       = method_none;
  conn->contenttype  = content_unknown;
  conn->cont100      = 0;
  conn->upStreamLen  = 0;
  conn->filesize     = 0;
  conn->transfered   = 0;
  conn->filename[0]  = 0;
#if HTTP_SERVLETS
  INIT_LIST_HEAD(&conn->mwlist);
  conn->servlet      = NULL;
  conn->session      = NULL;
  conn->stdoutbuf    = NULL;
  conn->curoutbuf    = NULL;
  conn->freeSlBufs   = NULL;
  conn->outbufsize   = 0;
  conn->outbufptr    = 0;
  conn->stdoutlen    = 0;
  conn->neededBufs   = 0;
  conn->optstring[0] = 0;
  conn->linkbuf[0]   = 0;
#endif
}


/* Create a new connection info structure
 * and put it to the list of active connections
 */
static HTTPCONN_t*  ht_newConnection(int socket)
{
  HTTPCONN_t*  conn;

  conn = FIRST_LIST_ELEM(&unusedConnList_g, HTTPCONN_t*);
  
  if (END_OF_LIST(&unusedConnList_g, conn))
  {
    conn = (HTTPCONN_t*) sysMemAlloc(sizeof(HTTPCONN_t));
    if (conn == NULL)
      return NULL;
  }
  else
  {
    ht_listDel((lelem_t*)(void*)conn);
  }

  conn->socket       = socket;
  conn->rxbuflen     = 0;
  conn->rxbufptr     = 0;
  conn->rxlinelen    = 0;
  conn->havebackchar = 0;
  conn->dataavail    = 0;

  ht_initConnection(conn);

  ht_addRdSocket(socket);
  ht_listAddTail(&activeConnList_g, (lelem_t*)(void*)conn);
  connections_g++;
  log(conn->socket, "------ new connection ------\r\n");
  return conn;
}


/* Destroy a connection (close the socket and remove
 * it from the list of active connections)
 */
static void ht_destroyConnection(HTTPCONN_t* conn)
{
  if (conn->socket >= 0)
  {
    ht_closeFile(conn);
    ht_delSocket(conn->socket);
    if (conn->wrDisabled != 0)
      blockedConns_g--;
#if HTTP_SERVLETS
    if (conn->servlet != NULL)
    {
      ht_destroySession(conn->session);
      if (IS_ON_LIST(&conn->mwlist))
        ht_listDel(&conn->mwlist);
      if (conn->stdoutbuf != NULL)
        ht_freeServletBufferChain(conn->stdoutbuf);
      if (conn->freeSlBufs != NULL)
        ht_freeServletBufferChain(conn->freeSlBufs);
    }
#endif
    ht_listDel((lelem_t*)(void*)conn);
    ht_listAddTail(&unusedConnList_g, (lelem_t*)(void*)conn);
    log(conn->socket, "------ connection destroyed ------\r\n");
    conn->socket = -1;

    connections_g--;
  }
}


/*-------------------------------------------------------------------------*/


/* Add a socket to the global read socket set.
 */
static sint_t ht_addRdSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalRdSocketSet);
    FD_SET(sock, &globalRdSocketSet);
    return 0;
  }
  return -1;
}


/* Add a socket to the global write socket set.
 */
static sint_t ht_addWrSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalWrSocketSet);
    FD_SET(sock, &globalWrSocketSet);
    return 0;
  }
  return -1;
}


/* Remove socket from fdsets and close it.
 */
static void ht_delSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalRdSocketSet);
    FD_CLR(sock, &globalWrSocketSet);
    closesocket(sock);
  }
}


/* Create a new server socket.
 */
static int ht_newServerSocket(void)
{
  unsigned long one = 1;
  struct sockaddr_in addr;
  int s, err;
  
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0)
  {
    sysPrintErr("HTTPD: Failed to create server socket!\n");
    return -1;
  }

  setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void*) &one, sizeof(one));
  ioctlsocket(s, FIONBIO, (void*) &one);    /* set nonblocking mode */

  sysMemSet(&addr, 0, sizeof(addr));
  addr.sin_family      = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port        = htons(HTTP_PORT);

  err = bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr));
  if (err < 0)
  {
    if ((sysGetErrno() == ENOMEM) || (sysGetErrno() == EADDRINUSE))
    {
      /* wait some time and try again...*/
      sysSleep(500);
      err = bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr));
    }
    if (err < 0)
    {
      closesocket(s);
      sysPrintErr("HTTPD: Failed to bind server socket!\n");
      return -1;
    }
  }

  listen(s, HTTP_MAXCONN-1);

  serverSocket_g = s;
  return 0;
}


/* Accept and open a new connection to the next client.
 * Put the connection structure into the global list.
 */
static void ht_acceptClient(void)
{
#ifdef SOL_TCP
  unsigned long zero = 0;
#endif
  unsigned long one = 1;
  struct sockaddr_in addr;
  int    s, alen;
  static sint_t errors = 0;
  sint_t i;

  alen = sizeof(addr);
  sysMemSet(&addr, 0, sizeof(addr));
  s = accept(serverSocket_g, (struct sockaddr *)&addr, &alen);

  if (s < 0)
  {
    if ((sysGetErrno() == EBADF
#ifdef EPIPE
       || sysGetErrno() == EPIPE
#endif
       ) && (++errors >= 3))
    {
      /* try to recover server socket on too much errors */
      closesocket(serverSocket_g);
      serverSocket_g = -1;
      i = 10;
      while ((ht_newServerSocket() != 0) && (--i > 0))
        sysSleep(500);

      if (i == 0)
      {
        sysPrintErr("HTTPD: Failed to create server socket! Server is unusable.\n");
      }
      errors = 0;
    }
  }
  else
  {
    if (connections_g >= HTTP_MAXCONN)
    {
      /* do not accept this connection */
      closesocket(s);
    }
    else
    {
      /* set options: nonblocking transfer, no delay */
      ioctlsocket(s, FIONBIO, (void*) &one);
#ifdef SOL_TCP
      setsockopt(s, SOL_TCP, TCP_NODELAY, (void *)&zero, sizeof(zero));
#endif

      /* create new connection */
      ht_newConnection(s);
    }
    errors = 0;
  }
}


/* check for timed out sockets and close the connections
 */
static void  ht_timeout(void)
{
  HTTPCONN_t    *conn, *nextc;
  COUNTERTYPE   now = COUNTERVAR;  
  COUNTERSTYPE  remain, to;
#if HTTP_SERVLETS
  SESSION_t     *ss, *nss;
#endif

  for (conn = FIRST_LIST_ELEM(&activeConnList_g, HTTPCONN_t*);
       !END_OF_LIST(&activeConnList_g, conn);
       conn = nextc)
  {
    nextc = NEXT_LIST_ELEM(conn, HTTPCONN_t*);

    if (conn->state == STATE_INIT)
    {
      to = (COUNTERSTYPE)(HTTP_TIMEOUT_IDLE * COUNTERTPS);
    }
    else
    {
      to = (COUNTERSTYPE)(HTTP_TIMEOUT_TRANS * COUNTERTPS);
    }

    remain = ((COUNTERSTYPE) conn->lasttransfer) + to -
             (COUNTERSTYPE) now;
    if (remain <= 0)
    {
      log(conn->socket, "connection timed out\r\n");
      ht_destroyConnection(conn);
    }
  }

#if HTTP_SERVLETS
  for (ss = FIRST_LIS

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -