Commit | Line | Data |
---|---|---|
1a93e64a VK |
1 | /* |
2 | ** NetXMS client proxy | |
3 | ** Copyright (C) 2003-2013 Victor Kirhenshtein | |
4 | ** | |
5 | ** This program is free software; you can redistribute it and/or modify | |
6 | ** it under the terms of the GNU General Public License as published by | |
7 | ** the Free Software Foundation; either version 2 of the License, or | |
8 | ** (at your option) any later version. | |
9 | ** | |
10 | ** This program is distributed in the hope that it will be useful, | |
11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | ** GNU General Public License for more details. | |
14 | ** | |
15 | ** You should have received a copy of the GNU General Public License | |
16 | ** along with this program; if not, write to the Free Software | |
17 | ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
18 | ** | |
19 | ** File: listener.cpp | |
20 | ** | |
21 | **/ | |
22 | ||
23 | #include "nxcproxy.h" | |
24 | ||
25 | /** | |
26 | * Listener thread | |
27 | */ | |
28 | THREAD_RESULT THREAD_CALL ListenerThread(void *) | |
29 | { | |
30 | SOCKET hSocket, hClientSocket; | |
31 | struct sockaddr_in servAddr; | |
32 | int iNumErrors = 0, nRet; | |
33 | socklen_t iSize; | |
34 | TCHAR szBuffer[256]; | |
35 | struct timeval tv; | |
36 | fd_set rdfs; | |
37 | ||
38 | // Create socket | |
39 | if ((hSocket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) | |
40 | { | |
41 | nxlog_write(MSG_SOCKET_ERROR, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError()); | |
42 | exit(1); | |
43 | } | |
44 | ||
45 | SetSocketExclusiveAddrUse(hSocket); | |
46 | SetSocketReuseFlag(hSocket); | |
47 | ||
48 | // Fill in local address structure | |
49 | memset(&servAddr, 0, sizeof(struct sockaddr_in)); | |
50 | servAddr.sin_family = AF_INET; | |
51 | if (!_tcscmp(g_listenAddress, _T("*"))) | |
52 | { | |
53 | servAddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
54 | } | |
55 | else | |
56 | { | |
688b5dc2 | 57 | servAddr.sin_addr.s_addr = InetAddress::resolveHostName(g_listenAddress, AF_INET).getAddressV4(); |
1a93e64a VK |
58 | if (servAddr.sin_addr.s_addr == htonl(INADDR_NONE)) |
59 | servAddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
60 | } | |
61 | servAddr.sin_port = htons(g_listenPort); | |
62 | ||
63 | // Bind socket | |
64 | DebugPrintf(1, _T("Trying to bind on %s:%d"), IpToStr(ntohl(servAddr.sin_addr.s_addr), szBuffer), ntohs(servAddr.sin_port)); | |
65 | if (bind(hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0) | |
66 | { | |
67 | nxlog_write(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "e", WSAGetLastError()); | |
68 | exit(1); | |
69 | } | |
70 | ||
71 | // Set up queue | |
72 | listen(hSocket, SOMAXCONN); | |
73 | nxlog_write(MSG_LISTENING, EVENTLOG_INFORMATION_TYPE, "ad", ntohl(servAddr.sin_addr.s_addr), g_listenPort); | |
74 | ||
75 | // Wait for connection requests | |
76 | while(!(g_flags & AF_SHUTDOWN)) | |
77 | { | |
78 | tv.tv_sec = 1; | |
79 | tv.tv_usec = 0; | |
80 | FD_ZERO(&rdfs); | |
81 | FD_SET(hSocket, &rdfs); | |
82 | nRet = select(SELECT_NFDS(hSocket + 1), &rdfs, NULL, NULL, &tv); | |
83 | if ((nRet > 0) && (!(g_flags & AF_SHUTDOWN))) | |
84 | { | |
85 | iSize = sizeof(struct sockaddr_in); | |
86 | if ((hClientSocket = accept(hSocket, (struct sockaddr *)&servAddr, &iSize)) == -1) | |
87 | { | |
88 | int error = WSAGetLastError(); | |
89 | ||
90 | if (error != WSAEINTR) | |
91 | nxlog_write(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error); | |
92 | iNumErrors++; | |
93 | if (iNumErrors > 1000) | |
94 | { | |
95 | nxlog_write(MSG_TOO_MANY_ERRORS, EVENTLOG_WARNING_TYPE, NULL); | |
96 | iNumErrors = 0; | |
97 | } | |
98 | ThreadSleepMs(500); | |
99 | continue; | |
100 | } | |
101 | ||
102 | iNumErrors = 0; // Reset consecutive errors counter | |
103 | DebugPrintf(5, _T("Incoming connection from %s"), IpToStr(ntohl(servAddr.sin_addr.s_addr), szBuffer)); | |
104 | ||
105 | SetSocketNonBlocking(hClientSocket); | |
106 | ||
107 | ProxySession *session = new ProxySession(hClientSocket); | |
108 | session->run(); | |
109 | } | |
110 | else if (nRet == -1) | |
111 | { | |
112 | int error = WSAGetLastError(); | |
113 | ||
114 | // On AIX, select() returns ENOENT after SIGINT for unknown reason | |
115 | #ifdef _WIN32 | |
116 | if (error != WSAEINTR) | |
117 | #else | |
118 | if ((error != EINTR) && (error != ENOENT)) | |
119 | #endif | |
120 | { | |
121 | nxlog_write(MSG_SELECT_ERROR, EVENTLOG_ERROR_TYPE, "e", error); | |
122 | ThreadSleepMs(100); | |
123 | } | |
124 | } | |
125 | } | |
126 | ||
127 | closesocket(hSocket); | |
128 | DebugPrintf(1, _T("Listener thread terminated")); | |
129 | return THREAD_OK; | |
130 | } |