Server core implemented as DLL/shared library
[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 "nxcore.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 THREAD_RESULT THREAD_CALL 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 return THREAD_OK;
175 }
176
177
178 //
179 // Local administrative interface listener thread
180 //
181
182 THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg)
183 {
184 SOCKET sock, sockClient;
185 struct sockaddr_in servAddr;
186 int errorCount = 0;
187 socklen_t iSize;
188
189 // Create socket
190 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
191 {
192 WriteLog(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", "LocalAdminListener");
193 return THREAD_OK;
194 }
195
196 // Fill in local address structure
197 memset(&servAddr, 0, sizeof(struct sockaddr_in));
198 servAddr.sin_family = AF_INET;
199 servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
200 servAddr.sin_port = htons(LOCAL_ADMIN_PORT);
201
202 // Bind socket
203 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
204 {
205 WriteLog(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", LOCAL_ADMIN_PORT, "LocalAdminListener", WSAGetLastError());
206 closesocket(sock);
207 /* TODO: we should initiate shutdown from here */
208 return THREAD_OK;
209 }
210
211 // Set up queue
212 listen(sock, SOMAXCONN);
213
214 // Wait for connection requests
215 while(!ShutdownInProgress())
216 {
217 iSize = sizeof(struct sockaddr_in);
218 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
219 {
220 int error;
221
222 #ifdef _WIN32
223 error = WSAGetLastError();
224 if (error != WSAEINTR)
225 #else
226 error = errno;
227 if (error != EINTR)
228 #endif
229 WriteLog(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
230 errorCount++;
231 if (errorCount > 1000)
232 {
233 WriteLog(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
234 errorCount = 0;
235 }
236 ThreadSleepMs(500);
237 }
238
239 errorCount = 0; // Reset consecutive errors counter
240
241 // Create new session structure and threads
242 ThreadCreate(ProcessingThread, 0, (void *)sockClient);
243 }
244
245 closesocket(sock);
246 return THREAD_OK;
247 }