#region License Information
/* HeuristicLab
* Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Xml;
using HeuristicLab.Core;
using HeuristicLab.Data;
namespace HeuristicLab.Communication.Data {
public class SocketData : ItemBase, IDataStream {
private TcpNetworkDriverConfiguration config;
public IDriverConfiguration Configuration {
get { return config; }
set { config = (TcpNetworkDriverConfiguration)value; }
}
private TcpListener tcpListener;
private TcpClient tcpIn;
private TcpClient tcpOut;
private string buffer;
public SocketData() {
tcpListener = null;
tcpIn = null;
tcpOut = null;
config = null;
buffer = "";
}
#region clone & persistence
// A socket cannot be cloned
public override object Clone(IDictionary clonedObjects) {
SocketData clone = new SocketData();
clonedObjects.Add(Guid, clone);
clone.tcpIn = tcpIn;
clone.config = (TcpNetworkDriverConfiguration)Auxiliary.Clone(config, clonedObjects);
clone.buffer = buffer;
return clone;
}
// A socket cannot be persisted
// but information can be persisted that will allow it to be recreated
public override XmlNode GetXmlNode(string name, XmlDocument document, IDictionary persistedObjects) {
XmlNode node = base.GetXmlNode(name, document, persistedObjects);
XmlNode configNode = PersistenceManager.Persist("Configuration", config, document, persistedObjects);
node.AppendChild(configNode);
XmlNode bufferNode = document.CreateNode(XmlNodeType.Element, "Buffer", null);
bufferNode.InnerText = buffer;
node.AppendChild(bufferNode);
return node;
}
// A socket cannot be persisted
// but information can be persisted that will allow it to be recreated
public override void Populate(XmlNode node, IDictionary restoredObjects) {
base.Populate(node, restoredObjects);
Configuration = (TcpNetworkDriverConfiguration)PersistenceManager.Restore(node.SelectSingleNode("Configuration"), restoredObjects);
buffer = node.SelectSingleNode("Buffer").InnerText;
if (tcpListener == null) StartListening();
}
#endregion
private void StartListening() {
tcpListener = new TcpListener(IPAddress.Any, config.SourcePort.Data);
tcpListener.Start();
}
public void Initialize(IDriverConfiguration configuration) {
Configuration = configuration;
StartListening();
}
public bool Connect() {
if (tcpIn == null || !tcpIn.Connected) {
if (tcpListener.Pending())
tcpIn = tcpListener.AcceptTcpClient();
}
if (tcpOut == null || !tcpOut.Connected) {
tcpOut = new TcpClient();
try {
tcpOut.Connect(new IPEndPoint(IPAddress.Parse(config.TargetIPAddress.Data), config.TargetPort.Data));
} catch (SocketException) {
tcpOut.Close();
tcpOut = null;
}
}
return (tcpIn != null && tcpIn.Connected) && (tcpOut != null && tcpOut.Connected);
}
public void Close() {
tcpListener.Stop();
if ((tcpOut != null && tcpOut.Connected) && (tcpIn != null && tcpIn.Connected)) {
Write("CLOSING");
if (Read() != null)
throw new InvalidOperationException("ERROR in SocketData: Out of sync during Close()");
}
if (tcpIn != null) {
tcpIn.Close();
tcpIn = null;
}
if (tcpOut != null) {
tcpOut.Close();
tcpOut = null;
}
buffer = "";
}
public void Write(string s) {
if (tcpOut == null || !tcpOut.Connected) Connect();
NetworkStream outStream = tcpOut.GetStream();
byte[] sendBytes = Encoding.ASCII.GetBytes(s + "\n.\n");
outStream.Write(sendBytes, 0, sendBytes.Length);
outStream.Flush();
return;
}
public string Read() {
if (tcpIn == null || !tcpIn.Connected) Connect();
NetworkStream inStream = tcpIn.GetStream();
byte[] receivedBytes;
int count = 0;
int messageEnd = -1;
int bufferCount = 0;
if (buffer.Length > 0) {
byte[] bufferBytes = Encoding.ASCII.GetBytes(buffer);
receivedBytes = new byte[1000 + bufferBytes.Length];
Array.Copy(bufferBytes, receivedBytes, bufferBytes.Length);
messageEnd = TerminationCheck(receivedBytes, 0, bufferBytes.Length);
count = bufferBytes.Length;
bufferCount = count;
buffer = "";
} else
receivedBytes = new byte[1000];
if (messageEnd < 0) {
byte[] tmp = new byte[1000];
bool done;
do {
int recvd = inStream.Read(tmp, 0, 1000);
if (recvd == 0) break;
count += recvd;
if (count > receivedBytes.Length) {
byte[] h = receivedBytes;
receivedBytes = new byte[2 * h.Length];
Array.Copy(h, receivedBytes, count - recvd);
}
Array.Copy(tmp, 0, receivedBytes, count - recvd, recvd);
if (count < 3) done = false;
else done = (receivedBytes[count - 1] == 10 && receivedBytes[count - 2] == 46 && receivedBytes[count - 3] == 10); // \n.\n
} while (!done);
messageEnd = TerminationCheck(receivedBytes, bufferCount, count - bufferCount);
}
if (messageEnd < 0) throw new InvalidOperationException("ERROR: message was not received");
if (messageEnd < count - 3)
buffer = Encoding.ASCII.GetString(receivedBytes, messageEnd + 3, count - messageEnd - 3);
string result = Encoding.ASCII.GetString(receivedBytes, 0, messageEnd);
if (result.Equals("CLOSING")) return null;
else return result;
}
private int TerminationCheck(byte[] buffer, int start, int length) {
for (int i = start ; i < start + length - 2 ; i++) {
if (buffer[i] == 10 && buffer[i + 1] == 46 && buffer[i + 2] == 10) return i;
}
return -1;
}
}
}