merged latest from develop

This commit is contained in:
bharnden 2019-06-17 20:13:58 -07:00
commit d053d126a9
45 changed files with 303 additions and 1076 deletions

View file

@ -64,6 +64,7 @@ fpm -s dir -t rpm -n core \
-v $(PACKAGE_VERSION) \
--rpm-init scripts/core-daemon \
--config-files "/etc/core" \
-d "ethtool" \
-d "tcl" \
-d "tk" \
-d "procps-ng" \
@ -89,6 +90,7 @@ fpm -s dir -t deb -n core \
--deb-systemd scripts/core-daemon.service \
--deb-no-default-config-files \
--config-files "/etc/core" \
-d "ethtool" \
-d "tcl" \
-d "tk" \
-d "libtk-img" \

View file

@ -13,8 +13,9 @@
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<jung.version>2.1.1</jung.version>
<jackson.version>2.9.6</jackson.version>
<jackson.version>2.9.9</jackson.version>
<grpc.version>1.20.0</grpc.version>
<log4j.version>2.9.0</log4j.version>
</properties>
<dependencies>
@ -58,25 +59,15 @@
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.9.0</version>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>io.socket</groupId>
<artifactId>socket.io-client</artifactId>
<version>0.8.3</version>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
@ -84,11 +75,6 @@
<version>1.18.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>com.jfoenix</groupId>
<artifactId>jfoenix</artifactId>
@ -114,6 +100,11 @@
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
<dependency>
<groupId>com.github.seancfoley</groupId>
<artifactId>ipaddress</artifactId>
<version>5.0.2</version>
</dependency>
</dependencies>
<build>

View file

@ -1,8 +1,8 @@
package com.core.client;
import com.core.Controller;
import com.core.client.rest.ServiceFile;
import com.core.client.rest.WlanConfig;
import com.core.data.ServiceFile;
import com.core.data.WlanConfig;
import com.core.data.*;
import java.io.File;

View file

