[solved]send_data

Posted By: Wjbender

[solved]send_data - 06/10/15 12:12

I need some help here with c#

I see I can only use send_data in c# instead of send_var , as i am new to whole network thing and stil new to c# , I first tried sending a simple string with send_data , it works fine .

now I wanted to try sending a structure with a string and a intptr in it , instead.

I tried marshalling the structure to intptr and sending it like that , then on the server/client event I tried marshalling the ptr back to a structure ,then reading the string and data from that .

However i cannot figure out where I went wrong because I get errors , so after a while I got rid of the code and now here I am asking for a bit of help in doing this correctly ,marshalling sending/receiving a struct and reconverting back with send_data , if you know how ?

Posted By: Wjbender

Re: send_data - 06/10/15 14:50

useless .
Posted By: Ch40zzC0d3r

Re: send_data - 06/10/15 15:12

A struct pointer just points to some memory location.
So you receive the data and can directly cast the data as struct, I didnt do that alot on C# yet but since pointers are the same on C# and C++ and think it should work that way.

http://stackoverflow.com/questions/2297598/passing-a-struct-pointer-as-a-parameter-in-c-sharp
Posted By: Wjbender

Re: send_data - 06/10/15 15:28

I don't know what's up , I still think my marshalling was correct , and to be sure I wil rather test the Marshall back and forth between two simple functions, instead of across the network session ,my suspicion is that the memmory is the problem across the session because I am not using two separate computers ,instead I am running the c# compiled exe and setting the one as server and other as client while one of them I execute in debug mode to catch any unknown exceptions from the debug break , if my test idea works then my suspicion might be on the dot .

other than that it's useless to keep worring about send_data , I wil just move on to other tests .
Posted By: Wjbender

Re: send_data - 06/11/15 12:47

so i have tested the conversion across simple functions ,it works with no problem.
i am fully able to read the data like this with one instance of the application which
tells me my conversion is fine
heres example code i used :

Code:
//this is a packet to be send by send_data_to
[StructLayout(LayoutKind.Sequential)]
public class packet
{
   public string message;
}

//test marshal packet to intptr
public IntPtr to_intptr(object obj)
{
   IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
   Marshal.StructureToPtr(obj, ptr, false);
   return ptr;
}

//test demarshal intptr to packet
public object to_struct(IntPtr ptr, Type t)
{
   return Marshal.PtrToStructure(ptr, t);
}

//test recieve marshaled packet across function
public void recieve_packet(IntPtr ptr)
{
	//get packet from intptr
   packet my_packet = (packet)to_struct(ptr, typeof(packet));
   Marshal.FreeHGlobal(ptr);
   //a test message
   network.network_events.mes = my_packet.message;
}

//test send packet across function
public void send_packet(packet ppacket)
{
	//marshal packet to intptr
   IntPtr ptr = to_intptr(ppacket);
   //send intptr
   recieve_packet(ptr);
}

.......
//inside my test loop        
if (EngVar.key_3 && key3)
{
  key3 = false;
  //create packet
  packet mypacket = new packet();
  mypacket.message = "hello there";
  //test send
  send_packet(mypacket);
}



why do i convert ?

because the wrapper needs the conversion to intptr because
we do not use unsafe void* pointers in c# right.

in the wrapper ,the native engine function send_data_to is wrapped like:
Code:
public static double send_data_to(ENTITY entity, IntPtr data, int size)
{
   IntPtr entityPointer = IntPtr.Zero;
   if (entity != null)
   {
       entityPointer = entity.getIntPtr();
   }

   return Conversion.varToDouble(NativeEngFun.send_data_to(entityPointer,data,Conversion.doubleToVar(size)));
}



and the native send_data_to which calls the dll function is:
Code:
[DllImport("acknex.dll", CallingConvention = CallingConvention.Cdecl)]
internal static extern int send_data_to(IntPtr param0, IntPtr param1, int param2);



now ,that that's obvious and out of the way to whom-ever is reading.
let me get to how i tried doing it across the network.
heres my network test class file.

Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading;
using System.Runtime.InteropServices;

using AcknexWrapper;

namespace network
{
    //client information container
    class client_info
    {
        public string player_name;
        public int id;
    }//client information container

    //list of clients information containers
    static class connected_clients
    {
        public static List<client_info> client_ids = new List<client_info>();
    }//list of clients information containers

