Implemented functionality for zone specific SNMP credentials. Fixes #NX-1199
authorEriks Jenkevics <eriks@netxms.org>
Wed, 1 Nov 2017 10:56:05 +0000 (12:56 +0200)
committerEriks Jenkevics <eriks@netxms.org>
Fri, 3 Nov 2017 13:41:46 +0000 (15:41 +0200)
23 files changed:
include/netxmsdb.h
include/nms_cscp.h
sql/schema.in
src/client/java/netxms-client/src/main/java/org/netxms/client/NXCObjectModificationData.java
src/client/java/netxms-client/src/main/java/org/netxms/client/NXCSession.java
src/client/java/netxms-client/src/main/java/org/netxms/client/objects/Zone.java
src/client/java/netxms-client/src/main/java/org/netxms/client/snmp/SnmpUsmCredential.java
src/java/netxms-eclipse/ObjectBrowser/src/org/netxms/ui/eclipse/objectbrowser/widgets/ZoneSelector.java
src/java/netxms-eclipse/SNMP/src/org/netxms/ui/eclipse/snmp/views/SnmpCredentials.java
src/java/netxms-eclipse/SNMP/src/org/netxms/ui/eclipse/snmp/views/helpers/SnmpConfig.java
src/libnxjava/java/base/netxms-base/src/main/java/org/netxms/base/NXCPCodes.java
src/server/core/node.cpp
src/server/core/np.cpp
src/server/core/nxsl_classes.cpp
src/server/core/session.cpp
src/server/core/snmp.cpp
src/server/core/zone.cpp
src/server/include/nms_core.h
src/server/include/nms_objects.h
src/server/tools/nxdbmgr/upgrade_v30.cpp
webui/webapp/ObjectBrowser/src/org/netxms/ui/eclipse/objectbrowser/widgets/ZoneSelector.java
webui/webapp/SNMP/src/org/netxms/ui/eclipse/snmp/views/SnmpCredentials.java
webui/webapp/SNMP/src/org/netxms/ui/eclipse/snmp/views/helpers/SnmpConfig.java

index 9fe636a..f38bb6c 100644 (file)
@@ -25,7 +25,7 @@
 
 #define DB_LEGACY_SCHEMA_VERSION       700
 #define DB_SCHEMA_VERSION_MAJOR        30
-#define DB_SCHEMA_VERSION_MINOR        9
+#define DB_SCHEMA_VERSION_MINOR        10
 
 #define DB_SCHEMA_VERSION_V30_MINOR    DB_SCHEMA_VERSION_MINOR
 
index d362d8d..ea36b0b 100644 (file)
@@ -1213,6 +1213,7 @@ typedef struct
 #define VID_STRING_COUNT            ((UINT32)604)
 #define VID_EXPAND_STRING           ((UINT32)605)
 #define VID_ACTION_LIST             ((UINT32)606)
+#define VID_ZONE_SNMP_PORT_COUNT    ((UINT32)607)
 
 // Base variabe for single threshold in message
 #define VID_THRESHOLD_BASE          ((UINT32)0x00800000)
@@ -1415,9 +1416,14 @@ typedef struct
 #define VID_EXP_STRING_BASE         ((UINT32)0x10000000)
 #define VID_IN_FIELD_BASE           ((UINT32)0x20000000)
 
-
 #define VID_ZMQ_SUBSCRIPTION_BASE   ((UINT32)0x10000000)
 
+// base value for SNMP community strings
+#define VID_COMMUNITY_STRING_LIST_BASE       ((UINT32)0x10000000)
+#define VID_COMMUNITY_STRING_ZONE_LIST_BASE  ((UINT32)0x20000000)
+
+#define VID_ZONE_SNMP_PORT_LIST_BASE         ((UINT32)0x10000000)
+
 #ifdef __cplusplus
 
 inline BOOL IsBinaryMsg(NXCP_MESSAGE *msg)
index bf9b672..e41c571 100644 (file)
@@ -215,6 +215,7 @@ CREATE TABLE zones
   id integer not null,    // Zone object ID
   zone_guid integer not null, // Globally unique ID for zone
   proxy_node integer not null,
+  snmp_ports integer null,
   PRIMARY KEY(id)
 ) TABLE_TYPE;
 
@@ -1291,6 +1292,7 @@ CREATE TABLE snmp_communities
 (
   id integer not null,
   community varchar(255) null,
+  zone integer not null,
   PRIMARY KEY(id)
 ) TABLE_TYPE;
 
@@ -1346,6 +1348,7 @@ CREATE TABLE usm_credentials
   priv_method integer not null,
   auth_password varchar(255),
   priv_password varchar(255),
+  zone integer not null,
   PRIMARY KEY(id)
 ) TABLE_TYPE;
 
index 290b369..3b0d877 100644 (file)
@@ -128,6 +128,7 @@ public class NXCObjectModificationData
    public static final int META_TYPE              = 76;
    public static final int SENSOR_PROXY           = 77;
    public static final int XML_CONFIG             = 78;
+   public static final int SNMP_PORT_LIST         = 79;
        
        private Set<Integer> fieldSet;
        private long objectId;
@@ -230,6 +231,7 @@ public class NXCObjectModificationData
    private String metaType;
    private long sensorProxy;
    private String xmlConfig;
+   private List<String> snmpPorts;
        
        /**
         * Constructor for creating modification data for given object
@@ -1932,4 +1934,23 @@ public class NXCObjectModificationData
       this.xmlConfig = xmlConfig;
       fieldSet.add(XML_CONFIG);
    }
+   
+   /**
+    * Update zone snmp port list
+    * @param snmpPorts to set
+    */
+   public void setSnmpPorts(List<String> snmpPorts)
+   {
+      this.snmpPorts = snmpPorts;
+      fieldSet.add(SNMP_PORT_LIST);
+   }
+   
+   /**
+    * Get the snmp port list
+    * @return snmp port list
+    */
+   public List<String> getSnmpPorts()
+   {
+      return snmpPorts;
+   }
 }
index e81b110..fdef4c4 100644 (file)
@@ -5117,6 +5117,15 @@ public class NXCSession
       {
          msg.setField(NXCPCodes.VID_XML_CONFIG, data.getXmlConfig());
       }
+      
+      if (data.isFieldSet(NXCObjectModificationData.SNMP_PORT_LIST))
+      {
+         msg.setFieldInt32(NXCPCodes.VID_ZONE_SNMP_PORT_COUNT, data.getSnmpPorts().size());
+         for(int i = 0; i < data.getSnmpPorts().size(); i++)
+         {
+            msg.setField(NXCPCodes.VID_ZONE_SNMP_PORT_LIST_BASE+i, data.getSnmpPorts().get(i));
+         }
+      }
             
       modifyCustomObject(data, userData, msg);
 
@@ -6553,46 +6562,57 @@ public class NXCSession
    /**
     * Get list of well-known SNMP communities configured on server.
     *
-    * @return List of SNMP community strings
+    * @return map of SNMP community strings
     * @throws IOException  if socket I/O error occurs
     * @throws NXCException if NetXMS server returns an error or operation was timed out
     */
-   public List<String> getSnmpCommunities() throws IOException, NXCException
+   public Map<Integer, List<String>> getSnmpCommunities() throws IOException, NXCException
    {
       final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_COMMUNITY_LIST);
       sendMessage(msg);
       final NXCPMessage response = waitForRCC(msg.getMessageId());
 
       int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_STRINGS);
-      ArrayList<String> list = new ArrayList<String>(count);
-      long varId = NXCPCodes.VID_STRING_LIST_BASE;
+      long stringBase = NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE, zoneBase = NXCPCodes.VID_COMMUNITY_STRING_ZONE_LIST_BASE;
+      Map<Integer, List<String>> map = new HashMap<Integer, List<String>>(count);
+      List<String> stringList = new ArrayList<String>();
+      int zoneId = 0;
       for(int i = 0; i < count; i++)
       {
-         list.add(response.getFieldAsString(varId++));
+         if (i != 0 && zoneId != response.getFieldAsInt32(zoneBase))
+         {
+            map.put(zoneId, stringList);
+            stringList = new ArrayList<String>();
+         }
+         stringList.add(response.getFieldAsString(stringBase++));
+         zoneId = response.getFieldAsInt32(zoneBase++);
       }
-
-      return list;
+      if (count > 0)
+         map.put(zoneId, stringList);
+      return map;
    }
 
    /**
     * Update list of well-known SNMP community strings on server. Existing list
     * will be replaced by given one.
     *
-    * @param list New list of SNMP community strings
+    * @param map New map of SNMP community strings
     * @throws IOException  if socket I/O error occurs
     * @throws NXCException if NetXMS server returns an error or operation was timed out
     */
-   public void updateSnmpCommunities(final List<String> list) throws IOException, NXCException
+   public void updateSnmpCommunities(final Map<Integer, List<String>> map) throws IOException, NXCException
    {
       final NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_COMMUNITY_LIST);
-
-      msg.setFieldInt32(NXCPCodes.VID_NUM_STRINGS, list.size());
-      long varId = NXCPCodes.VID_STRING_LIST_BASE;
-      for(int i = 0; i < list.size(); i++)
+      long stringBase = NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE, zoneBase = NXCPCodes.VID_COMMUNITY_STRING_ZONE_LIST_BASE;
+      for(Integer i : map.keySet())
       {
-         msg.setField(varId++, list.get(i));
+         for(String s : map.get(i))
+         {
+            msg.setField(stringBase++, s);
+            msg.setFieldInt32(zoneBase++, i);  
+         }
       }
