bd3b2f2b385a1d5b014fed2b880aee3756b3325c
[public/netxms.git] / src / server / core / subnet.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Copyright (C) 2003-2017 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: subnet.cpp
20 **/
21
22 #include "nxcore.h"
23
24 /**
25 * Subnet class default constructor
26 */
27 Subnet::Subnet() : NetObj()
28 {
29 m_zoneUIN = 0;
30 m_bSyntheticMask = false;
31 }
32
33 /**
34 * Subnet class constructor
35 */
36 Subnet::Subnet(const InetAddress& addr, UINT32 zoneUIN, bool bSyntheticMask) : NetObj()
37 {
38 TCHAR szBuffer[64];
39 _sntprintf(m_name, MAX_OBJECT_NAME, _T("%s/%d"), addr.toString(szBuffer), addr.getMaskBits());
40 m_ipAddress = addr;
41 m_zoneUIN = zoneUIN;
42 m_bSyntheticMask = bSyntheticMask;
43 }
44
45 /**
46 * Subnet class destructor
47 */
48 Subnet::~Subnet()
49 {
50 }
51
52 /**
53 * Create object from database data
54 */
55 bool Subnet::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
56 {
57 TCHAR szQuery[256];
58 DB_RESULT hResult;
59
60 m_id = dwId;
61
62 if (!loadCommonProperties(hdb))
63 return false;
64
65 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("SELECT ip_addr,ip_netmask,zone_guid,synthetic_mask FROM subnets WHERE id=%d"), dwId);
66 hResult = DBSelect(hdb, szQuery);
67 if (hResult == 0)
68 return false; // Query failed
69
70 if (DBGetNumRows(hResult) == 0)
71 {
72 DBFreeResult(hResult);
73 return false;
74 }
75
76 m_ipAddress = DBGetFieldInetAddr(hResult, 0, 0);
77 m_ipAddress.setMaskBits(DBGetFieldLong(hResult, 0, 1));
78 m_zoneUIN = DBGetFieldULong(hResult, 0, 2);
79 m_bSyntheticMask = DBGetFieldLong(hResult, 0, 3) ? true : false;
80
81 DBFreeResult(hResult);
82
83 // Load access list
84 loadACLFromDB(hdb);
85
86 return true;
87 }
88
89 /**
90 * Save subnet object to database
91 */
92 bool Subnet::saveToDatabase(DB_HANDLE hdb)
93 {
94 TCHAR szQuery[1024], szIpAddr[64];
95
96 // Lock object's access
97 lockProperties();
98
99 saveCommonProperties(hdb);
100
101 // Form and execute INSERT or UPDATE query
102 if (IsDatabaseRecordExist(hdb, _T("subnets"), _T("id"), m_id))
103 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR),
104 _T("UPDATE subnets SET ip_addr='%s',ip_netmask=%d,zone_guid=%d,synthetic_mask=%d WHERE id=%d"),
105 m_ipAddress.toString(szIpAddr), m_ipAddress.getMaskBits(), m_zoneUIN, m_bSyntheticMask ? 1 : 0, m_id);
106 else
107 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR),
108 _T("INSERT INTO subnets (id,ip_addr,ip_netmask,zone_guid,synthetic_mask) VALUES (%d,'%s',%d,%d,%d)"),
109 m_id, m_ipAddress.toString(szIpAddr), m_ipAddress.getMaskBits(), m_zoneUIN, m_bSyntheticMask ? 1 : 0);
110 DBQuery(hdb, szQuery);
111
112 // Update node to subnet mapping
113 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("DELETE FROM nsmap WHERE subnet_id=%d"), m_id);
114 DBQuery(hdb, szQuery);
115 lockChildList(false);
116 for(int i = 0; i < m_childList->size(); i++)
117 {
118 _sntprintf(szQuery, sizeof(szQuery) / sizeof(TCHAR), _T("INSERT INTO nsmap (subnet_id,node_id) VALUES (%d,%d)"), m_id, m_childList->get(i)->getId());
119 DBQuery(hdb, szQuery);
120 }
121 unlockChildList();
122
123 // Save access list
124 saveACLToDB(hdb);
125
126 // Clear modifications flag and unlock object
127 m_isModified = false;
128 unlockProperties();
129
130 return true;
131 }
132
133 /**
134 * Delete subnet object from database
135 */
136 bool Subnet::deleteFromDatabase(DB_HANDLE hdb)
137 {
138 bool success = NetObj::deleteFromDatabase(hdb);
139 if (success)
140 success = executeQueryOnObject(hdb, _T("DELETE FROM subnets WHERE id=?"));
141 if (success)
142 success = executeQueryOnObject(hdb, _T("DELETE FROM nsmap WHERE subnet_id=?"));
143 return success;
144 }
145
146 /**
147 * Create CSCP message with object's data
148 */
149 void Subnet::fillMessageInternal(NXCPMessage *pMsg)
150 {
151 NetObj::fillMessageInternal(pMsg);
152 pMsg->setField(VID_IP_ADDRESS, m_ipAddress);
153 pMsg->setField(VID_ZONE_UIN, m_zoneUIN);
154 pMsg->setField(VID_SYNTHETIC_MASK, (WORD)(m_bSyntheticMask ? 1 : 0));
155 }
156
157 /**
158 * Set correct netmask for subnet
159 */
160 void Subnet::setCorrectMask(const InetAddress& addr)
161 {
162 TCHAR szName[MAX_OBJECT_NAME], szBuffer[64];
163
164 lockProperties();
165
166 // Check if name is default
167 _sntprintf(szName, MAX_OBJECT_NAME, _T("%s/%d"), m_ipAddress.toString(szBuffer), m_ipAddress.getMaskBits());
168 if (!_tcsicmp(szName, m_name))
169 {
170 // Change name
171 _sntprintf(m_name, MAX_OBJECT_NAME, _T("%s/%d"), addr.toString(szBuffer), addr.getMaskBits());
172 }
173
174 bool reAdd = !m_ipAddress.equals(addr);
175 if (reAdd)
176 {
177 g_idxSubnetByAddr.remove(m_ipAddress);
178 }
179
180 m_ipAddress = addr;
181 m_bSyntheticMask = false;
182
183 if (reAdd)
184 {
185 g_idxSubnetByAddr.put(m_ipAddress, this);
186 }
187 setModified();
188 unlockProperties();
189 }
190
191 /**
192 * Find MAC address for given IP address. May take a long time because it involves reading ARP caches
193 * from nodes in this subnet.
194 *
195 * @param ipAddr IP address (host byte order)
196 * @param macAddr buffer for found MAC address
197 * @return true if MAC address found
198 */
199 bool Subnet::findMacAddress(const InetAddress& ipAddr, BYTE *macAddr)
200 {
201 bool success = false;
202
203 lockChildList(false);
204
205 for(int i = 0; (i < m_childList->size()) && !success; i++)
206 {
207 if (m_childList->get(i)->getObjectClass() != OBJECT_NODE)
208 continue;
209
210 Node *node = (Node *)m_childList->get(i);
211 DbgPrintf(6, _T("Subnet[%s]::findMacAddress: reading ARP cache for node %s [%u]"), m_name, node->getName(), node->getId());
212 ARP_CACHE *arpCache = node->getArpCache();
213 if (arpCache == NULL)
214 continue;
215
216 for(UINT32 j = 0; j < arpCache->dwNumEntries; j++)
217 {
218 if (arpCache->pEntries[j].ipAddr.equals(ipAddr))
219 {
220 memcpy(macAddr, arpCache->pEntries[j].bMacAddr, MAC_ADDR_LENGTH);
221 success = true;
222 break;
223 }
224 }
225
226 DestroyArpCache(arpCache);
227 }
228
229 unlockChildList();
230
231 return success;
232 }
233
234 /**
235 * Build IP topology
236 */
237 void Subnet::buildIPTopologyInternal(NetworkMapObjectList &topology, int nDepth, UINT32 seedNode, bool includeEndNodes)
238 {
239 ObjectArray<Node> nodes;
240 lockChildList(false);
241 for(int i = 0; i < m_childList->size(); i++)
242 {
243 NetObj *object = m_childList->get(i);
244 if ((object->getId() == seedNode) || (object->getObjectClass() != OBJECT_NODE))
245 continue;
246 if (!includeEndNodes && !((Node *)object)->isRouter())
247 continue;
248 object->incRefCount();
249 nodes.add((Node *)object);
250 }
251 unlockChildList();
252
253 for(int j = 0; j < nodes.size(); j++)
254 {
255 Node *n = nodes.get(j);
256 n->buildIPTopologyInternal(topology, nDepth - 1, m_id, false, includeEndNodes);
257 n->decRefCount();
258 }
259 }
260
261 /**
262 * Called by client session handler to check if threshold summary should be shown for this object.
263 */
264 bool Subnet::showThresholdSummary()
265 {
266 return true;
267 }
268
269 /**
270 * Build address map - mark used and free addresses
271 */
272 UINT32 *Subnet::buildAddressMap(int *length)
273 {
274 *length = 1 << (32 - m_ipAddress.getMaskBits());
275 if ((*length < 2) || (*length > 65536))
276 return NULL;
277 UINT32 *map = (UINT32 *)malloc(*length * sizeof(UINT32));
278
279 map[0] = 0xFFFFFFFF; // subnet
280 map[*length - 1] = 0xFFFFFFFF; // broadcast
281 UINT32 addr = m_ipAddress.getAddressV4() + 1;
282 for(int i = 1; i < *length - 1; i++, addr++)
283 {
284 Node *node = FindNodeByIP(m_zoneUIN, addr);
285 map[i] = (node != NULL) ? node->getId() : 0;
286 }
287
288 return map;
289 }
290
291 /**
292 * Prepare node object for deletion
293 */
294 void Subnet::prepareForDeletion()
295 {
296 PostEvent(EVENT_SUBNET_DELETED, g_dwMgmtNode, "isAd", m_id, m_name, &m_ipAddress, m_ipAddress.getMaskBits());
297 NetObj::prepareForDeletion();
298 }
299
300 /**
301 * Serialize object to JSON
302 */
303 json_t *Subnet::toJson()
304 {
305 json_t *root = NetObj::toJson();
306 json_object_set_new(root, "ipAddress", m_ipAddress.toJson());
307 json_object_set_new(root, "zoneUIN", json_integer(m_zoneUIN));
308 json_object_set_new(root, "syntheticMask", json_boolean(m_bSyntheticMask));
309 return root;
310 }