	  //the packet to be send
     [StructLayout(LayoutKind.Sequential)]
     public class packet
     {
         public string message;
     }
        
	  //marshalling & demarshaling helper
     static class packet_convert
     {
         public static IntPtr to_intptr(object obj)
         {
             IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(obj));
             Marshal.StructureToPtr(obj, ptr, false);
             return ptr;
         }
         public static object to_struct(IntPtr ptr, Type t)
         {
             return Marshal.PtrToStructure(ptr, t);
         }
     }

    //event handler for server & clients
    static class network_events
    {
        public static string mes;

        #region client_events
        //client recieved an event
        public static IEnumerable<int> on_client(IntPtr ptr)
        {
            //the server has send data to the client
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_DATA)
            {
                //mes = AcknexWrapper.Native.Conversion.getStringFromIntPtr(ptr);
                if (ptr != IntPtr.Zero)
                {
                    packet my_packet  = (packet)packet_convert.to_struct(ptr, typeof(packet));
                    network.network_events.mes = my_packet.message;
                }
            }
            //client has joined session
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_JOIN)
            {
            }
            //client was dropped
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_LEAVE)
            {
            }
            yield return 1;
        }//client recieved an event

        #endregion

        #region server_events
        //server recieved an event
        public static IEnumerable<int> on_server(IntPtr ptr,double id)
        {
            //the client has send data to the server
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_DATA)
            {
            }
            //client has joined session
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_JOIN)
            {
                client_info this_client= new client_info();
                this_client.id = (int)id;
                this_client.player_name = AcknexWrapper.Native.Conversion.getStringFromIntPtr(ptr);
                connected_clients.client_ids.Add(this_client);
            }
            //client was dropped
            if (EngVar.event_type == AcknexWrapper.Flags.EVENT_LEAVE)
            {
            }
            yield return 1;
        }//server recieved an event
        #endregion

    }//event handler for server & clients

    public class mp_session
    {
        //open a session on the server
        public bool open_session(string session)
        {
            if (EngFun.session_open(session) > 0)
            {
                return true;
            }
            else return false;
        }//open a session on the server

        //connect to a session on the server
        public bool connect_to_session(string session,string hostname)
        {
            if (EngFun.session_connect(session, hostname) > 0)
            {
                return true;
            }
            else return false;
        }//connect to a session on the server

        //close the session
        public void close_session()
        {
            EngFun.session_close();
        }//close the session

        //send a string to client/s or server
        //from client to server target must be null
        //from server to all clients ,target must be null
        //from server to the client that created the target entity
        //The buffer size should not exceed about 1000 bytes - data packets above that size often get lost on transmission over the Internet
        public void session_send_string(ENTITY target,string str)
        {
            if (str.Length > 0)
            {
                //The buffer size should not exceed about 1000 bytes
                //data packets above that size often get lost on transmission over the Internet
                if ((sizeof(char) * str.Length) < 1000)
                {
                    EngFun.send_data_to(target, AcknexWrapper.Native.Conversion.getIntPtrForString(str), sizeof(char) * str.Length);
                }
            }
        }

        public void session_send_packet_to(ENTITY target, packet this_packet)
        {
            IntPtr ptr = packet_convert.to_intptr(this_packet);
            int size=Marshal.SizeOf(this_packet);
            //int size = Marshal.SizeOf(ptr);
            EngFun.send_data_to(target,ptr,size);
            Marshal.FreeHGlobal(ptr);
        }

    }
}



which i then call like this again in my main loop:
Code:
//test send string to clients
if (EngVar.key_3 && key3)
{
  key3 = false;
  //multiplayer_session.session_send_string(null, "hello there");
  packet mypacket = new packet();
  mypacket.message = "hello there";
  multiplayer_session.session_send_packet_to(null, mypacket);
}



then i run one instance of the application in debug mode and the other from
the exe file , so that i can set one as the server ,the other as the client.
i then press 3 to send the packet to all clients ,then when the debugger breaks
in to the on_client event ,it breaks at the demarshalling code with an exception
of trying to read/write protected memmory at:
Code:
public static object to_struct(IntPtr ptr, Type t)
{
    return Marshal.PtrToStructure(ptr, t);
}



which is taken from:
Code:
packet = (packet)packet_convert.to_struct(ptr, typeof(packet));



