Linked against new CSCP API library
[public/netxms.git] / src / libnxcl / comm.cpp
CommitLineData
05d9bba3
VK
1/*
2** NetXMS - Network Management System
3** Client Library
4** Copyright (C) 2004 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU General Public License as published by
8** the Free Software Foundation; either version 2 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** $module: comm.cpp
21**
22**/
23
24#include "libnxcl.h"
25
26
27//
28// Static data
29//
30
31static SOCKET m_hSocket = -1;
32static DWORD m_dwMsgId;
33static char m_szServer[MAX_SERVER_NAME];
34static char m_szLogin[MAX_LOGIN_NAME];
f160ff09 35static BYTE m_szPassword[SHA_DIGEST_LENGTH];
05d9bba3
VK
36static MsgWaitQueue m_msgWaitQueue;
37
38
1dd9669b
VK
39//
40// Get symbolic name for message code
41// This function is intended to be used from receiver thread only,
42// so we don't care about reentrancy
43//
44
45static char *MessageCodeName(WORD wCode)
46{
47 static char *pszMsgNames[] =
48 {
49 "CMD_LOGIN",
50 "CMD_LOGIN_RESP",
51 "CMD_KEEPALIVE",
52 "CMD_EVENT",
53 "CMD_GET_OBJECTS",
54 "CMD_OBJECT",
55 "CMD_DELETE_OBJECT",
84287f54 56 "CMD_MODIFY_OBJECT",
1dd9669b
VK
57 "CMD_OBJECT_LIST_END",
58 "CMD_OBJECT_UPDATE",
59 "CMD_GET_EVENTS",
60 "CMD_EVENT_LIST_END",
61 "CMD_GET_CONFIG_VARLIST",
62 "CMD_SET_CONFIG_VARIABLE",
63 "CMD_CONFIG_VARIABLE",
64 "CMD_CONFIG_VARLIST_END",
65 "CMD_DELETE_CONFIG_VARIABLE",
66 "CMD_NOTIFY",
67 "CMD_OPEN_EPP",
68 "CMD_CLOSE_EPP",
69 "CMD_INSTALL_EPP",
70 "CMD_SAVE_EPP",
71 "CMD_EPP_RECORD",
72 "CMD_OPEN_EVENT_DB",
73 "CMD_CLOSE_EVENT_DB",
74 "CMD_SET_EVENT_INFO",
75 "CMD_EVENT_DB_RECORD",
76 "CMD_EVENT_DB_EOF",
bb68f467
VK
77 "CMD_REQUEST_COMPLETED",
78 "CMD_LOAD_USER_DB",
79 "CMD_USER_DATA",
80 "CMD_GROUP_DATA",
54abbe0e
VK
81 "CMD_USER_DB_EOF",
82 "CMD_UPDATE_USER",
83 "CMD_DELETE_USER",
84 "CMD_CREATE_USER",
85 "CMD_LOCK_USER_DB",
86 "CMD_UNLOCK_USER_DB"
1dd9669b
VK
87 };
88 static char szBuffer[32];
89
54abbe0e 90 if ((wCode >= CMD_LOGIN) && (wCode <= CMD_UNLOCK_USER_DB))
1dd9669b
VK
91 return pszMsgNames[wCode - CMD_LOGIN];
92 sprintf(szBuffer, "CMD_UNKNOWN(%d)", wCode);
93 return szBuffer;
94}
95
96
05d9bba3
VK
97//
98// Send raw message
99//
100
101static BOOL SendRawMsg(CSCP_MESSAGE *pMsg)
102{
103 return send(m_hSocket, (char *)pMsg, ntohs(pMsg->wSize), 0) == (int)ntohs(pMsg->wSize);
104}
105
106
107//
108// Send message
109//
110
111BOOL SendMsg(CSCPMessage *pMsg)
112{
113 CSCP_MESSAGE *pRawMsg;
114 BOOL bResult;
115
1dd9669b 116 DebugPrintf("SendMsg(\"%s\", id:%ld)", MessageCodeName(pMsg->GetCode()), pMsg->GetId());
05d9bba3
VK
117 pRawMsg = pMsg->CreateMessage();
118 bResult = SendRawMsg(pRawMsg);
5b9ed9ac 119 MemFree(pRawMsg);
05d9bba3
VK
120 return bResult;
121}
122
123
124//
125// Network receiver thread
126//
127
128static void NetReceiver(void *pArg)
129{
130 CSCPMessage *pMsg;
131 CSCP_MESSAGE *pRawMsg;
132 CSCP_BUFFER *pMsgBuffer;
133 int iErr;
d8d6e1a4 134 BOOL bMsgNotNeeded;
05d9bba3
VK
135
136 // Initialize raw message receiving function
5b9ed9ac 137 pMsgBuffer = (CSCP_BUFFER *)MemAlloc(sizeof(CSCP_BUFFER));
05d9bba3
VK
138 RecvCSCPMessage(0, NULL, pMsgBuffer);
139
140 // Allocate space for raw message
5b9ed9ac 141 pRawMsg = (CSCP_MESSAGE *)MemAlloc(65536);
05d9bba3
VK
142
143 // Message receiving loop
144 while(1)
145 {
146 // Receive raw message
147 if ((iErr = RecvCSCPMessage(m_hSocket, pRawMsg, pMsgBuffer)) <= 0)
148 break;
149
150 // Check that actual received packet size is equal to encoded in packet
151 if (ntohs(pRawMsg->wSize) != iErr)
152 {
1dd9669b 153 DebugPrintf("RecvMsg: Bad packet length [wSize=%d ActualSize=%d]", ntohs(pRawMsg->wSize), iErr);
05d9bba3
VK
154 continue; // Bad packet, wait for next
155 }
156
157 // Create message object from raw message
f8e075ce
VK
158 if (IsBinaryMsg(pRawMsg))
159 {
160 // Convert numeric fields to host byte order
161 pRawMsg->wCode = ntohs(pRawMsg->wCode) & 0x0FFF; // Clear flag bits from code
162 pRawMsg->wSize = ntohs(pRawMsg->wSize);
163 pRawMsg->dwId = ntohl(pRawMsg->dwId);
164
1dd9669b
VK
165 DebugPrintf("RecvRawMsg(\"%s\", id:%ld)", MessageCodeName(pRawMsg->wCode), pRawMsg->dwId);
166
f8e075ce
VK
167 // Process message
168 switch(pRawMsg->wCode)
169 {
170 case CMD_EVENT:
171 ProcessEvent(NULL, pRawMsg);
f8e075ce
VK
172 break;
173 default: // We ignore unknown raw messages
174 break;
175 }
176 }
177 else
05d9bba3 178 {
f8e075ce 179 pMsg = new CSCPMessage(pRawMsg);
d8d6e1a4 180 bMsgNotNeeded = TRUE;
1dd9669b 181 DebugPrintf("RecvMsg(\"%s\", id:%ld)", MessageCodeName(pMsg->GetCode()), pMsg->GetId());
f8e075ce
VK
182
183 // Process message
184 switch(pMsg->GetCode())
185 {
186 case CMD_KEEPALIVE: // Keepalive message, ignore it
f8e075ce
VK
187 break;
188 case CMD_OBJECT: // Object information
824615ef 189 case CMD_OBJECT_UPDATE:
f8e075ce
VK
190 case CMD_OBJECT_LIST_END:
191 ProcessObjectUpdate(pMsg);
f8e075ce
VK
192 break;
193 case CMD_EVENT_LIST_END:
194 ProcessEvent(pMsg, NULL);
f8e075ce 195 break;
f160ff09
VK
196 case CMD_EVENT_DB_RECORD:
197 case CMD_EVENT_DB_EOF:
198 ProcessEventDBRecord(pMsg);
199 break;
bb68f467
VK
200 case CMD_USER_DATA:
201 case CMD_GROUP_DATA:
202 case CMD_USER_DB_EOF:
203 ProcessUserDBRecord(pMsg);
204 break;
f8e075ce
VK
205 default:
206 m_msgWaitQueue.Put(pMsg);
d8d6e1a4 207 bMsgNotNeeded = FALSE;
f8e075ce
VK
208 break;
209 }
d8d6e1a4
VK
210 if (bMsgNotNeeded)
211 delete pMsg;
05d9bba3
VK
212 }
213 }
214
215 ChangeState(STATE_DISCONNECTED);
5b9ed9ac
VK
216 MemFree(pRawMsg);
217 MemFree(pMsgBuffer);
05d9bba3
VK
218}
219
220
221//
222// Connect to server
223//
224
225BOOL Connect(void)
226{
227 struct sockaddr_in servAddr;
228 CSCPMessage msg, *pResp;
229 BOOL bSuccess;
230
231 ChangeState(STATE_CONNECTING);
232
233 // Reset unique message ID
234 m_dwMsgId = 1;
235
236 // Prepare address structure
237 memset(&servAddr, 0, sizeof(struct sockaddr_in));
238 servAddr.sin_family = AF_INET;
239 servAddr.sin_addr.s_addr = inet_addr(m_szServer);
240 if (servAddr.sin_addr.s_addr == INADDR_NONE)
241 {
242 struct hostent *hs;
243
244 hs = gethostbyname(m_szServer);
245 if (hs == NULL)
246 {
247 return FALSE; // Unable to resolve host name
248 }
249 else
250 {
251 memcpy(&servAddr.sin_addr, hs->h_addr, hs->h_length);
252 }
253 }
254 servAddr.sin_port = htons((WORD)SERVER_LISTEN_PORT);
255
256 // Create socket
257 if ((m_hSocket = socket(AF_INET, SOCK_STREAM, 0)) == -1)
258 {
259 return FALSE;
260 }
261
262 // Connect to target
263 if (connect(m_hSocket, (struct sockaddr *)&servAddr, sizeof(struct sockaddr_in)) != 0)
264 {
265 closesocket(m_hSocket);
266 m_hSocket = -1;
267 return FALSE;
268 }
269
270 // Start receiver thread
271 ThreadCreate(NetReceiver, 0, NULL);
272
273 // Prepare login message
274 msg.SetId(m_dwMsgId++);
275 msg.SetCode(CMD_LOGIN);
a5f8dbb8 276 msg.SetVariable(VID_LOGIN_NAME, m_szLogin);
f160ff09 277 msg.SetVariable(VID_PASSWORD, m_szPassword, SHA_DIGEST_LENGTH);
05d9bba3
VK
278
279 if (!SendMsg(&msg))
280 {
281 // Message send failed, drop connection
282 shutdown(m_hSocket, 2);
283 closesocket(m_hSocket);
284 m_hSocket = -1;
285 return FALSE;
286 }
287
288 // Receive responce message
289 pResp = m_msgWaitQueue.WaitForMessage(CMD_LOGIN_RESP, msg.GetId(), 2000);
290 if (pResp == NULL) // Connection is broken or timed out
291 {
292 shutdown(m_hSocket, 2);
293 closesocket(m_hSocket);
294 m_hSocket = -1;
295 return FALSE;
296 }
297
a5f8dbb8 298 bSuccess = pResp->GetVariableLong(VID_LOGIN_RESULT);
05d9bba3
VK
299 delete pResp;
300
301 CallEventHandler(NXC_EVENT_LOGIN_RESULT, bSuccess, NULL);
302 if (!bSuccess)
303 {
304 shutdown(m_hSocket, 2);
305 closesocket(m_hSocket);
306 m_hSocket = -1;
307 }
308 return bSuccess;
309}
310
311
312//
313// Initiate connection to server
314//
315
8aeffdee 316BOOL LIBNXCL_EXPORTABLE NXCConnect(char *szServer, char *szLogin, char *szPassword)
05d9bba3
VK
317{
318 if (g_dwState != STATE_DISCONNECTED)
319 return FALSE;
320
321 strcpy(m_szServer, szServer);
322 strcpy(m_szLogin, szLogin);
f160ff09 323 CreateSHA1Hash(szPassword, m_szPassword);
05d9bba3
VK
324
325 CreateRequest(RQ_CONNECT, NULL, FALSE);
326
327 return TRUE;
328}
329
330
331//
332// Disconnect from server
333//
334
8aeffdee 335void LIBNXCL_EXPORTABLE NXCDisconnect(void)
05d9bba3
VK
336{
337 // Close socket
338 shutdown(m_hSocket, 2);
339 closesocket(m_hSocket);
340
341 // Clear message wait queue
342 m_msgWaitQueue.Clear();
343}
d8d6e1a4
VK
344
345
346//
347// Wait for specific message
348//
349
350CSCPMessage *WaitForMessage(DWORD dwCode, DWORD dwId, DWORD dwTimeOut)
351{
352 return m_msgWaitQueue.WaitForMessage(dwCode, dwId, dwTimeOut);
353}