-
+      msg.setFieldInt32(NXCPCodes.VID_NUM_STRINGS, (int)(stringBase - NXCPCodes.VID_COMMUNITY_STRING_LIST_BASE));
       sendMessage(msg);
       waitForRCC(msg.getMessageId());
    }
@@ -6601,25 +6621,37 @@ public class NXCSession
     * Get list of well-known SNMP USM (user security model) credentials
     * configured on server.
     *
-    * @return List of SNMP USM credentials
+    * @return Map of SNMP USM credentials
     * @throws IOException  if socket I/O error occurs
     * @throws NXCException if NetXMS server returns an error or operation was timed out
     */
-   public List<SnmpUsmCredential> getSnmpUsmCredentials() throws IOException, NXCException
+   public Map<Integer, List<SnmpUsmCredential>> getSnmpUsmCredentials() throws IOException, NXCException
    {
       final NXCPMessage msg = newMessage(NXCPCodes.CMD_GET_USM_CREDENTIALS);
       sendMessage(msg);
       final NXCPMessage response = waitForRCC(msg.getMessageId());
 
       int count = response.getFieldAsInt32(NXCPCodes.VID_NUM_RECORDS);
-      ArrayList<SnmpUsmCredential> list = new ArrayList<SnmpUsmCredential>(count);
+      Map<Integer, List<SnmpUsmCredential>> map = new HashMap<Integer, List<SnmpUsmCredential>>(count);
+      List<SnmpUsmCredential> credentials = new ArrayList<SnmpUsmCredential>();
       long varId = NXCPCodes.VID_USM_CRED_LIST_BASE;
+      SnmpUsmCredential cred;
+      int zoneId = 0;
       for(int i = 0; i < count; i++, varId += 10)
       {
-         list.add(new SnmpUsmCredential(response, varId));
+         cred = new SnmpUsmCredential(response, varId);
+         if (i != 0 && zoneId != cred.getZoneId())
+         {
+            map.put(zoneId, credentials);
+            credentials = new ArrayList<SnmpUsmCredential>();
+         }
+         credentials.add(cred);
+         zoneId = cred.getZoneId();
       }
+      if (count > 0)
+         map.put(zoneId, credentials);
 
-      return list;
+      return map;
    }
 
    /**
@@ -6630,17 +6662,24 @@ public class NXCSession
     * @throws IOException  if socket I/O error occurs
     * @throws NXCException if NetXMS server returns an error or operation was timed out
     */
-   public void updateSnmpUsmCredentials(final List<SnmpUsmCredential> list) throws IOException, NXCException
+   public void updateSnmpUsmCredentials(final Map<Integer, List<SnmpUsmCredential>> map) throws IOException, NXCException
    {
       final NXCPMessage msg = newMessage(NXCPCodes.CMD_UPDATE_USM_CREDENTIALS);
-
-      msg.setFieldInt32(NXCPCodes.VID_NUM_RECORDS, list.size());
       long varId = NXCPCodes.VID_USM_CRED_LIST_BASE;
-      for(int i = 0; i < list.size(); i++, varId += 10)
+      int count = 0, i;
+      for(List<SnmpUsmCredential> l : map.values())
       {
-         list.get(i).fillMessage(msg, varId);
+         if (l.isEmpty())
+            continue;
+         
+         for(i = 0; i < l.size(); i++, varId += 10)
+         {
+            l.get(i).fillMessage(msg, varId);
+         }
+         count += i;
       }
-
+      
+      msg.setFieldInt32(NXCPCodes.VID_NUM_RECORDS, count);      
       sendMessage(msg);
       waitForRCC(msg.getMessageId());
    }
index cc09247..ece0fd7 100644 (file)
@@ -18,6 +18,8 @@
  */
 package org.netxms.client.objects;
 
+import java.util.ArrayList;
+import java.util.List;
 import org.netxms.base.NXCPCodes;
 import org.netxms.base.NXCPMessage;
 import org.netxms.client.NXCSession;
@@ -29,6 +31,7 @@ public class Zone extends GenericObject
 {
        private long uin;
        private long proxyNodeId;
+       private List<String> snmpPorts;
        
        /**
         * Create zone object from NXCP message
@@ -41,6 +44,11 @@ public class Zone extends GenericObject
                super(msg, session);
                uin = msg.getFieldAsInt64(NXCPCodes.VID_ZONE_UIN);
                proxyNodeId = msg.getFieldAsInt64(NXCPCodes.VID_ZONE_PROXY);
+               snmpPorts = new ArrayList<String>(msg.getFieldAsInt32(NXCPCodes.VID_ZONE_SNMP_PORT_COUNT));
+               for(int i = 0; i < msg.getFieldAsInt32(NXCPCodes.VID_ZONE_SNMP_PORT_COUNT); i++)
+               {
+                  snmpPorts.add(msg.getFieldAsString(NXCPCodes.VID_ZONE_SNMP_PORT_LIST_BASE + i));
+               }
        }
 
        /* (non-Javadoc)
@@ -87,4 +95,13 @@ public class Zone extends GenericObject
        {
                return "Zone";
        }
+       
+       /**
+        * Get snmp ports
+        * @return snmp port list
+        */
+       public List<String> getSnmpPorts()
+       {
+          return snmpPorts;
+       }
 }
index 0956403..93857ef 100644 (file)
@@ -31,6 +31,7 @@ public class SnmpUsmCredential
        private int privMethod;
        private String authPassword;
        private String privPassword;
+       private int zoneId;
        
        /**
         * Create credentials object from data in NXCP message
@@ -45,6 +46,7 @@ public class SnmpUsmCredential
                privMethod = msg.getFieldAsInt32(baseId + 2);
                authPassword = msg.getFieldAsString(baseId + 3);
                privPassword = msg.getFieldAsString(baseId + 4);
+               zoneId = msg.getFieldAsInt32(baseId + 5);
        }
        
        /**
@@ -57,6 +59,7 @@ public class SnmpUsmCredential
                privMethod = 0;
                authPassword = "";
                privPassword = "";
+               zoneId = 0;
        }
        
        /**
@@ -72,6 +75,7 @@ public class SnmpUsmCredential
                msg.setFieldInt16(baseId + 2, privMethod);
                msg.setField(baseId + 3, authPassword);
                msg.setField(baseId + 4, privPassword);
+      msg.setFieldInt32(baseId + 5, zoneId);
        }
 
        /**
@@ -210,4 +214,22 @@ public class SnmpUsmCredential
                        return false;
                return true;
        }
+       
+       /**
+        * Get zone id of credential
+        * @return zone id
+        */
+       public int getZoneId()
+       {
+          return zoneId;
+       }
+       
+       /**
+        * Set zone if of credential
+        * @param zoneId to set
+        */
+       public void setZoneId(int zoneId)
+       {
+          this.zoneId = zoneId;
+       }
 }
index eda0e4b..fbac947 100644 (file)
@@ -30,7 +30,7 @@ import org.netxms.ui.eclipse.widgets.AbstractSelector;
  */
 public class ZoneSelector extends AbstractSelector
 {
-   private long zoneUIN = 0;
+   private long zoneUIN = -1;
    private String emptySelectionName = "<none>";
    
    /**
@@ -108,4 +108,14 @@ public class ZoneSelector extends AbstractSelector
          setText((zone != null) ? zone.getObjectName() : ("<" + Long.toString(zoneUIN) + ">")); //$NON-NLS-1$ //$NON-NLS-2$
       }
    }
+   
+   /**
+    * Set empty selection text
+    * @param text to set
+    */
+   public void setEmptySelectionText(String text)
+   {
+      emptySelectionName = text;
+      setText(emptySelectionName);
+   }
 }
index a96ad20..7446971 100644 (file)
@@ -29,6 +29,8 @@ import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
@@ -49,6 +51,7 @@ import org.netxms.client.NXCSession;
 import org.netxms.client.snmp.SnmpUsmCredential;
 import org.netxms.ui.eclipse.console.resources.SharedIcons;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
+import org.netxms.ui.eclipse.objectbrowser.widgets.ZoneSelector;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
 import org.netxms.ui.eclipse.snmp.Activator;
 import org.netxms.ui.eclipse.snmp.Messages;
@@ -75,6 +78,8 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
        private TableViewer snmpPortList;
        private Action actionSave;
        private SnmpConfig config;
