[Release] Work In Progress LoginServer Packet Documentation

10/21/2010 21:56 lesderid#1
I'm (edit: was) working on packet documentation for SRO, using my own file format.
LoginServer: [Only registered and activated users can see links. Click Here To Register...]
Character Selection: [Only registered and activated users can see links. Click Here To Register...]

Note: All (non-LoginServer) packets only work in kSRO.
Other versions will have other opcodes (and other packets).

Credits: Me, pushedx (for the awesome help), Windrius (for always being nice) and some (public) emulators.

Edit: The server moved to my new site: [Only registered and activated users can see links. Click Here To Register...] ([Only registered and activated users can see links. Click Here To Register...]).
I'm not working on any Silkroad stuff anymore, so I made it public for anyone to edit.

You can update and add files to that directory by connecting to the server ('lesderid.net') with an FTP client.
However, please use the same format as in the files I created, so it's straightforward and so the reading tool (r.php) will keep working.

The username and password are both 'pdoc'.
You can also use this to easily download all documentation files and to check the creation/edit date of the files so you have an idea of how accurate they are.


(Warning: The documentation is no longer being updated by me. Some of it might be outdated.)
10/22/2010 10:43 chea77er#2
Nice work.

You could write UString and String. So we know that is an Unicode / ASCII Text.
10/22/2010 17:40 lesderid#3
I hate tabs. They are never like they should be >.<

EDIT:
Firefox VS. Notepad++:
[Only registered and activated users can see links. Click Here To Register...]

Text size is not exactly the same.
10/23/2010 00:40 vpegas1234#4
wow, i dont know that language but i think thats a Good job..?

EDIT:
I read my sentence 4 times and i check that i was offending someone i think.
So what i wanna mean is: that is good right?
10/23/2010 07:12 lesderid#5
Quote:
Originally Posted by vpegas1234 View Post
wow, i dont know that language
It's just a documentation language that I made, it's not used for any other projects.

Quote:
Originally Posted by vpegas1234 View Post
but i think thats a Good job..?
It's helpful for people who want to make their own emulator.
11/17/2010 14:14 Yo123#6
btw:
#sticky!
11/17/2010 14:28 lesderid#7
Added Character Selection to the first post.
11/21/2010 13:28 CraYu#8
links are dead.
11/21/2010 16:16 lesderid#9
Quote:
Originally Posted by HeavyLegend View Post
links are dead.
They are up again, there was a problem at my hosting company.
11/21/2010 20:47 lvszoc#10
can you make other packets documentation ?
11/21/2010 22:09 lesderid#11
Quote:
Originally Posted by lvszoc View Post
can you make other packets documentation ?
Maybe some day I will.
11/21/2010 22:41 doublea500#12
wow ty!
11/23/2010 09:44 pushedx#13
Here are some other other stuff you can add:

0x600D is the Joymax MassiveMsg (as they call it) so rather than format packets that come in 0x600d through 0x600d, you can just have them as normal packets, then flag them as "massive". The logic of formatting any 0x600d packet is the same, so it'd help clear up the packets that can be sent through it.

For example, when the client ends 0x6100, which is the version information, the server responds with 0xA100. The 0xA100 packet comes in the 0x600d massive message packet since patch information can very well be a "huge packet". So instead of documenting packets through the 0x600d packet format, you should just do it normally.

Once you get 0xA100 added to your list, you can also add 0x2005 and 0x6005. The actual formats don't really matter since those packets are only used by the server processes, but a lot of people end up hard coding them in and they are not even needed. All the client needs is the 0xA100 packet which is in response to its 0x6100, so it's all balanced out. If you check my [Only registered and activated users can see links. Click Here To Register...] project, you can grab the format of the 0xA100 version packet as well. The code isn't the greatest, but I'm working on a new version of all my stuff that properly implements everything as it should be.

One note about 0x600d packets is the client has 4kb buffers, so even though you can send larger packets with Silkroad, you should only send 0x600d packets that are no more than 4kb in side. That means 4089 bytes of data + 1 byte data flag + 6 byte regular header. Also, massive messages can be encrypted and the client doesn't seem to complain. However, you can't send
any packet through 0x600d, since the client and their server hard code which packets to process from it. I think it's a bad design flaw on their part, but my code does support it, even if it's not "valid'.


Now about the security flags. The first byte is actually a bitset of flags to use. This is the structure:
Code:
#pragma pack( push, 1 )
struct TFlags
{
	uint8_t none : 1;
	uint8_t blowfish : 1;
	uint8_t security_bytes : 1;
	uint8_t handshake : 1;
	uint8_t handshake_response : 1;
	uint8_t _6 : 1;
	uint8_t _7 : 1;
	uint8_t _8 : 1;
};
#pragma pack( pop )
Now, based on which bits are set, the security code only processes packets and logic specific to those features. So trying to hard code each different mode works, like I had in my previous code, but it's really ineffeicent since the concepts are much easier. You'll see in my new security code what I'm talking about. Here's a simple example of building the initial security packet for a server to a client:
Code:
void GenerateHandshake( uint8_t mode )
	{
		m_security_flag = mode;

		m_client_security = true;

		PacketContainer response;
		response.opcode = 0x5000;

		response.data.Write< uint8_t >( mode );

		if( m_security_flags->blowfish )
		{
			m_initial_blowfish_key = rng();
			m_blowfish.Initialize( &m_initial_blowfish_key, sizeof( m_initial_blowfish_key ) );

			response.data.Write< uint64_t >( m_initial_blowfish_key );
		}

		if( m_security_flags->security_bytes )
		{
			m_seed_count = rng() % 0xFF;
			SetupCountByte( m_seed_count );

			m_crc_seed = rng() % 0xFF;

			response.data.Write< uint32_t >( m_seed_count );
			response.data.Write< uint32_t >( m_crc_seed );
		}

		if( m_security_flags->handshake )
		{
			m_handshake_blowfish_key = rng();
			m_value_x = rng() & 0x7FFFFFFF;
			m_value_g = rng() & 0x7FFFFFFF;
			m_value_p = rng() & 0x7FFFFFFF;
			m_value_A = G_pow_X_mod_P( m_value_p, m_value_x, m_value_g );

			response.data.Write< uint64_t >( m_handshake_blowfish_key );
			response.data.Write< uint32_t >( m_value_g );
			response.data.Write< uint32_t >( m_value_p );
			response.data.Write< uint32_t >( m_value_A );
		}

		m_outgoing_packets.push_back( response );
	}
Here you can see the bitfields in action. If all flags are set, which is mode 0x0E, you get the full packet. If only some of the flags are set, you get a packet that the client expects based on the logic. If no flags are set, all you get is the actual mode, which is obviously correct since no security is simply the mode byte!

[Edit] Removed 0x2002 remarks since the packets are worthless by design. All they do is tell the server the last time a packet was received on the connection, but they can't be used for much more than that.

I think that's about it for now. Nice work!
11/26/2010 21:55 Haxor#14
So for what this for,
I cant understand this thing :)
11/29/2010 01:09 Yo123#15
understanding packet structures.