Now can be compiled under Linux
[public/netxms.git] / src / server / core / admin.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003, 2004 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: admin.cpp
20 **
21 **/
22
23 #include "nms_core.h"
24 #include <local_admin.h>
25
26
27 //
28 // Send success or error notification
29 //
30
31 #define SEND_ERROR() \
32 { \
33 wCmd = LA_RESP_ERROR; \
34 send(sock, (char *)&wCmd, sizeof(WORD), 0); \
35 }
36 #define SEND_SUCCESS() \
37 { \
38 wCmd = LA_RESP_SUCCESS; \
39 send(sock, (char *)&wCmd, sizeof(WORD), 0); \
40 }
41
42
43
44 //
45 // Receive string from client
46 //
47
48 static BOOL RecvString(SOCKET sock, char *pBuffer, int iBufSize)
49 {
50 int iError;
51 WORD wSize = 0;
52
53 // Receive string length
54 iError = recv(sock, (char *)&wSize, 2, 0);
55 if ((iError != 2) || (wSize > iBufSize - 1))
56 return FALSE;
57
58 iError = recv(sock, pBuffer, wSize, 0);
59 if (iError != wSize)
60 return FALSE;
61 pBuffer[iError] = 0;
62 return TRUE;
63 }
64
65
66 //
67 // Send string to client
68 //
69
70 static BOOL SendString(SOCKET sock, char *szString)
71 {
72 WORD wLen;
73
74 wLen = strlen(szString);
75 if (send(sock, (char *)&wLen, sizeof(WORD), 0) != 2)
76 return FALSE;
77
78 return send(sock, szString, wLen, 0) == wLen;
79 }
80
81
82 //
83 // Request processing thread
84 //
85
86 static void ProcessingThread(void *pArg)
87 {
88 SOCKET sock = (SOCKET)pArg;
89 WORD wCmd;
90 int iError;
91 char szBuffer[256];
92 DWORD dwTemp;
93
94 while(1)
95 {
96 iError = recv(sock, (char *)&wCmd, sizeof(WORD), 0);
97 if (iError != 2)
98 break; // Communication error or closed connection
99
100 switch(wCmd)
101 {
102 case LA_CMD_LIST_CONFIG:
103 SEND_ERROR();
104 break;
105 case LA_CMD_GET_CONFIG:
106 // Receive variable name
107 if (RecvString(sock, szBuffer, 256))
108 {
109 char szValue[256];
110
111 if (ConfigReadStr(szBuffer, szValue, 255, ""))
112 SendString(sock, szValue);
113 else
114 SEND_ERROR();
115 }
116 else
117 {
118 goto close_connection;
119 }
120 break;
121 case LA_CMD_SET_CONFIG:
122 // Receive variable name
123 if (RecvString(sock, szBuffer, 256))
124 {
125 char szValue[256];
126
127 // Receive new value
128 if (RecvString(sock, szValue, 256))
129 {
130 if (ConfigWriteStr(szBuffer, szValue, TRUE))
131 {
132 SEND_SUCCESS();
133 }
134 else
135 {
136 SEND_ERROR();
137 }
138 }
139 else
140 {
141 goto close_connection;
142 }
143 }
144 else
145 {
146 goto close_connection;
147 }
148 break;
149 case LA_CMD_GET_FLAGS:
150 // Send value of application flags
151 send(sock, (char *)&g_dwFlags, sizeof(DWORD), 0);
152 break;
153 case LA_CMD_SET_FLAGS:
154 iError = recv(sock, (char *)&dwTemp, sizeof(DWORD), 0);
155 if (iError == sizeof(DWORD))
156 {
157 dwTemp &= ~AF_STANDALONE; // Standalone flag shouldn't be changed
158 g_dwFlags = dwTemp | (g_dwFlags & AF_STANDALONE);
159 SEND_SUCCESS();
160 }
161 else
162 {
163 goto close_connection;
164 }
165 break;
166 default:
167 break;
168 }
169 }
170
171 close_connection:
172 shutdown(sock, 2);
173 closesocket(sock);
174 }
175
176
177 //
178 // Local administrative interface listener thread
179 //
180
181 void LocalAdminListener(void *pArg)
182 {
183 SOCKET sock, sockClient;
184 struct sockaddr_in servAddr;
185 int errorCount = 0;
186 socklen_t iSize;
187
188 // Create socket
189 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
190 {
191 WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "LocalAdminListener");
192 return;
193 }
194
195 // Fill in local address structure
196 memset(&servAddr, 0, sizeof(struct sockaddr_in));
197 servAddr.sin_family = AF_INET;
198 servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
199 servAddr.sin_port = htons(LOCAL_ADMIN_PORT);
200
201 // Bind socket
202 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
203 {
204 WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", LOCAL_ADMIN_PORT, "LocalAdminListener", WSAGetLastError());
205 exit(1);
206 }
207
208 // Set up queue
209 listen(sock, SOMAXCONN);
210
211 // Wait for connection requests
212 while(!ShutdownInProgress())
213 {
214 iSize = sizeof(struct sockaddr_in);
215 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
216 {
217 int error;
218
219 #ifdef _WIN32
220 error = WSAGetLastError();
221 if (error != WSAEINTR)
222 #else
223 error = errno;
224 if (error != EINTR)
225 #endif
226 WriteLog(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
227 errorCount++;
228 if (errorCount > 1000)
229 {
230 WriteLog(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
231 errorCount = 0;
232 }
233 ThreadSleepMs(500);
234 }
235
236 errorCount = 0; // Reset consecutive errors counter
237
238 // Create new session structure and threads
239 ThreadCreate(ProcessingThread, 0, (void *)sockClient);
240 }
241
242 closesocket(sock);
243 }