This wiki is archived and useful information is being migrated to the main bzflag.org website

Difference between revisions of "Network Protocol"

From BZFlagWiki
Jump to: navigation, search
(Platform differences)
(Partial port from http://bzflag.svn.sourceforge.net/viewvccheckout: bzflag/trunk/bzflag/doc/guide/NetworkProtocol.xml)
Line 1: Line 1:
This page describes the used networking protocol of BZFlag.
+
{{Inaccurate}}
 +
 
 +
= Introduction =
 +
 
 +
BZFlag uses standard IP (Internet) networking protocols. The code is written to the BSD socket interface, with adjustments for winsock on win32 platforms. Future revisions may centralize the network code into one file behind a single class interface to simplify porting to platforms without the BSD socket API.
 +
Most communication is non-blocking. That is, reads and sends return immediately instead of waiting for data to become available or to be sent. That's important since BZFlag is a real time game. It can't afford to get stuck waiting for a packet to come in. (The one exception to this is when BZFlag connects to a server, and this should get fixed someday.)
 +
Communication is multiplexed using the select() call, which notifies the caller which sockets have data pending for read and/or are ready for sends. Instead of checking for incoming data by trying to read every socket and testing for success, we simply ask the system which sockets have data and read on those only. This also means that we use just a single thread for network communication.
 +
BZFlag uses two distinct transport protocols to communicate with the server. Server communication uses TCP/IP for reliability. Live game data communication uses UDP for speed and efficiency. See the other pages for more details.
 +
 
 +
 
 +
= Client/Server Communication =
 +
The BZFlag server manages games. It is the judge and arbitrar between clients. It manages game-global resources and information, such as flags and scores. It does not enforce game rules. Clients are trusted to follow the rules, saving the server the trouble of validating kills and client manouvering.
 +
For example, the server is not told of changes to a client's position on the game board. Therefore the server cannot enfore the rule that players can't drive through walls (without the OO or PH flags). This allows each client to run freely. If it had to wait for the server to okay each movement, it would be impossible to play BZFlag except on fast or dedicated networks.
 +
Furthermore, clients inform the server when they've killed another client player. The server doesn't verify the kill was legal beyond checking to see if someone has already claimed a kill on the same player. If more than one player claims a kill or tries to grab a particular flag, the server decides which player gets the kill or the flag.
 +
Client/server communication is mostly limited to those messages that must be successfully delivered. These include, among others, notifications of players coming alive or being killed, notifications of shots being fired, flags coming or going or being grabbed or dropped.
 +
Client/server communication in BZFlag is through TCP/IP. TCP/IP has the advantages of being bidirectional, reliable, and sequential. Bidirectional means each side of the connection can send to the other. Reliable means that each message will be delivered to the destination. Sequential means that messages (on a particular connection) will be received in the order they were sent.
 +
The main disadvantage of TCP/IP is that it's slow. Reliability may require a given message to be sent several times, until the receiver acknowledges its receipt. While delays can cause problems, there really isn't a way around it. Messages between the client and server are specifically those messages that must not be lost. If we didn't use TCP/IP we'd simply have to implement something that did the same thing, and which would necessarily suffer from the same drawbacks.
 +
There are some instances where client/server communication doesn't use TCP/IP. One example is client attempts to locate servers on the network. Clients send broadcast `pings' which the servers listen for and respond to in kind. These messages are not part of normal game communication.
 +
 
 +
= Client/Client Communication =
 +
BZFlag clients send certain information to other clients during a game. This information includes: status, position, orientation, and linear and angular velocity. This state can change quickly and getting it late is no better than not getting it at all. So client to client packets are sent using UDP, a datagram protocol.
 +
UDP is unreliable, meaning that packets are not guaranteed to be delivered. It's also connectionless, meaning we don't even know if anybody is listening for the message. However, it's also fast because it's so simple. UDP suits our needs because: we need fast delivery; we don't care if a message is lost because another will arrive shortly afterwards; and we don't care if the receiver isn't listening.
 +
BZFlag clients need to send their information to all the other clients. There are several ways to do this. First, each client can send each message to all the other clients. If there are N clients then each message is sent N-1 times. Traffic grows as the square of clients. This is slow and wasteful.
 +
Alternatively, each client can send all messages to one special computer (for example, the server) and that computer can forward the messages to all the other players. This makes life easier on the clients and much harder on the server. It also delays the deliverly of each message. And traffic from the server still grows as N squared (though traffic to the server grows linearly).
 +
Another possibility is to broadcast messages. A broadcast message is sent once and received by all computers on a subnet. This scales linearly and minimizes network traffic but broadcast traffic is never routed outside the subnet, so it means only clients on the same subnet of the same local area network could play together.
 +
BZFlag uses the second technique, using the server as a relay system. The server uses the TCP client/server connection to send client traffic that must be reliable and UDP for information that must be timely but does not need to be reliable.
 +
 
 +
= Protocol =
 +
  --> means from client to server
 +
  <-- means from server to client
 +
 
 +
All multi-byte data is in network byte order (aka big endian); that is, the most significant byte comes first followed by successively less significant bytes.
 +
All numbers are integers unless otherwise specified. Integers can be 8, 16, or 32 bit signed 2's compliment or unsigned (encoding is the same in regardless of signed status). Values in this document in byte boxes are given in hexadecimal. Values in the text are given in decimal unless otherwise noted.
 +
Bitfields are encoded as unsigned integers. All floating point numbers are in standard IEEE-754 single precision format. Multibyte values are *not* necessarily aligned on 2 or 4 byte boundaries.
 +
A client normally follows the following sequence during game play: connect to server get the world database join the game send/receive game messages leave game disconnect from server
 +
common message structures ------------------------- Most messages begin with the length of the message in bytes followed by a 16 bit code. The length is 16 bits and excludes itself and the code, so it's the actual length of the message minus 4.
 +
 
 +
 
 +
Player identifiers are 1 byte and are used in many messages.
 +
 
 +
          0 - 243 : Regular Players
 +
        244 - 250 : Special Team Ids
 +
        251 - 252 : Unused IDs
 +
              253 : ServerPlayer (World weapons, etc)
 +
              254 : All Players
 +
              255 : No Player (Invalid Player)
 +
 
 +
Flag status is common to a few message types:
 +
 
 +
u16 flag id
 +
u16 status
 +
u16 type
 +
u8 owner id
 +
float position (x)
 +
float position (y)
 +
float position (z)
 +
float launch (x)
 +
float launch (y)
 +
float launch (z)
 +
float landing (x)
 +
float landing (y)
 +
float landing (z)
 +
float flight time
 +
float flight end time
 +
float initial velocity
 +
 
 +
`Position,' `launch,' `landing,' `flight time,' `flight end,' and `initial velocity' are all floating point numbers. `Flag id' is the type of flag,enumerated in FlagId.
 +
 
 +
`Status' gives the current location of the flag:
 +
  FlagNoExist  -- the flag is not active (i.e. not in the game)
 +
  FlagOnGround -- the flag is sitting on the ground ready to get picked up
 +
  FlagOnTank  -- the flag is on a player's tank
 +
  FlagInAir    -- the flag is in the air and will fall back down
 +
  FlagComing  -- the flag just appeared and is falling to the ground
 +
  FlagGoing    -- the flag was thrown in the air and is disappearing
 +
 
 +
`Type' indicates the behavior of the flag: FlagNormal means the flag is permanent and can be dropped normally (e.g. a team flag); FlagUnstable means the flag may disappear after use (e.g. a good super flag); FlagSticky means the flag cannot be dropped normally (e.g. a bad super flag).
 +
`Player id' indicates which player has the flag when `status' is FlagOnTank. It isn't used for any other status.
 +
`Position' is the location of the flag on the ground. It only has meaning when `status' is FlagOnGround. The position of a flag when on a tank is the position of the tank (centered on and at the top of the tank)
 +
`Launch' is the location of the flag where it was thrown in the air. `Landing' is the location where the flag will/would touch ground. These are used when `status' is FlagInAir, FlagComing, and FlagGoing. The client should make the flag follow a reasonable flight path (e.g. a parabolic arc) from `launch' to `landing.'
 +
`Flight time' is the time elapsed since the flag was thrown into the air. `Flight end' the time when the flag will reach the ground. `Initial velocity' gives the vertical (z) velocity of the flag when lanuched. The vertical position of the flag at time t (ranging from 0 to `flight end') is: z = z0 + v * t + 0.5 * g * t * t. z0 = `launch z;' v = `initial velocity;' g = acceleration due to gravity.
  
  
== Platform differences ==
 
The network protocol is cross platform, however implementation of sockets is different on the platforms. *nix, Linux and Mac OS X use BSD sockets, Windows® uses WinSock. WinSock is not 100% compatible to the standard therefore if you use a low level language you need different code for Windows® to do the same like on other platforms.
 
  
 
== Connecting to a server ==
 
== Connecting to a server ==
 
The [http://bzflag.svn.sourceforge.net/viewvc/*checkout*/bzflag/trunk/bzflag/misc/bzfquery.php bzfquery.php script] is a nice example of how to connect to a server.
 
The [http://bzflag.svn.sourceforge.net/viewvc/*checkout*/bzflag/trunk/bzflag/misc/bzfquery.php bzfquery.php script] is a nice example of how to connect to a server.
  
At the beginning you need to open a socket using the TCP/IP protocol. Beginning with protocol 0048 you need to send "BZFLAG\r\n\r\n" in order to get any reply. At that time you unfortunately don't know the protocol, so send it by default or your client will probably freeze.
+
At the beginning you need to open a socket. Beginning with protocol 0048 you need to send "BZFLAG\r\n\r\n" in order to get any reply. At that time you unfortunately don't know the protocol, so send it by default or your client will probably freeze.
 +
 
 +
  -->  connect(server port)
 +
  -->    +----+----+----+----+----+----+----+----+----+----+
 +
| 42 | 5a | 46 | 4C | 41 | 47 | 0D | 0A | 0D | 0A |    BZFLAG\r\n\r\n
 +
+----+----+----+----+----+----+----+----+----+----+
 +
  <--    +----+----+----+----+----+----+----+----+----+
 +
  | 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |          BZFS1910        FF
 +
  +----+----+----+----+----+----+----+----+----+
 +
 
 +
 
 +
Client should verify the version. In old versions the first four bytes indicates a BZFlag server, the next byte indicates the major version number (as an ascii digit), the two bytes after that are the minor version number (as ascii digits), and the 7th byte is the revision. Major and minor version number changes indicate incompatible protocol changes. Different revisions of a given version are compatible and usually just indicate client user interface changes. A following FF ends the packet. In new versions the protocol is just a number increased by 1 when the protocol changes.
 +
 
 +
If the reply was a protocol older than 0048 then bzfs will kick the client connecting to it. In this case we recommend a fallback, not sending BZFLAG\r\n\r\n during connection try:
 +
 
 +
  -->  connect(server port)
 +
  <--    +----+----+----+----+----+----+----+----+----+
 +
  | 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |          BZFS1910        FF
 +
  +----+----+----+----+----+----+----+----+----+
  
Then you will get 9 bytes from the socket: First the string "BZFS" and then a 4 digit protocol number. If the protocol is newer or equal to 0048 your established connection is fine. If it is older than 0048 your client has been kicked, in this case you need to reconnect again without sending "BZFLAG\r\n\r\n".
 
  
 
Server owners will see something like the following in the logs if their server(s) use a protocol older than 0048:
 
Server owners will see something like the following in the logs if their server(s) use a protocol older than 0048:

Revision as of 11:58, 12 April 2007

MessedUp.png This page contains inaccurate information, blatant errors, wild claims, and/or simply unclear text. Please discuss these issues on the talk page or fix them yourself.

Look out for flying tanks.


Introduction

BZFlag uses standard IP (Internet) networking protocols. The code is written to the BSD socket interface, with adjustments for winsock on win32 platforms. Future revisions may centralize the network code into one file behind a single class interface to simplify porting to platforms without the BSD socket API. Most communication is non-blocking. That is, reads and sends return immediately instead of waiting for data to become available or to be sent. That's important since BZFlag is a real time game. It can't afford to get stuck waiting for a packet to come in. (The one exception to this is when BZFlag connects to a server, and this should get fixed someday.) Communication is multiplexed using the select() call, which notifies the caller which sockets have data pending for read and/or are ready for sends. Instead of checking for incoming data by trying to read every socket and testing for success, we simply ask the system which sockets have data and read on those only. This also means that we use just a single thread for network communication. BZFlag uses two distinct transport protocols to communicate with the server. Server communication uses TCP/IP for reliability. Live game data communication uses UDP for speed and efficiency. See the other pages for more details.


Client/Server Communication

The BZFlag server manages games. It is the judge and arbitrar between clients. It manages game-global resources and information, such as flags and scores. It does not enforce game rules. Clients are trusted to follow the rules, saving the server the trouble of validating kills and client manouvering. For example, the server is not told of changes to a client's position on the game board. Therefore the server cannot enfore the rule that players can't drive through walls (without the OO or PH flags). This allows each client to run freely. If it had to wait for the server to okay each movement, it would be impossible to play BZFlag except on fast or dedicated networks. Furthermore, clients inform the server when they've killed another client player. The server doesn't verify the kill was legal beyond checking to see if someone has already claimed a kill on the same player. If more than one player claims a kill or tries to grab a particular flag, the server decides which player gets the kill or the flag. Client/server communication is mostly limited to those messages that must be successfully delivered. These include, among others, notifications of players coming alive or being killed, notifications of shots being fired, flags coming or going or being grabbed or dropped. Client/server communication in BZFlag is through TCP/IP. TCP/IP has the advantages of being bidirectional, reliable, and sequential. Bidirectional means each side of the connection can send to the other. Reliable means that each message will be delivered to the destination. Sequential means that messages (on a particular connection) will be received in the order they were sent. The main disadvantage of TCP/IP is that it's slow. Reliability may require a given message to be sent several times, until the receiver acknowledges its receipt. While delays can cause problems, there really isn't a way around it. Messages between the client and server are specifically those messages that must not be lost. If we didn't use TCP/IP we'd simply have to implement something that did the same thing, and which would necessarily suffer from the same drawbacks. There are some instances where client/server communication doesn't use TCP/IP. One example is client attempts to locate servers on the network. Clients send broadcast `pings' which the servers listen for and respond to in kind. These messages are not part of normal game communication.

Client/Client Communication

BZFlag clients send certain information to other clients during a game. This information includes: status, position, orientation, and linear and angular velocity. This state can change quickly and getting it late is no better than not getting it at all. So client to client packets are sent using UDP, a datagram protocol. UDP is unreliable, meaning that packets are not guaranteed to be delivered. It's also connectionless, meaning we don't even know if anybody is listening for the message. However, it's also fast because it's so simple. UDP suits our needs because: we need fast delivery; we don't care if a message is lost because another will arrive shortly afterwards; and we don't care if the receiver isn't listening. BZFlag clients need to send their information to all the other clients. There are several ways to do this. First, each client can send each message to all the other clients. If there are N clients then each message is sent N-1 times. Traffic grows as the square of clients. This is slow and wasteful. Alternatively, each client can send all messages to one special computer (for example, the server) and that computer can forward the messages to all the other players. This makes life easier on the clients and much harder on the server. It also delays the deliverly of each message. And traffic from the server still grows as N squared (though traffic to the server grows linearly). Another possibility is to broadcast messages. A broadcast message is sent once and received by all computers on a subnet. This scales linearly and minimizes network traffic but broadcast traffic is never routed outside the subnet, so it means only clients on the same subnet of the same local area network could play together. BZFlag uses the second technique, using the server as a relay system. The server uses the TCP client/server connection to send client traffic that must be reliable and UDP for information that must be timely but does not need to be reliable.

Protocol

 --> means from client to server
 <-- means from server to client

All multi-byte data is in network byte order (aka big endian); that is, the most significant byte comes first followed by successively less significant bytes. All numbers are integers unless otherwise specified. Integers can be 8, 16, or 32 bit signed 2's compliment or unsigned (encoding is the same in regardless of signed status). Values in this document in byte boxes are given in hexadecimal. Values in the text are given in decimal unless otherwise noted. Bitfields are encoded as unsigned integers. All floating point numbers are in standard IEEE-754 single precision format. Multibyte values are *not* necessarily aligned on 2 or 4 byte boundaries. A client normally follows the following sequence during game play: connect to server get the world database join the game send/receive game messages leave game disconnect from server common message structures ------------------------- Most messages begin with the length of the message in bytes followed by a 16 bit code. The length is 16 bits and excludes itself and the code, so it's the actual length of the message minus 4.


Player identifiers are 1 byte and are used in many messages.

         0 - 243 : Regular Players
       244 - 250 : Special Team Ids
       251 - 252 : Unused IDs
             253 : ServerPlayer (World weapons, etc)
             254 : All Players
             255 : No Player (Invalid Player)

Flag status is common to a few message types:

u16 flag id u16 status u16 type u8 owner id float position (x) float position (y) float position (z) float launch (x) float launch (y) float launch (z) float landing (x) float landing (y) float landing (z) float flight time float flight end time float initial velocity

`Position,' `launch,' `landing,' `flight time,' `flight end,' and `initial velocity' are all floating point numbers. `Flag id' is the type of flag,enumerated in FlagId.

`Status' gives the current location of the flag:

 FlagNoExist  -- the flag is not active (i.e. not in the game)
 FlagOnGround -- the flag is sitting on the ground ready to get picked up
 FlagOnTank   -- the flag is on a player's tank
 FlagInAir    -- the flag is in the air and will fall back down
 FlagComing   -- the flag just appeared and is falling to the ground
 FlagGoing    -- the flag was thrown in the air and is disappearing

`Type' indicates the behavior of the flag: FlagNormal means the flag is permanent and can be dropped normally (e.g. a team flag); FlagUnstable means the flag may disappear after use (e.g. a good super flag); FlagSticky means the flag cannot be dropped normally (e.g. a bad super flag). `Player id' indicates which player has the flag when `status' is FlagOnTank. It isn't used for any other status. `Position' is the location of the flag on the ground. It only has meaning when `status' is FlagOnGround. The position of a flag when on a tank is the position of the tank (centered on and at the top of the tank) `Launch' is the location of the flag where it was thrown in the air. `Landing' is the location where the flag will/would touch ground. These are used when `status' is FlagInAir, FlagComing, and FlagGoing. The client should make the flag follow a reasonable flight path (e.g. a parabolic arc) from `launch' to `landing.' `Flight time' is the time elapsed since the flag was thrown into the air. `Flight end' the time when the flag will reach the ground. `Initial velocity' gives the vertical (z) velocity of the flag when lanuched. The vertical position of the flag at time t (ranging from 0 to `flight end') is: z = z0 + v * t + 0.5 * g * t * t. z0 = `launch z;' v = `initial velocity;' g = acceleration due to gravity.


Connecting to a server

The bzfquery.php script is a nice example of how to connect to a server.

At the beginning you need to open a socket. Beginning with protocol 0048 you need to send "BZFLAG\r\n\r\n" in order to get any reply. At that time you unfortunately don't know the protocol, so send it by default or your client will probably freeze.

 -->   connect(server port)
 -->    +----+----+----+----+----+----+----+----+----+----+
	| 42 | 5a | 46 | 4C | 41 | 47 | 0D | 0A | 0D | 0A |     BZFLAG\r\n\r\n
	+----+----+----+----+----+----+----+----+----+----+
 <--    +----+----+----+----+----+----+----+----+----+
 	| 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |           BZFS1910        FF
 	+----+----+----+----+----+----+----+----+----+


Client should verify the version. In old versions the first four bytes indicates a BZFlag server, the next byte indicates the major version number (as an ascii digit), the two bytes after that are the minor version number (as ascii digits), and the 7th byte is the revision. Major and minor version number changes indicate incompatible protocol changes. Different revisions of a given version are compatible and usually just indicate client user interface changes. A following FF ends the packet. In new versions the protocol is just a number increased by 1 when the protocol changes.

If the reply was a protocol older than 0048 then bzfs will kick the client connecting to it. In this case we recommend a fallback, not sending BZFLAG\r\n\r\n during connection try:

 -->   connect(server port)
 <--    +----+----+----+----+----+----+----+----+----+
 	| 42 | 5a | 46 | 53 | 31 | 39 | 31 | 30 | FF |           BZFS1910        FF
 	+----+----+----+----+----+----+----+----+----+


Server owners will see something like the following in the logs if their server(s) use a protocol older than 0048:

 Player [0] sent huge packet length (len=16986), possible attack
 Player  [0] removed at 2007-04-11 15:52:55: large packet recvd