+       private ZoneSelector zoneSelector;
+       private long zoneUIN = SnmpConfig.SNMP_CONFIG_GLOBAL;
 
        /* (non-Javadoc)
     * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
@@ -94,12 +99,36 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
        {
                toolkit = new FormToolkit(getSite().getShell().getDisplay());
                form = toolkit.createScrolledForm(parent);
-               form.setText(Messages.get().SnmpCredentials_FormTitle);
-
+      form.setText(Messages.get().SnmpCredentials_FormTitle);
+       
                TableWrapLayout layout = new TableWrapLayout();
                layout.numColumns = 2;
                form.getBody().setLayout(layout);
-               
+
+               if (session.isZoningEnabled())
+               {
+         toolkit.decorateFormHeading(form.getForm());
+               Composite headArea = toolkit.createComposite(form.getForm().getHead());
+               headArea.setLayout(new GridLayout());
+         zoneSelector = new ZoneSelector(headArea, SWT.NONE, true);
+         zoneSelector.setEmptySelectionText("Global");
+         zoneSelector.setLabel("Select zone");
+   
+         GridData gd = new GridData();
+         gd.widthHint = 300;
+         zoneSelector.setLayoutData(gd);
+         form.setHeadClient(headArea);
+         zoneSelector.addModifyListener(new ModifyListener() {
+            
+            @Override
+            public void modifyText(ModifyEvent e)
+            {
+               zoneUIN = zoneSelector.getZoneUIN();
+               loadSnmpConfig();
+            }
+         });
+               }
+      
                createSnmpCommunitySection();
                createSnmpUsmCredSection();
                createSnmpPortList();
@@ -108,7 +137,16 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                contributeToActionBars();
 
       // Load config
-      new ConsoleJob(Messages.get().SnmpCredentials_LoadingConfig, this, Activator.PLUGIN_ID, null) {
+      loadSnmpConfig();
+       }
+       
+       /**
+        * Load SNMP config
+        * @param zoneUIN of config
+        */
+       private void loadSnmpConfig()
+       {
+          new ConsoleJob(Messages.get().SnmpCredentials_LoadingConfig, this, Activator.PLUGIN_ID, null) {
          @Override
          protected void runInternal(IProgressMonitor monitor) throws Exception
          {
@@ -373,14 +411,13 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
        /**
         * @param config
         */
-       public void setConfig(SnmpConfig config)
+       private void setConfig(SnmpConfig config)
        {
-               this.config = config;           
+               this.config = config;
+               snmpCommunityList.setInput(config.getCommunities(zoneUIN));
+               snmpUsmCredList.setInput(config.getUsmCredentials(zoneUIN));
+               snmpPortList.setInput(config.getPorts(zoneUIN));
                
-               snmpCommunityList.setInput(config.getCommunities().toArray());
-               snmpUsmCredList.setInput(config.getUsmCredentials().toArray());
-      snmpPortList.setInput(config.getPorts().toArray());
-
                modified = false;
                firePropertyChange(PROP_DIRTY);
        }
@@ -487,13 +524,9 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                if (dlg.open() == Window.OK)
                {
                        String s = dlg.getValue();
-                       final List<String> list = config.getCommunities();
-                       if (!list.contains(s))
-                       {
-                               list.add(s);
-                               snmpCommunityList.setInput(list.toArray());
-                               setModified();
-                       }
+                       config.addCommunityString(s, zoneUIN);
+         snmpCommunityList.setInput(config.getCommunities(zoneUIN));
+         setModified();
                }
        }
        
@@ -502,7 +535,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
         */
        private void removeCommunity()
        {
-               final List<String> list = config.getCommunities();
+               final List<String> list = config.getCommunities(zoneUIN);
                IStructuredSelection selection = (IStructuredSelection)snmpCommunityList.getSelection();
                if (selection.size() > 0)
                {
@@ -510,7 +543,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                        {
                                list.remove(o);
                        }
-                       snmpCommunityList.setInput(list.toArray());
+                       snmpCommunityList.setInput(list);
                        setModified();
                }
        }
@@ -524,13 +557,10 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                if (dlg.open() == Window.OK)
                {
                        SnmpUsmCredential cred = dlg.getValue();
-                       final List<SnmpUsmCredential> list = config.getUsmCredentials();
-                       if (!list.contains(cred))
-                       {
-                               list.add(cred);
-                               snmpUsmCredList.setInput(list.toArray());
-                               setModified();
-                       }
+                       cred.setZoneId((int)zoneUIN);
+         config.addUsmCredentials(cred, zoneUIN);
+         snmpUsmCredList.setInput(config.getUsmCredentials(zoneUIN));
+         setModified();
                }
        }
        
@@ -539,7 +569,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
         */
        private void removeUsmCredentials()
        {
-               final List<SnmpUsmCredential> list = config.getUsmCredentials();
+               final List<SnmpUsmCredential> list = config.getUsmCredentials(zoneUIN);
                IStructuredSelection selection = (IStructuredSelection)snmpUsmCredList.getSelection();
                if (selection.size() > 0)
                {
@@ -562,13 +592,9 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
       if (dlg.open() == Window.OK)
       {
          String value = dlg.getValue();
-         final List<String> list = config.getPorts();
-         if (!list.contains(value))
-         {
-            list.add(value);
-            snmpPortList.setInput(list.toArray());
-            setModified();
-         }
+         config.addPort(value, zoneUIN);
+         snmpPortList.setInput(config.getPorts(zoneUIN));
+         setModified();
       }
    }
    
@@ -577,7 +603,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
     */
    private void removeSnmpPort()
    {
-      final List<String> list = config.getPorts();
+      final List<String> list = config.getPorts(zoneUIN);
       IStructuredSelection selection = (IStructuredSelection)snmpPortList.getSelection();
       if (selection.size() > 0)
       {
index a010cad..08ec0c3 100644 (file)
@@ -3,18 +3,24 @@ package org.netxms.ui.eclipse.snmp.views.helpers;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import org.netxms.client.NXCException;
+import org.netxms.client.NXCObjectModificationData;
 import org.netxms.client.NXCSession;
+import org.netxms.client.objects.Zone;
 import org.netxms.client.server.ServerVariable;
 import org.netxms.client.snmp.SnmpUsmCredential;
 
 public class SnmpConfig
 {
-   private List<String> communities;
-   private List<SnmpUsmCredential> usmCredentials;
-   private List<String> ports;
+   // Global SNMP config flag
+   public static int SNMP_CONFIG_GLOBAL = -1;
+   
+   private Map<Integer, List<String>> communities;
+   private Map<Integer, List<SnmpUsmCredential>> usmCredentials;
+   private Map<Integer, List<String>> ports;
 
    /**
     * Create empty object
@@ -38,31 +44,48 @@ public class SnmpConfig
       
       config.communities = session.getSnmpCommunities();
       config.usmCredentials = session.getSnmpUsmCredentials();
-      Map<String, ServerVariable> variables = session.getServerVariables();
-      ServerVariable v = variables.get("SNMPPorts"); //$NON-NLS-1$
-      config.ports = parsePorts(v != null ? v.getValue() : "" ); //$NON-NLS-1$
+      config.ports = loadPortConfig(session);
 
       return config;
    }
    
+   private static Map<Integer, List<String>> loadPortConfig(NXCSession session) throws IOException, NXCException
+   {
+      List<Zone> zones = session.getAllZones();
+      Map<Integer, List<String>> ports = new HashMap<Integer, List<String>>();
+      for (Zone z : zones)
+      {
+         if (!z.getSnmpPorts().isEmpty())
+            ports.put((int)z.getUIN(), z.getSnmpPorts());
+      }
+      Map<String, ServerVariable> variables = session.getServerVariables();
+      ServerVariable v = variables.get("SNMPPorts"); //$NON-NLS-1$
+      parsePorts(v != null ? v.getValue() : "", ports); //$NON-NLS-1$
+      
+      return ports;
+   }
+   
    /**
     * 
     * @param portList
     */
-   public static List<String> parsePorts(String portList)
+   private static void parsePorts(String portList, Map<Integer, List<String>> ports)
    {
-      String[] arr = portList.split(","); //$NON-NLS-1$
-      List<String> list = new ArrayList<String>(Arrays.asList(arr));
-      return list;      
+      List<String> list = new ArrayList<String>(Arrays.asList(portList.split(",")));
+      ports.put(SNMP_CONFIG_GLOBAL, list);      
    }
    
    public String parsePorts() 
    {
       StringBuilder str = new StringBuilder();
-      for(int i = 0; i < ports.size(); i++)
+      List<String> list = ports.get(SNMP_CONFIG_GLOBAL);
+      if (list == null)
+         return "";
+      
+      for(int i = 0; i < list.size(); i++)
       {
-         str.append(ports.get(i));
-         if(i != ports.size() - 1)
+         str.append(list.get(i));
+         if(i != list.size() - 1)
          {
             str.append(",");             //$NON-NLS-1$
          }
@@ -81,55 +104,97 @@ public class SnmpConfig
    {
       session.updateSnmpCommunities(communities);
       session.updateSnmpUsmCredentials(usmCredentials);
+      savePortConfig(session);
+   }
+   
+   private void savePortConfig(final NXCSession session) throws IOException, NXCException
+   {
       session.setServerVariable("SNMPPorts", parsePorts()); //$NON-NLS-1$
+      for(Integer i : ports.keySet())
+      {
+         if (ports.get(i).isEmpty() || session.findZone(i) == null)
+            continue;
+         final NXCObjectModificationData data = new NXCObjectModificationData(session.findZone(i).getObjectId());
+         data.setSnmpPorts(ports.get(i));
+         session.modifyObject(data);
+      }
    }
    
    /**
     * @return the communities
     */
-   public List<String> getCommunities()
+   public List<String> getCommunities(long zoneUIN)
    {
-      return communities;
+      if (communities.containsKey((int)zoneUIN))
+         return communities.get((int)zoneUIN);
+      else
+         return new ArrayList<String>();
    }
 
    /**
     * @param communities the communities to set
     */
-   public void setCommunities(List<String> communities)
+   public void addCommunityString(String communityString, long zoneUIN)
    {
-      this.communities = communities;
+      if (this.communities.containsKey((int)zoneUIN))
+         this.communities.get((int)zoneUIN).add(communityString);
+      else
+      {
+         List<String> list = new ArrayList<String>();
+         list.add(communityString);
+         this.communities.put((int)zoneUIN, list);
+      }
    }
    
    /**
     * @return the ports
     */
-   public List<String> getPorts()
+   public List<String> getPorts(long zoneUIN)
    {
-      return ports;
+      if (ports.containsKey((int)zoneUIN))
+         return ports.get((int)zoneUIN);
+      else
+         return new ArrayList<String>();
    }
    
    /**
     * @param communities the communities to set
     */
-   public void setPorts(List<String> ports)
+   public void addPort(String port, long zoneUIN)
    {
-      this.ports = ports;
+      if (this.ports.containsKey((int)zoneUIN))
+         this.ports.get((int)zoneUIN).add(port);
+      else
+      {
+         List<String> list = new ArrayList<String>();
+         list.add(port);
+         this.ports.put((int)zoneUIN, list);
+      }
    }
 
    /**
     * @return the usmCredentials
     */
-   public List<SnmpUsmCredential> getUsmCredentials()
+   public List<SnmpUsmCredential> getUsmCredentials(long zoneUIN)
    {
-      return usmCredentials;
+      if (usmCredentials.containsKey((int)zoneUIN))
+         return usmCredentials.get((int)zoneUIN);
+      else
+         return new ArrayList<SnmpUsmCredential>();
    }
 
    /**
     * @param usmCredentials the usmCredentials to set
     */
-   public void setUsmCredentials(List<SnmpUsmCredential> usmCredentials)
+   public void addUsmCredentials(SnmpUsmCredential credential, long zoneUIN)
    {
-      this.usmCredentials = usmCredentials;
-   }
-   
+      if (usmCredentials.containsKey((int)zoneUIN))
+         usmCredentials.get((int)zoneUIN).add(credential);
+      else
+      {
+         List<SnmpUsmCredential> list = new ArrayList<SnmpUsmCredential>();
+         list.add(credential);
+         usmCredentials.put((int)zoneUIN, list);
+      }
+   }   
 }
index f06eae9..2227c92 100644 (file)
@@ -994,6 +994,7 @@ public class NXCPCodes
    public static final long VID_STRING_COUNT = 604;
    public static final long VID_EXPAND_STRING = 605;
    public static final long VID_ACTION_LIST = 606;
+   public static final long VID_ZONE_SNMP_PORT_COUNT = 607;
 
        public static final long VID_ACL_USER_BASE = 0x00001000L;
        public static final long VID_ACL_USER_LAST = 0x00001FFFL;
@@ -1087,4 +1088,7 @@ public class NXCPCodes
    public static final long VID_EXP_STRING_BASE= 0x10000000L;
    public static final long VID_IN_FIELD_BASE= 0x20000000L;
    public static final long VID_ZMQ_SUBSCRIPTION_BASE= 0x10000000L;
+   public static final long VID_COMMUNITY_STRING_LIST_BASE= 0x10000000L;
+   public static final long VID_COMMUNITY_STRING_ZONE_LIST_BASE= 0x20000000L;
+   public static final long VID_ZONE_SNMP_PORT_LIST_BASE= 0x10000000L;
 }
index 350c670..e743db6 100644 (file)
@@ -2806,7 +2806,7 @@ bool Node::confPollSnmp(UINT32 rqId)
    oids.add(_T(".1.3.6.1.2.1.1.2.0"));
    oids.add(_T(".1.3.6.1.2.1.1.1.0"));
    AddDriverSpecificOids(&oids);
-   SNMP_Transport *pTransport = SnmpCheckCommSettings(getEffectiveSnmpProxy(), (getEffectiveSnmpProxy() == m_id) ? InetAddress::LOOPBACK : m_ipAddress, &m_snmpVersion, m_snmpPort, m_snmpSecurity, &oids);
+   SNMP_Transport *pTransport = SnmpCheckCommSettings(getEffectiveSnmpProxy(), (getEffectiveSnmpProxy() == m_id) ? InetAddress::LOOPBACK : m_ipAddress, &m_snmpVersion, m_snmpPort, m_snmpSecurity, &oids, m_zoneUIN);
    if (pTransport == NULL)
    {
       DbgPrintf(5, _T("ConfPoll(%s): unable to create SNMP transport"), m_name);
index 2fac7a9..77e67c1 100644 (file)
@@ -385,7 +385,7 @@ static bool HostIsReachable(const InetAddress& ipAddr, UINT32 zoneUIN, bool full
    oids.add(_T(".1.3.6.1.2.1.1.2.0"));
    oids.add(_T(".1.3.6.1.2.1.1.1.0"));
    AddDriverSpecificOids(&oids);
-   SNMP_Transport *pTransport = SnmpCheckCommSettings(snmpProxy, ipAddr, &version, 0, NULL, &oids);
+   SNMP_Transport *pTransport = SnmpCheckCommSettings(snmpProxy, ipAddr, &version, 0, NULL, &oids, zoneUIN);
    //pass correct port
    if (pTransport != NULL)
    {
index 48c3a15..5c60a18 100644 (file)
@@ -318,6 +318,10 @@ NXSL_Value *NXSL_ZoneClass::getAttr(NXSL_Object *object, const TCHAR *attr)
    {
       value = new NXSL_Value(zone->getUIN());
    }
+   else if (!_tcscmp(attr, _T("snmpPorts")))
+   {
+      value = new NXSL_Value(new NXSL_Array(zone->getSnmpPortList()));
+   }
    return value;
 }
 
index 2294f04..b9997ec 100644 (file)
@@ -10157,8 +10157,6 @@ void ClientSession::sendSMS(NXCPMessage *pRequest)
 void ClientSession::SendCommunityList(UINT32 dwRqId)
 {
    NXCPMessage msg;
-       int i, count;
-       UINT32 id;
        TCHAR buffer[256];
        DB_RESULT hResult;
 
@@ -10168,15 +10166,17 @@ void ClientSession::SendCommunityList(UINT32 dwRqId)
        if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
        {
       DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-               hResult = DBSelect(hdb, _T("SELECT community FROM snmp_communities"));
+               hResult = DBSelect(hdb, _T("SELECT community,zone FROM snmp_communities ORDER BY zone"));
                if (hResult != NULL)
                {
-                       count = DBGetNumRows(hResult);
+                       int count = DBGetNumRows(hResult);
+                       UINT32 stringBase = VID_COMMUNITY_STRING_LIST_BASE, zoneBase = VID_COMMUNITY_STRING_ZONE_LIST_BASE;
                        msg.setField(VID_NUM_STRINGS, (UINT32)count);
-                       for(i = 0, id = VID_STRING_LIST_BASE; i < count; i++)
+                       for(int i = 0; i < count; i++)
                        {
                                DBGetField(hResult, i, 0, buffer, 256);
-                               msg.setField(id++, buffer);
+                               msg.setField(stringBase++, buffer);
+                               msg.setField(zoneBase++, DBGetFieldULong(hResult, i, 1));
                        }
                        DBFreeResult(hResult);
                        msg.setField(VID_RCC, RCC_SUCCESS);
@@ -10201,9 +10201,7 @@ void ClientSession::SendCommunityList(UINT32 dwRqId)
 void ClientSession::UpdateCommunityList(NXCPMessage *pRequest)
 {
    NXCPMessage msg;
-       TCHAR value[256], query[1024];
-       int i, count;
-       UINT32 id;
+       UINT32 rcc = RCC_SUCCESS;
 
        msg.setId(pRequest->getId());
        msg.setCode(CMD_REQUEST_COMPLETED);
@@ -10214,38 +10212,40 @@ void ClientSession::UpdateCommunityList(NXCPMessage *pRequest)
                if (DBBegin(hdb))
                {
                        DBQuery(hdb, _T("DELETE FROM snmp_communities"));
-                       count = pRequest->getFieldAsUInt32(VID_NUM_STRINGS);
-                       for(i = 0, id = VID_STRING_LIST_BASE; i < count; i++)
+         UINT32 stringBase = VID_COMMUNITY_STRING_LIST_BASE, zoneBase = VID_COMMUNITY_STRING_ZONE_LIST_BASE;
+                       DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO snmp_communities (id,community,zone) VALUES(?,?,?)"));
+                       if (hStmt != NULL)
                        {
-                               pRequest->getFieldAsString(id++, value, 256);
-                               String escValue = DBPrepareString(hdb, value);
-                               _sntprintf(query, 1024, _T("INSERT INTO snmp_communities (id,community) VALUES(%d,%s)"), i + 1, (const TCHAR *)escValue);
-                               if (!DBQuery(hdb, query))
-                                       break;
+                int count = pRequest->getFieldAsUInt32(VID_NUM_STRINGS);
+                for(int i = 0; i < count; i++)
+                {
+               DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, i + 1);
+                   DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, pRequest->getFieldAsString(stringBase++), DB_BIND_DYNAMIC);
+               DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, pRequest->getFieldAsUInt32(zoneBase++));
+                   if (!DBExecute(hStmt))
+                   {
+                      rcc = RCC_DB_FAILURE;
+                      break;
+                   }
+                }
+                          DBFreeStatement(hStmt);
                        }
+                       else
+                          rcc = RCC_DB_FAILURE;
 
-                       if (i == count)
-                       {
+                       if (rcc == RCC_SUCCESS)
                                DBCommit(hdb);
-                               msg.setField(VID_RCC, RCC_SUCCESS);
-                       }
                        else
-                       {
                                DBRollback(hdb);
-                               msg.setField(VID_RCC, RCC_DB_FAILURE);
-                       }
                }
                else
-               {
-                       msg.setField(VID_RCC, RCC_DB_FAILURE);
-               }
+                  rcc = RCC_DB_FAILURE;
       DBConnectionPoolReleaseConnection(hdb);
        }
        else
-       {
-               msg.setField(VID_RCC, RCC_ACCESS_DENIED);
-       }
+               rcc = RCC_ACCESS_DENIED;
 
+       msg.setField(VID_RCC, rcc);
        sendMessage(&msg);
 }
 
@@ -11233,12 +11233,12 @@ void ClientSession::sendUsmCredentials(UINT32 dwRqId)
        if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
        {
           DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-               hResult = DBSelect(hdb, _T("SELECT user_name,auth_method,priv_method,auth_password,priv_password FROM usm_credentials"));
+               hResult = DBSelect(hdb, _T("SELECT user_name,auth_method,priv_method,auth_password,priv_password,zone FROM usm_credentials ORDER BY zone"));
                if (hResult != NULL)
                {
                        count = DBGetNumRows(hResult);
                        msg.setField(VID_NUM_RECORDS, (UINT32)count);
-                       for(i = 0, id = VID_USM_CRED_LIST_BASE; i < count; i++, id += 5)
+                       for(i = 0, id = VID_USM_CRED_LIST_BASE; i < count; i++, id += 4)
                        {
                                DBGetField(hResult, i, 0, buffer, MAX_DB_STRING);       // security name
                                msg.setField(id++, buffer);
@@ -11251,6 +11251,8 @@ void ClientSession::sendUsmCredentials(UINT32 dwRqId)
 
                                DBGetField(hResult, i, 4, buffer, MAX_DB_STRING);       // priv password
                                msg.setField(id++, buffer);
+
+                               msg.setField(id++, DBGetFieldULong(hResult, i, 5)); // zone ID
                        }
                        DBFreeResult(hResult);
                        msg.setField(VID_RCC, RCC_SUCCESS);
@@ -11278,58 +11280,57 @@ void ClientSession::updateUsmCredentials(NXCPMessage *request)
 
        msg.setId(request->getId());
        msg.setCode(CMD_REQUEST_COMPLETED);
+   UINT32 rcc = RCC_SUCCESS;
 
        if (m_dwSystemAccess & SYSTEM_ACCESS_SERVER_CONFIG)
        {
                DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
                if (DBBegin(hdb))
                {
-                       TCHAR query[4096];
-                       UINT32 id;
-                       int i = -1;
-                       int count = (int)request->getFieldAsUInt32(VID_NUM_RECORDS);
 
                        if (DBQuery(hdb, _T("DELETE FROM usm_credentials")))
                        {
-                               for(i = 0, id = VID_USM_CRED_LIST_BASE; i < count; i++, id += 5)
-                               {
-                                       TCHAR name[MAX_DB_STRING], authPasswd[MAX_DB_STRING], privPasswd[MAX_DB_STRING];
-
-                                       request->getFieldAsString(id++, name, MAX_DB_STRING);
-                                       int authMethod = (int)request->getFieldAsUInt16(id++);
-                                       int privMethod = (int)request->getFieldAsUInt16(id++);
-                                       request->getFieldAsString(id++, authPasswd, MAX_DB_STRING);
-                                       request->getFieldAsString(id++, privPasswd, MAX_DB_STRING);
-                                       _sntprintf(query, 4096, _T("INSERT INTO usm_credentials (id,user_name,auth_method,priv_method,auth_password,priv_password) VALUES(%d,%s,%d,%d,%s,%s)"),
-                                                                 i + 1, (const TCHAR *)DBPrepareString(hdb, name), authMethod, privMethod,
-                                                                 (const TCHAR *)DBPrepareString(hdb, authPasswd), (const TCHAR *)DBPrepareString(hdb, privPasswd));
-                                       if (!DBQuery(hdb, query))
-                                               break;
-                               }
+                          DB_STATEMENT hStmt = DBPrepare(hdb, _T("INSERT INTO usm_credentials (id,user_name,auth_method,priv_method,auth_password,priv_password,zone) VALUES(?,?,?,?,?,?,?)"));
+                          if (hStmt != NULL)
+                          {
+                        UINT32 id;
+                        int count = (int)request->getFieldAsUInt32(VID_NUM_RECORDS);
+               for(int i = 0, id = VID_USM_CRED_LIST_BASE; i < count; i++, id += 4)
+               {
+                  DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, i+1);
+                  DBBind(hStmt, 2, DB_SQLTYPE_VARCHAR, request->getFieldAsString(id++), DB_BIND_DYNAMIC);
+                  DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, (int)request->getFieldAsUInt16(id++)); // Auth method
+                  DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, (int)request->getFieldAsUInt16(id++)); // Priv method
+                  DBBind(hStmt, 5, DB_SQLTYPE_VARCHAR, request->getFieldAsString(id++), DB_BIND_DYNAMIC);
+                  DBBind(hStmt, 6, DB_SQLTYPE_VARCHAR, request->getFieldAsString(id++), DB_BIND_DYNAMIC);
+                  DBBind(hStmt, 7, DB_SQLTYPE_INTEGER, (int)request->getFieldAsUInt32(id++));
+                  if (!DBExecute(hStmt))
+                  {
+                     rcc = RCC_DB_FAILURE;
+                     break;
+                  }
+               }
+               DBFreeStatement(hStmt);
+                          }
+                else
+                   rcc = RCC_DB_FAILURE;
                        }
+         else
+            rcc = RCC_DB_FAILURE;
 
-                       if (i == count)
-                       {
-                               DBCommit(hdb);
-                               msg.setField(VID_RCC, RCC_SUCCESS);
-                       }
-                       else
-                       {
-                               DBRollback(hdb);
-                               msg.setField(VID_RCC, RCC_DB_FAILURE);
-                       }
-               }
-               else
-               {
-                       msg.setField(VID_RCC, RCC_DB_FAILURE);
+                       if (rcc == RCC_SUCCESS)
+            DBCommit(hdb);
+         else
+            DBRollback(hdb);
                }
+      else
+         rcc = RCC_DB_FAILURE;
                DBConnectionPoolReleaseConnection(hdb);
        }
        else
-       {
-               msg.setField(VID_RCC, RCC_ACCESS_DENIED);
-       }
+      rcc = RCC_ACCESS_DENIED;
 
+   msg.setField(VID_RCC, rcc);
        sendMessage(&msg);
 }
 
index 4e00653..4935fa9 100644 (file)
@@ -163,7 +163,7 @@ static bool SnmpTestRequest(SNMP_Transport *snmp, StringList *testOids)
 /**
  * Check SNMP v3 connectivity
  */
-bool SnmpCheckV3CommSettings(SNMP_Transport *pTransport, SNMP_SecurityContext *originalContext, StringList *testOids, const TCHAR *id)
+bool SnmpCheckV3CommSettings(SNMP_Transport *pTransport, SNMP_SecurityContext *originalContext, StringList *testOids, const TCHAR *id, UINT32 zoneUIN)
 {
    pTransport->setSnmpVersion(SNMP_VERSION_3);
 
@@ -182,50 +182,63 @@ bool SnmpCheckV3CommSettings(SNMP_Transport *pTransport, SNMP_SecurityContext *o
 
        // Try pre-configured SNMP v3 USM credentials
    DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-       DB_RESULT hResult = DBSelect(hdb, _T("SELECT user_name,auth_method,priv_method,auth_password,priv_password FROM usm_credentials"));
-       if (hResult != NULL)
-       {
-               int count = DBGetNumRows(hResult);
-               ObjectArray<SNMP_SecurityContext> contexts(count, 16, false);
-      for(int i = 0; i < count; i++)
+   DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT user_name,auth_method,priv_method,auth_password,priv_password FROM usm_credentials WHERE zone=? OR zone=?"));
+   if (hStmt != NULL)
+   {
+      DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, zoneUIN);
+      DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, SNMP_CONFIG_GLOBAL);
+      DB_RESULT hResult = DBSelectPrepared(hStmt);
+      if (hResult != NULL)
       {
-         char name[MAX_DB_STRING], authPasswd[MAX_DB_STRING], privPasswd[MAX_DB_STRING];
-         DBGetFieldA(hResult, i, 0, name, MAX_DB_STRING);
-         DBGetFieldA(hResult, i, 3, authPasswd, MAX_DB_STRING);
-         DBGetFieldA(hResult, i, 4, privPasswd, MAX_DB_STRING);
-         contexts.add(new SNMP_SecurityContext(name, authPasswd, privPasswd, DBGetFieldLong(hResult, i, 1), DBGetFieldLong(hResult, i, 2)));
-      }
+         int count = DBGetNumRows(hResult);
+         ObjectArray<SNMP_SecurityContext> contexts(count, 16, false);
+         for(int i = 0; i < count; i++)
+         {
+            char name[MAX_DB_STRING], authPasswd[MAX_DB_STRING], privPasswd[MAX_DB_STRING];
+            DBGetFieldA(hResult, i, 0, name, MAX_DB_STRING);
+            DBGetFieldA(hResult, i, 3, authPasswd, MAX_DB_STRING);
+            DBGetFieldA(hResult, i, 4, privPasswd, MAX_DB_STRING);
+            contexts.add(new SNMP_SecurityContext(name, authPasswd, privPasswd, DBGetFieldLong(hResult, i, 1), DBGetFieldLong(hResult, i, 2)));
+         }
 
-      DBFreeResult(hResult);
-      DBConnectionPoolReleaseConnection(hdb);
+         DBFreeResult(hResult);
+         DBConnectionPoolReleaseConnection(hdb);
 
-      bool found = false;
-               for(int i = 0; (i < contexts.size()) && !found && !IsShutdownInProgress(); i++)
-               {
-                  SNMP_SecurityContext *ctx = contexts.get(i);
-                       pTransport->setSecurityContext(ctx);
-                       DbgPrintf(5, _T("SnmpCheckV3CommSettings(%s): trying %hs/%d:%d"), id, ctx->getUser(), ctx->getAuthMethod(), ctx->getPrivMethod());
-                       if (SnmpTestRequest(pTransport, testOids))
+         bool found = false;
+         for(int i = 0; (i < contexts.size()) && !found && !IsShutdownInProgress(); i++)
          {
-            DbgPrintf(5, _T("SnmpCheckV3CommSettings(%s): success"), id);
-            found = true;
+            SNMP_SecurityContext *ctx = contexts.get(i);
+            pTransport->setSecurityContext(ctx);
+            DbgPrintf(5, _T("SnmpCheckV3CommSettings(%s): trying %hs/%d:%d"), id, ctx->getUser(), ctx->getAuthMethod(), ctx->getPrivMethod());
+            if (SnmpTestRequest(pTransport, testOids))
+            {
+               DbgPrintf(5, _T("SnmpCheckV3CommSettings(%s): success"), id);
+               found = true;
 
-            // Delete unused contexts
-            for(int j = i + 1; j < contexts.size(); j++)
-               delete contexts.get(j);
+               // Delete unused contexts
+               for(int j = i + 1; j < contexts.size(); j++)
+                  delete contexts.get(j);
 
-            break;
+               break;
+            }
          }
-               }
 
-               if (found)
-                       return true;
-       }
-       else
-       {
+         if (found)
+            return true;
+      }
+      else
+      {
+         DBConnectionPoolReleaseConnection(hdb);
+         DbgPrintf(3, _T("SnmpCheckV3CommSettings(%s): DBSelect() failed"), id);
+      }
+
+      DBFreeStatement(hStmt);
+   }
+   else
+   {
       DBConnectionPoolReleaseConnection(hdb);
-               DbgPrintf(3, _T("SnmpCheckV3CommSettings(%s): DBSelect() failed"), id);
-       }
+      DbgPrintf(3, _T("SnmpCheckV3CommSettings(%s): DBPrepare() failed"), id);
+   }
 
        DbgPrintf(5, _T("SnmpCheckV3CommSettings(%s): failed"), id);
        return false;
@@ -236,7 +249,7 @@ bool SnmpCheckV3CommSettings(SNMP_Transport *pTransport, SNMP_SecurityContext *o
  * On success, returns new security context object (dynamically created).
  * On failure, returns NULL
  */
-SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAddr, INT16 *version, UINT16 originalPort, SNMP_SecurityContext *originalContext, StringList *testOids)
+SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAddr, INT16 *version, UINT16 originalPort, SNMP_SecurityContext *originalContext, StringList *testOids, UINT32 zoneUIN)
 {
    DbgPrintf(5, _T("SnmpCheckCommSettings(%s): starting check (proxy=%d, originalPort=%d)"), (const TCHAR *)ipAddr.toString(), snmpProxy, (int)originalPort);
 
@@ -246,6 +259,9 @@ SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAdd
    TCHAR tmp[MAX_CONFIG_VALUE];
        ConfigReadStr(_T("SNMPPorts"), tmp, MAX_CONFIG_VALUE, _T("161"));
    StringList *ports = new StringList(tmp, _T(","));
+   Zone *zone = FindZoneByUIN(zoneUIN);
+   if (zone != NULL)
+      ports->addAll(zone->getSnmpPortList());
    for(int j = -1; (j < ports->size()) && !IsShutdownInProgress(); j++)
    {
       UINT16 port;
@@ -288,7 +304,7 @@ SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAdd
       }
 
       // Check for V3 USM
-      if (SnmpCheckV3CommSettings(pTransport, originalContext, testOids, (const TCHAR *)ipAddr.toString()))
+      if (SnmpCheckV3CommSettings(pTransport, originalContext, testOids, (const TCHAR *)ipAddr.toString(), zoneUIN))
       {
          *version = SNMP_VERSION_3;
          goto success;
@@ -320,13 +336,21 @@ restart_check:
       {
          communities = new StringList();
          DB_HANDLE hdb = DBConnectionPoolAcquireConnection();
-         DB_RESULT hResult = DBSelect(hdb, _T("SELECT community FROM snmp_communities"));
-         if (hResult != NULL)
+         DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT community FROM snmp_communities WHERE zone=? OR zone=?"));
+         if (hStmt != NULL)
          {
-            int count = DBGetNumRows(hResult);
-            for(int i = 0; i < count; i++)
-               communities->addPreallocated(DBGetField(hResult, i, 0, NULL, 0));
-            DBFreeResult(hResult);
+            DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, zoneUIN);
+            DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, SNMP_CONFIG_GLOBAL);
+
+            DB_RESULT hResult = DBSelectPrepared(hStmt);
+            if (hResult != NULL)
+            {
+               int count = DBGetNumRows(hResult);
+               for(int i = 0; i < count; i++)
+                  communities->addPreallocated(DBGetField(hResult, i, 0, NULL, 0));
+               DBFreeResult(hResult);
+            }
+            DBFreeStatement(hStmt);
          }
          DBConnectionPoolReleaseConnection(hdb);
       }
index 64cceff..4f2aead 100644 (file)
@@ -75,36 +75,46 @@ bool Zone::loadFromDatabase(DB_HANDLE hdb, UINT32 dwId)
    if (!loadCommonProperties(hdb))
       return false;
 
-   TCHAR szQuery[256];
-   _sntprintf(szQuery, 256, _T("SELECT zone_guid,proxy_node FROM zones WHERE id=%d"), dwId);
-   DB_RESULT hResult = DBSelect(hdb, szQuery);
-   if (hResult == NULL)
-      return false;     // Query failed
-
-   if (DBGetNumRows(hResult) == 0)
+   DB_STATEMENT hStmt = DBPrepare(hdb, _T("SELECT zone_guid,proxy_node,snmp_ports FROM zones WHERE id=?"));
+   if (hStmt != NULL)
    {
-      DBFreeResult(hResult);
-      if (dwId == BUILTIN_OID_ZONE0)
-      {
-         m_uin = 0;
-         return true;
-      }
-      else
+      DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, dwId);
+      DB_RESULT hResult = DBSelectPrepared(hStmt);
+      if (hResult != NULL)
       {
-                       DbgPrintf(4, _T("Cannot load zone object %ld - missing record in \"zones\" table"), (long)m_id);
-         return false;
-      }
-   }
+         if (DBGetNumRows(hResult) == 0)
+         {
+            DBFreeResult(hResult);
+            if (dwId == BUILTIN_OID_ZONE0)
+            {
+               m_uin = 0;
+               return true;
+            }
+            else
+            {
+               DbgPrintf(4, _T("Cannot load zone object %ld - missing record in \"zones\" table"), (long)m_id);
+               return false;
+            }
+         }
+
+         m_uin = DBGetFieldULong(hResult, 0, 0);
+         m_proxyNodeId = DBGetFieldULong(hResult, 0, 1);
+         TCHAR buffer[MAX_DB_STRING];
+         DBGetField(hResult, 0, 2, buffer, MAX_DB_STRING);
+         if (buffer[0] != 0)
+            m_snmpPorts.splitAndAdd(buffer, _T(","));
 
