07a1bb9e0dc5cd21da51dd8b3b421c8b2f039554
[public/netxms.git] / src / server / core / admin.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2013 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 ** File: admin.cpp
20 **
21 **/
22
23 #include "nxcore.h"
24 #include <local_admin.h>
25
26 /**
27 * Max message size
28 */
29 #define MAX_MSG_SIZE 32768
30
31 /**
32 * Request processing thread
33 */
34 static THREAD_RESULT THREAD_CALL ProcessingThread(void *pArg)
35 {
36 SOCKET sock = CAST_FROM_POINTER(pArg, SOCKET);
37 int iError, nExitCode;
38 NXCP_MESSAGE *pRawMsg, *pRawMsgOut;
39 NXCP_BUFFER *pRecvBuffer;
40 NXCPMessage *pRequest, response;
41 TCHAR szCmd[256];
42 struct __console_ctx ctx;
43 static NXCPEncryptionContext *pDummyCtx = NULL;
44
45 pRawMsg = (NXCP_MESSAGE *)malloc(MAX_MSG_SIZE);
46 pRecvBuffer = (NXCP_BUFFER *)malloc(sizeof(NXCP_BUFFER));
47 RecvNXCPMessage(0, NULL, pRecvBuffer, 0, NULL, NULL, 0);
48 ctx.hSocket = sock;
49 ctx.socketMutex = MutexCreate();
50 ctx.pMsg = &response;
51 ctx.session = NULL;
52 ctx.output = NULL;
53
54 while(1)
55 {
56 iError = RecvNXCPMessage(sock, pRawMsg, pRecvBuffer, MAX_MSG_SIZE, &pDummyCtx, NULL, INFINITE);
57 if (iError <= 0)
58 break; // Communication error or closed connection
59
60 if (iError == 1)
61 continue; // Too big message
62
63 pRequest = new NXCPMessage(pRawMsg);
64 pRequest->getFieldAsString(VID_COMMAND, szCmd, 256);
65
66 response.setCode(CMD_ADM_MESSAGE);
67 response.setId(pRequest->getId());
68 nExitCode = ProcessConsoleCommand(szCmd, &ctx);
69 switch(nExitCode)
70 {
71 case CMD_EXIT_SHUTDOWN:
72 InitiateShutdown();
73 break;
74 case CMD_EXIT_CLOSE_SESSION:
75 delete pRequest;
76 goto close_session;
77 default:
78 break;
79 }
80
81 response.setCode(CMD_REQUEST_COMPLETED);
82 pRawMsgOut = response.createMessage();
83 SendEx(sock, pRawMsgOut, ntohl(pRawMsgOut->size), 0, ctx.socketMutex);
84
85 free(pRawMsgOut);
86 delete pRequest;
87 }
88
89 close_session:
90 shutdown(sock, 2);
91 closesocket(sock);
92 free(pRawMsg);
93 free(pRecvBuffer);
94 MutexDestroy(ctx.socketMutex);
95 return THREAD_OK;
96 }
97
98 /**
99 * Local administrative interface listener thread
100 */
101 THREAD_RESULT THREAD_CALL LocalAdminListener(void *pArg)
102 {
103 SOCKET sock, sockClient;
104 struct sockaddr_in servAddr;
105 int errorCount = 0;
106 socklen_t iSize;
107
108 // Create socket
109 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
110 {
111 nxlog_write(MSG_SOCKET_FAILED, EVENTLOG_ERROR_TYPE, "s", _T("LocalAdminListener"));
112 return THREAD_OK;
113 }
114
115 SetSocketExclusiveAddrUse(sock);
116 SetSocketReuseFlag(sock);
117 #ifndef _WIN32
118 fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC);
119 #endif
120
121 // Fill in local address structure
122 memset(&servAddr, 0, sizeof(struct sockaddr_in));
123 servAddr.sin_family = AF_INET;
124 servAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
125 servAddr.sin_port = htons(LOCAL_ADMIN_PORT);
126
127 // Bind socket
128 if (bind(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
129 {
130 nxlog_write(MSG_BIND_ERROR, EVENTLOG_ERROR_TYPE, "dse", LOCAL_ADMIN_PORT, _T("LocalAdminListener"), WSAGetLastError());
131 closesocket(sock);
132 /* TODO: we should initiate shutdown from here */
133 return THREAD_OK;
134 }
135
136 // Set up queue
137 listen(sock, SOMAXCONN);
138
139 // Wait for connection requests
140 while(!IsShutdownInProgress())
141 {
142 iSize = sizeof(struct sockaddr_in);
143 if ((sockClient = accept(sock, (struct sockaddr *)&servAddr, &iSize)) == -1)
144 {
145 int error;
146
147 #ifdef _WIN32
148 error = WSAGetLastError();
149 if (error != WSAEINTR)
150 #else
151 error = errno;
152 if (error != EINTR)
153 #endif
154 nxlog_write(MSG_ACCEPT_ERROR, EVENTLOG_ERROR_TYPE, "e", error);
155 errorCount++;
156 if (errorCount > 1000)
157 {
158 nxlog_write(MSG_TOO_MANY_ACCEPT_ERRORS, EVENTLOG_WARNING_TYPE, NULL);
159 errorCount = 0;
160 }
161 ThreadSleepMs(500);
162 }
163
164 errorCount = 0; // Reset consecutive errors counter
165
166 // Create new session structure and threads
167 ThreadCreate(ProcessingThread, 0, CAST_TO_POINTER(sockClient, void *));
168 }
169
170 closesocket(sock);
171 return THREAD_OK;
172 }