📄 socket.c
字号:
return;
}
if (len < 0)
{
// There was an error reading from this socket. Play it safe and
// close it. This will force the client to generate a shutdown
// and we will read a len = 0 the next time around.
shutdown(descr, SHUT_WR);
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("ERROR reading from socket. read() returned: %d\n",
httpstate.inbuffer_len);
#endif
return;
}
httpstate.inbuffer_len += len;
}
httpstate.inbuffer[httpstate.inbuffer_len] = '\0';
// Timestamp the socket.
httpstate.sockets[index].timestamp = time(NULL);
// This is where it all happens.
cyg_httpd_process_method();
if (httpstate.mode & CYG_HTTPD_MODE_CLOSE_CONN)
// There are 2 cases we can be here:
// 1) chunked frames close their connection by default
// 2) The client requested the connection be terminated with a
// "Connection: close" in the header
// In any case, we close the TX pipe and wait for the client to
// send us an EOF on the receive pipe. This is a more graceful way
// to handle the closing of the socket, compared to just calling
// close() without first asking the opinion of the client, and
// running the risk of stray data lingering around.
shutdown(descr, SHUT_WR);
}
void
cyg_httpd_handle_new_connection(cyg_int32 listener)
{
cyg_int32 i;
int fd_client = accept(listener, NULL, NULL);
CYG_ASSERT(listener != -1, "accept() failed");
if (fd_client == -1)
return;
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("Opening descriptor: %d\n", fd_client);
#endif
// Timestamp the socket and process the frame immediately, since the accept
// guarantees the presence of valid data on the newly opened socket.
for (i = 0; i < CYGPKG_NET_MAXSOCKETS; i++)
if (httpstate.sockets[i].descriptor == 0)
{
httpstate.sockets[i].descriptor = fd_client;
httpstate.sockets[i].timestamp = time(NULL);
cyg_httpd_process_request(i);
return;
}
}
// This is the "garbage collector" (or better, the "garbage disposer") of
// the server. It closes any socket that has been idle for a time period
// of CYG_HTTPD_SELECT_TIMEOUT seconds.
void
cyg_httpd_close_unused_sockets(cyg_int32 listener)
{
cyg_int32 i;
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("Garbage collector called\r\n");
#endif
httpstate.fdmax = listener;
for (i = 0; i < CYGPKG_NET_MAXSOCKETS; i++)
{
if (httpstate.sockets[i].descriptor != 0)
{
if (time(NULL) - httpstate.sockets[i].timestamp >
CYG_HTTPD_SOCKET_IDLE_TIMEOUT)
{
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("Closing descriptor: %d\n",
httpstate.sockets[i].descriptor);
#endif
shutdown(httpstate.sockets[i].descriptor, SHUT_WR);
}
else
httpstate.fdmax = MAX(httpstate.fdmax,
httpstate.sockets[i].descriptor);
}
}
}
void
cyg_httpd_daemon(cyg_addrword_t data)
{
cyg_int32 rc;
init_all_network_interfaces();
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
#ifdef CYGHWR_NET_DRIVER_ETH0
if (eth0_up)
{
struct bootp* bps = ð0_bootp_data;
diag_printf("ETH0 is up. IP address: %s\n", inet_ntoa(bps->bp_yiaddr));
}
#endif
#endif
#ifdef CYGOPT_NET_ATHTTPD_USE_CGIBIN_TCL
cyg_httpd_init_tcl_interpreter();
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("Tcl interpreter has been initialized...\n");
#endif
#endif
cyg_httpd_initialize();
// Get the network going. This is benign if the application has
// already done this.
cyg_int32 listener = socket(AF_INET, SOCK_STREAM, 0);
CYG_ASSERT(listener > 0, "Socket create failed");
if (listener < 0)
return;
cyg_int32 yes = 1;
rc = setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (rc == -1)
return;
memset(&(httpstate.server_conn), 0, sizeof(struct sockaddr_in));
httpstate.server_conn.sin_family = AF_INET;
httpstate.server_conn.sin_addr.s_addr = INADDR_ANY;
httpstate.server_conn.sin_port = htons(CYGNUM_NET_ATHTTPD_SERVEROPT_PORT);
rc = bind(listener,
(struct sockaddr *)&httpstate.server_conn,
sizeof(struct sockaddr));
CYG_ASSERT(rc == 0, "bind() returned error");
if (rc != 0)
return;
rc = listen(listener, SOMAXCONN);
CYG_ASSERT(rc == 0, "listen() returned error");
if (rc != 0)
return;
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
diag_printf("Web server Started and listening...\n");
#endif
cyg_int32 i;
for (i = 0; i < CYGNUM_FILEIO_NFILE; i++)
{
httpstate.sockets[i].descriptor = 0;
httpstate.sockets[i].timestamp = (time_t)0;
}
FD_ZERO(&httpstate.rfds);
httpstate.fdmax = listener;
while (1)
{
// The listener is always added to the select() sensitivity list.
FD_SET(listener, &httpstate.rfds);
struct timeval tv = {CYG_HTTPD_SOCKET_IDLE_TIMEOUT, 0};
rc = select(httpstate.fdmax + 1, &httpstate.rfds, NULL, NULL, &tv);
if (rc > 0)
{
if (FD_ISSET(listener, &httpstate.rfds))
// If the request is from the listener socket, then
// this must be a new connection.
cyg_httpd_handle_new_connection(listener);
httpstate.fdmax = listener;
// The sensitivity list returned by select() can have multiple
// socket descriptors that need service. Loop through the whole
// descriptor list to see if one or more need to be served.
for (i = 0; i < CYGPKG_NET_MAXSOCKETS; i ++)
{
cyg_int32 descr = httpstate.sockets[i].descriptor;
if (descr != 0)
{
// If the descriptor is set in the descriptor list, we
// service it. Otherwise, we add it to the descriptor list
// to listen for. The rfds list gets rewritten each time
// select() is called and after the call it contains only
// the descriptors that need be serviced. Before calling
// select() again we must repopulate the list with all the
// descriptors that must be listened for.
if (FD_ISSET(descr, &httpstate.rfds))
cyg_httpd_process_request(i);
else
FD_SET(descr, &httpstate.rfds);
if (httpstate.sockets[i].descriptor != 0)
httpstate.fdmax = MAX(httpstate.fdmax, descr);
}
}
}
else if (rc == 0)
{
cyg_httpd_close_unused_sockets(listener);
}
else
{
#if CYGOPT_NET_ATHTTPD_DEBUG_LEVEL > 0
cyg_int8 *ptr = (cyg_int8*)&httpstate.rfds;
diag_printf("rfds: %x %x %x %x\n", ptr[0], ptr[1], ptr[2], ptr[3] );
for (i = 0; i < CYGPKG_NET_MAXSOCKETS; i++)
if (httpstate.sockets[i].descriptor != 0)
diag_printf("Socket in list: %d\n",
httpstate.sockets[i].descriptor);
#endif
CYG_ASSERT(rc != -1, "Error during select()");
}
}
}
void
cyg_httpd_start(void)
{
if (cyg_httpd_initialized)
return;
cyg_httpd_initialized = 1;
cyg_thread_create(CYGNUM_NET_ATHTTPD_THREADOPT_PRIORITY,
cyg_httpd_daemon,
(cyg_addrword_t)0,
"HTTPD Thread",
(void *)cyg_httpd_thread_stack,
CYG_HTTPD_DAEMON_STACK_SIZE,
&cyg_httpd_thread_handle,
&cyg_httpd_thread_object);
cyg_thread_resume(cyg_httpd_thread_handle);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -