/*
* 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);
}
}