@ -2,10 +2,10 @@ package com.core.client.grpc;
import com.core.Controller;
import com.core.client.ICoreClient;
import com.core.client.rest.ServiceFile;
import com.core.client.rest.WlanConfig;
import com.core.data.*;
import com.core.ui.dialogs.MobilityPlayerDialog;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressString;
import io.grpc.Context;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
@ -123,6 +123,9 @@ public class CoreGrpcClient implements ICoreClient {
private CoreProto.Interface interfaceToProto(CoreInterface coreInterface) {
CoreProto.Interface.Builder builder = CoreProto.Interface.newBuilder();
if (coreInterface.getId() != null) {
builder.setId(coreInterface.getId());
}
if (coreInterface.getName() != null) {
builder.setName(coreInterface.getName());
}
@ -130,16 +133,16 @@ public class CoreGrpcClient implements ICoreClient {
builder.setMac(coreInterface.getMac());
}
if (coreInterface.getIp4() != null) {
builder.setIp4(coreInterface.getIp4());
builder.setIp4(coreInterface.getIp4().toAddressString().getHostAddress().toString());
}
if (coreInterface.getIp4Mask() != null) {
builder.setIp4Mask(coreInterface.getIp4Mask());
if (coreInterface.getIp4() != null) {
builder.setIp4Mask(coreInterface.getIp4().getPrefixLength());
}
if (coreInterface.getIp6() != null) {
builder.setIp6(coreInterface.getIp6());
builder.setIp6(coreInterface.getIp6().toAddressString().getHostAddress().toString());
}
if (coreInterface.getIp6Mask() != null) {
builder.setIp6Mask(Integer.parseInt(coreInterface.getIp6Mask()));
if (coreInterface.getIp6() != null) {
builder.setIp6Mask(coreInterface.getIp6().getPrefixLength());
}
return builder.build();
}
@ -170,10 +173,12 @@ public class CoreGrpcClient implements ICoreClient {
coreInterface.setId(protoInterface.getId());
coreInterface.setName(protoInterface.getName());
coreInterface.setMac(protoInterface.getMac());
coreInterface.setIp4(protoInterface.getIp4());
coreInterface.setIp4Mask(protoInterface.getIp4Mask());
coreInterface.setIp6(protoInterface.getIp6());
coreInterface.setIp6Mask(Integer.toString(protoInterface.getIp6Mask()));
String ip4String = String.format("%s/%s", protoInterface.getIp4(), protoInterface.getIp4Mask());
IPAddress ip4 = new IPAddressString(ip4String).getAddress();
coreInterface.setIp4(ip4);
String ip6String = String.format("%s/%s", protoInterface.getIp6(), protoInterface.getIp6Mask());
IPAddress ip6 = new IPAddressString(ip6String).getAddress();
coreInterface.setIp6(ip6);
return coreInterface;
}

View file

@ -1,430 +0,0 @@
package com.core.client.rest;
import com.core.Controller;
import com.core.client.ICoreClient;
import com.core.data.*;
import com.core.utils.WebUtils;
import com.core.websocket.CoreWebSocket;
import lombok.Data;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
@Data
public class CoreRestClient implements ICoreClient {
private static final Logger logger = LogManager.getLogger();
private String address;
private int port;
private Integer sessionId;
private SessionState sessionState;
private CoreWebSocket coreWebSocket;
@Override
public void setConnection(String address, int port) {
this.address = address;
this.port = port;
}
@Override
public boolean isLocalConnection() {
return address.equals("127.0.0.1") || address.equals("localhost");
}
@Override
public Integer currentSession() {
return sessionId;
}
@Override
public void updateState(SessionState state) {
sessionState = state;
}
@Override
public void updateSession(Integer sessionId) {
this.sessionId = sessionId;
}
private String getUrl(String path) {
return String.format("http://%s:%s/%s", address, port, path);
}
@Override
public SessionOverview createSession() throws IOException {
String url = getUrl("sessions");
return WebUtils.post(url, SessionOverview.class);
}
@Override
public boolean deleteSession(Integer sessionId) throws IOException {
String path = String.format("sessions/%s", sessionId);
String url = getUrl(path);
return WebUtils.delete(url);
}
public Map<String, List<String>> getServices() throws IOException {
String url = getUrl("services");
GetServices getServices = WebUtils.getJson(url, GetServices.class);
return getServices.getGroups();
}
@Override
public Session getSession(Integer sessionId) throws IOException {
String path = String.format("sessions/%s", sessionId);
String url = getUrl(path);
return WebUtils.getJson(url, Session.class);
}
@Override
public List<SessionOverview> getSessions() throws IOException {
String url = getUrl("sessions");
GetSessions getSessions = WebUtils.getJson(url, GetSessions.class);
return getSessions.getSessions();
}
@Override
public boolean start(Collection<CoreNode> nodes, Collection<CoreLink> links, List<Hook> hooks) throws IOException {
boolean result = setState(SessionState.DEFINITION);
if (!result) {
return false;
}
result = setState(SessionState.CONFIGURATION);
if (!result) {
return false;
}
for (Hook hook : hooks) {
if (!createHook(hook)) {
return false;
}
}
for (CoreNode node : nodes) {
// must pre-configure wlan nodes, if not already
if (node.getNodeType().getValue() == NodeType.WLAN) {
WlanConfig config = getWlanConfig(node);
setWlanConfig(node, config);
}
if (!createNode(node)) {
return false;
}
}
for (CoreLink link : links) {
if (!createLink(link)) {
return false;
}
}
return setState(SessionState.INSTANTIATION);
}
@Override
public boolean stop() throws IOException {
return setState(SessionState.SHUTDOWN);
}
@Override
public boolean setState(SessionState state) throws IOException {
String url = getUrl(String.format("sessions/%s/state", sessionId));
Map<String, Integer> data = new HashMap<>();
data.put("state", state.getValue());
boolean result = WebUtils.putJson(url, data);
if (result) {
sessionState = state;
}
return result;
}
private boolean uploadFile(File file) throws IOException {
String url = getUrl("upload");
return WebUtils.postFile(url, file);
}
@Override
public boolean startThroughput(Controller controller) throws IOException {
String url = getUrl("throughput/start");
return WebUtils.putJson(url);
}
@Override
public boolean stopThroughput() throws IOException {
String url = getUrl("throughput/stop");
return WebUtils.putJson(url);
}
@Override
public Map<String, List<String>> getDefaultServices() throws IOException {
String url = getUrl(String.format("sessions/%s/services/default", sessionId));
GetDefaultServices getDefaultServices = WebUtils.getJson(url, GetDefaultServices.class);
return getDefaultServices.getDefaults();
}
@Override
public boolean setDefaultServices(Map<String, Set<String>> defaults) throws IOException {
String url = getUrl(String.format("sessions/%s/services/default", sessionId));
return WebUtils.postJson(url, defaults);
}
@Override
public CoreService getService(CoreNode node, String serviceName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName));
return WebUtils.getJson(url, CoreService.class);
}
@Override
public boolean setService(CoreNode node, String serviceName, CoreService service) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s", sessionId, node.getId(), serviceName));
return WebUtils.putJson(url, service);
}
@Override
public String getServiceFile(CoreNode node, String serviceName, String fileName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(),
serviceName));
Map<String, String> args = new HashMap<>();
args.put("file", fileName);
return WebUtils.getJson(url, String.class, args);
}
@Override
public boolean startService(CoreNode node, String serviceName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/start", sessionId, node.getId(),
serviceName));
return WebUtils.putJson(url);
}
@Override
public boolean stopService(CoreNode node, String serviceName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/stop", sessionId, node.getId(),
serviceName));
return WebUtils.putJson(url);
}
@Override
public boolean restartService(CoreNode node, String serviceName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/restart", sessionId, node.getId(),
serviceName));
return WebUtils.putJson(url);
}
@Override
public boolean validateService(CoreNode node, String serviceName) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/validate", sessionId, node.getId(),
serviceName));
return WebUtils.putJson(url);
}
@Override
public boolean setServiceFile(CoreNode node, String serviceName, ServiceFile serviceFile) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/services/%s/file", sessionId, node.getId(),
serviceName));
return WebUtils.putJson(url, serviceFile);
}
@Override
public List<String> getEmaneModels() throws IOException {
String url = getUrl(String.format("sessions/%s/emane/models", sessionId));
GetEmaneModels getEmaneModels = WebUtils.getJson(url, GetEmaneModels.class);
return getEmaneModels.getModels();
}
@Override
public List<ConfigGroup> getEmaneModelConfig(Integer id, String model) throws IOException {
String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId));
Map<String, String> args = new HashMap<>();
args.put("node", id.toString());
args.put("name", model);
GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args);
return getConfig.getGroups();
}
@Override
public List<ConfigGroup> getEmaneConfig(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/emane/config", sessionId));
Map<String, String> args = new HashMap<>();
args.put("node", node.getId().toString());
GetConfig getConfig = WebUtils.getJson(url, GetConfig.class, args);
return getConfig.getGroups();
}
@Override
public boolean setEmaneConfig(CoreNode node, List<ConfigOption> options) throws IOException {
String url = getUrl(String.format("sessions/%s/emane/config", sessionId));
SetEmaneConfig setEmaneConfig = new SetEmaneConfig();
setEmaneConfig.setNode(node.getId());
setEmaneConfig.setValues(options);
return WebUtils.putJson(url, setEmaneConfig);
}
@Override
public boolean setEmaneModelConfig(Integer id, String model, List<ConfigOption> options) throws IOException {
String url = getUrl(String.format("sessions/%s/emane/model/config", sessionId));
SetEmaneModelConfig setEmaneModelConfig = new SetEmaneModelConfig();
setEmaneModelConfig.setNode(id);
setEmaneModelConfig.setName(model);
setEmaneModelConfig.setValues(options);
return WebUtils.putJson(url, setEmaneModelConfig);
}
@Override
public boolean isRunning() {
return sessionState == SessionState.RUNTIME;
}
@Override
public void saveSession(File file) throws IOException {
String path = String.format("sessions/%s/xml", sessionId);
String url = getUrl(path);
WebUtils.getFile(url, file);
}
@Override
public SessionOverview openSession(File file) throws IOException {
String url = getUrl("sessions/xml");
return WebUtils.postFile(url, file, SessionOverview.class);
}
@Override
public List<ConfigGroup> getSessionConfig() throws IOException {
String url = getUrl(String.format("sessions/%s/options", sessionId));
GetConfig getConfig = WebUtils.getJson(url, GetConfig.class);
return getConfig.getGroups();
}
@Override
public boolean setSessionConfig(List<ConfigOption> configOptions) throws IOException {
String url = getUrl(String.format("sessions/%s/options", sessionId));
SetConfig setConfig = new SetConfig(configOptions);
return WebUtils.putJson(url, setConfig);
}
@Override
public LocationConfig getLocationConfig() throws IOException {
String url = getUrl(String.format("sessions/%s/location", sessionId));
return WebUtils.getJson(url, LocationConfig.class);
}
@Override
public boolean setLocationConfig(LocationConfig config) throws IOException {
String url = getUrl(String.format("sessions/%s/location", sessionId));
return WebUtils.putJson(url, config);
}
@Override
public String nodeCommand(CoreNode node, String command) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/command", sessionId, node.getId()));
return WebUtils.putJson(url, command, String.class);
}
@Override
public boolean createNode(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes", sessionId));
return WebUtils.postJson(url, node);
}
@Override
public boolean editNode(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s", sessionId, node.getId()));
return WebUtils.putJson(url, node);
}
@Override
public boolean deleteNode(CoreNode node) throws IOException {
String url = getUrl(String.format("/sessions/%s/nodes/%s", sessionId, node.getId()));
return WebUtils.delete(url);
}
@Override
public boolean createLink(CoreLink link) throws IOException {
String url = getUrl(String.format("sessions/%s/links", sessionId));
return WebUtils.postJson(url, link);
}
@Override
public boolean editLink(CoreLink link) throws IOException {
String url = getUrl(String.format("sessions/%s/links", sessionId));
return WebUtils.putJson(url, link);
}
@Override
public boolean createHook(Hook hook) throws IOException {
String url = getUrl(String.format("sessions/%s/hooks", sessionId));
return WebUtils.postJson(url, hook);
}
@Override
public List<Hook> getHooks() throws IOException {
String url = getUrl(String.format("sessions/%s/hooks", sessionId));
GetHooks getHooks = WebUtils.getJson(url, GetHooks.class);
return getHooks.getHooks();
}
@Override
public WlanConfig getWlanConfig(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId()));
return WebUtils.getJson(url, WlanConfig.class);
}
@Override
public boolean setWlanConfig(CoreNode node, WlanConfig config) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/wlan", sessionId, node.getId()));
return WebUtils.putJson(url, config);
}
@Override
public String getTerminalCommand(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/terminal", sessionId, node.getId()));
return WebUtils.getJson(url, String.class);
}
@Override
public boolean setMobilityConfig(CoreNode node, MobilityConfig config) throws IOException {
boolean uploaded = uploadFile(config.getScriptFile());
if (!uploaded) {
throw new IOException("failed to upload mobility script");
}
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId()));
config.setFile(config.getScriptFile().getName());
return WebUtils.postJson(url, config);
}
@Override
public Map<Integer, MobilityConfig> getMobilityConfigs() throws IOException {
String url = getUrl(String.format("sessions/%s/mobility/configs", sessionId));
GetMobilityConfigs getMobilityConfigs = WebUtils.getJson(url, GetMobilityConfigs.class);
return getMobilityConfigs.getConfigurations();
}
@Override
public MobilityConfig getMobilityConfig(CoreNode node) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility", sessionId, node.getId()));
return WebUtils.getJson(url, MobilityConfig.class);
}
@Override
public boolean mobilityAction(CoreNode node, String action) throws IOException {
String url = getUrl(String.format("sessions/%s/nodes/%s/mobility/%s", sessionId, node.getId(), action));
return WebUtils.putJson(url);
}
@Override
public void setupEventHandlers(Controller controller) throws IOException {
coreWebSocket.stop();
coreWebSocket = new CoreWebSocket(controller);
try {
coreWebSocket.start(address, port);
} catch (URISyntaxException ex) {
throw new IOException("error starting web socket", ex);
}
}
}

