condTimedWait fixed
[public/netxms.git] / src / server / core / admin.cpp
1 /* $Id: admin.cpp,v 1.7 2005-02-02 22:32:16 alk Exp $ */
2
3 /*
4 ** NetXMS - Network Management System
5 ** Copyright (C) 2003, 2004 Victor Kirhenshtein
6 **
7 ** This program is free software; you can redistribute it and/or modify
8 ** it under the terms of the GNU General Public License as published by
9 ** the Free Software Foundation; either version 2 of the License, or
10 ** (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 **
21 ** $module: admin.cpp
22 **
23 **/
24
25 #include "nxcore.h"
26 #include <local_admin.h>
27
28
29 //
30 // Send success or error notification
31 //
32
33 #define SEND_ERROR() \
34 { \
35 wCmd = LA_RESP_ERROR; \
36 SendEx(sock, (char *)&wCmd, sizeof(WORD), 0); \
37 }
38 #define SEND_SUCCESS() \
39 { \
40 wCmd = LA_RESP_SUCCESS; \
41 SendEx(sock, (char *)&wCmd, sizeof(WORD), 0); \
42 }
43
44
45
46 //
47 // Receive string from client
48 //
49
50 static BOOL RecvString(SOCKET sock, char *pBuffer, int iBufSize)
51 {
52 int iError;
53 WORD wSize = 0;
54
55 // Receive string length
56 iError = recv(sock, (char *)&wSize, 2, 0);
57 if ((iError != 2) || (wSize > iBufSize - 1))
58 return FALSE;
59
60 iError = recv(sock, pBuffer, wSize, 0);
61 if (iError != wSize)
62 return FALSE;
63 pBuffer[iError] = 0;
64 return TRUE;
65 }
66
67
68 //
69 // Send string to client
70 //
71
72 static BOOL SendString(SOCKET sock, char *szString)
73 {
74 WORD wLen;
75
76 wLen = strlen(szString);
77 if (SendEx(sock, (char *)&wLen, sizeof(WORD), 0) != 2)
78 return FALSE;
79
80 return SendEx(sock, szString, wLen, 0) == wLen;
81 }
82
83
84 //
85 // Request processing thread
86 //
87
88 static THREAD_RESULT THREAD_CALL ProcessingThread(void *pArg)
89 {
90 SOCKET sock = (SOCKET)pArg;
91 WORD wCmd;
92 int iError;
93 char szBuffer[256];
94 DWORD dwTemp;
95
96 while(1)
97 {
98 iError = recv(sock, (char *)&wCmd, sizeof(WORD), 0);
99 if (iError != 2)
100 break; // Communication error or closed connection
101
102 switch(wCmd)
103 {
104 case LA_CMD_LIST_CONFIG:
105 SEND_ERROR();
106 break;
107 case LA_CMD_GET_CONFIG:
108 // Receive variable name
109 if (RecvString(sock, szBuffer, 256))
110 {
111 char szValue[256];
112
113 if (ConfigReadStr(szBuffer, szValue, 255, ""))
114 SendString(sock, szValue);
115 else
116 SEND_ERROR();
117 }
118 else
119 {
120 goto close_connection;
121 }
122 break;
123 case LA_CMD_SET_CONFIG:
124 // Receive variable name
125 if (RecvString(sock, szBuffer, 256))
126 {
127 char szValue[256];
128
129 // Receive new value
130 if (RecvString(sock, szValue, 256))
131 {
132 if (ConfigWriteStr(szBuffer, szValue, TRUE))
133 {
134 SEND_SUCCESS();
135 }
136 else
137 {
138 SEND_ERROR();
139 }
140 }
141 else
142 {
143 goto close_connection;
144 }
145 }
146 else
147 {
148 goto close_connection;
149 }
150 break;
151 case LA_CMD_GET_FLAGS:
152 // Send value of application flags
153 SendEx(sock, (char *)&g_dwFlags, sizeof(DWORD), 0);
154 break;
155 case LA_CMD_SET_FLAGS:
156 iError = recv(sock, (char *)&dwTemp, sizeof(DWORD), 0);
157 if (iError == sizeof(DWORD))
158 {
159 dwTemp &= ~AF_STANDALONE; // Standalone flag shouldn't be changed
160 g_dwFlags = dwTemp | (g_dwFlags & AF_STANDALONE);
161 SEND_SUCCESS();
162 }
163 else
164 {
165 goto close_connection;
166 }
167 break;
168 default:
169 break;
170 }
171 }
172
173 close_connection:
174 shutdown(sock, 2);
175 closesocket(sock);
176 return THREAD_OK;
177 }
178
179
180 //
181 // Local administrative interface listener thread
182 //
183
184 THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg)
185 {
186 SOCKET sock, sockClient;
187 struct sockaddr_in servAddr;
188 int errorCount = 0;
189 socklen_t iSize;
190
191 // Create socket
192 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
193 {
194 WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "LocalAdminListener");
195 return THREAD_OK;
196 }
197
198 SetSocketReuseFlag(sock);
199
200 // Fill in local address structure
201 memset(&servAddr, 0, sizeof(struct sockaddr_in));
202 servAddr.sin_family = AF_INET;
203 servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
204 servAddr.sin_port = htons(LOCAL_ADMIN_PORT);
205
206 // Bind socket
207 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
208 {
209 WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", LOCAL_ADMIN_PORT, "LocalAdminListener", WSAGetLastError());
210 closesocket(sock);
211 /* TODO: we should initiate shutdown from here */
212 return THREAD_OK;
213 }
214
215 // Set up queue
216 listen(sock, SOMAXCONN);
217
218 // Wait for connection requests
219 while(!ShutdownInProgress())
220 {
221 iSize = sizeof(struct sockaddr_in);
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 WriteLog(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
234 errorCount++;
235 if (errorCount > 1000)
236 {
237 WriteLog(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
238 errorCount = 0;
239 }
240 ThreadSleepMs(500);
241 }
242
243 errorCount = 0; // Reset consecutive errors counter
244
245 // Create new session structure and threads
246 ThreadCreate(ProcessingThread, 0, (void *)sockClient);
247 }
248
249 closesocket(sock);
250 return THREAD_OK;
251 }
252
253 ///////////////////////////////////////////////////////////////////////////////
254 /*
255
256 $Log: not supported by cvs2svn $
257 Revision 1.6 2005/01/18 15:51:42 alk
258 + sockets reuse (*nix only)
259
260
261 */