Fix for 100% CPU issue in select() in miniserv.c. I have also removed
the sleep() call, it was just a workaround. SF Bug Tracker [ 3086852 ] 99% CPU loop in miniserver.c on a non ipv6 system. Submitted by: Jin ( jin_eld ) - 2010-10-13 19:29:13 UTC I cross compiled libupnp 1.6.7 for ARM9 using the --disable-ipv6 option, my system is an ipv4 only setup. I do not know why this problem only appears when running the app in the background (for instance using nohup &), but then it starts using 99% CPU. I traced the problem down to the select() call in miniserver.c in the RunMiniServer() function. Select returns code 1, but errno is set to "Socket operation on non-socket", I also see this when running my app under strace. I set all ...Sock6 variables to INVALID_SOCKET to make sure that they do not get added to the FD_SET and the problem is gone.
This commit is contained in:
parent
8401a59ed5
commit
f74746ff3f
25
ChangeLog
25
ChangeLog
@ -7,6 +7,31 @@ Version 1.6.8
|
||||
Version 1.6.7
|
||||
*******************************************************************************
|
||||
|
||||
2010-10-15 Marcelo Roberto Jimenez <mroberto(at)users.sourceforge.net>
|
||||
|
||||
Fix for 100% CPU issue in select() in miniserv.c. I have also removed
|
||||
the sleep() call, it was just a workaround.
|
||||
|
||||
SF Bug Tracker [ 3086852 ] 99% CPU loop in miniserver.c on a non ipv6
|
||||
system.
|
||||
|
||||
Submitted by: Jin ( jin_eld ) - 2010-10-13 19:29:13 UTC
|
||||
|
||||
I cross compiled libupnp 1.6.7 for ARM9 using the --disable-ipv6
|
||||
option, my system is an ipv4 only setup.
|
||||
|
||||
I do not know why this problem only appears when running the app in the
|
||||
background (for instance using nohup &), but then it starts using 99%
|
||||
CPU.
|
||||
|
||||
I traced the problem down to the select() call in miniserver.c in the
|
||||
RunMiniServer() function. Select returns code 1, but errno is set to
|
||||
"Socket operation on non-socket", I also see this when running my app
|
||||
under strace.
|
||||
|
||||
I set all ...Sock6 variables to INVALID_SOCKET to make sure that they
|
||||
do not get added to the FD_SET and the problem is gone.
|
||||
|
||||
2010-10-01 Fabrice Fontaine <fabrice.fontaine(at)orange-ftgroup.com>
|
||||
|
||||
Adding --disable-notification-reordering option
|
||||
|
@ -194,8 +194,7 @@ static void free_handle_request_arg(
|
||||
{
|
||||
struct mserv_request_t *request = (struct mserv_request_t *)args;
|
||||
|
||||
shutdown(request->connfd, SD_BOTH);
|
||||
UpnpCloseSocket(request->connfd);
|
||||
sock_close(request->connfd);
|
||||
free(request);
|
||||
}
|
||||
|
||||
@ -242,7 +241,7 @@ static void handle_request(
|
||||
"miniserver %d: PROCESSING...\n", connfd);
|
||||
|
||||
// dispatch
|
||||
http_error_code = dispatch_request( &info, &parser );
|
||||
http_error_code = dispatch_request(&info, &parser);
|
||||
if (http_error_code != 0) {
|
||||
goto error_handler;
|
||||
}
|
||||
@ -257,13 +256,12 @@ error_handler:
|
||||
}
|
||||
handle_error(&info, http_error_code, major, minor);
|
||||
}
|
||||
sock_destroy(&info, SD_BOTH);
|
||||
httpmsg_destroy(hmsg);
|
||||
free(request);
|
||||
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"miniserver %d: COMPLETE\n", connfd);
|
||||
sock_destroy(&info, SD_BOTH); // should shutdown completely
|
||||
|
||||
httpmsg_destroy(hmsg);
|
||||
free(request);
|
||||
}
|
||||
|
||||
|
||||
@ -283,9 +281,8 @@ static UPNP_INLINE void schedule_request_job(
|
||||
request = (struct mserv_request_t *)malloc(sizeof (struct mserv_request_t));
|
||||
if (request == NULL) {
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"mserv %d: out of memory\n", connfd );
|
||||
shutdown( connfd, SD_BOTH );
|
||||
UpnpCloseSocket( connfd );
|
||||
"mserv %d: out of memory\n", connfd);
|
||||
sock_close(connfd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -301,13 +298,83 @@ static UPNP_INLINE void schedule_request_job(
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"mserv %d: cannot schedule request\n", connfd);
|
||||
free(request);
|
||||
shutdown(connfd, SD_BOTH);
|
||||
UpnpCloseSocket(connfd);
|
||||
sock_close(connfd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void fdset_if_valid(int sock, fd_set *set)
|
||||
{
|
||||
if (sock != -1) {
|
||||
FD_SET(sock, set);
|
||||
}
|
||||
}
|
||||
|
||||
static void web_server_accept(int lsock, fd_set *set)
|
||||
{
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
int asock;
|
||||
socklen_t clientLen;
|
||||
struct sockaddr_storage clientAddr;
|
||||
char errorBuffer[ERROR_BUFFER_LEN];
|
||||
|
||||
if (lsock != -1 && FD_ISSET(lsock, set)) {
|
||||
clientLen = sizeof(clientAddr);
|
||||
asock = accept(lsock, (struct sockaddr *)&clientAddr,
|
||||
&clientLen);
|
||||
if (asock == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"miniserver: Error in accept(): %s\n",
|
||||
errorBuffer);
|
||||
} else {
|
||||
schedule_request_job(asock,
|
||||
(struct sockaddr *)&clientAddr);
|
||||
}
|
||||
}
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
}
|
||||
|
||||
static void ssdp_read(int rsock, fd_set *set)
|
||||
{
|
||||
if (rsock != -1 && FD_ISSET(rsock, set)) {
|
||||
readFromSSDPSocket(rsock);
|
||||
}
|
||||
}
|
||||
|
||||
static int receive_from_stopSock(int ssock, fd_set *set)
|
||||
{
|
||||
int byteReceived;
|
||||
socklen_t clientLen;
|
||||
struct sockaddr_storage clientAddr;
|
||||
char requestBuf[256];
|
||||
char buf_ntop[64];
|
||||
|
||||
if (FD_ISSET(ssock, set)) {
|
||||
clientLen = sizeof(clientAddr);
|
||||
memset((char *)&clientAddr, 0, sizeof(clientAddr));
|
||||
byteReceived = recvfrom(ssock, requestBuf,
|
||||
25, 0, (struct sockaddr *)&clientAddr, &clientLen);
|
||||
if (byteReceived > 0) {
|
||||
requestBuf[byteReceived] = '\0';
|
||||
inet_ntop(AF_INET,
|
||||
&((struct sockaddr_in*)&clientAddr)->sin_addr,
|
||||
buf_ntop, sizeof(buf_ntop));
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"Received response: %s From host %s \n",
|
||||
requestBuf, buf_ntop );
|
||||
UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__,
|
||||
"Received multicast packet: \n %s\n",
|
||||
requestBuf);
|
||||
if (NULL != strstr(requestBuf, "ShutDown")) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Run the miniserver.
|
||||
@ -321,199 +388,71 @@ static void RunMiniServer(
|
||||
MiniServerSockArray *miniSock)
|
||||
{
|
||||
char errorBuffer[ERROR_BUFFER_LEN];
|
||||
struct sockaddr_storage clientAddr;
|
||||
socklen_t clientLen;
|
||||
SOCKET connectHnd;
|
||||
SOCKET miniServStopSock = miniSock->miniServerStopSock;
|
||||
SOCKET ssdpSock4 = miniSock->ssdpSock4;
|
||||
SOCKET ssdpSock6 = miniSock->ssdpSock6;
|
||||
SOCKET ssdpSock6UlaGua = miniSock->ssdpSock6UlaGua;
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
SOCKET miniServSock4 = miniSock->miniServerSock4;
|
||||
SOCKET miniServSock6 = miniSock->miniServerSock6;
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
SOCKET ssdpReqSock4 = miniSock->ssdpReqSock4;
|
||||
SOCKET ssdpReqSock6 = miniSock->ssdpReqSock6;
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
char buf_ntop[64];
|
||||
fd_set expSet;
|
||||
fd_set rdSet;
|
||||
unsigned int maxMiniSock = 0;
|
||||
int byteReceived;
|
||||
char requestBuf[256];
|
||||
unsigned int maxMiniSock;
|
||||
int ret = 0;
|
||||
int stopSock = 0;
|
||||
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
if (miniServSock4 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, miniServSock4);
|
||||
}
|
||||
if (miniServSock6 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, miniServSock6);
|
||||
}
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
if (ssdpSock4 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, ssdpSock4);
|
||||
}
|
||||
if (ssdpSock6 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, ssdpSock6);
|
||||
}
|
||||
if (ssdpSock6UlaGua != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, ssdpSock6UlaGua);
|
||||
}
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
if (ssdpReqSock4 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, ssdpReqSock4);
|
||||
}
|
||||
if (ssdpReqSock6 != INVALID_SOCKET) {
|
||||
maxMiniSock = max(maxMiniSock, ssdpReqSock6);
|
||||
}
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
maxMiniSock = max(maxMiniSock, miniServStopSock);
|
||||
maxMiniSock = 0;
|
||||
maxMiniSock = max(maxMiniSock, miniSock->miniServerSock4);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->miniServerSock6);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->miniServerStopSock);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->ssdpSock4);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->ssdpSock6);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->ssdpSock6UlaGua);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->ssdpReqSock4);
|
||||
maxMiniSock = max(maxMiniSock, miniSock->ssdpReqSock6);
|
||||
++maxMiniSock;
|
||||
|
||||
gMServState = MSERV_RUNNING;
|
||||
while(TRUE) {
|
||||
while (!stopSock) {
|
||||
FD_ZERO(&rdSet);
|
||||
FD_ZERO(&expSet);
|
||||
|
||||
FD_SET(miniServStopSock, &expSet);
|
||||
FD_SET(miniServStopSock, &rdSet);
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
if(miniServSock4 != INVALID_SOCKET) {
|
||||
FD_SET(miniServSock4, &rdSet);
|
||||
}
|
||||
if(miniServSock6 != INVALID_SOCKET) {
|
||||
FD_SET(miniServSock6, &rdSet);
|
||||
}
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
if(ssdpSock4 != INVALID_SOCKET) {
|
||||
FD_SET(ssdpSock4, &rdSet);
|
||||
}
|
||||
if(ssdpSock6 != INVALID_SOCKET) {
|
||||
FD_SET(ssdpSock6, &rdSet);
|
||||
}
|
||||
if(ssdpSock6UlaGua != INVALID_SOCKET) {
|
||||
FD_SET(ssdpSock6UlaGua, &rdSet);
|
||||
}
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
if(ssdpReqSock4 != INVALID_SOCKET) {
|
||||
FD_SET(ssdpReqSock4, &rdSet);
|
||||
}
|
||||
if(ssdpReqSock6 != INVALID_SOCKET) {
|
||||
FD_SET(ssdpReqSock6, &rdSet);
|
||||
}
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
|
||||
/* FD_SET()'s */
|
||||
FD_SET(miniSock->miniServerStopSock, &expSet);
|
||||
FD_SET(miniSock->miniServerStopSock, &rdSet);
|
||||
fdset_if_valid(miniSock->miniServerSock4, &rdSet);
|
||||
fdset_if_valid(miniSock->miniServerSock6, &rdSet);
|
||||
fdset_if_valid(miniSock->ssdpSock4, &rdSet);
|
||||
fdset_if_valid(miniSock->ssdpSock6, &rdSet);
|
||||
fdset_if_valid(miniSock->ssdpSock6UlaGua, &rdSet);
|
||||
fdset_if_valid(miniSock->ssdpReqSock4, &rdSet);
|
||||
fdset_if_valid(miniSock->ssdpReqSock6, &rdSet);
|
||||
/* select() */
|
||||
ret = select(maxMiniSock, &rdSet, NULL, &expSet, NULL);
|
||||
if (ret == -1 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
if (ret == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
||||
"Error in select(): %s\n", errorBuffer);
|
||||
/* Avoid 100% CPU in case of repeated error in select() */
|
||||
isleep(1);
|
||||
continue;
|
||||
} else {
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
if (miniServSock6 != INVALID_SOCKET &&
|
||||
FD_ISSET(miniServSock6, &rdSet)) {
|
||||
clientLen = sizeof( clientAddr );
|
||||
connectHnd = accept(miniServSock6,
|
||||
(struct sockaddr *)&clientAddr, &clientLen);
|
||||
if (connectHnd == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"miniserver: Error in accept(): %s\n",
|
||||
errorBuffer);
|
||||
continue;
|
||||
}
|
||||
schedule_request_job(
|
||||
connectHnd, (struct sockaddr *)&clientAddr);
|
||||
}
|
||||
if (miniServSock4 != INVALID_SOCKET &&
|
||||
FD_ISSET(miniServSock4, &rdSet)) {
|
||||
clientLen = sizeof(clientAddr);
|
||||
connectHnd = accept(miniServSock4,
|
||||
(struct sockaddr *)&clientAddr, &clientLen);
|
||||
if (connectHnd == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"miniserver: Error in accept(): %s\n",
|
||||
errorBuffer);
|
||||
continue;
|
||||
}
|
||||
schedule_request_job(
|
||||
connectHnd, (struct sockaddr *)&clientAddr);
|
||||
}
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
web_server_accept(miniSock->miniServerSock4, &rdSet);
|
||||
web_server_accept(miniSock->miniServerSock6, &rdSet);
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
// ssdp
|
||||
if (ssdpReqSock6 != INVALID_SOCKET &&
|
||||
FD_ISSET(ssdpReqSock6, &rdSet)) {
|
||||
readFromSSDPSocket(ssdpReqSock6);
|
||||
}
|
||||
if (ssdpReqSock4 != INVALID_SOCKET &&
|
||||
FD_ISSET( ssdpReqSock4, &rdSet)) {
|
||||
readFromSSDPSocket(ssdpReqSock4);
|
||||
}
|
||||
ssdp_read(miniSock->ssdpReqSock4, &rdSet);
|
||||
ssdp_read(miniSock->ssdpReqSock6, &rdSet);
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
if (ssdpSock6 != INVALID_SOCKET &&
|
||||
FD_ISSET(ssdpSock6, &rdSet)) {
|
||||
readFromSSDPSocket(ssdpSock6);
|
||||
}
|
||||
if (ssdpSock6UlaGua != INVALID_SOCKET &&
|
||||
FD_ISSET(ssdpSock6UlaGua, &rdSet)) {
|
||||
readFromSSDPSocket(ssdpSock6UlaGua);
|
||||
}
|
||||
if (ssdpSock4 != INVALID_SOCKET &&
|
||||
FD_ISSET(ssdpSock4, &rdSet)) {
|
||||
readFromSSDPSocket(ssdpSock4);
|
||||
}
|
||||
if (FD_ISSET( miniServStopSock, &rdSet)) {
|
||||
clientLen = sizeof(clientAddr);
|
||||
memset((char *)&clientAddr, 0, sizeof(clientAddr));
|
||||
byteReceived = recvfrom(miniServStopSock, requestBuf,
|
||||
25, 0, (struct sockaddr *)&clientAddr, &clientLen);
|
||||
if (byteReceived > 0) {
|
||||
requestBuf[byteReceived] = '\0';
|
||||
inet_ntop(AF_INET,
|
||||
&((struct sockaddr_in*)&clientAddr)->sin_addr,
|
||||
buf_ntop, sizeof(buf_ntop));
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"Received response: %s From host %s \n",
|
||||
requestBuf, buf_ntop );
|
||||
UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__,
|
||||
"Received multicast packet: \n %s\n",
|
||||
requestBuf);
|
||||
if (NULL != strstr(requestBuf, "ShutDown")) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ssdp_read(miniSock->ssdpSock4, &rdSet);
|
||||
ssdp_read(miniSock->ssdpSock6, &rdSet);
|
||||
ssdp_read(miniSock->ssdpSock6UlaGua, &rdSet);
|
||||
stopSock = receive_from_stopSock(
|
||||
miniSock->miniServerStopSock, &rdSet);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
shutdown(miniServSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniServSock4);
|
||||
shutdown(miniServSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniServSock6);
|
||||
#endif /* INTERNAL_WEB_SERVER */
|
||||
shutdown(miniServStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniServStopSock);
|
||||
shutdown(ssdpSock4, SD_BOTH);
|
||||
UpnpCloseSocket(ssdpSock4);
|
||||
shutdown(ssdpSock6, SD_BOTH);
|
||||
UpnpCloseSocket(ssdpSock6);
|
||||
shutdown(ssdpSock6UlaGua, SD_BOTH);
|
||||
UpnpCloseSocket(ssdpSock6UlaGua);
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
shutdown(ssdpReqSock4, SD_BOTH);
|
||||
UpnpCloseSocket(ssdpReqSock4);
|
||||
shutdown(ssdpReqSock6, SD_BOTH);
|
||||
UpnpCloseSocket(ssdpReqSock6);
|
||||
#endif /* INCLUDE_CLIENT_APIS */
|
||||
|
||||
/* Close all sockets. */
|
||||
sock_close(miniSock->miniServerSock4);
|
||||
sock_close(miniSock->miniServerSock6);
|
||||
sock_close(miniSock->miniServerStopSock);
|
||||
sock_close(miniSock->ssdpSock4);
|
||||
sock_close(miniSock->ssdpSock6);
|
||||
sock_close(miniSock->ssdpSock6UlaGua);
|
||||
sock_close(miniSock->ssdpReqSock4);
|
||||
sock_close(miniSock->ssdpReqSock6);
|
||||
/* Free minisock. */
|
||||
free(miniSock);
|
||||
gMServState = MSERV_IDLE;
|
||||
|
||||
@ -580,12 +519,12 @@ static int get_miniserver_sockets(
|
||||
char errorBuffer[ERROR_BUFFER_LEN];
|
||||
struct sockaddr_storage __ss_v4;
|
||||
struct sockaddr_in* serverAddr4 = (struct sockaddr_in*)&__ss_v4;
|
||||
SOCKET listenfd4 = INVALID_SOCKET;
|
||||
SOCKET listenfd4;
|
||||
unsigned short actual_port4;
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
struct sockaddr_storage __ss_v6;
|
||||
struct sockaddr_in6* serverAddr6 = (struct sockaddr_in6*)&__ss_v6;
|
||||
SOCKET listenfd6 = INVALID_SOCKET;
|
||||
SOCKET listenfd6;
|
||||
unsigned short actual_port6;
|
||||
#endif
|
||||
int ret_code;
|
||||
@ -593,22 +532,16 @@ static int get_miniserver_sockets(
|
||||
int sockError = UPNP_E_SUCCESS;
|
||||
int errCode = 0;
|
||||
|
||||
//
|
||||
// Initialize all the sockets to be invalid
|
||||
//
|
||||
out->miniServerSock4 = INVALID_SOCKET;
|
||||
out->miniServerSock6 = INVALID_SOCKET;
|
||||
|
||||
// Create listen socket for IPv4/IPv6. An error here may indicate
|
||||
// that we don't have an IPv4/IPv6 stack.
|
||||
listenfd4 = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listenfd4 == INVALID_SOCKET) {
|
||||
if (listenfd4 == -1) {
|
||||
return UPNP_E_OUTOF_SOCKET;
|
||||
}
|
||||
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
listenfd6 = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (listenfd6 == INVALID_SOCKET) {
|
||||
if (listenfd6 == -1) {
|
||||
return UPNP_E_OUTOF_SOCKET;
|
||||
}
|
||||
#endif
|
||||
@ -645,31 +578,28 @@ static int get_miniserver_sockets(
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: resuseaddr set\n");
|
||||
|
||||
if (listenfd4 != INVALID_SOCKET) {
|
||||
if (listenfd4 != -1) {
|
||||
sockError = setsockopt(listenfd4, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&reuseaddr_on, sizeof (int));
|
||||
if (sockError == -1) {
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
sock_close(listenfd4);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd6);
|
||||
#endif
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
|
||||
serverAddr4->sin_port = htons(listen_port4);
|
||||
sockError = bind(listenfd4, (struct sockaddr *)&__ss_v4, sizeof (__ss_v4));
|
||||
sockError = bind(listenfd4, (struct sockaddr *)&__ss_v4,
|
||||
sizeof (__ss_v4));
|
||||
if (sockError == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: Error in IPv4 bind(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
sock_close(listenfd4);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd6);
|
||||
#endif
|
||||
/* Bind failed */
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
@ -677,35 +607,32 @@ static int get_miniserver_sockets(
|
||||
}
|
||||
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
if (listenfd6 != INVALID_SOCKET) {
|
||||
if (listenfd6 != -1) {
|
||||
sockError = setsockopt(listenfd6, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char *)&reuseaddr_on, sizeof (int));
|
||||
if (sockError == -1) {
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd4);
|
||||
sock_close(listenfd6);
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
|
||||
serverAddr6->sin6_port = htons(listen_port6);
|
||||
sockError = bind(listenfd6, (struct sockaddr *)&__ss_v6, sizeof (__ss_v6));
|
||||
sockError = bind(listenfd6, (struct sockaddr *)&__ss_v6,
|
||||
sizeof (__ss_v6));
|
||||
if (sockError == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: Error in IPv6 bind(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd4);
|
||||
sock_close(listenfd6);
|
||||
/* Bind failed */
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
}
|
||||
#endif //IPv6
|
||||
} else {
|
||||
if (listenfd4 != INVALID_SOCKET) {
|
||||
if (listenfd4 != -1) {
|
||||
unsigned short orig_listen_port4 = listen_port4;
|
||||
do {
|
||||
serverAddr4->sin_port = htons(listen_port4++);
|
||||
@ -729,22 +656,21 @@ static int get_miniserver_sockets(
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: Error in IPv4 bind(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
sock_close(listenfd4);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd6);
|
||||
#endif
|
||||
return UPNP_E_SOCKET_BIND; // bind failed
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
if (listenfd6 != INVALID_SOCKET) {
|
||||
if (listenfd6 != -1) {
|
||||
unsigned short orig_listen_port6 = listen_port6;
|
||||
do {
|
||||
serverAddr6->sin6_port = htons(listen_port6++);
|
||||
sockError = bind(listenfd6, (struct sockaddr *)serverAddr6, sizeof(*serverAddr6));
|
||||
sockError = bind(listenfd6, (struct sockaddr *)serverAddr6,
|
||||
sizeof(*serverAddr6));
|
||||
if (sockError == -1) {
|
||||
#ifdef WIN32
|
||||
errCode = WSAGetLastError();
|
||||
@ -764,10 +690,8 @@ static int get_miniserver_sockets(
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: Error in IPv6 bind(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd4);
|
||||
sock_close(listenfd6);
|
||||
/* Bind failied */
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
@ -778,60 +702,47 @@ static int get_miniserver_sockets(
|
||||
UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"get_miniserver_sockets: bind successful\n" );
|
||||
|
||||
if (listenfd4 != INVALID_SOCKET) {
|
||||
if (listenfd4 != -1) {
|
||||
ret_code = listen(listenfd4, SOMAXCONN);
|
||||
if (ret_code == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"mserv start: Error in IPv4 listen(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
sock_close(listenfd4);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd6);
|
||||
#endif
|
||||
return UPNP_E_LISTEN;
|
||||
}
|
||||
|
||||
actual_port4 = get_port(listenfd4);
|
||||
if (actual_port4 <= 0) {
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
sock_close(listenfd4);
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd6);
|
||||
#endif
|
||||
return UPNP_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
out->miniServerPort4 = actual_port4;
|
||||
}
|
||||
|
||||
#ifdef UPNP_ENABLE_IPV6
|
||||
if (listenfd6 != INVALID_SOCKET) {
|
||||
if (listenfd6 != -1) {
|
||||
ret_code = listen(listenfd6, SOMAXCONN);
|
||||
if (ret_code == -1) {
|
||||
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
|
||||
UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
|
||||
"mserv start: Error in IPv6 listen(): %s\n",
|
||||
errorBuffer);
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd4);
|
||||
sock_close(listenfd6);
|
||||
return UPNP_E_LISTEN;
|
||||
}
|
||||
|
||||
actual_port6 = get_port(listenfd6);
|
||||
if (actual_port6 <= 0) {
|
||||
shutdown(listenfd4, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd4);
|
||||
shutdown(listenfd6, SD_BOTH);
|
||||
UpnpCloseSocket(listenfd6);
|
||||
sock_close(listenfd4);
|
||||
sock_close(listenfd6);
|
||||
return UPNP_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
out->miniServerPort6 = actual_port6;
|
||||
}
|
||||
#endif
|
||||
@ -881,15 +792,13 @@ static int get_miniserver_stopsock(
|
||||
UpnpPrintf(UPNP_CRITICAL,
|
||||
MSERV, __FILE__, __LINE__,
|
||||
"Error in binding localhost!!!\n");
|
||||
shutdown(miniServerStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniServerStopSock);
|
||||
sock_close(miniServerStopSock);
|
||||
return UPNP_E_SOCKET_BIND;
|
||||
}
|
||||
|
||||
miniStopSockPort = get_port( miniServerStopSock );
|
||||
if (miniStopSockPort <= 0) {
|
||||
shutdown(miniServerStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniServerStopSock);
|
||||
sock_close(miniServerStopSock);
|
||||
return UPNP_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
@ -899,6 +808,20 @@ static int get_miniserver_stopsock(
|
||||
return UPNP_E_SUCCESS;
|
||||
}
|
||||
|
||||
static inline void InitMiniServerSockArray(MiniServerSockArray *miniSocket)
|
||||
{
|
||||
miniSocket->miniServerSock4 = -1;
|
||||
miniSocket->miniServerSock6 = -1;
|
||||
miniSocket->miniServerStopSock = -1;
|
||||
miniSocket->ssdpSock4 = -1;
|
||||
miniSocket->ssdpSock6 = -1;
|
||||
miniSocket->ssdpSock6UlaGua = -1;
|
||||
miniSocket->stopPort = -1;
|
||||
miniSocket->miniServerPort4 = -1;
|
||||
miniSocket->miniServerPort6 = -1;
|
||||
miniSocket->ssdpReqSock4 = -1;
|
||||
miniSocket->ssdpReqSock6 = -1;
|
||||
}
|
||||
|
||||
int StartMiniServer(
|
||||
/*! [in,out] Port on which the server listens for incoming IPv4 connections. */
|
||||
@ -914,17 +837,18 @@ int StartMiniServer(
|
||||
ThreadPoolJob job;
|
||||
|
||||
if (gMServState != MSERV_IDLE) {
|
||||
return UPNP_E_INTERNAL_ERROR; // miniserver running
|
||||
/* miniserver running. */
|
||||
return UPNP_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
miniSocket = (MiniServerSockArray *)malloc(sizeof (MiniServerSockArray));
|
||||
if (miniSocket == NULL) {
|
||||
if (!miniSocket) {
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
}
|
||||
memset(miniSocket, 0, sizeof (*miniSocket));
|
||||
InitMiniServerSockArray(miniSocket);
|
||||
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
// V4 and V6 http listeners.
|
||||
/* V4 and V6 http listeners. */
|
||||
ret_code = get_miniserver_sockets(miniSocket, *listen_port4, *listen_port6);
|
||||
if (ret_code != UPNP_E_SUCCESS) {
|
||||
free(miniSocket);
|
||||
@ -932,30 +856,21 @@ int StartMiniServer(
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stop socket (To end miniserver processing).
|
||||
/* Stop socket (To end miniserver processing). */
|
||||
ret_code = get_miniserver_stopsock(miniSocket);
|
||||
if (ret_code != UPNP_E_SUCCESS) {
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
shutdown(miniSocket->miniServerSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock4);
|
||||
shutdown(miniSocket->miniServerSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock6);
|
||||
#endif
|
||||
sock_close(miniSocket->miniServerSock4);
|
||||
sock_close(miniSocket->miniServerSock6);
|
||||
free(miniSocket);
|
||||
return ret_code;
|
||||
}
|
||||
|
||||
// SSDP socket for discovery / advertising.
|
||||
/* SSDP socket for discovery/advertising. */
|
||||
ret_code = get_ssdp_sockets(miniSocket);
|
||||
if (ret_code != UPNP_E_SUCCESS) {
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
shutdown(miniSocket->miniServerSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock4);
|
||||
shutdown(miniSocket->miniServerSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock6);
|
||||
#endif
|
||||
shutdown(miniSocket->miniServerStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerStopSock);
|
||||
sock_close(miniSocket->miniServerSock4);
|
||||
sock_close(miniSocket->miniServerSock6);
|
||||
sock_close(miniSocket->miniServerStopSock);
|
||||
free(miniSocket);
|
||||
return ret_code;
|
||||
}
|
||||
@ -965,26 +880,14 @@ int StartMiniServer(
|
||||
TPJobSetFreeFunction(&job, (free_routine)free);
|
||||
ret_code = ThreadPoolAddPersistent(&gMiniServerThreadPool, &job, NULL);
|
||||
if (ret_code < 0) {
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
shutdown(miniSocket->miniServerSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock4);
|
||||
shutdown(miniSocket->miniServerSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock6);
|
||||
#endif
|
||||
shutdown(miniSocket->miniServerStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerStopSock);
|
||||
shutdown(miniSocket->ssdpSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock4);
|
||||
shutdown(miniSocket->ssdpSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock6);
|
||||
shutdown(miniSocket->ssdpSock6UlaGua, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock6UlaGua);
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
shutdown(miniSocket->ssdpReqSock4, SD_BOTH );
|
||||
UpnpCloseSocket(miniSocket->ssdpReqSock4 );
|
||||
shutdown(miniSocket->ssdpReqSock6, SD_BOTH );
|
||||
UpnpCloseSocket(miniSocket->ssdpReqSock6 );
|
||||
#endif
|
||||
sock_close(miniSocket->miniServerSock4);
|
||||
sock_close(miniSocket->miniServerSock6);
|
||||
sock_close(miniSocket->miniServerStopSock);
|
||||
sock_close(miniSocket->ssdpSock4);
|
||||
sock_close(miniSocket->ssdpSock6);
|
||||
sock_close(miniSocket->ssdpSock6UlaGua);
|
||||
sock_close(miniSocket->ssdpReqSock4);
|
||||
sock_close(miniSocket->ssdpReqSock6);
|
||||
return UPNP_E_OUTOF_MEMORY;
|
||||
}
|
||||
// wait for miniserver to start
|
||||
@ -996,26 +899,14 @@ int StartMiniServer(
|
||||
|
||||
// taking too long to start that thread
|
||||
if (count >= max_count) {
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
shutdown(miniSocket->miniServerSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock4);
|
||||
shutdown(miniSocket->miniServerSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerSock6);
|
||||
#endif
|
||||
shutdown(miniSocket->miniServerStopSock, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->miniServerStopSock);
|
||||
shutdown(miniSocket->ssdpSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock4);
|
||||
shutdown(miniSocket->ssdpSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock6);
|
||||
shutdown(miniSocket->ssdpSock6UlaGua, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpSock6UlaGua);
|
||||
#ifdef INCLUDE_CLIENT_APIS
|
||||
shutdown(miniSocket->ssdpReqSock4, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpReqSock4);
|
||||
shutdown(miniSocket->ssdpReqSock6, SD_BOTH);
|
||||
UpnpCloseSocket(miniSocket->ssdpReqSock6);
|
||||
#endif
|
||||
sock_close(miniSocket->miniServerSock4);
|
||||
sock_close(miniSocket->miniServerSock6);
|
||||
sock_close(miniSocket->miniServerStopSock);
|
||||
sock_close(miniSocket->ssdpSock4);
|
||||
sock_close(miniSocket->ssdpSock6);
|
||||
sock_close(miniSocket->ssdpSock6UlaGua);
|
||||
sock_close(miniSocket->ssdpReqSock4);
|
||||
sock_close(miniSocket->ssdpReqSock6);
|
||||
return UPNP_E_INTERNAL_ERROR;
|
||||
}
|
||||
#ifdef INTERNAL_WEB_SERVER
|
||||
@ -1063,8 +954,7 @@ int StopMiniServer()
|
||||
}
|
||||
isleep(1);
|
||||
}
|
||||
shutdown(sock, SD_BOTH);
|
||||
UpnpCloseSocket(sock);
|
||||
sock_close(sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user