-   m_uin = DBGetFieldULong(hResult, 0, 0);
-   m_proxyNodeId = DBGetFieldULong(hResult, 0, 1);
+         DBFreeResult(hResult);
 
-   DBFreeResult(hResult);
+         // Load access list
+         loadACLFromDB(hdb);
 
-   // Load access list
-   loadACLFromDB(hdb);
+         return true;
+      }
+      DBFreeStatement(hStmt);
+   }
 
-   return true;
+   return false;
 }
 
 /**
@@ -120,17 +130,18 @@ bool Zone::saveToDatabase(DB_HANDLE hdb)
       DB_STATEMENT hStmt;
       if (IsDatabaseRecordExist(hdb, _T("zones"), _T("id"), m_id))
       {
-         hStmt = DBPrepare(hdb, _T("UPDATE zones SET zone_guid=?,proxy_node=? WHERE id=?"));
+         hStmt = DBPrepare(hdb, _T("UPDATE zones SET zone_guid=?,proxy_node=?,snmp_ports=? WHERE id=?"));
       }
       else
       {
-         hStmt = DBPrepare(hdb, _T("INSERT INTO zones (zone_guid,proxy_node,id) VALUES (?,?,?)"));
+         hStmt = DBPrepare(hdb, _T("INSERT INTO zones (zone_guid,proxy_node,snmp_ports,id) VALUES (?,?,?,?)"));
       }
       if (hStmt != NULL)
       {
          DBBind(hStmt, 1, DB_SQLTYPE_INTEGER, m_uin);
          DBBind(hStmt, 2, DB_SQLTYPE_INTEGER, m_proxyNodeId);
-         DBBind(hStmt, 3, DB_SQLTYPE_INTEGER, m_id);
+         DBBind(hStmt, 3, DB_SQLTYPE_VARCHAR, m_snmpPorts.join(_T(",")), DB_BIND_DYNAMIC);
+         DBBind(hStmt, 4, DB_SQLTYPE_INTEGER, m_id);
          success = DBExecute(hStmt);
          DBFreeStatement(hStmt);
       }
@@ -168,6 +179,7 @@ void Zone::fillMessageInternal(NXCPMessage *msg)
    NetObj::fillMessageInternal(msg);
    msg->setField(VID_ZONE_UIN, m_uin);
    msg->setField(VID_ZONE_PROXY, m_proxyNodeId);
+   m_snmpPorts.fillMessage(msg, VID_ZONE_SNMP_PORT_LIST_BASE, VID_ZONE_SNMP_PORT_COUNT);
 }
 
 /**
@@ -177,6 +189,14 @@ UINT32 Zone::modifyFromMessageInternal(NXCPMessage *request)
 {
        if (request->isFieldExist(VID_ZONE_PROXY))
                m_proxyNodeId = request->getFieldAsUInt32(VID_ZONE_PROXY);
+       if (request->isFieldExist(VID_ZONE_SNMP_PORT_LIST_BASE) && request->isFieldExist(VID_ZONE_SNMP_PORT_COUNT))
+       {
+          m_snmpPorts.clear();
+          for(int i = 0; i < request->getFieldAsUInt32(VID_ZONE_SNMP_PORT_COUNT); i++)
+          {
+             m_snmpPorts.addPreallocated(request->getFieldAsString(VID_ZONE_SNMP_PORT_LIST_BASE + i));
+          }
+       }
 
    return NetObj::modifyFromMessageInternal(request);
 }
index 51c495a..7a151db 100644 (file)
@@ -263,6 +263,11 @@ typedef struct
 #define InetAddressListElement_RANGE      1
 
 /**
+ * SNMP config global ID
+ */
+#define SNMP_CONFIG_GLOBAL -1
+
+/**
  * IP address list element
  */
 class NXCORE_EXPORTABLE InetAddressListElement
