📄 httpd.c
字号:
(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 + -