and i have tried everything i could think off , changing packing ,determining the size differently etc etc
i cannot figure out whats going wrong , i am not even sure if the events are of the correct parameters , but sending a string instead of a packet works fine so i
am assuming its correct , this is not to important but i would like to know whats wrong , although like i said i think its a memmory thing but i am not sure anymore .

help is welcome .

Posted By: Ch40zzC0d3r

Re: send_data - 06/11/15 13:25

From what I can see:
Your send string func might be wrong because you have to send the string.length + 1 due to null terminator.
I also dont know why you call Marshal.FreeHGlobal(ptr) since you only received the pointer (unless you _want_ to erase the data after sending).
In your "object to_struct" you should add a check for the pointer not being null.
Otherwise I cant see a real error here, but Im not really good with C# anyways
Hope that helped a bit
Posted By: Wjbender

Re: send_data - 06/11/15 13:36

the send_string is the one that fully works , the session_send_packet_to is the one I am testing ,it successfully works until the data recieved event is triggered and I try to get the data from the intptr is where it fails with an exception , the freeing doesnt matter at this point I can comment it out and the result stays the same (same problem persists)

I do not really need to check if the intptr is zero because I check it in the event before calling the to_struct .

to me it seems like the intptr in the event parameter`s memmory is held and does not belong to me ? how am I going to test this weird theory I now have
Posted By: Ch40zzC0d3r

Re: send_data - 06/11/15 15:46

Thats easy, you either use a debugger (OllyDbg, WinDbg) or just Cheat Engine which I'd recommend. Its easy to use, just attach to the process, display the address of the pointer in a msgbox and goto memory-view in CE laugh
Posted By: Wjbender

Re: send_data - 06/11/15 17:10

I do have cheatengine but anyhow I debugged a little longer with visual studio and I see that the object is converted back on the event ,depending if I debug the client or server , but the message is empty .

now in the manual it says that:

The event function on the receiving PC receives a
pointer to the buffer as its first argument. The
buffer is only valid during the event function, and is
deallocated afterwards.

"deallocated afterwards." 0_o

soo does this not tell me now that I cannot demarshal because for the engine to be able to "deallocate" it ,it would mean I cannot access that memmory (buffer) by demarshalling because demarshalling needs full access to that memmory anyway ?

I am fully confused now , does this require a memcpy equivalent ?

.....
Posted By: Ch40zzC0d3r

Re: send_data - 06/11/15 18:27

look its really easy:
Code:
char szData[256];
if(recv(sock, szData, 256, flags))
    callback(szData, 256, id);



since this is all executed from a function its only on the stack!
all the data will cleared after the engine function which called your callback returns which is kind of de-allocate.
So when you ONLY use the stuff in your callback its fine, if you need it longer memcpy it to a global structure wink
Posted By: Wjbender

Re: send_data - 06/11/15 19:49

your right it should really be as easy as that , like the test I did between two functions which worked no problem , but somehow I am missing something here ,maby the string in the class/structure should be converted . I don't know and that's why I am jumping on the delusional highway lol , I wil figure it out sooner or later .

I don't believe that I will really need it , because I stil have to try out skills ,if it turns out that I need it for some reason and I still couldn't figure out what I did wrong I wil simply resort to a dll function or two .
Posted By: Wjbender

Re: send_data - 06/11/15 20:31

aaaaah and like magic I jumped on the issue without realising it , I took away the string in the packet class and dropped in a int value which should be supported across from c# to the engine dll and what do you know , tadaaa it works as it was supposed to .

so the conclusion : I need to marshal/convert the string or any unsupported members of the packet class ,or use different supported types .

Posted By: Ch40zzC0d3r

Re: send_data - 06/11/15 20:38

so you used a string and no char array? lol
Posted By: Wjbender

Re: send_data - 06/11/15 20:40

yup but I am sure I can still marshal it as an array or whatever (man I am really tired of writing marshal ) hurpy durpy
Posted By: Wjbender

Re: send_data - 06/12/15 11:49

thanks for the help this was my solution
Code:
[StructLayout(LayoutKind.Sequential)]
public class packet
{
   [MarshalAs (UnmanagedType.ByValTStr,SizeConst=256)] public string message;
   public int id;
}

© 2024 lite-C Forums