• Welcome to Valhalla Legends Archive.
 

[C++] Inserting Null-Terminating Strings. (Cont.)

Started by Sorc.Polgara, December 04, 2004, 10:44 AM

Previous topic - Next topic

Sorc.Polgara

Make a packet buffer in C++.


I'm having problems converting and between different types.  Again, C++ is much different that VB6 and I am just frustrated.

I'm not quite understanding.  I've searched the forums a bit and I looked at Mynd's C# Packet Buffer (I think it is yours), but I can't make perfect sense of it b/c it's the other kind of C language.

I'm not quite sure but I the closest I think I've gotten is something like this:

DWORD prodID = 0x07;
char teststr[4];

memcpy(teststr, &prodID, 4);


Its doesn't work or seem to.

I've really tried making my own packet buffer.  I've tried not to post because some people get mad if I come across like I'm not giving any effort.

I've sort of daydreamed even in my calculus class about how I could make the packet buffer.  I've spent more hours working on this than playing with my Clan memebers.  Please help.

Adron


Sorc.Polgara

Quote from: Adron on December 04, 2004, 10:53 AM
That code is OK.

hmmmmm

My DebugOutput function might be the problem....

inline void DebugOutput(const char* buf)
{
int rem = 12;
int len = strlen(buf);

printf("%s\n%s%i\n%s\n", "-----------------------------------", "Size: ", len, "-----------------------------------");
for( int j = 0; j < len; j = (j + 12))
{
if( (len - j) < 12 )
rem = ((len - j));

for( int i = 0; i < rem; i++)
{
printf("%2X ", (buf[i + j]) & 0xFF);
}

printf("%5c", 0x20);

if( rem < 12 )
{
for( int spc = 0; spc < (3 * (12 - rem)); spc++ )
{
printf("%c", 0x20);
}
}


for( int l = 0; l < rem; l++ )
{
if((buf[j + l] == 0x20))
printf("%c", 0x2E);
else
printf("%c", buf[j + l]);
}
printf("\n\n");
}

}


It seems to work fine with strings that I tested it with "Qwert likes old, fat, short, bald men."


dunno.

OnlyMeat

Ill give you the best peace of advice iv ever come across,  sort of discovered it as well i suppose as i went along.

(1) Before you write any code try and put down in writing/diagram format the basic conceptual design of your application/module/class and your goals.

(2) The golden rule of problem solving is - it's all about simplifying and the way you do that is by breaking a problem down into smaller units of work i.e for a packet buffer the way to simplify it would be to create a packet buffer class ( usually polymorphic so you can extend it ) then add member functions to assemble/dissasemble it. An example of a simplified packet buffer:-


/* 1024 ( this should be as big as you need to store your largest buffer or possibly use a dynamic sizing buffer depending on it's contents - your choice )
*/
#define MAX_PKT 0x400

class CPacket
{
public:
   /////////////////////////////////////////
  // Standard class Constructor/Deconstructor
   CPacket(){m_pBuf = new char[MAX_PKT];} //allocate buf   
    ~CPacket(){delete [] m_pBuf;}  // deallocate buf

public:
  //////////////////////////////////////////
// Interface ( functions that assemble/dissasemble the       //packet)
  void AddDWORD( DWORD dwData );
  void AddWORD ( WORD wData );
  void AddBYTE ( BYTE byData );
  void AddString ( LPCSTR lpData );

  ////////////////////////////////////////////
// Functions that prepare the outgoing structure for sending
  virtual int Send ( char cID, SOCKET s );
  virtual int Serialize ( char cID ); for debug testing etc ( very usefull )

  ////////////////////////////////////////////
// Cleanup functions
  virtual void Clear(); // Resets any state data and the actual //buffer

  ////////////////////////////////////////////
// Disassemble functions ( for extracting primative types     //from the packet buffer
  ...

  ////////////////////////////////////////////
// Read functions ( more advanced i use these to read the //socket data directly into my packet buffer also it can do //length checks i.e bnet chat header + data section to //ensure a complete packet is received before dispatching it
virtual int ReadPart ( char* pBuf ) ;

