1,5 → 1,6 |
using System; |
using System.Collections; |
using System.IO; |
using System.Net; |
using System.Net.Sockets; |
using System.Threading; |
12,6 → 13,12 |
// FIXME option to not store parsed data, just raw packets and reparse on demand |
namespace TCPproxy |
{ |
public enum BinLogTypes |
{ |
None = 1, |
TcpConnection |
} |
|
public enum LogLevel |
{ |
Critical, |
34,6 → 41,7 |
|
public enum TcpMessageDirection |
{ |
None, |
Local, |
Remote |
} |
251,6 → 259,15 |
TcpLogEventArgs e = new TcpLogEventArgs(level, null, ex); |
OnLog(e); |
} |
|
public void ReadBinLog(BinaryReader reader) |
{ |
// tcp connections |
TcpConnection tcp; |
while((tcp = TcpConnection.ReadBinLog(reader)) != null) { |
OnNewTcp(new TcpConnectionEventArgs(tcp)); |
} |
} |
} |
|
public class TcpConnection |
350,7 → 367,8 |
|
public void Cancel() |
{ |
worker.Cancel(); |
if(worker != null) |
worker.Cancel(); |
} |
|
protected TcpMessage Append(TcpMessageDirection direction, byte[] newBytes) |
388,13 → 406,11 |
} |
} |
|
|
public override string ToString() // FIXME delete the method |
{ |
return id + " " + startTimestamp.ToString("HH:mm:ss.ffff"); |
} |
|
|
protected void SetLocalPoint(IPEndPoint localPoint) |
{ |
this.localPoint = localPoint; |
575,6 → 591,113 |
OnLog(e); |
} |
|
private void WriteEndPoint(BinaryWriter writer, IPEndPoint endPoint) |
{ |
// end point as (family as int, ip length, ip as bytes, port) |
byte[] ipBuf = endPoint.Address.GetAddressBytes(); |
writer.Write((UInt32)endPoint.AddressFamily); |
writer.Write((UInt32)ipBuf.Length); |
writer.Write(ipBuf); |
writer.Write((UInt32)endPoint.Port); |
} |
|
public void WriteBinLog(BinaryWriter writer) |
{ |
// header |
writer.Write((byte)BinLogTypes.TcpConnection); |
|
// id as (length, UTF-8) |
byte[] idBuf = Encoding.UTF8.GetBytes(id); |
writer.Write((UInt32)idBuf.Length); |
writer.Write(idBuf); |
|
// timestamps as ticks |
writer.Write((UInt64)startTimestamp.Ticks); |
writer.Write((UInt64)localEndTimestamp.Ticks); |
writer.Write((UInt64)remoteEndTimestamp.Ticks); |
|
// end points as (family as int, ip length, ip as bytes, port) |
WriteEndPoint(writer, localPoint); |
WriteEndPoint(writer, remotePoint); |
|
// states as byte |
writer.Write((byte)localState); |
writer.Write((byte)remoteState); |
|
// each tcp message as (direction as byte, timestamp in ticks, length, content) |
foreach(TcpMessage message in messages) { |
writer.Write((byte)message.Direction); |
writer.Write((UInt64)message.Timestamp.Ticks); |
writer.Write((UInt32)message.Length); |
writer.Write(message.Bytes, 0, message.Length); |
} |
|
// end of stream marker |
writer.Write((byte)TcpMessageDirection.None); |
} |
|
private static IPEndPoint ReadEndPoint(BinaryReader reader) |
{ |
// end point as (family as int, ip length, ip as bytes, port) |
AddressFamily fam = (AddressFamily)reader.ReadInt32(); |
int addressLength = reader.ReadInt32(); |
byte[] addressBytes = reader.ReadBytes(addressLength); |
int port = reader.ReadInt32(); |
IPAddress address = new IPAddress(addressBytes); |
|
return new IPEndPoint(address, port); |
} |
|
internal static TcpConnection ReadBinLog(BinaryReader reader) |
{ |
// header |
BinLogTypes recordType = (BinLogTypes)reader.ReadByte(); |
|
if(recordType == BinLogTypes.None) |
return null; |
else if(recordType == BinLogTypes.TcpConnection) { |
} |
else |
throw new Exception("Wrong data type"); |
|
// id as (length, UTF-8) |
int idLength = (int)reader.ReadUInt32(); |
string id = Encoding.UTF8.GetString(reader.ReadBytes(idLength)); |
|
TcpConnection tcp = new TcpConnection(id); |
|
// timestamps as ticks |
tcp.startTimestamp = new DateTime((long)reader.ReadUInt64()); |
tcp.localEndTimestamp = new DateTime((long)reader.ReadUInt64()); |
tcp.remoteEndTimestamp = new DateTime((long)reader.ReadUInt64()); |
|
// end points as (family as int, ip length, ip as bytes, port) |
tcp.localPoint = ReadEndPoint(reader); |
tcp.remotePoint = ReadEndPoint(reader); |
|
// states as byte - read but ignore |
reader.ReadByte(); |
reader.ReadByte(); |
|
// each tcp message as (direction as byte, timestamp in ticks, length, content) |
tcp.localState = SocketState.Closed; |
tcp.remoteState = SocketState.Closed; |
for(;;) { |
TcpMessageDirection direction = (TcpMessageDirection)reader.ReadByte(); |
if(direction == TcpMessageDirection.None) break; // end of stream marker |
|
DateTime timestamp = new DateTime((long)reader.ReadUInt64()); |
int bufLength = (int)reader.ReadUInt32(); |
byte[] buf = reader.ReadBytes(bufLength); |
|
TcpMessage msg = tcp.Append(direction, buf); |
msg.SetTimestamp(timestamp); |
} |
tcp.OnUpdate(new TcpEventArgs()); |
|
return tcp; |
} |
|
protected class SocketWorker |
{ |
private enum SendCommandType |
1208,6 → 1331,9 |
{ |
newMessageEvent.Reset(); |
moved = messagesEnum.MoveNext(); |
|
if(!moved && messages.LocalState == SocketState.Closed && messages.RemoteState == SocketState.Closed) |
return false; |
} |
|
if(moved) break; |
1293,20 → 1419,19 |
} |
} |
|
private TcpConnection messages; |
private AutoResetEvent requestEvent = new AutoResetEvent(false); // new request found |
private AutoResetEvent nextMessageEvent = new AutoResetEvent(false); // request goes to next TCP message |
private LinkedList https = new LinkedList(); |
private ParsePosition requestPos; |
private ParsePosition responsePos; |
private AutoResetEvent newMessageEvent = new AutoResetEvent(false); // new TCP message available |
private Thread runThread; |
private TcpConnection messages; |
private AutoResetEvent requestEvent = new AutoResetEvent(false); // new request found |
private AutoResetEvent nextMessageEvent = new AutoResetEvent(false); // request goes to next TCP message |
private LinkedList https = new LinkedList(); |
private ParsePosition requestPos; |
private ParsePosition responsePos; |
private Thread runThread; |
|
public static HttpParser Parse(TcpConnection messages) |
{ |
HttpParser parser = new HttpParser(messages); |
parser.runThread = new Thread(new ThreadStart(parser.Run)); |
parser.RunThread.Name = "HttpParser.Run"; |
parser.runThread.Name = "HttpParser.Run"; |
parser.runThread.Start(); |
|
return parser; |
1325,7 → 1450,9 |
|
private HttpParser(TcpConnection messages) |
{ |
this.messages = messages; |
this.messages = messages; |
this.requestPos = new ParsePosition(messages, nextMessageEvent); |
this.responsePos = new ParsePosition(messages, null); |
InitTables(); |
} |
|
1338,9 → 1465,6 |
|
try |
{ |
requestPos = new ParsePosition(messages, nextMessageEvent); |
responsePos = new ParsePosition(messages, null); |
|
responseThread = new Thread(new ThreadStart(MatchResponses)); |
responseThread.Name = "HttpParser.MatchResponses"; |
responseThread.Start(); |
2240,7 → 2364,7 |
|
public class TcpMessage |
{ |
private TcpMessageDirection direction; |
private TcpMessageDirection direction = TcpMessageDirection.None; |
private byte[] bytes; |
private int length = 0; |
private DateTime timestamp; |
2274,6 → 2398,11 |
get { return timestamp; } |
} |
|
internal void SetTimestamp(DateTime timestamp) |
{ |
this.timestamp = timestamp; |
} |
|
internal TcpMessage() |
{ |
this.timestamp = DateTime.Now; |