View file

@ -1,12 +0,0 @@
package com.core.client.rest;
import com.core.data.ConfigGroup;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class GetConfig {
private List<ConfigGroup> groups = new ArrayList<>();
}

View file

@ -1,16 +0,0 @@
package com.core.client.rest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GetDefaultServices {
private Map<String, List<String>> defaults = new HashMap<>();
}

View file

@ -1,11 +0,0 @@
package com.core.client.rest;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class GetEmaneModels {
private List<String> models = new ArrayList<>();
}

View file

@ -1,12 +0,0 @@
package com.core.client.rest;
import com.core.data.Hook;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class GetHooks {
private List<Hook> hooks = new ArrayList<>();
}

View file

@ -1,12 +0,0 @@
package com.core.client.rest;
import com.core.data.MobilityConfig;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class GetMobilityConfigs {
private Map<Integer, MobilityConfig> configurations = new HashMap<>();
}

View file

@ -1,13 +0,0 @@
package com.core.client.rest;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Map;
@Data
@NoArgsConstructor
public class GetServices {
private Map<String, List<String>> groups;
}

View file

@ -1,14 +0,0 @@
package com.core.client.rest;
import com.core.data.SessionOverview;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@NoArgsConstructor
public class GetSessions {
private List<SessionOverview> sessions = new ArrayList<>();
}

View file

@ -1,16 +0,0 @@
package com.core.client.rest;
import com.core.data.ConfigOption;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SetConfig {
private List<ConfigOption> values = new ArrayList<>();
}

View file

@ -1,13 +0,0 @@
package com.core.client.rest;
import com.core.data.ConfigOption;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class SetEmaneConfig {
private Integer node;
private List<ConfigOption> values = new ArrayList<>();
}

View file

@ -1,14 +0,0 @@
package com.core.client.rest;
import com.core.data.ConfigOption;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
@Data
public class SetEmaneModelConfig {
private Integer node;
private String name;
private List<ConfigOption> values = new ArrayList<>();
}

View file

@ -1,6 +1,5 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonSetter;
import lombok.Data;
@Data
@ -11,9 +10,4 @@ public class CoreEvent {
private Double time;
private EventType eventType;
private String data;
@JsonSetter("event_type")
public void setEventType(int value) {
eventType = EventType.get(value);
}
}

View file

@ -1,6 +1,6 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import inet.ipaddr.IPAddress;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -10,10 +10,6 @@ public class CoreInterface {
private Integer id;
private String name;
private String mac;
private String ip4;
@JsonProperty("ip4mask")
private Integer ip4Mask;
private String ip6;
@JsonProperty("ip6mask")
private String ip6Mask;
private IPAddress ip4;
private IPAddress ip6;
}

View file