@@ -1043,7 +1048,7 @@ void PerfDataStorageRequest(DCTable *dci, time_t timestamp, Table *value);
 
 void DecodeSQLStringAndSetVariable(NXCPMessage *pMsg, UINT32 dwVarId, TCHAR *pszStr);
 
-SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAddr, INT16 *version, UINT16 originalPort, SNMP_SecurityContext *originalContext, StringList *customTestOids);
+SNMP_Transport *SnmpCheckCommSettings(UINT32 snmpProxy, const InetAddress& ipAddr, INT16 *version, UINT16 originalPort, SNMP_SecurityContext *originalContext, StringList *customTestOids, UINT32 zoneUIN);
 void StrToMac(const TCHAR *pszStr, BYTE *pBuffer);
 
 void InitLocalNetInfo();
index a53bfc5..fa539fe 100644 (file)
@@ -2315,6 +2315,7 @@ protected:
        InetAddressIndex *m_idxNodeByAddr;
        InetAddressIndex *m_idxInterfaceByAddr;
        InetAddressIndex *m_idxSubnetByAddr;
+       StringList m_snmpPorts;
 
    virtual void fillMessageInternal(NXCPMessage *msg);
    virtual UINT32 modifyFromMessageInternal(NXCPMessage *request);
@@ -2341,6 +2342,8 @@ public:
 
    void addSubnet(Subnet *pSubnet) { addChild(pSubnet); pSubnet->addParent(this); }
 
