PDA

View Full Version : C# Initial Packet Query


alistairuk
7th December 2007, 16:46
Hi all,

I am attempting to connect to the InSim on an LFS server using c#.

So far I have:


TcpClient objTCPC = newTcpClient(this.strRemoteHost, this.intRemortPort);
NetworkStream objNS = objTCPC.GetStream();
Console.WriteLine("TCP Connected {0}:{1}", this.strRemoteHost, this.intRemortPort);
//Send Connection Packet
IS_ISI connect = newIS_ISI(0, "pass", "appname");


Basically the problem is I havn't used Structures before and in order to send the IS_ISI structure I created I need to convert it to a Byte array.

Can anyone help me out? The structure is defined as per the InSim specifications file;

//InSim Init - Packet to initialise the InSim System
publicstructIS_ISI
{
staticbyte Size = 44;
staticbyte Type = 1; //ISP_ISI
staticbyte ReqI = 1; //Requests IS_VER packet
staticUInt16 UDPPort = 0; //Port for UDP Replies 0 - 65535
staticUInt16 Flags = 32; //Bit flags for options
staticbyte Sp0 = 0;
staticbyte Prefix = System.Text.Encoding.ASCII.GetBytes("$")[0];
publicUInt16 Interval;
publicchar[] Admin;
publicchar[] IName;
public IS_ISI(UInt16 Interval, string Admin, string IName)
{
this.Interval = Interval;
this.Admin = Admin.ToCharArray();
this.IName = IName.ToCharArray();
}

}

T-RonX
7th December 2007, 17:51
using System.Runtime.InteropServices;

// Convert structure to byte array
public byte[] PacketToData(object SourceStruct)
{
int len = Marshal.SizeOf(SourceStruct); // Size of source structure
IntPtr Ptr = Marshal.AllocHGlobal(len); // Memory pointer to copy data to
byte[] data = new byte[len]; // Size of new aray
Marshal.StructureToPtr(SourceStruct, Ptr, false); // Copy struct to pointer
Marshal.Copy(Ptr, data, 0, len); // Copy pointer to byte array
Marshal.FreeHGlobal(Ptr); // Free pointer
return data; // Return byte array
}

// Convert byte array to a structure
public object DataToPacket(byte[] Data, object DestStruct)
{
int len = Marshal.SizeOf(DestStruct); // Size of destination structure
IntPtr Pointer = Marshal.AllocHGlobal(len); // Memory pointer to copy data to
Marshal.Copy(Data, 0, Pointer, Data.Length); // Copy array to pointer
DestStruct = Marshal.PtrToStructure(Pointer, DestStruct.GetType()); // Copy pointer to structure
Marshal.FreeHGlobal(Pointer); // Free pointer
return DestStruct; // Return object
}Pass the new instance of the ISI struct in the PacketToData() method and it will return a byte array.

To reverse it:
Pass the byte array you received in the DataToPacket() method to return a struct, example:

IS_VER VER = new IS_VER();
VER = (IS_VER)DataToPacket(packet, VER);

This should work. :)

--- Btw, how do you color your code like that?

alistairuk
7th December 2007, 18:17
Cheers, i'll give that a try.

No idea, I just copied and pasted it from Visual C# 2008 and it coloured it automatically.

alistairuk
7th December 2007, 18:59
Ok, ive run it but I get a TypeMissMatch error at;

Marshal.StructureToPtr(SourceStruct, Ptr, false);

T-RonX
7th December 2007, 19:04
what parameter did you pass in PacketToData()? Can you show me the complete error message?

alistairuk
7th December 2007, 19:10
I hope this is what you mean;


IS_ISI objConnect = newIS_ISI(0, this.strLFSPass, this.strAppName);
Byte[] data = PacketToData( objConnect );


When the debug pauses and I inspect the objects the objConnect has the correct values (as in structure above), is it possible ive defined the structure wrong?

T-RonX
7th December 2007, 19:16
Ahh, I forgot to tell you something, I'm sorry. You have to change your struct layout to sequential. This is how I declaied my struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct IS_ISI
{
public byte Size; // 44
public Enums.Packets Type; // ISP_ISI
public byte ReqI; // If non-zero LFS will send an IS_VER packet
public byte Zero; // 0

public ushort UDPPort; // Port for UDP replies from LFS (0 to 65535)
public ushort Flags; // Bit flags for options (see below)

public byte Sp0; // 0
public byte Prefix; // Special host message prefix character
public ushort Interval; // Time in ms between NLP or MCI (0 = none)

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Admin; // Admin password (if set in LFS)
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string IName; // A short name for your program
}

The first line is crucial, and dont forget to make the strings a static length like I did in the struct above.

alistairuk
7th December 2007, 19:23
it appears to be working now, thank you so much for your help.

T-RonX
7th December 2007, 19:25
Great. No problem m8. :)