@ -1,7 +1,5 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@ -12,36 +10,16 @@ import lombok.NoArgsConstructor;
public class CoreLink {
@EqualsAndHashCode.Include
private Integer id;
@JsonIgnore
private Float weight = 1.0f;
@JsonIgnore
private boolean loaded = true;
@JsonIgnore
private double throughput;
@JsonIgnore
private boolean visible = true;
@JsonProperty("message_type")
private Integer messageType;
private Integer type = 1;
@JsonProperty("node_one")
private Integer nodeOne;
@JsonProperty("node_two")
private Integer nodeTwo;
@JsonProperty("interface_one")
private CoreInterface interfaceOne;
@JsonProperty("interface_two")
private CoreInterface interfaceTwo;
private CoreLinkOptions options = new CoreLinkOptions();
public CoreLink(Integer id) {

View file

@ -2,7 +2,6 @@ package com.core.data;
import com.core.graph.RadioIcon;
import com.core.utils.IconUtils;
import com.fasterxml.jackson.annotation.JsonIgnore;
import edu.uci.ics.jung.visualization.LayeredIcon;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -27,15 +26,10 @@ public class CoreNode {
private Set<String> services = new HashSet<>();
private String emane;
private String url;
@JsonIgnore
private NodeType nodeType;
@JsonIgnore
private String icon;
@JsonIgnore
private boolean loaded = true;
@JsonIgnore
private LayeredIcon graphIcon;
@JsonIgnore
private RadioIcon radioIcon = new RadioIcon();
public CoreNode(Integer id) {

View file

@ -1,6 +1,5 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.ArrayList;
@ -14,9 +13,7 @@ public class CoreService {
private List<String> configs = new ArrayList<>();
private List<String> startup = new ArrayList<>();
private List<String> validate = new ArrayList<>();
@JsonProperty("validation_mode")
private String validationMode;
@JsonProperty("validation_timer")
private String validationTimer;
private List<String> shutdown = new ArrayList<>();
private String meta;

View file

@ -1,13 +1,11 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
@Data
public class Hook {
private String file;
private Integer state;
@JsonIgnore
private String stateDisplay;
private String data;
}

View file

@ -1,12 +1,10 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class InterfaceThroughput {
private int node;
@JsonProperty("interface")
private int nodeInterface;
private double throughput;
}

View file

@ -1,7 +1,5 @@
package com.core.data;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.File;
@ -9,17 +7,12 @@ import java.io.File;
@Data
public class MobilityConfig {
private String file;
@JsonIgnore
private File scriptFile;
@JsonProperty("refresh_ms")
private Integer refresh;
private String loop;
private String autostart;
private String map;
@JsonProperty("script_start")
private String startScript;
@JsonProperty("script_pause")
private String pauseScript;
@JsonProperty("script_stop")
private String stopScript;
}

View file

@ -73,11 +73,9 @@ public class NodeType {
return ID_LOOKUP.values().stream()
.filter(nodeType -> {
boolean sameType = nodeType.getValue() == type;
boolean sameModel;
if (model != null) {
boolean sameModel = true;
if (!model.isEmpty()) {
sameModel = model.equals(nodeType.getModel());
} else {
sameModel = nodeType.getModel() == null;
}
return sameType && sameModel;
})

View file

@ -1,4 +1,4 @@
package com.core.client.rest;
package com.core.data;
import lombok.AllArgsConstructor;
import lombok.Data;

View file

@ -1,4 +1,4 @@
package com.core.client.rest;
package com.core.data;
import lombok.Data;

View file

@ -1,41 +1,79 @@
package com.core.graph;
import com.core.data.CoreInterface;
import inet.ipaddr.IPAddress;
import inet.ipaddr.IPAddressString;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.Collection;
import java.beans.IndexedPropertyDescriptor;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
public class CoreAddresses {
private static final Logger logger = LogManager.getLogger();
public static final int IP4_MASK = 24;
public static final int IP4_INDEX = (IP4_MASK / 8) - 1;
private IPAddress currentSubnet = new IPAddressString("10.0.0.0/24").getAddress().toPrefixBlock();
private Queue<IPAddress> deleted = new LinkedBlockingQueue<>();
private Set<IPAddress> usedSubnets = new HashSet<>();
private String ip4Base;
public CoreAddresses(String ip4Base) {
this.ip4Base = ip4Base;
public void usedAddress(IPAddress address) {
logger.info("adding used address: {} - {}", address, address.toPrefixBlock());
usedSubnets.add(address.toPrefixBlock());
logger.info("used subnets: {}", usedSubnets);
}
public int getSubnet(Collection<CoreInterface> nodeOneInterfaces, Collection<CoreInterface> nodeTwoInterfaces) {
int subOne = getMaxSubnet(nodeOneInterfaces);
int subTwo = getMaxSubnet(nodeTwoInterfaces);
logger.info("next subnet: {} - {}", subOne, subTwo);
return Math.max(subOne, subTwo) + 1;
public void reuseSubnet(IPAddress subnet) {
deleted.add(subnet);
}
private int getMaxSubnet(Collection<CoreInterface> coreInterfaces) {
int sub = 0;
for (CoreInterface coreInterface : coreInterfaces) {
String[] values = coreInterface.getIp4().split("\\.");
int currentSub = Integer.parseInt(values[IP4_INDEX]);
logger.info("checking {} value {}", coreInterface.getIp4(), currentSub);
sub = Math.max(currentSub, sub);
}
return sub;
public IPAddress nextSubnet() {
logger.info("getting next subnet: {}", currentSubnet);
// skip existing subnets, when loaded from file
while (usedSubnets.contains(currentSubnet)) {
currentSubnet = currentSubnet.incrementBoundary(1).toPrefixBlock();
}
public String getIp4Address(int sub, int id) {
return String.format("%s.%s.%s", ip4Base, sub, id);
// re-use any deleted subnets
IPAddress next = deleted.poll();
if (next == null) {
next = currentSubnet;
currentSubnet = currentSubnet.incrementBoundary(1).toPrefixBlock();
}
return next;
}
public IPAddress findSubnet(Set<CoreInterface> interfaces) {
IPAddress subnet;
logger.info("finding subnet from interfaces: {}", interfaces);
if (interfaces.isEmpty()) {
subnet = nextSubnet();
} else {
IPAddress maxAddress = getMaxAddress(interfaces);
subnet = maxAddress.toPrefixBlock();
}
return subnet;
}
private IPAddress getMaxAddress(Set<CoreInterface> interfaces) {
return interfaces.stream()
.map(CoreInterface::getIp4)
.max(Comparator.comparingInt(x -> x.toIPv4().intValue()))
.orElseGet(() -> currentSubnet);
}
public void reset() {
deleted.clear();
usedSubnets.clear();
currentSubnet = new IPAddressString("10.0.0.0/24").getAddress().toPrefixBlock();
}
public static void main(String... args) {
IPAddress addresses = new IPAddressString("10.0.0.0/16").getAddress();
System.out.println(String.format("address: %s", addresses.increment(257)));
}
}

View file

@ -20,9 +20,9 @@ import edu.uci.ics.jung.visualization.control.GraphMouseListener;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import inet.ipaddr.IPAddress;
import javafx.application.Platform;
import lombok.Data;
import org.apache.commons.net.util.SubnetUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -32,7 +32,6 @@ import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -50,8 +49,7 @@ public class NetworkGraph {
private EditingModalGraphMouse<CoreNode, CoreLink> graphMouse;
private AnnotationControls<CoreNode, CoreLink> annotationControls;
private SubnetUtils subnetUtils = new SubnetUtils("10.0.0.0/24");
private CoreAddresses coreAddresses = new CoreAddresses("10.0");
private CoreAddresses coreAddresses = new CoreAddresses();
private NodeType nodeType;
private Map<Integer, CoreNode> nodeMap = new ConcurrentHashMap<>();
private int vertexId = 1;
@ -77,9 +75,8 @@ public class NetworkGraph {
graphViewer.setBackground(Color.WHITE);
graphViewer.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S);
RenderContext<CoreNode, CoreLink> renderContext = graphViewer.getRenderContext();
// node render properties
RenderContext<CoreNode, CoreLink> renderContext = graphViewer.getRenderContext();
renderContext.setVertexLabelTransformer(CoreNode::getName);
renderContext.setVertexLabelRenderer(nodeLabelRenderer);
renderContext.setVertexShapeTransformer(node -> {
@ -251,6 +248,7 @@ public class NetworkGraph {
}
nodeMap.clear();
graphViewer.repaint();
coreAddresses.reset();
}
public void updatePositions() {
@ -287,40 +285,93 @@ public class NetworkGraph {
private void handleEdgeAdded(GraphEvent.Edge<CoreNode, CoreLink> edgeEvent) {
CoreLink link = edgeEvent.getEdge();
if (!link.isLoaded()) {
if (link.isLoaded()) {
// load addresses to avoid duplication
if (link.getInterfaceOne().getIp4() != null) {
coreAddresses.usedAddress(link.getInterfaceOne().getIp4());
}
if (link.getInterfaceTwo().getIp4() != null) {
coreAddresses.usedAddress(link.getInterfaceTwo().getIp4());
}
return;
}
Pair<CoreNode> endpoints = graph.getEndpoints(link);
CoreNode nodeOne = endpoints.getFirst();
CoreNode nodeTwo = endpoints.getSecond();
boolean nodeOneIsDefault = isNode(nodeOne);
boolean nodeTwoIsDefault = isNode(nodeTwo);
// create interfaces for nodes
int sub = coreAddresses.getSubnet(
getInterfaces(nodeOne),
getInterfaces(nodeTwo)
);
// check what we are linking together
IPAddress subnet = null;
Set<CoreInterface> interfaces;
if (nodeOneIsDefault && nodeTwoIsDefault) {
subnet = coreAddresses.nextSubnet();
logger.info("linking node to node using subnet: {}", subnet);
} else if (nodeOneIsDefault) {
interfaces = getNetworkInterfaces(nodeTwo, new HashSet<>());
subnet = coreAddresses.findSubnet(interfaces);
logger.info("linking node one to network using subnet: {}", subnet);
} else if (nodeTwoIsDefault) {
interfaces = getNetworkInterfaces(nodeOne, new HashSet<>());
subnet = coreAddresses.findSubnet(interfaces);
logger.info("linking node two to network using subnet: {}", subnet);
} else {
logger.info("subnet not needed for linking networks together");
}
link.setNodeOne(nodeOne.getId());
if (isNode(nodeOne)) {
if (nodeOneIsDefault) {
int interfaceOneId = nextInterfaceId(nodeOne);
CoreInterface interfaceOne = createInterface(nodeOne, sub, interfaceOneId);
CoreInterface interfaceOne = createInterface(nodeOne, interfaceOneId, subnet);
link.setInterfaceOne(interfaceOne);
}
link.setNodeTwo(nodeTwo.getId());
if (isNode(nodeTwo)) {
if (nodeTwoIsDefault) {
int interfaceTwoId = nextInterfaceId(nodeTwo);
CoreInterface interfaceTwo = createInterface(nodeTwo, sub, interfaceTwoId);
CoreInterface interfaceTwo = createInterface(nodeTwo, interfaceTwoId, subnet);
link.setInterfaceTwo(interfaceTwo);
}
boolean isVisible = !checkForWirelessNode(nodeOne, nodeTwo);
link.setVisible(isVisible);
logger.info("adding user created edge: {}", link);
}
public Set<CoreInterface> getNetworkInterfaces(CoreNode node, Set<CoreNode> visited) {
Set<CoreInterface> interfaces = new HashSet<>();
if (visited.contains(node)) {
return interfaces;
}
visited.add(node);
logger.info("checking network node links: {}", node);
for (CoreLink link : graph.getIncidentEdges(node)) {
logger.info("checking link: {}", link);
if (link.getNodeOne() == null && link.getNodeTwo() == null) {
continue;
}
public List<CoreInterface> getInterfaces(CoreNode node) {
// ignore oneself
CoreNode currentNode = getVertex(link.getNodeOne());
CoreInterface currentInterface = link.getInterfaceOne();
if (node.getId().equals(link.getNodeOne())) {
currentNode = getVertex(link.getNodeTwo());
currentInterface = link.getInterfaceTwo();
}
if (isNode(currentNode)) {
interfaces.add(currentInterface);
} else {
Set<CoreInterface> nextInterfaces = getNetworkInterfaces(currentNode, visited);
interfaces.addAll(nextInterfaces);
}
}
return interfaces;
}
public Set<CoreInterface> getNodeInterfaces(CoreNode node) {
return graph.getIncidentEdges(node).stream()
.map(link -> {
if (node.getId().equals(link.getNodeOne())) {
@ -330,7 +381,7 @@ public class NetworkGraph {
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
.collect(Collectors.toSet());
}
private int nextInterfaceId(CoreNode node) {
@ -360,19 +411,52 @@ public class NetworkGraph {
return node.getType() == NodeType.DEFAULT;
}
private CoreInterface createInterface(CoreNode node, int sub, int interfaceId) {
private CoreInterface createInterface(CoreNode node, int interfaceId, IPAddress subnet) {
CoreInterface coreInterface = new CoreInterface();
coreInterface.setId(interfaceId);
coreInterface.setName(String.format("eth%s", interfaceId));
String nodeOneIp4 = coreAddresses.getIp4Address(sub, node.getId());
coreInterface.setIp4(nodeOneIp4);
coreInterface.setIp4Mask(CoreAddresses.IP4_MASK);
IPAddress address = subnet.increment(node.getId());
logger.info("creating interface for node({}): {}", node.getId(), address);
coreInterface.setIp4(address);
coreInterface.setIp6(address.toIPv6());
return coreInterface;
}
private void handleEdgeRemoved(GraphEvent.Edge<CoreNode, CoreLink> edgeEvent) {
CoreLink link = edgeEvent.getEdge();
logger.info("removed edge: {}", link);
CoreNode nodeOne = getVertex(link.getNodeOne());
CoreInterface interfaceOne = link.getInterfaceOne();
CoreNode nodeTwo = getVertex(link.getNodeTwo());
CoreInterface interfaceTwo = link.getInterfaceTwo();
boolean nodeOneIsDefault = isNode(nodeOne);
boolean nodeTwoIsDefault = isNode(nodeTwo);
// check what we are unlinking
Set<CoreInterface> interfaces;
IPAddress subnet = null;
if (nodeOneIsDefault && nodeTwoIsDefault) {
subnet = interfaceOne.getIp4().toPrefixBlock();
logger.info("unlinking node to node reuse subnet: {}", subnet);
} else if (nodeOneIsDefault) {
interfaces = getNetworkInterfaces(nodeTwo, new HashSet<>());
if (interfaces.isEmpty()) {
subnet = interfaceOne.getIp4().toPrefixBlock();
logger.info("unlinking node one from network reuse subnet: {}", subnet);
}
} else if (nodeTwoIsDefault) {
interfaces = getNetworkInterfaces(nodeOne, new HashSet<>());
if (interfaces.isEmpty()) {
subnet = interfaceTwo.getIp4().toPrefixBlock();
logger.info("unlinking node two from network reuse subnet: {}", subnet);
}
} else {
logger.info("nothing to do when unlinking networks");
}
if (subnet != null) {
coreAddresses.reuseSubnet(subnet);
}
}
private void handleVertexAdded(GraphEvent.Vertex<CoreNode, CoreLink> vertexEvent) {
@ -431,7 +515,7 @@ public class NetworkGraph {
}
private boolean isWirelessNode(CoreNode node) {
return node.getType() == NodeType.EMANE || node.getType() == NodeType.WLAN;
return node != null && (node.getType() == NodeType.EMANE || node.getType() == NodeType.WLAN);
}
private boolean checkForWirelessNode(CoreNode nodeOne, CoreNode nodeTwo) {

View file

@ -11,6 +11,7 @@ import com.core.ui.textfields.DoubleFilter;
import com.core.utils.FxmlUtils;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXTextField;
import inet.ipaddr.IPAddress;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
@ -129,8 +130,8 @@ public class LinkDetails extends ScrollPane {
if (coreInterface.getMac() != null) {
addRow("MAC", coreInterface.getMac(), true);
}
addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask());
addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask());
addIp4Address(coreInterface.getIp4());
addIp6Address(coreInterface.getIp6());
}
private void addRow(String labelText, String value, boolean disabled) {
@ -155,18 +156,18 @@ public class LinkDetails extends ScrollPane {
return textField;
}
private void addIp4Address(String ip, Integer mask) {
private void addIp4Address(IPAddress ip) {
if (ip == null) {
return;
}
addRow("IP4", String.format("%s/%s", ip, mask), true);
addRow("IP4", ip.toString(), true);
}
private void addIp6Address(String ip, String mask) {
private void addIp6Address(IPAddress ip) {
if (ip == null) {
return;
}
addRow("IP6", String.format("%s/%s", ip, mask), true);
addRow("IP6", ip.toString(), true);
}
private void clear() {

View file

@ -10,6 +10,7 @@ import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXScrollPane;
import com.jfoenix.controls.JFXTextField;
import inet.ipaddr.IPAddress;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
@ -147,8 +148,8 @@ public class NodeDetails extends ScrollPane {
if (coreInterface.getMac() != null) {
addRow("MAC", coreInterface.getMac(), true);
}
addIp4Address(coreInterface.getIp4(), coreInterface.getIp4Mask());
addIp6Address(coreInterface.getIp6(), coreInterface.getIp6Mask());
addIp4Address(coreInterface.getIp4());
addIp6Address(coreInterface.getIp6());
}
private void addRow(String labelText, String value, boolean disabled) {
@ -158,18 +159,18 @@ public class NodeDetails extends ScrollPane {
gridPane.addRow(index++, label, textField);
}
private void addIp4Address(String ip, Integer mask) {
private void addIp4Address(IPAddress ip) {
if (ip == null) {
return;
}
addRow("IP4", String.format("%s/%s", ip, mask), true);
addRow("IP4", ip.toString(), true);
}
private void addIp6Address(String ip, String mask) {
private void addIp6Address(IPAddress ip) {
if (ip == null) {
return;
}
addRow("IP6", String.format("%s/%s", ip, mask), true);
addRow("IP6", ip.toString(), true);
}
private void clear() {

View file

@ -1,7 +1,7 @@
package com.core.ui.dialogs;
import com.core.Controller;
import com.core.client.rest.WlanConfig;
import com.core.data.WlanConfig;
import com.core.data.CoreNode;
import com.core.ui.Toast;
import com.jfoenix.controls.JFXButton;

View file

@ -1,7 +1,7 @@
package com.core.ui.dialogs;
import com.core.Controller;
import com.core.client.rest.ServiceFile;
import com.core.data.ServiceFile;
import com.core.data.CoreNode;
import com.core.data.CoreService;
import com.jfoenix.controls.JFXButton;

View file

@ -1,174 +0,0 @@
package com.core.utils;
import com.fasterxml.jackson.core.type.TypeReference;
import okhttp3.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.util.Collections;
import java.util.Map;
public final class WebUtils {
private static final Logger logger = LogManager.getLogger();
private static final OkHttpClient client = new OkHttpClient();
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private WebUtils() {
}
public static <T> T getJson(String url, Class<T> clazz) throws IOException {
return getJson(url, clazz, Collections.emptyMap());
}
public static <T> T getJson(String url, Class<T> clazz, Map<String, String> args) throws IOException {
logger.debug("get json: {}", url);
HttpUrl.Builder urlBuilder = HttpUrl.parse(url).newBuilder();
args.forEach(urlBuilder::addQueryParameter);
HttpUrl httpUrl = urlBuilder.build();
Request request = new Request.Builder()
.url(httpUrl)
.build();
String response = readResponse(request);
return JsonUtils.read(response, clazz);
}
public static void getFile(String url, File file) throws IOException {
logger.debug("get file: {}", url);
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
InputStream input = response.body().byteStream();
try (OutputStream output = new FileOutputStream(file)) {
int count;
byte[] data = new byte[1024];
while ((count = input.read(data)) != -1) {
output.write(data, 0, count);
}
}
}
}
public static boolean postFile(String url, File file) throws IOException {
MediaType mediaType = MediaType.parse("File/*");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
}
}
public static <T> T postFile(String url, File file, Class<T> clazz) throws IOException {
MediaType mediaType = MediaType.parse("File/*");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), RequestBody.create(mediaType, file))
.build();
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
String response = readResponse(request);
return JsonUtils.read(response, clazz);
}
public static <T> T getJson(String url, TypeReference<T> reference) throws IOException {
Request request = new Request.Builder()
.url(url)
.build();
String response = readResponse(request);
return JsonUtils.getMapper().readValue(response, reference);
}
private static String readResponse(Request request) throws IOException {
try (Response response = client.newCall(request).execute()) {
ResponseBody body = response.body();
if (body == null) {
throw new IOException("failed to received body");
} else {
return body.string();
}
}
}
public static boolean postJson(String url, Object json) throws IOException {
logger.debug("post json: {} - {}", url, json);
RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json));
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
}
}
public static boolean putJson(String url) throws IOException {
logger.debug("put json: {}", url);
RequestBody body = new FormBody.Builder().build();
Request request = new Request.Builder()
.url(url)
.put(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
}
}
public static boolean putJson(String url, Object json) throws IOException {
logger.debug("put json: {} - {}", url, json);
RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json));
Request request = new Request.Builder()
.url(url)
.put(body)
.build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
}
}
public static <T> T putJson(String url, Object json, Class<T> clazz) throws IOException {
logger.debug("put json: {} - {}", url, json);
RequestBody body = RequestBody.create(JSON, JsonUtils.toString(json));
Request request = new Request.Builder()
.url(url)
.put(body)
.build();
String response = readResponse(request);
return JsonUtils.read(response, clazz);
}
public static <T> T post(String url, Class<T> clazz) throws IOException {
logger.debug("post: {}", url);
RequestBody body = new FormBody.Builder().build();
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
String response = readResponse(request);
return JsonUtils.read(response, clazz);
}
public static boolean delete(String url) throws IOException {
logger.debug("delete: {}", url);
Request request = new Request.Builder()
.url(url)
.delete()
.build();
try (Response response = client.newCall(request).execute()) {
return response.isSuccessful();
}
}
}

View file

@ -1,130 +0,0 @@
package com.core.websocket;
import com.core.Controller;
import com.core.data.*;
import com.core.ui.dialogs.MobilityPlayerDialog;
import com.core.utils.JsonUtils;
import io.socket.client.IO;
import io.socket.client.Socket;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.net.URISyntaxException;
public class CoreWebSocket {
private static final Logger logger = LogManager.getLogger();
private final Controller controller;
private Thread socketThread;
private Socket socket;
public CoreWebSocket(Controller controller) {
this.controller = controller;
}
public void start(String address, int port) throws URISyntaxException {
socket = IO.socket(String.format("http://%s:%s", address, port));
socket.on(Socket.EVENT_CONNECT, args -> logger.info("connected to web socket"));
socket.on("node", this::handleNodes);
socket.on("event", this::handleEvents);
socket.on("config", this::handleConfigs);
socket.on("link", this::handleLinks);
socket.on("throughput", this::handleThroughputs);
socket.on(Socket.EVENT_DISCONNECT, args -> logger.info("disconnected from web socket"));
logger.info("attempting to connect to web socket!");
socketThread = new Thread(socket::connect);
socketThread.setDaemon(true);
socketThread.start();
}
public void stop() {
if (socketThread != null) {
socket.close();
socketThread.interrupt();
}
}
private void handleThroughputs(Object... args) {
for (Object arg : args) {
logger.info("throughput update: {}", arg);
try {
Throughputs throughputs = JsonUtils.read(arg.toString(), Throughputs.class);
controller.handleThroughputs(throughputs);
} catch (IOException ex) {
logger.error("error getting throughputs", ex);
}
}
}
private void handleNodes(Object... args) {
for (Object arg : args) {
try {
CoreNode node = JsonUtils.read(arg.toString(), CoreNode.class);
logger.info("core node update: {}", node);
controller.getNetworkGraph().setNodeLocation(node);
} catch (IOException ex) {
logger.error("error getting core node", ex);
}
}
}
private void handleEvents(Object... args) {
for (Object arg : args) {
try {
CoreEvent event = JsonUtils.read(arg.toString(), CoreEvent.class);
logger.info("handling broadcast event: {}", event);
SessionState state = SessionState.get(event.getEventType().getValue());
if (state == null) {
logger.warn("unknown event type: {}", event.getEventType().getValue());
return;
}
// session state event
if (state.getValue() <= 6) {
logger.info("event updating session state: {}", state);
controller.getCoreClient().updateState(state);
// mobility script event
} else if (state.getValue() <= 9) {
Integer nodeId = event.getNode();
String[] values = event.getData().split("\\s+");
Integer start = Integer.parseInt(values[0].split("=")[1]);
Integer end = Integer.parseInt(values[1].split("=")[1]);
logger.info(String.format("node(%s) mobility event (%s) - start(%s) stop(%s)",
nodeId, state, start, end));
logger.info("all dialogs: {}", controller.getMobilityPlayerDialogs().keySet());
MobilityPlayerDialog mobilityPlayerDialog = controller.getMobilityPlayerDialogs().get(nodeId);
mobilityPlayerDialog.event(state, start, end);
}
} catch (IOException ex) {
logger.error("error getting core event", ex);
}
}
}
private void handleLinks(Object... args) {
for (Object arg : args) {
try {
CoreLink link = JsonUtils.read(arg.toString(), CoreLink.class);
logger.info("handling broadcast link: {}", link);
MessageFlags flag = MessageFlags.get(link.getMessageType());
if (MessageFlags.DELETE == flag) {
logger.info("delete");
controller.getNetworkGraph().removeWirelessLink(link);
} else if (MessageFlags.ADD == flag) {
link.setLoaded(true);
controller.getNetworkGraph().addLink(link);
}
controller.getNetworkGraph().getGraphViewer().repaint();
} catch (IOException ex) {
logger.error("error handling broadcast link", ex);
}
}
}
private void handleConfigs(Object... args) {
for (Object arg : args) {
logger.info("handling broadcast config: {}", arg);
}
}
}

View file

@ -1 +1 @@
../../../../daemon/proto/core.proto
../../../../daemon/proto/core/api/grpc/core.proto

View file

@ -17,6 +17,7 @@ from core.emulator.emudata import NodeOptions, InterfaceData, LinkOptions
from core.emulator.enumerations import NodeTypes, EventTypes, LinkTypes
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes import nodeutils
from core.nodes.base import CoreNetworkBase
from core.nodes.ipaddress import MacAddress
from core.services.coreservices import ServiceManager
@ -73,18 +74,24 @@ def convert_link(session, link_data):
interface_one = None
if link_data.interface1_id is not None:
node = session.get_node(link_data.node1_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface1_id)
interface_name = interface.name
interface_one = core_pb2.Interface(
id=link_data.interface1_id, name=interface.name, mac=convert_value(link_data.interface1_mac),
id=link_data.interface1_id, name=interface_name, mac=convert_value(link_data.interface1_mac),
ip4=convert_value(link_data.interface1_ip4), ip4mask=link_data.interface1_ip4_mask,
ip6=convert_value(link_data.interface1_ip6), ip6mask=link_data.interface1_ip6_mask)
interface_two = None
if link_data.interface2_id is not None:
node = session.get_node(link_data.node2_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface2_id)
interface_name = interface.name
interface_two = core_pb2.Interface(
id=link_data.interface2_id, name=interface.name, mac=convert_value(link_data.interface2_mac),
id=link_data.interface2_id, name=interface_name, mac=convert_value(link_data.interface2_mac),
ip4=convert_value(link_data.interface2_ip4), ip4mask=link_data.interface2_ip4_mask,
ip6=convert_value(link_data.interface2_ip6), ip6mask=link_data.interface2_ip6_mask)
@ -855,6 +862,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("set wlan config: %s", request)
session = self.get_session(request.session_id, context)
session.mobility.set_model_config(request.node_id, BasicRangeModel.name, request.config)
if session.state == EventTypes.RUNTIME_STATE.value:
node = self.get_node(session, request.node_id, context)
node.updatemodel(request.config)
return core_pb2.SetWlanConfigResponse(result=True)
def GetEmaneConfig(self, request, context):

View file

@ -40,6 +40,7 @@ from core.emulator.enumerations import NodeTlvs
from core.emulator.enumerations import NodeTypes
from core.emulator.enumerations import RegisterTlvs
from core.emulator.enumerations import SessionTlvs
from core.location.mobility import BasicRangeModel
from core.nodes import nodeutils
from core.services.coreservices import ServiceManager
from core.services.coreservices import ServiceShim
@ -1268,6 +1269,13 @@ class CoreHandler(socketserver.BaseRequestHandler):
parsed_config = ConfigShim.str_to_dict(values_str)
self.session.mobility.set_model_config(node_id, object_name, parsed_config)
if self.session.state == EventTypes.RUNTIME_STATE.value:
try:
node = self.session.get_node(node_id)
if object_name == BasicRangeModel.name:
node.updatemodel(parsed_config)
except KeyError:
logging.error("skipping mobility configuration for unknown node: %s", node_id)
return replies

View file

@ -20,6 +20,7 @@ VCMD_BIN = which("vcmd")
BRCTL_BIN = which("brctl")
SYSCTL_BIN = which("sysctl")
IP_BIN = which("ip")
ETHTOOL_BIN = which("ethtool")
TC_BIN = which("tc")
EBTABLES_BIN = which("ebtables")
MOUNT_BIN = which("mount")

View file

@ -9,7 +9,7 @@ import os
import threading
import time
from builtins import int
from past.builtins import cmp
from functools import total_ordering
from core import utils
from core.config import ConfigGroup
@ -358,7 +358,7 @@ class BasicRangeModel(WirelessModel):
:param dict config: values to convert
:return: nothing
"""
self.range = int(config["range"])
self.range = int(float(config["range"]))
logging.info("basic range model configured for WLAN %d using range %d", self.wlan.id, self.range)
self.bw = int(config["bandwidth"])
if self.bw == 0:
@ -561,6 +561,7 @@ class BasicRangeModel(WirelessModel):
return all_links
@total_ordering
class WayPoint(object):
"""
Maintains information regarding waypoints.
@ -580,18 +581,17 @@ class WayPoint(object):
self.coords = coords
self.speed = speed
def __cmp__(self, other):
"""
Custom comparison method for waypoints.
def __eq__(self, other):
return (self.time, self.nodenum) == (other.time, other.nodedum)
:param WayPoint other: waypoint to compare to
:return: the comparison result against the other waypoint
:rtype: int
"""
tmp = cmp(self.time, other.time)
if tmp == 0:
tmp = cmp(self.nodenum, other.nodenum)
return tmp
def __ne__(self, other):
return not self == other
def __lt__(self, other):
result = self.time < other.time
if result:
result = self.nodenum < other.nodenum
return result
class WayPointMobility(WirelessModel):
@ -836,7 +836,12 @@ class WayPointMobility(WirelessModel):
:param z: z position
:return: nothing
"""
# this would cause PyCoreNetIf.poshook() callback (range calculation)
if x is not None:
x = int(x)
if y is not None:
y = int(y)
if z is not None:
z = int(z)
node.position.set(x, y, z)
node_data = node.data(message_type=0)
self.session.broadcast_node(node_data)

View file

@ -668,6 +668,7 @@ class CoreNode(CoreNodeBase):
if self.up:
utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
self.check_cmd([constants.ETHTOOL_BIN, "-K", ifname, "rx", "off", "tx", "off"])
veth.name = ifname

View file

@ -73,7 +73,7 @@ class VnodeClient(object):
# run command, return process when not waiting
cmd = self._cmd_args() + args
logging.info("cmd wait(%s): %s", wait, cmd)
logging.debug("cmd wait(%s): %s", wait, cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
if not wait:
return 0
@ -124,7 +124,7 @@ class VnodeClient(object):
self._verify_connection()
args = utils.split_args(args)
cmd = self._cmd_args() + args
logging.info("popen: %s", cmd)
logging.debug("popen: %s", cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE, stdin=PIPE)
return p, p.stdin, p.stdout, p.stderr
@ -157,7 +157,7 @@ class VnodeClient(object):
# run command, return process when not waiting
args = utils.split_args(args)
cmd = self._cmd_args() + args
logging.info("redircmd: %s", cmd)
logging.debug("redircmd: %s", cmd)
p = Popen(cmd, stdin=infd, stdout=outfd, stderr=errfd)
if not wait:

View file

@ -1018,14 +1018,7 @@ class WlanNode(CoreNetwork):
logging.info("adding model: %s", model.name)
if model.config_type == RegisterTlvs.WIRELESS.value:
self.model = model(session=self.session, _id=self.id)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
self.updatemodel(config)
elif model.config_type == RegisterTlvs.MOBILITY.value:
self.mobility = model(session=self.session, _id=self.id)
self.mobility.update_config(config)
@ -1033,20 +1026,19 @@ class WlanNode(CoreNetwork):
def update_mobility(self, config):
if not self.mobility:
raise ValueError("no mobility set to update for node(%s)", self.id)
self.mobility.set_configs(config, node_id=self.id)
self.mobility.update_config(config)
def updatemodel(self, config):
if not self.model:
raise ValueError("no model set to update for node(%s)", self.id)
logging.info("node(%s) updating model(%s): %s", self.id, self.model.name, config)
self.model.set_configs(config, node_id=self.id)
self.model.update_config(config)
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.updateconfig()
def all_link_data(self, flags):
"""

View file

@ -148,9 +148,7 @@ def split_args(args):
:return: shell-like syntax list
:rtype: list
"""
logging.info("split args: %s - %s", args, type(args))
if isinstance(args, basestring):
logging.info("splitting args")
args = shlex.split(args)
return args

View file

@ -14,7 +14,7 @@
}
},
"root": {
"level": "DEBUG",
"level": "INFO",
"handlers": ["console"]
}
}

View file

@ -458,18 +458,29 @@ class TestGrpc:
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
wlan.setmodel(BasicRangeModel, BasicRangeModel.default_values())
session.instantiate()
range_key = "range"
range_value = "300"
range_value = "50"
# then
with client.context_connect():
response = client.set_wlan_config(session.id, wlan.id, {range_key: range_value})
response = client.set_wlan_config(session.id, wlan.id, {
range_key: range_value,
"delay": "0",
"loss": "0",
"bandwidth": "50000",
"error": "0",
"jitter": "0"
})
# then
assert response.result is True
config = session.mobility.get_model_config(wlan.id, BasicRangeModel.name)
assert config[range_key] == range_value
assert wlan.model.range == int(range_value)
def test_get_emane_config(self, grpc_server):
# given