474ba94a0576108306639228d17e3bef349c5ce8
[public/netxms.git] / src / server / core / mdconn.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2016 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: mdconn.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24
25 /**
26 * Static data
27 */
28 static MobileDeviceSession *m_pSessionList[MAX_DEVICE_SESSIONS];
29 static RWLOCK m_rwlockSessionListAccess;
30
31 /**
32 * Register new session in list
33 */
34 static BOOL RegisterMobileDeviceSession(MobileDeviceSession *pSession)
35 {
36 UINT32 i;
37
38 RWLockWriteLock(m_rwlockSessionListAccess, INFINITE);
39 for(i = 0; i < MAX_DEVICE_SESSIONS; i++)
40 if (m_pSessionList[i] == NULL)
41 {
42 m_pSessionList[i] = pSession;
43 pSession->setId(i + MAX_CLIENT_SESSIONS);
44 RWLockUnlock(m_rwlockSessionListAccess);
45 return TRUE;
46 }
47
48 RWLockUnlock(m_rwlockSessionListAccess);
49 nxlog_write(MSG_TOO_MANY_MD_SESSIONS, EVENTLOG_WARNING_TYPE, NULL);
50 return FALSE;
51 }
52
53 /**
54 * Unregister session
55 */
56 void UnregisterMobileDeviceSession(int id)
57 {
58 RWLockWriteLock(m_rwlockSessionListAccess, INFINITE);
59 m_pSessionList[id - MAX_CLIENT_SESSIONS] = NULL;
60 RWLockUnlock(m_rwlockSessionListAccess);
61 }
62
63 /**
64 * Initialize mobile device listener(s)
65 */
66 void InitMobileDeviceListeners()
67 {
68 // Create session list access rwlock
69 m_rwlockSessionListAccess = RWLockCreate();
70 }
71
72 /**
73 * Listener thread
74 */
75 THREAD_RESULT THREAD_CALL MobileDeviceListener(void *arg)
76 {
77 SOCKET sock, sockClient;
78 struct sockaddr_in servAddr;
79 int errorCount = 0;
80 socklen_t iSize;
81 WORD wListenPort;
82 MobileDeviceSession *pSession;
83
84 // Read configuration
85 wListenPort = (WORD)ConfigReadInt(_T("MobileDeviceListenerPort"), SERVER_LISTEN_PORT_FOR_MOBILES);
86
87 // Create socket
88 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
89 {
90 nxlog_write(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", _T("MobileDeviceListener"));
91 return THREAD_OK;
92 }
93
94 SetSocketExclusiveAddrUse(sock);
95 SetSocketReuseFlag(sock);
96 #ifndef _WIN32
97 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
98 #endif
99
100 // Fill in local address structure
101 memset(&servAddr, 0, sizeof(struct sockaddr_in));
102 servAddr.sin_family = AF_INET;
103 servAddr.sin_addr.s_addr = !_tcscmp(g_szListenAddress, _T("*")) ? 0 : htonl(InetAddress::resolveHostName(g_szListenAddress, AF_INET).getAddressV4());
104 servAddr.sin_port = htons(wListenPort);
105
106 // Bind socket
107 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
108 {
109 nxlog_write(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", wListenPort, _T("MobileDeviceListener"), WSAGetLastError());
110 closesocket(sock);
111 /* TODO: we should initiate shutdown procedure here */
112 return THREAD_OK;
113 }
114
115 // Set up queue
116 listen(sock, SOMAXCONN);
117 nxlog_write(MSG_LISTENING_FOR_MOBILE_DEVICES, EVENTLOG_INFORMATION_TYPE, "ad", ntohl(servAddr.sin_addr.s_addr), wListenPort);
118
119 // Wait for connection requests
120 while(!IsShutdownInProgress())
121 {
122 iSize = sizeof(struct sockaddr_in);
123 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
124 {
125 int error;
126
127 #ifdef _WIN32
128 error = WSAGetLastError();
129 if (error != WSAEINTR)
130 #else
131 error = errno;
132 if (error != EINTR)
133 #endif
134 nxlog_write(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
135 errorCount++;
136 if (errorCount > 1000)
137 {
138 nxlog_write(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
139 errorCount = 0;
140 }
141 ThreadSleepMs(500);
142 continue;
143 }
144
145 errorCount = 0; // Reset consecutive errors counter
146 SetSocketNonBlocking(sockClient);
147
148 // Create new session structure and threads
149 pSession = new MobileDeviceSession(sockClient, (struct sockaddr *)&servAddr);
150 if (!RegisterMobileDeviceSession(pSession))
151 {
152 delete pSession;
153 }
154 else
155 {
156 pSession->run();
157 }
158 }
159
160 closesocket(sock);
161 return THREAD_OK;
162 }
163
164 /**
165 * Listener thread - IPv6
166 */
167 #ifdef WITH_IPV6
168
169 THREAD_RESULT THREAD_CALL MobileDeviceListenerIPv6(void *arg)
170 {
171 SOCKET sock, sockClient;
172 struct sockaddr_in6 servAddr;
173 int errorCount = 0;
174 socklen_t iSize;
175 WORD wListenPort;
176 MobileDeviceSession *pSession;
177
178 // Read configuration
179 wListenPort = (WORD)ConfigReadInt(_T("MobileDeviceListenerPort"), SERVER_LISTEN_PORT_FOR_MOBILES);
180
181 // Create socket
182 if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) == INVALID_SOCKET)
183 {
184 nxlog_write(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", _T("MobileDeviceListenerIPv6"));
185 return THREAD_OK;
186 }
187
188 SetSocketExclusiveAddrUse(sock);
189 SetSocketReuseFlag(sock);
190 #ifdef IPV6_V6ONLY
191 int on = 1;
192 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(int));
193 #endif
194 #ifndef _WIN32
195 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
196 #endif
197
198 // Fill in local address structure
199 memset(&servAddr, 0, sizeof(struct sockaddr_in6));
200 servAddr.sin6_family = AF_INET6;
201 if (_tcscmp(g_szListenAddress, _T("*")))
202 memcpy(servAddr.sin6_addr.s6_addr, InetAddress::resolveHostName(g_szListenAddress, AF_INET6).getAddressV6(), 16);
203 servAddr.sin6_port = htons(wListenPort);
204
205 // Bind socket
206 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in6)) != 0)
207 {
208 nxlog_write(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", wListenPort, _T("MobileDeviceListenerIPv6"), WSAGetLastError());
209 closesocket(sock);
210 /* TODO: we should initiate shutdown procedure here */
211 return THREAD_OK;
212 }
213
214 // Set up queue
215 listen(sock, SOMAXCONN);
216 nxlog_write(MSG_LISTENING_FOR_MOBILE_DEVICES, EVENTLOG_INFORMATION_TYPE, "Hd", servAddr.sin6_addr.s6_addr, wListenPort);
217
218 // Wait for connection requests
219 while(!IsShutdownInProgress())
220 {
221 iSize = sizeof(struct sockaddr_in6);
222 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
223 {
224 int error;
225
226 #ifdef _WIN32
227 error = WSAGetLastError();
228 if (error != WSAEINTR)
229 #else
230 error = errno;
231 if (error != EINTR)
232 #endif
233 nxlog_write(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
234 errorCount++;
235 if (errorCount > 1000)
236 {
237 nxlog_write(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
238 errorCount = 0;
239 }
240 ThreadSleepMs(500);
241 continue;
242 }
243
244 errorCount = 0; // Reset consecutive errors counter
245 SetSocketNonBlocking(sockClient);
246
247 // Create new session structure and threads
248 pSession = new MobileDeviceSession(sockClient, (struct sockaddr *)&servAddr);
249 if (!RegisterMobileDeviceSession(pSession))
250 {
251 delete pSession;
252 }
253 else
254 {
255 pSession->run();
256 }
257 }
258
259 closesocket(sock);
260 return THREAD_OK;
261 }
262
263 #endif
264
265 /**
266 * Dump client sessions to screen
267 */
268 void DumpMobileDeviceSessions(CONSOLE_CTX pCtx)
269 {
270 int i, iCount;
271 TCHAR szBuffer[256];
272 static const TCHAR *pszStateName[] = { _T("init"), _T("idle"), _T("processing") };
273 static const TCHAR *pszCipherName[] = { _T("NONE"), _T("AES-256"), _T("BLOWFISH"), _T("IDEA"), _T("3DES"), _T("AES-128") };
274
275 ConsolePrintf(pCtx, _T("ID STATE CIPHER USER [CLIENT]\n"));
276 RWLockReadLock(m_rwlockSessionListAccess, INFINITE);
277 for(i = 0, iCount = 0; i < MAX_DEVICE_SESSIONS; i++)
278 if (m_pSessionList[i] != NULL)
279 {
280 ConsolePrintf(pCtx, _T("%-3d %-24s %-8s %s [%s]\n"), i,
281 (m_pSessionList[i]->getState() != SESSION_STATE_PROCESSING) ?
282 pszStateName[m_pSessionList[i]->getState()] :
283 NXCPMessageCodeName(m_pSessionList[i]->getCurrentCmd(), szBuffer),
284 pszCipherName[m_pSessionList[i]->getCipher() + 1],
285 m_pSessionList[i]->getUserName(),
286 m_pSessionList[i]->getClientInfo());
287 iCount++;
288 }
289 RWLockUnlock(m_rwlockSessionListAccess);
290 ConsolePrintf(pCtx, _T("\n%d active session%s\n\n"), iCount, iCount == 1 ? _T("") : _T("s"));
291 }