+   const StringList *getSnmpPortList() const { return &m_snmpPorts; }
+
        void addToIndex(Subnet *subnet) { m_idxSubnetByAddr->put(subnet->getIpAddress(), subnet); }
    void addToIndex(Interface *iface) { m_idxInterfaceByAddr->put(iface->getIpAddressList(), iface); }
    void addToIndex(const InetAddress& addr, Interface *iface) { m_idxInterfaceByAddr->put(addr, iface); }
index 08a9af6..eee4537 100644 (file)
 #include "nxdbmgr.h"
 
 /**
+ * Upgrade from 30.9 to 30.10
+ */
+static bool H_UpgradeFromV9()
+{
+   static const TCHAR *batch =
+            _T("ALTER TABLE snmp_communities ADD zone integer null\n")
+            _T("ALTER TABLE usm_credentials ADD zone integer null\n")
+            _T("ALTER TABLE zones ADD snmp_ports varchar(512) null\n")
+            _T("UPDATE snmp_communities SET zone=-1\n")
+            _T("UPDATE usm_credentials SET zone=-1\n")
+            _T("UPDATE zones SET snmp_ports=''\n")
+            _T("<END>");
+   CHK_EXEC(SQLBatch(batch));
+
+   DBSetNotNullConstraint(g_hCoreDB, _T("snmp_communities"), _T("zone"));
+   DBSetNotNullConstraint(g_hCoreDB, _T("usm_credentials"), _T("zone"));
+
+   CHK_EXEC(SetMinorSchemaVersion(10));
+   return true;
+}
+
+/**
  * Upgrade from 30.8 to 30.9 (changes also included into 22.2)
  */
 static bool H_UpgradeFromV8()
