+ sockets reuse (*nix only)
[public/netxms.git] / src / server / core / client.cpp
CommitLineData
5d0ff6bd 1/*
da54bd8d 2** NetXMS - Network Management System
5d0ff6bd
VK
3** Copyright (C) 2003 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** $module: client.cpp
20**
21**/
22
a551fe4d 23#include "nxcore.h"
5d0ff6bd 24
da54bd8d
VK
25
26//
27// Constants
28//
29
30#define MAX_CLIENT_SESSIONS 128
31
32
33//
34// Static data
35//
36
37static ClientSession *m_pSessionList[MAX_CLIENT_SESSIONS];
62f5857f 38static MUTEX m_hSessionListAccess;
4a4afbd0 39
5d0ff6bd
VK
40
41//
ecb7e1ee 42// Register new session in list
5af4c41b
VK
43//
44
ecb7e1ee 45static BOOL RegisterSession(ClientSession *pSession)
5af4c41b 46{
ecb7e1ee
VK
47 DWORD i;
48
62f5857f 49 MutexLock(m_hSessionListAccess, INFINITE);
ecb7e1ee
VK
50 for(i = 0; i < MAX_CLIENT_SESSIONS; i++)
51 if (m_pSessionList[i] == NULL)
52 {
53 m_pSessionList[i] = pSession;
54 pSession->SetIndex(i);
62f5857f 55 MutexUnlock(m_hSessionListAccess);
ecb7e1ee
VK
56 return TRUE;
57 }
58
62f5857f 59 MutexUnlock(m_hSessionListAccess);
ecb7e1ee
VK
60 WriteLog(MSG_TOO_MANY_SESSIONS, EVENTLOG_WARNING_TYPE, NULL);
61 return FALSE;
5af4c41b
VK
62}
63
64
65//
ecb7e1ee 66// Unregister session
5af4c41b
VK
67//
68
ccdbbb52 69void UnregisterSession(DWORD dwIndex)
5af4c41b 70{
62f5857f 71 MutexLock(m_hSessionListAccess, INFINITE);
ecb7e1ee 72 m_pSessionList[dwIndex] = NULL;
62f5857f 73 MutexUnlock(m_hSessionListAccess);
5d0ff6bd
VK
74}
75
76
77//
78// Listener thread
79//
80
ccdbbb52 81THREAD_RESULT THREAD_CALL ClientListener(void *)
5d0ff6bd
VK
82{
83 SOCKET sock, sockClient;
84 struct sockaddr_in servAddr;
b7271ccb
VK
85 int errorCount = 0;
86 socklen_t iSize;
5d0ff6bd 87 WORD wListenPort;
5af4c41b 88 ClientSession *pSession;
5d0ff6bd
VK
89
90 // Read configuration
91 wListenPort = (WORD)ConfigReadInt("ClientListenerPort", SERVER_LISTEN_PORT);
92
93 // Create socket
94 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
95 {
96 WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "ClientListener");
ccdbbb52 97 return THREAD_OK;
5d0ff6bd
VK
98 }
99
9f881a19
AK
100 SetSocketReuseFlag(sock);
101
62f5857f
VK
102 // Create session list access mutex
103 m_hSessionListAccess = MutexCreate();
104
5d0ff6bd
VK
105 // Fill in local address structure
106 memset(&servAddr, 0, sizeof(struct sockaddr_in));
107 servAddr.sin_family = AF_INET;
108 servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
109 servAddr.sin_port = htons(wListenPort);
110
111 // Bind socket
112 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
113 {
5d0ff6bd 114 WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", wListenPort, "ClientListener", WSAGetLastError());
37c4d6aa
VK
115 closesocket(sock);
116 /* TODO: we should initiate shutdown procedure here */
117 return THREAD_OK;
5d0ff6bd
VK
118 }
119
120 // Set up queue
121 listen(sock, SOMAXCONN);
122
123 // Wait for connection requests
124 while(!ShutdownInProgress())
125 {
126 iSize = sizeof(struct sockaddr_in);
127 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
128 {
129 int error;
130
131#ifdef _WIN32
132 error = WSAGetLastError();
133 if (error != WSAEINTR)
134#else
135 error = errno;
136 if (error != EINTR)
137#endif
138 WriteLog(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
139 errorCount++;
140 if (errorCount > 1000)
141 {
142 WriteLog(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
143 errorCount = 0;
144 }
145 ThreadSleepMs(500);
146 }
147
148 errorCount = 0; // Reset consecutive errors counter
149
5af4c41b 150 // Create new session structure and threads
205acaf4 151 pSession = new ClientSession(sockClient, ntohl(servAddr.sin_addr.s_addr));
da54bd8d
VK
152 if (!RegisterSession(pSession))
153 {
154 delete pSession;
155 }
156 else
157 {
ccdbbb52 158 pSession->Run();
da54bd8d 159 }
5d0ff6bd
VK
160 }
161
162 closesocket(sock);
ccdbbb52 163 return THREAD_OK;
5d0ff6bd 164}
ecb7e1ee
VK
165
166
167//
168// Dump client sessions to screen
169//
170
171void DumpSessions(void)
172{
c868331f 173 int i, iCount;
cb7ec554
VK
174 TCHAR szBuffer[256];
175 static TCHAR *pszStateName[] = { "init", "idle", "processing" };
ecb7e1ee 176
cb7ec554 177 printf("ID STATE USER\n");
c868331f 178 for(i = 0, iCount = 0; i < MAX_CLIENT_SESSIONS; i++)
ecb7e1ee 179 if (m_pSessionList[i] != NULL)
c868331f 180 {
cb7ec554
VK
181 printf("%-3d %-24s %s\n", i,
182 (m_pSessionList[i]->GetState() != SESSION_STATE_PROCESSING) ?
183 pszStateName[m_pSessionList[i]->GetState()] :
184 CSCPMessageCodeName(m_pSessionList[i]->GetCurrentCmd(), szBuffer),
185 m_pSessionList[i]->GetUserName());
c868331f
VK
186 iCount++;
187 }
188 printf("\n%d active session%s\n\n", iCount, iCount == 1 ? "" : "s");
ecb7e1ee 189}
62f5857f
VK
190
191
192//
193// Enumerate active sessions
194//
195
196void EnumerateClientSessions(void (*pHandler)(ClientSession *, void *), void *pArg)
197{
198 int i;
199
200 MutexLock(m_hSessionListAccess, INFINITE);
201 for(i = 0; i < MAX_CLIENT_SESSIONS; i++)
202 if (m_pSessionList[i] != NULL)
203 pHandler(m_pSessionList[i], pArg);
204 MutexUnlock(m_hSessionListAccess);
205}
984542f8
VK
206
207
208//
209// Send update notification to all clients
210//
211
212void SendUserDBUpdate(int iCode, DWORD dwUserId, NMS_USER *pUser, NMS_USER_GROUP *pGroup)
213{
214 int i;
215
216 MutexLock(m_hSessionListAccess, INFINITE);
217 for(i = 0; i < MAX_CLIENT_SESSIONS; i++)
218 if (m_pSessionList[i] != NULL)
219 m_pSessionList[i]->OnUserDBUpdate(iCode, dwUserId, pUser, pGroup);
220 MutexUnlock(m_hSessionListAccess);
221}