  ////////////////////////////////////////////
// Status functions ( note most of these interfaces should be //polymorphic to allow overriding for different formats etc )
  virtual BOOL IsComplete(); // header + data section in case // of bnet chat
  virtual BOOL HasHeader();

etc etc.. you get the idea.

private:
char* m_pBuf; // internal packet buffer
int      nPos;     // current position within buffer
}

Now the assemble functions are pretty simple, you will just copy the data to your internal buffer used in your packet class 'm_pBuf' :-

for the function AddDWORD for example you could do this:

void CPacket::AddDWORD(DWORD dwData)
{
       // Copy the dword to our internal packet buffer
      memcpy(m_pBuf + nPos, &dwData, sizeof(DWORD));
       
      // Increment our buffer position counter
      nPos += sizeof(DWORD);
}


Thats a very simple example but it should get you started.

Adron

Quote from: bethra on December 04, 2004, 11:29 AM
My DebugOutput function might be the problem....

You really like to insert things using %c and %s? Much of what you've inserted that way could've been written directly in the format strings instead.. But that's not likely to be a problem.

You may want to replace all characters between 0 and 31 with '.' instead of just spaces.

Could you explain why you think your code isn't working? Show your test program and the output of it?



Sorc.Polgara

Quote from: Adron on December 04, 2004, 12:22 PM
Quote from: bethra on December 04, 2004, 11:29 AM
My DebugOutput function might be the problem....

You really like to insert things using %c and %s? Much of what you've inserted that way could've been written directly in the format strings instead.. But that's not likely to be a problem.

You may want to replace all characters between 0 and 31 with '.' instead of just spaces.

Could you explain why you think your code isn't working? Show your test program and the output of it?

ok

void DebugOutput(const char*);

int main(void)
{
unsigned long int iDWORD = 0x07;
char buff[4];

memcpy(buff, &iDWORD, sizeof(iDWORD));

DebugOutput(buff);

        //  I'm the chief of a clan and we all joke around with this 14y/o member :)
DebugOutput("Qwert smells");

return 0;
}

//=============================================================
// dump buffer in hex
inline void DebugOutput(const char* buf)
{
int rem = 12;
int len = strlen(buf);

printf("%s\n%s%i\n%s\n", "-----------------------------------", "Size: ", len, "-----------------------------------");
for( int j = 0; j < len; j = (j + 12))
{
if( (len - j) < 12 )
rem = ((len - j));

for( int i = 0; i < rem; i++)
{
printf("%2X ", (buf[i + j]) & 0xFF);
}

printf("%5c", 0x20);

if( rem < 12 )
{
for( int spc = 0; spc < (3 * (12 - rem)); spc++ )
{
printf("%c", 0x20);
}
}


for( int l = 0; l < rem; l++ )
{
if((buf[j + l] == 0x20))
printf("%c", 0x2E);
else
printf("%c", buf[j + l]);
}
printf("\n\n");
}

}


k here is what is returned for the string "Qwert smells":
Quote
-----------------------------------
Size:  12
-----------------------------------
51 77 65 72 74 20 73 6D 65 6C 6C 73           Qwert.smells

This is what I get for the string buff[4]:
Quote
-----------------------------------
Size:  1
-----------------------------------
7
This is what is displayed, but my computer actually beeps.  From the computer case/tower.  Not from my head phones or speakers.  The program doesn't crash though.

tA-Kane

Your computer could beep on this statement:for( int l = 0; l < rem; l++ )
{
if((buf[j + l] == 0x20))
printf("%c", 0x2E);
else
printf("%c", buf[j + l]);
}
printf("\n\n");
}
}
You should check to see if buf[j+l] <= 0x20, not if it's == 0x20. Otherwise, you may end up adding nulls, which some consoles won't handle nicely.

What are you expecting it to display?