@@ -500,6 +522,7 @@ static struct
    bool (* upgradeProc)();
 } s_dbUpgradeMap[] =
 {
+   { 9, 30, 10, H_UpgradeFromV9 },
    { 8, 30, 9, H_UpgradeFromV8 },
    { 7, 30, 8, H_UpgradeFromV7 },
    { 6, 30, 7, H_UpgradeFromV6 },
index eda0e4b..fbac947 100644 (file)
@@ -30,7 +30,7 @@ import org.netxms.ui.eclipse.widgets.AbstractSelector;
  */
 public class ZoneSelector extends AbstractSelector
 {
-   private long zoneUIN = 0;
+   private long zoneUIN = -1;
    private String emptySelectionName = "<none>";
    
    /**
@@ -108,4 +108,14 @@ public class ZoneSelector extends AbstractSelector
          setText((zone != null) ? zone.getObjectName() : ("<" + Long.toString(zoneUIN) + ">")); //$NON-NLS-1$ //$NON-NLS-2$
       }
    }
+   
+   /**
+    * Set empty selection text
+    * @param text to set
+    */
+   public void setEmptySelectionText(String text)
+   {
+      emptySelectionName = text;
+      setText(emptySelectionName);
+   }
 }
index e7c5766..f2b4f38 100644 (file)
@@ -29,6 +29,8 @@ import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.TableViewer;
 import org.eclipse.jface.window.Window;
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
@@ -49,6 +51,7 @@ import org.netxms.client.NXCSession;
 import org.netxms.client.snmp.SnmpUsmCredential;
 import org.netxms.ui.eclipse.console.resources.SharedIcons;
 import org.netxms.ui.eclipse.jobs.ConsoleJob;
+import org.netxms.ui.eclipse.objectbrowser.widgets.ZoneSelector;
 import org.netxms.ui.eclipse.shared.ConsoleSharedData;
 import org.netxms.ui.eclipse.snmp.Activator;
 import org.netxms.ui.eclipse.snmp.Messages;
@@ -75,6 +78,8 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
        private TableViewer snmpPortList;
        private Action actionSave;
        private SnmpConfig config;
+       private ZoneSelector zoneSelector;
+       private long zoneUIN = SnmpConfig.SNMP_CONFIG_GLOBAL;
 
        /* (non-Javadoc)
     * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite)
@@ -99,7 +104,31 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                TableWrapLayout layout = new TableWrapLayout();
                layout.numColumns = 2;
                form.getBody().setLayout(layout);
-               
+
+               if (session.isZoningEnabled())
+               {
+         toolkit.decorateFormHeading(form.getForm());
+               Composite headArea = toolkit.createComposite(form.getForm().getHead());
+               headArea.setLayout(new GridLayout());
+         zoneSelector = new ZoneSelector(headArea, SWT.NONE, true);
+         zoneSelector.setEmptySelectionText("Global");
+         zoneSelector.setLabel("Select zone");
+   
+         GridData gd = new GridData();
+         gd.widthHint = 300;
+         zoneSelector.setLayoutData(gd);
+         form.setHeadClient(headArea);
+         zoneSelector.addModifyListener(new ModifyListener() {
+            
+            @Override
+            public void modifyText(ModifyEvent e)
+            {
+               zoneUIN = zoneSelector.getZoneUIN();
+               loadSnmpConfig();
+            }
+         });
+               }
+      
                createSnmpCommunitySection();
                createSnmpUsmCredSection();
                createSnmpPortList();
@@ -108,7 +137,16 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                contributeToActionBars();
 
       // Load config
-      new ConsoleJob("Loading SNMP configuration", this, Activator.PLUGIN_ID, null) {
+      loadSnmpConfig();
+       }
+       
+       /**
+        * Load SNMP config
+        * @param zoneUIN of config
+        */
+       private void loadSnmpConfig()
+       {
+          new ConsoleJob(Messages.get().SnmpCredentials_LoadingConfig, this, Activator.PLUGIN_ID, null) {
          @Override
          protected void runInternal(IProgressMonitor monitor) throws Exception
          {
@@ -373,14 +411,13 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
        /**
         * @param config
         */
-       public void setConfig(SnmpConfig config)
+       private void setConfig(SnmpConfig config)
        {
-               this.config = config;           
+               this.config = config;
+               snmpCommunityList.setInput(config.getCommunities(zoneUIN));
+               snmpUsmCredList.setInput(config.getUsmCredentials(zoneUIN));
+               snmpPortList.setInput(config.getPorts(zoneUIN));
                
-               snmpCommunityList.setInput(config.getCommunities().toArray());
-               snmpUsmCredList.setInput(config.getUsmCredentials().toArray());
-      snmpPortList.setInput(config.getPorts().toArray());
-
                modified = false;
                firePropertyChange(PROP_DIRTY);
        }
@@ -487,13 +524,9 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                if (dlg.open() == Window.OK)
                {
                        String s = dlg.getValue();
-                       final List<String> list = config.getCommunities();
-                       if (!list.contains(s))
-                       {
-                               list.add(s);
-                               snmpCommunityList.setInput(list.toArray());
-                               setModified();
-                       }
+                       config.addCommunityString(s, zoneUIN);
+         snmpCommunityList.setInput(config.getCommunities(zoneUIN));
+         setModified();
                }
        }
        
@@ -502,7 +535,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
         */
        private void removeCommunity()
        {
-               final List<String> list = config.getCommunities();
+               final List<String> list = config.getCommunities(zoneUIN);
                IStructuredSelection selection = (IStructuredSelection)snmpCommunityList.getSelection();
                if (selection.size() > 0)
                {
@@ -510,7 +543,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                        {
                                list.remove(o);
                        }
-                       snmpCommunityList.setInput(list.toArray());
+                       snmpCommunityList.setInput(list);
                        setModified();
                }
        }
@@ -524,13 +557,10 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
                if (dlg.open() == Window.OK)
                {
                        SnmpUsmCredential cred = dlg.getValue();
-                       final List<SnmpUsmCredential> list = config.getUsmCredentials();
-                       if (!list.contains(cred))
-                       {
-                               list.add(cred);
-                               snmpUsmCredList.setInput(list.toArray());
-                               setModified();
-                       }
+                       cred.setZoneId((int)zoneUIN);
+         config.addUsmCredentials(cred, zoneUIN);
+         snmpUsmCredList.setInput(config.getUsmCredentials(zoneUIN));
+         setModified();
                }
        }
        
@@ -539,7 +569,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
         */
        private void removeUsmCredentials()
        {
-               final List<SnmpUsmCredential> list = config.getUsmCredentials();
+               final List<SnmpUsmCredential> list = config.getUsmCredentials(zoneUIN);
                IStructuredSelection selection = (IStructuredSelection)snmpUsmCredList.getSelection();
                if (selection.size() > 0)
                {
@@ -562,13 +592,9 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
       if (dlg.open() == Window.OK)
       {
          String value = dlg.getValue();
-         final List<String> list = config.getPorts();
-         if (!list.contains(value))
-         {
-            list.add(value);
-            snmpPortList.setInput(list.toArray());
-            setModified();
-         }
+         config.addPort(value, zoneUIN);
+         snmpPortList.setInput(config.getPorts(zoneUIN));
+         setModified();
       }
    }
    
@@ -577,7 +603,7 @@ public class SnmpCredentials extends ViewPart implements ISaveablePart
     */
    private void removeSnmpPort()
    {
-      final List<String> list = config.getPorts();
+      final List<String> list = config.getPorts(zoneUIN);
       IStructuredSelection selection = (IStructuredSelection)snmpPortList.getSelection();
       if (selection.size() > 0)
       {
index 1e96505..3159acb 100644 (file)
@@ -3,18 +3,27 @@ package org.netxms.ui.eclipse.snmp.views.helpers;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import org.eclipse.core.runtime.IProgressMonitor;
 import org.netxms.client.NXCException;
+import org.netxms.client.NXCObjectModificationData;
 import org.netxms.client.NXCSession;
+import org.netxms.client.objects.Zone;
 import org.netxms.client.server.ServerVariable;
 import org.netxms.client.snmp.SnmpUsmCredential;
+import org.netxms.ui.eclipse.jobs.ConsoleJob;
+import org.netxms.ui.eclipse.snmp.Activator;
 
 public class SnmpConfig
 {
-   private List<String> communities;
-   private List<SnmpUsmCredential> usmCredentials;
-   private List<String> ports;
+   // Global SNMP config flag
+   public static int SNMP_CONFIG_GLOBAL = -1;
+   
+   private Map<Integer, List<String>> communities;
+   private Map<Integer, List<SnmpUsmCredential>> usmCredentials;
+   private Map<Integer, List<String>> ports;
 
    /**
     * Create empty object
@@ -38,33 +47,50 @@ public class SnmpConfig
       
       config.communities = session.getSnmpCommunities();
       config.usmCredentials = session.getSnmpUsmCredentials();
-      Map<String, ServerVariable> variables = session.getServerVariables();
-      ServerVariable v = variables.get("SNMPPorts");
-      config.ports = parsePorts(v != null ? v.getValue() : "" );
+      config.ports = loadPortConfig(session);
 
       return config;
    }
    
+   private static Map<Integer, List<String>> loadPortConfig(NXCSession session) throws IOException, NXCException
+   {
+      List<Zone> zones = session.getAllZones();
+      Map<Integer, List<String>> ports = new HashMap<Integer, List<String>>();
+      for (Zone z : zones)
+      {
+         if (!z.getSnmpPorts().isEmpty())
+            ports.put((int)z.getUIN(), z.getSnmpPorts());
+      }
+      Map<String, ServerVariable> variables = session.getServerVariables();
+      ServerVariable v = variables.get("SNMPPorts"); //$NON-NLS-1$
+      parsePorts(v != null ? v.getValue() : "", ports); //$NON-NLS-1$
+      
+      return ports;
+   }
+   
    /**
     * 
     * @param portList
     */
-   public static List<String> parsePorts(String portList)
+   private static void parsePorts(String portList, Map<Integer, List<String>> ports)
    {
-      String[] arr = portList.split(",");
-      List<String> list = new ArrayList<String>(Arrays.asList(arr));
-      return list;      
+      List<String> list = new ArrayList<String>(Arrays.asList(portList.split(",")));
+      ports.put(SNMP_CONFIG_GLOBAL, list);      
    }
    
    public String parsePorts() 
    {
       StringBuilder str = new StringBuilder();
-      for(int i = 0; i < ports.size(); i++)
+      List<String> list = ports.get(SNMP_CONFIG_GLOBAL);
+      if (list == null)
+         return "";
+      
+      for(int i = 0; i < list.size(); i++)
       {
-         str.append(ports.get(i));
-         if(i != ports.size() - 1)
+         str.append(list.get(i));
+         if(i != list.size() - 1)
          {
-            str.append(",");            
+            str.append(",");             //$NON-NLS-1$
          }
       }
       return str.toString();
@@ -81,55 +107,97 @@ public class SnmpConfig
    {
       session.updateSnmpCommunities(communities);
       session.updateSnmpUsmCredentials(usmCredentials);
-      session.setServerVariable("SNMPPorts", parsePorts());
+      savePortConfig(session);
+   }
+   
+   private void savePortConfig(final NXCSession session) throws IOException, NXCException
+   {
+      session.setServerVariable("SNMPPorts", parsePorts()); //$NON-NLS-1$
+      for(Integer i : ports.keySet())
+      {
+         if (ports.get(i).isEmpty() || session.findZone(i) == null)
+            continue;
+         final NXCObjectModificationData data = new NXCObjectModificationData(session.findZone(i).getObjectId());
+         data.setSnmpPorts(ports.get(i));
+         session.modifyObject(data);
+      }
    }
    
    /**
     * @return the communities
     */
-   public List<String> getCommunities()
+   public List<String> getCommunities(long zoneUIN)
    {
-      return communities;
+      if (communities.containsKey((int)zoneUIN))
+         return communities.get((int)zoneUIN);
+      else
+         return new ArrayList<String>();
    }
 
    /**
     * @param communities the communities to set
     */
-   public void setCommunities(List<String> communities)
+   public void addCommunityString(String communityString, long zoneUIN)
    {
-      this.communities = communities;
+      if (this.communities.containsKey((int)zoneUIN))
+         this.communities.get((int)zoneUIN).add(communityString);
+      else
+      {
+         List<String> list = new ArrayList<String>();
+         list.add(communityString);
+         this.communities.put((int)zoneUIN, list);
+      }
    }
    
    /**
     * @return the ports
     */
-   public List<String> getPorts()
+   public List<String> getPorts(long zoneUIN)
    {
-      return ports;
+      if (ports.containsKey((int)zoneUIN))
+         return ports.get((int)zoneUIN);
+      else
+         return new ArrayList<String>();
    }
    
    /**
     * @param communities the communities to set
     */
-   public void setPorts(List<String> ports)
+   public void addPort(String port, long zoneUIN)
    {
-      this.ports = ports;
+      if (this.ports.containsKey((int)zoneUIN))
+         this.ports.get((int)zoneUIN).add(port);
+      else
+      {
+         List<String> list = new ArrayList<String>();
+         list.add(port);
+         this.ports.put((int)zoneUIN, list);
+      }
    }
 
    /**
     * @return the usmCredentials
     */
-   public List<SnmpUsmCredential> getUsmCredentials()
+   public List<SnmpUsmCredential> getUsmCredentials(long zoneUIN)
    {
-      return usmCredentials;
+      if (usmCredentials.containsKey((int)zoneUIN))
+         return usmCredentials.get((int)zoneUIN);
+      else
+         return new ArrayList<SnmpUsmCredential>();
    }
 
    /**
     * @param usmCredentials the usmCredentials to set
     */
-   public void setUsmCredentials(List<SnmpUsmCredential> usmCredentials)
+   public void addUsmCredentials(SnmpUsmCredential credential, long zoneUIN)
    {
-      this.usmCredentials = usmCredentials;
-   }
-   
+      if (usmCredentials.containsKey((int)zoneUIN))
+         usmCredentials.get((int)zoneUIN).add(credential);
+      else
+      {
+         List<SnmpUsmCredential> list = new ArrayList<SnmpUsmCredential>();
+         list.add(credential);
+         usmCredentials.put((int)zoneUIN, list);
+      }
+   }   
 }