├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md ├── libudt4-sys ├── Cargo.toml ├── build.rs ├── lib.rs ├── udt_base.h ├── udt_wrap.cpp └── udt_wrap.h ├── src └── lib.rs └── tests └── test.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libudt4-sys/libudt4"] 2 | path = libudt4-sys/libudt4 3 | url = git://github.com/eminence/udt 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | sudo: false 7 | notifications: 8 | email: false 9 | os: 10 | - linux 11 | - osx 12 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "udt" 3 | version = "0.2.1" 4 | authors = ["Andrew Chin "] 5 | keywords = ["udp", "socket", "udt", "udt4"] 6 | readme = "README.md" 7 | repository = "https://github.com/eminence/udt-rs" 8 | homepage = "https://github.com/eminence/udt-rs" 9 | description = """ 10 | Bindings to udt, a high performance data transfer protocol (based on UDP) 11 | """ 12 | license = "BSD-3-Clause" 13 | edition = "2018" 14 | 15 | [dependencies] 16 | libudt4-sys = {path = "libudt4-sys", version="0.2"} 17 | libc = "0.2" 18 | log = "0.3" 19 | bitflags = "0.7" 20 | 21 | [target.'cfg(windows)'.dependencies] 22 | winapi = "0.2" 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Andrew Chin 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 16 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # udt-rs 2 | 3 | UDT bindings for rust 4 | 5 | # What is UDT? 6 | 7 | See http://udt.sourceforge.net/ 8 | 9 | # Documentation and examples 10 | 11 | In progress, see the [documentation](https://eminence.github.io/udt-rs/doc/udt/index.html) 12 | 13 | # License 14 | 15 | The bindings are distributed under a BSD license. 16 | 17 | UDT is distributed under a BSD license (copyright held by The Board of Trustees of the University of Illinois). See [here](https://github.com/eminence/udt/blob/master/udt4/LICENSE.txt) 18 | 19 | The wrapper is distributed user a BSD license (copyright held by Brave New Software). See [here](https://github.com/eminence/udt-rs/blob/master/libudt4-sys/udt_wrap.cpp) 20 | -------------------------------------------------------------------------------- /libudt4-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "libudt4-sys" 3 | authors = ["Andrew Chin "] 4 | build = "build.rs" 5 | version = "0.2.1" 6 | links = "udt4wrap" 7 | description = "Native bindings to a C wrapper around the UDT library" 8 | license = "BSD-3-Clause" 9 | repository = "https://github.com/eminence/udt-rs" 10 | edition = "2018" 11 | 12 | [lib] 13 | name = "libudt4_sys" 14 | path = "lib.rs" 15 | 16 | [build-dependencies] 17 | cc = "^1.0" 18 | 19 | [dependencies] 20 | libc = "^0.2" 21 | 22 | [target.'cfg(windows)'.dependencies] 23 | winapi = "^0.2" 24 | -------------------------------------------------------------------------------- /libudt4-sys/build.rs: -------------------------------------------------------------------------------- 1 | 2 | 3 | use std::path::PathBuf; 4 | use std::fs::{read_dir}; 5 | 6 | 7 | fn main() { 8 | 9 | let udt4_src = PathBuf::from("libudt4/udt4/src"); 10 | if let Err(_) = std::fs::metadata(&udt4_src) { 11 | panic!("Can't find UDT src dir: {:?}", udt4_src); 12 | } 13 | 14 | let mut cpp_files = Vec::new(); 15 | // get list of .cpp files 16 | for dir in read_dir(&udt4_src).unwrap() { 17 | let path = dir.unwrap().path(); 18 | if let Some(ext) = path.extension() { 19 | if ext == "cpp" { 20 | cpp_files.push(path.clone()); 21 | } 22 | } 23 | } 24 | 25 | // g++ -fPIC -Wall -Wextra -DLINUX -finline-functions -O3 -fno-strict-aliasing -fvisibility=hidden -DAMD64 ccc.cpp -c 26 | let mut cfg = cc::Build::new(); 27 | for file in cpp_files { 28 | cfg.file(file); 29 | } 30 | cfg.include(&udt4_src); 31 | cfg.file("udt_wrap.cpp"); 32 | if cfg!(target_os = "macox") { 33 | cfg.define("osx", None); 34 | } 35 | if cfg!(target_os = "unix") { 36 | cfg.define("LINUX", None) 37 | .define("AMD64", None); 38 | 39 | } 40 | if cfg!(target_os = "windows") { 41 | // These flags were discovered by opening the UDT vcproject file and viewing the 'Command Line' section of the Release Configuration 42 | cfg.flag("/GS") 43 | .flag("/analyze-") 44 | .flag("/Zc:wchar_t") 45 | .flag("/Zi") 46 | .flag("/Zc:inline") 47 | .flag("/fp:precise") 48 | .define("WIN32", None) 49 | .define("NDEBUG", None) 50 | .define("_CONSOLE", None) 51 | .define("UDT_EXPORTS", None) 52 | .define("_WINDLL", None) 53 | .flag("/errorReport:prompt") 54 | //.flag("/WX") 55 | .flag("/Zc:forScope") 56 | .flag("/Gd") 57 | .flag("/O2") // optimize for speed 58 | .flag("/Ot") // favor fast code 59 | .flag("/Ob2") // inline any suitable function 60 | .flag("/Oy") // omit frame pointers 61 | .flag("/nologo") // suppress startup banner 62 | .flag("/W4") // warning level 63 | .flag("/Gm-") // disable minimal rebuild 64 | .flag("/EHsc")// enable c++ exceptions 65 | .flag("/MD"); // multi-threaded DLL runtime 66 | } else { 67 | cfg.flag("-fPIC") 68 | .opt_level(3) 69 | .flag("-Wextra") 70 | .flag("-Wall") 71 | .flag("-finline-functions") 72 | .flag("-fno-strict-aliasing") 73 | .flag("-fvisibility=hidden"); 74 | } 75 | 76 | cfg.debug(false) 77 | .cpp(true) 78 | .compile("libudt4wrap.a"); 79 | 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /libudt4-sys/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate libc; 2 | 3 | use libc::{c_char, c_double, c_int, c_long, c_uchar, c_void}; 4 | 5 | #[cfg(windows)] 6 | extern crate winapi; 7 | 8 | #[cfg(windows)] 9 | mod plat_imports { 10 | pub use winapi::SOCKADDR as sockaddr; 11 | } 12 | #[cfg(not(windows))] 13 | mod plat_imports { 14 | pub use libc::sockaddr; 15 | } 16 | 17 | use plat_imports::*; 18 | 19 | 20 | pub type UDTSOCKET = c_int; 21 | pub type SYSSOCKET = c_int; 22 | 23 | /// success operation. 24 | pub const SUCCESS : c_int = 0; 25 | /// connection setup failure. 26 | pub const ECONNSETUP : c_int = 1000; 27 | /// server does not exist. 28 | pub const ENOSERVER : c_int = 1001; 29 | /// connection request was rejected by server. 30 | pub const ECONNREJ : c_int = 1002; 31 | /// could not create/configure UDP socket. 32 | pub const ESOCKFAIL : c_int = 1003; 33 | /// connection request was aborted due to security reasons. 34 | pub const ESECFAIL : c_int = 1004; 35 | /// connection failure. 36 | pub const ECONNFAIL : c_int = 2000; 37 | /// connection was broken. 38 | pub const ECONNLOST : c_int = 2001; 39 | /// connection does not exist. 40 | pub const ENOCONN : c_int = 2002; 41 | /// system resource failure. 42 | pub const ERESOURCE : c_int = 3000; 43 | /// could not create new thread. 44 | pub const ETHREAD : c_int = 3001; 45 | /// no memory space. 46 | pub const ENOBUF : c_int = 3002; 47 | /// file access error. 48 | pub const EFILE : c_int = 4000; 49 | /// invalid read offset. 50 | pub const EINVRDOFF : c_int = 4001; 51 | /// no read permission. 52 | pub const ERDPERM : c_int = 4002; 53 | /// invalid write offset. 54 | pub const EINVWROFF : c_int = 4003; 55 | /// no write permission. 56 | pub const EWRPERM : c_int = 4004; 57 | /// operation not supported. 58 | pub const EINVOP : c_int = 5000; 59 | /// cannot execute the operation on a bound socket. 60 | pub const EBOUNDSOCK : c_int = 5001; 61 | /// cannot execute the operation on a connected socket. 62 | pub const ECONNSOCK : c_int = 5002; 63 | /// bad parameters. 64 | pub const EINVPARAM : c_int = 5003; 65 | /// invalid UDT socket. 66 | pub const EINVSOCK : c_int = 5004; 67 | /// cannot listen on unbound socket. 68 | pub const EUNBOUNDSOCK : c_int = 5005; 69 | /// (accept) socket is not in listening state. 70 | pub const ENOLISTEN : c_int = 5006; 71 | /// rendezvous connection process does not allow listen and accept call. 72 | pub const ERDVNOSERV : c_int = 5007; 73 | /// rendezvous connection setup is enabled but bind has not been called before connect. 74 | pub const ERDVUNBOUND : c_int = 5008; 75 | /// operation not supported in SOCK_STREAM mode. 76 | pub const ESTREAMILL : c_int = 5009; 77 | /// operation not supported in SOCK_DGRAM mode. 78 | pub const EDGRAMILL : c_int = 5010; 79 | /// another socket is already listening on the same UDP port. 80 | pub const EDUPLISTEN : c_int = 5011; 81 | /// message is too large to be hold in the sending buffer. 82 | pub const ELARGEMSG : c_int = 5012; 83 | /// non-blocking call failure. 84 | pub const EASYNCFAIL : c_int = 6000; 85 | /// no buffer available for sending. 86 | pub const EASYNCSND : c_int = 6001; 87 | /// no data available for read. 88 | pub const EASYNCRCV : c_int = 6002; 89 | /// timeout before operation completes. 90 | pub const ETIMEOUT : c_int = 6003; 91 | /// Error has happened at the peer side. 92 | pub const EPEERERR : c_int = 7000; 93 | 94 | 95 | pub const INVALID_SOCK: c_int = -1; 96 | pub const UDT_ERROR: c_int = -1; 97 | 98 | #[repr(C)] 99 | pub enum EPOLLOpt { 100 | UDT_EPOLL_IN = 0x1, 101 | UDT_EPOLL_OUT = 0x4, 102 | UDT_EPOLL_ERR = 0x8 103 | } 104 | 105 | #[repr(C)] 106 | pub enum UDTOpt { 107 | #[allow(non_camel_case_types)] 108 | UDT_MSS, // the Maximum Transfer Unit 109 | UDT_SNDSYN, // if sending is blocking 110 | UDT_RCVSYN, // if receiving is blocking 111 | UDT_CC, // custom congestion control algorithm 112 | UDT_FC, // Flight flag size (window size) 113 | UDT_SNDBUF, // maximum buffer in sending queue 114 | UDT_RCVBUF, // UDT receiving buffer size 115 | UDT_LINGER, // waiting for unsent data when closing 116 | UDP_SNDBUF, // UDP sending buffer size 117 | UDP_RCVBUF, // UDP receiving buffer size 118 | UDT_MAXMSG, // maximum datagram message size 119 | UDT_MSGTTL, // time-to-live of a datagram message 120 | UDT_RENDEZVOUS, // rendezvous connection mode 121 | UDT_SNDTIMEO, // send() timeout 122 | UDT_RCVTIMEO, // recv() timeout 123 | UDT_REUSEADDR, // reuse an existing port or create a new one 124 | UDT_MAXBW, // maximum bandwidth (bytes per second) that the connection can use 125 | UDT_STATE, // current socket state, see UDTSTATUS, read only 126 | UDT_EVENT, // current avalable events associated with the socket 127 | UDT_SNDDATA, // size of data in the sending buffer 128 | UDT_RCVDATA // size of data available for recv 129 | } 130 | 131 | #[derive(Debug, Clone, Copy, PartialEq)] 132 | #[repr(C)] 133 | pub enum UdtStatus { 134 | INIT = 1, 135 | OPENED, 136 | LISTENING, 137 | CONNECTING, 138 | CONNECTED, 139 | BROKEN, 140 | CLOSING, 141 | CLOSED, 142 | NONEXIST 143 | } 144 | 145 | 146 | pub type SOCKOPT = UDTOpt; 147 | 148 | #[cfg(windows)] 149 | pub type SYS_UDPSOCKET = std::os::windows::io::RawSocket; 150 | #[cfg(not(windows))] 151 | pub type SYS_UDPSOCKET = std::os::unix::io::RawFd; 152 | 153 | #[derive(Debug, Default)] 154 | #[repr(C)] 155 | pub struct PerfMon { 156 | // global measurements 157 | /// time since the UDT entity is started, in milliseconds 158 | pub ms_time_stamp: c_long, 159 | /// total number of sent data packets, including retransmissions 160 | pub pkt_sent_total: c_long, 161 | /// total number of received packets 162 | pub pkt_recv_total: c_long, 163 | /// total number of lost packets (sender side) 164 | pub pkt_snd_loss_total: c_int, 165 | /// total number of lost packets (receiver side) 166 | pub pkt_rcv_loss_total: c_int, 167 | /// total number of retransmitted packets 168 | pub pkt_retrans_total: c_int, 169 | /// total number of sent ACK packets 170 | pub pkt_sent_acktotal: c_int, 171 | /// total number of received ACK packets 172 | pub pkt_recv_acktotal: c_int, 173 | /// total number of sent NAK packets 174 | pub pkt_sent_naktotal: c_int, 175 | /// total number of received NAK packets 176 | pub pkt_recv_naktotal: c_int, 177 | /// total time duration when UDT is sending data (idle time exclusive) 178 | pub us_snd_duration_total: c_long, 179 | /// number of sent data packets, including retransmissions 180 | pub pkt_sent: c_long, 181 | /// number of received packets 182 | pub pkt_recv: c_long, 183 | /// number of lost packets (sender side) 184 | pub pkt_snd_loss: c_int, 185 | /// number of lost packets (receiver side) 186 | pub pkt_rcv_loss: c_int, 187 | /// number of retransmitted packets 188 | pub pkt_retrans: c_int, 189 | /// number of sent ACK packets 190 | pub pkt_sent_ack: c_int, 191 | /// number of received ACK packets 192 | pub pkt_recv_ack: c_int, 193 | /// number of sent NAK packets 194 | pub pkt_sent_nak: c_int, 195 | /// number of received NAK packets 196 | pub pkt_recv_nak: c_int, 197 | /// sending rate in Mb/s 198 | pub mbps_send_rate: c_double, 199 | /// receiving rate in Mb/s 200 | pub mbps_recv_rate: c_double, 201 | /// busy sending time (i.e., idle time exclusive) 202 | pub us_snd_duration: c_long, 203 | /// packet sending period, in microseconds 204 | pub us_pkt_snd_period: c_double, 205 | /// flow window size, in number of packets 206 | pub pkt_flow_window: c_int, 207 | /// congestion window size, in number of packets 208 | pub pkt_congestion_window: c_int, 209 | /// number of packets on flight 210 | pub pkt_flight_size: c_int, 211 | /// RTT, in milliseconds 212 | pub ms_rtt: c_double, 213 | /// estimated bandwidth, in Mb/s 214 | pub mbps_bandwidth: c_double, 215 | /// available UDT sender buffer size 216 | pub byte_avail_snd_buf: c_int, 217 | /// available UDT receiver buffer size 218 | pub byte_avail_rcv_buf: c_int, 219 | } 220 | 221 | extern { 222 | 223 | pub fn udt_startup(); 224 | pub fn udt_cleanup(); 225 | pub fn udt_socket(af: c_int, ty: c_int, protocol: c_int) -> UDTSOCKET; 226 | pub fn udt_bind(u: UDTSOCKET, name: *const sockaddr, namelen: c_int) -> c_int; 227 | pub fn udt_bind2(u: UDTSOCKET, other: SYS_UDPSOCKET) -> c_int; 228 | pub fn udt_listen(u: UDTSOCKET, backlog: c_int) -> c_int; 229 | pub fn udt_accept(u: UDTSOCKET, addr: *mut sockaddr, addrlen: *mut c_int) -> UDTSOCKET; 230 | pub fn udt_connect(u: UDTSOCKET, name: *const sockaddr, namelen: c_int) -> c_int; 231 | pub fn udt_close(u: UDTSOCKET) -> c_int; 232 | pub fn udt_getpeername(u: UDTSOCKET, name: *mut sockaddr, namelen: *mut c_int) -> c_int; 233 | pub fn udt_getsockname(u: UDTSOCKET, name: *mut sockaddr, namelen: *mut c_int) -> c_int; 234 | pub fn udt_getsockopt(u: UDTSOCKET, level: c_int, optname: SOCKOPT, optval: *mut c_void, optlen: *mut c_int) -> c_int; 235 | pub fn udt_setsockopt(u: UDTSOCKET, level: c_int, optname: SOCKOPT, optval: *const c_void, openlen: c_int) -> c_int; 236 | 237 | pub fn udt_send(u: UDTSOCKET, buf: *const c_uchar, len: c_int, flags: c_int) -> c_int; 238 | pub fn udt_sendmsg(U: UDTSOCKET, buf: *const c_uchar, len: c_int, ttl: c_int, inorder: c_int) -> c_int; 239 | 240 | pub fn udt_recv(u: UDTSOCKET, buf: *mut c_uchar, len: c_int, flags: c_int) -> c_int; 241 | pub fn udt_recvmsg(u: UDTSOCKET, but: *mut c_uchar, len: c_int) -> c_int; 242 | 243 | pub fn udt_epoll_create() -> c_int; 244 | pub fn udt_epoll_add_usock(eid: c_int, usock: UDTSOCKET, events: *const c_int) -> c_int; 245 | pub fn udt_epoll_add_ssock(eid: c_int, ssock: SYSSOCKET, events: *const c_int) -> c_int; 246 | 247 | pub fn udt_epoll_remove_usock(eid: c_int, usock: UDTSOCKET) -> c_int; 248 | pub fn udt_epoll_remove_ssock(eid: c_int, ssock: SYSSOCKET) -> c_int; 249 | 250 | pub fn udt_epoll_wait2(eid: c_int, readfs: *mut UDTSOCKET, rnum: *mut c_int, writefs: *mut UDTSOCKET, wnum: *mut c_int, msTimeOut: i64, 251 | lrfds: *mut SYSSOCKET, lrnum: *mut c_int, lwfds: *mut SYSSOCKET, lwnum: *mut c_int) -> c_int; 252 | pub fn udt_epoll_release(eid: c_int) -> c_int; 253 | 254 | pub fn udt_getsockstate(u: UDTSOCKET) -> UdtStatus; 255 | 256 | 257 | pub fn udt_getlasterror_code() -> c_int; 258 | pub fn udt_getlasterror_desc() -> *const c_char; 259 | 260 | pub fn udt_perfmon(u: UDTSOCKET, perf: &mut PerfMon, clear: c_int) -> c_int; 261 | 262 | } 263 | 264 | 265 | #[test] 266 | fn smoke() { 267 | unsafe { 268 | udt_startup(); 269 | udt_cleanup(); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /libudt4-sys/udt_base.h: -------------------------------------------------------------------------------- 1 | #ifndef __UDT_BASE_H__ 2 | #define __UDT_BASE_H__ 3 | 4 | #ifndef WIN32 5 | #include 6 | #include 7 | #include 8 | #else 9 | #ifdef __MINGW__ 10 | #include 11 | #include 12 | #endif 13 | #include 14 | #endif 15 | 16 | #ifdef WIN32 17 | #ifndef __MINGW__ 18 | // Explicitly define 32-bit and 64-bit numbers 19 | typedef __int32 int32_t; 20 | typedef __int64 int64_t; 21 | typedef unsigned __int32 uint32_t; 22 | #ifndef LEGACY_WIN32 23 | typedef unsigned __int64 uint64_t; 24 | #else 25 | // VC 6.0 does not support unsigned __int64: may cause potential problems. 26 | typedef __int64 uint64_t; 27 | #endif 28 | 29 | #ifdef UDT_EXPORTS 30 | #define UDT_API __declspec(dllexport) 31 | #else 32 | #define UDT_API __declspec(dllimport) 33 | #endif 34 | #else 35 | #define UDT_API 36 | #endif 37 | #else 38 | //#define UDT_API __attribute__ ((visibility("default"))) 39 | #define UDT_API // to make SWIG happy 40 | #endif 41 | 42 | #define NO_BUSY_WAITING 43 | 44 | #ifdef WIN32 45 | #ifndef __MINGW__ 46 | typedef SOCKET SYSSOCKET; 47 | #else 48 | typedef int SYSSOCKET; 49 | #endif 50 | #else 51 | typedef int SYSSOCKET; 52 | #endif 53 | 54 | typedef SYSSOCKET UDPSOCKET; 55 | typedef int UDTSOCKET; 56 | 57 | //////////////////////////////////////////////////////////////////////////////// 58 | 59 | enum EPOLLOpt 60 | { 61 | // this values are defined same as linux epoll.h 62 | // so that if system values are used by mistake, they should have the same effect 63 | UDT_EPOLL_IN = 0x1, 64 | UDT_EPOLL_OUT = 0x4, 65 | UDT_EPOLL_ERR = 0x8 66 | }; 67 | 68 | enum UDTSTATUS {INIT = 1, OPENED, LISTENING, CONNECTING, CONNECTED, BROKEN, CLOSING, CLOSED, NONEXIST}; 69 | 70 | //////////////////////////////////////////////////////////////////////////////// 71 | 72 | enum UDTOpt 73 | { 74 | UDT_MSS, // the Maximum Transfer Unit 75 | UDT_SNDSYN, // if sending is blocking 76 | UDT_RCVSYN, // if receiving is blocking 77 | UDT_CC, // custom congestion control algorithm 78 | UDT_FC, // Flight flag size (window size) 79 | UDT_SNDBUF, // maximum buffer in sending queue 80 | UDT_RCVBUF, // UDT receiving buffer size 81 | UDT_LINGER, // waiting for unsent data when closing 82 | UDP_SNDBUF, // UDP sending buffer size 83 | UDP_RCVBUF, // UDP receiving buffer size 84 | UDT_MAXMSG, // maximum datagram message size 85 | UDT_MSGTTL, // time-to-live of a datagram message 86 | UDT_RENDEZVOUS, // rendezvous connection mode 87 | UDT_SNDTIMEO, // send() timeout 88 | UDT_RCVTIMEO, // recv() timeout 89 | UDT_REUSEADDR, // reuse an existing port or create a new one 90 | UDT_MAXBW, // maximum bandwidth (bytes per second) that the connection can use 91 | UDT_STATE, // current socket state, see UDTSTATUS, read only 92 | UDT_EVENT, // current avalable events associated with the socket 93 | UDT_SNDDATA, // size of data in the sending buffer 94 | UDT_RCVDATA // size of data available for recv 95 | }; 96 | 97 | //////////////////////////////////////////////////////////////////////////////// 98 | 99 | struct CPerfMon 100 | { 101 | // global measurements 102 | int64_t msTimeStamp; // time since the UDT entity is started, in milliseconds 103 | int64_t pktSentTotal; // total number of sent data packets, including retransmissions 104 | int64_t pktRecvTotal; // total number of received packets 105 | int pktSndLossTotal; // total number of lost packets (sender side) 106 | int pktRcvLossTotal; // total number of lost packets (receiver side) 107 | int pktRetransTotal; // total number of retransmitted packets 108 | int pktSentACKTotal; // total number of sent ACK packets 109 | int pktRecvACKTotal; // total number of received ACK packets 110 | int pktSentNAKTotal; // total number of sent NAK packets 111 | int pktRecvNAKTotal; // total number of received NAK packets 112 | int64_t usSndDurationTotal; // total time duration when UDT is sending data (idle time exclusive) 113 | 114 | // local measurements 115 | int64_t pktSent; // number of sent data packets, including retransmissions 116 | int64_t pktRecv; // number of received packets 117 | int pktSndLoss; // number of lost packets (sender side) 118 | int pktRcvLoss; // number of lost packets (receiver side) 119 | int pktRetrans; // number of retransmitted packets 120 | int pktSentACK; // number of sent ACK packets 121 | int pktRecvACK; // number of received ACK packets 122 | int pktSentNAK; // number of sent NAK packets 123 | int pktRecvNAK; // number of received NAK packets 124 | double mbpsSendRate; // sending rate in Mb/s 125 | double mbpsRecvRate; // receiving rate in Mb/s 126 | int64_t usSndDuration; // busy sending time (i.e., idle time exclusive) 127 | 128 | // instant measurements 129 | double usPktSndPeriod; // packet sending period, in microseconds 130 | int pktFlowWindow; // flow window size, in number of packets 131 | int pktCongestionWindow; // congestion window size, in number of packets 132 | int pktFlightSize; // number of packets on flight 133 | double msRTT; // RTT, in milliseconds 134 | double mbpsBandwidth; // estimated bandwidth, in Mb/s 135 | int byteAvailSndBuf; // available UDT sender buffer size 136 | int byteAvailRcvBuf; // available UDT receiver buffer size 137 | }; 138 | 139 | typedef enum UDTOpt SOCKOPT; 140 | typedef struct CPerfMon TRACEINFO; 141 | 142 | UDT_API extern const UDTSOCKET INVALID_SOCK; 143 | #undef ERROR 144 | UDT_API extern const int ERROR; 145 | 146 | #endif -------------------------------------------------------------------------------- /libudt4-sys/udt_wrap.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2014, Brave New Software 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the 14 | above copyright notice, this list of conditions 15 | and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the University of Illinois 19 | nor the names of its contributors may be used to 20 | endorse or promote products derived from this 21 | software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 27 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | *****************************************************************************/ 35 | 36 | #include "udt.h" 37 | #include "udt_wrap.h" 38 | 39 | int udt_startup() 40 | { 41 | return UDT::startup(); 42 | } 43 | 44 | int udt_cleanup() 45 | { 46 | return UDT::cleanup(); 47 | } 48 | 49 | UDTSOCKET udt_socket(int af, int type, int protocol) 50 | { 51 | return UDT::socket(af, type, protocol); 52 | } 53 | 54 | int udt_bind(UDTSOCKET u, const struct sockaddr* name, int namelen) 55 | { 56 | return UDT::bind(u, name, namelen); 57 | } 58 | 59 | int udt_bind2(UDTSOCKET u, UDPSOCKET udpsock) 60 | { 61 | return UDT::bind2(u, udpsock); 62 | } 63 | 64 | int udt_listen(UDTSOCKET u, int backlog) 65 | { 66 | return UDT::listen(u, backlog); 67 | } 68 | 69 | UDTSOCKET udt_accept(UDTSOCKET u, struct sockaddr* addr, int* addrlen) 70 | { 71 | return UDT::accept(u, addr, addrlen); 72 | } 73 | 74 | int udt_connect(UDTSOCKET u, const struct sockaddr* name, int namelen) 75 | { 76 | return UDT::connect(u, name, namelen); 77 | } 78 | 79 | int udt_close(UDTSOCKET u) 80 | { 81 | return UDT::close(u); 82 | } 83 | 84 | int udt_getpeername(UDTSOCKET u, struct sockaddr* name, int* namelen) 85 | { 86 | return UDT::getpeername(u, name, namelen); 87 | } 88 | 89 | int udt_getsockname(UDTSOCKET u, struct sockaddr* name, int* namelen) 90 | { 91 | return UDT::getsockname(u, name, namelen); 92 | } 93 | 94 | int udt_getsockopt(UDTSOCKET u, int level, SOCKOPT optname, void* optval, int* optlen) 95 | { 96 | return UDT::getsockopt(u, level, optname, optval, optlen); 97 | } 98 | 99 | int udt_setsockopt(UDTSOCKET u, int level, SOCKOPT optname, const void* optval, int optlen) 100 | { 101 | return UDT::setsockopt(u, level, optname, optval, optlen); 102 | } 103 | 104 | int udt_send(UDTSOCKET u, const char* buf, int len, int flags) 105 | { 106 | return UDT::send(u, buf, len, flags); 107 | } 108 | 109 | int udt_recv(UDTSOCKET u, char* buf, int len, int flags) 110 | { 111 | return UDT::recv(u, buf, len, flags); 112 | } 113 | 114 | int udt_sendmsg(UDTSOCKET u, const char* buf, int len, int ttl, int inorder) 115 | { 116 | return UDT::sendmsg(u, buf, len, ttl, inorder == 1); 117 | } 118 | 119 | int udt_recvmsg(UDTSOCKET u, char* buf, int len) 120 | { 121 | return UDT::recvmsg(u, buf, len); 122 | } 123 | 124 | int64_t udt_sendfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block) 125 | { 126 | return UDT::sendfile2(u, path, offset, size, block); 127 | } 128 | 129 | int64_t udt_recvfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block) 130 | { 131 | return UDT::recvfile2(u, path, offset, size, block); 132 | } 133 | 134 | int udt_epoll_create() 135 | { 136 | return UDT::epoll_create(); 137 | } 138 | 139 | int udt_epoll_add_usock(int eid, UDTSOCKET u, const int* events) 140 | { 141 | return UDT::epoll_add_usock(eid, u, events); 142 | } 143 | 144 | int udt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events) 145 | { 146 | return UDT::epoll_add_ssock(eid, s, events); 147 | } 148 | 149 | int udt_epoll_remove_usock(int eid, UDTSOCKET u) 150 | { 151 | return UDT::epoll_remove_usock(eid, u); 152 | } 153 | 154 | int udt_epoll_remove_ssock(int eid, SYSSOCKET s) 155 | { 156 | return UDT::epoll_remove_ssock(eid, s); 157 | } 158 | 159 | int udt_epoll_wait2(int eid, UDTSOCKET* readfds, int* rnum, UDTSOCKET* writefds, int* wnum, int64_t msTimeOut, 160 | SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum) 161 | { 162 | return UDT::epoll_wait2(eid, readfds, rnum, writefds, wnum, msTimeOut, lrfds, lrnum, lwfds, lwnum); 163 | } 164 | 165 | int udt_epoll_release(int eid) 166 | { 167 | return UDT::epoll_release(eid); 168 | } 169 | 170 | int udt_getlasterror_code() 171 | { 172 | return UDT::getlasterror_code(); 173 | } 174 | 175 | const char* udt_getlasterror_desc() 176 | { 177 | return UDT::getlasterror_desc(); 178 | } 179 | 180 | int udt_perfmon(UDTSOCKET u, TRACEINFO* perf, int clear) 181 | { 182 | return UDT::perfmon(u, perf, clear == 1); 183 | } 184 | 185 | UDTSTATUS udt_getsockstate(UDTSOCKET u) 186 | { 187 | return UDT::getsockstate(u); 188 | } 189 | -------------------------------------------------------------------------------- /libudt4-sys/udt_wrap.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2014, Brave New Software 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the 14 | above copyright notice, this list of conditions 15 | and the following disclaimer in the documentation 16 | and/or other materials provided with the distribution. 17 | 18 | * Neither the name of the University of Illinois 19 | nor the names of its contributors may be used to 20 | endorse or promote products derived from this 21 | software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 24 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 27 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | *****************************************************************************/ 35 | 36 | // udt_wrap.h defines wrappers around the udt c++ functions that are callable 37 | // from C 38 | 39 | #ifndef __UDT_WRAP_H__ 40 | #define __UDT_WRAP_H__ 41 | 42 | typedef CUDTException ERRORINFO; 43 | typedef UDTOpt SOCKOPT; 44 | typedef CPerfMon TRACEINFO; 45 | typedef ud_set UDSET; 46 | 47 | // We have to redefine htons for use in Go for some reason 48 | // extern "C" uint16_t _htons(uint16_t hostshort); 49 | 50 | extern "C" int udt_startup(); 51 | extern "C" int udt_cleanup(); 52 | extern "C" UDTSOCKET udt_socket(int af, int type, int protocol); 53 | extern "C" int udt_bind(UDTSOCKET u, const struct sockaddr* name, int namelen); 54 | extern "C" int udt_bind2(UDTSOCKET u, UDPSOCKET udpsock); 55 | extern "C" int udt_listen(UDTSOCKET u, int backlog); 56 | extern "C" UDTSOCKET udt_accept(UDTSOCKET u, struct sockaddr* addr, int* addrlen); 57 | extern "C" int udt_connect(UDTSOCKET u, const struct sockaddr* name, int namelen); 58 | extern "C" int udt_close(UDTSOCKET u); 59 | extern "C" int udt_getpeername(UDTSOCKET u, struct sockaddr* name, int* namelen); 60 | extern "C" int udt_getsockname(UDTSOCKET u, struct sockaddr* name, int* namelen); 61 | extern "C" int udt_getsockopt(UDTSOCKET u, int level, SOCKOPT optname, void* optval, int* optlen); 62 | extern "C" int udt_setsockopt(UDTSOCKET u, int level, SOCKOPT optname, const void* optval, int optlen); 63 | extern "C" int udt_send(UDTSOCKET u, const char* buf, int len, int flags); 64 | extern "C" int udt_recv(UDTSOCKET u, char* buf, int len, int flags); 65 | extern "C" int udt_sendmsg(UDTSOCKET u, const char* buf, int len, int ttl, int inorder); 66 | extern "C" int udt_recvmsg(UDTSOCKET u, char* buf, int len); 67 | extern "C" int64_t udt_sendfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block); 68 | extern "C" int64_t udt_recvfile2(UDTSOCKET u, const char* path, int64_t* offset, int64_t size, int block); 69 | 70 | extern "C" int udt_epoll_create(); 71 | extern "C" int udt_epoll_add_usock(int eid, UDTSOCKET u, const int* events); 72 | extern "C" int udt_epoll_add_ssock(int eid, SYSSOCKET s, const int* events); 73 | extern "C" int udt_epoll_remove_usock(int eid, UDTSOCKET u); 74 | extern "C" int udt_epoll_remove_ssock(int eid, SYSSOCKET s); 75 | extern "C" int udt_epoll_wait2(int eid, UDTSOCKET* readfds, int* rnum, UDTSOCKET* writefds, int* wnum, int64_t msTimeOut, 76 | SYSSOCKET* lrfds, int* lrnum, SYSSOCKET* lwfds, int* lwnum); 77 | extern "C" int udt_epoll_release(int eid); 78 | extern "C" int udt_getlasterror_code(); 79 | extern "C" const char* udt_getlasterror_desc(); 80 | extern "C" int udt_perfmon(UDTSOCKET u, TRACEINFO* perf, int clear); 81 | extern "C" enum UDTSTATUS udt_getsockstate(UDTSOCKET u); 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! *Note about these docs* 2 | //! 3 | //! These docs are mostly copied verbatim from the UDT documentation. If you see references to the 4 | //! C++ function names instead of the rust function names, that's why. 5 | //! 6 | //! # UDT 7 | //! Bindings to the UDT4 high performance data data transfer library 8 | //! 9 | //! UDT follows closely the BSD socket API, but several of the functions have different semantics. 10 | //! 11 | //! UDT is a high performance data transfer protocol - UDP-based data transfer protocol. It was 12 | //! designed for data intensive applications over high speed wide area networks, to overcome the 13 | //! efficiency and fairness problems of TCP. As its name indicates, UDT is built on top of UDP and 14 | //! it provides both reliable data streaming and messaging services. 15 | //! 16 | //! 17 | //! # Examples 18 | //! 19 | //! To create a Datagram server, that can send and receive messages: 20 | //! 21 | //! ``` no_run 22 | //! use std::str::FromStr; 23 | //! use std::net::{SocketAddr, SocketAddrV4}; 24 | //! use udt::*; 25 | //! 26 | //! let localhost = std::net::Ipv4Addr::from_str("127.0.0.1").unwrap(); 27 | //! 28 | //! let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 29 | //! sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))).unwrap(); 30 | //! let my_addr = sock.getsockname().unwrap(); 31 | //! println!("Server bound to {:?}", my_addr); 32 | //! sock.listen(5).unwrap(); 33 | //! let (mut new_socket, peer) = sock.accept().unwrap(); 34 | //! println!("Received new connection from peer {:?}", peer); 35 | //! 36 | //! 37 | //! ``` 38 | //! 39 | //! 40 | 41 | #[macro_use] 42 | extern crate log; 43 | #[macro_use] 44 | extern crate bitflags; 45 | extern crate libudt4_sys as raw; 46 | #[cfg(windows)] 47 | extern crate winapi; 48 | 49 | use std::sync::{Once, ONCE_INIT}; 50 | extern crate libc; 51 | 52 | use libc::c_int; 53 | use std::ffi::CStr; 54 | use std::mem::size_of; 55 | use std::net::SocketAddr; 56 | use std::net::SocketAddrV4; 57 | 58 | #[cfg(windows)] 59 | #[macro_use] 60 | mod _plat_specifics { 61 | pub use winapi::IN_ADDR as in_addr; 62 | pub use winapi::SOCKADDR as sockaddr; 63 | pub use winapi::SOCKADDR_IN as sockaddr_in; 64 | pub use winapi::{AF_INET, AF_INET6}; 65 | pub use winapi::{SOCK_DGRAM, SOCK_STREAM}; 66 | pub fn get_udpsock_fd(a: ::std::net::UdpSocket) -> ::std::os::windows::io::RawSocket { 67 | use ::std::os::windows::io::IntoRawSocket; 68 | a.into_raw_socket() 69 | } 70 | macro_rules! s_addr { 71 | ($x:expr) => { 72 | $x.S_un 73 | }; 74 | } 75 | } 76 | #[cfg(not(windows))] 77 | #[macro_use] 78 | mod _plat_specifics { 79 | pub use libc::{in_addr, sockaddr, sockaddr_in}; 80 | pub use libc::{AF_INET, AF_INET6}; 81 | pub use libc::{SOCK_DGRAM, SOCK_STREAM}; 82 | pub fn get_udpsock_fd(a: ::std::net::UdpSocket) -> ::std::os::unix::io::RawFd { 83 | use ::std::os::unix::io::IntoRawFd; 84 | a.into_raw_fd() 85 | } 86 | macro_rules! s_addr { 87 | ($x:expr) => { 88 | $x.s_addr 89 | }; 90 | } 91 | } 92 | use _plat_specifics::*; 93 | 94 | pub use raw::UdtStatus; 95 | 96 | bitflags! { 97 | /// This is a bitflag field that can be constructed with `UDT_EPOLL_IN`, `UDT_EPOLL_OUT`, or 98 | /// `UDT_EPOLL_ERR` 99 | /// 100 | /// Example: 101 | /// 102 | /// ``` 103 | /// # use udt::*; 104 | /// let mut events = EpollEvents::all(); 105 | /// events.remove(UDT_EPOLL_ERR); 106 | /// assert!(events.contains(UDT_EPOLL_OUT)); 107 | /// assert!(! events.contains(UDT_EPOLL_ERR)); 108 | /// ``` 109 | pub flags EpollEvents: c_int { 110 | /// An Epoll Event to watch for read events 111 | const UDT_EPOLL_IN = 0x1, 112 | /// An Epoll Event to watch for write events 113 | const UDT_EPOLL_OUT = 0x4, 114 | /// An Epoll Event to watch for exception events 115 | const UDT_EPOLL_ERR = 0x8 116 | } 117 | } 118 | 119 | // makes defining the UdtOpts mod a little less messy 120 | macro_rules! impl_udt_opt { 121 | ($(#[$doc:meta])* 122 | impl $name:ident: $ty:ty) => { 123 | $(#[$doc])* 124 | pub struct $name; 125 | impl crate::UdtOption<$ty> for $name { 126 | fn get_type(&self) -> ::raw::UDTOpt { ::raw::UDTOpt::$name } 127 | } 128 | }; 129 | } 130 | 131 | /// Initialize the UDT library. 132 | /// 133 | /// In particular, starts the background garbage collection thread. 134 | /// 135 | /// It is safe to call this function multiple times. A corresponding cleanup function will 136 | /// automatically be called when the program exists. 137 | pub fn init() { 138 | static INIT: Once = ONCE_INIT; 139 | INIT.call_once(|| unsafe { 140 | trace!("did INIT"); 141 | raw::udt_startup(); 142 | assert_eq!(libc::atexit(shutdown), 0); 143 | }); 144 | extern "C" fn shutdown() { 145 | unsafe { 146 | raw::udt_cleanup(); 147 | }; 148 | } 149 | } 150 | 151 | /// A UDT Socket 152 | /// 153 | /// Internally, a UDT socket is represented as a 32-bit int. As such, a `UdtSocket` can be copied 154 | /// and cloned 155 | #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] 156 | pub struct UdtSocket { 157 | _sock: raw::UDTSOCKET, 158 | } 159 | 160 | /// A UDT Error 161 | #[derive(Debug)] 162 | pub struct UdtError { 163 | /// The numeric error code may be one of the constants in the [`libudt4-sys`][1] crate 164 | /// 165 | /// [1]: ../libudt4_sys/index.html 166 | pub err_code: i32, 167 | /// A textual description of the error 168 | pub err_msg: String, 169 | } 170 | 171 | pub trait UdtOption { 172 | fn get_type(&self) -> raw::UDTOpt; 173 | } 174 | 175 | #[repr(C)] 176 | /// Linger option 177 | pub struct Linger { 178 | /// Nonzero to linger on close 179 | pub onoff: i32, 180 | /// Time to longer 181 | pub linger: i32, 182 | } 183 | 184 | #[allow(non_camel_case_types)] 185 | #[allow(non_snake_case)] 186 | pub mod UdtOpts { 187 | //! Various options that can be passed to `getsockopt` or `setsockopt` 188 | //! 189 | //! These are typed in such a way so that when they are used with `getsockopt` or `setsockopt`, 190 | //! they will require the right data type. 191 | //! 192 | //! # Examples 193 | //! 194 | //! ``` 195 | //! use udt::*; 196 | //! 197 | //! let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 198 | //! let recv_buf: i32 = sock.getsockopt(UdtOpts::UDT_RCVBUF).unwrap(); 199 | //! let rendezvous: bool = sock.getsockopt(UdtOpts::UDT_RENDEZVOUS).unwrap(); 200 | //! 201 | //! ``` 202 | //! 203 | 204 | impl_udt_opt! { 205 | /// Maximum Packet size (bytes) 206 | /// 207 | /// Including all UDT, UDP, and IP headers. Default 1500 bytes 208 | impl UDT_MSS: i32 209 | } 210 | 211 | impl_udt_opt! { 212 | /// Synchronization mode of data sending 213 | /// 214 | /// True for blocking sending; false for non-blocking sending. Default true 215 | impl UDT_SNDSYN: bool 216 | } 217 | 218 | impl_udt_opt! { 219 | /// Synchronization mode for receiving. 220 | /// 221 | /// true for blocking receiving; false for non-blocking 222 | /// receiving. Default true. 223 | impl UDT_RCVSYN: bool 224 | } 225 | 226 | // MISSING: UDT_CC for custom congestion control 227 | 228 | impl_udt_opt! { 229 | ///Maximum window size (packets) 230 | /// 231 | ///Default 25600. Do NOT change this unless you know what you are doing. Must change this 232 | ///before modifying the buffer sizes. 233 | impl UDT_FC: i32 234 | } 235 | 236 | impl_udt_opt!( 237 | /// UDT sender buffer size limit (bytes) 238 | /// 239 | /// Default 10MB (10240000). 240 | impl UDT_SNDBUF: i32); 241 | 242 | impl_udt_opt!( 243 | /// UDT receiver buffer size limit (bytes) 244 | /// 245 | /// Default 10MB (10240000). 246 | impl UDT_RCVBUF: i32); 247 | 248 | impl_udt_opt!(///UDP socket sender buffer size (bytes) 249 | /// 250 | /// Default 1MB (1024000). 251 | impl UDP_SNDBUF: i32); 252 | impl_udt_opt!(/// UDP socket receiver buffer size (bytes) 253 | /// 254 | /// Default 1MB (1024000). 255 | impl UDP_RCVBUF: i32); 256 | impl_udt_opt!(/// Linger time on close(). 257 | /// 258 | /// Default 180 seconds. 259 | impl UDT_LINGER: crate::Linger); 260 | impl_udt_opt!(/// Rendezvous connection setup. 261 | /// 262 | /// Default false (no rendezvous mode). 263 | impl UDT_RENDEZVOUS: bool); 264 | impl_udt_opt!(/// Sending call timeout (milliseconds). 265 | /// 266 | /// Default -1 (infinite). 267 | impl UDT_SNDTIMEO: i32); 268 | impl_udt_opt!(/// Receiving call timeout (milliseconds). 269 | /// 270 | /// Default -1 (infinite). 271 | impl UDT_RCVTIMEO: i32); 272 | impl_udt_opt!(/// Reuse an existing address or create a new one. 273 | /// 274 | /// Default true (reuse). 275 | impl UDT_REUSEADDR: bool); 276 | impl_udt_opt!(/// Maximum bandwidth that one single UDT connection can use (bytes per second). 277 | /// 278 | /// Default -1 (no upper limit). 279 | impl UDT_MAXBW: i64); 280 | impl_udt_opt!(/// Current status of the UDT socket. Read only. 281 | impl UDT_STATE: i32); 282 | impl_udt_opt!(/// The EPOLL events available to this socket. Read only. 283 | impl UDT_EVENT: i32); 284 | impl_udt_opt!(/// Size of pending data in the sending buffer. Read only. 285 | impl UDT_SNDDATA: i32); 286 | impl_udt_opt!(/// Size of data available to read, in the receiving buffer. Read only. 287 | impl UDT_RCVDATA: i32); 288 | 289 | } 290 | 291 | fn get_last_err() -> UdtError { 292 | let msg = unsafe { CStr::from_ptr(raw::udt_getlasterror_desc()) }; 293 | UdtError { 294 | err_code: unsafe { raw::udt_getlasterror_code() as i32 }, 295 | err_msg: String::from_utf8_lossy(msg.to_bytes()).into_owned(), 296 | } 297 | } 298 | 299 | #[repr(C)] 300 | pub enum SocketFamily { 301 | /// IPv4 302 | AFInet, 303 | /// IPV6 304 | AFInet6, 305 | } 306 | 307 | impl SocketFamily { 308 | fn get_val(&self) -> c_int { 309 | match *self { 310 | SocketFamily::AFInet => AF_INET, 311 | SocketFamily::AFInet6 => AF_INET6, 312 | } 313 | } 314 | } 315 | 316 | /// Socket type 317 | /// 318 | /// When a UDT socket is created as a Datagram type, UDT will send and receive data as messages. 319 | /// The boundary of the message is preserved and the message is delivered as a whole unit. Sending 320 | /// or receving messages do not need a loop; a message will be either completely delivered or not 321 | /// delivered at all. However, at the receiver side, if the user buffer is shorter than the message 322 | /// length, only part of the message will be copied into the user buffer while the message will 323 | /// still be discarded. 324 | /// 325 | /// 326 | #[repr(C)] 327 | pub enum SocketType { 328 | /// A socket type that supports data streaming 329 | Stream = SOCK_STREAM as isize, 330 | /// A socket type for messaging 331 | /// 332 | /// Note that UDT Datagram sockets are also connection oriented. A UDT connection can only be 333 | /// set up between the same socket types 334 | Datagram = SOCK_DGRAM as isize, 335 | } 336 | 337 | impl SocketType { 338 | fn get_val(&self) -> c_int { 339 | match *self { 340 | SocketType::Stream => SOCK_STREAM, 341 | SocketType::Datagram => SOCK_DGRAM, 342 | } 343 | } 344 | } 345 | 346 | 347 | // SocketAddr to sockaddr_in 348 | #[cfg(target_os = "linux")] 349 | fn get_sockaddr(name: SocketAddr) -> sockaddr_in { 350 | if let SocketAddr::V4(v4) = name { 351 | trace!("binding to {:?}", v4); 352 | let addr_bytes = v4.ip().octets(); 353 | let addr_b: u32 = ((addr_bytes[3] as u32) << 24) 354 | + ((addr_bytes[2] as u32) << 16) 355 | + ((addr_bytes[1] as u32) << 8) 356 | + (addr_bytes[0] as u32); 357 | // construct a sockaddr_in 358 | sockaddr_in { 359 | sin_family: AF_INET as u16, 360 | sin_port: v4.port().to_be(), 361 | sin_addr: in_addr { s_addr: addr_b }, 362 | sin_zero: [0; 8], 363 | } 364 | } else { 365 | panic!("ipv6 not implemented (yet) in this binding"); 366 | } 367 | } 368 | 369 | #[cfg(target_os = "windows")] 370 | fn get_sockaddr(name: SocketAddr) -> sockaddr_in { 371 | if let SocketAddr::V4(v4) = name { 372 | trace!("binding to {:?}", v4); 373 | let addr_bytes = v4.ip().octets(); 374 | let addr_b: u32 = ((addr_bytes[3] as u32) << 24) 375 | + ((addr_bytes[2] as u32) << 16) 376 | + ((addr_bytes[1] as u32) << 8) 377 | + (addr_bytes[0] as u32); 378 | // construct a sockaddr_in 379 | sockaddr_in { 380 | sin_family: AF_INET as u16, 381 | sin_port: v4.port().to_be(), 382 | sin_addr: in_addr { S_un: addr_b }, 383 | sin_zero: [0; 8], 384 | } 385 | } else { 386 | panic!("ipv6 not implemented (yet) in this binding"); 387 | } 388 | } 389 | 390 | #[cfg(any(target_os = "macos",target_os = "freebsd"))] 391 | fn get_sockaddr(name: SocketAddr) -> sockaddr_in { 392 | if let SocketAddr::V4(v4) = name { 393 | trace!("binding to {:?}", v4); 394 | let addr_bytes = v4.ip().octets(); 395 | let addr_b: u32 = ((addr_bytes[3] as u32) << 24) 396 | + ((addr_bytes[2] as u32) << 16) 397 | + ((addr_bytes[1] as u32) << 8) 398 | + (addr_bytes[0] as u32); 399 | // construct a sockaddr_in 400 | sockaddr_in { 401 | sin_len: std::mem::size_of::() as u8, 402 | sin_family: AF_INET as u8, 403 | sin_port: v4.port().to_be(), 404 | sin_addr: in_addr { s_addr: addr_b }, 405 | sin_zero: [0; 8], 406 | } 407 | } else { 408 | panic!("ipv6 not implemented (yet) in this binding"); 409 | } 410 | } 411 | 412 | // sockaddr_to_SocketAddr 413 | fn sockaddr_to_socketaddr(s: sockaddr) -> SocketAddr { 414 | let fam: i32 = s.sa_family as i32; 415 | 416 | match fam { 417 | AF_INET => { 418 | let name1: sockaddr_in = unsafe { std::mem::transmute(s) }; 419 | let ip: u32 = s_addr!(name1.sin_addr); 420 | let d: u8 = ((ip & 0xff000000) >> 24) as u8; 421 | let c: u8 = ((ip & 0xff0000) >> 16) as u8; 422 | let b: u8 = ((ip & 0xff00) >> 8) as u8; 423 | let a: u8 = (ip & 0xff) as u8; 424 | SocketAddr::V4(SocketAddrV4::new( 425 | std::net::Ipv4Addr::new(a, b, c, d), 426 | u16::from_be(name1.sin_port), 427 | )) 428 | } 429 | AF_INET6 => panic!("ipv6 not yet implemented"), 430 | _ => panic!("unknown family type"), 431 | } 432 | } 433 | 434 | impl UdtSocket { 435 | fn wrap_raw(u: raw::UDTSOCKET) -> UdtSocket { 436 | UdtSocket { _sock: u } 437 | } 438 | 439 | /// Creates a new UDT Socket. 440 | /// 441 | /// Creates a new socket. There is no limits for the number of UDT sockets in one system, as 442 | /// long as there is enough system resources. UDT supports both IPv4 and IPv6, which can be 443 | /// selected by the `address_family` parameter. 444 | /// 445 | /// Two socket types are supported in UDT: Stream for data streaming and Datagram for 446 | /// messaging. Note that UDT sockets are connection oriented in all cases. 447 | /// 448 | pub fn new(address_family: SocketFamily, ty: SocketType) -> Result { 449 | let fd = unsafe { raw::udt_socket(address_family.get_val(), ty.get_val(), 0) }; 450 | if fd == raw::INVALID_SOCK { 451 | Err(get_last_err()) 452 | } else { 453 | Ok(UdtSocket { _sock: fd }) 454 | } 455 | } 456 | 457 | /// Binds a UDT socket to a known or an available local address. 458 | /// 459 | /// The bind method is usually to assign a UDT socket a local address, including IP address and 460 | /// port number. If INADDR_ANY is used, a proper IP address will be used once the UDT 461 | /// connection is set up. If 0 is used for the port, a randomly available port number will be 462 | /// used. The method getsockname can be used to retrieve this port number. 463 | /// 464 | /// The bind call is necessary in all cases except for a socket to listen. If bind is not 465 | /// called, UDT will automatically bind a socket to a randomly available address when a 466 | /// connection is set up. 467 | /// 468 | /// By default, UDT allows to reuse existing UDP port for new UDT sockets, unless UDT_REUSEADDR 469 | /// is set to false. When UDT_REUSEADDR is false, UDT will create an exclusive UDP port for 470 | /// this UDT socket. UDT_REUSEADDR must be called before bind. To reuse an existing UDT/UDP 471 | /// port, the new UDT socket must explicitly bind to the port. If the port is already used by a 472 | /// UDT socket with UDT_REUSEADDR as false, the new bind will return error. If 0 is passed as 473 | /// the port number, bind always creates a new port, no matter what value the UDT_REUSEADDR 474 | /// sets. 475 | /// 476 | pub fn bind(&self, name: std::net::SocketAddr) -> Result<(), UdtError> { 477 | let addr: sockaddr_in = get_sockaddr(name); 478 | let ret = unsafe { 479 | raw::udt_bind( 480 | self._sock, 481 | &addr as *const sockaddr_in as *const sockaddr, 482 | size_of::() as i32, 483 | ) 484 | }; 485 | if ret == raw::SUCCESS { 486 | Ok(()) 487 | } else { 488 | Err(get_last_err()) 489 | } 490 | } 491 | 492 | /// Binds a UDT socket to an existing UDP socket. 493 | /// 494 | /// This second form of bind allows UDT to bind directly on an existing UDP socket. This is 495 | /// usefule for firewall traversing in certain situations: 1) a UDP socket is created and its 496 | /// address is learned from a name server, there is no need to close the UDP socket and open a 497 | /// UDT socket on the same address again; 2) for certain firewall, especially some on local 498 | /// system, the port mapping maybe changed or the "hole" may be closed when a UDP socket is 499 | /// closed and reopened, thus it is necessary to use the UDP socket directly in UDT. 500 | /// 501 | /// Use the second form of bind with caution, as it violates certain programming rules 502 | /// regarding code robustness. Once the UDP socket descriptor is passed to UDT, it MUST NOT be 503 | /// touched again. DO NOT use this unless you clearly understand how the related systems work. 504 | pub fn bind_from(&self, other: std::net::UdpSocket) -> Result<(), UdtError> { 505 | {} 506 | let ret = unsafe { raw::udt_bind2(self._sock, get_udpsock_fd(other)) }; 507 | if ret == raw::SUCCESS { 508 | Ok(()) 509 | } else { 510 | Err(get_last_err()) 511 | } 512 | } 513 | 514 | /// Connects to a server socket (in regular mode) or a peer socket (in rendezvous mode) to set 515 | /// up a UDT connection 516 | /// 517 | /// UDT is connection oriented, for both of its `Stream` and `Datagram` mode. `connect` must 518 | /// be called in order to set up a UDT connection. The name parameter is the address of the 519 | /// server or the peer side. In regular (default) client/server mode, the server side must has 520 | /// called bind and listen. In rendezvous mode, both sides must call bind and connect to each 521 | /// other at (approximately) the same time. Rendezvous connect may not be used for more than 522 | /// one connections on the same UDP port pair, in which case UDT_REUSEADDR may be set to false. 523 | /// 524 | /// UDT connect takes at least one round trip to finish. This may become a bottleneck if 525 | /// applications frequently connect and disconnect to the same address. 526 | /// 527 | /// When UDT_RCVSYN is set to false, the connect call will return immediately and perform the 528 | /// actual connection setup at background. Applications may use epoll to wait for the connect 529 | /// to complete. 530 | /// 531 | /// When connect fails, the UDT socket can still be used to connect again. However, if the 532 | /// socket was not bound before, it may be bound implicitly, as mentioned above, even if the 533 | /// connect fails. In addition, in the situation when the connect call fails, the UDT socket 534 | /// will not be automatically released, it is the applications' responsibility to close the 535 | /// socket, if the socket is not needed anymore (e.g., to re-connect). 536 | pub fn connect(&self, name: std::net::SocketAddr) -> Result<(), UdtError> { 537 | let addr = get_sockaddr(name); 538 | let ret = unsafe { 539 | raw::udt_connect( 540 | self._sock, 541 | &addr as *const sockaddr_in as *const sockaddr, 542 | size_of::() as i32, 543 | ) 544 | }; 545 | trace!("connect returned {:?}", ret); 546 | if ret == raw::SUCCESS { 547 | Ok(()) 548 | } else { 549 | Err(get_last_err()) 550 | } 551 | } 552 | 553 | /// Enables a user UDT entity to wait for clients to connect. 554 | /// 555 | /// The listen method lets a UDT socket enter a listening state. The sock must call `bind` 556 | /// before a `listen` call. In addition, if the socket is enabled for rendezvous mode, neither 557 | /// listen nor accept can be used on the socket. A UDT socket can call `listen` more than 558 | /// once, in which case only the first call is effective, while all subsequent calls will be 559 | /// ignored if the socket is already in the listening state. 560 | /// 561 | /// `backlog` specifies the maximum number of pending connections. 562 | pub fn listen(&self, backlog: i32) -> Result<(), UdtError> { 563 | let ret = unsafe { raw::udt_listen(self._sock, backlog) }; 564 | 565 | if ret == raw::SUCCESS { 566 | Ok(()) 567 | } else { 568 | Err(get_last_err()) 569 | } 570 | } 571 | 572 | /// Retrieves an incoming connection. 573 | /// 574 | /// Once a UDT socket is in listening state, it accepts new connections and maintains the 575 | /// pending connections in a queue. An accept call retrieves the first connection in the queue, 576 | /// removes it from the queue, and returns the associate socket descriptor. 577 | /// 578 | /// If there is no connections in the queue when accept is called, a blocking socket will wait 579 | /// until a new connection is set up, whereas a non-blocking socket will return immediately 580 | /// with an error. 581 | /// 582 | /// The accepted sockets will inherit all proper attributes from the listening socket. 583 | /// 584 | /// # Returns 585 | /// 586 | /// Returns a tuple containing the new UdtSocket and a `SockAddr` structure containing the 587 | /// address of the new peer 588 | pub fn accept(&self) -> Result<(UdtSocket, SocketAddr), UdtError> { 589 | let mut peer = unsafe { std::mem::zeroed() }; 590 | let mut size: i32 = size_of::() as i32; 591 | let ret = unsafe { raw::udt_accept(self._sock, &mut peer, &mut size) }; 592 | assert_eq!(size, size_of::() as i32); 593 | if ret == raw::INVALID_SOCK { 594 | Err(get_last_err()) 595 | } else { 596 | let new_sock = UdtSocket::wrap_raw(ret); 597 | let addr = sockaddr_to_socketaddr(peer); 598 | Ok((new_sock, addr)) 599 | } 600 | } 601 | 602 | /// Close a UDT connection 603 | /// 604 | /// The close method gracefully shutdowns the UDT connection and releases all related data 605 | /// structures associated with the UDT socket. If there is no connection associated with the 606 | /// socket, close simply release the socket resources. 607 | /// 608 | /// On a blocking socket, if UDT_LINGER is non-zero, the close call will wait until all data in 609 | /// the sending buffer are sent out or the waiting time has exceeded the expiration time set by 610 | /// UDT_LINGER. However, if UDT_SYNSND is set to false (i.e., non-blocking sending), close will 611 | /// return immediately and any linger data will be sent at background until the linger timer 612 | /// expires. 613 | /// 614 | /// The closing UDT socket will send a shutdown message to the peer side so that the peer 615 | /// socket will also be closed. This is a best-effort message. If the message is not 616 | /// successfully delivered, the peer side will also be closed after a time-out. In UDT, 617 | /// shutdown is not supported. 618 | /// 619 | /// All sockets should be closed if they are not used any more. 620 | pub fn close(self) -> Result<(), UdtError> { 621 | let ret = unsafe { raw::udt_close(self._sock) }; 622 | if ret == raw::SUCCESS { 623 | Ok(()) 624 | } else { 625 | Err(get_last_err()) 626 | } 627 | } 628 | 629 | /// Retrieves the address information of the peer side of a connected UDT socket 630 | /// 631 | /// The getpeername retrieves the address of the peer side associated to the connection. The 632 | /// UDT socket must be connected at the time when this method is called. 633 | pub fn getpeername(&self) -> Result { 634 | let mut name = unsafe { std::mem::zeroed() }; 635 | let mut size: i32 = size_of::() as i32; 636 | let ret = unsafe { raw::udt_getpeername(self._sock, &mut name, &mut size) }; 637 | assert_eq!(size as usize, size_of::()); 638 | if ret != raw::SUCCESS { 639 | Err(get_last_err()) 640 | } else { 641 | Ok(sockaddr_to_socketaddr(name)) 642 | } 643 | } 644 | 645 | /// Retrieves the local address associated with a UDT socket. 646 | /// 647 | /// The getsockname retrieves the local address associated with the socket. The UDT socket must 648 | /// be bound explicitly (via bind) or implicitly (via connect), otherwise this method will fail 649 | /// because there is no meaningful address bound to the socket. 650 | /// 651 | /// If getsockname is called after an explicit bind, but before connect, the IP address 652 | /// returned will be exactly the IP address that is used for bind and it may be 0.0.0.0 if 653 | /// ADDR_ANY is used. If getsockname is called after connect, the IP address returned will be 654 | /// the address that the peer socket sees. In the case when there is a proxy (e.g., NAT), the 655 | /// IP address returned will be the translated address by the proxy, but not a local address. 656 | /// If there is no proxy, the IP address returned will be a local address. In either case, the 657 | /// port number is local (i.e, not the translated proxy port). 658 | /// 659 | /// Because UDP is connection-less, using getsockname on a UDP port will almost always return 660 | /// 0.0.0.0 as IP address (unless it is bound to an explicit IP) . As a connection oriented 661 | /// protocol, UDT will return a meaningful IP address by getsockname if there is no proxy 662 | /// translation exist. 663 | /// 664 | /// UDT has no multihoming support yet. When there are multiple local addresses and more than 665 | /// one of them can be routed to the destination address, UDT may not behave properly due to 666 | /// the multi-path effect. In this case, the UDT socket must be explicitly bound to one of 667 | /// the local addresses. 668 | pub fn getsockname(&self) -> Result { 669 | let mut name = unsafe { std::mem::zeroed() }; 670 | let mut size: i32 = size_of::() as i32; 671 | let ret = unsafe { raw::udt_getsockname(self._sock, &mut name, &mut size) }; 672 | 673 | assert_eq!(size as usize, size_of::()); 674 | if ret != raw::SUCCESS { 675 | Err(get_last_err()) 676 | } else { 677 | Ok(sockaddr_to_socketaddr(name)) 678 | } 679 | } 680 | 681 | /// Sends a message to the peer side. 682 | /// 683 | /// The sendmsg method sends a message to the peer side. The UDT socket must be in SOCK_DGRAM 684 | /// mode in order to send or receive messages. Message is the minimum data unit in this 685 | /// situation. In particular, sendmsg always tries to send the message out as a whole, that is, 686 | /// the message will either to completely sent or it is not sent at all. 687 | /// 688 | /// In blocking mode (default), sendmsg waits until there is enough space to hold the whole 689 | /// message. In non-blocking mode, sendmsg returns immediately and returns error if no buffer 690 | /// space available. 691 | /// 692 | /// If UDT_SNDTIMEO is set and the socket is in blocking mode, sendmsg only waits a limited 693 | /// time specified by UDT_SNDTIMEO option. If there is still no buffer space available when the 694 | /// timer expires, error will be returned. UDT_SNDTIMEO has no effect for non-blocking socket. 695 | /// 696 | /// The ttl parameter gives the message a limited life time, which starts counting once the 697 | /// first packet of the message is sent out. If the message has not been delivered to the 698 | /// receiver after the TTL timer expires and each packet in the message has been sent out at 699 | /// least once, the message will be discarded. Lost packets in the message will be 700 | /// retransmitted before TTL expires. 701 | /// 702 | /// On the other hand, the inorder option decides if this message should be delivered in order. 703 | /// That is, the message should not be delivered to the receiver side application unless all 704 | /// messages prior to it are either delivered or discarded. 705 | /// 706 | /// Finally, if the message size is greater than the size of the receiver buffer, the message 707 | /// will never be received in whole by the receiver side. Only the beginning part that can be 708 | /// hold in the receiver buffer may be read and the rest will be discarded. 709 | /// 710 | /// # Returns 711 | /// 712 | /// On success, sendmsg returns the actual size of message that has just been sent. The size 713 | /// should be equal to len. Otherwise UDT::ERROR is returned and specific error information can 714 | /// be retrieved by getlasterror. If UDT_SNDTIMEO is set to a positive value, zero will be 715 | /// returned if the message cannot be sent before the timer expires. 716 | pub fn sendmsg(&self, buf: &[u8]) -> Result { 717 | let ret = unsafe { 718 | raw::udt_sendmsg( 719 | self._sock, 720 | buf.as_ptr(), 721 | buf.len() as i32, 722 | -1 as i32, 723 | 1 as i32, 724 | ) 725 | }; 726 | if ret == raw::UDT_ERROR { 727 | Err(get_last_err()) 728 | } else { 729 | Ok(ret) 730 | } 731 | } 732 | 733 | /// Sends out a certain amount of data from an application buffer. 734 | /// 735 | /// The send method sends certain amount of data from the application buffer. If the the size 736 | /// limit of sending buffer queue is reached, send only sends a portion of the application 737 | /// buffer and returns the actual size of data that has been sent. 738 | /// 739 | /// In blocking mode (default), send waits until there is some sending buffer space available. 740 | /// In non-blocking mode, send returns immediately and returns error if the sending queue limit 741 | /// is already limited. 742 | /// 743 | /// If UDT_SNDTIMEO is set and the socket is in blocking mode, send only waits a limited time 744 | /// specified by UDT_SNDTIMEO option. If there is still no buffer space available when the 745 | /// timer expires, error will be returned. UDT_SNDTIMEO has no effect for non-blocking socket. 746 | /// 747 | /// # Returns 748 | /// 749 | /// On success, returns the actual size of the data that as been sent. Otherwise, a UdtError 750 | /// is returned with specific error information. 751 | /// 752 | /// If UDT_SNDTIMEO is set to a positive value, zero will be returned if no data is sent before 753 | /// the time expires. 754 | pub fn send(&self, buf: &[u8]) -> Result { 755 | let ret = unsafe { raw::udt_send(self._sock, buf.as_ptr(), buf.len() as i32, 0) }; 756 | if ret == raw::UDT_ERROR { 757 | Err(get_last_err()) 758 | } else { 759 | Ok(ret) 760 | } 761 | } 762 | 763 | /// The recvmsg method receives a valid message. 764 | /// 765 | /// The recvmsg method reads a message from the protocol buffer. The UDT socket must be in 766 | /// SOCK_DGRAM mode in order to send or receive messages. Message is the minimum data unit in 767 | /// this situation. Each recvmsg will read no more than one message, even if the message is 768 | /// smaller than the size of buf and there are more messages available. On the other hand, if 769 | /// the buf is not enough to hold the first message, only part of the message will be copied 770 | /// into the buffer, but the message will still be discarded after this recvmsg call. 771 | /// 772 | /// In blocking mode (default), recvmsg waits until there is a valid message received into the 773 | /// receiver buffer. In non-blocking mode, recvmsg returns immediately and returns error if no 774 | /// message available. 775 | /// 776 | /// If UDT_RCVTIMEO is set and the socket is in blocking mode, recvmsg only waits a limited 777 | /// time specified by UDT_RCVTIMEO option. If there is still no message available when the 778 | /// timer expires, error will be returned. UDT_RCVTIMEO has no effect for non-blocking socket. 779 | /// 780 | /// # Returns 781 | /// 782 | /// On success, recvmsg returns the actual size of received message. Otherwise UDT::ERROR is 783 | /// returned and specific error information can be retrieved by getlasterror. If UDT_RCVTIMEO 784 | /// is set to a positive value, zero will be returned if no message is received before the 785 | /// timer expires. 786 | pub fn recvmsg(&self, buf: &mut [u8]) -> Result { 787 | let ret = unsafe { raw::udt_recvmsg(self._sock, buf.as_mut_ptr(), buf.len() as i32) }; 788 | if ret > 0 { 789 | Ok(ret as usize) 790 | } else { 791 | Err(get_last_err()) 792 | } 793 | } 794 | 795 | /// Reads a certain amount of data into a local memory buffer. 796 | /// 797 | /// The recv method reads certain amount of data from the protocol buffer. If there is not 798 | /// enough data in the buffer, recv only reads the available data in the protocol buffer and 799 | /// returns the actual size of data received. However, recv will never read more data than the 800 | /// buffer size indicates by len. 801 | /// 802 | /// In blocking mode (default), recv waits until there is some data received into the receiver 803 | /// buffer. In non-blocking mode, recv returns immediately and returns error if no data 804 | /// available. 805 | /// 806 | /// If UDT_RCVTIMEO is set and the socket is in blocking mode, recv only waits a limited time 807 | /// specified by UDT_RCVTIMEO option. If there is still no data available when the timer 808 | /// expires, error will be returned. UDT_RCVTIMEO has no effect for non-blocking socket. 809 | pub fn recv(&self, buf: &mut [u8], len: usize) -> Result { 810 | let ret = unsafe { raw::udt_recv(self._sock, buf.as_mut_ptr(), len as i32, 0) }; 811 | 812 | if ret == raw::UDT_ERROR { 813 | Err(get_last_err()) 814 | } else { 815 | Ok(ret) 816 | } 817 | } 818 | 819 | /// Gets UDT options 820 | /// 821 | /// See the [`UdtOpts`][1] module for all the supported option types. 822 | /// 823 | /// [1]: UdtOpts/index.html 824 | /// 825 | /// # Example 826 | /// 827 | /// ``` 828 | /// use udt::*; 829 | /// 830 | /// let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 831 | /// let recv_buf: i32 = sock.getsockopt(UdtOpts::UDP_RCVBUF).unwrap(); 832 | /// ``` 833 | pub fn getsockopt>(&self, opt: T) -> Result { 834 | let mut val: B = unsafe { std::mem::zeroed() }; 835 | let val_p: *mut B = &mut val; 836 | let ty: raw::UDTOpt = opt.get_type(); 837 | let mut size: c_int = size_of::() as i32; 838 | let ret = unsafe { 839 | raw::udt_getsockopt(self._sock, 0, ty, val_p as *mut libc::c_void, &mut size) 840 | }; 841 | 842 | if ret == raw::SUCCESS { 843 | Ok(val) 844 | } else { 845 | Err(get_last_err()) 846 | } 847 | } 848 | 849 | /// Sets UDT options 850 | /// 851 | /// See the [`UdtOpts`][1] module for all the supported option types. 852 | 853 | /// [1]: UdtOpts/index.html 854 | pub fn setsockopt>(&self, opt: T, value: B) -> Result<(), UdtError> { 855 | let ty: raw::UDTOpt = opt.get_type(); 856 | let val_p: *const B = &value; 857 | let size: c_int = size_of::() as i32; 858 | 859 | let ret = 860 | unsafe { raw::udt_setsockopt(self._sock, 0, ty, val_p as *const libc::c_void, size) }; 861 | 862 | if ret == raw::SUCCESS { 863 | Ok(()) 864 | } else { 865 | Err(get_last_err()) 866 | } 867 | } 868 | 869 | pub fn getstate(&self) -> UdtStatus { 870 | unsafe { raw::udt_getsockstate(self._sock) } 871 | } 872 | 873 | /// The perfmon method retrieves the internal protocol parameters and performance trace. 874 | /// 875 | /// The perfmon method reads the performance data since the last time perfmon is executed, or since the connection is started. 876 | /// 877 | /// There are three kinds of performance information that can be read by applications: the total counts since the connection is started, the periodical counts since last time the counts are cleared, and instant parameter values. 878 | pub fn perfmon(&self) -> Result { 879 | let mut perf = raw::PerfMon::default(); 880 | let ret = unsafe { raw::udt_perfmon(self._sock, &mut perf, 0) }; 881 | 882 | if ret == raw::SUCCESS { 883 | Ok(perf) 884 | } else { 885 | Err(get_last_err()) 886 | } 887 | } 888 | } 889 | 890 | /// Used with the `epoll*` methods of a UDTSocket 891 | /// 892 | /// The epoll functions provides a highly scalable and efficient way to wait for UDT sockets IO 893 | /// events. It should be used instead of select and selectEx when the application needs to wait for 894 | /// a very large number of sockets. In addition, epoll also offers to wait on system sockets at the 895 | /// same time, which can be convenient when an application uses both UDT and TCP/UDP. 896 | /// 897 | /// Applications should use [`Epoll::create`][1] to create an epoll ID and use [`add_usock`][2]/ssock and 898 | /// [`remove_usock`][3]/ssock to add/remove sockets. If a socket is already in the epoll set, it 899 | /// will be ignored if being added again. Adding invalid or closed sockets will cause error. 900 | /// However, they will simply be ignored without any error returned when being removed. 901 | /// 902 | /// Multiple epoll entities can be created and there is no upper limits as long as system resource 903 | /// allows. There is also no hard limit on the number of UDT sockets. The number system descriptors 904 | /// supported by UDT::epoll are platform dependent. 905 | /// 906 | /// For system sockets on Linux, developers may choose to watch individual events from EPOLLIN 907 | /// (read), EPOLLOUT (write), and EPOLLERR (exceptions). When using epoll_remove_ssock, if the 908 | /// socket is waiting on multiple events, only those specified in events are removed. The events 909 | /// can be a combination (with "|" operation) of any of the following values. 910 | /// 911 | /// [1]: #method.create 912 | /// [2]: #method.add_usock 913 | /// [3]: #method.remove_usock 914 | /// 915 | #[derive(Debug)] 916 | pub struct Epoll { 917 | eid: c_int, 918 | 919 | // poll requires us to pass in an array to receive a list of sockets. 920 | // instead of allocating one every time we call into poll, we create 921 | // two vecs and re-use them. this means that while the UDT api is 922 | // thread safe, this impl of epoll is not 923 | rd_vec: Vec, 924 | wr_vec: Vec, 925 | } 926 | 927 | impl Epoll { 928 | /// Creates a new Epoll object 929 | pub fn create() -> Result { 930 | let ret = unsafe { raw::udt_epoll_create() }; 931 | if ret < 0 { 932 | Err(get_last_err()) 933 | } else { 934 | Ok(Epoll { 935 | eid: ret, 936 | rd_vec: Vec::new(), 937 | wr_vec: Vec::new(), 938 | }) 939 | } 940 | } 941 | 942 | /// Adds a UdtSocket to an epoll 943 | /// 944 | /// `events` can be any combination of `UDT_EPOLL_IN`, `UDT_EPOLL_OUT`, and `UDT_EPOLL_ERR` 945 | pub fn add_usock( 946 | &mut self, 947 | socket: &UdtSocket, 948 | events: Option, 949 | ) -> Result<(), UdtError> { 950 | use std::ptr::null; 951 | 952 | let ret = match events { 953 | None => unsafe { raw::udt_epoll_add_usock(self.eid, socket._sock, null()) }, 954 | Some(val) => { 955 | let b: c_int = val.bits(); 956 | unsafe { raw::udt_epoll_add_usock(self.eid, socket._sock, &b) } 957 | } 958 | }; 959 | if ret == 0 { 960 | trace!("Added UdpSocket={} to epoll", socket._sock); 961 | self.wr_vec.push(-1); 962 | self.rd_vec.push(-1); 963 | Ok(()) 964 | } else { 965 | Err(get_last_err()) 966 | } 967 | } 968 | 969 | /// Removes a UdtSocket from an epoll 970 | /// 971 | /// If the socket isn't part of the epoll, there is no error 972 | pub fn remove_usock(&self, socket: &UdtSocket) -> Result<(), UdtError> { 973 | let ret = unsafe { raw::udt_epoll_remove_usock(self.eid, socket._sock) }; 974 | if ret == 0 { 975 | Ok(()) 976 | } else { 977 | Err(get_last_err()) 978 | } 979 | } 980 | 981 | /// Wait for events 982 | /// 983 | /// Timeout is in milliseconds. If negative, wait forever. If zero, return immediately. 984 | /// 985 | /// If `write` is false, the list of sockets for writing will always be null. 986 | /// 987 | /// # Returns 988 | /// 989 | /// A tuple of sockets to be read and sockets to be written (or have exceptions) 990 | pub fn wait( 991 | &mut self, 992 | timeout: i64, 993 | write: bool, 994 | ) -> Result<(Vec, Vec), UdtError> { 995 | use std::ptr::null_mut; 996 | let mut rnum: c_int = self.rd_vec.len() as c_int; 997 | let mut wnum: c_int = self.wr_vec.len() as c_int; 998 | 999 | let wr_vec_ptr = if !write { 1000 | wnum = 0; 1001 | std::ptr::null_mut() 1002 | } else { 1003 | self.wr_vec.as_mut_ptr() 1004 | }; 1005 | 1006 | let ret = unsafe { 1007 | raw::udt_epoll_wait2( 1008 | self.eid, 1009 | self.rd_vec.as_mut_ptr(), 1010 | &mut rnum, 1011 | wr_vec_ptr, 1012 | &mut wnum, 1013 | timeout, 1014 | null_mut(), 1015 | null_mut(), 1016 | null_mut(), 1017 | null_mut(), // no support for polling sys sockets right now 1018 | ) 1019 | }; 1020 | trace!("epoll returned {:?}", ret); 1021 | trace!("rnum={}, wnum={}", rnum, wnum); 1022 | if ret < 0 { 1023 | let e = get_last_err(); 1024 | if e.err_code != 6003 { 1025 | return Err(get_last_err()); 1026 | } else { 1027 | rnum = 0; 1028 | wnum = 0; 1029 | } 1030 | } 1031 | for v in 0..rnum { 1032 | trace!("rnum[{}] = {}", v, self.rd_vec[v as usize]); 1033 | } 1034 | for v in 0..wnum { 1035 | trace!("wnum[{}] = {}", v, self.wr_vec[v as usize]); 1036 | } 1037 | 1038 | let mut rds = Vec::with_capacity(rnum as usize); 1039 | rds.extend( 1040 | self.rd_vec 1041 | .iter() 1042 | .take(rnum as usize) 1043 | .map(|&x| UdtSocket::wrap_raw(x)), 1044 | ); 1045 | 1046 | let mut wrs = Vec::with_capacity(wnum as usize); 1047 | wrs.extend( 1048 | self.wr_vec 1049 | .iter() 1050 | .take(wnum as usize) 1051 | .map(|&x| UdtSocket::wrap_raw(x)), 1052 | ); 1053 | Ok((rds, wrs)) 1054 | } 1055 | } 1056 | 1057 | #[test] 1058 | fn test_udt_socket() { 1059 | init(); 1060 | let _ = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 1061 | } 1062 | 1063 | #[test] 1064 | fn test_udt_bind() { 1065 | use std::net::Ipv4Addr; 1066 | use std::str::FromStr; 1067 | 1068 | init(); 1069 | let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 1070 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 1071 | if cfg!(target_os = "macos") { 1072 | trace!("Lowering buffer sizes on OSX"); 1073 | sock.setsockopt(UdtOpts::UDP_RCVBUF, 8192).unwrap(); 1074 | sock.setsockopt(UdtOpts::UDP_SNDBUF, 8192).unwrap(); 1075 | } 1076 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 1077 | .or_else(|e| Err(panic!("Failed to bind to {:?} --> {:?}", localhost, e))); 1078 | } 1079 | 1080 | #[test] 1081 | fn test_udt_socket_state() { 1082 | use std::net::Ipv4Addr; 1083 | use std::str::FromStr; 1084 | use std::thread::sleep; 1085 | use std::time::Duration; 1086 | 1087 | init(); 1088 | let sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 1089 | assert_eq!(sock.getstate(), UdtStatus::INIT); 1090 | if cfg!(target_os = "macos") { 1091 | trace!("Lowering buffer sizes on OSX"); 1092 | sock.setsockopt(UdtOpts::UDP_RCVBUF, 8192).unwrap(); 1093 | sock.setsockopt(UdtOpts::UDP_SNDBUF, 8192).unwrap(); 1094 | } 1095 | 1096 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 1097 | 1098 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 1099 | .or_else(|e| Err(panic!("Failed to bind to {:?} --> {:?}", localhost, e))); 1100 | assert_eq!(sock.getstate(), UdtStatus::OPENED); 1101 | sock.listen(5).unwrap(); 1102 | assert_eq!(sock.getstate(), UdtStatus::LISTENING); 1103 | sock.close().unwrap(); 1104 | assert_eq!(sock.getstate(), UdtStatus::BROKEN); 1105 | sleep(Duration::from_millis(4500)); 1106 | // after some time, the sock transitions to CLOSED and then NONEXIST 1107 | // THe LISTENING -> CLOSED transition is made after a 3 second timeout 1108 | assert!(sock.getstate() == UdtStatus::NONEXIST || sock.getstate() == UdtStatus::CLOSED); 1109 | } 1110 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | extern crate udt; 2 | #[macro_use] 3 | extern crate log; 4 | 5 | use std::str; 6 | use udt::*; 7 | 8 | #[cfg(any(target_os = "linux", target_os = "windows"))] 9 | #[allow(unused_variables)] 10 | fn do_platform_specific_init(sock: &mut UdtSocket) {} 11 | 12 | #[cfg(any(target_os = "macos", target_os = "freebsd"))] 13 | fn do_platform_specific_init(sock: &mut UdtSocket) { 14 | sock.setsockopt(UdtOpts::UDP_RCVBUF, 8192).unwrap(); 15 | sock.setsockopt(UdtOpts::UDP_SNDBUF, 8192).unwrap(); 16 | } 17 | 18 | #[test] 19 | fn test_getsockopt() { 20 | init(); 21 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 22 | do_platform_specific_init(&mut sock); 23 | 24 | // test some defaults 25 | assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500 as i32); 26 | assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDSYN).unwrap(), true); 27 | assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVSYN).unwrap(), true); 28 | assert_eq!(sock.getsockopt(UdtOpts::UDT_FC).unwrap(), 25600 as i32); 29 | assert_eq!(sock.getsockopt(UdtOpts::UDT_RENDEZVOUS).unwrap(), false); 30 | assert_eq!(sock.getsockopt(UdtOpts::UDT_SNDTIMEO).unwrap(), -1); 31 | assert_eq!(sock.getsockopt(UdtOpts::UDT_RCVTIMEO).unwrap(), -1); 32 | } 33 | 34 | #[test] 35 | fn test_setsockopt() { 36 | init(); 37 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 38 | do_platform_specific_init(&mut sock); 39 | 40 | assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1500); 41 | sock.setsockopt(UdtOpts::UDT_MSS, 1400).unwrap(); 42 | assert_eq!(sock.getsockopt(UdtOpts::UDT_MSS).unwrap(), 1400); 43 | } 44 | 45 | #[test] 46 | fn test_sendmsg() { 47 | use std::net::Ipv4Addr; 48 | use std::net::{SocketAddr, SocketAddrV4}; 49 | use std::str::FromStr; 50 | use std::sync::mpsc::channel; 51 | use std::thread::spawn; 52 | 53 | init(); 54 | 55 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 56 | 57 | // the server will bind to a random port and pass it back for the client to connect to 58 | let (tx, rx) = channel(); 59 | 60 | // spawn the server 61 | let server = spawn(move || { 62 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 63 | do_platform_specific_init(&mut sock); 64 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 65 | .unwrap(); 66 | let my_addr = sock.getsockname().unwrap(); 67 | debug!("Server bound to {:?}", my_addr); 68 | 69 | sock.listen(5).unwrap(); 70 | 71 | tx.send(my_addr.port()).unwrap(); 72 | 73 | let (new, peer) = sock.accept().unwrap(); 74 | debug!("Server recieved connection from {:?}", peer); 75 | 76 | let peer2 = new.getpeername().unwrap(); 77 | assert_eq!(peer2, peer); 78 | 79 | let msg = &mut [0u8; 100]; 80 | 81 | let len = new.recvmsg(msg).unwrap(); 82 | assert_eq!(len, 5); 83 | assert_eq!(&msg[..len], "hello".as_bytes()); 84 | new.sendmsg("world".as_bytes()).unwrap(); 85 | 86 | new.close().unwrap(); 87 | sock.close().unwrap(); 88 | }); 89 | 90 | let client = spawn(move || { 91 | let port = rx.recv().unwrap(); 92 | debug!("Client connecting to port {:?}", port); 93 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 94 | do_platform_specific_init(&mut sock); 95 | sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))) 96 | .unwrap(); 97 | 98 | sock.sendmsg("hello".as_bytes()).unwrap(); 99 | let msg = &mut [0u8; 1024]; 100 | let len = sock.recvmsg(msg).unwrap(); 101 | assert_eq!(len, 5); 102 | assert_eq!(&msg[..len], "world".as_bytes()); 103 | 104 | sock.close().unwrap(); 105 | }); 106 | 107 | server.join().unwrap(); 108 | client.join().unwrap(); 109 | } 110 | 111 | #[test] 112 | fn test_send() { 113 | use std::net::Ipv4Addr; 114 | use std::net::{SocketAddr, SocketAddrV4}; 115 | use std::str::FromStr; 116 | use std::sync::mpsc::channel; 117 | use std::thread::spawn; 118 | 119 | init(); 120 | 121 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 122 | 123 | // the server will bind to a random port and pass it back for the client to connect to 124 | let (tx, rx) = channel(); 125 | 126 | // spawn the server 127 | let server = spawn(move || { 128 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 129 | do_platform_specific_init(&mut sock); 130 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 131 | .unwrap(); 132 | let my_addr = sock.getsockname().unwrap(); 133 | debug!("Server bound to {:?}", my_addr); 134 | 135 | sock.listen(5).unwrap(); 136 | 137 | tx.send(my_addr.port()).unwrap(); 138 | 139 | let (new, new_peer) = sock.accept().unwrap(); 140 | debug!("Server recieved connection from {:?}", new_peer); 141 | 142 | let mut buf: [u8; 10] = [0; 10]; 143 | assert_eq!(new.recv(&mut buf, 5).unwrap(), 5); 144 | assert_eq!(&buf[0..5], "hello".as_bytes()); 145 | assert_eq!(&buf[5..], [0; 5]); 146 | assert_eq!(new.recv(&mut buf[5..], 5).unwrap(), 5); 147 | assert_eq!(&buf[5..], "world".as_bytes()); 148 | assert_eq!(&buf, "helloworld".as_bytes()); 149 | 150 | new.close().unwrap(); 151 | sock.close().unwrap(); 152 | }); 153 | 154 | let client = spawn(move || { 155 | let port = rx.recv().unwrap(); 156 | debug!("Client connecting to port {:?}", port); 157 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 158 | do_platform_specific_init(&mut sock); 159 | sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))) 160 | .unwrap(); 161 | 162 | assert_eq!(sock.send("hello".as_bytes()).unwrap(), 5); 163 | assert_eq!(sock.send("world".as_bytes()).unwrap(), 5); 164 | 165 | sock.close().unwrap(); 166 | }); 167 | 168 | server.join().unwrap(); 169 | client.join().unwrap(); 170 | } 171 | 172 | #[test] 173 | fn test_perfmon() { 174 | use std::net::Ipv4Addr; 175 | use std::net::{SocketAddr, SocketAddrV4}; 176 | use std::str::FromStr; 177 | use std::sync::mpsc::channel; 178 | use std::thread::spawn; 179 | 180 | init(); 181 | 182 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 183 | 184 | // the server will bind to a random port and pass it back for the client to connect to 185 | let (tx, rx) = channel(); 186 | 187 | // spawn the server 188 | let server = spawn(move || { 189 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 190 | do_platform_specific_init(&mut sock); 191 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 192 | .unwrap(); 193 | let my_addr = sock.getsockname().unwrap(); 194 | debug!("Server bound to {:?}", my_addr); 195 | 196 | sock.listen(5).unwrap(); 197 | 198 | tx.send(my_addr.port()).unwrap(); 199 | 200 | let (new, new_peer) = sock.accept().unwrap(); 201 | debug!("Server recieved connection from {:?}", new_peer); 202 | 203 | let mut buf: [u8; 10] = [0; 10]; 204 | assert_eq!(new.recv(&mut buf, 5).unwrap(), 5); 205 | 206 | let perf = new.perfmon(); 207 | assert!(perf.is_ok()); 208 | assert_eq!(perf.unwrap().pkt_recv, 1); 209 | 210 | new.close().unwrap(); 211 | sock.close().unwrap(); 212 | }); 213 | 214 | let client = spawn(move || { 215 | let port = rx.recv().unwrap(); 216 | debug!("Client connecting to port {:?}", port); 217 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Stream).unwrap(); 218 | do_platform_specific_init(&mut sock); 219 | sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))) 220 | .unwrap(); 221 | 222 | assert_eq!(sock.send(b"hello").unwrap(), 5); 223 | std::thread::sleep(std::time::Duration::from_millis(50)); 224 | let perf = sock.perfmon(); 225 | assert!(perf.is_ok()); 226 | assert_eq!(perf.unwrap().pkt_sent, 1); 227 | 228 | sock.close().unwrap(); 229 | }); 230 | 231 | server.join().unwrap(); 232 | client.join().unwrap(); 233 | } 234 | 235 | #[test] 236 | fn test_epoll() { 237 | use std::net::Ipv4Addr; 238 | use std::net::{SocketAddr, SocketAddrV4}; 239 | use std::str::FromStr; 240 | use std::sync::mpsc::channel; 241 | use std::thread::sleep; 242 | use std::thread::spawn; 243 | use std::time::Duration; 244 | 245 | init(); 246 | 247 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 248 | 249 | // the server will bind to a random port and pass it back for the client to connect to 250 | let (tx, rx) = channel(); 251 | 252 | // spawn the server 253 | let server = spawn(move || { 254 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 255 | do_platform_specific_init(&mut sock); 256 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 257 | .unwrap(); 258 | let my_addr = sock.getsockname().unwrap(); 259 | debug!("Server bound to {:?}", my_addr); 260 | 261 | sock.listen(5).unwrap(); 262 | 263 | tx.send(my_addr.port()).unwrap(); 264 | 265 | let mut epoll = Epoll::create().unwrap(); 266 | 267 | epoll.add_usock(&sock, None).unwrap(); 268 | 269 | let mut counter = 0; 270 | loop { 271 | let (pending_rd, pending_wr) = epoll.wait(1000, true).unwrap(); 272 | debug!("Pending sockets: {:?} {:?}", pending_rd, pending_wr); 273 | 274 | let rd_len = pending_rd.len(); 275 | for s in pending_rd { 276 | if s == sock { 277 | debug!("trying to accept new sock"); 278 | let (new, peer) = sock.accept().unwrap(); 279 | debug!("Server recieved connection from {:?}", peer); 280 | epoll.add_usock(&new, None).unwrap(); 281 | } else { 282 | let msg = &mut [0u8; 100]; 283 | let len = s.recvmsg(msg).unwrap(); 284 | let msg_string = str::from_utf8(&msg[..len]).unwrap(); 285 | debug!("Received message: {:?}", msg_string); 286 | } 287 | } 288 | 289 | for s in pending_wr { 290 | let state = s.getstate(); 291 | if rd_len == 0 292 | && (state == UdtStatus::BROKEN 293 | || state == UdtStatus::CLOSED 294 | || state == UdtStatus::NONEXIST) 295 | { 296 | epoll.remove_usock(&s).unwrap(); 297 | return; 298 | } 299 | debug!("Sock {:?} is in state {:?}", s, state); 300 | } 301 | sleep(Duration::from_millis(100)); 302 | counter += 1; 303 | assert!(counter < 500); 304 | } 305 | }); 306 | 307 | let client = spawn(move || { 308 | let port = rx.recv().unwrap(); 309 | debug!("Client connecting to port {:?}", port); 310 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 311 | do_platform_specific_init(&mut sock); 312 | sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))) 313 | .unwrap(); 314 | 315 | sock.sendmsg("hello".as_bytes()).unwrap(); 316 | 317 | sleep(Duration::from_millis(3000)); 318 | sock.sendmsg("world".as_bytes()).unwrap(); 319 | sock.sendmsg("done.".as_bytes()).unwrap(); 320 | 321 | sock.close().unwrap(); 322 | }); 323 | 324 | server.join().unwrap(); 325 | client.join().unwrap(); 326 | } 327 | 328 | #[test] 329 | fn test_epoll2() { 330 | use std::net::Ipv4Addr; 331 | use std::net::{SocketAddr, SocketAddrV4}; 332 | use std::str::FromStr; 333 | use std::sync::mpsc::channel; 334 | use std::thread::sleep; 335 | use std::thread::spawn; 336 | use std::time::Duration; 337 | 338 | init(); 339 | 340 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 341 | 342 | // the server will bind to a random port and pass it back for the client to connect to 343 | let (tx, rx) = channel(); 344 | 345 | // spawn the server 346 | let server = spawn(move || { 347 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 348 | do_platform_specific_init(&mut sock); 349 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 350 | .unwrap(); 351 | let my_addr = sock.getsockname().unwrap(); 352 | println!("Server bound to {:?}", my_addr); 353 | 354 | sock.listen(5).unwrap(); 355 | 356 | tx.send(my_addr.port()).unwrap(); 357 | 358 | let mut epoll = Epoll::create().unwrap(); 359 | 360 | epoll 361 | .add_usock(&sock, Some(UDT_EPOLL_ERR | UDT_EPOLL_IN)) 362 | .unwrap(); 363 | 364 | let mut counter = 0; 365 | let mut outer = true; 366 | while outer { 367 | let (pending_rd, pending_wr) = epoll.wait(1000, true).unwrap(); 368 | println!("Pending sockets: {:?} {:?}", pending_rd, pending_wr); 369 | 370 | let rd_len = pending_rd.len(); 371 | for s in pending_rd { 372 | if s == sock { 373 | println!("trying to accept new sock"); 374 | let (new, peer) = sock.accept().unwrap(); 375 | println!("Server recieved connection from {:?}", peer); 376 | epoll 377 | .add_usock(&new, Some(UDT_EPOLL_ERR | UDT_EPOLL_IN)) 378 | .unwrap(); 379 | } else { 380 | let msg = &mut [0u8; 100]; 381 | if let Ok(len) = s.recvmsg(msg) { 382 | let msg_string = str::from_utf8(&msg[..len]).unwrap(); 383 | println!("Received message: {:?}", msg_string); 384 | } else { 385 | println!("Error on recieve, removing usock"); 386 | epoll.remove_usock(&s).unwrap(); 387 | outer = false; 388 | } 389 | } 390 | } 391 | 392 | for s in pending_wr { 393 | let state = s.getstate(); 394 | println!("state: {:?}", state); 395 | if rd_len == 0 396 | && (state == UdtStatus::BROKEN 397 | || state == UdtStatus::CLOSED 398 | || state == UdtStatus::NONEXIST) 399 | { 400 | epoll.remove_usock(&s).unwrap(); 401 | return; 402 | } 403 | println!("Sock {:?} is in state {:?}", s, state); 404 | } 405 | sleep(Duration::from_millis(100)); 406 | counter += 1; 407 | assert!(counter < 500); 408 | } 409 | }); 410 | 411 | let client = spawn(move || { 412 | let port = rx.recv().unwrap(); 413 | debug!("Client connecting to port {:?}", port); 414 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 415 | do_platform_specific_init(&mut sock); 416 | sock.connect(SocketAddr::V4(SocketAddrV4::new(localhost, port))) 417 | .unwrap(); 418 | 419 | sock.sendmsg("hello".as_bytes()).unwrap(); 420 | 421 | sleep(Duration::from_millis(3000)); 422 | sock.sendmsg("world".as_bytes()).unwrap(); 423 | sock.sendmsg("done.".as_bytes()).unwrap(); 424 | 425 | sock.close().unwrap(); 426 | println!("Client is done"); 427 | }); 428 | 429 | server.join().unwrap(); 430 | client.join().unwrap(); 431 | } 432 | 433 | #[test] 434 | fn test_epoll3() { 435 | use std::net::Ipv4Addr; 436 | use std::net::{SocketAddr, SocketAddrV4}; 437 | use std::str::FromStr; 438 | use std::thread::spawn; 439 | 440 | init(); 441 | 442 | let localhost = Ipv4Addr::from_str("127.0.0.1").unwrap(); 443 | 444 | // spawn the server 445 | let server = spawn(move || { 446 | let mut sock = UdtSocket::new(SocketFamily::AFInet, SocketType::Datagram).unwrap(); 447 | do_platform_specific_init(&mut sock); 448 | sock.bind(SocketAddr::V4(SocketAddrV4::new(localhost, 0))) 449 | .unwrap(); 450 | let my_addr = sock.getsockname().unwrap(); 451 | println!("Server bound to {:?}", my_addr); 452 | 453 | sock.listen(5).unwrap(); 454 | 455 | let mut epoll = Epoll::create().unwrap(); 456 | println!("Epoll {:?} created", epoll); 457 | 458 | epoll.add_usock(&sock, None).unwrap(); 459 | epoll.remove_usock(&sock).unwrap(); 460 | epoll.add_usock(&sock, None).unwrap(); 461 | }); 462 | server.join().unwrap(); 463 | } 464 | --------------------------------------------------------------------------------