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