0x7 is indeed the same as 0x00000007 when on a Windows platform. If you want it to display 07 00 00 00, then you'll need to add checks for those, and add zeros if necessary. Alternately, I think you can pass some sort of argument to printf() to make a minimum length of the hex str.

If you want it to display as 00 00 00 07, then you'll need to byteswap buf[] before you send it to the debug function.
Macintosh programmer and enthusiast.
Battle.net Bot Programming: http://www.bash.org/?240059
I can write programs. Can you right them?

http://www.clan-mac.com
http://www.eve-online.com

Mephisto

LoRd has a public packet buffer.  http://www.fictionwelive.com/lord -- note: prone to buffer overflows (a minimal risk if you make sure you're not overflowing it; unless he fixed it).

Sorc.Polgara

Quote from: Mephisto on December 04, 2004, 03:55 PM
LoRd has a public packet buffer.  http://www.fictionwelive.com/lord -- note: prone to buffer overflows (a minimal risk if you make sure you're not overflowing it; unless he fixed it).

ummmm link doesn't work... errr well it has nothing there.

Mephisto

Guess his hosting was shutdown, you should go ask him then.

iago

There are several packetbuffers around, written by various people.  But it's very good practice to write your own.  I highly recommend continuing with this.
This'll make an interesting test for broken AV:
QuoteX5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*


Sorc.Polgara

Quote from: tA-Kane on December 04, 2004, 03:49 PM
If you want it to display as 00 00 00 07, then you'll need to byteswap buf[] before you send it to the debug function.

Yeah! That is what I want it to display!  k, I'll try redo'ing my DebugOutput.  Thanks.

Yoni

Quote from: bethra on December 04, 2004, 05:51 PM
Quote from: tA-Kane on December 04, 2004, 03:49 PM
If you want it to display as 00 00 00 07, then you'll need to byteswap buf[] before you send it to the debug function.

Yeah! That is what I want it to display! k, I'll try redo'ing my DebugOutput. Thanks.

I think the problem is different. Look at your DebugOutput function. buf may contain "good nulls", but you're using strlen, which stops when it sees a null.
A solution: Pass len as a parameter, instead of setting len = strlen(buf).

Sorc.Polgara

#13
ok, I kind of modified my DebugOutput function.

Now, this is how I am trying to make the BNLS_REQUESTVERSIONBYTE (0x10) packet.  Is it correct?


// packet ID for BNLS_REQUESTVERSIONBYTE
BYTE pID = 0x10;
// packet Size of 0x10
WORD pSize = sizeof(WORD) + sizeof(BYTE) + sizeof(DWORD);
// product ID for Warcraft III
DWORD prodID = 0x07;
// packet buffer
char buff[sizeof(WORD) + sizeof(BYTE) + sizeof(DWORD)];

// constructing the packet buffer
memcpy(buff, &pSize, sizeof(pSize));
memcpy(buff + sizeof(WORD), &pID, sizeof(pID));
memcpy(buff + sizeof(WORD) + sizeof(BYTE), &prodID, sizeof(prodID));


Ya see, once I can get the gist of how to assemble the different datatypes into  a packet, then I can make my packet buffer work!



EDIT:  I also changed the name displayed.  Sorc.Polgara is my Bnet name.

Yoni

That looks correct.
Here is another way to do it, without using memcpy:


*(WORD*)(buff) = pSize;
*(BYTE*)(buff + sizeof(WORD)) = pID;
*(DWORD*)(buff + sizeof(WORD) + sizeof(BYTE)) = prodID;


And here is a more elegant way (with a few redundancies which you'll have to get over for the sake of elegancy), which you can think about while writing your packet buffer:


int pos = 0;

*(WORD*)(buff + pos) = pSize;
pos += sizeof(WORD);

*(BYTE*)(buff + pos) = pID;
pos += sizeof(BYTE);

*(DWORD*)(buff + pos) = prodID;
pos += sizeof(DWORD);


Edit:

Quote from: Sorc.Polgara on December 04, 2004, 10:44 AM
I've sort of daydreamed even in my calculus class about how I could make the packet buffer.

No! Do it in history class!