├── .gitignore ├── Cargo.toml ├── examples ├── simple_client.rs └── simple_server.rs ├── license ├── readme.md ├── specification.md └── src ├── async.rs ├── constants.rs ├── frame.rs ├── lib.rs ├── packets ├── decoder.rs ├── decoder_tests.rs ├── encoder.rs ├── encoder_tests.rs └── mod.rs ├── server ├── ack_manager.rs ├── connection.rs ├── data_packet_handler.rs ├── mio_server.rs ├── mod.rs └── roundtrip_estimator.rs └── status_translator.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fastnet" 3 | version = "0.1.0" 4 | authors = ["Austin Hicks "] 5 | 6 | [dependencies] 7 | mio = "0.5.0" 8 | byteorder = "0.5.0" 9 | crc = "*" 10 | uuid = { version = "0.2", features = ["use_std", "v4"] } 11 | log = "0.3.6" 12 | time = "0.1" 13 | 14 | [dev-dependencies] 15 | env_logger = "*" 16 | 17 | -------------------------------------------------------------------------------- /examples/simple_client.rs: -------------------------------------------------------------------------------- 1 | extern crate fastnet; 2 | extern crate env_logger; 3 | use std::net::{ToSocketAddrs}; 4 | use std::env; 5 | 6 | fn main() { 7 | env_logger::init().unwrap(); 8 | let args = env::args().collect::>(); 9 | if args.len() != 2{ 10 | println!("Syntax: {}
", args[0]); 11 | return; 12 | } 13 | let mut i = args[1].to_socket_addrs().unwrap(); 14 | let server_addr = i.next().unwrap(); 15 | i = "0.0.0.0:11000".to_socket_addrs().unwrap(); 16 | let our_addr = i.next().unwrap(); 17 | let maybe_serv = fastnet::Server::new(our_addr, fastnet::PrintingHandler::new()); 18 | if let Err(ref what) = maybe_serv { 19 | format!("Error: {:?}", what); 20 | } 21 | let mut serv = maybe_serv.unwrap(); 22 | serv.connect(server_addr, 0); 23 | println!("Server is running."); 24 | loop {} 25 | } 26 | -------------------------------------------------------------------------------- /examples/simple_server.rs: -------------------------------------------------------------------------------- 1 | extern crate fastnet; 2 | extern crate env_logger; 3 | use std::net::{ToSocketAddrs}; 4 | use std::env; 5 | 6 | fn main() { 7 | env_logger::init().unwrap(); 8 | let args = env::args().collect::>(); 9 | if args.len() != 2{ 10 | println!("Syntax: {}
", args[0]); 11 | return; 12 | } 13 | let mut i = args[1].to_socket_addrs().unwrap(); 14 | let addr = i.next().unwrap(); 15 | let maybe_serv = fastnet::Server::new(addr, fastnet::PrintingHandler::new()); 16 | if let Err(ref what) = maybe_serv { 17 | format!("Error: {:?}", what); 18 | } 19 | let mut serv = maybe_serv.unwrap(); 20 | println!("Server is running."); 21 | loop {} 22 | } 23 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. “Contributor” 6 | means each individual or legal entity that creates, contributes to the 7 | creation of, or owns Covered Software. 8 | 9 | 1.2. “Contributor Version” 10 | means the combination of the Contributions of others (if any) used by a 11 | Contributor and that particular Contributor’s Contribution. 12 | 13 | 1.3. “Contribution” 14 | means Covered Software of a particular Contributor. 15 | 16 | 1.4. “Covered Software” 17 | means Source Code Form to which the initial Contributor has attached the 18 | notice in Exhibit A, the Executable Form of such Source Code Form, 19 | and Modifications of such Source Code Form, in each case 20 | including portions thereof. 21 | 22 | 1.5. “Incompatible With Secondary Licenses” 23 | means 24 | 25 | a. that the initial Contributor has attached the notice described 26 | in Exhibit B to the Covered Software; or 27 | 28 | b. that the Covered Software was made available under the terms of 29 | version 1.1 or earlier of the License, but not also under the terms 30 | of a Secondary License. 31 | 32 | 1.6. “Executable Form” 33 | means any form of the work other than Source Code Form. 34 | 35 | 1.7. “Larger Work” 36 | means a work that combines Covered Software with other material, 37 | in a separate file or files, that is not Covered Software. 38 | 39 | 1.8. “License” 40 | means this document. 41 | 42 | 1.9. “Licensable” 43 | means having the right to grant, to the maximum extent possible, 44 | whether at the time of the initial grant or subsequently, 45 | any and all of the rights conveyed by this License. 46 | 47 | 1.10. “Modifications” 48 | means any of the following: 49 | 50 | a. any file in Source Code Form that results from an addition to, 51 | deletion from, or modification of the contents of Covered Software; or 52 | 53 | b. any new file in Source Code Form that contains any Covered Software. 54 | 55 | 1.11. “Patent Claims” of a Contributor 56 | means any patent claim(s), including without limitation, method, process, 57 | and apparatus claims, in any patent Licensable by such Contributor that 58 | would be infringed, but for the grant of the License, by the making, 59 | using, selling, offering for sale, having made, import, or transfer of 60 | either its Contributions or its Contributor Version. 61 | 62 | 1.12. “Secondary License” 63 | means either the GNU General Public License, Version 2.0, the 64 | GNU Lesser General Public License, Version 2.1, the GNU Affero General 65 | Public License, Version 3.0, or any later versions of those licenses. 66 | 67 | 1.13. “Source Code Form” 68 | means the form of the work preferred for making modifications. 69 | 70 | 1.14. “You” (or “Your”) 71 | means an individual or a legal entity exercising rights under this License. 72 | For legal entities, “You” includes any entity that controls, 73 | is controlled by, or is under common control with You. For purposes of 74 | this definition, “control” means (a) the power, direct or indirect, 75 | to cause the direction or management of such entity, whether by contract 76 | or otherwise, or (b) ownership of more than fifty percent (50%) of the 77 | outstanding shares or beneficial ownership of such entity. 78 | 79 | 2. License Grants and Conditions 80 | 81 | 2.1. Grants 82 | Each Contributor hereby grants You a world-wide, royalty-free, 83 | non-exclusive license: 84 | 85 | a. under intellectual property rights (other than patent or trademark) 86 | Licensable by such Contributor to use, reproduce, make available, 87 | modify, display, perform, distribute, and otherwise exploit its 88 | Contributions, either on an unmodified basis, with Modifications, 89 | or as part of a Larger Work; and 90 | 91 | b. under Patent Claims of such Contributor to make, use, sell, 92 | offer for sale, have made, import, and otherwise transfer either 93 | its Contributions or its Contributor Version. 94 | 95 | 2.2. Effective Date 96 | The licenses granted in Section 2.1 with respect to any Contribution 97 | become effective for each Contribution on the date the Contributor 98 | first distributes such Contribution. 99 | 100 | 2.3. Limitations on Grant Scope 101 | The licenses granted in this Section 2 are the only rights granted 102 | under this License. No additional rights or licenses will be implied 103 | from the distribution or licensing of Covered Software under this License. 104 | Notwithstanding Section 2.1(b) above, no patent license is granted 105 | by a Contributor: 106 | 107 | a. for any code that a Contributor has removed from 108 | Covered Software; or 109 | 110 | b. for infringements caused by: (i) Your and any other third party’s 111 | modifications of Covered Software, or (ii) the combination of its 112 | Contributions with other software (except as part of its 113 | Contributor Version); or 114 | 115 | c. under Patent Claims infringed by Covered Software in the 116 | absence of its Contributions. 117 | 118 | This License does not grant any rights in the trademarks, service marks, 119 | or logos of any Contributor (except as may be necessary to comply with 120 | the notice requirements in Section 3.4). 121 | 122 | 2.4. Subsequent Licenses 123 | No Contributor makes additional grants as a result of Your choice to 124 | distribute the Covered Software under a subsequent version of this 125 | License (see Section 10.2) or under the terms of a Secondary License 126 | (if permitted under the terms of Section 3.3). 127 | 128 | 2.5. Representation 129 | Each Contributor represents that the Contributor believes its 130 | Contributions are its original creation(s) or it has sufficient rights 131 | to grant the rights to its Contributions conveyed by this License. 132 | 133 | 2.6. Fair Use 134 | This License is not intended to limit any rights You have under 135 | applicable copyright doctrines of fair use, fair dealing, 136 | or other equivalents. 137 | 138 | 2.7. Conditions 139 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the 140 | licenses granted in Section 2.1. 141 | 142 | 3. Responsibilities 143 | 144 | 3.1. Distribution of Source Form 145 | All distribution of Covered Software in Source Code Form, including 146 | any Modifications that You create or to which You contribute, must be 147 | under the terms of this License. You must inform recipients that the 148 | Source Code Form of the Covered Software is governed by the terms 149 | of this License, and how they can obtain a copy of this License. 150 | You may not attempt to alter or restrict the recipients’ rights 151 | in the Source Code Form. 152 | 153 | 3.2. Distribution of Executable Form 154 | If You distribute Covered Software in Executable Form then: 155 | 156 | a. such Covered Software must also be made available in Source Code 157 | Form, as described in Section 3.1, and You must inform recipients of 158 | the Executable Form how they can obtain a copy of such Source Code 159 | Form by reasonable means in a timely manner, at a charge no more than 160 | the cost of distribution to the recipient; and 161 | 162 | b. You may distribute such Executable Form under the terms of this 163 | License, or sublicense it under different terms, provided that the 164 | license for the Executable Form does not attempt to limit or alter 165 | the recipients’ rights in the Source Code Form under this License. 166 | 167 | 3.3. Distribution of a Larger Work 168 | You may create and distribute a Larger Work under terms of Your choice, 169 | provided that You also comply with the requirements of this License for 170 | the Covered Software. If the Larger Work is a combination of 171 | Covered Software with a work governed by one or more Secondary Licenses, 172 | and the Covered Software is not Incompatible With Secondary Licenses, 173 | this License permits You to additionally distribute such Covered Software 174 | under the terms of such Secondary License(s), so that the recipient of 175 | the Larger Work may, at their option, further distribute the 176 | Covered Software under the terms of either this License or such 177 | Secondary License(s). 178 | 179 | 3.4. Notices 180 | You may not remove or alter the substance of any license notices 181 | (including copyright notices, patent notices, disclaimers of warranty, 182 | or limitations of liability) contained within the Source Code Form of 183 | the Covered Software, except that You may alter any license notices to 184 | the extent required to remedy known factual inaccuracies. 185 | 186 | 3.5. Application of Additional Terms 187 | You may choose to offer, and to charge a fee for, warranty, support, 188 | indemnity or liability obligations to one or more recipients of 189 | Covered Software. However, You may do so only on Your own behalf, 190 | and not on behalf of any Contributor. You must make it absolutely clear 191 | that any such warranty, support, indemnity, or liability obligation is 192 | offered by You alone, and You hereby agree to indemnify every Contributor 193 | for any liability incurred by such Contributor as a result of warranty, 194 | support, indemnity or liability terms You offer. You may include 195 | additional disclaimers of warranty and limitations of liability 196 | specific to any jurisdiction. 197 | 198 | 4. Inability to Comply Due to Statute or Regulation 199 | 200 | If it is impossible for You to comply with any of the terms of this License 201 | with respect to some or all of the Covered Software due to statute, 202 | judicial order, or regulation then You must: (a) comply with the terms of 203 | this License to the maximum extent possible; and (b) describe the limitations 204 | and the code they affect. Such description must be placed in a text file 205 | included with all distributions of the Covered Software under this License. 206 | Except to the extent prohibited by statute or regulation, such description 207 | must be sufficiently detailed for a recipient of ordinary skill 208 | to be able to understand it. 209 | 210 | 5. Termination 211 | 212 | 5.1. The rights granted under this License will terminate automatically 213 | if You fail to comply with any of its terms. However, if You become 214 | compliant, then the rights granted under this License from a particular 215 | Contributor are reinstated (a) provisionally, unless and until such 216 | Contributor explicitly and finally terminates Your grants, and (b) on an 217 | ongoing basis, if such Contributor fails to notify You of the 218 | non-compliance by some reasonable means prior to 60 days after You have 219 | come back into compliance. Moreover, Your grants from a particular 220 | Contributor are reinstated on an ongoing basis if such Contributor 221 | notifies You of the non-compliance by some reasonable means, 222 | this is the first time You have received notice of non-compliance with 223 | this License from such Contributor, and You become compliant prior to 224 | 30 days after Your receipt of the notice. 225 | 226 | 5.2. If You initiate litigation against any entity by asserting a patent 227 | infringement claim (excluding declaratory judgment actions, 228 | counter-claims, and cross-claims) alleging that a Contributor Version 229 | directly or indirectly infringes any patent, then the rights granted 230 | to You by any and all Contributors for the Covered Software under 231 | Section 2.1 of this License shall terminate. 232 | 233 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 234 | end user license agreements (excluding distributors and resellers) which 235 | have been validly granted by You or Your distributors under this License 236 | prior to termination shall survive termination. 237 | 238 | 6. Disclaimer of Warranty 239 | 240 | Covered Software is provided under this License on an “as is” basis, without 241 | warranty of any kind, either expressed, implied, or statutory, including, 242 | without limitation, warranties that the Covered Software is free of defects, 243 | merchantable, fit for a particular purpose or non-infringing. The entire risk 244 | as to the quality and performance of the Covered Software is with You. 245 | Should any Covered Software prove defective in any respect, You 246 | (not any Contributor) assume the cost of any necessary servicing, repair, 247 | or correction. This disclaimer of warranty constitutes an essential part of 248 | this License. No use of any Covered Software is authorized under this 249 | License except under this disclaimer. 250 | 251 | 7. Limitation of Liability 252 | 253 | Under no circumstances and under no legal theory, whether tort 254 | (including negligence), contract, or otherwise, shall any Contributor, or 255 | anyone who distributes Covered Software as permitted above, be liable to 256 | You for any direct, indirect, special, incidental, or consequential damages 257 | of any character including, without limitation, damages for lost profits, 258 | loss of goodwill, work stoppage, computer failure or malfunction, or any and 259 | all other commercial damages or losses, even if such party shall have been 260 | informed of the possibility of such damages. This limitation of liability 261 | shall not apply to liability for death or personal injury resulting from 262 | such party’s negligence to the extent applicable law prohibits such 263 | limitation. Some jurisdictions do not allow the exclusion or limitation of 264 | incidental or consequential damages, so this exclusion and limitation may 265 | not apply to You. 266 | 267 | 8. Litigation 268 | 269 | Any litigation relating to this License may be brought only in the courts of 270 | a jurisdiction where the defendant maintains its principal place of business 271 | and such litigation shall be governed by laws of that jurisdiction, without 272 | reference to its conflict-of-law provisions. Nothing in this Section shall 273 | prevent a party’s ability to bring cross-claims or counter-claims. 274 | 275 | 9. Miscellaneous 276 | 277 | This License represents the complete agreement concerning the subject matter 278 | hereof. If any provision of this License is held to be unenforceable, 279 | such provision shall be reformed only to the extent necessary to make it 280 | enforceable. Any law or regulation which provides that the language of a 281 | contract shall be construed against the drafter shall not be used to construe 282 | this License against a Contributor. 283 | 284 | 10. Versions of the License 285 | 286 | 10.1. New Versions 287 | Mozilla Foundation is the license steward. Except as provided in 288 | Section 10.3, no one other than the license steward has the right to 289 | modify or publish new versions of this License. Each version will be 290 | given a distinguishing version number. 291 | 292 | 10.2. Effect of New Versions 293 | You may distribute the Covered Software under the terms of the version 294 | of the License under which You originally received the Covered Software, 295 | or under the terms of any subsequent version published 296 | by the license steward. 297 | 298 | 10.3. Modified Versions 299 | If you create software not governed by this License, and you want to 300 | create a new license for such software, you may create and use a modified 301 | version of this License if you rename the license and remove any 302 | references to the name of the license steward (except to note that such 303 | modified license differs from this License). 304 | 305 | 10.4. Distributing Source Code Form that is 306 | Incompatible With Secondary Licenses 307 | If You choose to distribute Source Code Form that is 308 | Incompatible With Secondary Licenses under the terms of this version of 309 | the License, the notice described in Exhibit B of this 310 | License must be attached. 311 | 312 | Exhibit A - Source Code Form License Notice 313 | 314 | This Source Code Form is subject to the terms of the 315 | Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed 316 | with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 317 | 318 | If it is not possible or desirable to put the notice in a particular file, 319 | then You may include the notice in a location (such as a LICENSE file in a 320 | relevant directory) where a recipient would be likely to 321 | look for such a notice. 322 | 323 | You may add additional accurate notices of copyright ownership. 324 | 325 | Exhibit B - “Incompatible With Secondary Licenses” Notice 326 | 327 | This Source Code Form is “Incompatible With Secondary Licenses”, 328 | as defined by the Mozilla Public License, v. 2.0. -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | #Fastnet# 2 | 3 | 4 | Fastnet aims to be a multiplexed, message-based protocol over UDP. 5 | It splits a physical connection into 32768 streams, each of which guarantees in-order delivery of messages. 6 | Every message may be sent either reliably or unreliably. 7 | In addition, Fastnet aims to support P2P connections via UDP hole punching, the ability to efficiently distribute large assets and other data to clients, and efficient TCP fallback. 8 | Finally, Fastnet will be fully specified. 9 | 10 | This repository includes the specificationn and a reference implementation in Rust. 11 | 12 | Unlike my other projects, Fastnet is primarily aimed at teaching me things (namely rust and the design of reliable protocols over unreliable transports). 13 | I anticipate that Fastnet will be useful, but other libraries already implement much of this functionality. 14 | That said and in so far as I know, you have to go to C++ or one of the big game engine/distribution platforms to find everything here with a convenient interface. 15 | 16 | The biggest advantage of this protocol, however, is that it is fully and formally specified. 17 | Consequently, others may learn from and maintain it without having to read the code from top to bottom. 18 | A not insignificant part of my motivation for this project is the documentation: finding good resources on the designs of such protocols as offered here is surprisingly difficult, and source code for libraries providing them is often large, cumbersome, and uncommented. 19 | Furthermore, having a specification makes it easier for third parties to identify possible security issues and evaluate Fastnet as compared to other alternatives. 20 | 21 | The license of this project is [MPL2](license). 22 | -------------------------------------------------------------------------------- /specification.md: -------------------------------------------------------------------------------- 1 | Fastnet 1.0 Protocol Specification 2 | 3 | ##Introduction and Goals 4 | 5 | Fastnet is a connection-based, channel-based protocol intended for games and realtime applications. 6 | It intensionally forgoes much of the automatic management of TCP and assumes that settings will be provided by the application developer. 7 | 8 | Unlike TCP, Fastnet works at the level of a message: a chunk of binary data of any size. 9 | Messages are either fully received or never received at all, and the application need not provide further separation logic. 10 | One Fastnet connection is logically 32768 smaller multiplexed connections called channels. 11 | 12 | Messages can be sent reliably or unreliably. 13 | Unreliable messages may or may not arrive at the other end, but are extremely fast and capable of representing frequently updated data such as position. 14 | Reliable messages are intended for chat messages, status updates, or other information that absolutely must arrive. 15 | A reliable message stalls all other messages in the queue behind it until such time as it arrives on the other end. 16 | 17 | When considering the advantages of Fastnet, it is helpful and mostly accurate to think of TCP as a train. 18 | If one train car derails, everything behind it stops. 19 | The primary advantage of Fastnet, then, is that you have the ability to use multiple train tracks at once. 20 | Furthermore, for applications which can tolerate data loss, it is possible to mark some of the metaphorical cars as unimportant; 21 | if these unimportant cars derail, the stream continues regardless. 22 | 23 | Other semireliable UDP-based protocols exist, but usually only for one language. 24 | Fastnet aims to be fully documented to the point where it can be recoded from scratch. 25 | The other two features that Fastnet aims to support are the ability to fall back to other transports (TCP, HTTP, WebRTC) and the ability to support UDP hole-punching. 26 | In my experience, it is difficult to find networking libraries that offer all three of these benefits. 27 | 28 | ##Definition of Terms## 29 | 30 | The key words "must", "must not", "required", "shall", "shall not", "should", "should not", "recommended", "may", and 31 | "optional" in this document are to be interpreted as described in 32 | [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt). 33 | 34 | A client refers to an entity who requests a connection from a server. 35 | A server refers to an entity capable of accepting multiple connections. 36 | 37 | A sender is an entity capable of sending messages. 38 | A receiver is an entity capable of receiving messages. 39 | Clients and servers are both senders and receivers. 40 | 41 | A packet refers to a chunk of data of any size. 42 | 43 | A message refers to a chunk of data specified by the application. This specification places no semantic meaning on the content of messages provided by applications. 44 | 45 | A transport means a method of moving packets from one destination to another. Transports usually involve the internet. 46 | 47 | A transport's implementation refers to the concrete implementation of a transport. 48 | 49 | UDP hole-punching refers to a technique for circumventing network Address Translation and connecting two computers directly without the use of an intermediate server. 50 | 51 | ##Specifying packet Format## 52 | 53 | This specification uses a mostly self-explanatory language to specify packet formats, and this section may likely be skipped. For clarity: 54 | 55 | - Nonterminals are written in the form ``. Terminals are written in the form | | ) 134 | response = -1:i16 1:u8 ( | | ) 135 | 136 | fastnet_quiery = 0: u8 137 | fastnet_response = 0: u8 response: b 138 | 139 | version_query = 1:u8 140 | version_response = 1: u8 version: a 141 | 142 | extension_query = 2: u8 name: a 143 | extension_response = 2: u8 name: a supported: b 144 | ``` 145 | 146 | Channel -1 is the status query and connection handshake channel. 147 | Queries are specifically designed such that they need not arrive in order. 148 | Queries must be responded to in both directions. 149 | All of the following query operations must be implemented. 150 | Unless otherwise noted, the result of a query should never change. 151 | 152 | - 0 is a query to determine if Fastnet is listening on a specified port. Return `false` for no, `true` for yes. An implementation shall assume that there is no server listening if this query is consistently not responded to. An implementation shall send this query no more than ten times. An implementation functioning only as a client should respond with `false` but is permitted not to respond at all. 153 | 154 | - 1 is the version query. The version response must contain a version string in the form `major.minor`. The current version is "1.0". Two implementations must be compatible if they have the same version number. It is anticipated that implementations will be considered compatible if they have the same major version number, but this specification avoids mandating it for now. 155 | 156 | - 2 is the extension supported query. Extension names should be of the form `vendorname_extensionname` and stored in lower case. This specification reserves the prefix `fastnet_` for use by this specification. 157 | 158 | An implementation shall not place limits on the number of times that a query may be sent and must always respond. 159 | An implementation must continue to respond to queries even after a connection is established. 160 | 161 | ##Connection Establishment## 162 | 163 | packets: 164 | 165 | ``` 166 | connect = -1:i16 2:u8 id: id 167 | connected = -1:i16 3:u8 id: id 168 | aborted = -1:i16 4:u8 error:s 169 | ``` 170 | 171 | With the exception of UDP hole-punching, connections are established using the following algorithm. UDP hole-punching is described elsewhere in this specification. 172 | 173 | A Fastnet server must allow only one connection from a specific IP and port. 174 | 175 | The following must always take place on channel -1 before a connection is considered established. 176 | 177 | To begin a connection, a client must: 178 | 179 | 1. Generate an id. This id will be used to identify the connection to the user. 180 | 181 | 2. Use the `fastnet_query` from the status query section to determine if a fastnet implementation is listening. An implementation must make no more than 10 attempts before aborting. 182 | 183 | 3. Use the `version_query` to determine that the implementations are compatible. Again, an implementation must make no more than 10 attempts before aborting. 184 | 185 | 4. Send the connect packet, containing the id. 186 | 187 | 5. Begin waiting for either the connected packet or the aborted packet with a timeout of 5000 MS. The client must resend the connect packet every 200 MS during this process. If the connected packet does not contain an ID matching the ID we sent, ignore it. 188 | 189 | If the client receives the connected packet, it must notify the application that the connection has been established and begin processing packets. 190 | The client must disregard all other packets including queries until it manages to receive the connected packet. 191 | 192 | If the client receives the aborted packet, it must report the error string to the user of the implementation in an implementation-defined manner. 193 | 194 | if the client times out before receiving either the connected or aborted packet, the implementation must report an implementation-defined error. 195 | 196 | When the server sees the connect packet and wishes to accept a connection, it must send the connected packet containing the id sent by the client. 197 | If the server continues to receive the connect packet, it must continue to respond with the connected packet but do nothing further; it is possible for the client to not yet know that it is connected due to packet loss. 198 | If there is a UUID collision, the server is free to simply ignore the incoming packet. 199 | Given the unlikelihood of having two connections from two different IP/port pairs generating the same UUID, such behavior merely causes an astronomically small percent of connection attempts to time out. 200 | 201 | To refuse a connection, a server must send the aborted packet with an implementation-defined string as to the reason. 202 | This string must not be empty. 203 | This specification suggests "unspecified error" as a reasonable default for situations in which a string is not available, i.e. because a game does not wish to advertise that a player has been banned. 204 | 205 | Servers must ignore any packets not involved in an active connection. 206 | 207 | ##Connection Closing and Breaking## 208 | 209 | TODO: define packets and intentional closing logic (this is awaiting a coming refactor involving identification of connections by UUID). 210 | 211 | If either end of a fastnet connection does not receive any packets from the other end of the connection for a timeout period then it must consider the connection broken. This period must be configurable by the user on either an implementation-wide or connection-specific basis and should default to 10 seconds. 212 | 213 | ##The Heartbeat Channel## 214 | 215 | Packet format: 216 | 217 | ``` 218 | heartbeat = -2:i16 counter: u64 sent_packets: u64 received_packets: u64 219 | ``` 220 | 221 | Channel -2 must be the heartbeat channel. 222 | 223 | A heartbeat is composed of three pieces of information: 224 | 225 | - A 64-bit counter, interpreted as a sequence number. 226 | 227 | - A 64-bit integer specifying how many packets this end of the connection has sent. 228 | 229 | - A 64-bit integer specifying how many packets this end of the connection has received from the other end of the connection. 230 | 231 | Both parties involved in a fastnet connection must send a heartbeat to each other once a second. 232 | 233 | Heartbeat packet counts do not include any packets exchanged before the establishment of a connection. 234 | 235 | An implementation must not place any semantic meaning on anything in the heartbeat beyond using it for rough packet loss estimation. 236 | 237 | ##The Echo Channel## 238 | 239 | Packet format: 240 | 241 | ``` 242 | echo = -3: i16 endpoint: u128 uuid: u128 243 | ``` 244 | 245 | When an implementation receives a packet on the echo channel for a connected Fastnet peer, it must immediately resend (echo) the packet back to the sender without modification. 246 | 247 | This channnel exists for implementations wishing to attempt provision of round-trip estimation. A conforming implementation must implement the echo channel but is not required to provide a round-trip estimation algorithm. 248 | 249 | Endpoint is a value which must be generated from a UUID at connection startup and not changed thereafter. uuid is a value which must be generated per-echo. An implementation must not respond to echoes whose endpoint value matches their own, as this means that the other side of the connection sent it in response to a previous echo. 250 | 251 | ##Frame Channels 252 | 253 | A frame is a container whose maximum size is 4GB. 254 | These frames are then sent across the network using the algorithms described below. 255 | Channels which have frames sent on them are known as frame channels. 256 | 257 | As will be seen later in this specification, Fastnet needs the ability to send large chunks of information to clients. 258 | this section lays out how to send or receive a frame on a channel, either reliably or unreliably. 259 | 260 | ###Frame Packets 261 | 262 | grammar: 263 | 264 | ``` 265 | data = 0: u8 sn: u64 flags: u8 payload: p 266 | ack = 1: u8 (sn: u64)+ 267 | ``` 268 | 269 | Data packets represent chunks of data of arbetrary length. 270 | The flags byte has the following flags: 271 | 272 | - 0 is the start of frame flag. 273 | 274 | - 1is the end of frame flag. 275 | 276 | - 2 is the reliability flag. 277 | 278 | All other bits of the flags byte must be 0. 279 | 280 | The sequence number must be set to 0 for the first packet sent on some channel, 1 for the next, etc. 281 | Sending enough data to exhaust the available sequence numbers is nearly impossible. 282 | A 64-bit sequence number is capable of handling at least 18 million terabytes of data, well beyond what can be handled by any consumer and most professional-grade internet. 283 | In practice, few data packets will carry only one byte of data, so this limit is all but meaningless. 284 | To that end, an implementation must drop the connection if the sequence number for any channel is exhausted. 285 | 286 | Borrowing from TCP terminology, ack is short for acknowledge. 287 | The ack packet is used to indicate reception of a reliable packet. 288 | It must only be sent for reliable packets in the manner described below. 289 | 290 | ###Encoding Frames 291 | 292 | A frame is an array of bytes of any length, with a header of the following form: 293 | 294 | ``` 295 | last_reliable: u64 length: u32 296 | ``` 297 | 298 | Any limits on the size of outgoing frames are implementation-defined, but are limited to 4GB because of the length field. 299 | Limits on incoming frames are implicitly defined by the packet reception algorithm, defined later in this document. 300 | 301 | To send a frame, an implementation must implement the following algorithm or something functionally equivalent: 302 | 303 | - Get data from the user and add the header. 304 | 305 | - Split the frame into some number of chunks, putting each into a data packet with all fields set to 0. The entire header must be in the first chunk. 306 | 307 | - Allocate sequence numbers to all packets in the obvious manner. 308 | 309 | - If the frame is being sent reliably (hereafter a reliable frame), set the reliability flag on all packets. 310 | 311 | - Set the start of frame flag on the first packet; set the end of frame flag on the last packet. If these are the same packet, both flags should be set. 312 | 313 | - Send all packets using the algorithms described below. 314 | 315 | - If this is a reliable frame, update the stored sequence number used to set `last_reliable` by setting it to the first sequence number assigned to this frame. `last_reliable` is described below. 316 | 317 | Frames must be split into chunks of data which can be encapsulated in a data packet of no more than 1000 bytes in total length. 318 | 4 bytes are taken by the checksum, 2 by the channel identifier, 1 by the specifier for data packet, 8 by the sequence number, and 1 by the flags byte. 319 | This leaves a total of 984 bytes of payload for each data packet. 320 | 321 | In order to encode a frame, an implementation must split the frame into some number of chunks. 322 | the algorithm for doing this is implementation-defined. 323 | For the earliest stages of implementing Fastnet, using a simple fixed size is the easiest option, though this specification suggests that implementations taking this path allow the user to configure it. 324 | There are more detailed and involved approaches that work better, however, such as MTU estimation. 325 | 326 | Frame headers currently have 2 fields: 327 | 328 | - `last_reliable` must be set to the sequence number of the packet which started the previous reliable frame. 329 | If no reliable frame has been sent yet, `last_reliable` must be set to 0. 330 | 331 | - `length` must be set to the length of the frame including the header. 332 | 333 | ###Sending Unreliable Data Packets 334 | 335 | To send an unreliable data packet, an implementation shall encode and broadcast it, as with all other unreliable packets. 336 | 337 | ###Sending Reliable Data packets 338 | 339 | An implementation must send reliable packets as if sending unreliable packets. 340 | The difference is that an implementation must remember and periodically resend unacked reliable packets. 341 | The resending algorithm is implementation-defined but should use exponential backoff if possible. 342 | This section will be updated once experience shows which method is the best. 343 | 344 | It is possible to attack a fastnet implementation by never acking a packet. 345 | A fastnet implementation must provide facilities to detect this case and deal with it; at a minimum, it must be possible for the application developer to forceably drop such bad-behaved connections if they begin using too many resources. 346 | 347 | ###Receiving Frames and Acking 348 | 349 | Though it can be used for other purposes, Fastnet is designed primarily for the use case of games. 350 | When given a choice between two alternatives, Fastnet chooses the one which is most likely to be friendly to a client-server architecture where the server sends much more data than the client. 351 | To that end, most of the complexity of sending and receiving frames is placed in the receiver. 352 | 353 | This subsection is long and involved, and by far the most complicated part of this specification. 354 | If your goal is to implement the Fastnet specification, read carefully. 355 | To aid in comprehension, a number of subsections follow. 356 | 357 | Most of this section is per-channel. 358 | When it is not, the specification will be sure to inform you. 359 | 360 | ####The Packet Storage Area 361 | 362 | For the purposes of public APIs, there must be a per-connection and per-channel packet storage area allocated to each frame channel. 363 | It is used to store data packets which have not yet been assembled into frames. 364 | 365 | At a minimum, the packet storage area must be able to store whether or not a packet has been acked. 366 | One good way of doing this is to use separate containers for acked and unacked packets. 367 | As will be seen shortly, acking packets immediately is not always possible. 368 | 369 | To protect against a variety of attacks that involve sending incomplete frames on all channels, There must be a connection-specific memory limit on the size of the packet storage areas for all channels. 370 | if this limit is exceeded, the application must be informed in a manner that allows it to drop the connection or raise the limit. 371 | This limit must default to 2 MB and be configurable by the application. 372 | This limit must not be allowed to go below 100KB and must count private channels. 373 | Without this limit, it is possible for an attacker to send multible gigabytes of reliable data packets on each channel, eventually exhausting ram. 374 | the rest of this specification refers to this limit as the per-connection memory limit. 375 | 376 | 377 | There must be a per-channel limit on the size of the packet storage area, hereafter the per-channel memory limit. 378 | The per-channel memory limit must default to 100KB for all message channels and be configurable by the application developer. 379 | Whether it can be configured on a per-channel basis is implementation-defined behavior. 380 | The channel-specific memory limit will be stated for private channels when it deviates from this default. 381 | how it is used it described below. 382 | 383 | 384 | Both of the above described limits must be specified in bytes of data payload. 385 | 386 | the maximum frame size which can be used is the minimum of the two above limits. 387 | It is recommended that implementations provide helper functions which can be used to determine and configure appropriate settings for these values given a specification of whichb message channels the application will use and the maximum message size on each. 388 | 389 | ####Ignoring and Dropping Data Packets 390 | 391 | Let there be a channel-specific unsigned 64-bit integer called the ignore number. 392 | The initial value of the ignore number is 0. 393 | How the ignore number is updated will be described below when assembling and delivering frames is discussed. 394 | If an incoming and unreliable packet has a sequence number less than the ignore number, it is immediately dropped. 395 | If an incoming and reliable packet has a sequence number less than the ignore nyumber, it is immediately acked and then dropped. 396 | 397 | When a receiver receives an unreliable packet that would take a channel over the per-channel memory limit, it must ignore it as though it was never received. 398 | 399 | When a receiver receives a reliable packet that would take it over the per-channel memory limit, it must perform the following, stopping at the first which succeeds: 400 | 401 | - First, if there are one or more unreliable packets which have not yet been processed and whose removal would make enough room for the packet, they must be dropped and the new packet accepted. Implementations should first prefer packets whose sequence number is less than the packet: if the packet storage area is a sorted array, the implementation should iterate from lowest to highest index. 402 | 403 | - Next, if there are one or more reliable packets with higher sequence numbers whose absence would make enough room for the reliable packet, they must be dropped in favor of the packet. Implementations should prefer reliable packets with the highest sequence number first: if the packet storage area is a sorted array, implementations should iterate from highest to lowest index. 404 | 405 | - Next, if performing both of the above cases would result in enough room, perform both. 406 | 407 | - Finally, the packet should be dropped. 408 | 409 | If performing the first two above cases cannot make room for the packet, the packet should be dropped without modifying the contents of the packet storage area. 410 | 411 | ####verifying Frame Headers 412 | 413 | When an implementation receives a data packet which has the start of frame flag set, it must check the length against the per-connection memory limit and the per-channel memory limit. 414 | If the length of the incoming frame is larger than the smaller of these limits, the connection must be closed. 415 | Applications should be given an opportunity to intercept and prevent this closure. 416 | This procedure must be performed before acking occurs. 417 | 418 | Note that raising the limit without taking care is a possible vector of attack. 419 | Suppose the application always increases both limits by 5%. 420 | In this case, an attacker can start by sending a frame of only a few bytes. 421 | To continue the attack, the attacker simply increases the size by 4.5% every time, resending the frame. 422 | Eventually, the application has increased the limit to at least the size of the largest packet the attacker has sent. 423 | In the best case, this was done per-channel and the attacker has to keep sending for a while to exhaust memory. 424 | In the worst case, the application raised the limit for all channels and the attacker need only get to 1 MB or so before sending a 1MB frame to all channels, taking all available memory. 425 | To prevent this, implementations are strongly encouraged to inform users that changing these settings and preventing connection closing should only be used for debugging purposes or in very special cases by expert users. 426 | 427 | ####Acking Packets 428 | 429 | Immediately after an ack is sent, the ignore number must be updated to one more than the sequence number sent in the ack packet. 430 | An ack must be sent if and only if one of the following two cases is met: 431 | 432 | - First, there is an unacked reliable packet in the packet storage area whose sequence number equals the ignore number. 433 | 434 | - Second, there is an unacked reliable packet in the packet storage area which begins a frame and has a header with `last_reliable` set to the first packet of the most recent delivered reliable frame sent on the channel in question. 435 | 436 | It is anticipated that implementations will periodically iterate over the packet storage area, performing the above acking algorithm. 437 | Implementations should attempt to keep the delay between receiving an ackable reliable packet and sending the ack for that packet to under 200 MS. 438 | 439 | Implementations must be prepared to receive duplicate reliable packets. 440 | 441 | Preemptively sending the first packet of large reliable frames multiple times is a possible performance-improving measure. 442 | 443 | ####Assembling frames 444 | 445 | An unassembled frame is a group of data packets meeting the following conditions: 446 | 447 | - Has consecutive sequence numbers. 448 | 449 | - Has the same value for the reliability flag in all packets. 450 | 451 | - If the packets are reliable, all have been acked. 452 | 453 | 454 | - The first packet has the start of frame flag set. 455 | 456 | - The last packet has the end of frame flag set. 457 | 458 | - No other packet has the start of frame or end of frame flags set. 459 | 460 | - The total lengths of the payloads of all the packets in the group sum to match the length as specified in the header contained in the first packet in the group. 461 | 462 | An unassembled frame may be assembled by concatenating all of the payloads of the unassembled frame into a buffer. 463 | A deliverable frame is an unassembled frame whose `last_reliable` is set to the sequence number of the first packet of the last reliable frame delivered on this channel. 464 | Delivering a frame refers to assembling a frame, stripping the header, and notifying other parts of Fastnet of the frame's existance as needed. 465 | 466 | An implementation must periodically scan the packet storage area to identify possible deliverable frames. 467 | When it finds one, it must immediately deliver it. 468 | How this is done is implementation-defined. 469 | 470 | After delivering a frame, the ignore number must be updated to the sequence number of the last packet in the frame; additionally, all packets in the packet storage areaa whose sequence number is now less than the ignore number must be dropped. 471 | 472 | ##Messages and Message Channels 473 | 474 | A message channel is a frame channel with no particular limits. 475 | A message is a frame sent on a message channel. 476 | To receive a message meanns to have a frame be delivered on a message channel. 477 | 478 | When an implementation receives a message, it must immediately notify the application of the message in an implementation-defined manner. 479 | 480 | An implementation must support sending messages in an implementation-defined manner. 481 | 482 | Messages will eventually have headers and additional features. This section is incomplete, but is enough to code. -------------------------------------------------------------------------------- /src/async.rs: -------------------------------------------------------------------------------- 1 | use std::{result, io, net}; 2 | use server; 3 | use uuid; 4 | 5 | ///Represents a Fastnet error. 6 | #[derive(Debug)] 7 | pub enum Error { 8 | TimedOut, 9 | HostNotFound, 10 | PeerNotFound, 11 | NotListening, 12 | IncompatibleVersions, 13 | ConnectionAborted, 14 | MessageTooLarge, 15 | IoError(io::Error), 16 | } 17 | 18 | pub type Result = result::Result; 19 | 20 | /**A Fastnet server. 21 | 22 | Fastnet does not distinguish between clients and servers. This is used both for connecting to other peers and listening for incoming connections.*/ 23 | pub struct Server { 24 | server: server::MioServer, 25 | } 26 | 27 | impl Server { 28 | pub fn new(addr: net::SocketAddr, handler: H)->Result> { 29 | let s = try!(server::MioServer::new(addr, handler).map_err(Error::IoError)); 30 | Ok(Server{server: s}) 31 | } 32 | 33 | /**Schedule a connection request. 34 | 35 | This will cause the associated handler to be passed the result with the specified request ID.*/ 36 | pub fn connect(&mut self, addr: net::SocketAddr, request_id: u64) { 37 | self.server.with(move |s| s.connect(addr, request_id)); 38 | } 39 | 40 | /**Disconnect from a peer with the specified ID.*/ 41 | pub fn disconnect(&mut self, id: uuid::Uuid, request_id: u64) { 42 | self.server.with(move |s| s.disconnect(id, request_id)); 43 | } 44 | 45 | /**Configure the timeout. 46 | The value to this function is in MS. Most applications should leave this alone. The default of 10 seconds is sufficient.*/ 47 | pub fn configure_timeout(&mut self, timeout_ms: u64) { 48 | self.server.with(move |s| s.configure_timeout(timeout_ms)); 49 | } 50 | } 51 | 52 | /**An event handler. 53 | 54 | The methods in this trait are called in a thread which is running in the background, not on the main thread. None of them should ever block.*/ 55 | pub trait Handler { 56 | fn connected(&mut self, id: uuid::Uuid, request_id: Option) { 57 | } 58 | 59 | fn disconnected(&mut self, id: uuid::Uuid, request_id: Option) { 60 | } 61 | 62 | fn incoming_message(&mut self, id: uuid::Uuid, channel: u16, payload: &[u8]) { 63 | } 64 | 65 | fn request_failed(&mut self, request_id: u64, error: Error) { 66 | } 67 | 68 | /**Fastnet has completed a roundtrip estimate for a peer. 69 | 70 | The time provided to this function is in milliseconds.*/ 71 | fn roundtrip_estimate(&mut self, id: uuid::Uuid, estimate: u32) { 72 | } 73 | } 74 | 75 | ///This will go away. 76 | #[derive(Default, Debug)] 77 | pub struct PrintingHandler; 78 | 79 | impl PrintingHandler { 80 | pub fn new()->PrintingHandler { 81 | PrintingHandler::default() 82 | } 83 | } 84 | 85 | impl Handler for PrintingHandler { 86 | fn connected(&mut self, id: uuid::Uuid, request_id: Option) { 87 | println!("Connected: {:?} {:?}", id, request_id); 88 | } 89 | 90 | fn disconnected(&mut self, id: uuid::Uuid, request_id: Option) { 91 | println!("Disconnected: {:?} {:?}", id, request_id); 92 | } 93 | 94 | fn incoming_message(&mut self, id: uuid::Uuid, channel: u16, payload: &[u8]) { 95 | println!("Incoming message: {:?} {:?} {:?}", id, channel, payload); 96 | } 97 | 98 | fn request_failed(&mut self, request_id: u64, error: Error) { 99 | println!("Request failure: {:?} {:?}", request_id, error); 100 | } 101 | 102 | fn roundtrip_estimate(&mut self, id: uuid::Uuid, estimate: u32) { 103 | println!("Roundtrip estimate: {:?} {:?}", id, estimate); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | 2 | pub const PER_CHANNEL_MEMORY_LIMIT_DEFAULT: usize = 100*1024; 3 | pub const PER_CONNECTION_MEMORY_LIMIT_DEFAULT: usize = 2*1024*1024; -------------------------------------------------------------------------------- /src/frame.rs: -------------------------------------------------------------------------------- 1 | use packets; 2 | use std::iter; 3 | use std::cmp; 4 | use std::convert::From; 5 | use std::borrow; 6 | 7 | //This has to be small enough to leave room for the header. 8 | const CHUNK_SIZE: usize = 500; 9 | 10 | #[derive(Debug)] 11 | pub struct FrameEncoder<'A, T: 'A> { 12 | channel: i16, 13 | sn: u64, 14 | last_reliable_frame: u64, 15 | reliable: bool, 16 | first: bool, 17 | iter: &'A mut T, 18 | workspace: Vec, 19 | } 20 | 21 | impl<'A, T, Q> FrameEncoder<'A, T> 22 | where T: iter::ExactSizeIterator+iter::Iterator, 23 | Q: borrow::Borrow, 24 | Vec: iter::Extend { 25 | pub fn new(iter: &'A mut T, channel: i16, starting_sequence_number: u64, last_reliable_frame: u64, reliable: bool)->FrameEncoder<'A, T> { 26 | FrameEncoder { 27 | channel: channel, 28 | sn: starting_sequence_number, 29 | last_reliable_frame: last_reliable_frame, 30 | reliable: reliable, 31 | first: true, 32 | iter: iter, 33 | workspace: Vec::with_capacity(CHUNK_SIZE), 34 | } 35 | } 36 | } 37 | 38 | impl<'A, T, Q> iter::Iterator for FrameEncoder<'A, T> 39 | where T: iter::ExactSizeIterator+iter::Iterator, 40 | Q: borrow::Borrow, 41 | Vec: iter::Extend { 42 | type Item = packets::Packet; 43 | 44 | fn next(&mut self)->Option { 45 | let mut header = None; 46 | if self.first { 47 | let length = packets::FRAME_HEADER_SIZE+self.iter.len(); 48 | header = Some(packets::FrameHeader{last_reliable_frame: self.last_reliable_frame, length: length as u32}); 49 | } 50 | //Get some bytes. 51 | self.workspace.clear(); 52 | self.workspace.extend(self.iter.take(CHUNK_SIZE)); 53 | if self.first == false && self.workspace.len() == 0 {return None;} 54 | let dp = packets::DataPacketBuilder::with_payload_and_header(self.sn, self.workspace.clone(), header) 55 | .set_reliable(self.reliable) 56 | .set_frame_start(self.first) 57 | .set_frame_end(self.iter.len() == 0) 58 | .build(); 59 | self.first = false; 60 | self.sn += 1; 61 | return Some(packets::Packet::Data{chan: self.channel, packet: dp}); 62 | } 63 | } 64 | 65 | impl<'A, T, Q> iter::ExactSizeIterator for FrameEncoder<'A, T> 66 | where T: iter::ExactSizeIterator+iter::Iterator, 67 | Q: borrow::Borrow, 68 | Vec: iter::Extend { 69 | fn len(&self)->usize { 70 | let mut res = self.iter.len()/CHUNK_SIZE; 71 | if res*CHUNK_SIZE < self.iter.len() {res += 1} 72 | if res ==0 && self.first == true {res = 1} 73 | return res; 74 | } 75 | } 76 | 77 | 78 | #[test] 79 | fn test_frame_encoding() { 80 | let test_data: Vec = vec![1u8; 1000]; 81 | //channel 100, start at sn 3, last reliable is 1. 82 | let mut got_packets = FrameEncoder::new(&mut test_data.iter(), 100, 3, 1, false).collect::>(); 83 | let mut expected_packets = vec![ 84 | packets::Packet::Data{chan: 100, 85 | packet: packets::DataPacketBuilder::with_payload_and_header(3, vec![1u8; 500], Some(packets::FrameHeader{length: 1012, last_reliable_frame: 1})).build() 86 | }, 87 | packets::Packet::Data{chan: 100, 88 | packet: packets::DataPacketBuilder::with_payload(4, vec![1u8; 500]).set_frame_end(true).build() 89 | } 90 | ]; 91 | assert_eq!(got_packets, expected_packets); 92 | got_packets = FrameEncoder::new(&mut test_data.iter(), 100, 3, 1, true).collect(); 93 | expected_packets = vec![ 94 | packets::Packet::Data{chan: 100, 95 | packet: packets::DataPacketBuilder::with_payload_and_header(3, vec![1u8; 500], Some(packets::FrameHeader{length: 1012, last_reliable_frame: 1})).set_reliable(true).build() 96 | }, 97 | packets::Packet::Data{chan: 100, 98 | packet: packets::DataPacketBuilder::with_payload(4, vec![1u8; 500]).set_reliable(true).set_frame_end(true).build(), 99 | } 100 | ]; 101 | assert_eq!(got_packets, expected_packets); 102 | } 103 | 104 | macro_rules! lentest { 105 | ($a: expr, $b: expr) => { 106 | assert_eq!(FrameEncoder::new(&mut [0u8; $a].iter(), 0, 0, 0, false).len(), $b); 107 | } 108 | } 109 | 110 | #[test] 111 | fn test_frame_exact_size_iterator() { 112 | lentest!(0, 1); 113 | lentest!(499, 1); 114 | lentest!(501, 2); 115 | lentest!(1000, 2); 116 | lentest!(2001, 5); 117 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! The main Fastnet module. 2 | 3 | This is the low-level API. If your goal is extremely high-performance usage, this is the API you want. See the blocking module for a simpler API which is less annoying for common use cases.*/ 4 | #![allow(warnings)] 5 | 6 | extern crate byteorder; 7 | extern crate mio; 8 | extern crate crc; 9 | extern crate uuid; 10 | #[macro_use] 11 | extern crate log; 12 | extern crate time; 13 | 14 | mod constants; 15 | mod packets; 16 | mod server; 17 | mod status_translator; 18 | mod async; 19 | mod frame; 20 | 21 | pub use async::*; 22 | -------------------------------------------------------------------------------- /src/packets/decoder.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use std::io::{self, Read}; 3 | use std::cmp; 4 | use byteorder::{BigEndian, ReadBytesExt}; 5 | use uuid; 6 | 7 | #[derive(Debug)] 8 | pub enum PacketDecodingError { 9 | //We need more bytes than what we got. 10 | TooSmall, 11 | Invalid, 12 | } 13 | 14 | pub struct PacketReader<'a> { 15 | slice: &'a [u8], 16 | index: usize, 17 | } 18 | 19 | impl<'a> PacketReader<'a> { 20 | pub fn new(destination: &[u8])->PacketReader { 21 | PacketReader{slice: destination, index: 0} 22 | } 23 | 24 | pub fn available(&self)->usize { 25 | self.slice.len()-self.index 26 | } 27 | 28 | pub fn read_count(&self)->usize { 29 | self.index 30 | } 31 | } 32 | 33 | impl<'a> Read for PacketReader<'a> { 34 | fn read(&mut self, buf: &mut[u8])->io::Result { 35 | let will_read = cmp::min(buf.len(), self.available()); 36 | for i in 0..will_read { 37 | buf[i] = self.slice[self.index+i]; 38 | } 39 | self.index += will_read; 40 | Ok(will_read) 41 | } 42 | } 43 | 44 | pub trait Decodable { 45 | type Output; 46 | fn decode(source: &mut PacketReader)->Result; 47 | } 48 | 49 | impl Decodable for Packet { 50 | type Output = Packet; 51 | fn decode(source: &mut PacketReader)->Result { 52 | use super::Packet::*; 53 | use self::PacketDecodingError::*; 54 | let channel = try!(i16::decode(source)); 55 | match channel { 56 | CONNECTION_CHANNEL => { 57 | let code = try!(u8::decode(source)); 58 | match code { 59 | STATUS_REQUEST_SPECIFIER => {return Ok(StatusRequest(try!(super::StatusRequest::decode(source))));}, 60 | STATUS_RESPONSE_SPECIFIER => {return Ok(StatusResponse(try!(super::StatusResponse::decode(source))));}, 61 | CONNECT_SPECIFIER => {return Ok(Connect(try!(uuid::Uuid::decode(source))));}, 62 | CONNECTED_SPECIFIER => {return Ok(Connected(try!(uuid::Uuid::decode(source))));}, 63 | ABORTED_SPECIFIER => {return Ok(Aborted(try!(String::decode(source))));}, 64 | _ => {return Err(Invalid);}, 65 | } 66 | }, 67 | HEARTBEAT_CHANNEL => { 68 | let count = try!(u64::decode(source)); 69 | let sent_packets = try!(u64::decode(source)); 70 | let received_packets = try!(u64::decode(source)); 71 | return Ok(Heartbeat{counter: count, sent: sent_packets, received: received_packets}); 72 | }, 73 | ECHO_CHANNEL => { 74 | let endpoint = try!(uuid::Uuid::decode(source)); 75 | let uuid = try!(uuid::Uuid::decode(source)); 76 | return Ok(Echo{endpoint: endpoint, uuid: uuid}); 77 | }, 78 | //All other channels are frame channels. 79 | chan@_ => { 80 | let specifier = try!(source.read_u8().or(Err(TooSmall))); 81 | match specifier { 82 | DATA_PACKET_SPECIFIER => { 83 | let dp = try!(DataPacket::decode(source)); 84 | return Ok(Packet::Data{chan: chan, packet: dp}); 85 | }, 86 | ACK_PACKET_SPECIFIER => { 87 | let sn = try!(source.read_u64::().or(Err(TooSmall))); 88 | return Ok(Packet::Ack{chan: chan, sequence_number: sn}); 89 | }, 90 | _ => { 91 | return Err(Invalid) 92 | }, 93 | } 94 | } 95 | } 96 | } 97 | } 98 | 99 | impl Decodable for StatusRequest { 100 | type Output = StatusRequest; 101 | fn decode(source: &mut PacketReader)->Result { 102 | use self::PacketDecodingError::*; 103 | use super::StatusRequest::*; 104 | let code = try!(u8::decode(source)); 105 | match code { 106 | STATUS_FASTNET_SPECIFIER => {return Ok(FastnetQuery);}, 107 | STATUS_VERSION_SPECIFIER => {return Ok(VersionQuery);}, 108 | STATUS_EXTENSION_SPECIFIER => { 109 | let extension_name = try!(String::decode(source)); 110 | return Ok(ExtensionQuery(extension_name)); 111 | }, 112 | _ => {return Err(Invalid);}, 113 | } 114 | } 115 | } 116 | 117 | impl Decodable for StatusResponse { 118 | type Output = StatusResponse; 119 | fn decode(source: &mut PacketReader)->Result { 120 | use self::PacketDecodingError::*; 121 | use super::StatusResponse::*; 122 | let code = try!(u8::decode(source)); 123 | match code { 124 | STATUS_FASTNET_SPECIFIER => { 125 | let listening = try!(bool::decode(source)); 126 | return Ok(FastnetResponse(listening)); 127 | }, 128 | STATUS_VERSION_SPECIFIER => { 129 | let version_string = try!(String::decode(source)); 130 | return Ok(VersionResponse(version_string)); 131 | }, 132 | STATUS_EXTENSION_SPECIFIER => { 133 | let name = try!(String::decode(source)); 134 | let supported = try!(bool::decode(source)); 135 | return Ok(ExtensionResponse{name: name, supported: supported}); 136 | }, 137 | _ => {return Err(Invalid);}, 138 | } 139 | } 140 | } 141 | 142 | impl Decodable for bool { 143 | type Output = bool; 144 | fn decode(source: &mut PacketReader)->Result { 145 | let code = try!(u8::decode(source)); 146 | return match code { 147 | 0 => Ok(false), 148 | 1 => Ok(true), 149 | _ => Err(PacketDecodingError::Invalid), 150 | } 151 | } 152 | } 153 | 154 | impl Decodable for i8 { 155 | type Output = i8; 156 | fn decode(source: &mut PacketReader)->Result { 157 | Ok(try!(source.read_i8().or(Err(PacketDecodingError::TooSmall)))) 158 | } 159 | } 160 | 161 | impl Decodable for u8 { 162 | type Output = u8; 163 | fn decode(source: &mut PacketReader)->Result { 164 | Ok(try!(source.read_u8().or(Err(PacketDecodingError::TooSmall)))) 165 | } 166 | } 167 | 168 | impl Decodable for i16 { 169 | type Output = i16; 170 | fn decode(source: &mut PacketReader)->Result { 171 | Ok(try!(source.read_i16::().or(Err(PacketDecodingError::TooSmall)))) 172 | } 173 | } 174 | 175 | impl Decodable for u16 { 176 | type Output = u16; 177 | fn decode(source: &mut PacketReader)->Result { 178 | Ok(try!(source.read_u16::().or(Err(PacketDecodingError::TooSmall)))) 179 | } 180 | } 181 | 182 | impl Decodable for i32 { 183 | type Output = i32; 184 | fn decode(source: &mut PacketReader)->Result { 185 | Ok(try!(source.read_i32::().or(Err(PacketDecodingError::TooSmall)))) 186 | } 187 | } 188 | 189 | impl Decodable for u32 { 190 | type Output = u32; 191 | fn decode(source: &mut PacketReader)->Result { 192 | Ok(try!(source.read_u32::().or(Err(PacketDecodingError::TooSmall)))) 193 | } 194 | } 195 | 196 | impl Decodable for i64 { 197 | type Output = i64; 198 | fn decode(source: &mut PacketReader)->Result { 199 | Ok(try!(source.read_i64::().or(Err(PacketDecodingError::TooSmall)))) 200 | } 201 | } 202 | 203 | impl Decodable for u64 { 204 | type Output = u64; 205 | fn decode(source: &mut PacketReader)->Result { 206 | Ok(try!(source.read_u64::().or(Err(PacketDecodingError::TooSmall)))) 207 | } 208 | } 209 | 210 | impl Decodable for String { 211 | type Output = String; 212 | fn decode(source: &mut PacketReader)->Result { 213 | let data = &source.slice[source.index..]; 214 | let mut index_of_null: Option = None; 215 | for i in 0..data.len() { 216 | if data[i] == 0 { 217 | index_of_null = Some(i); 218 | break; 219 | } 220 | } 221 | if let Some(extracted_index) = index_of_null { 222 | let string_slice = &data[..extracted_index]; 223 | source.index += extracted_index+1; //advance it. 224 | return String::from_utf8(string_slice.to_vec()).or(Err(PacketDecodingError::Invalid)); 225 | } 226 | else { 227 | return Err(PacketDecodingError::Invalid); 228 | } 229 | } 230 | } 231 | 232 | impl Decodable for uuid::Uuid { 233 | type Output = uuid::Uuid; 234 | 235 | fn decode(source: &mut PacketReader)->Result { 236 | let data = &source.slice[source.index..]; 237 | if data.len() < 16 {return Err(PacketDecodingError::TooSmall);} 238 | let uuid = try!(uuid::Uuid::from_bytes(&data[..16]).or(Err(PacketDecodingError::Invalid))); 239 | source.index += 16; 240 | return Ok(uuid); 241 | } 242 | } 243 | 244 | impl Decodable for DataPacket { 245 | type Output = DataPacket; 246 | 247 | fn decode(source: &mut PacketReader)->Result { 248 | let sn = try!(source.read_u64::().or(Err(PacketDecodingError::TooSmall))); 249 | let flags = try!(source.read_u8().or(Err(PacketDecodingError::TooSmall))); 250 | let mut header = None; 251 | if (flags & (1< 0 { 252 | header = Some(try!(FrameHeader::decode(source))); 253 | } 254 | let payload = source.slice[source.index..].to_vec(); 255 | source.index = source.slice.len(); 256 | Ok(DataPacket { 257 | sequence_number: sn, 258 | flags: flags, 259 | payload: payload, 260 | header: header, 261 | }) 262 | } 263 | } 264 | 265 | impl Decodable for FrameHeader { 266 | type Output = FrameHeader; 267 | 268 | fn decode(source: &mut PacketReader)->Result { 269 | let last_reliable_frame = try!(u64::decode(source)); 270 | let length = try!(u32::decode(source)); 271 | Ok(FrameHeader {last_reliable_frame: last_reliable_frame, length: length}) 272 | 273 | } 274 | } 275 | 276 | pub fn decode_packet(buffer: &[u8])->Result { 277 | let mut reader = PacketReader::new(&buffer); 278 | Packet::decode(&mut reader) 279 | } -------------------------------------------------------------------------------- /src/packets/decoder_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use uuid; 3 | 4 | macro_rules! decoder_test { 5 | ($name: ident, $t: ty, $data: expr, $result: expr) => { 6 | #[test] 7 | fn $name() { 8 | let data = $data; 9 | { 10 | let mut reader = PacketReader::new(&data); 11 | let result = <$t as Decodable>::decode(&mut reader).unwrap(); 12 | assert_eq!(reader.available(), 0); //We need to decode it all. 13 | assert_eq!(result, $result); 14 | } 15 | } 16 | } 17 | } 18 | 19 | decoder_test!(test_decode_true, bool, 20 | [1u8], 21 | true); 22 | 23 | decoder_test!(test_decode_false, bool, 24 | [0u8], 25 | false); 26 | 27 | decoder_test!(test_decode_i8_positive, i8, 28 | [1u8], 29 | 1i8); 30 | 31 | decoder_test!(test_decode_i8_negative, i8, 32 | [253u8], 33 | -3i8); 34 | 35 | decoder_test!(test_decode_u8, u8, 36 | [5u8], 5u8); 37 | 38 | decoder_test!(test_decode_i16_positive, i16, 39 | [0x12u8, 0x34u8], 0x1234i16); 40 | 41 | decoder_test!(test_decode_i16_negative, i16, 42 | [0xffu8, 0xfdu8], -3i16); 43 | 44 | decoder_test!(test_decode_u16, u16, 45 | [0x12u8, 0x34u8], 0x1234u16); 46 | 47 | decoder_test!(test_decode_i32_positive, i32, 48 | [0x12u8, 0x34u8, 0x56u8, 0x78u8], 0x12345678i32); 49 | 50 | decoder_test!(test_decode_i32_negative, i32, 51 | [0xffu8, 0xff, 0xff, 0xfd], -3i32); 52 | 53 | decoder_test!(test_decode_u32, u32, 54 | [0x12u8, 0x34, 0x56, 0x78], 0x12345678u32); 55 | 56 | decoder_test!(test_decode_i64_positive, i64, 57 | [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0], 58 | 0x123456789abcdef0i64); 59 | 60 | decoder_test!(test_decode_i64_negative, i64, 61 | [0xffu8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd], 62 | -3i64); 63 | 64 | decoder_test!(test_decode_u64, u64, 65 | [0x12u8, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0], 66 | 0x123456789abcdef0u64); 67 | 68 | decoder_test!(test_decode_string, String, 69 | [b'a', b' ', b't', b'e', b's', b't', 0], 70 | "a test".to_string()); 71 | 72 | //Fastnet specific types: 73 | 74 | decoder_test!(test_decode_fastnet_query, StatusRequest, 75 | [0u8], 76 | StatusRequest::FastnetQuery); 77 | 78 | decoder_test!(test_decode_version_query, StatusRequest, 79 | [1u8], 80 | StatusRequest::VersionQuery); 81 | 82 | decoder_test!(test_decode_extension_query, StatusRequest, 83 | [2u8, b't', b'e', b's', b't', b'_', b'a', b't', b'e', b's', b't', 0], 84 | StatusRequest::ExtensionQuery("test_atest".to_string())); 85 | 86 | decoder_test!(test_decode_fastnet_response, StatusResponse, 87 | [0u8, 1u8], 88 | StatusResponse::FastnetResponse(true)); 89 | 90 | decoder_test!(test_decode_version_response, StatusResponse, 91 | [1u8, b'1', b'.', b'0', 0], 92 | StatusResponse::VersionResponse("1.0".to_string())); 93 | 94 | decoder_test!(test_decode_extension_response, StatusResponse, 95 | [2u8, b't', b'e', b's', b't', b'_', b'a', b't', b'e', b's', b't', 0, 1], 96 | StatusResponse::ExtensionResponse{name: "test_atest".to_string(), supported: true}); 97 | 98 | decoder_test!(test_decode_status_request_packet, Packet, 99 | [255u8, 255, 0, 2, 100 | b'a', b'_', b'b', 0], 101 | Packet::StatusRequest(StatusRequest::ExtensionQuery("a_b".to_string()))); 102 | 103 | decoder_test!(test_decode_status_response_packet, Packet, 104 | [255u8, 255, 1, 2, 105 | b'a', b'_', b'b', 0, 1], 106 | Packet::StatusResponse(StatusResponse::ExtensionResponse{name: "a_b".to_string(), supported: true})); 107 | 108 | //The following tests need a UUID. The following comment is one which can be pasted into such positions: 109 | //0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f 110 | 111 | decoder_test!(test_decode_connect_packet, Packet, 112 | [255u8, 255, 2, 113 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f], 114 | Packet::Connect(uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap())); 115 | 116 | decoder_test!(test_decode_connected_packet, Packet, 117 | [255u8, 255, 3, 118 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f], 119 | Packet::Connected(uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap())); 120 | 121 | decoder_test!(test_decode_aborted_packet, Packet, 122 | [255u8, 255, 4, b'e', b'r', b'r', 0], 123 | Packet::Aborted("err".to_string())); 124 | 125 | decoder_test!(test_decode_heartbeat_packet, Packet, 126 | [255u8, 254, 127 | 0, 0, 0, 0, 0, 0, 0, 1, 128 | 0, 0, 0, 0, 0, 0, 0, 5, 129 | 0, 0, 0, 0, 0, 0, 0, 10], 130 | Packet::Heartbeat{counter: 1, sent: 5, received: 10}); 131 | 132 | decoder_test!(test_decode_echo_packet, Packet, 133 | [255u8, 253, 134 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f, 135 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f,], 136 | Packet::Echo{ 137 | endpoint: uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap(), 138 | uuid: uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap() 139 | }); 140 | 141 | decoder_test!(test_decode_data_packet, Packet, 142 | [0u8, 5, 0, //channel and specifier. 143 | 0, 0, 0, 0, 0, 0, 0, 1, //sequence number is 1. 144 | 6, //flags skips first, but see below. 145 | 5, 10], //And payload. 146 | Packet::Data{ 147 | chan: 5, 148 | packet: DataPacket { 149 | sequence_number: 1, 150 | flags: 6, 151 | payload: vec![5, 10], 152 | header: None, 153 | } 154 | }); 155 | 156 | decoder_test!(test_decode_data_packet_with_header, Packet, 157 | [0u8, 5, 0, //channel and specifier. 158 | 0, 0, 0, 0, 0, 0, 0, 1, //sequence number is 1. 159 | 7, 160 | 0, 0, 0, 0, 0, 0, 0, 5, 161 | 0, 0, 0, 5, 162 | 5, 10], //And payload. 163 | Packet::Data{ 164 | chan: 5, 165 | packet: DataPacket { 166 | sequence_number: 1, 167 | flags: 7, 168 | payload: vec![5, 10], 169 | header: Some(FrameHeader{last_reliable_frame: 5, length: 5}), 170 | } 171 | }); 172 | 173 | decoder_test!(test_decode_ack_packet, Packet, 174 | [0u8, 5, 1, 0, 0, 0, 0, 0, 0, 0, 1], 175 | Packet::Ack{chan: 5, sequence_number: 1}); 176 | -------------------------------------------------------------------------------- /src/packets/encoder.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use byteorder::{BigEndian, WriteBytesExt}; 3 | use uuid; 4 | use std::io::{self, Write}; 5 | use std::cmp; 6 | use std::borrow::{Borrow}; 7 | 8 | #[derive(Debug)] 9 | pub enum PacketEncodingError { 10 | //Not enough space in the buffer. 11 | TooLarge, 12 | //Data didn't validate. 13 | Invalid, 14 | } 15 | 16 | pub struct PacketWriter<'a> { 17 | slice: &'a mut[u8], 18 | index: usize, 19 | } 20 | 21 | impl<'a> PacketWriter<'a> { 22 | pub fn new(destination: &'a mut[u8])->PacketWriter { 23 | PacketWriter{slice: destination, index: 0} 24 | } 25 | 26 | pub fn written(&self)->usize { 27 | self.index 28 | } 29 | 30 | pub fn available(&self)->usize { 31 | self.slice.len()-self.index 32 | } 33 | } 34 | 35 | impl<'a> Write for PacketWriter<'a> { 36 | fn write(&mut self, buf: &[u8])->io::Result { 37 | let available = self.slice.len()-self.index; 38 | let willWrite = cmp::min(available, buf.len()); 39 | for i in 0..willWrite { 40 | self.slice[self.index+i] = buf[i]; 41 | } 42 | self.index += willWrite; 43 | Ok(willWrite) 44 | } 45 | 46 | fn flush(&mut self)->io::Result<()> { 47 | Ok(()) 48 | } 49 | } 50 | 51 | pub trait Encodable { 52 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError>; 53 | } 54 | 55 | impl Encodable for Packet { 56 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 57 | use self::PacketEncodingError::*; 58 | match *self { 59 | Packet::StatusRequest(ref req) => { 60 | try!(CONNECTION_CHANNEL.encode(destination)); 61 | try!(STATUS_REQUEST_SPECIFIER.encode(destination)); 62 | try!(req.encode(destination)); 63 | }, 64 | Packet::StatusResponse(ref resp) => { 65 | try!(CONNECTION_CHANNEL.encode(destination)); 66 | try!(STATUS_RESPONSE_SPECIFIER.encode(destination)); 67 | try!(resp.encode(destination)); 68 | }, 69 | Packet::Connect(id) => { 70 | try!(CONNECTION_CHANNEL.encode(destination)); 71 | try!(CONNECT_SPECIFIER.encode(destination)); 72 | try!(id.encode(destination)); 73 | }, 74 | Packet::Connected(id) => { 75 | try!(CONNECTION_CHANNEL.encode(destination)); 76 | try!(CONNECTED_SPECIFIER.encode(destination)); 77 | try!(id.encode(destination)); 78 | }, 79 | Packet::Aborted(ref msg) => { 80 | try!(CONNECTION_CHANNEL.encode(destination)); 81 | try!(ABORTED_SPECIFIER.encode(destination)); 82 | try!(msg.encode(destination)); 83 | }, 84 | Packet::Heartbeat{counter, sent, received} => { 85 | try!(HEARTBEAT_CHANNEL.encode(destination)); 86 | try!(counter.encode(destination)); 87 | try!(sent.encode(destination)); 88 | try!(received.encode(destination)); 89 | }, 90 | Packet::Echo{endpoint, uuid} => { 91 | try!(ECHO_CHANNEL.encode(destination)); 92 | try!(endpoint.encode(destination)); 93 | try!(uuid.encode(destination)); 94 | }, 95 | Packet::Data{chan, packet: ref p} => { 96 | try!(chan.encode(destination)); 97 | try!(DATA_PACKET_SPECIFIER.encode(destination)); 98 | try!(p.encode(destination)); 99 | }, 100 | Packet::Ack{chan, sequence_number} => { 101 | try!(chan.encode(destination)); 102 | try!(ACK_PACKET_SPECIFIER.encode(destination)); 103 | try!(sequence_number.encode(destination)); 104 | }, 105 | } 106 | Ok(()) 107 | } 108 | } 109 | 110 | impl Encodable for StatusRequest { 111 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 112 | use self::PacketEncodingError::*; 113 | match *self { 114 | StatusRequest::FastnetQuery => { 115 | try!(STATUS_FASTNET_SPECIFIER.encode(destination)); 116 | }, 117 | StatusRequest::VersionQuery => { 118 | try!(STATUS_VERSION_SPECIFIER.encode(destination)); 119 | }, 120 | StatusRequest::ExtensionQuery(ref name) => { 121 | try!(STATUS_EXTENSION_SPECIFIER.encode(destination)); 122 | try!(name.encode(destination)); 123 | }, 124 | } 125 | Ok(()) 126 | } 127 | } 128 | 129 | impl Encodable for StatusResponse { 130 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 131 | use self::PacketEncodingError::*; 132 | match *self { 133 | StatusResponse::FastnetResponse(value) => { 134 | try!(STATUS_FASTNET_SPECIFIER.encode(destination)); 135 | try!(value.encode(destination)); 136 | }, 137 | StatusResponse::VersionResponse(ref version) => { 138 | try!(STATUS_VERSION_SPECIFIER.encode(destination)); 139 | try!(version.encode(destination)); 140 | }, 141 | StatusResponse::ExtensionResponse{ref name, supported} => { 142 | try!(STATUS_EXTENSION_SPECIFIER.encode(destination)); 143 | try!(name.encode(destination)); 144 | try!(supported.encode(destination)); 145 | }, 146 | } 147 | Ok(()) 148 | } 149 | } 150 | 151 | //Encoding primitive types: 152 | 153 | impl Encodable for bool { 154 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 155 | if *self {1u8.encode(destination)} 156 | else {0u8.encode(destination)} 157 | } 158 | } 159 | 160 | impl Encodable for i8 { 161 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 162 | try!(destination.write_i8(*self).or(Err(PacketEncodingError::TooLarge))); 163 | Ok(()) 164 | } 165 | } 166 | 167 | impl Encodable for u8 { 168 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 169 | try!(destination.write_u8(*self).or(Err(PacketEncodingError::TooLarge))); 170 | Ok(()) 171 | } 172 | } 173 | 174 | impl Encodable for i16 { 175 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 176 | try!(destination.write_i16::(*self).or(Err(PacketEncodingError::TooLarge))); 177 | Ok(()) 178 | } 179 | } 180 | 181 | impl Encodable for u16 { 182 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 183 | try!(destination.write_u16::(*self).or(Err(PacketEncodingError::TooLarge))); 184 | Ok(()) 185 | } 186 | } 187 | 188 | impl Encodable for i32 { 189 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 190 | try!(destination.write_i32::(*self).or(Err(PacketEncodingError::TooLarge))); 191 | return Ok(()) 192 | } 193 | } 194 | 195 | impl Encodable for u32 { 196 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 197 | try!(destination.write_u32::(*self).or(Err(PacketEncodingError::TooLarge))); 198 | Ok(()) 199 | } 200 | } 201 | 202 | impl Encodable for i64 { 203 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 204 | try!(destination.write_i64::(*self).or(Err(PacketEncodingError::TooLarge))); 205 | Ok(()) 206 | } 207 | } 208 | 209 | impl Encodable for u64 { 210 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 211 | try!(destination.write_u64::(*self).or(Err(PacketEncodingError::TooLarge))); 212 | Ok(()) 213 | } 214 | } 215 | 216 | //These are the two string types. 217 | //The Fastnet spec requires null-termination. Rust strings are not null terminated. 218 | 219 | fn encode_string_slice(data: &[u8], destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 220 | use self::PacketEncodingError::*; 221 | if data.iter().any(|&x| x == 0) {return Err(Invalid)}; 222 | try!(destination.write_all(data).or(Err(TooLarge))); 223 | try!(0u8.encode(destination)); 224 | Ok(()) 225 | } 226 | 227 | impl Encodable for str { 228 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 229 | encode_string_slice(self.as_bytes(), destination) 230 | } 231 | } 232 | 233 | impl Encodable for String { 234 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 235 | encode_string_slice(self.as_bytes(), destination) 236 | } 237 | } 238 | 239 | impl Encodable for uuid::Uuid { 240 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 241 | try!(destination.write_all(self.as_bytes()).or(Err(PacketEncodingError::TooLarge))); 242 | Ok(()) 243 | } 244 | } 245 | 246 | 247 | impl Encodable for DataPacket { 248 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 249 | use self::PacketEncodingError::*; 250 | try!(self.sequence_number.encode(destination)); 251 | try!(self.flags.encode(destination)); 252 | if let Some(h) = self.header { 253 | try!(h.encode(destination)); 254 | } 255 | for i in self.payload.iter() { 256 | try!(destination.write_u8(*i).or(Err(TooLarge))); 257 | } 258 | Ok(()) 259 | } 260 | } 261 | 262 | impl Encodable for FrameHeader { 263 | fn encode(&self, destination: &mut PacketWriter)->Result<(), PacketEncodingError> { 264 | use self::PacketEncodingError::*; 265 | try!(self.last_reliable_frame.encode(destination)); 266 | try!(self.length.encode(destination)); 267 | Ok(()) 268 | } 269 | } 270 | 271 | pub fn encode_packet>(packet: P, buffer: &mut [u8])->Result { 272 | let mut writer = PacketWriter::new(buffer); 273 | packet.borrow().encode(&mut writer).map(|_| writer.written()) 274 | } -------------------------------------------------------------------------------- /src/packets/encoder_tests.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use uuid; 3 | 4 | macro_rules! encoder_test { 5 | ($name: ident, $result: expr, $($encodees: expr),* ) => { 6 | #[test] 7 | fn $name() { 8 | let mut array = [0u8;1024]; 9 | { 10 | let mut dest = PacketWriter::new(&mut array); 11 | $(($encodees).encode(&mut dest).unwrap();)* 12 | assert!(dest.written() == ($result).len()); 13 | } 14 | assert!($result[..] == array[..($result).len()]); 15 | } 16 | }; 17 | } 18 | 19 | encoder_test!(test_encode_u8, 20 | [0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9], 21 | 0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8); 22 | 23 | 24 | encoder_test!(test_encode_i8, 25 | [251u8, 252u8, 253u8, 254u8, 255u8, 0u8, 1u8, 2u8, 3u8, 4u8], 26 | -5i8, -4i8, -3i8, -2i8, -1i8, 0i8, 1i8, 2i8, 3i8, 4i8); 27 | 28 | encoder_test!(test_encode_u16, 29 | [0u8, 1u8, 1u8, 0u8, 1u8, 1u8, 255u8, 255u8], 30 | 0x0001u16, 0x0100u16, 0x0101u16, 0xffffu16); 31 | 32 | encoder_test!(test_encode_i16, 33 | [0u8, 1, 0x23, 0x45, 0xff, 0xfe, 0xff, 0xff], 34 | 1i16, 0x2345i16, -2i16, -1i16); 35 | 36 | encoder_test!(test_encode_u32, 37 | [0u8, 0, 0, 1, 0x23, 0x45, 0x67, 0x89], 38 | 1u32, 0x23456789u32); 39 | 40 | encoder_test!(test_encode_i32, 41 | [0x23u8, 0x45, 0x67, 0x89, 0xff, 0xff, 0xff, 0xff], 42 | 0x23456789i32, -1i32); 43 | 44 | encoder_test!(test_encode_u64, 45 | [0u8, 0, 0, 0, 0, 0, 0, 5, 46 | 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0], 47 | 5u64, 0x123456789abcdef0u64); 48 | 49 | encoder_test!(test_encode_i64, 50 | [0u8, 0, 0, 0, 0, 0, 0, 5, 51 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe], 52 | 5i64, -2i64); 53 | 54 | encoder_test!(test_encode_str, 55 | [b'h', b'e', b'l', b'l', b'o', 0u8], 56 | "hello"); 57 | 58 | encoder_test!(test_encode_string, 59 | [b'h', b'e', b'l', b'l', b'o', 0u8], 60 | "hello".to_string()); 61 | 62 | encoder_test!(test_encode_status_request, 63 | [0u8, //Fastnet query. 64 | 1, //Version query. 65 | 2, b't', b'e', b's', b't', b'_', 66 | b'a', b't', b'e', b's', b't', 0], //Extension query. 67 | StatusRequest::FastnetQuery, StatusRequest::VersionQuery, StatusRequest::ExtensionQuery("test_atest".to_string())); 68 | 69 | encoder_test!(test_encode_status_response, 70 | [0u8, 1, //fastnet response. 71 | 1, b'1', b'.', b'0', 0, //Version. 72 | 2, b't', b'e', b's', b't', b'_', 73 | b'a', b't', b'e', b's', b't', 0, 1], //Extension "test_atest" is supported. 74 | StatusResponse::FastnetResponse(true), StatusResponse::VersionResponse("1.0".to_string()), 75 | StatusResponse::ExtensionResponse{name: "test_atest".to_string(), supported: true}); 76 | 77 | //We assume that primitive types are tested sufficiently by the above. 78 | //So test one variant each of the Packet enum, using the simplest inner representations we can for testing. 79 | 80 | encoder_test!(test_encode_status_request_packet, 81 | [255u8, 255, 0, 0], //status request of type fastnet query. 82 | Packet::StatusRequest(StatusRequest::FastnetQuery)); 83 | 84 | encoder_test!(test_encode_status_response_packet, 85 | [255, 255, 1, 0, 1], //Fastnet is listening. 86 | Packet::StatusResponse(StatusResponse::FastnetResponse(true))); 87 | 88 | //The following tests need a UUID. The following comment is one which can be pasted into such positions: 89 | //0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f 90 | 91 | encoder_test!(test_encode_connect_packet, 92 | [255, 255, 2, 93 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f], 94 | Packet::Connect(uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap())); 95 | 96 | encoder_test!(test_encode_connected_packet, 97 | [255, 255, 3, 98 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f], 99 | Packet::Connected(uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap())); 100 | 101 | encoder_test!(test_encode_aborted_packet, 102 | [255, 255, 4, b'f', b'a', b'i', b'l', 0], //aborted with message "fail". 103 | Packet::Aborted("fail".to_string())); 104 | 105 | encoder_test!(test_encode_heartbeat_packet, 106 | [255, 254, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 15], 107 | Packet::Heartbeat{counter: 5, sent: 10, received: 15}); 108 | 109 | encoder_test!(test_encode_echo_packet, 110 | [255u8, 253, 111 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f, 112 | 0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f], 113 | Packet::Echo{ 114 | endpoint: uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap(), 115 | uuid: uuid::Uuid::from_bytes(&[0x2d, 0x83, 0x36, 0x9c, 0xc2, 0x26, 0x4a, 0x37, 0x97, 0x97, 0x32, 0x06, 0xf5, 0xb9, 0x50, 0x2f]).unwrap() 116 | }); 117 | 118 | encoder_test!(test_encode_data_packet, 119 | [0u8, 5, 0, //channel and specifier. 120 | 0, 0, 0, 0, 0, 0, 0, 1, //sequence number is 1. 121 | 6, //flags skips first, but see below. 122 | 5, 10], //And payload. 123 | Packet::Data{ 124 | chan: 5, 125 | packet: DataPacket { 126 | sequence_number: 1, 127 | flags: 6, 128 | payload: vec![5, 10], 129 | header: None, 130 | } 131 | }); 132 | 133 | encoder_test!(test_encode_data_packet_with_header, 134 | [0u8, 5, 0, //channel and specifier. 135 | 0, 0, 0, 0, 0, 0, 0, 1, //sequence number is 1. 136 | 7, 137 | 0, 0, 0, 0, 0, 0, 0, 5, 138 | 0, 0, 0, 5, 139 | 5, 10], //And payload. 140 | Packet::Data{ 141 | chan: 5, 142 | packet: DataPacket { 143 | sequence_number: 1, 144 | flags: 7, 145 | payload: vec![5, 10], 146 | header: Some(FrameHeader{last_reliable_frame: 5, length: 5}), 147 | } 148 | }); 149 | 150 | encoder_test!(test_encode_ack_packet, 151 | [0u8, 5, 1, 0, 0, 0, 0, 0, 0, 0, 1], 152 | Packet::Ack{chan: 5, sequence_number: 1}); 153 | -------------------------------------------------------------------------------- /src/packets/mod.rs: -------------------------------------------------------------------------------- 1 | /*! Provides packet encoding and decoding functionality, as well as the packet enum. 2 | 3 | This module does not handle the checksum. If it did, it would be incredibly difficult to write Fastnet tests.*/ 4 | pub use self::encoder::*; 5 | pub use self::decoder::*; 6 | use uuid; 7 | use std::cmp; 8 | 9 | mod encoder; 10 | mod encoder_tests; 11 | mod decoder; 12 | mod decoder_tests; 13 | 14 | #[derive(Debug, PartialEq, Eq, Clone)] 15 | pub enum Packet { 16 | //Status request and response (channel -1) 17 | StatusRequest(StatusRequest), 18 | StatusResponse(StatusResponse), 19 | 20 | //Connection handshake (also channel -1). 21 | Connect(uuid::Uuid), 22 | Connected(uuid::Uuid), 23 | Aborted(String), 24 | 25 | //Heartbeat (channel -2). 26 | Heartbeat{counter: u64, sent: u64, received: u64}, 27 | 28 | Echo{endpoint: uuid::Uuid, uuid: uuid::Uuid}, 29 | 30 | Data{chan: i16, packet: DataPacket}, 31 | Ack{chan: i16, sequence_number: u64} 32 | } 33 | 34 | #[derive(Debug, PartialEq, Eq, Clone)] 35 | pub enum StatusRequest { 36 | FastnetQuery, 37 | VersionQuery, 38 | ExtensionQuery(String), 39 | } 40 | 41 | #[derive(Debug, PartialEq, Eq, Clone)] 42 | pub enum StatusResponse { 43 | FastnetResponse(bool), 44 | VersionResponse(String), 45 | ExtensionResponse {name: String, supported: bool}, 46 | } 47 | 48 | pub const CONNECTION_CHANNEL: i16 = -1; 49 | pub const HEARTBEAT_CHANNEL: i16 = -2; 50 | pub const ECHO_CHANNEL: i16 = -3; 51 | 52 | pub const STATUS_REQUEST_SPECIFIER: u8 = 0; 53 | pub const STATUS_RESPONSE_SPECIFIER: u8 = 1; 54 | pub const CONNECT_SPECIFIER: u8 = 2; 55 | pub const CONNECTED_SPECIFIER: u8 = 3; 56 | pub const ABORTED_SPECIFIER: u8 = 4; 57 | 58 | //These are used both for query and response. 59 | pub const STATUS_FASTNET_SPECIFIER: u8 = 0; 60 | pub const STATUS_VERSION_SPECIFIER: u8 = 1; 61 | pub const STATUS_EXTENSION_SPECIFIER: u8 = 2; 62 | 63 | //Flag bits for data packets, used in the impl of the struct. 64 | pub const DATA_FRAME_START_BIT: u8 = 0; 65 | pub const DATA_FRAME_END_BIT: u8 = 1; 66 | pub const DATA_RELIABLE_BIT: u8 = 2; 67 | 68 | pub const DATA_PACKET_SPECIFIER: u8 = 0; 69 | pub const ACK_PACKET_SPECIFIER: u8 = 1; 70 | 71 | pub const FRAME_HEADER_SIZE: usize = 12; //64-bit sequence number and 32-bit length. 72 | 73 | /**Represents the part of a data packet that a channel must use to assemble packets. 74 | 75 | The actual channel itself is stored in the enum variant. 76 | 77 | These are ordered by sequence number, for use in trees.*/ 78 | #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 79 | pub struct DataPacket { 80 | sequence_number: u64, 81 | flags: u8, 82 | payload: Vec, 83 | header: Option 84 | } 85 | 86 | //It would be nice to put this somewhere else, but we unfortunately can't. 87 | #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)] 88 | pub struct FrameHeader { 89 | pub last_reliable_frame: u64, 90 | pub length: u32, 91 | } 92 | 93 | #[derive(Debug, Clone, Eq, PartialEq)] 94 | pub struct DataPacketBuilder { 95 | sequence_number: u64, 96 | is_reliable: bool, 97 | is_frame_start: bool, 98 | is_frame_end: bool, 99 | payload: Vec, 100 | header: Option, 101 | } 102 | 103 | impl DataPacketBuilder { 104 | /**Initial state is unreliable, mid-frame, and empty payload.*/ 105 | pub fn new(sequence_number: u64)->DataPacketBuilder { 106 | DataPacketBuilder::with_payload(sequence_number, Vec::default()) 107 | } 108 | 109 | /**Makes a packet with the specified payload, no header, and all flags cleared.*/ 110 | pub fn with_payload(sequence_number: u64, payload: Vec)->DataPacketBuilder { 111 | DataPacketBuilder::with_payload_and_header(sequence_number, payload, None) 112 | } 113 | 114 | /**Configures the builder for mid-frame and using the specified header. 115 | 116 | If a header is provided, the packet automatically has its first flag set.*/ 117 | pub fn with_payload_and_header(sequence_number: u64, payload: Vec, header: Option)->DataPacketBuilder { 118 | DataPacketBuilder { 119 | sequence_number: sequence_number, 120 | is_reliable: false, 121 | is_frame_start: header.is_some(), 122 | is_frame_end: false, 123 | payload: payload, 124 | header: header, 125 | } 126 | } 127 | 128 | pub fn set_payload(mut self, payload: Vec)->Self { 129 | self.payload = payload; 130 | self 131 | } 132 | 133 | pub fn set_header(mut self, header: Option)->Self { 134 | self.header = header; 135 | self.is_reliable = header.is_some(); 136 | self 137 | } 138 | 139 | pub fn set_reliable(mut self, reliable: bool)->Self { 140 | self.is_reliable = reliable; 141 | self 142 | } 143 | 144 | pub fn set_frame_start(mut self, start: bool)->Self { 145 | self.is_frame_start = start; 146 | self 147 | } 148 | 149 | pub fn set_frame_end(mut self, end: bool)->Self { 150 | self.is_frame_end = end; 151 | self 152 | } 153 | 154 | pub fn set_sequence_number(mut self, sequence_number: u64)->Self { 155 | self.sequence_number = sequence_number; 156 | self 157 | } 158 | 159 | /**Panics if the packet is invalid. Building invalid packets is a bug.*/ 160 | pub fn build(self)->DataPacket { 161 | if self.is_frame_start != self.header.is_some() { 162 | panic!("Header and start flag mismatch. Start flag = {:?}, header = {:?}", self.is_frame_start, self.header); 163 | } 164 | let start_flag = (self.is_frame_start as u8) << DATA_FRAME_START_BIT; 165 | let end_flag = (self.is_frame_end as u8) << DATA_FRAME_END_BIT; 166 | let reliable_flag = (self.is_reliable as u8) << DATA_RELIABLE_BIT; 167 | let flags = start_flag | end_flag | reliable_flag; 168 | DataPacket { 169 | sequence_number: self.sequence_number, 170 | flags: flags, 171 | payload: self.payload, 172 | header: self.header, 173 | } 174 | } 175 | } 176 | 177 | impl DataPacket { 178 | pub fn is_reliable(&self)->bool { 179 | (self.flags & DATA_RELIABLE_BIT) > 0 180 | } 181 | 182 | pub fn is_frame_start(&self)->bool { 183 | (self.flags & DATA_FRAME_START_BIT) > 0 184 | } 185 | 186 | pub fn is_frame_end(&self)->bool { 187 | (self.flags & DATA_FRAME_END_BIT) > 0 188 | } 189 | 190 | pub fn sequence_number(&self)->u64 { 191 | self.sequence_number 192 | } 193 | 194 | pub fn borrow_header(&self)->Option<&FrameHeader> { 195 | self.header.as_ref() 196 | } 197 | 198 | pub fn get_header(&self)->Option { 199 | self.header 200 | } 201 | 202 | pub fn borrow_payload(&self)->&Vec { 203 | &self.payload 204 | } 205 | 206 | pub fn into_payload(self)->Vec { 207 | self.payload 208 | } 209 | } 210 | 211 | impl FrameHeader { 212 | pub fn new(last_reliable_frame: u64, length: u32)->FrameHeader { 213 | FrameHeader{last_reliable_frame: last_reliable_frame, length: length} 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/server/ack_manager.rs: -------------------------------------------------------------------------------- 1 | use std::collections; 2 | use std::iter; 3 | use packets; 4 | use time; 5 | 6 | const INITIAL_DURATION: u64 = 100000000; 7 | const INITIAL_DURATION_MULTIPLIER: f64 = 1.1; 8 | 9 | #[derive(Debug, Clone, PartialEq)] 10 | struct AckRecord { 11 | packet: packets::Packet, 12 | next_time: u64, 13 | duration_multiplier: f64, 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct AckManager { 18 | packets: collections::BTreeMap<(i16, u64), AckRecord>, 19 | } 20 | 21 | impl AckManager { 22 | pub fn new()->AckManager { 23 | AckManager {packets: collections::BTreeMap::default()} 24 | } 25 | 26 | /**Handles either ack or data. 27 | 28 | Returns true if the packet was handled. Otherwise false.*/ 29 | pub fn submit_packet(&mut self, packet: packets::Packet)->bool { 30 | let mut channel = 0i16; 31 | let mut sn = 0u64; 32 | match packet { 33 | packets::Packet::Ack{chan, sequence_number} => { 34 | //If in the map, kill it. 35 | self.packets.remove(&(chan, sequence_number)); 36 | return true; 37 | }, 38 | packets::Packet::Data{chan, packet: ref p} => { 39 | //To make this work out, we fall through after gathering the information we need. 40 | channel = chan; 41 | sn = p.sequence_number(); 42 | }, 43 | _ => {return false} 44 | } 45 | //If we get here, it's a data packet. Insert and return true. 46 | self.packets.insert((channel, sn), AckRecord{ 47 | packet: packet, 48 | next_time: time::precise_time_ns()+INITIAL_DURATION, 49 | duration_multiplier: INITIAL_DURATION_MULTIPLIER, 50 | }); 51 | return true; 52 | } 53 | 54 | pub fn iter_needs_ack<'A>(&'A mut self)->Box+'A> { 55 | let now = time::precise_time_ns(); 56 | let mut res = self.packets.iter_mut().filter(move |i| { 57 | i.1.next_time <= now 58 | }).map(move |i| { 59 | let rec: &mut AckRecord = i.1; 60 | rec.next_time = now+((INITIAL_DURATION as f64)*rec.duration_multiplier) as u64; 61 | rec.duration_multiplier *= INITIAL_DURATION_MULTIPLIER; 62 | &rec.packet 63 | }); 64 | Box::new(res) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/server/connection.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use packets::*; 3 | use async; 4 | use status_translator; 5 | use std::net; 6 | use std::borrow::{Borrow}; 7 | use std::time; 8 | use uuid; 9 | 10 | #[derive(Debug, Copy, Clone)] 11 | pub enum ConnectionState { 12 | Establishing{listening: bool, compatible_version: bool, attempts: u32, request_id: Option}, 13 | Established, 14 | Closing{request_id: Option}, 15 | Closed, 16 | } 17 | 18 | #[derive(Debug)] 19 | pub struct Connection { 20 | pub state: ConnectionState, 21 | pub id: uuid::Uuid, 22 | pub address: net::SocketAddr, 23 | pub received_packets: u64, 24 | pub sent_packets: u64, 25 | pub heartbeat_counter: u64, 26 | //For echoes. 27 | pub endpoint_id: uuid::Uuid, 28 | pub roundtrip_estimator: RoundtripEstimator, 29 | //For timing out. 30 | pub last_received_packet_time: time::Instant, 31 | pub ack_manager: AckManager, 32 | } 33 | 34 | const MAX_STATUS_ATTEMPTS: u32 = 10; 35 | const MAX_CONNECTION_ATTEMPTS:u32 = 25; //5000 ms divided by 200 ms per attempt, see spec. 36 | 37 | impl Connection { 38 | 39 | pub fn new(address: net::SocketAddr, id: uuid::Uuid)->Connection { 40 | Connection { 41 | state: ConnectionState::Closed, 42 | id: id, 43 | address: address, 44 | sent_packets: 0, 45 | received_packets: 0, 46 | heartbeat_counter: 0, 47 | endpoint_id: uuid::Uuid::new_v4(), 48 | roundtrip_estimator: RoundtripEstimator::new(5), 49 | last_received_packet_time: time::Instant::now(), 50 | ack_manager: AckManager::new(), 51 | } 52 | } 53 | 54 | pub fn from_connection_request(address: net::SocketAddr, id: uuid::Uuid)->Connection { 55 | let mut conn = Connection::new(address, id); 56 | conn.state = ConnectionState::Established; 57 | conn 58 | } 59 | 60 | pub fn establish(&mut self, request_id: Option, service: &mut MioServiceProvider) { 61 | if let ConnectionState::Closed = self.state { 62 | self.state = ConnectionState::Establishing{listening: false, compatible_version: false, attempts: 0, request_id: request_id}; 63 | //get things rolling... 64 | self.send(Packet::StatusRequest(StatusRequest::FastnetQuery), service); 65 | } 66 | } 67 | 68 | pub fn send, H: async::Handler>(&mut self, packet: P, service: &mut MioServiceProvider)->bool { 69 | self.sent_packets += 1; 70 | service.send(packet, self.address) 71 | } 72 | 73 | pub fn handle_incoming_packet(&mut self, packet: &Packet, service: &mut MioServiceProvider)->bool { 74 | self.received_packets += 1; 75 | self.last_received_packet_time = time::Instant::now(); 76 | match *packet { 77 | Packet::StatusResponse(ref resp) => { 78 | self.handle_status_response(resp, service); 79 | true 80 | }, 81 | Packet::Echo{endpoint, uuid} => { 82 | if endpoint != self.endpoint_id { 83 | self.send(packet, service); 84 | } 85 | else { 86 | self.roundtrip_estimator.handle_echo(self.id, uuid, service); 87 | } 88 | true 89 | }, 90 | Packet::Heartbeat{counter: c, sent: s, received: r} => { 91 | true 92 | }, 93 | Packet::Connected(id) => { 94 | self.handle_connected(id, service); 95 | true 96 | }, 97 | Packet::Aborted(ref message) => { 98 | self.handle_aborted(message, service); 99 | true 100 | }, 101 | Packet::Ack{..} => { 102 | self.ack_manager.submit_packet(packet.clone()) 103 | } 104 | _ => false 105 | } 106 | } 107 | 108 | fn handle_connected(&mut self, id: uuid::Uuid, service: &mut MioServiceProvider) { 109 | //per the spec, ignore any connected packet that doesn't echo our id. 110 | if id != self.id {return;} 111 | if let ConnectionState::Establishing{listening, compatible_version, request_id, ..} = self.state { 112 | if listening && compatible_version { 113 | //The spec says that heartbeats don't count any packets that happen before full establishment. 114 | self.sent_packets = 0; 115 | self.received_packets = 0; 116 | self.state = ConnectionState::Established; 117 | service.handler.connected(self.id, request_id); 118 | } 119 | } 120 | //Otherwise, we shouldn't be receiving this yet so just drop it. 121 | } 122 | 123 | fn handle_aborted(&mut self, message: &str, service: &mut MioServiceProvider) { 124 | if let ConnectionState::Establishing{listening, compatible_version, request_id, ..} = self.state { 125 | if listening && compatible_version { 126 | self.state = ConnectionState::Closed; 127 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::ConnectionAborted);} 128 | } 129 | } 130 | } 131 | 132 | fn handle_status_response(&mut self, resp: &StatusResponse, service: &mut MioServiceProvider) { 133 | if let ConnectionState::Establishing{mut listening, mut compatible_version, mut attempts, request_id} = self.state { 134 | match *resp { 135 | StatusResponse::FastnetResponse(new_listening) if listening == false => { 136 | if new_listening == false { 137 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::NotListening);} 138 | self.state = ConnectionState::Closed; 139 | return; 140 | } 141 | listening = true; 142 | self.send(Packet::StatusRequest(StatusRequest::VersionQuery), service); 143 | }, 144 | StatusResponse::VersionResponse(ref v) if compatible_version == false => { 145 | if v.eq(status_translator::PROTOCOL_VERSION) == false { 146 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::IncompatibleVersions)} 147 | self.state = ConnectionState::Closed; 148 | return; 149 | } 150 | compatible_version = true; 151 | } 152 | _ => {} 153 | } 154 | if listening && compatible_version { 155 | let id = self.id; 156 | self.send(Packet::Connect(id), service); 157 | } 158 | self.state = ConnectionState::Establishing{attempts: 0, listening: listening, compatible_version: compatible_version, request_id: request_id}; 159 | } 160 | } 161 | 162 | pub fn tick1000(&mut self, service: &mut MioServiceProvider) { 163 | if let ConnectionState::Established = self.state { 164 | let heartbeat = Packet::Heartbeat{counter: self.heartbeat_counter, sent: self.sent_packets, received: self.received_packets}; 165 | self.heartbeat_counter += 1; 166 | self.send(heartbeat, service); 167 | } 168 | } 169 | 170 | pub fn tick200(&mut self, service: &mut MioServiceProvider) { 171 | match self.state { 172 | ConnectionState::Establishing{mut attempts, listening, compatible_version, request_id} => { 173 | attempts += 1; 174 | if listening == false { 175 | if attempts > MAX_STATUS_ATTEMPTS { 176 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::TimedOut);} 177 | self.state = ConnectionState::Closed; 178 | return; 179 | } 180 | service.send(Packet::StatusRequest(StatusRequest::FastnetQuery), self.address); 181 | } 182 | else if compatible_version == false { 183 | if attempts > MAX_STATUS_ATTEMPTS { 184 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::TimedOut);} 185 | self.state = ConnectionState::Closed; 186 | return; 187 | } 188 | service.send(Packet::StatusRequest(StatusRequest::VersionQuery), self.address); 189 | } 190 | else { 191 | if attempts > MAX_CONNECTION_ATTEMPTS { 192 | if let Some(id) = request_id {service.handler.request_failed(id, async::Error::TimedOut);} 193 | self.state = ConnectionState::Closed; 194 | return; 195 | } 196 | service.send(Packet::Connect(self.id), self.address); 197 | } 198 | }, 199 | ConnectionState::Established => { 200 | self.roundtrip_estimator.tick(self.address, self.endpoint_id, service); 201 | //Send the acks. 202 | for i in self.ack_manager.iter_needs_ack() { 203 | service.send(i, self.address); 204 | } 205 | }, 206 | _ => {}, 207 | } 208 | } 209 | 210 | } 211 | -------------------------------------------------------------------------------- /src/server/data_packet_handler.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use packets::*; 3 | use async; 4 | use constants; 5 | use std::net; 6 | use std::thread; 7 | use std::cell; 8 | use std::ops::{Deref, DerefMut}; 9 | 10 | 11 | //These are used by the message delivery logic. 12 | thread_local!(static message_buffer: cell::RefCell> = cell::RefCell::new(Vec::default())); 13 | thread_local!(static index_buffer: cell::RefCell> = cell::RefCell::new(Vec::default())); 14 | 15 | /**handles acking packets, etc.*/ 16 | #[derive(Debug)] 17 | pub struct DataPacketHandler { 18 | channel: i16, 19 | address : net::SocketAddr, 20 | ignore_number: u64, 21 | last_reliable_frame: u64, 22 | contained_payload: usize, //Used for cost limits. 23 | limit: usize, //the per-channel memory limit. 24 | acked_packets: Vec, 25 | unacked_packets: Vec, 26 | } 27 | 28 | 29 | impl DataPacketHandler { 30 | 31 | pub fn new(chan: i16, address: net::SocketAddr)->DataPacketHandler { 32 | DataPacketHandler { 33 | channel: chan, 34 | address: address, 35 | ignore_number: 0, 36 | last_reliable_frame: 0, 37 | contained_payload: 0, 38 | limit: constants::PER_CHANNEL_MEMORY_LIMIT_DEFAULT, 39 | acked_packets: Vec::default(), 40 | unacked_packets: Vec::default(), 41 | } 42 | } 43 | 44 | pub fn handle_incoming_packet(&mut self, packet: DataPacket, service: &mut MioServiceProvider) { 45 | let sn = packet.sequence_number(); 46 | let reliable = packet.is_reliable(); 47 | if(sn < self.ignore_number && reliable) { 48 | self.ack(sn, service); 49 | return; 50 | } 51 | else if(sn < self.ignore_number) { 52 | return; 53 | } 54 | if packet.is_reliable() {self.ensure_room(packet.borrow_payload().len());} 55 | let new_contained_payload = self.contained_payload + packet.borrow_payload().len(); 56 | if(new_contained_payload > self.limit) {return;} 57 | //If the sequence nubmer is already in acked_packets then we ack and abort. 58 | //Otherwise, we just abort. 59 | let is_in_acked = self.acked_packets.binary_search_by_key(&packet.sequence_number(), |i| i.sequence_number()); 60 | if let Ok(_) = is_in_acked { 61 | if(reliable) {self.ack(sn, service);} 62 | return; 63 | } 64 | let is_in_unacked = self.unacked_packets.binary_search_by_key(&packet.sequence_number(), |i| i.sequence_number()); 65 | if let Ok(_) = is_in_unacked {return;} 66 | if(reliable) { 67 | self.unacked_packets.insert(is_in_unacked.unwrap_err(), packet); 68 | } 69 | else { 70 | self.acked_packets.insert(is_in_acked.unwrap_err(), packet); 71 | } 72 | self.contained_payload = new_contained_payload; 73 | } 74 | 75 | pub fn do_acks(&mut self, service: &mut MioServiceProvider) { 76 | //Because the acked packets are in order, failure to ack means we can stop early. 77 | let mut end_index = 0; 78 | for pack in self.unacked_packets.iter() { 79 | let sn = pack.sequence_number(); 80 | if sn < self.ignore_number || sn == self.last_reliable_frame + 1 { 81 | self.ignore_number = sn; 82 | self.ack(sn, service); 83 | end_index += 1; 84 | } 85 | else {break;} 86 | } 87 | //Promote the packets. 88 | for pack in self.unacked_packets.drain(..end_index) { 89 | let ind = self.acked_packets.binary_search_by_key(&pack.sequence_number(), |i| i.sequence_number()); 90 | if let Err(index) = ind { 91 | self.acked_packets.insert(index, pack); 92 | } 93 | //Otherwise it's a duplicate, so we do nothing. 94 | } 95 | } 96 | 97 | //Delivery logic. Returns the number of packets delivered. 98 | pub fn deliver)>(&mut self, destination: F)->usize { 99 | //Extract the two TLS keys. 100 | message_buffer.with(|message_buff| { 101 | index_buffer.with(|index_buff| { 102 | self.deliver_helper(destination, message_buff.borrow_mut().deref_mut(), index_buff.borrow_mut().deref_mut()) 103 | }) 104 | }) 105 | } 106 | 107 | fn deliver_helper)>(&mut self, destination: F, message_buff: &mut Vec, index_buff: &mut Vec)->usize { 108 | message_buff.clear(); 109 | index_buff.clear(); 110 | let mut delivered_count = 0; 111 | //Collect all the starting packets into index_buff. 112 | index_buff.extend( 113 | self.acked_packets.iter().enumerate().filter(|i| i.1.is_frame_start()).map(|i| i.0) 114 | ); 115 | for index in index_buff.iter() { 116 | let header = self.acked_packets[*index].get_header().unwrap(); //This is a start of frame; bug if it doesn't have one. 117 | if header.last_reliable_frame != self.last_reliable_frame {break;} //There's a reliable frame we don't have yet. 118 | let mut end_index = *index; 119 | let mut sn = self.acked_packets[*index].sequence_number(); 120 | for p in self.acked_packets[*index..].iter() { 121 | //Handle the first one, possibly breaking out now. 122 | if p.sequence_number() == sn { 123 | if p.is_frame_end() {break;} //It's a 1-packet message. 124 | continue; //Otherwise we skip it. 125 | } 126 | //Either it starts a new frame, may end the current frame, or is a gap. 127 | //In all three cases, we break out. 128 | if p.is_frame_start() || p.is_frame_end() || p.sequence_number()-sn != 1 {break;} 129 | end_index += 1; 130 | sn += 1; 131 | } 132 | //We know that the range is consecutive and that the last reliable frame condition was met. 133 | //If the start and end are not true, it's undeliverable and we stop. 134 | if self.acked_packets[*index].is_frame_start() == false || self.acked_packets[end_index].is_frame_end() == false {break;} 135 | //Otherwise, we need to assemble the frame and remove the packets. 136 | let is_reliable = self.acked_packets[*index].is_reliable(); 137 | let new_last_reliable = self.acked_packets[*index].sequence_number(); 138 | for p in self.acked_packets.drain(*index..end_index+1) { 139 | let mut payload = p.into_payload(); 140 | self.contained_payload -= payload.len(); 141 | message_buff.append(&mut payload); 142 | } 143 | if is_reliable {self.last_reliable_frame = new_last_reliable;} 144 | delivered_count += 1; 145 | destination(&message_buff); 146 | } 147 | delivered_count 148 | } 149 | 150 | //Implements the packet dropping logic to allow incoming reliable packets to evict other, less important packets. 151 | pub fn ensure_room(&mut self, amount: usize) { 152 | if amount < self.limit-self.contained_payload {return;} 153 | let mut reliable_endpoint = self.unacked_packets.len(); 154 | let mut unreliable_endpoint = 0; 155 | let mut sum = 0; 156 | //This simulates a goto, the best way to do the following. 157 | 'outer: loop { 158 | for pack in self.acked_packets.iter() { 159 | if sum > amount {break 'outer;} 160 | if pack.is_reliable() == false { 161 | sum += pack.borrow_payload().len(); 162 | } 163 | unreliable_endpoint += 1; 164 | } 165 | for pack in self.unacked_packets.iter().rev() { 166 | if sum > amount {break 'outer;} 167 | if pack.is_reliable() { 168 | sum += pack.borrow_payload().len(); 169 | } 170 | reliable_endpoint -= 1; 171 | } 172 | break; 173 | } 174 | //Kill unreliables. 175 | for i in 0..unreliable_endpoint { 176 | if self.acked_packets[i].is_reliable() == false { 177 | self.acked_packets.remove(i); 178 | } 179 | } 180 | //The unacked packets are all reliable, so we can use drain. 181 | self.unacked_packets.drain(reliable_endpoint..); 182 | self.contained_payload -= sum; 183 | } 184 | 185 | pub fn ack(&self, sn: u64, service: &mut MioServiceProvider) { 186 | let packet = Packet::Ack{chan: self.channel, sequence_number: sn}; 187 | service.send(packet, self.address); 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/server/mio_server.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use async; 3 | use packets::{self, Encodable, Decodable}; 4 | use status_translator; 5 | use crc::crc32; 6 | use byteorder::{self, BigEndian, ByteOrder}; 7 | use std::collections; 8 | use std::net; 9 | use std::thread; 10 | use std::io; 11 | use std::sync::mpsc; 12 | use std::time; 13 | use std::borrow::{Borrow}; 14 | use mio; 15 | use mio::udp; 16 | use uuid; 17 | 18 | const SOCKET_TOKEN: mio::Token = mio::Token(0); 19 | 20 | #[derive(Debug, Copy, Clone)] 21 | pub enum TimeoutTypes { 22 | Timeout1000, 23 | Timeout200, 24 | } 25 | 26 | pub enum MioHandlerCommand { 27 | DoCall(Box)+Send>), 28 | } 29 | 30 | /*This doesn't have a good name. 31 | 32 | Basically it exists so that we can pass some stuff around without making the borrow checker mad. Primarily it "provides" services, so we call it for that.*/ 33 | pub struct MioServiceProvider<'a, H: async::Handler> { 34 | pub socket: &'a udp::UdpSocket, 35 | pub incoming_packet_buffer: [u8; 1000], 36 | pub outgoing_packet_buffer: [u8; 1000], 37 | pub handler: H, 38 | } 39 | 40 | pub struct MioHandler<'a, H: async::Handler> { 41 | service: MioServiceProvider<'a, H>, 42 | connections: collections::HashMap, 43 | connection_timeout_duration: time::Duration, 44 | //This is a workaround because maps don't have retain. 45 | connection_key_vector: Vec, 46 | } 47 | 48 | impl<'a, H: async::Handler> MioHandler<'a, H> { 49 | pub fn new(socket: &'a udp::UdpSocket, handler: H)->MioHandler<'a, H> { 50 | MioHandler { 51 | service: MioServiceProvider { 52 | socket: socket, 53 | incoming_packet_buffer: [0u8; 1000], 54 | outgoing_packet_buffer: [0u8; 1000], 55 | handler: handler, 56 | }, 57 | connections: collections::HashMap::new(), 58 | connection_key_vector: Vec::default(), 59 | connection_timeout_duration: time::Duration::from_secs(10), 60 | } 61 | } 62 | 63 | fn got_packet(&mut self, size: usize, address: net::SocketAddr) { 64 | if size == 0 {return;} 65 | let maybe_packet = { 66 | let slice = &self.service.incoming_packet_buffer[0..size]; 67 | let computed_checksum = crc32::checksum_castagnoli(&slice[4..]); 68 | let expected_checksum = BigEndian::read_u32(&slice[..4]); 69 | if computed_checksum != expected_checksum { 70 | debug!("Checksum invalid: {} versus {}", computed_checksum, expected_checksum); 71 | Err(packets::PacketDecodingError::Invalid) 72 | } 73 | else {packets::decode_packet(&slice[4..])} 74 | }; 75 | if let Err(_) = maybe_packet {return;} 76 | let packet = maybe_packet.unwrap(); 77 | debug!("Incoming from {:?}: {:?}", address, packet); 78 | if let Some(ref mut conn) = self.connections.get_mut(&address) { 79 | if conn.handle_incoming_packet(&packet, &mut self.service) {return;} 80 | } 81 | match packet { 82 | packets ::Packet::Connect(id) => { 83 | if let Some(c) = self.connections.get(&address) { 84 | self.service.send(packets::Packet::Connected(c.id), address); 85 | return; 86 | } 87 | let conn = Connection::from_connection_request(address, id); 88 | self.connections.insert(address, conn); 89 | self.service.send(packets::Packet::Connected(id), address); 90 | self.service.handler.connected(id, None); 91 | }, 92 | packets::Packet::StatusRequest(ref req) => { 93 | self.service.send(packets::Packet::StatusResponse(status_translator::translate(req)), address); 94 | }, 95 | p@_ => { 96 | debug!("Previous packet was unhandled."); 97 | } 98 | } 99 | } 100 | 101 | pub fn connect(&mut self, address: net:: SocketAddr, request_id: u64) { 102 | let id = uuid::Uuid::new_v4(); 103 | info!("New connection, id = {}", id); 104 | let mut conn = Connection::new(address, id); 105 | conn.establish(Some(request_id), &mut self.service); 106 | self.connections.insert(address, conn); 107 | } 108 | 109 | pub fn disconnect(&mut self, id: uuid::Uuid, request_id: u64) { 110 | //todo: fill this out. 111 | } 112 | 113 | pub fn configure_timeout(&mut self, timeout_ms: u64) { 114 | self.connection_timeout_duration = time::Duration::from_millis(timeout_ms); 115 | } 116 | } 117 | 118 | impl<'A, H: async::Handler> MioServiceProvider<'A, H> { 119 | pub fn send>(&mut self, packet: P, address: net::SocketAddr)->bool { 120 | debug!("sending to {:?}: {:?}", address, packet.borrow()); 121 | if let Ok(size) = packets::encode_packet(packet, &mut self.outgoing_packet_buffer[4..]) { 122 | let checksum = crc32::checksum_castagnoli(&self.outgoing_packet_buffer[4..4+size]); 123 | BigEndian::write_u32(&mut self.outgoing_packet_buffer[..4], checksum); 124 | if let Ok(Some(sent_bytes)) = self.socket.send_to(&self.outgoing_packet_buffer[..4+size], &address) { 125 | if sent_bytes == 4+size {return true;} 126 | else {return false;} 127 | } 128 | else {return false;} 129 | } 130 | else {return false;}; 131 | } 132 | } 133 | 134 | impl<'a, H: async::Handler+Send> mio::Handler for MioHandler<'a, H> { 135 | type Timeout = TimeoutTypes; 136 | type Message = MioHandlerCommand; 137 | 138 | fn ready(&mut self, event_loop: &mut mio::EventLoop, token: mio::Token, events: mio::EventSet) { 139 | //We only have one socket, so can avoid the match on the token. 140 | if events.is_error() { 141 | //We need to do something sensible here, probably a callback with whatever state we can get. 142 | } 143 | if events.is_readable() { 144 | let result = self.service.socket.recv_from(&mut self.service.incoming_packet_buffer); 145 | if let Ok(Some((size, address))) = result { 146 | self.got_packet(size, address); 147 | } 148 | } 149 | } 150 | 151 | fn timeout(&mut self, event_loop: &mut mio::EventLoop, timeout: Self::Timeout) { 152 | let rereg = match timeout { 153 | TimeoutTypes::Timeout200 => { 154 | for i in self.connections.iter_mut() {i.1.tick200(&mut self.service)} 155 | 200 156 | }, 157 | TimeoutTypes::Timeout1000 => { 158 | self.connection_key_vector.clear(); 159 | let now = time::Instant::now(); 160 | for i in self.connections.iter_mut() { 161 | i.1.tick1000(&mut self.service); 162 | if now.duration_since(i.1.last_received_packet_time) > self.connection_timeout_duration { 163 | self.connection_key_vector.push(*i.0); 164 | self.service.handler.disconnected(i.1.id, None); 165 | } 166 | } 167 | for i in self.connection_key_vector.iter() { 168 | self.connections.remove(&i); 169 | } 170 | 1000 171 | }, 172 | }; 173 | event_loop.timeout_ms(timeout, rereg).unwrap(); 174 | } 175 | 176 | fn notify(&mut self, event_loop: &mut mio::EventLoop, message: Self::Message) { 177 | match message { 178 | MioHandlerCommand::DoCall(ref f) => f(self), 179 | } 180 | } 181 | } 182 | 183 | fn mio_server_thread< H: async::Handler+Send>(address: net::SocketAddr, handler: H, notify_created: mpsc::Sender>, io::Error>>) { 184 | let maybe_socket = match address { 185 | net::SocketAddr::V4(_) => udp::UdpSocket::v4(), 186 | net::SocketAddr::V6(_) => udp::UdpSocket::v6() 187 | }; 188 | if let Err(what) = maybe_socket { 189 | notify_created.send(Err(what)).unwrap(); 190 | return; 191 | } 192 | let socket = maybe_socket.unwrap(); 193 | if let Err(what) = socket.bind(&address) { 194 | notify_created.send(Err(what)).unwrap(); 195 | return; 196 | } 197 | let maybe_loop = mio::EventLoop::new(); 198 | if let Err(what) = maybe_loop { 199 | notify_created.send(Err(what)).unwrap(); 200 | return; 201 | } 202 | let mut event_loop = maybe_loop.unwrap(); 203 | let mut handler = MioHandler::new(&socket, handler); 204 | if let Err(what) = event_loop.register(&socket, SOCKET_TOKEN, mio::EventSet::all(), mio::PollOpt::level()) { 205 | notify_created.send(Err(what)).unwrap(); 206 | return; 207 | } 208 | let timer_error = Err(io::Error::new(io::ErrorKind::Other, "Couldn't create the timer.")); 209 | if let Err(_) = event_loop.timeout_ms(TimeoutTypes::Timeout1000, 1000) { 210 | notify_created.send(timer_error).unwrap(); 211 | return; 212 | } 213 | if let Err(_) = event_loop.timeout_ms(TimeoutTypes::Timeout200, 200) { 214 | notify_created.send(timer_error); 215 | return; 216 | } 217 | let sender = event_loop.channel(); 218 | notify_created.send(Ok(sender)); 219 | event_loop.run(&mut handler); 220 | } 221 | 222 | pub struct MioServer { 223 | thread: thread::JoinHandle<()>, 224 | sender: mio::Sender>, 225 | } 226 | 227 | impl MioServer { 228 | pub fn new(address: net::SocketAddr, handler: H)->Result, io::Error> { 229 | let (sender, receiver) = mpsc::channel(); 230 | let join_handle = thread::spawn(move || mio_server_thread(address, handler, sender)); 231 | let message_sender = try!(receiver.recv().unwrap()); 232 | Ok(MioServer { 233 | thread: join_handle, 234 | sender: message_sender, 235 | }) 236 | } 237 | 238 | pub fn with)+Send+'static>(&mut self, func: F) { 239 | let command = MioHandlerCommand::DoCall(Box::new(func)); 240 | self.sender.send(command); 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /src/server/mod.rs: -------------------------------------------------------------------------------- 1 | use packets; 2 | use std::net; 3 | 4 | mod mio_server; 5 | mod connection; 6 | mod data_packet_handler; 7 | mod ack_manager; 8 | mod roundtrip_estimator; 9 | 10 | pub use self::mio_server::*; 11 | pub use self::connection::*; 12 | pub use self::roundtrip_estimator::*; 13 | pub use self::ack_manager::*; 14 | 15 | -------------------------------------------------------------------------------- /src/server/roundtrip_estimator.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use async; 3 | use std::time; 4 | use std::collections; 5 | use std::cmp; 6 | use std::net; 7 | use std::ops; 8 | use uuid; 9 | use packets::{Packet}; 10 | 11 | 12 | #[derive(Debug)]pub struct RoundtripEstimator { 13 | expected_echoes: collections::HashMap, 14 | estimation: Vec, 15 | required_echoes: usize, 16 | last_estimate: Option, 17 | } 18 | 19 | impl RoundtripEstimator { 20 | 21 | pub fn new(required_echoes: usize)->RoundtripEstimator { 22 | RoundtripEstimator { 23 | expected_echoes: collections::HashMap::default(), 24 | estimation: Vec::default(), 25 | required_echoes: required_echoes, 26 | last_estimate: None, 27 | } 28 | } 29 | 30 | pub fn get_last_estimate(&self)->Option { 31 | self.last_estimate 32 | } 33 | 34 | //Called once a second by established connections. 35 | pub fn tick(&mut self, address: net::SocketAddr, endpoint_id: uuid::Uuid, service: &mut MioServiceProvider) { 36 | let now = time::Instant::now(); 37 | //Kill all echoes older than 5 seconds. 38 | let mut removing = Vec::with_capacity(self.expected_echoes.len()); 39 | for i in self.expected_echoes.iter() { 40 | let dur = now.duration_since(*i.1); 41 | if dur.as_secs() >= 5 { 42 | removing.push(*i.0); 43 | } 44 | } 45 | for i in removing.iter() { 46 | self.expected_echoes.remove(i); 47 | } 48 | //Replace any if needed. 49 | if self.expected_echoes.len() < self.required_echoes { 50 | let needed_echoes = cmp::min(5, self.required_echoes-self.expected_echoes.len()); 51 | for i in 0..needed_echoes { 52 | let uuid = uuid::Uuid::new_v4(); 53 | self.expected_echoes.insert(uuid, now); 54 | service.send(Packet::Echo{endpoint: endpoint_id, uuid: uuid}, address); 55 | } 56 | } 57 | } 58 | 59 | pub fn handle_echo(&mut self, connection_id: uuid::Uuid, echo_id: uuid::Uuid, service: &mut MioServiceProvider) { 60 | if let Some(&instant) = self.expected_echoes.get(&echo_id) { 61 | let dur = time::Instant::now().duration_since(instant); 62 | let dur_ms: u64 = dur.as_secs()*1000+dur.subsec_nanos() as u64/1000000u64; 63 | self.estimation.push(dur_ms as u32); 64 | self.expected_echoes.remove(&echo_id); 65 | } 66 | if self.estimation.len() >= self.required_echoes { 67 | let average: u32 = self.estimation.iter().fold(0, ops::Add::add)/self.estimation.len() as u32; 68 | self.estimation.clear(); 69 | service.handler.roundtrip_estimate(connection_id, average); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/status_translator.rs: -------------------------------------------------------------------------------- 1 | use packets; 2 | use std::collections; 3 | use std::iter::{self, Iterator, IntoIterator}; 4 | use std::net; 5 | use std::convert; 6 | 7 | pub static PROTOCOL_VERSION: &'static str = "1.0"; 8 | pub static SUPPORTED_EXTENSIONS: &'static [&'static str] = &[]; 9 | 10 | pub fn translate(request: &packets::StatusRequest)->packets::StatusResponse { 11 | match *request { 12 | packets::StatusRequest::FastnetQuery => packets::StatusResponse::FastnetResponse(true), 13 | packets::StatusRequest::VersionQuery => packets::StatusResponse::VersionResponse(PROTOCOL_VERSION.to_string()), 14 | packets::StatusRequest::ExtensionQuery(ref name) => { 15 | let mut supported = false; 16 | for i in SUPPORTED_EXTENSIONS { 17 | if i.eq(&name) { 18 | supported = true; 19 | } 20 | } 21 | packets::StatusResponse::ExtensionResponse{name: name.clone(), supported: supported} 22 | } 23 | } 24 | } 25 | --------------------------------------------------------------------------------