/* * ImondConnection.cs - .NET library for Imond communication * * Copyright (c) 2012 - Christian Schwinn - christianschwinn@quadrant1.net * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. */ using System; using System.Collections.Generic; using System.Text; using System.Net.Sockets; using System.Runtime.InteropServices; namespace ImoncLib { /// /// The class ImondConnection can create a TCP connection to a fli4l router, /// send commands over this connection and retrieve the the answers to commands. /// In opposition to Imond the indexes for channels start with 0. /// Given indexes are incremented automatically. /// [ComVisible(true), Guid("B7046C0D-4EC7-43E7-8BCB-88DADBE1EA6E"), ProgId("ImoncLib.ImondConnection"), ClassInterface(ClassInterfaceType.None)] public class ImondConnection : IImondConnection, IDisposable { private TcpClient tcpSocket; private int timeoutInMillis = 100; private string[] circuitNames; private string[] circuitDevices; // -------------------------------------------------------------------------- /// /// Create a new TcpClient which is not connected yet. /// public ImondConnection() { tcpSocket = new TcpClient(); circuitNames = new string[0]; circuitDevices = new string[0]; } // -------------------------------------------------------------------------- #region IImondConnection Members /// /// Connects to an Imond without using a password. /// /// hostname or IP address of the fli4l router /// listening port of the Imond /// number of circuits defined on the router public int connectWithoutPassword(string host, int port) { if (port < 1 || port > 65535) return -1; tcpSocket.Connect(host, port); return readCircuits(); } // -------------------------------------------------------------------------- /// /// Connects to an Imond when a password is needed for sending user commands. /// /// hostname or IP address of the fli4l router /// listening port of the Imond /// password for sending user commands /// number of circuits defined on the router public int connectWithPassword(string host, int port, string userpass) { if (port < 1 || port > 65535) return -1; tcpSocket.Connect(host, port); if (!sendNonEmptyUserPass(userpass)) return -1; return readCircuits(); } // -------------------------------------------------------------------------- /// /// Returns the nummber of circuits of the router. /// /// number of circuits defined on the router public int nrOfCircuits { get { return circuitNames.Length; } } // -------------------------------------------------------------------------- /// /// Returns if the TCP connection to the router established. /// /// true if the connection is established, false otherwise public bool isConnected { get { return tcpSocket.Connected; } } // -------------------------------------------------------------------------- /// /// Disconnects from the router by sending the quit command. /// public void disconnect() { quit(); } // -------------------------------------------------------------------------- /// /// Fetches the uptime from the router. /// /// time in the format "days'd' hh:mm:ss" public string getUpTime() { TimeSpan time = TimeSpan.FromSeconds(parseSingleIntOutput(uptime())); return string.Format("{0:d}d {1:D2}:{2:D2}:{3:D2}", time.Days, time.Hours, time.Minutes, time.Seconds); } // -------------------------------------------------------------------------- /// /// Fetches the current CPU load from the router. /// /// CPU load in a range from 0 to 100 public int getCPULoad() { return parseSingleIntOutput(cpu()); } // -------------------------------------------------------------------------- /// /// Gets the name of the circuit with the index circuitIndex. /// /// index of the circuit /// Name of the circuit, e.g. "DSL" when PPPOE_NAME='DSL' was set in config/dsl.txt public string getCircuitName(int circuitIndex) { if (!isIndexInRange(circuitIndex)) return ""; return circuitNames[circuitIndex]; } // -------------------------------------------------------------------------- /// /// Returns if the circuit with the index circuitIndex has established an internet connection. /// /// index of the circuit /// true if the router returns "Online" as status of the circuit, false otherwise public bool isOnline(int circuitIndex) { if (!isIndexInRange(circuitIndex)) return false; return "Online".Equals(parseSingleStringOutput(status(circuitDevices[circuitIndex]))); } // -------------------------------------------------------------------------- /// /// Gets the IP address assigned to the circuit with the index circuitIndex. /// /// index of the circuit /// IP address of the circuit if the circuit is online, the empty string otherwise public string getIPAddress(int circuitIndex) { if (!isIndexInRange(circuitIndex)) return ""; return parseSingleStringOutput(ip(circuitDevices[circuitIndex])); } // -------------------------------------------------------------------------- /// /// Gets the online time of the circuit with the index circuitIndex. /// /// index of the circuit /// time in the format "hh:mm:ss" if the circuit is online, the empty string otherwise public string getOnlineTime(int circuitIndex) { if (!isIndexInRange(circuitIndex)) return ""; return parseSingleStringOutput(onlineTime(circuitDevices[circuitIndex])); } // -------------------------------------------------------------------------- /// /// Gets the current download and upload rate of the circuit with the index circuitIndex. /// /// index of the circuit /// delimiter used for separating download and upload rate /// download ans upload rates in Bytes/s; -1 and -1 if an error occured public string getDownAndUpRate(int circuitIndex, string separator) { if (!isIndexInRange(circuitIndex)) return "-1" + separator + "-1"; int[] downAndUp = parseDoubleIntOutput(rate(circuitDevices[circuitIndex])); return downAndUp[0].ToString() + separator + downAndUp[1].ToString(); } #endregion // -------------------------------------------------------------------------- private int readCircuits() { int nrOFCircuits = readNrOfCircuits(); if (nrOFCircuits < 1) return -1; circuitNames = new string[nrOFCircuits]; circuitDevices = new string[nrOFCircuits]; for (int i = 1; i <= nrOFCircuits; i++) { circuitNames[i - 1] = readCircuitName(i); circuitDevices[i - 1] = readDevice(i); } return nrOFCircuits; } // -------------------------------------------------------------------------- private bool sendNonEmptyUserPass(string userpass) { if (userpass == null || userpass.Length < 1) return false; int answer = parseSingleIntOutput(pass(userpass)); if (answer > 0) return true; return false; } // -------------------------------------------------------------------------- private int readNrOfCircuits() { return parseSingleIntOutput(circuits()); } // -------------------------------------------------------------------------- private string readCircuitName(int ciIndex) { return parseSingleStringOutput(circuit(ciIndex)); } // -------------------------------------------------------------------------- private string readDevice(int ciIndex) { return parseSingleStringOutput(device(ciIndex)); } // -------------------------------------------------------------------------- private void quit() { sendCommand("quit"); } // -------------------------------------------------------------------------- private string pass(string pass) { return sendCommandWithOutput("pass " + pass); } // -------------------------------------------------------------------------- private string circuits() { return sendCommandWithOutput("circuits"); } // -------------------------------------------------------------------------- private string circuit(int ciIndex) { return sendCommandWithOutput("circuit " + ciIndex.ToString()); } // -------------------------------------------------------------------------- private string device(int ciIndex) { return sendCommandWithOutput("device " + ciIndex.ToString()); } // -------------------------------------------------------------------------- private string uptime() { return sendCommandWithOutput("uptime"); } // -------------------------------------------------------------------------- private string cpu() { return sendCommandWithOutput("cpu"); } // -------------------------------------------------------------------------- private string status(string channelId) { return sendCommandWithOutput("status " + channelId); } // -------------------------------------------------------------------------- private string onlineTime(string channelId) { return sendCommandWithOutput("online-time " + channelId); } // -------------------------------------------------------------------------- private string rate(string channelId) { return sendCommandWithOutput("rate " + channelId); } // -------------------------------------------------------------------------- private string ip(String channelId) { return sendCommandWithOutput("ip " + channelId); } // -------------------------------------------------------------------------- private bool isIndexInRange(int index) { return index >= 0 && index < circuitDevices.Length; } // -------------------------------------------------------------------------- private string parseSingleStringOutput(string output) { if (output.StartsWith("ERR")) return null; return output.Substring(3); } // -------------------------------------------------------------------------- private int parseSingleIntOutput(string output) { if (output.StartsWith("ERR")) return -1; return int.Parse(output.Substring(3)); } // -------------------------------------------------------------------------- private int[] parseDoubleIntOutput(string output) { int[] doubleOutput = { -1, -1 }; if (output.StartsWith("ERR")) return doubleOutput; string[] parts = output.Substring(3).Split(' '); if (parts.Length < 2) return doubleOutput; doubleOutput[0] = int.Parse(parts[0]); doubleOutput[1] = int.Parse(parts[1]); return doubleOutput; } // -------------------------------------------------------------------------- private void sendCommand(string command) { if (!command.EndsWith("\n")) command += "\n"; if (!tcpSocket.Connected) return; byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(command.Replace("\0xFF", "\0xFF\0xFF")); tcpSocket.GetStream().Write(buf, 0, buf.Length); System.Threading.Thread.Sleep(timeoutInMillis); } // -------------------------------------------------------------------------- private string sendCommandWithOutput(string command) { sendCommand(command); if (!tcpSocket.Connected) return "ERR"; StringBuilder sb = new StringBuilder(); do { int input = tcpSocket.GetStream().ReadByte(); if (input == -1) break; sb.Append((char)input); } while (tcpSocket.Available > 0); return sb.ToString().Trim(); } // -------------------------------------------------------------------------- #region IDisposable Members public void Dispose() { } #endregion } // -------------------------------------------------------------------------- /// /// The interface defines the methods the ImondConnection shall provide. /// The interface is needed that ImondConnection can be initialized as ActiveX object. /// [ComVisible(true), Guid("DAE987D2-1B1F-4ACE-9390-2EC0A9A3DD02"), InterfaceType(ComInterfaceType.InterfaceIsDual)] public interface IImondConnection { int connectWithoutPassword(string host, int port); int connectWithPassword(string host, int port, string userpass); int nrOfCircuits { get; } bool isConnected { get; } void disconnect(); string getUpTime(); int getCPULoad(); string getCircuitName(int circuitIndex); bool isOnline(int circuitIndex); string getIPAddress(int circuitIndex); string getOnlineTime(int circuitIndex); string getDownAndUpRate(int circuitIndex, string separator); } }