├── CodeWalkThrough.pdf ├── LICENSE ├── Readme.md └── src ├── LICENSE.txt ├── Makefile ├── app ├── Makefile ├── pccclient.cpp ├── pccserver.cpp └── test_util.h ├── core ├── Makefile ├── api.cpp ├── api.h ├── buffer.cpp ├── buffer.h ├── cache.cpp ├── cache.h ├── ccc.cpp ├── ccc.h ├── channel.cpp ├── channel.h ├── common.cpp ├── common.h ├── core.cpp ├── core.h ├── epoll.cpp ├── epoll.h ├── list.cpp ├── list.h ├── md5.cpp ├── md5.h ├── packet.cpp ├── packet.h ├── packet_tracker.h ├── queue.cpp ├── queue.h ├── udt.h ├── window.cpp └── window.h └── pcc ├── Makefile ├── pcc_monitor_interval_queue.cpp ├── pcc_monitor_interval_queue.h ├── pcc_sender.cpp ├── pcc_sender.h ├── pcc_utility_manager.cpp ├── pcc_utility_manager.h ├── pcc_vivace_sender.cpp ├── pcc_vivace_sender.h └── quic_types ├── LICENSE.txt ├── Readme.md ├── quic_bandwidth.h ├── quic_constants.h ├── quic_time.h └── quic_types.h /CodeWalkThrough.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PCCproject/PCC-Uspace/30c2cfe1e276646aae03751b9df91889afea42dd/CodeWalkThrough.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Tong Meng, Nathan Jay, Mo Dong, Xuefeng Zhu, UIUC, Google Inc. 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 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of PCC_QUIC nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Performance-oriented Congestion Control 2 | 3 | This repository houses the userspace implementations of the Performance-oriented Congestion Control (PCC) project. 4 | 5 | PCC is a new transport rate control architecture which uses online learning. By empirically observing what actions lead to high performance, PCC achieves substantially higher performance than legacy TCP congestion controllers that are based on fixed rules. For more, see our original paper on PCC Allegro in [USENIX NSDI 2015](https://www.usenix.org/conference/nsdi15/technical-sessions/presentation/dong), and the paper on PCC Vivace in [USENIX NSDI 2018](https://www.usenix.org/conference/nsdi18/presentation/dong). 6 | 7 | The current PCC implementation employs the Proteus architecture that supports different priorities with different utility functions, e.g., primary, scavenger, hybrid. Details can be found in our recent paper on PCC Proteus in [ACM SIGCOMM 2020](https://dl.acm.org/doi/pdf/10.1145/3387514.3405891)([talk video](https://dl.acm.org/doi/abs/10.1145/3387514.3405891#sec-supp)). 8 | 9 | (You can find the version of PCC Vivace as in our NSDI 2018 paper in branch [NSDI-2018](https://github.com/PCCproject/PCC-Uspace/tree/NSDI-2018).) 10 | 11 | ## Implementations 12 | 13 | Our implementation in folder src/ branches off the open-source UDT framework. All PCC related files locate in /src/pcc. Specifically, we implement the transport algorithms using QUIC-compatible function APIs, and QUIC data structures (src/pcc/quic_types/). So PCC should be easy for QUIC adoption. 14 | 15 | The code in this repository is broken into 3 parts: 16 | 1. The application code (located in src/app) 17 | 2. The UDT library code (located in src/core) 18 | 3. The PCC implementation (located in src/pcc) 19 | 20 | 21 | ## Building 22 | 23 | To build PCC for UDT, simply run the following: 24 | 25 | ``` 26 | cd src 27 | make 28 | ``` 29 | 30 | This will produce two apps (pccclient and pccserver) in the src/app directory. 31 | 32 | To test that PCC is functioning, create a PCC server that listens on a port and receives data: 33 | 34 | ``` 35 | ./app/pccserver recv pcc_server_port 36 | ``` 37 | 38 | Then, create a PCC client that connects to the IP hosting the PCC server at the server listening port, then sends data to the server at that address (the last parameter tells the application to use the Vivace rate control algorithm, details in our PCC Vivace paper in NSDI 2018): 39 | ``` 40 | ./app/pccclient send pcc_server_ip pcc_server_port Vivace 41 | ``` 42 | 43 | This will by default initiate data transfer using the primary priority utility function. To use a different utility function, give the corresponding parameter (utility function name, and if necessary, utility function parameter) when running PCC client: 44 | ``` 45 | ./app/pccclient send pcc_server_ip pcc_server_port Vivace [utility_function] [utility_parameter] 46 | ``` 47 | 48 | For example, 49 | 1. To use primary utility function: 50 | ``` 51 | ./app/pccclient send pcc_server_ip pcc_server_port Vivace Vivace 52 | ``` 53 | 54 | 2. To use scavenger utility function (0.0015 is the default coefficient for our scavenger utility function): 55 | ``` 56 | ./app/pccclient send pcc_server_ip pcc_server_port Vivace Scavenger 0.0015 57 | ``` 58 | 59 | 3. To use hybrid utility function with some switching threshold (in unit of Mbit/sec, see our PCC Proteus paper in SIGCOMM 2020 for details): 60 | ``` 61 | ./app/pccclient send pcc_server_ip pcc_server_port Vivace Hybrid threshold 62 | ``` 63 | -------------------------------------------------------------------------------- /src/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 6 | met: 7 | 8 | * Redistributions of source code must retain the above 9 | copyright notice, this list of conditions and the 10 | following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the 13 | above copyright notice, this list of conditions 14 | and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the University of Illinois 18 | nor the names of its contributors may be used to 19 | endorse or promote products derived from this 20 | software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | DIRS = pcc core app 2 | TARGETS = all clean install 3 | 4 | $(TARGETS): %: $(patsubst %, %.%, $(DIRS)) 5 | 6 | $(foreach TGT, $(TARGETS), $(patsubst %, %.$(TGT), $(DIRS))): 7 | $(MAKE) -C $(subst ., , $@) 8 | -------------------------------------------------------------------------------- /src/app/Makefile: -------------------------------------------------------------------------------- 1 | C++ = g++ -g -std=c++0x 2 | 3 | ifndef os 4 | os = LINUX 5 | endif 6 | 7 | ifndef arch 8 | arch = IA32 9 | endif 10 | 11 | CCFLAGS = -Wall -D$(os) -I../core -finline-functions -O3 12 | 13 | ifeq ($(arch), IA32) 14 | CCFLAGS += -DIA32 #-mcpu=pentiumpro -march=pentiumpro -mmmx -msse 15 | endif 16 | 17 | ifeq ($(arch), POWERPC) 18 | CCFLAGS += -mcpu=powerpc 19 | endif 20 | 21 | ifeq ($(arch), IA64) 22 | CCFLAGS += -DIA64 23 | endif 24 | 25 | ifeq ($(arch), SPARC) 26 | CCFLAGS += -DSPARC 27 | endif 28 | 29 | LDFLAGS = -L../core -ludt -lstdc++ -lpthread -lm 30 | 31 | ifeq ($(os), UNIX) 32 | LDFLAGS += -lsocket 33 | endif 34 | 35 | ifeq ($(os), SUNOS) 36 | LDFLAGS += -lrt -lsocket 37 | endif 38 | 39 | DIR = $(shell pwd) 40 | 41 | %.o: %.cpp 42 | $(C++) $(CCFLAGS) $< -c 43 | 44 | pccserver: pccserver.o 45 | $(C++) $^ -o $@ $(LDFLAGS) -static 46 | pccclient: pccclient.o 47 | $(C++) $^ -o $@ $(LDFLAGS) -static 48 | 49 | APP = pccserver pccclient 50 | 51 | all: $(APP) 52 | 53 | clean: 54 | rm -f *.o $(APP) 55 | 56 | install: 57 | export PATH=$(DIR):$$PATH 58 | -------------------------------------------------------------------------------- /src/app/pccclient.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/udt.h" 2 | 3 | #include 4 | #include 5 | 6 | #ifndef WIN32 7 | #include 8 | #include 9 | #include 10 | #include 11 | #else 12 | #include 13 | #include 14 | #include 15 | #endif 16 | 17 | using namespace std; 18 | 19 | #ifndef WIN32 20 | void* monitor(void*); 21 | #else 22 | DWORD WINAPI monitor(LPVOID); 23 | #endif 24 | 25 | void intHandler(int dummy) { 26 | //TODO (nathan jay): Print useful summary statistics. 27 | exit(0); 28 | } 29 | 30 | 31 | int main(int argc, char* argv[]) { 32 | if (argc < 4 || 0 == atoi(argv[3])) { 33 | cout << "usage: " << argv[0] 34 | << " server_ip server_port " 35 | << "[control algorithm] [utility tag] [utility parameter]"; 36 | cout << endl; 37 | return 0; 38 | } 39 | 40 | bool should_send = !strcmp(argv[1], "send"); 41 | 42 | signal(SIGINT, intHandler); 43 | 44 | // use this function to initialize the UDT library 45 | UDT::startup(); 46 | 47 | struct addrinfo hints, *local, *peer; 48 | 49 | memset(&hints, 0, sizeof(struct addrinfo)); 50 | 51 | hints.ai_flags = AI_PASSIVE; 52 | hints.ai_family = AF_INET; 53 | hints.ai_socktype = SOCK_STREAM; 54 | 55 | if (0 != getaddrinfo(NULL, "9000", &hints, &local)) { 56 | cout << "incorrect network address.\n" << endl; 57 | return 0; 58 | } 59 | 60 | // CUDT class constructor will be called here. 61 | UDTSOCKET client = 62 | UDT::socket(local->ai_family, local->ai_socktype, local->ai_protocol); 63 | 64 | // Set PCC control algorithm. 65 | string pcc_control_algorithm = "Vivace"; 66 | if (argc >= 5) { 67 | pcc_control_algorithm = argv[4]; 68 | } 69 | UDT::setsockopt(client, 0, UDT_PCC, &pcc_control_algorithm, 70 | pcc_control_algorithm.size()); 71 | // Set PCC utility tag and parameters. 72 | string utility_tag = "Vivace"; 73 | if (argc >= 6) { 74 | utility_tag = argv[5]; 75 | } 76 | UDT::setsockopt(client, 0, UDT_UTAG, &utility_tag, utility_tag.size()); 77 | if (utility_tag == "HybridAllegro" || utility_tag == "HybridVivace" || 78 | utility_tag == "Scavenger" || utility_tag == "RateLimiter" || 79 | utility_tag == "Hybrid") { 80 | if (argc < 7) { 81 | cout << "Parameter should be provided for [" << utility_tag 82 | << "] utility function" << endl; 83 | return 0; 84 | } else { 85 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(atof(argv[6])), 86 | sizeof(float)); 87 | } 88 | } 89 | if (utility_tag == "Proportional" || utility_tag == "TEST") { 90 | if (argc < 7) { 91 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(900), sizeof(float)); 92 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(11.35), sizeof(float)); 93 | } else if (argc == 7) { 94 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(atof(argv[6])), 95 | sizeof(float)); 96 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(11.35), sizeof(float)); 97 | } else { 98 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(atof(argv[6])), 99 | sizeof(float)); 100 | UDT::setsockopt(client, 0, UDT_UPARAM, new float(atof(argv[7])), 101 | sizeof(float)); 102 | } 103 | } 104 | 105 | #ifdef WIN32 106 | // Windows UDP issue 107 | // For better performance, modify HKLM\System\CurrentControlSet\Services\Afd\ 108 | // \Parameters\FastSendDatagramThreshold 109 | UDT::setsockopt(client, 0, UDT_MSS, new int(1052), sizeof(int)); 110 | #endif 111 | 112 | freeaddrinfo(local); 113 | 114 | if (0 != getaddrinfo(argv[2], argv[3], &hints, &peer)) { 115 | cout << "incorrect server/peer address. " << argv[1] << ":" << argv[2]; 116 | cout << endl; 117 | return 0; 118 | } 119 | 120 | // connect to the server, implict bind 121 | if (UDT::ERROR == UDT::connect(client, peer->ai_addr, peer->ai_addrlen)) { 122 | cout << "connect: " << UDT::getlasterror().getErrorMessage() << endl; 123 | return 0; 124 | } 125 | freeaddrinfo(peer); 126 | 127 | // using CC method 128 | int temp; 129 | 130 | int size = 100000; 131 | char* data = new char[size]; 132 | bzero(data, size); 133 | 134 | #ifndef WIN32 135 | pthread_create(new pthread_t, NULL, monitor, &client); 136 | #else 137 | CreateThread(NULL, 0, monitor, &client, 0, NULL); 138 | #endif 139 | 140 | if (should_send) { 141 | while (true) { 142 | int ssize = 0; 143 | int ss; 144 | while (ssize < size) { 145 | if (UDT::ERROR == 146 | (ss = UDT::send(client, data + ssize, size - ssize, 0))) { 147 | cout << "send:" << UDT::getlasterror().getErrorMessage() << endl; 148 | break; 149 | } 150 | 151 | ssize += ss; 152 | } 153 | 154 | if (ssize < size) { 155 | break; 156 | } 157 | } 158 | } else { 159 | while (true) { 160 | int rsize = 0; 161 | int rs; 162 | while (rsize < size) { 163 | if (UDT::ERROR == 164 | (rs = UDT::recv(client, data + rsize, size - rsize, 0))) { 165 | cout << "recv:" << UDT::getlasterror().getErrorMessage() << endl; 166 | break; 167 | } 168 | 169 | rsize += rs; 170 | } 171 | 172 | if (rsize < size) { 173 | break; 174 | } 175 | } 176 | } 177 | 178 | UDT::close(client); 179 | 180 | delete [] data; 181 | 182 | // use this function to release the UDT library 183 | UDT::cleanup(); 184 | 185 | return 1; 186 | } 187 | 188 | #ifndef WIN32 189 | void* monitor(void* s) 190 | #else 191 | DWORD WINAPI monitor(LPVOID s) 192 | #endif 193 | { 194 | UDTSOCKET u = *(UDTSOCKET*)s; 195 | 196 | UDT::TRACEINFO perf; 197 | 198 | cout << "SendRate(Mb/s)\tRTT(ms)\tCTotal\tLoss\tRecvACK\tRecvNAK" << endl; 199 | int i=0; 200 | while (true) { 201 | #ifndef WIN32 202 | usleep(1000000); 203 | #else 204 | Sleep(1000); 205 | #endif 206 | i++; 207 | if (UDT::ERROR == UDT::perfmon(u, &perf)) { 208 | cout << "perfmon: " << UDT::getlasterror().getErrorMessage() << endl; 209 | break; 210 | } 211 | cout << i << "\t" << perf.mbpsSendRate << "\t" << perf.msRTT << "\t" 212 | << perf.pktSentTotal << "\t" << perf.pktSndLossTotal << endl; 213 | } 214 | 215 | #ifndef WIN32 216 | return NULL; 217 | #else 218 | return 0; 219 | #endif 220 | } 221 | 222 | -------------------------------------------------------------------------------- /src/app/pccserver.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/udt.h" 2 | #include "test_util.h" 3 | 4 | #include 5 | #ifndef WIN32 6 | #include 7 | #include 8 | #include 9 | #include 10 | #else 11 | #include 12 | #include 13 | #include 14 | #endif 15 | 16 | using namespace std; 17 | 18 | #ifndef WIN32 19 | void* senddata(void*); 20 | void* recvdata(void*); 21 | void* recv_monitor(void* s); 22 | void* send_monitor(void* s); 23 | #else 24 | DWORD WINAPI recvdata(LPVOID); 25 | #endif 26 | 27 | int main(int argc, char* argv[]) { 28 | if ((strcmp(argv[1], "recv") && strcmp(argv[1], "send")) || 29 | (2 != argc && (3 != argc || 0 == atoi(argv[2])))) { 30 | cout << "usage: appserver [server_port]" << endl; 31 | return 0; 32 | } 33 | 34 | bool should_recv = !strcmp(argv[1], "recv"); 35 | 36 | // Automatically start up and clean up UDT module. 37 | UDTUpDown _udt_; 38 | 39 | addrinfo hints; 40 | addrinfo* res; 41 | 42 | memset(&hints, 0, sizeof(struct addrinfo)); 43 | 44 | hints.ai_flags = AI_PASSIVE; 45 | hints.ai_family = AF_INET; 46 | hints.ai_socktype = SOCK_STREAM; 47 | //hints.ai_socktype = SOCK_DGRAM; 48 | 49 | string service("9000"); 50 | if (argc == 3) { 51 | service = argv[2]; 52 | } 53 | 54 | if (0 != getaddrinfo(NULL, service.c_str(), &hints, &res)) { 55 | cout << "illegal port number or port is busy.\n" << endl; 56 | return 0; 57 | } 58 | 59 | UDTSOCKET serv = 60 | UDT::socket(res->ai_family, res->ai_socktype, res->ai_protocol); 61 | 62 | // UDT Options 63 | // UDT::setsockopt(serv, 0, UDT_CC, new CCCFactory, 64 | // sizeof(CCCFactory)); 65 | // UDT::setsockopt(serv, 0, UDT_MSS, new int(9000), sizeof(int)); 66 | // UDT::setsockopt(serv, 0, UDT_RCVBUF, new int(10000000), sizeof(int)); 67 | // UDT::setsockopt(serv, 0, UDP_RCVBUF, new int(10000000), sizeof(int)); 68 | 69 | if (UDT::ERROR == UDT::bind(serv, res->ai_addr, res->ai_addrlen)) { 70 | cout << "bind: " << UDT::getlasterror().getErrorMessage() << endl; 71 | return 0; 72 | } 73 | 74 | freeaddrinfo(res); 75 | 76 | cout << "server is ready at port: " << service << endl; 77 | 78 | if (UDT::ERROR == UDT::listen(serv, 10)) { 79 | cout << "listen: " << UDT::getlasterror().getErrorMessage() << endl; 80 | return 0; 81 | } 82 | 83 | sockaddr_storage clientaddr; 84 | int addrlen = sizeof(clientaddr); 85 | 86 | UDTSOCKET udt_socket; 87 | 88 | while (true) { 89 | if (UDT::INVALID_SOCK == 90 | (udt_socket = UDT::accept(serv, (sockaddr*)&clientaddr, &addrlen))) { 91 | cout << "accept: " << UDT::getlasterror().getErrorMessage() << endl; 92 | return 0; 93 | } 94 | 95 | char clienthost[NI_MAXHOST]; 96 | char clientservice[NI_MAXSERV]; 97 | getnameinfo((sockaddr *)&clientaddr, addrlen, clienthost, 98 | sizeof(clienthost), clientservice, sizeof(clientservice), 99 | NI_NUMERICHOST|NI_NUMERICSERV); 100 | cout << "new connection: " << clienthost << ":" << clientservice << endl; 101 | 102 | #ifndef WIN32 103 | pthread_t worker_thread; 104 | if (should_recv) { 105 | pthread_create(&worker_thread, NULL, recvdata, new UDTSOCKET(udt_socket)); 106 | } else { 107 | pthread_create(&worker_thread, NULL, senddata, new UDTSOCKET(udt_socket)); 108 | } 109 | pthread_detach(worker_thread); 110 | #else 111 | if (should_recv) { 112 | CreateThread(NULL, 0, recvdata, new UDTSOCKET(udt_socket), 0, NULL); 113 | } else { 114 | CreateThread(NULL, 0, senddata, new UDTSOCKET(udt_socket), 0, NULL); 115 | } 116 | #endif 117 | } 118 | 119 | UDT::close(serv); 120 | 121 | return 0; 122 | } 123 | 124 | #ifndef WIN32 125 | void* senddata(void* usocket) 126 | #else 127 | DWORD WINAPI senddata(LPVOID usocket) 128 | #endif 129 | { 130 | UDTSOCKET sender = *(UDTSOCKET*)usocket; 131 | delete (UDTSOCKET*)usocket; 132 | pthread_create(new pthread_t, NULL, send_monitor, &sender); 133 | char* data; 134 | int size = 100000000; 135 | data = new char[size]; 136 | 137 | while (true) { 138 | int ssize = 0; 139 | int ss; 140 | while (ssize < size) { 141 | if (UDT::ERROR == 142 | (ss = UDT::send(sender, data + ssize, size - ssize, 0))) { 143 | cout << "send:" << UDT::getlasterror().getErrorMessage() << endl; 144 | break; 145 | } 146 | ssize += ss; 147 | } 148 | 149 | if (ssize < size) { 150 | break; 151 | } 152 | } 153 | 154 | delete [] data; 155 | 156 | UDT::close(sender); 157 | 158 | #ifndef WIN32 159 | return NULL; 160 | #else 161 | return 0; 162 | #endif 163 | } 164 | 165 | #ifndef WIN32 166 | void* recvdata(void* usocket) 167 | #else 168 | DWORD WINAPI recvdata(LPVOID usocket) 169 | #endif 170 | { 171 | UDTSOCKET recver = *(UDTSOCKET*)usocket; 172 | delete (UDTSOCKET*)usocket; 173 | pthread_create(new pthread_t, NULL, recv_monitor, &recver); 174 | char* data; 175 | int size = 100000000; 176 | data = new char[size]; 177 | 178 | while (true) { 179 | int rsize = 0; 180 | int rs; 181 | while (rsize < size) { 182 | int rcv_size; 183 | int var_size = sizeof(int); 184 | // UDT::getsockopt(recver, 0, UDT_RCVDATA, &rcv_size, &var_size); 185 | if (UDT::ERROR == 186 | (rs = UDT::recv(recver, data + rsize, size - rsize, 0))) { 187 | cout << "recv:" << UDT::getlasterror().getErrorMessage() << endl; 188 | break; 189 | } 190 | 191 | rsize += rs; 192 | } 193 | 194 | if (rsize < size) { 195 | break; 196 | } 197 | } 198 | 199 | delete [] data; 200 | 201 | UDT::close(recver); 202 | 203 | #ifndef WIN32 204 | return NULL; 205 | #else 206 | return 0; 207 | #endif 208 | } 209 | 210 | #ifndef WIN32 211 | void* recv_monitor(void* s) 212 | #else 213 | DWORD WINAPI recv_monitor(LPVOID s) 214 | #endif 215 | { 216 | UDTSOCKET u = *(UDTSOCKET*)s; 217 | int i = 0; 218 | 219 | UDT::TRACEINFO perf; 220 | 221 | cout << "Recv Rate(Mb/s)\tRTT(ms)\tPackets Recvd" << endl; 222 | 223 | while (true) { 224 | ++i; 225 | #ifndef WIN32 226 | sleep(1); 227 | #else 228 | Sleep(1000); 229 | #endif 230 | 231 | if (UDT::ERROR == UDT::perfmon(u, &perf)) { 232 | cout << "perfmon: " << UDT::getlasterror().getErrorMessage() << endl; 233 | break; 234 | } 235 | 236 | cout << perf.mbpsRecvRate << "\t\t" << perf.msRTT << "\t" 237 | << perf.pktRecv << "\t\t" << endl; 238 | } 239 | 240 | #ifndef WIN32 241 | return NULL; 242 | #else 243 | return 0; 244 | #endif 245 | } 246 | 247 | #ifndef WIN32 248 | void* send_monitor(void* s) 249 | #else 250 | DWORD WINAPI send_monitor(LPVOID s) 251 | #endif 252 | { 253 | UDTSOCKET u = *(UDTSOCKET*)s; 254 | int i = 0; 255 | 256 | UDT::TRACEINFO perf; 257 | 258 | cout << "Send Rate(Mb/s)\tRTT(ms)\t\tSent\t\tLost" << endl; 259 | 260 | while (true) { 261 | ++i; 262 | #ifndef WIN32 263 | sleep(1); 264 | #else 265 | Sleep(1000); 266 | #endif 267 | 268 | if (UDT::ERROR == UDT::perfmon(u, &perf)) { 269 | cout << "perfmon: " << UDT::getlasterror().getErrorMessage() << endl; 270 | break; 271 | } 272 | 273 | cout << perf.mbpsSendRate << "\t\t" << perf.msRTT << "\t" 274 | << perf.pktSentTotal << "\t" << perf.pktSndLossTotal << "\t" << endl; 275 | } 276 | 277 | #ifndef WIN32 278 | return NULL; 279 | #else 280 | return 0; 281 | #endif 282 | } 283 | -------------------------------------------------------------------------------- /src/core/Makefile: -------------------------------------------------------------------------------- 1 | C++ = g++ -g -std=c++0x 2 | 3 | ifndef os 4 | os = LINUX 5 | endif 6 | 7 | ifndef arch 8 | arch = IA32 9 | endif 10 | 11 | CCFLAGS = -fPIC -Wall -Wextra -D$(os) -finline-functions -O3 -fno-strict-aliasing #-msse3 12 | 13 | ifeq ($(arch), IA32) 14 | CCFLAGS += -DIA32 15 | endif 16 | 17 | ifeq ($(arch), POWERPC) 18 | CCFLAGS += -mcpu=powerpc 19 | endif 20 | 21 | ifeq ($(arch), SPARC) 22 | CCFLAGS += -DSPARC 23 | endif 24 | 25 | ifeq ($(arch), IA64) 26 | CCFLAGS += -DIA64 27 | endif 28 | 29 | ifeq ($(arch), AMD64) 30 | CCFLAGS += -DAMD64 31 | endif 32 | 33 | OBJS = ../pcc/pcc_monitor_interval_queue.o ../pcc/pcc_utility_manager.o ../pcc/pcc_sender.o ../pcc/pcc_vivace_sender.o md5.o common.o window.o list.o buffer.o packet.o channel.o queue.o ccc.o cache.o core.o epoll.o api.o 34 | DIR = $(shell pwd) 35 | 36 | all: libudt.so libudt.a udt 37 | 38 | %.o: %.cpp %.h udt.h 39 | $(C++) $(CCFLAGS) $< -c 40 | 41 | libudt.so: $(OBJS) 42 | ifneq ($(os), OSX) 43 | $(C++) -shared -o $@ $^ 44 | else 45 | $(C++) -dynamiclib -o libudt.dylib -lstdc++ -lpthread -lm $^ 46 | endif 47 | 48 | libudt.a: $(OBJS) 49 | ar -rcs $@ $^ 50 | 51 | udt: 52 | cp udt.h udt 53 | 54 | clean: 55 | rm -f *.o *.so *.dylib *.a udt 56 | 57 | install: 58 | export LD_LIBRARY_PATH=$(DIR):$$LD_LIBRARY_PATH 59 | -------------------------------------------------------------------------------- /src/core/api.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2010, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 09/28/2010 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_API_H__ 42 | #define __UDT_API_H__ 43 | 44 | #include "cache.h" 45 | #include "epoll.h" 46 | #include "packet.h" 47 | #include "queue.h" 48 | #include "udt.h" 49 | 50 | #include 51 | #include 52 | 53 | class CUDT; 54 | 55 | class CUDTSocket { 56 | public: 57 | CUDTSocket(); 58 | ~CUDTSocket(); 59 | 60 | // current socket state 61 | UDTSTATUS m_Status; 62 | 63 | // time when the socket is closed 64 | uint64_t m_TimeStamp; 65 | 66 | // IP version 67 | int m_iIPversion; 68 | // pointer to the local address of the socket 69 | sockaddr* m_pSelfAddr; 70 | // pointer to the peer address of the socket 71 | sockaddr* m_pPeerAddr; 72 | 73 | // socket ID 74 | UDTSOCKET m_SocketID; 75 | // ID of the listener socket; 0 means this is an independent socket 76 | UDTSOCKET m_ListenSocket; 77 | 78 | // peer socket ID 79 | UDTSOCKET m_PeerID; 80 | // initial sequence number, used to tell different connection from same 81 | // IP:port 82 | int32_t m_iISN; 83 | 84 | // pointer to the UDT entity 85 | CUDT* m_pUDT; 86 | 87 | // set of connections waiting for accept() 88 | std::set* m_pQueuedSockets; 89 | // set of accept()ed connections 90 | std::set* m_pAcceptSockets; 91 | 92 | // used to block "accept" call 93 | pthread_cond_t m_AcceptCond; 94 | // mutex associated to m_AcceptCond 95 | pthread_mutex_t m_AcceptLock; 96 | 97 | // maximum number of connections in queue 98 | unsigned int m_uiBackLog; 99 | 100 | // multiplexer ID 101 | int m_iMuxID; 102 | 103 | // lock this socket exclusively for control APIs: bind/listen/connect 104 | pthread_mutex_t m_ControlLock; 105 | 106 | private: 107 | CUDTSocket(const CUDTSocket&); 108 | CUDTSocket& operator=(const CUDTSocket&); 109 | }; 110 | 111 | //////////////////////////////////////////////////////////////////////////////// 112 | 113 | class CUDTUnited { 114 | friend class CUDT; 115 | friend class CRendezvousQueue; 116 | 117 | public: 118 | CUDTUnited(); 119 | ~CUDTUnited(); 120 | 121 | // Functionality: 122 | // initialize the UDT library. 123 | // Parameters: 124 | // None. 125 | // Returned value: 126 | // 0 if success, otherwise -1 is returned. 127 | int startup(); 128 | 129 | // Functionality: 130 | // release the UDT library. 131 | // Parameters: 132 | // None. 133 | // Returned value: 134 | // 0 if success, otherwise -1 is returned. 135 | int cleanup(); 136 | 137 | // Functionality: 138 | // Create a new UDT socket. 139 | // Parameters: 140 | // 0) [in] af: IP version, IPv4 (AF_INET) or IPv6 (AF_INET6). 141 | // 1) [in] type: socket type, SOCK_STREAM or SOCK_DGRAM 142 | // Returned value: 143 | // The new UDT socket ID, or INVALID_SOCK. 144 | UDTSOCKET newSocket(const int& af, const int& type); 145 | 146 | // Functionality: 147 | // Create a new UDT connection. 148 | // Parameters: 149 | // 0) [in] listen: the listening UDT socket; 150 | // 1) [in] peer: peer address. 151 | // 2) [in/out] hs: handshake information from peer side (in), negotiated 152 | // value (out); 153 | // Returned value: 154 | // If the new connection is successfully created: 1 success, 0 already 155 | // exist, -1 error. 156 | int newConnection(const UDTSOCKET listen, 157 | const sockaddr* peer, 158 | CHandShake* hs); 159 | 160 | // Functionality: 161 | // look up the UDT entity according to its ID. 162 | // Parameters: 163 | // 0) [in] u: the UDT socket ID. 164 | // Returned value: 165 | // Pointer to the UDT entity. 166 | CUDT* lookup(const UDTSOCKET u); 167 | 168 | // Functionality: 169 | // Check the status of the UDT socket. 170 | // Parameters: 171 | // 0) [in] u: the UDT socket ID. 172 | // Returned value: 173 | // UDT socket status, or NONEXIST if not found. 174 | UDTSTATUS getStatus(const UDTSOCKET u); 175 | 176 | // socket APIs 177 | int bind(const UDTSOCKET u, const sockaddr* name, const int& namelen); 178 | int bind(const UDTSOCKET u, UDPSOCKET udpsock); 179 | int listen(const UDTSOCKET u, const int& backlog); 180 | UDTSOCKET accept(const UDTSOCKET listen, sockaddr* addr, int* addrlen); 181 | int connect(const UDTSOCKET u, const sockaddr* name, const int& namelen); 182 | int close(const UDTSOCKET u); 183 | int getpeername(const UDTSOCKET u, sockaddr* name, int* namelen); 184 | int getsockname(const UDTSOCKET u, sockaddr* name, int* namelen); 185 | int select(ud_set* readfds, 186 | ud_set* writefds, 187 | ud_set* exceptfds, 188 | const timeval* timeout); 189 | int selectEx(const std::vector& fds, 190 | std::vector* readfds, 191 | std::vector* writefds, 192 | std::vector* exceptfds, 193 | int64_t msTimeOut); 194 | int epoll_create(); 195 | int epoll_add_usock(const int eid, 196 | const UDTSOCKET u, 197 | const int* events = NULL); 198 | int epoll_add_ssock(const int eid, 199 | const SYSSOCKET s, 200 | const int* events = NULL); 201 | int epoll_remove_usock(const int eid, const UDTSOCKET u); 202 | int epoll_remove_ssock(const int eid, const SYSSOCKET s); 203 | int epoll_wait(const int eid, 204 | std::set* readfds, 205 | std::set* writefds, 206 | int64_t msTimeOut, 207 | std::set* lrfds = NULL, 208 | std::set* lwfds = NULL); 209 | int epoll_release(const int eid); 210 | 211 | // Functionality: 212 | // record the UDT exception. 213 | // Parameters: 214 | // 0) [in] e: pointer to a UDT exception instance. 215 | // Returned value: 216 | // None. 217 | void setError(CUDTException* e); 218 | 219 | // Functionality: 220 | // look up the most recent UDT exception. 221 | // Parameters: 222 | // None. 223 | // Returned value: 224 | // pointer to a UDT exception instance. 225 | CUDTException* getError(); 226 | 227 | private: 228 | // stores all the socket structures 229 | std::map m_Sockets; 230 | 231 | // used to synchronize UDT API 232 | pthread_mutex_t m_ControlLock; 233 | 234 | // used to synchronize ID generation 235 | pthread_mutex_t m_IDLock; 236 | // seed to generate a new unique socket ID 237 | UDTSOCKET m_SocketID; 238 | 239 | // record sockets from peers to avoid repeated connection request, 240 | // int64_t = (socker_id << 30) + isn 241 | std::map > m_PeerRec; 242 | 243 | private: 244 | // thread local error record (last error) 245 | pthread_key_t m_TLSError; 246 | #ifndef WIN32 247 | static void TLSDestroy(void* e) { if (NULL != e) {delete (CUDTException*)e;} } 248 | #else 249 | std::map m_mTLSRecord; 250 | void checkTLSValue(); 251 | pthread_mutex_t m_TLSLock; 252 | #endif 253 | 254 | private: 255 | void connect_complete(const UDTSOCKET u); 256 | CUDTSocket* locate(const UDTSOCKET u); 257 | CUDTSocket* locate(const sockaddr* peer, 258 | const UDTSOCKET& id, 259 | const int32_t& isn); 260 | void updateMux(CUDTSocket* s, 261 | const sockaddr* addr = NULL, 262 | const UDPSOCKET* = NULL); 263 | void updateMux(CUDTSocket* s, const CUDTSocket* ls); 264 | 265 | private: 266 | // UDP multiplexer 267 | std::map m_mMultiplexer; 268 | pthread_mutex_t m_MultiplexerLock; 269 | 270 | private: 271 | // UDT network information cache 272 | CCache* m_pCache; 273 | 274 | private: 275 | volatile bool m_bClosing; 276 | pthread_mutex_t m_GCStopLock; 277 | pthread_cond_t m_GCStopCond; 278 | 279 | pthread_mutex_t m_InitLock; 280 | // number of startup() called by application 281 | int m_iInstanceCount; 282 | // if the GC thread is working (true) 283 | bool m_bGCStatus; 284 | 285 | pthread_t m_GCThread; 286 | #ifndef WIN32 287 | static void* garbageCollect(void*); 288 | #else 289 | static DWORD WINAPI garbageCollect(LPVOID); 290 | #endif 291 | 292 | // temporarily store closed sockets 293 | std::map m_ClosedSockets; 294 | 295 | void checkBrokenSockets(); 296 | void removeSocket(const UDTSOCKET u); 297 | 298 | private: 299 | // handling epoll data structures and events 300 | CEPoll m_EPoll; 301 | 302 | private: 303 | CUDTUnited(const CUDTUnited&); 304 | CUDTUnited& operator=(const CUDTUnited&); 305 | }; 306 | 307 | #endif 308 | -------------------------------------------------------------------------------- /src/core/buffer.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 05/05/2009 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_BUFFER_H__ 42 | #define __UDT_BUFFER_H__ 43 | 44 | #include "list.h" 45 | #include "queue.h" 46 | #include "udt.h" 47 | 48 | #include 49 | #include 50 | 51 | class LessThan { 52 | public: 53 | int operator() (const int32_t& a, const int32_t& b) { return b < a; } 54 | }; 55 | 56 | class CSndBuffer { 57 | public: 58 | CSndBuffer(const int& size = 64, const int& mss = 1464); 59 | ~CSndBuffer(); 60 | 61 | // Functionality: 62 | // Insert a user buffer into the sending list. 63 | // Parameters: 64 | // 0) [in] data: pointer to the user data block. 65 | // 1) [in] len: size of the block. 66 | // 2) [in] ttl: time to live in milliseconds 67 | // 3) [in] order: if the block should be delivered in order, for DGRAM only 68 | // Returned value: 69 | // None. 70 | void addBuffer(const char* data, 71 | const int& len, 72 | const int& ttl = -1, 73 | const bool& order = false); 74 | 75 | // Functionality: 76 | // Read a block of data from file and insert it into the sending list. 77 | // Parameters: 78 | // 0) [in] ifs: input file stream. 79 | // 1) [in] len: size of the block. 80 | // Returned value: 81 | // actual size of data added from the file. 82 | int addBufferFromFile(std::fstream& ifs, const int& len); 83 | 84 | // Functionality: 85 | // Find data position to pack a DATA packet from the furthest reading point. 86 | // Parameters: 87 | // 0) [out] data: the pointer to the data position. 88 | // 1) [out] msgno: message number of the packet. 89 | // Returned value: 90 | // Actual length of data read. 91 | int readData(char** data, int32_t& msgno); 92 | 93 | // Functionality: 94 | // Find data position to pack a DATA packet for a retransmission. 95 | // Parameters: 96 | // 0) [out] data: the pointer to the data position. 97 | // 1) [in] offset: offset from the last ACK point. 98 | // 2) [out] msgno: message number of the packet. 99 | // 3) [out] msglen: length of the message 100 | // Returned value: 101 | // Actual length of data read. 102 | int readData(char** data, const int offset, int32_t& msgno, int& msglen); 103 | 104 | // Functionality: 105 | // Update the ACK point and may release/unmap/return the user data according 106 | // to the flag. 107 | // Parameters: 108 | // 0) [in] offset: number of packets acknowledged. 109 | // Returned value: 110 | // None. 111 | void ackData(const int& offset); 112 | 113 | // Functionality: 114 | // Read size of data still in the sending list. 115 | // Parameters: 116 | // None. 117 | // Returned value: 118 | // Current size of the data in the sending list. 119 | int getCurrBufSize() const; 120 | 121 | void resizeMSS(int size); 122 | 123 | private: 124 | void increase(); 125 | 126 | // used to synchronize buffer operation 127 | pthread_mutex_t m_BufLock; 128 | 129 | struct Block { 130 | // pointer to the data block 131 | char* m_pcData; 132 | // length of the block 133 | int m_iLength; 134 | 135 | // message number 136 | int32_t m_iMsgNo; 137 | int32_t m_iBufferNo; 138 | // original request time 139 | uint64_t m_OriginTime; 140 | // time to live (milliseconds) 141 | int m_iTTL; 142 | 143 | // next block 144 | Block* m_pNext; 145 | } *m_pBlock, *m_pFirstBlock, *m_pCurrBlock, *m_pLastBlock, *blockEnder; 146 | 147 | // m_pBlock: The head pointer 148 | // m_pFirstBlock: The first block 149 | // m_pCurrBlock: The current block 150 | // m_pLastBlock: The last block (if first == last, buffer is empty) 151 | int FirstBlock; 152 | 153 | // physical buffer 154 | struct Buffer { 155 | Block* first_block; 156 | // buffer 157 | char* m_pcData; 158 | // size 159 | int m_iSize; 160 | // next buffer 161 | Buffer* m_pNext; 162 | } *m_pBuffer, *FirstBuffer, *bufferEnder; 163 | 164 | // next message number 165 | int32_t m_iNextMsgNo; 166 | 167 | // buffer size (number of packets) 168 | int m_iSize; 169 | // maximum seqment/packet size 170 | int m_iMSS; 171 | 172 | // number of used blocks 173 | int m_iCount; 174 | 175 | int m_iBlockSize; 176 | 177 | CSndBuffer(const CSndBuffer&); 178 | CSndBuffer& operator=(const CSndBuffer&); 179 | // Block* findBlock(int offset); 180 | 181 | }; 182 | 183 | //////////////////////////////////////////////////////////////////////////////// 184 | 185 | class CRcvBuffer { 186 | public: 187 | CRcvBuffer(CUnitQueue* queue, 188 | int32_t first_seq_no, 189 | const int& bufsize = 65536); 190 | ~CRcvBuffer(); 191 | 192 | // Functionality: 193 | // Write data into the buffer. 194 | // Parameters: 195 | // 0) [in] unit: pointer to a data unit containing new packet 196 | // 1) [in] offset: offset from last ACK point. 197 | // Returned value: 198 | // 0 is success, -1 if data is repeated. 199 | int addData(CUnit* unit, int offset); 200 | 201 | // Functionality: 202 | // Read data into a user buffer. 203 | // Parameters: 204 | // 0) [in] data: pointer to user buffer. 205 | // 1) [in] len: length of user buffer. 206 | // Returned value: 207 | // size of data read. 208 | int readBuffer(char* data, const int& len); 209 | 210 | // Functionality: 211 | // Read data directly into file. 212 | // Parameters: 213 | // 0) [in] file: C++ file stream. 214 | // 1) [in] len: expected length of data to write into the file. 215 | // Returned value: 216 | // size of data read. 217 | int readBufferToFile(std::fstream& ofs, const int& len); 218 | 219 | // Functionality: 220 | // Update the ACK point of the buffer. 221 | // Parameters: 222 | // 0) [in] len: size of data to be acknowledged. 223 | // Returned value: 224 | // 1 if a user buffer is fulfilled, otherwise 0. 225 | void AckData(int32_t seq_no); 226 | 227 | // Functionality: 228 | // Query how many buffer space left for data receiving. 229 | // Parameters: 230 | // None. 231 | // Returned value: 232 | // size of available buffer space (including user buffer) for data receiving. 233 | int getAvailBufSize() const; 234 | 235 | // Functionality: 236 | // Query how many data has been continuously received (for reading). 237 | // Parameters: 238 | // None. 239 | // Returned value: 240 | // size of valid (continous) data for reading. 241 | int getRcvDataSize() const; 242 | 243 | // Functionality: 244 | // mark the message to be dropped from the message list. 245 | // Parameters: 246 | // 0) [in] msgno: message nuumer. 247 | // Returned value: 248 | // None. 249 | void dropMsg(const int32_t& msgno); 250 | 251 | // Functionality: 252 | // read a message. 253 | // Parameters: 254 | // 0) [out] data: buffer to write the message into. 255 | // 1) [in] len: size of the buffer. 256 | // Returned value: 257 | // actuall size of data read. 258 | int readMsg(char* data, const int& len); 259 | 260 | // Functionality: 261 | // Query how many messages are available now. 262 | // Parameters: 263 | // None. 264 | // Returned value: 265 | // number of messages available for recvmsg. 266 | int getRcvMsgNum(); 267 | 268 | private: 269 | bool scanMsg(int& start, int& end, bool& passack); 270 | 271 | // pointer to the protocol buffer 272 | CUnit** m_pUnit; 273 | // size of the protocol buffer 274 | int m_iSize; 275 | // the shared unit queue 276 | CUnitQueue* m_pUnitQueue; 277 | 278 | // the head position for I/O (inclusive) 279 | int m_iStartPos; 280 | // the last ACKed position (exclusive) 281 | int m_iLastAckPos; 282 | // EMPTY: m_iStartPos = m_iLastAckPos FULL: m_iStartPos = m_iLastAckPos + 1 283 | // the furthest data position 284 | int m_iMaxPos; 285 | 286 | // the starting read point of the first unit 287 | int m_iNotch; 288 | 289 | std::priority_queue, LessThan> ack_queue_; 290 | 291 | int32_t seq_offset_; 292 | 293 | CRcvBuffer(); 294 | CRcvBuffer(const CRcvBuffer&); 295 | CRcvBuffer& operator=(const CRcvBuffer&); 296 | }; 297 | 298 | #endif 299 | -------------------------------------------------------------------------------- /src/core/cache.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 05/05/2009 39 | *****************************************************************************/ 40 | 41 | #include "cache.h" 42 | #include "core.h" 43 | 44 | #include 45 | #ifdef WIN32 46 | #include 47 | #include 48 | #ifdef LEGACY_WIN32 49 | #include 50 | #endif 51 | #endif 52 | 53 | using namespace std; 54 | 55 | CInfoBlock& CInfoBlock::operator=(const CInfoBlock& obj) { 56 | std::copy(obj.m_piIP, obj.m_piIP + 3, m_piIP); 57 | m_iIPversion = obj.m_iIPversion; 58 | m_ullTimeStamp = obj.m_ullTimeStamp; 59 | m_iRTT = obj.m_iRTT; 60 | m_iBandwidth = obj.m_iBandwidth; 61 | m_iLossRate = obj.m_iLossRate; 62 | m_iReorderDistance = obj.m_iReorderDistance; 63 | m_dInterval = obj.m_dInterval; 64 | m_dCWnd = obj.m_dCWnd; 65 | 66 | return *this; 67 | } 68 | 69 | bool CInfoBlock::operator==(const CInfoBlock& obj) { 70 | if (m_iIPversion != obj.m_iIPversion) { 71 | return false; 72 | } else if (m_iIPversion == AF_INET) { 73 | return (m_piIP[0] == obj.m_piIP[0]); 74 | } 75 | 76 | for (int i = 0; i < 4; ++ i) { 77 | if (m_piIP[i] != obj.m_piIP[i]) { 78 | return false; 79 | } 80 | } 81 | 82 | return true; 83 | } 84 | 85 | CInfoBlock* CInfoBlock::clone() { 86 | CInfoBlock* obj = new CInfoBlock; 87 | 88 | std::copy(m_piIP, m_piIP + 3, obj->m_piIP); 89 | obj->m_iIPversion = m_iIPversion; 90 | obj->m_ullTimeStamp = m_ullTimeStamp; 91 | obj->m_iRTT = m_iRTT; 92 | obj->m_iBandwidth = m_iBandwidth; 93 | obj->m_iLossRate = m_iLossRate; 94 | obj->m_iReorderDistance = m_iReorderDistance; 95 | obj->m_dInterval = m_dInterval; 96 | obj->m_dCWnd = m_dCWnd; 97 | 98 | return obj; 99 | } 100 | 101 | int CInfoBlock::getKey() { 102 | if (m_iIPversion == AF_INET) { 103 | return m_piIP[0]; 104 | } 105 | 106 | return m_piIP[0] + m_piIP[1] + m_piIP[2] + m_piIP[3]; 107 | } 108 | 109 | void CInfoBlock::convert(const sockaddr* addr, const int& ver, uint32_t ip[]) { 110 | if (ver == AF_INET) { 111 | ip[0] = ((sockaddr_in*)addr)->sin_addr.s_addr; 112 | ip[1] = ip[2] = ip[3] = 0; 113 | } else { 114 | memcpy((char*)ip, (char*)((sockaddr_in6*)addr)->sin6_addr.s6_addr, 16); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/core/cache.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/27/2011 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_CACHE_H__ 42 | #define __UDT_CACHE_H__ 43 | 44 | #include "common.h" 45 | #include "udt.h" 46 | 47 | #include 48 | #include 49 | 50 | class CCacheItem { 51 | public: 52 | virtual ~CCacheItem() {} 53 | 54 | virtual CCacheItem& operator=(const CCacheItem&) = 0; 55 | 56 | // The "==" operator SHOULD only compare key values. 57 | virtual bool operator==(const CCacheItem&) = 0; 58 | 59 | // Functionality: 60 | // get a deep copy clone of the current item 61 | // Parameters: 62 | // None. 63 | // Returned value: 64 | // Pointer to the new item, or NULL if failed. 65 | virtual CCacheItem* clone() = 0; 66 | 67 | // Functionality: 68 | // get a random key value between 0 and MAX_INT to be used for the hash in 69 | // cache 70 | // Parameters: 71 | // None. 72 | // Returned value: 73 | // A random hash key. 74 | virtual int getKey() = 0; 75 | 76 | // If there is any shared resources between the cache item and its clone, 77 | // the shared resource should be released by this function. 78 | virtual void release() {} 79 | }; 80 | 81 | template class CCache { 82 | public: 83 | CCache(const int& size = 1024) : m_iMaxSize(size), 84 | m_iHashSize(size * 3), 85 | m_iCurrSize(0) { 86 | m_vHashPtr.resize(m_iHashSize); 87 | CGuard::createMutex(m_Lock); 88 | } 89 | 90 | ~CCache() { 91 | clear(); 92 | CGuard::releaseMutex(m_Lock); 93 | } 94 | 95 | // Functionality: 96 | // find the matching item in the cache. 97 | // Parameters: 98 | // 0) [in/out] data: storage for the retrieved item; initially it must 99 | // carry the key information 100 | // Returned value: 101 | // 0 if found a match, otherwise -1. 102 | int lookup(T* data) { 103 | CGuard cacheguard(m_Lock); 104 | 105 | int key = data->getKey(); 106 | if (key < 0) { 107 | return -1; 108 | } 109 | if (key >= m_iMaxSize) { 110 | key %= m_iHashSize; 111 | } 112 | 113 | const ItemPtrList& item_list = m_vHashPtr[key]; 114 | for (typename ItemPtrList::const_iterator i = item_list.begin(); 115 | i != item_list.end(); ++ i) { 116 | if (*data == ***i) { 117 | // copy the cached info 118 | *data = ***i; 119 | return 0; 120 | } 121 | } 122 | 123 | return -1; 124 | } 125 | 126 | // Functionality: 127 | // update an item in the cache, or insert one if it doesn't exist; oldest 128 | // item may be removed 129 | // Parameters: 130 | // 0) [in] data: the new item to updated/inserted to the cache 131 | // Returned value: 132 | // 0 if success, otherwise -1. 133 | int update(T* data) { 134 | CGuard cacheguard(m_Lock); 135 | 136 | int key = data->getKey(); 137 | if (key < 0) { 138 | return -1; 139 | } 140 | if (key >= m_iMaxSize) { 141 | key %= m_iHashSize; 142 | } 143 | 144 | T* curr = NULL; 145 | 146 | ItemPtrList& item_list = m_vHashPtr[key]; 147 | for (typename ItemPtrList::iterator i = item_list.begin(); 148 | i != item_list.end(); ++ i) { 149 | if (*data == ***i) { 150 | // update the existing entry with the new value 151 | ***i = *data; 152 | curr = **i; 153 | 154 | // remove the current entry 155 | m_StorageList.erase(*i); 156 | item_list.erase(i); 157 | 158 | // re-insert to the front 159 | m_StorageList.push_front(curr); 160 | item_list.push_front(m_StorageList.begin()); 161 | 162 | return 0; 163 | } 164 | } 165 | 166 | // create new entry and insert to front 167 | curr = data->clone(); 168 | m_StorageList.push_front(curr); 169 | item_list.push_front(m_StorageList.begin()); 170 | 171 | ++ m_iCurrSize; 172 | if (m_iCurrSize >= m_iMaxSize) { 173 | // Cache overflow, remove oldest entry. 174 | T* last_data = m_StorageList.back(); 175 | int last_key = last_data->getKey() % m_iHashSize; 176 | 177 | item_list = m_vHashPtr[last_key]; 178 | for (typename ItemPtrList::iterator i = item_list.begin(); 179 | i != item_list.end(); ++ i) { 180 | if (*last_data == ***i) { 181 | item_list.erase(i); 182 | break; 183 | } 184 | } 185 | 186 | last_data->release(); 187 | delete last_data; 188 | m_StorageList.pop_back(); 189 | --m_iCurrSize; 190 | } 191 | 192 | return 0; 193 | } 194 | 195 | // Functionality: 196 | // Specify the cache size (i.e., max number of items). 197 | // Parameters: 198 | // 0) [in] size: max cache size. 199 | // Returned value: 200 | // None. 201 | void setSizeLimit(const int& size) { 202 | m_iMaxSize = size; 203 | m_iHashSize = size * 3; 204 | m_vHashPtr.resize(m_iHashSize); 205 | } 206 | 207 | // Functionality: 208 | // Clear all entries in the cache, restore to initialization state. 209 | // Parameters: 210 | // None. 211 | // Returned value: 212 | // None. 213 | void clear() { 214 | for (typename std::list::iterator i = m_StorageList.begin(); 215 | i != m_StorageList.end(); ++ i) { 216 | (*i)->release(); 217 | delete *i; 218 | } 219 | m_StorageList.clear(); 220 | for (typename std::vector::iterator i = m_vHashPtr.begin(); 221 | i != m_vHashPtr.end(); ++ i) { 222 | i->clear(); 223 | } 224 | m_iCurrSize = 0; 225 | } 226 | 227 | private: 228 | std::list m_StorageList; 229 | typedef typename std::list::iterator ItemPtr; 230 | typedef std::list ItemPtrList; 231 | std::vector m_vHashPtr; 232 | 233 | int m_iMaxSize; 234 | int m_iHashSize; 235 | int m_iCurrSize; 236 | 237 | pthread_mutex_t m_Lock; 238 | 239 | CCache(const CCache&); 240 | CCache& operator=(const CCache&); 241 | }; 242 | 243 | 244 | class CInfoBlock { 245 | public: 246 | // IP address, machine read only, not human readable format 247 | uint32_t m_piIP[4]; 248 | // IP version 249 | int m_iIPversion; 250 | // last update time 251 | uint64_t m_ullTimeStamp; 252 | // RTT 253 | int m_iRTT; 254 | // estimated bandwidth 255 | int m_iBandwidth; 256 | // average loss rate 257 | int m_iLossRate; 258 | // packet reordering distance 259 | int m_iReorderDistance; 260 | // inter-packet time, congestion control 261 | double m_dInterval; 262 | // congestion window size, congestion control 263 | double m_dCWnd; 264 | 265 | virtual ~CInfoBlock() {} 266 | virtual CInfoBlock& operator=(const CInfoBlock& obj); 267 | virtual bool operator==(const CInfoBlock& obj); 268 | virtual CInfoBlock* clone(); 269 | virtual int getKey(); 270 | virtual void release() {} 271 | 272 | // Functionality: 273 | // convert sockaddr structure to an integer array 274 | // Parameters: 275 | // 0) [in] addr: network address 276 | // 1) [in] ver: IP version 277 | // 2) [out] ip: the result machine readable IP address in integer array 278 | // Returned value: 279 | // None. 280 | static void convert(const sockaddr* addr, const int& ver, uint32_t ip[]); 281 | }; 282 | 283 | #endif 284 | -------------------------------------------------------------------------------- /src/core/ccc.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 03/17/2011 39 | *****************************************************************************/ 40 | 41 | #include "ccc.h" 42 | #include "core.h" 43 | 44 | #include 45 | #include 46 | 47 | CCC::CCC() : m_iSYNInterval(CUDT::m_iSYNInterval), 48 | m_dPktSndPeriod(1.0), 49 | m_dCWndSize(16.0), 50 | m_iBandwidth(), 51 | m_dMaxCWndSize(), 52 | m_iMSS(), 53 | m_iSndCurrSeqNo(), 54 | m_iRcvRate(), 55 | m_iRTT(), 56 | m_pcParam(NULL), 57 | m_iPSize(0), 58 | m_UDT(), 59 | m_iACKPeriod(0), 60 | m_iACKInterval(0), 61 | m_bUserDefinedRTO(true), 62 | m_iRTO(-1), 63 | m_PerfInfo() {} 64 | 65 | CCC::~CCC() { 66 | delete [] m_pcParam; 67 | } 68 | 69 | void CCC::setACKTimer(const int& msINT) { 70 | m_iACKPeriod = msINT; 71 | 72 | if (m_iACKPeriod > m_iSYNInterval) { 73 | m_iACKPeriod = m_iSYNInterval; 74 | } 75 | } 76 | 77 | void CCC::setACKInterval(const int& pktINT) { 78 | m_iACKInterval = pktINT; 79 | } 80 | 81 | void CCC::setRTO(const int& usRTO) { 82 | m_bUserDefinedRTO = true; 83 | m_iRTO = usRTO; 84 | } 85 | 86 | void CCC::sendCustomMsg(CPacket& pkt) const { 87 | CUDT* u = CUDT::getUDTHandle(m_UDT); 88 | 89 | if (NULL != u) { 90 | pkt.m_iID = u->m_PeerID; 91 | u->m_pSndQueue->sendto(u->m_pPeerAddr, pkt); 92 | } 93 | } 94 | 95 | const CPerfMon* CCC::getPerfInfo() { 96 | try { 97 | CUDT* u = CUDT::getUDTHandle(m_UDT); 98 | if (NULL != u) { 99 | u->sample(&m_PerfInfo, false); 100 | } 101 | } catch (...) { 102 | return NULL; 103 | } 104 | 105 | return &m_PerfInfo; 106 | } 107 | 108 | void CCC::setMSS(const int& mss) { 109 | m_iMSS = mss; 110 | } 111 | 112 | void CCC::setBandwidth(const int& bw) { 113 | m_iBandwidth = bw; 114 | } 115 | 116 | void CCC::setSndCurrSeqNo(const int32_t& seqno) { 117 | m_iSndCurrSeqNo = seqno; 118 | } 119 | 120 | void CCC::setRcvRate(const int& rcvrate) { 121 | m_iRcvRate = rcvrate; 122 | } 123 | 124 | void CCC::setMaxCWndSize(const int& cwnd) { 125 | m_dMaxCWndSize = cwnd; 126 | } 127 | 128 | void CCC::setRTT(const int& rtt) { 129 | m_iRTT = rtt; 130 | } 131 | 132 | void CCC::setUserParam(const char* param, const int& size) { 133 | delete [] m_pcParam; 134 | m_pcParam = new char[size]; 135 | memcpy(m_pcParam, param, size); 136 | m_iPSize = size; 137 | } 138 | 139 | CUDTCC::CUDTCC() : m_iRCInterval(), 140 | m_LastRCTime(), 141 | m_bSlowStart(), 142 | m_iLastAck(), 143 | m_bLoss(), 144 | m_iLastDecSeq(), 145 | m_dLastDecPeriod(), 146 | m_iNAKCount(), 147 | m_iDecRandom(), 148 | m_iAvgNAKNum(), 149 | m_iDecCount() {} 150 | 151 | void CUDTCC::init() { 152 | m_iRCInterval = m_iSYNInterval; 153 | m_LastRCTime = CTimer::getTime(); 154 | setACKTimer(m_iRCInterval); 155 | 156 | m_bSlowStart = true; 157 | m_iLastAck = m_iSndCurrSeqNo; 158 | m_bLoss = false; 159 | m_iLastDecSeq = CSeqNo::decseq(m_iLastAck); 160 | m_dLastDecPeriod = 1; 161 | m_iAvgNAKNum = 0; 162 | m_iNAKCount = 0; 163 | m_iDecRandom = 1; 164 | 165 | m_dCWndSize = 16; 166 | m_dPktSndPeriod = 1; 167 | } 168 | 169 | void CUDTCC::onACK(const int32_t& /*ack*/) { 170 | return; 171 | /* int64_t B = 0; 172 | double inc = 0; 173 | 174 | uint64_t currtime = CTimer::getTime(); 175 | if (currtime - m_LastRCTime < (uint64_t)m_iRCInterval) { 176 | return; 177 | } 178 | 179 | m_LastRCTime = currtime; 180 | 181 | if (m_bSlowStart) { 182 | m_dCWndSize += CSeqNo::seqlen(m_iLastAck, ack); 183 | m_iLastAck = ack; 184 | 185 | if (m_dCWndSize > m_dMaxCWndSize) { 186 | m_bSlowStart = false; 187 | if (m_iRcvRate > 0) { 188 | m_dPktSndPeriod = 1000000.0 / m_iRcvRate; 189 | } else { 190 | m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval); 191 | } 192 | } 193 | } else { 194 | m_dCWndSize = m_iRcvRate / 1000000.0 * (m_iRTT + m_iRCInterval) + 16; 195 | } 196 | 197 | // During Slow Start, no rate increase 198 | if (m_bSlowStart) { 199 | goto RATE_LIMIT; 200 | } 201 | 202 | if (m_bLoss) { 203 | m_bLoss = false; 204 | goto RATE_LIMIT; 205 | } 206 | 207 | B = (int64_t)(m_iBandwidth - 1000000.0 / m_dPktSndPeriod); 208 | if (m_dPktSndPeriod > m_dLastDecPeriod && (m_iBandwidth / 9) < B) { 209 | B = m_iBandwidth / 9; 210 | } 211 | if (B <= 0) { 212 | inc = 1.0 / m_iMSS; 213 | } else { 214 | // inc = max(10 ^ ceil(log10( B * MSS * 8 ) * Beta / MSS, 1/MSS) 215 | // Beta = 1.5 * 10^(-6) 216 | 217 | inc = pow(10.0, ceil(log10(B * m_iMSS * 8.0))) * 0.0000015 / m_iMSS; 218 | 219 | if (inc < 1.0/m_iMSS) { 220 | inc = 1.0/m_iMSS; 221 | } 222 | } 223 | 224 | m_dPktSndPeriod = (m_dPktSndPeriod * m_iRCInterval) / (m_dPktSndPeriod * inc + m_iRCInterval); 225 | 226 | RATE_LIMIT: 227 | //set maximum transfer rate 228 | if (NULL != m_pcParam && m_iPSize == 8) { 229 | int64_t maxSR = *(int64_t*)m_pcParam; 230 | if (maxSR <= 0) { 231 | return; 232 | } 233 | 234 | double minSP = 1000000.0 / (double(maxSR) / m_iMSS); 235 | if (m_dPktSndPeriod < minSP) { 236 | m_dPktSndPeriod = minSP; 237 | } 238 | } */ 239 | } 240 | 241 | void CUDTCC::onLoss(const int32_t* /*losslist*/, const int&) { 242 | return; 243 | /* // Slow Start stopped, if it hasn't yet 244 | if (m_bSlowStart) { 245 | m_bSlowStart = false; 246 | if (m_iRcvRate > 0) { 247 | m_dPktSndPeriod = 1000000.0 / m_iRcvRate; 248 | } else { 249 | m_dPktSndPeriod = m_dCWndSize / (m_iRTT + m_iRCInterval); 250 | } 251 | } 252 | 253 | m_bLoss = true; 254 | 255 | if (CSeqNo::seqcmp(losslist[0] & 0x7FFFFFFF, m_iLastDecSeq) > 0) { 256 | m_dLastDecPeriod = m_dPktSndPeriod; 257 | m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125); 258 | 259 | m_iAvgNAKNum = (int)ceil(m_iAvgNAKNum * 0.875 + m_iNAKCount * 0.125); 260 | m_iNAKCount = 1; 261 | m_iDecCount = 1; 262 | 263 | m_iLastDecSeq = m_iSndCurrSeqNo; 264 | 265 | // remove global synchronization using randomization 266 | srand(m_iLastDecSeq); 267 | m_iDecRandom = (int)ceil(m_iAvgNAKNum * (double(rand()) / RAND_MAX)); 268 | if (m_iDecRandom < 1) { 269 | m_iDecRandom = 1; 270 | } 271 | } else if (m_iDecCount ++ < 5 && 0 == ++ m_iNAKCount % m_iDecRandom) { 272 | // 0.875^5 = 0.51, rate should not be decreased by more than half within a 273 | // congestion period 274 | m_dPktSndPeriod = ceil(m_dPktSndPeriod * 1.125); 275 | m_iLastDecSeq = m_iSndCurrSeqNo; 276 | } */ 277 | } 278 | 279 | bool CUDTCC::onTimeout(int /*total*/, 280 | int /*loss*/, 281 | double /*in_time*/, 282 | int /*current*/, 283 | int /*endMonitor*/, 284 | double /*rtt*/) { 285 | return false; 286 | } 287 | -------------------------------------------------------------------------------- /src/core/ccc.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 05/05/2009 39 | *****************************************************************************/ 40 | 41 | 42 | #ifndef __UDT_CCC_H__ 43 | #define __UDT_CCC_H__ 44 | 45 | #include "packet.h" 46 | #include "udt.h" 47 | 48 | class UDT_API CCC { 49 | friend class CUDT; 50 | friend class PccSender; 51 | 52 | public: 53 | CCC(); 54 | virtual ~CCC(); 55 | 56 | private: 57 | CCC(const CCC&); 58 | CCC& operator=(const CCC&) {return *this;} 59 | 60 | public: 61 | // Functionality: 62 | // Callback function to be called (only) at the start of a UDT connection. 63 | // note that this is different from CCC(), which is always called. 64 | // Parameters: 65 | // None. 66 | // Returned value: 67 | // None. 68 | virtual void init() {} 69 | 70 | // Functionality: 71 | // Callback function to be called when a UDT connection is closed. 72 | // Parameters: 73 | // None. 74 | // Returned value: 75 | // None. 76 | virtual void close() {} 77 | 78 | // Functionality: 79 | // Callback function to be called when an ACK packet is received. 80 | // Parameters: 81 | // 0) [in] ackno: the data sequence number acknowledged by this ACK. 82 | // Returned value: 83 | // None. 84 | virtual void onACK(const int32_t&) {} 85 | 86 | // Functionality: 87 | // Callback function to be called when a loss report is received. 88 | // Parameters: 89 | // 0) [in] losslist: list of sequence number of packets, in the format 90 | // describled in packet.cpp. 91 | // 1) [in] size: length of the loss list. 92 | // Returned value: 93 | // None. 94 | virtual void onLoss(const int32_t*, const int&) {} 95 | 96 | // Functionality: 97 | // Callback function to be called when a timeout event occurs. 98 | // Parameters: 99 | // None. 100 | // Returned value: 101 | // None. 102 | virtual bool onTimeout(int /*total*/, 103 | int /*loss*/, 104 | double /*in_time*/, 105 | int /*current*/, 106 | int /*endMonitor*/, 107 | double /*rtt*/) {return false;} 108 | 109 | // Functionality: 110 | // Callback function to be called when a data is sent. 111 | // Parameters: 112 | // 0) [in] seqno: the data sequence number. 113 | // 1) [in] size: the payload size. 114 | // Returned value: 115 | // None. 116 | virtual void onPktSent(const CPacket*) {} 117 | 118 | // Functionality: 119 | // Callback function to be called when a data is received. 120 | // Parameters: 121 | // 0) [in] seqno: the data sequence number. 122 | // 1) [in] size: the payload size. 123 | // Returned value: 124 | // None. 125 | virtual void onPktReceived(const CPacket*) {} 126 | 127 | // Functionality: 128 | // Callback function to Process a user defined packet. 129 | // Parameters: 130 | // 0) [in] pkt: the user defined packet. 131 | // Returned value: 132 | // None. 133 | virtual void processCustomMsg(const CPacket*) {} 134 | 135 | virtual void onMonitorEnds(int /*total*/, 136 | int /*loss*/, 137 | double /*time*/, 138 | int /*skip*/, 139 | int /*num*/, 140 | double /*rtt*/, 141 | double) {} 142 | 143 | virtual void onMonitorStart(int /*monitor_number*/, int&, int&, double&) {} 144 | 145 | protected: 146 | // Functionality: 147 | // Set periodical acknowldging and the ACK period. 148 | // Parameters: 149 | // 0) [in] msINT: the period to send an ACK. 150 | // Returned value: 151 | // None. 152 | void setACKTimer(const int& msINT); 153 | 154 | // Functionality: 155 | // Set packet-based acknowldging and the number of packets to send an ACK. 156 | // Parameters: 157 | // 0) [in] pktINT: the number of packets to send an ACK. 158 | // Returned value: 159 | // None. 160 | void setACKInterval(const int& pktINT); 161 | 162 | // Functionality: 163 | // Set RTO value. 164 | // Parameters: 165 | // 0) [in] msRTO: RTO in macroseconds. 166 | // Returned value: 167 | // None. 168 | void setRTO(const int& usRTO); 169 | 170 | // Functionality: 171 | // Send a user defined control packet. 172 | // Parameters: 173 | // 0) [in] pkt: user defined packet. 174 | // Returned value: 175 | // None. 176 | void sendCustomMsg(CPacket& pkt) const; 177 | 178 | // Functionality: 179 | // retrieve performance information. 180 | // Parameters: 181 | // None. 182 | // Returned value: 183 | // Pointer to a performance info structure. 184 | const CPerfMon* getPerfInfo(); 185 | 186 | // Functionality: 187 | // Set user defined parameters. 188 | // Parameters: 189 | // 0) [in] param: the paramters in one buffer. 190 | // 1) [in] size: the size of the buffer. 191 | // Returned value: 192 | // None. 193 | void setUserParam(const char* param, const int& size); 194 | 195 | private: 196 | void setMSS(const int& mss); 197 | void setMaxCWndSize(const int& cwnd); 198 | void setBandwidth(const int& bw); 199 | void setSndCurrSeqNo(const int32_t& seqno); 200 | void setRcvRate(const int& rcvrate); 201 | void setRTT(const int& rtt); 202 | 203 | protected: 204 | // UDT constant parameter, SYN 205 | const int32_t& m_iSYNInterval; 206 | 207 | // Packet sending period, in microseconds 208 | double m_dPktSndPeriod; 209 | // Congestion window size, in packets 210 | double m_dCWndSize; 211 | 212 | // estimated bandwidth, packets per second 213 | int m_iBandwidth; 214 | // maximum cwnd size, in packets 215 | double m_dMaxCWndSize; 216 | 217 | // Maximum Packet Size, including all packet headers 218 | int m_iMSS; 219 | // current maximum seq no sent out 220 | int32_t m_iSndCurrSeqNo; 221 | // packet arrive rate at receiver side, packets per second 222 | int m_iRcvRate; 223 | // current estimated RTT, microsecond 224 | int m_iRTT; 225 | 226 | // user defined parameter 227 | char* m_pcParam; 228 | // size of m_pcParam 229 | int m_iPSize; 230 | volatile int starting_phase; 231 | private: 232 | // The UDT entity that this congestion control algorithm is bound to 233 | UDTSOCKET m_UDT; 234 | 235 | // Periodical timer to send an ACK, in milliseconds 236 | int m_iACKPeriod; 237 | // How many packets to send one ACK, in packets 238 | int m_iACKInterval; 239 | 240 | // if the RTO value is defined by users 241 | bool m_bUserDefinedRTO; 242 | // RTO value, microseconds 243 | int m_iRTO; 244 | 245 | // protocol statistics information 246 | CPerfMon m_PerfInfo; 247 | }; 248 | 249 | class CCCVirtualFactory { 250 | public: 251 | virtual ~CCCVirtualFactory() {} 252 | 253 | virtual CCC* create() = 0; 254 | virtual CCCVirtualFactory* clone() = 0; 255 | }; 256 | 257 | template 258 | class CCCFactory: public CCCVirtualFactory { 259 | public: 260 | virtual ~CCCFactory() {} 261 | 262 | virtual CCC* create() {return new T;} 263 | virtual CCCVirtualFactory* clone() {return new CCCFactory;} 264 | }; 265 | 266 | class CUDTCC: public CCC { 267 | public: 268 | CUDTCC(); 269 | 270 | virtual void init(); 271 | virtual void onACK(const int32_t&); 272 | virtual void onLoss(const int32_t*, const int&); 273 | virtual bool onTimeout(int /*total*/, 274 | int /*loss*/, 275 | double /*in_time*/, 276 | int /*current*/, 277 | int /*endMonitor*/, 278 | double /*rtt*/); 279 | 280 | private: 281 | // UDT Rate control interval 282 | int m_iRCInterval; 283 | // last rate increase time 284 | uint64_t m_LastRCTime; 285 | // if in slow start phase 286 | bool m_bSlowStart; 287 | // last ACKed seq no 288 | int32_t m_iLastAck; 289 | // if loss happened since last rate increase 290 | bool m_bLoss; 291 | // max pkt seq no sent out when last decrease happened 292 | int32_t m_iLastDecSeq; 293 | // value of pktsndperiod when last decrease happened 294 | double m_dLastDecPeriod; 295 | // NAK counter 296 | int m_iNAKCount; 297 | // random threshold on decrease by number of loss events 298 | int m_iDecRandom; 299 | // average number of NAKs per congestion 300 | int m_iAvgNAKNum; 301 | // number of decreases in a congestion epoch 302 | int m_iDecCount; 303 | }; 304 | 305 | #endif 306 | -------------------------------------------------------------------------------- /src/core/channel.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /**************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/27/2011 39 | *****************************************************************************/ 40 | 41 | #include "channel.h" 42 | #include "packet.h" 43 | 44 | #ifndef WIN32 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #else 53 | #include 54 | #include 55 | #ifdef LEGACY_WIN32 56 | #include 57 | #endif 58 | #endif 59 | 60 | #ifdef WIN32 61 | #define socklen_t int 62 | #endif 63 | 64 | #ifndef WIN32 65 | #define NET_ERROR errno 66 | #else 67 | #define NET_ERROR WSAGetLastError() 68 | #endif 69 | 70 | 71 | CChannel::CChannel() : m_iIPversion(AF_INET), 72 | m_iSockAddrSize(sizeof(sockaddr_in)), 73 | m_iSocket(), 74 | m_iSndBufSize(65536), 75 | m_iRcvBufSize(65536) {} 76 | 77 | CChannel::CChannel(const int& version) : m_iIPversion(version), 78 | m_iSocket(), 79 | m_iSndBufSize(65536), 80 | m_iRcvBufSize(65536) { 81 | m_iSockAddrSize = AF_INET == m_iIPversion 82 | ? sizeof(sockaddr_in) 83 | : sizeof(sockaddr_in6); 84 | } 85 | 86 | CChannel::~CChannel() {} 87 | 88 | void CChannel::open(const sockaddr* addr) { 89 | // construct an socket 90 | m_iSocket = socket(m_iIPversion, SOCK_DGRAM, 0); 91 | 92 | #ifdef WIN32 93 | if (INVALID_SOCKET == m_iSocket) { 94 | #else 95 | if (m_iSocket < 0) { 96 | #endif 97 | throw CUDTException(1, 0, NET_ERROR); 98 | } 99 | 100 | if (NULL != addr) { 101 | socklen_t namelen = m_iSockAddrSize; 102 | 103 | if (0 != bind(m_iSocket, addr, namelen)) { 104 | throw CUDTException(1, 3, NET_ERROR); 105 | } 106 | } else { 107 | //sendto or WSASendTo will also automatically bind the socket 108 | addrinfo hints; 109 | addrinfo* res; 110 | 111 | memset(&hints, 0, sizeof(struct addrinfo)); 112 | 113 | hints.ai_flags = AI_PASSIVE; 114 | hints.ai_family = m_iIPversion; 115 | hints.ai_socktype = SOCK_DGRAM; 116 | 117 | if (0 != getaddrinfo(NULL, "0", &hints, &res)) { 118 | throw CUDTException(1, 3, NET_ERROR); 119 | } 120 | 121 | if (0 != bind(m_iSocket, res->ai_addr, res->ai_addrlen)) { 122 | throw CUDTException(1, 3, NET_ERROR); 123 | } 124 | 125 | freeaddrinfo(res); 126 | } 127 | 128 | setUDPSockOpt(); 129 | } 130 | 131 | void CChannel::open(UDPSOCKET udpsock) { 132 | m_iSocket = udpsock; 133 | setUDPSockOpt(); 134 | } 135 | 136 | void CChannel::setUDPSockOpt() { 137 | #if defined(BSD) || defined(OSX) 138 | // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value 139 | int maxsize = 64000; 140 | if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, 141 | sizeof(int))) { 142 | setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&maxsize, sizeof(int)); 143 | } 144 | if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, 145 | sizeof(int))) { 146 | setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&maxsize, sizeof(int)); 147 | } 148 | #else 149 | // for other systems, if requested is greated than maximum, the maximum value will be automactally used 150 | if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, 151 | sizeof(int)) || 152 | 0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, 153 | sizeof(int))) { 154 | throw CUDTException(1, 3, NET_ERROR); 155 | } 156 | #endif 157 | 158 | timeval tv; 159 | tv.tv_sec = 0; 160 | #if defined (BSD) || defined (OSX) 161 | // Known BSD bug as the day I wrote this code. 162 | // A small time out value will cause the socket to block forever. 163 | tv.tv_usec = 10000; 164 | #else 165 | tv.tv_usec = 100; 166 | #endif 167 | 168 | #ifdef UNIX 169 | // Set non-blocking I/O 170 | // UNIX does not support SO_RCVTIMEO 171 | int opts = fcntl(m_iSocket, F_GETFL); 172 | if (-1 == fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) { 173 | throw CUDTException(1, 3, NET_ERROR); 174 | } 175 | #elif WIN32 176 | DWORD ot = 1; //milliseconds 177 | if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, 178 | sizeof(DWORD))) { 179 | throw CUDTException(1, 3, NET_ERROR); 180 | } 181 | #else 182 | // Set receiving time-out value 183 | if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, 184 | sizeof(timeval))) { 185 | throw CUDTException(1, 3, NET_ERROR); 186 | } 187 | #endif 188 | } 189 | 190 | void CChannel::close() const { 191 | #ifndef WIN32 192 | ::close(m_iSocket); 193 | #else 194 | closesocket(m_iSocket); 195 | #endif 196 | } 197 | 198 | int CChannel::getSndBufSize() { 199 | socklen_t size = sizeof(socklen_t); 200 | 201 | getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize, &size); 202 | 203 | return m_iSndBufSize; 204 | } 205 | 206 | int CChannel::getRcvBufSize() { 207 | socklen_t size = sizeof(socklen_t); 208 | 209 | getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, &size); 210 | 211 | return m_iRcvBufSize; 212 | } 213 | 214 | void CChannel::setSndBufSize(const int& size) { 215 | m_iSndBufSize = size; 216 | } 217 | 218 | void CChannel::setRcvBufSize(const int& size) { 219 | m_iRcvBufSize = size; 220 | } 221 | 222 | void CChannel::getSockAddr(sockaddr* addr) const { 223 | socklen_t namelen = m_iSockAddrSize; 224 | 225 | getsockname(m_iSocket, addr, &namelen); 226 | } 227 | 228 | void CChannel::getPeerAddr(sockaddr* addr) const { 229 | socklen_t namelen = m_iSockAddrSize; 230 | 231 | getpeername(m_iSocket, addr, &namelen); 232 | } 233 | 234 | int CChannel::sendto(const sockaddr* addr, CPacket& packet) const { 235 | // convert control information into network order 236 | if (packet.getFlag()) { 237 | for (int i = 0, n = packet.getLength() / 4; i < n; ++ i) { 238 | *((uint32_t *)packet.m_pcData + i) = 239 | htonl(*((uint32_t *)packet.m_pcData + i)); 240 | } 241 | } 242 | 243 | // convert packet header into network order 244 | // for (int j = 0; j < 4; ++ j) { 245 | // packet.m_nHeader[j] = htonl(packet.m_nHeader[j]); 246 | // } 247 | uint32_t* p = packet.m_nHeader; 248 | for (int j = 0; j < 4; ++ j) { 249 | *p = htonl(*p); 250 | ++ p; 251 | } 252 | 253 | #ifndef WIN32 254 | msghdr mh; 255 | mh.msg_name = (sockaddr*)addr; 256 | mh.msg_namelen = m_iSockAddrSize; 257 | mh.msg_iov = (iovec*)packet.m_PacketVector; 258 | mh.msg_iovlen = 2; 259 | mh.msg_control = NULL; 260 | mh.msg_controllen = 0; 261 | mh.msg_flags = 0; 262 | 263 | int res = sendmsg(m_iSocket, &mh, 0); 264 | #else 265 | DWORD size = CPacket::m_iPktHdrSize + packet.getLength(); 266 | int addrsize = m_iSockAddrSize; 267 | int res = WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, 268 | addr, addrsize, NULL, NULL); 269 | res = (0 == res) ? size : -1; 270 | #endif 271 | 272 | // convert back into local host order 273 | // for (int k = 0; k < 4; ++ k) { 274 | // packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]); 275 | // } 276 | p = packet.m_nHeader; 277 | for (int k = 0; k < 4; ++ k) { 278 | *p = ntohl(*p); 279 | ++p; 280 | } 281 | 282 | if (packet.getFlag()) { 283 | for (int l = 0, n = packet.getLength() / 4; l < n; ++ l) { 284 | *((uint32_t *)packet.m_pcData + l) = 285 | ntohl(*((uint32_t *)packet.m_pcData + l)); 286 | } 287 | } 288 | 289 | return res; 290 | } 291 | 292 | int CChannel::recvfrom(sockaddr* addr, CPacket& packet) const { 293 | #ifndef WIN32 294 | msghdr mh; 295 | mh.msg_name = addr; 296 | mh.msg_namelen = m_iSockAddrSize; 297 | mh.msg_iov = packet.m_PacketVector; 298 | mh.msg_iovlen = 2; 299 | mh.msg_control = NULL; 300 | mh.msg_controllen = 0; 301 | mh.msg_flags = 0; 302 | 303 | #ifdef UNIX 304 | fd_set set; 305 | timeval tv; 306 | FD_ZERO(&set); 307 | FD_SET(m_iSocket, &set); 308 | tv.tv_sec = 0; 309 | tv.tv_usec = 10000; 310 | select(m_iSocket+1, &set, NULL, &set, &tv); 311 | #endif 312 | 313 | int res = recvmsg(m_iSocket, &mh, 0); 314 | #else 315 | DWORD size = CPacket::m_iPktHdrSize + packet.getLength(); 316 | DWORD flag = 0; 317 | int addrsize = m_iSockAddrSize; 318 | 319 | int res = WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, &flag, addr, &addrsize, NULL, NULL); 320 | res = (0 == res) ? size : -1; 321 | #endif 322 | 323 | if (res <= 0) { 324 | packet.setLength(-1); 325 | return -1; 326 | } 327 | 328 | packet.setLength(res - CPacket::m_iPktHdrSize); 329 | 330 | // convert back into local host order 331 | // for (int i = 0; i < 4; ++ i) { 332 | // packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]); 333 | // } 334 | uint32_t* p = packet.m_nHeader; 335 | for (int i = 0; i < 4; ++ i) { 336 | *p = ntohl(*p); 337 | ++p; 338 | } 339 | 340 | if (packet.getFlag()) { 341 | for (int j = 0, n = packet.getLength() / 4; j < n; ++ j) { 342 | *((uint32_t *)packet.m_pcData + j) = 343 | ntohl(*((uint32_t *)packet.m_pcData + j)); 344 | } 345 | } 346 | 347 | return packet.getLength(); 348 | } 349 | -------------------------------------------------------------------------------- /src/core/channel.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/27/2011 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_CHANNEL_H__ 42 | #define __UDT_CHANNEL_H__ 43 | 44 | 45 | #include "packet.h" 46 | #include "udt.h" 47 | 48 | 49 | class CChannel { 50 | public: 51 | CChannel(); 52 | CChannel(const int& version); 53 | ~CChannel(); 54 | 55 | // Functionality: 56 | // Opne a UDP channel. 57 | // Parameters: 58 | // 0) [in] addr: The local address that UDP will use. 59 | // Returned value: 60 | // None. 61 | void open(const sockaddr* addr = NULL); 62 | 63 | // Functionality: 64 | // Opne a UDP channel based on an existing UDP socket. 65 | // Parameters: 66 | // 0) [in] udpsock: UDP socket descriptor. 67 | // Returned value: 68 | // None. 69 | void open(UDPSOCKET udpsock); 70 | 71 | // Functionality: 72 | // Disconnect and close the UDP entity. 73 | // Parameters: 74 | // None. 75 | // Returned value: 76 | // None. 77 | void close() const; 78 | 79 | // Functionality: 80 | // Get the UDP sending buffer size. 81 | // Parameters: 82 | // None. 83 | // Returned value: 84 | // Current UDP sending buffer size. 85 | int getSndBufSize(); 86 | 87 | // Functionality: 88 | // Get the UDP receiving buffer size. 89 | // Parameters: 90 | // None. 91 | // Returned value: 92 | // Current UDP receiving buffer size. 93 | int getRcvBufSize(); 94 | 95 | // Functionality: 96 | // Set the UDP sending buffer size. 97 | // Parameters: 98 | // 0) [in] size: expected UDP sending buffer size. 99 | // Returned value: 100 | // None. 101 | void setSndBufSize(const int& size); 102 | 103 | // Functionality: 104 | // Set the UDP receiving buffer size. 105 | // Parameters: 106 | // 0) [in] size: expected UDP receiving buffer size. 107 | // Returned value: 108 | // None. 109 | void setRcvBufSize(const int& size); 110 | 111 | // Functionality: 112 | // Query the socket address that the channel is using. 113 | // Parameters: 114 | // 0) [out] addr: pointer to store the returned socket address. 115 | // Returned value: 116 | // None. 117 | void getSockAddr(sockaddr* addr) const; 118 | 119 | // Functionality: 120 | // Query the peer side socket address that the channel is connect to. 121 | // Parameters: 122 | // 0) [out] addr: pointer to store the returned socket address. 123 | // Returned value: 124 | // None. 125 | void getPeerAddr(sockaddr* addr) const; 126 | 127 | // Functionality: 128 | // Send a packet to the given address. 129 | // Parameters: 130 | // 0) [in] addr: pointer to the destination address. 131 | // 1) [in] packet: reference to a CPacket entity. 132 | // Returned value: 133 | // Actual size of data sent. 134 | int sendto(const sockaddr* addr, CPacket& packet) const; 135 | 136 | // Functionality: 137 | // Receive a packet from the channel and record the source address. 138 | // Parameters: 139 | // 0) [in] addr: pointer to the source address. 140 | // 1) [in] packet: reference to a CPacket entity. 141 | // Returned value: 142 | // Actual size of data received. 143 | int recvfrom(sockaddr* addr, CPacket& packet) const; 144 | 145 | private: 146 | void setUDPSockOpt(); 147 | 148 | // IP version 149 | int m_iIPversion; 150 | // socket address structure size (pre-defined to avoid run-time test) 151 | int m_iSockAddrSize; 152 | 153 | // socket descriptor 154 | UDPSOCKET m_iSocket; 155 | 156 | // UDP sending buffer size 157 | int m_iSndBufSize; 158 | // UDP receiving buffer size 159 | int m_iRcvBufSize; 160 | }; 161 | 162 | #endif 163 | -------------------------------------------------------------------------------- /src/core/common.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2009, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 08/01/2009 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_COMMON_H__ 42 | #define __UDT_COMMON_H__ 43 | 44 | 45 | #include "udt.h" 46 | 47 | #include 48 | #ifndef WIN32 49 | #include 50 | #include 51 | #include 52 | #else 53 | #include 54 | #endif 55 | 56 | #ifdef WIN32 57 | // Windows compability 58 | typedef HANDLE pthread_t; 59 | typedef HANDLE pthread_mutex_t; 60 | typedef HANDLE pthread_cond_t; 61 | typedef DWORD pthread_key_t; 62 | #endif 63 | 64 | 65 | //////////////////////////////////////////////////////////////////////////////// 66 | 67 | class CTimer { 68 | public: 69 | CTimer(); 70 | ~CTimer(); 71 | 72 | // Functionality: 73 | // Sleep for "interval" CCs. 74 | // Parameters: 75 | // 0) [in] interval: CCs to sleep. 76 | // Returned value: 77 | // None. 78 | void sleep(const uint64_t& interval); 79 | 80 | // Functionality: 81 | // Seelp until CC "nexttime". 82 | // Parameters: 83 | // 0) [in] nexttime: next time the caller is waken up. 84 | // Returned value: 85 | // None. 86 | void sleepto(const uint64_t& nexttime); 87 | 88 | // Functionality: 89 | // Stop the sleep() or sleepto() methods. 90 | // Parameters: 91 | // None. 92 | // Returned value: 93 | // None. 94 | void interrupt(); 95 | 96 | // Functionality: 97 | // trigger the clock for a tick, for better granuality in no_busy_waiting 98 | // timer. 99 | // Parameters: 100 | // None. 101 | // Returned value: 102 | // None. 103 | void tick(); 104 | 105 | // Functionality: 106 | // Read the CPU clock cycle into x. 107 | // Parameters: 108 | // 0) [out] x: to record cpu clock cycles. 109 | // Returned value: 110 | // None. 111 | static void rdtsc(uint64_t &x); 112 | 113 | // Functionality: 114 | // return the CPU frequency. 115 | // Parameters: 116 | // None. 117 | // Returned value: 118 | // CPU frequency. 119 | static uint64_t getCPUFrequency(); 120 | 121 | // Functionality: 122 | // check the current time, 64bit, in microseconds. 123 | // Parameters: 124 | // None. 125 | // Returned value: 126 | // current time in microseconds. 127 | static uint64_t getTime(); 128 | 129 | // Functionality: 130 | // trigger an event such as new connection, close, new data, etc. for 131 | // "select" call. 132 | // Parameters: 133 | // None. 134 | // Returned value: 135 | // None. 136 | static void triggerEvent(); 137 | 138 | // Functionality: 139 | // wait for an event to br triggered by "triggerEvent". 140 | // Parameters: 141 | // None. 142 | // Returned value: 143 | // None. 144 | static void waitForEvent(); 145 | 146 | // Functionality: 147 | // sleep for a short interval. exact sleep time does not matter 148 | // Parameters: 149 | // None. 150 | // Returned value: 151 | // None. 152 | static void sleep(); 153 | 154 | private: 155 | // next schedulled time 156 | uint64_t m_ullSchedTime; 157 | 158 | pthread_cond_t m_TickCond; 159 | pthread_mutex_t m_TickLock; 160 | 161 | static pthread_cond_t m_EventCond; 162 | static pthread_mutex_t m_EventLock; 163 | 164 | // CPU frequency : clock cycles per microsecond 165 | static uint64_t s_ullCPUFrequency; 166 | static uint64_t readCPUFrequency(); 167 | }; 168 | 169 | //////////////////////////////////////////////////////////////////////////////// 170 | 171 | class CGuard { 172 | public: 173 | CGuard(pthread_mutex_t& lock); 174 | ~CGuard(); 175 | 176 | static void enterCS(pthread_mutex_t& lock); 177 | static void leaveCS(pthread_mutex_t& lock); 178 | 179 | static void createMutex(pthread_mutex_t& lock); 180 | static void releaseMutex(pthread_mutex_t& lock); 181 | 182 | static void createCond(pthread_cond_t& cond); 183 | static void releaseCond(pthread_cond_t& cond); 184 | 185 | private: 186 | // Alias name of the mutex to be protected 187 | pthread_mutex_t& m_Mutex; 188 | // Locking status 189 | int m_iLocked; 190 | 191 | CGuard& operator=(const CGuard&); 192 | }; 193 | 194 | 195 | //////////////////////////////////////////////////////////////////////////////// 196 | 197 | // UDT Sequence Number 0 - (2^31 - 1) 198 | 199 | // seqcmp: compare two seq#, considering the wraping 200 | // seqlen: length from the 1st to the 2nd seq#, including both 201 | // seqoff: offset from the 2nd to the 1st seq# 202 | // incseq: increase the seq# by 1 203 | // decseq: decrease the seq# by 1 204 | // incseq: increase the seq# by a given offset 205 | 206 | class CSeqNo { 207 | public: 208 | inline static int seqcmp(const int32_t& seq1, const int32_t& seq2) { 209 | return abs(seq1 - seq2) < m_iSeqNoTH ? seq1 - seq2 : seq2 - seq1; 210 | } 211 | 212 | inline static int seqlen(const int32_t& seq1, const int32_t& seq2) { 213 | return seq1 <= seq2 ? seq2 - seq1 + 1 : seq2 - seq1 + m_iMaxSeqNo + 2; 214 | } 215 | 216 | inline static int seqoff(const int32_t& seq1, const int32_t& seq2) { 217 | if (abs(seq1 - seq2) < m_iSeqNoTH) { 218 | return seq2 - seq1; 219 | } 220 | 221 | if (seq1 < seq2) { 222 | return seq2 - seq1 - m_iMaxSeqNo - 1; 223 | } 224 | 225 | return seq2 - seq1 + m_iMaxSeqNo + 1; 226 | } 227 | 228 | inline static int32_t incseq(const int32_t seq) { 229 | return seq == m_iMaxSeqNo ? 0 : seq + 1; 230 | } 231 | 232 | inline static int32_t decseq(const int32_t& seq) { 233 | return seq == 0 ? m_iMaxSeqNo : seq - 1; 234 | } 235 | 236 | inline static int32_t incseq(const int32_t& seq, const int32_t& inc) { 237 | return m_iMaxSeqNo - seq >= inc ? seq + inc : seq - m_iMaxSeqNo + inc - 1; 238 | } 239 | 240 | // threshold for comparing seq. no. 241 | static const int32_t m_iSeqNoTH; 242 | // maximum sequence number used in UDT 243 | static const int32_t m_iMaxSeqNo; 244 | }; 245 | 246 | //////////////////////////////////////////////////////////////////////////////// 247 | 248 | // UDT ACK Sub-sequence Number: 0 - (2^31 - 1) 249 | 250 | class CAckNo { 251 | public: 252 | inline static int32_t incack(const int32_t& ackno) { 253 | return (ackno == m_iMaxAckSeqNo) ? 0 : ackno + 1; 254 | } 255 | 256 | // maximum ACK sub-sequence number used in UDT 257 | static const int32_t m_iMaxAckSeqNo; 258 | }; 259 | 260 | //////////////////////////////////////////////////////////////////////////////// 261 | 262 | // UDT Message Number: 0 - (2^29 - 1) 263 | 264 | class CMsgNo { 265 | public: 266 | inline static int msgcmp(const int32_t& msgno1, const int32_t& msgno2) { 267 | return abs(msgno1 - msgno2) < m_iMsgNoTH 268 | ? msgno1 - msgno2 269 | : msgno2 - msgno1; 270 | } 271 | 272 | inline static int msglen(const int32_t& msgno1, const int32_t& msgno2) { 273 | return msgno1 <= msgno2 274 | ? msgno2 - msgno1 + 1 275 | : msgno2 - msgno1 + m_iMaxMsgNo + 2; 276 | } 277 | 278 | inline static int msgoff(const int32_t& msgno1, const int32_t& msgno2) { 279 | if (abs(msgno1 - msgno2) < m_iMsgNoTH) { 280 | return msgno2 - msgno1; 281 | } 282 | 283 | if (msgno1 < msgno2) { 284 | return msgno2 - msgno1 - m_iMaxMsgNo - 1; 285 | } 286 | 287 | return msgno2 - msgno1 + m_iMaxMsgNo + 1; 288 | } 289 | 290 | inline static int32_t incmsg(const int32_t& msgno) { 291 | return msgno == m_iMaxMsgNo ? 0 : msgno + 1; 292 | } 293 | 294 | // threshold for comparing msg. no. 295 | static const int32_t m_iMsgNoTH; 296 | // maximum message number used in UDT 297 | static const int32_t m_iMaxMsgNo; 298 | }; 299 | 300 | //////////////////////////////////////////////////////////////////////////////// 301 | 302 | struct CIPAddress { 303 | static bool ipcmp(const sockaddr* addr1, 304 | const sockaddr* addr2, 305 | const int& ver = AF_INET); 306 | static void ntop(const sockaddr* addr, 307 | uint32_t ip[4], 308 | const int& ver = AF_INET); 309 | static void pton(sockaddr* addr, 310 | const uint32_t ip[4], 311 | const int& ver = AF_INET); 312 | }; 313 | 314 | //////////////////////////////////////////////////////////////////////////////// 315 | 316 | struct CMD5 { 317 | static void compute(const char* input, unsigned char result[16]); 318 | }; 319 | 320 | 321 | #endif 322 | -------------------------------------------------------------------------------- /src/core/epoll.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/01/2011 39 | *****************************************************************************/ 40 | 41 | #include "common.h" 42 | #include "epoll.h" 43 | #include "udt.h" 44 | 45 | #include 46 | #include 47 | #include 48 | #include 49 | #ifdef LINUX 50 | #include 51 | #include 52 | #endif 53 | 54 | using namespace std; 55 | 56 | CEPoll::CEPoll() : m_iIDSeed(0) { 57 | CGuard::createMutex(m_EPollLock); 58 | } 59 | 60 | CEPoll::~CEPoll() { 61 | CGuard::releaseMutex(m_EPollLock); 62 | } 63 | 64 | int CEPoll::create() { 65 | CGuard pg(m_EPollLock); 66 | 67 | int localid = 0; 68 | 69 | #ifdef LINUX 70 | localid = epoll_create(1024); 71 | if (localid < 0) { 72 | throw CUDTException(-1, 0, errno); 73 | } 74 | #else 75 | // on BSD, use kqueue 76 | // on Solaris, use /dev/poll 77 | // on Windows, select 78 | #endif 79 | 80 | if (++ m_iIDSeed >= 0x7FFFFFFF) { 81 | m_iIDSeed = 0; 82 | } 83 | 84 | CEPollDesc desc; 85 | desc.m_iID = m_iIDSeed; 86 | desc.m_iLocalID = localid; 87 | m_mPolls[desc.m_iID] = desc; 88 | 89 | return desc.m_iID; 90 | } 91 | 92 | int CEPoll::add_usock(const int eid, const UDTSOCKET& u, const int* events) { 93 | CGuard pg(m_EPollLock); 94 | 95 | map::iterator p = m_mPolls.find(eid); 96 | if (p == m_mPolls.end()) { 97 | throw CUDTException(5, 13); 98 | } 99 | 100 | if (!events || (*events & UDT_EPOLL_IN)) { 101 | p->second.m_sUDTSocksIn.insert(u); 102 | } 103 | if (!events || (*events & UDT_EPOLL_OUT)) { 104 | p->second.m_sUDTSocksOut.insert(u); 105 | } 106 | 107 | return 0; 108 | } 109 | 110 | int CEPoll::add_ssock(const int eid, const SYSSOCKET& s, const int* events) { 111 | CGuard pg(m_EPollLock); 112 | 113 | map::iterator p = m_mPolls.find(eid); 114 | if (p == m_mPolls.end()) { 115 | throw CUDTException(5, 13); 116 | } 117 | 118 | #ifdef LINUX 119 | epoll_event ev; 120 | 121 | if (NULL == events) { 122 | ev.events = EPOLLIN | EPOLLOUT | EPOLLERR; 123 | } else { 124 | ev.events = 0; 125 | if (*events & UDT_EPOLL_IN) { 126 | ev.events |= EPOLLIN; 127 | } 128 | if (*events & UDT_EPOLL_OUT) { 129 | ev.events |= EPOLLOUT; 130 | } 131 | if (*events & UDT_EPOLL_ERR) { 132 | ev.events |= EPOLLERR; 133 | } 134 | } 135 | 136 | ev.data.fd = s; 137 | if (epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_ADD, s, &ev) < 0) { 138 | throw CUDTException(); 139 | } 140 | #endif 141 | 142 | p->second.m_sLocals.insert(s); 143 | 144 | return 0; 145 | } 146 | 147 | int CEPoll::remove_usock(const int eid, const UDTSOCKET& u) { 148 | CGuard pg(m_EPollLock); 149 | 150 | map::iterator p = m_mPolls.find(eid); 151 | if (p == m_mPolls.end()) { 152 | throw CUDTException(5, 13); 153 | } 154 | 155 | p->second.m_sUDTSocksIn.erase(u); 156 | p->second.m_sUDTSocksOut.erase(u); 157 | 158 | // when the socket is removed from a monitoring, it is not available anymore 159 | // for any IO notification 160 | p->second.m_sUDTReads.erase(u); 161 | p->second.m_sUDTWrites.erase(u); 162 | 163 | return 0; 164 | } 165 | 166 | int CEPoll::remove_ssock(const int eid, const SYSSOCKET& s) { 167 | CGuard pg(m_EPollLock); 168 | 169 | map::iterator p = m_mPolls.find(eid); 170 | if (p == m_mPolls.end()) { 171 | throw CUDTException(5, 13); 172 | } 173 | 174 | #ifdef LINUX 175 | // ev is ignored, for compatibility with old Linux kernel only. 176 | epoll_event ev; 177 | if (epoll_ctl(p->second.m_iLocalID, EPOLL_CTL_DEL, s, &ev) < 0) { 178 | throw CUDTException(); 179 | } 180 | #endif 181 | 182 | p->second.m_sLocals.erase(s); 183 | 184 | return 0; 185 | } 186 | 187 | int CEPoll::wait(const int eid, 188 | set* readfds, 189 | set* writefds, 190 | int64_t msTimeOut, 191 | set* lrfds, 192 | set* lwfds) { 193 | // if all fields is NULL and waiting time is infinite, then this would be a deadlock 194 | if (!readfds && !writefds && !lrfds && lwfds && msTimeOut < 0) { 195 | throw CUDTException(5, 3, 0); 196 | } 197 | 198 | // Clear these sets in case the app forget to do it. 199 | if (readfds) { 200 | readfds->clear(); 201 | } 202 | if (writefds) { 203 | writefds->clear(); 204 | } 205 | if (lrfds) { 206 | lrfds->clear(); 207 | } 208 | if (lwfds) { 209 | lwfds->clear(); 210 | } 211 | 212 | int total = 0; 213 | 214 | int64_t entertime = CTimer::getTime(); 215 | while (true) { 216 | CGuard::enterCS(m_EPollLock); 217 | 218 | map::iterator p = m_mPolls.find(eid); 219 | if (p == m_mPolls.end()) { 220 | CGuard::leaveCS(m_EPollLock); 221 | throw CUDTException(5, 13); 222 | } 223 | 224 | if (p->second.m_sUDTSocksIn.empty() && p->second.m_sUDTSocksOut.empty() && 225 | p->second.m_sLocals.empty() && msTimeOut < 0) { 226 | // no socket is being monitored, this may be a deadlock 227 | CGuard::leaveCS(m_EPollLock); 228 | throw CUDTException(5, 3); 229 | } 230 | 231 | if (NULL != readfds && !p->second.m_sUDTReads.empty()) { 232 | *readfds = p->second.m_sUDTReads; 233 | total += p->second.m_sUDTReads.size(); 234 | } 235 | 236 | if (NULL != writefds && !p->second.m_sUDTWrites.empty()) { 237 | *writefds = p->second.m_sUDTWrites; 238 | total += p->second.m_sUDTWrites.size(); 239 | } 240 | 241 | if (lrfds || lwfds) { 242 | #ifdef LINUX 243 | const int max_events = p->second.m_sLocals.size(); 244 | epoll_event ev[max_events]; 245 | int nfds = epoll_wait(p->second.m_iLocalID, ev, max_events, 0); 246 | 247 | for (int i = 0; i < nfds; ++ i) { 248 | if (NULL != lrfds && (ev[i].events & EPOLLIN)) { 249 | lrfds->insert(ev[i].data.fd); 250 | ++total; 251 | } 252 | if (NULL != lwfds && (ev[i].events & EPOLLOUT)) { 253 | lwfds->insert(ev[i].data.fd); 254 | ++total; 255 | } 256 | } 257 | #else 258 | // currently "select" is used for all non-Linux platforms. 259 | // faster approaches can be applied for specific systems in the future. 260 | 261 | // "select" has a limitation on the number of sockets 262 | 263 | fd_set readfds; 264 | fd_set writefds; 265 | FD_ZERO(&readfds); 266 | FD_ZERO(&writefds); 267 | 268 | for (set::const_iterator i = p->second.m_sLocals.begin(); 269 | i != p->second.m_sLocals.end(); ++i) { 270 | if (lrfds) { 271 | FD_SET(*i, &readfds); 272 | } 273 | if (lwfds) { 274 | FD_SET(*i, &writefds); 275 | } 276 | } 277 | 278 | timeval tv; 279 | tv.tv_sec = 0; 280 | tv.tv_usec = 0; 281 | if (select(0, &readfds, &writefds, NULL, &tv) > 0) { 282 | for (set::const_iterator i = p->second.m_sLocals.begin(); 283 | i != p->second.m_sLocals.end(); ++ i) { 284 | if (lrfds && FD_ISSET(*i, &readfds)) { 285 | lrfds->insert(*i); 286 | ++ total; 287 | } 288 | if (lwfds && FD_ISSET(*i, &writefds)) { 289 | lwfds->insert(*i); 290 | ++ total; 291 | } 292 | } 293 | } 294 | #endif 295 | } 296 | 297 | CGuard::leaveCS(m_EPollLock); 298 | 299 | if (total > 0) { 300 | return total; 301 | } 302 | 303 | if (msTimeOut >= 0 && 304 | int64_t(CTimer::getTime() - entertime) >= msTimeOut * 1000LL) { 305 | break; 306 | } 307 | 308 | CTimer::waitForEvent(); 309 | } 310 | 311 | return 0; 312 | } 313 | 314 | int CEPoll::release(const int eid) { 315 | CGuard pg(m_EPollLock); 316 | 317 | map::iterator i = m_mPolls.find(eid); 318 | if (i == m_mPolls.end()) { 319 | throw CUDTException(5, 13); 320 | } 321 | 322 | #ifdef LINUX 323 | // release local/system epoll descriptor 324 | ::close(i->second.m_iLocalID); 325 | #endif 326 | 327 | m_mPolls.erase(i); 328 | 329 | return 0; 330 | } 331 | 332 | int CEPoll::enable_write(const UDTSOCKET& uid, set& eids) { 333 | CGuard pg(m_EPollLock); 334 | 335 | map::iterator p; 336 | 337 | vector lost; 338 | for (set::iterator i = eids.begin(); i != eids.end(); ++i) { 339 | p = m_mPolls.find(*i); 340 | if (p == m_mPolls.end()) { 341 | lost.push_back(*i); 342 | } else if (p->second.m_sUDTSocksOut.find(uid) != 343 | p->second.m_sUDTSocksOut.end()) { 344 | p->second.m_sUDTWrites.insert(uid); 345 | } 346 | } 347 | 348 | for (vector::iterator i = lost.begin(); i != lost.end(); ++i) { 349 | eids.erase(*i); 350 | } 351 | 352 | return 0; 353 | } 354 | 355 | int CEPoll::enable_read(const UDTSOCKET& uid, set& eids) { 356 | CGuard pg(m_EPollLock); 357 | 358 | map::iterator p; 359 | 360 | vector lost; 361 | for (set::iterator i = eids.begin(); i != eids.end(); ++i) { 362 | p = m_mPolls.find(*i); 363 | if (p == m_mPolls.end()) { 364 | lost.push_back(*i); 365 | } else if (p->second.m_sUDTSocksIn.find(uid) != 366 | p->second.m_sUDTSocksIn.end()) { 367 | p->second.m_sUDTReads.insert(uid); 368 | } 369 | } 370 | 371 | for (vector::iterator i = lost.begin(); i != lost.end(); ++i) { 372 | eids.erase(*i); 373 | } 374 | 375 | return 0; 376 | } 377 | 378 | int CEPoll::disable_write(const UDTSOCKET& uid, set& eids) { 379 | CGuard pg(m_EPollLock); 380 | 381 | map::iterator p; 382 | 383 | vector lost; 384 | for (set::iterator i = eids.begin(); i != eids.end(); ++i) { 385 | p = m_mPolls.find(*i); 386 | if (p == m_mPolls.end()) { 387 | lost.push_back(*i); 388 | } else { 389 | p->second.m_sUDTWrites.erase(uid); 390 | } 391 | } 392 | 393 | for (vector::iterator i = lost.begin(); i != lost.end(); ++i) { 394 | eids.erase(*i); 395 | } 396 | 397 | return 0; 398 | } 399 | 400 | int CEPoll::disable_read(const UDTSOCKET& uid, set& eids) { 401 | CGuard pg(m_EPollLock); 402 | 403 | map::iterator p; 404 | 405 | vector lost; 406 | for (set::iterator i = eids.begin(); i != eids.end(); ++i) { 407 | p = m_mPolls.find(*i); 408 | if (p == m_mPolls.end()) { 409 | lost.push_back(*i); 410 | } else { 411 | p->second.m_sUDTReads.erase(uid); 412 | } 413 | } 414 | 415 | for (vector::iterator i = lost.begin(); i != lost.end(); ++i) { 416 | eids.erase(*i); 417 | } 418 | 419 | return 0; 420 | } 421 | -------------------------------------------------------------------------------- /src/core/epoll.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2010, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 08/20/2010 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_EPOLL_H__ 42 | #define __UDT_EPOLL_H__ 43 | 44 | #include "udt.h" 45 | 46 | #include 47 | #include 48 | 49 | struct CEPollDesc { 50 | // epoll ID 51 | int m_iID; 52 | // set of UDT sockets waiting for write events 53 | std::set m_sUDTSocksOut; 54 | // set of UDT sockets waiting for read events 55 | std::set m_sUDTSocksIn; 56 | 57 | // local system epoll ID 58 | int m_iLocalID; 59 | // set of local (non-UDT) descriptors 60 | std::set m_sLocals; 61 | 62 | // UDT sockets ready for write 63 | std::set m_sUDTWrites; 64 | // UDT sockets ready for read 65 | std::set m_sUDTReads; 66 | }; 67 | 68 | class CEPoll { 69 | friend class CUDT; 70 | friend class CRendezvousQueue; 71 | 72 | public: 73 | CEPoll(); 74 | ~CEPoll(); 75 | 76 | // for CUDTUnited API 77 | 78 | // Functionality: 79 | // create a new EPoll. 80 | // Parameters: 81 | // None. 82 | // Returned value: 83 | // new EPoll ID if success, otherwise an error number. 84 | int create(); 85 | 86 | // Functionality: 87 | // add a UDT socket to an EPoll. 88 | // Parameters: 89 | // 0) [in] eid: EPoll ID. 90 | // 1) [in] u: UDT Socket ID. 91 | // 2) [in] events: events to watch. 92 | // Returned value: 93 | // 0 if success, otherwise an error number. 94 | int add_usock(const int eid, const UDTSOCKET& u, const int* events = NULL); 95 | 96 | // Functionality: 97 | // add a system socket to an EPoll. 98 | // Parameters: 99 | // 0) [in] eid: EPoll ID. 100 | // 1) [in] s: system Socket ID. 101 | // 2) [in] events: events to watch. 102 | // Returned value: 103 | // 0 if success, otherwise an error number. 104 | int add_ssock(const int eid, const SYSSOCKET& s, const int* events = NULL); 105 | 106 | // Functionality: 107 | // remove a UDT socket event from an EPoll; socket will be removed if no 108 | // events to watch 109 | // Parameters: 110 | // 0) [in] eid: EPoll ID. 111 | // 1) [in] u: UDT socket ID. 112 | // Returned value: 113 | // 0 if success, otherwise an error number. 114 | int remove_usock(const int eid, const UDTSOCKET& u); 115 | 116 | // Functionality: 117 | // remove a system socket event from an EPoll; socket will be removed if 118 | // no events to watch 119 | // Parameters: 120 | // 0) [in] eid: EPoll ID. 121 | // 1) [in] s: system socket ID. 122 | // Returned value: 123 | // 0 if success, otherwise an error number. 124 | int remove_ssock(const int eid, const SYSSOCKET& s); 125 | 126 | // Functionality: 127 | // wait for EPoll events or timeout. 128 | // Parameters: 129 | // 0) [in] eid: EPoll ID. 130 | // 1) [out] readfds: UDT sockets available for reading. 131 | // 2) [out] writefds: UDT sockets available for writing. 132 | // 3) [in] msTimeOut: timeout threshold, in milliseconds. 133 | // 4) [out] lrfds: system file descriptors for reading. 134 | // 5) [out] lwfds: system file descriptors for writing. 135 | // Returned value: 136 | // number of sockets available for IO. 137 | int wait(const int eid, 138 | std::set* readfds, 139 | std::set* writefds, 140 | int64_t msTimeOut, 141 | std::set* lrfds, 142 | std::set* lwfds); 143 | 144 | // Functionality: 145 | // close and release an EPoll. 146 | // Parameters: 147 | // 0) [in] eid: EPoll ID. 148 | // Returned value: 149 | // 0 if success, otherwise an error number. 150 | int release(const int eid); 151 | 152 | // for CUDT to acknowledge IO status 153 | 154 | // Functionality: 155 | // set a UDT socket writable. 156 | // Parameters: 157 | // 0) [in] uid: UDT socket ID. 158 | // 1) [in] eids: EPoll IDs to be set 159 | // Returned value: 160 | // 0 if success, otherwise an error number. 161 | int enable_write(const UDTSOCKET& uid, std::set& eids); 162 | 163 | // Functionality: 164 | // set a UDT socket readable. 165 | // Parameters: 166 | // 0) [in] uid: UDT socket ID. 167 | // 1) [in] eids: EPoll IDs to be set 168 | // Returned value: 169 | // 0 if success, otherwise an error number. 170 | int enable_read(const UDTSOCKET& uid, std::set& eids); 171 | 172 | // Functionality: 173 | // reset a the writable status of a UDT socket. 174 | // Parameters: 175 | // 0) [in] uid: UDT socket ID. 176 | // 1) [in] eids: EPoll IDs to be set 177 | // Returned value: 178 | // 0 if success, otherwise an error number. 179 | int disable_write(const UDTSOCKET& uid, std::set& eids); 180 | 181 | // Functionality: 182 | // reset a the readable status of a UDT socket. 183 | // Parameters: 184 | // 0) [in] uid: UDT socket ID. 185 | // 1) [in] eids: EPoll IDs to be set 186 | // Returned value: 187 | // 0 if success, otherwise an error number. 188 | int disable_read(const UDTSOCKET& uid, std::set& eids); 189 | 190 | private: 191 | // seed to generate a new ID 192 | int m_iIDSeed; 193 | pthread_mutex_t m_SeedLock; 194 | 195 | // all epolls 196 | std::map m_mPolls; 197 | pthread_mutex_t m_EPollLock; 198 | }; 199 | 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /src/core/list.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/22/2011 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_LIST_H__ 42 | #define __UDT_LIST_H__ 43 | 44 | 45 | #include "common.h" 46 | #include "udt.h" 47 | 48 | #include 49 | 50 | using namespace std; 51 | 52 | class CSndLossList { 53 | public: 54 | CSndLossList(const int& size = 500000); 55 | ~CSndLossList(); 56 | 57 | // Functionality: 58 | // Insert a seq. no. into the sender loss list. 59 | // Parameters: 60 | // 0) [in] seqno1: sequence number starts. 61 | // 1) [in] seqno2: sequence number ends. 62 | // Returned value: 63 | // number of packets that are not in the list previously. 64 | int insert(const int32_t& seqno1, const int32_t& seqno2); 65 | 66 | // Functionality: 67 | // Remove ALL the seq. no. that are not greater than the parameter. 68 | // Parameters: 69 | // 0) [in] seqno: sequence number. 70 | // Returned value: 71 | // None. 72 | void remove(const int32_t& seqno); 73 | 74 | // Functionality: 75 | // Read the loss length. 76 | // Parameters: 77 | // None. 78 | // Returned value: 79 | // The length of the list. 80 | int getLossLength(); 81 | 82 | // Functionality: 83 | // Read the first (smallest) loss seq. no. in the list and remove it. 84 | // Parameters: 85 | // None. 86 | // Returned value: 87 | // The seq. no. or -1 if the list is empty. 88 | int32_t getLostSeq(); 89 | 90 | // sequence number starts 91 | int32_t* m_piData1; 92 | // seqnence number ends 93 | int32_t* m_piData2; 94 | // next node in the list 95 | int* m_piNext; 96 | 97 | // first node 98 | int m_iHead; 99 | // loss length 100 | int m_iLength; 101 | // size of the static array 102 | int m_iSize; 103 | // position of last insert node 104 | int m_iLastInsertPos; 105 | 106 | // used to synchronize list operation 107 | pthread_mutex_t m_ListLock; 108 | 109 | private: 110 | CSndLossList(const CSndLossList&); 111 | CSndLossList& operator=(const CSndLossList&); 112 | }; 113 | 114 | //////////////////////////////////////////////////////////////////////////////// 115 | 116 | class CRcvLossList { 117 | public: 118 | CRcvLossList(const int& size = 500000); 119 | ~CRcvLossList(); 120 | 121 | // Functionality: 122 | // Insert a series of loss seq. no. between "seqno1" and "seqno2" into the 123 | // receiver's loss list. 124 | // Parameters: 125 | // 0) [in] seqno1: sequence number starts. 126 | // 1) [in] seqno2: seqeunce number ends. 127 | // Returned value: 128 | // None. 129 | void insert(const int32_t& seqno1, const int32_t& seqno2); 130 | 131 | // Functionality: 132 | // Remove a loss seq. no. from the receiver's loss list. 133 | // Parameters: 134 | // 0) [in] seqno: sequence number. 135 | // Returned value: 136 | // if the packet is removed (true) or no such lost packet is found (false). 137 | int remove(const int32_t& seqno); 138 | 139 | // Functionality: 140 | // Remove all packets between seqno1 and seqno2. 141 | // Parameters: 142 | // 0) [in] seqno1: start sequence number. 143 | // 1) [in] seqno2: end sequence number. 144 | // Returned value: 145 | // if the packet is removed (true) or no such lost packet is found (false). 146 | int remove(const int32_t& seqno1, const int32_t& seqno2); 147 | 148 | // Functionality: 149 | // Find if there is any lost packets whose sequence number falling seqno1 150 | // and seqno2. 151 | // Parameters: 152 | // 0) [in] seqno1: start sequence number. 153 | // 1) [in] seqno2: end sequence number. 154 | // Returned value: 155 | // True if found; otherwise false. 156 | bool find(const int32_t& seqno1, const int32_t& seqno2) const; 157 | 158 | // Functionality: 159 | // Read the loss length. 160 | // Parameters: 161 | // None. 162 | // Returned value: 163 | // the length of the list. 164 | int getLossLength() const; 165 | 166 | // Functionality: 167 | // Read the first (smallest) seq. no. in the list. 168 | // Parameters: 169 | // None. 170 | // Returned value: 171 | // the sequence number or -1 if the list is empty. 172 | int getFirstLostSeq() const; 173 | 174 | // Functionality: 175 | // Get a encoded loss array for NAK report. 176 | // Parameters: 177 | // 0) [out] array: the result list of seq. no. to be included in NAK. 178 | // 1) [out] physical length of the result array. 179 | // 2) [in] limit: maximum length of the array. 180 | // Returned value: 181 | // None. 182 | void getLossArray(int32_t* array, int& len, int limit, int & offset); 183 | 184 | // sequence number starts 185 | int32_t* m_piData1; 186 | // sequence number ends 187 | int32_t* m_piData2; 188 | // next node in the list 189 | int* m_piNext; 190 | // prior node in the list; 191 | int* m_piPrior; 192 | 193 | // first node in the list 194 | int m_iHead; 195 | // last node in the list; 196 | int m_iTail; 197 | // loss length 198 | int m_iLength; 199 | // size of the static array 200 | int m_iSize; 201 | 202 | private: 203 | CRcvLossList(const CRcvLossList&); 204 | CRcvLossList& operator=(const CRcvLossList&); 205 | }; 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /src/core/md5.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.cpp,v 1.3 2008/01/20 22:52:04 lilyco Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.c is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order 41 | either statically or dynamically; added missing #include 42 | in library. 43 | 2002-03-11 lpd Corrected argument list for main(), and added int return 44 | type, in test program and T value program. 45 | 2002-02-21 lpd Added missing #include in test program. 46 | 2000-07-03 lpd Patched to eliminate warnings about "constant is 47 | unsigned in ANSI C, signed in traditional"; made test program 48 | self-checking. 49 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 50 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 51 | 1999-05-03 lpd Original version. 52 | */ 53 | 54 | #include "md5.h" 55 | 56 | #include 57 | 58 | #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ 59 | #ifdef ARCH_IS_BIG_ENDIAN 60 | #define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) 61 | #else 62 | #define BYTE_ORDER 0 63 | #endif 64 | 65 | #define T_MASK ((md5_word_t)~0) 66 | #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) 67 | #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) 68 | #define T3 0x242070db 69 | #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) 70 | #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) 71 | #define T6 0x4787c62a 72 | #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) 73 | #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) 74 | #define T9 0x698098d8 75 | #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) 76 | #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) 77 | #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) 78 | #define T13 0x6b901122 79 | #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) 80 | #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) 81 | #define T16 0x49b40821 82 | #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) 83 | #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) 84 | #define T19 0x265e5a51 85 | #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) 86 | #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) 87 | #define T22 0x02441453 88 | #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) 89 | #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) 90 | #define T25 0x21e1cde6 91 | #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) 92 | #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) 93 | #define T28 0x455a14ed 94 | #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) 95 | #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) 96 | #define T31 0x676f02d9 97 | #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) 98 | #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) 99 | #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) 100 | #define T35 0x6d9d6122 101 | #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) 102 | #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) 103 | #define T38 0x4bdecfa9 104 | #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) 105 | #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) 106 | #define T41 0x289b7ec6 107 | #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) 108 | #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) 109 | #define T44 0x04881d05 110 | #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) 111 | #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) 112 | #define T47 0x1fa27cf8 113 | #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) 114 | #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) 115 | #define T50 0x432aff97 116 | #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) 117 | #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) 118 | #define T53 0x655b59c3 119 | #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) 120 | #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) 121 | #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) 122 | #define T57 0x6fa87e4f 123 | #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) 124 | #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) 125 | #define T60 0x4e0811a1 126 | #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) 127 | #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) 128 | #define T63 0x2ad7d2bb 129 | #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) 130 | 131 | 132 | static void 133 | md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { 134 | md5_word_t a = pms->abcd[0], b = pms->abcd[1], 135 | c = pms->abcd[2], d = pms->abcd[3]; 136 | md5_word_t t; 137 | #if BYTE_ORDER > 0 138 | // Define storage only for big-endian CPUs. 139 | md5_word_t X[16]; 140 | #else 141 | // Define storage for little-endian or both types of CPUs. 142 | md5_word_t xbuf[16]; 143 | const md5_word_t *X; 144 | #endif 145 | 146 | { 147 | #if BYTE_ORDER == 0 148 | /* 149 | * Determine dynamically whether this is a big-endian or 150 | * little-endian machine, since we can use a more efficient 151 | * algorithm on the latter. 152 | */ 153 | static const int w = 1; 154 | 155 | if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ 156 | #endif 157 | #if BYTE_ORDER <= 0 /* little-endian */ 158 | { 159 | /* 160 | * On little-endian machines, we can process properly aligned 161 | * data without copying it. 162 | */ 163 | if (!((data - (const md5_byte_t *)0) & 3)) { 164 | /* data are properly aligned */ 165 | X = (const md5_word_t *)data; 166 | } else { 167 | /* not aligned */ 168 | memcpy(xbuf, data, 64); 169 | X = xbuf; 170 | } 171 | } 172 | #endif 173 | #if BYTE_ORDER == 0 174 | else /* dynamic big-endian */ 175 | #endif 176 | #if BYTE_ORDER >= 0 /* big-endian */ 177 | { 178 | /* 179 | * On big-endian machines, we must arrange the bytes in the 180 | * right order. 181 | */ 182 | const md5_byte_t *xp = data; 183 | int i; 184 | 185 | #if BYTE_ORDER == 0 186 | X = xbuf; /* (dynamic only) */ 187 | #else 188 | #define xbuf X /* (static only) */ 189 | #endif 190 | for (i = 0; i < 16; ++i, xp += 4) { 191 | xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); 192 | } 193 | } 194 | #endif 195 | } 196 | 197 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 198 | 199 | /* Round 1. */ 200 | /* Let [abcd k s i] denote the operation 201 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 202 | #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) 203 | #define SET(a, b, c, d, k, s, Ti)\ 204 | t = a + F(b,c,d) + X[k] + Ti;\ 205 | a = ROTATE_LEFT(t, s) + b 206 | /* Do the following 16 operations. */ 207 | SET(a, b, c, d, 0, 7, T1); 208 | SET(d, a, b, c, 1, 12, T2); 209 | SET(c, d, a, b, 2, 17, T3); 210 | SET(b, c, d, a, 3, 22, T4); 211 | SET(a, b, c, d, 4, 7, T5); 212 | SET(d, a, b, c, 5, 12, T6); 213 | SET(c, d, a, b, 6, 17, T7); 214 | SET(b, c, d, a, 7, 22, T8); 215 | SET(a, b, c, d, 8, 7, T9); 216 | SET(d, a, b, c, 9, 12, T10); 217 | SET(c, d, a, b, 10, 17, T11); 218 | SET(b, c, d, a, 11, 22, T12); 219 | SET(a, b, c, d, 12, 7, T13); 220 | SET(d, a, b, c, 13, 12, T14); 221 | SET(c, d, a, b, 14, 17, T15); 222 | SET(b, c, d, a, 15, 22, T16); 223 | #undef SET 224 | 225 | /* Round 2. */ 226 | /* Let [abcd k s i] denote the operation 227 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 228 | #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) 229 | #define SET(a, b, c, d, k, s, Ti)\ 230 | t = a + G(b,c,d) + X[k] + Ti;\ 231 | a = ROTATE_LEFT(t, s) + b 232 | /* Do the following 16 operations. */ 233 | SET(a, b, c, d, 1, 5, T17); 234 | SET(d, a, b, c, 6, 9, T18); 235 | SET(c, d, a, b, 11, 14, T19); 236 | SET(b, c, d, a, 0, 20, T20); 237 | SET(a, b, c, d, 5, 5, T21); 238 | SET(d, a, b, c, 10, 9, T22); 239 | SET(c, d, a, b, 15, 14, T23); 240 | SET(b, c, d, a, 4, 20, T24); 241 | SET(a, b, c, d, 9, 5, T25); 242 | SET(d, a, b, c, 14, 9, T26); 243 | SET(c, d, a, b, 3, 14, T27); 244 | SET(b, c, d, a, 8, 20, T28); 245 | SET(a, b, c, d, 13, 5, T29); 246 | SET(d, a, b, c, 2, 9, T30); 247 | SET(c, d, a, b, 7, 14, T31); 248 | SET(b, c, d, a, 12, 20, T32); 249 | #undef SET 250 | 251 | /* Round 3. */ 252 | /* Let [abcd k s t] denote the operation 253 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 254 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 255 | #define SET(a, b, c, d, k, s, Ti)\ 256 | t = a + H(b,c,d) + X[k] + Ti;\ 257 | a = ROTATE_LEFT(t, s) + b 258 | /* Do the following 16 operations. */ 259 | SET(a, b, c, d, 5, 4, T33); 260 | SET(d, a, b, c, 8, 11, T34); 261 | SET(c, d, a, b, 11, 16, T35); 262 | SET(b, c, d, a, 14, 23, T36); 263 | SET(a, b, c, d, 1, 4, T37); 264 | SET(d, a, b, c, 4, 11, T38); 265 | SET(c, d, a, b, 7, 16, T39); 266 | SET(b, c, d, a, 10, 23, T40); 267 | SET(a, b, c, d, 13, 4, T41); 268 | SET(d, a, b, c, 0, 11, T42); 269 | SET(c, d, a, b, 3, 16, T43); 270 | SET(b, c, d, a, 6, 23, T44); 271 | SET(a, b, c, d, 9, 4, T45); 272 | SET(d, a, b, c, 12, 11, T46); 273 | SET(c, d, a, b, 15, 16, T47); 274 | SET(b, c, d, a, 2, 23, T48); 275 | #undef SET 276 | 277 | /* Round 4. */ 278 | /* Let [abcd k s t] denote the operation 279 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 280 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 281 | #define SET(a, b, c, d, k, s, Ti)\ 282 | t = a + I(b,c,d) + X[k] + Ti;\ 283 | a = ROTATE_LEFT(t, s) + b 284 | /* Do the following 16 operations. */ 285 | SET(a, b, c, d, 0, 6, T49); 286 | SET(d, a, b, c, 7, 10, T50); 287 | SET(c, d, a, b, 14, 15, T51); 288 | SET(b, c, d, a, 5, 21, T52); 289 | SET(a, b, c, d, 12, 6, T53); 290 | SET(d, a, b, c, 3, 10, T54); 291 | SET(c, d, a, b, 10, 15, T55); 292 | SET(b, c, d, a, 1, 21, T56); 293 | SET(a, b, c, d, 8, 6, T57); 294 | SET(d, a, b, c, 15, 10, T58); 295 | SET(c, d, a, b, 6, 15, T59); 296 | SET(b, c, d, a, 13, 21, T60); 297 | SET(a, b, c, d, 4, 6, T61); 298 | SET(d, a, b, c, 11, 10, T62); 299 | SET(c, d, a, b, 2, 15, T63); 300 | SET(b, c, d, a, 9, 21, T64); 301 | #undef SET 302 | 303 | /* Then perform the following additions. (That is increment each 304 | of the four registers by the value it had before this block 305 | was started.) */ 306 | pms->abcd[0] += a; 307 | pms->abcd[1] += b; 308 | pms->abcd[2] += c; 309 | pms->abcd[3] += d; 310 | } 311 | 312 | void 313 | md5_init(md5_state_t *pms) { 314 | pms->count[0] = pms->count[1] = 0; 315 | pms->abcd[0] = 0x67452301; 316 | pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; 317 | pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; 318 | pms->abcd[3] = 0x10325476; 319 | } 320 | 321 | void 322 | md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { 323 | const md5_byte_t *p = data; 324 | int left = nbytes; 325 | int offset = (pms->count[0] >> 3) & 63; 326 | md5_word_t nbits = (md5_word_t)(nbytes << 3); 327 | 328 | if (nbytes <= 0) { 329 | return; 330 | } 331 | 332 | /* Update the message length. */ 333 | pms->count[1] += nbytes >> 29; 334 | pms->count[0] += nbits; 335 | if (pms->count[0] < nbits) { 336 | pms->count[1]++; 337 | } 338 | 339 | /* Process an initial partial block. */ 340 | if (offset) { 341 | int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); 342 | 343 | memcpy(pms->buf + offset, p, copy); 344 | if (offset + copy < 64) { 345 | return; 346 | } 347 | p += copy; 348 | left -= copy; 349 | md5_process(pms, pms->buf); 350 | } 351 | 352 | /* Process full blocks. */ 353 | for (; left >= 64; p += 64, left -= 64) { 354 | md5_process(pms, p); 355 | } 356 | 357 | /* Process a final partial block. */ 358 | if (left) { 359 | memcpy(pms->buf, p, left); 360 | } 361 | } 362 | 363 | void 364 | md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { 365 | static const md5_byte_t pad[64] = { 366 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 370 | md5_byte_t data[8]; 371 | int i; 372 | 373 | /* Save the length before padding. */ 374 | for (i = 0; i < 8; ++i) { 375 | data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); 376 | } 377 | /* Pad to 56 bytes mod 64. */ 378 | md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); 379 | /* Append the length. */ 380 | md5_append(pms, data, 8); 381 | for (i = 0; i < 16; ++i) { 382 | digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); 383 | } 384 | } 385 | -------------------------------------------------------------------------------- /src/core/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would be 15 | appreciated but is not required. 16 | 2. Altered source versions must be plainly marked as such, and must not be 17 | misrepresented as being the original software. 18 | 3. This notice may not be removed or altered from any source distribution. 19 | 20 | L. Peter Deutsch 21 | ghost@aladdin.com 22 | 23 | */ 24 | /* $Id: md5.h,v 1.2 2007/12/24 05:58:37 lilyco Exp $ */ 25 | /* 26 | Independent implementation of MD5 (RFC 1321). 27 | 28 | This code implements the MD5 Algorithm defined in RFC 1321, whose 29 | text is available at 30 | http://www.ietf.org/rfc/rfc1321.txt 31 | The code is derived from the text of the RFC, including the test suite 32 | (section A.5) but excluding the rest of Appendix A. It does not include 33 | any code or documentation that is identified in the RFC as being 34 | copyrighted. 35 | 36 | The original and principal author of md5.h is L. Peter Deutsch 37 | . Other authors are noted in the change history 38 | that follows (in reverse chronological order): 39 | 40 | 2002-04-13 lpd Removed support for non-ANSI compilers; removed 41 | references to Ghostscript; clarified derivation from RFC 1321; 42 | now handles byte order either statically or dynamically. 43 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 44 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); 45 | added conditionalization for C++ compilation from Martin 46 | Purschke . 47 | 1999-05-03 lpd Original version. 48 | */ 49 | 50 | #ifndef md5_INCLUDED 51 | #define md5_INCLUDED 52 | 53 | /* 54 | * This package supports both compile-time and run-time determination of CPU 55 | * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be 56 | * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is 57 | * defined as non-zero, the code will be compiled to run only on big-endian 58 | * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to 59 | * run on either big- or little-endian CPUs, but will run slightly less 60 | * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. 61 | */ 62 | 63 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 64 | typedef unsigned int md5_word_t; /* 32-bit word */ 65 | 66 | /* Define the state of the MD5 Algorithm. */ 67 | typedef struct md5_state_s { 68 | md5_word_t count[2]; /* message length in bits, lsw first */ 69 | md5_word_t abcd[4]; /* digest buffer */ 70 | md5_byte_t buf[64]; /* accumulate block */ 71 | } md5_state_t; 72 | 73 | #ifdef __cplusplus 74 | extern "C" { 75 | #endif 76 | 77 | /* Initialize the algorithm. */ 78 | void md5_init(md5_state_t *pms); 79 | 80 | /* Append a string to the message. */ 81 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 82 | 83 | /* Finish the message and return the digest. */ 84 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 85 | 86 | #ifdef __cplusplus 87 | } /* end extern "C" */ 88 | #endif 89 | 90 | #endif /* md5_INCLUDED */ 91 | -------------------------------------------------------------------------------- /src/core/packet.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/02/2011 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_PACKET_H__ 42 | #define __UDT_PACKET_H__ 43 | 44 | 45 | #include "udt.h" 46 | 47 | #ifdef WIN32 48 | struct iovec { 49 | int iov_len; 50 | char* iov_base; 51 | }; 52 | #endif 53 | 54 | class CChannel; 55 | 56 | class CPacket { 57 | friend class CChannel; 58 | friend class CSndQueue; 59 | friend class CRcvQueue; 60 | 61 | public: 62 | // alias: sequence number 63 | int32_t& m_iSeqNo; 64 | // alias: message number 65 | int32_t& m_iMsgNo; 66 | // alias: timestamp 67 | int32_t& m_iTimeStamp; 68 | // alias: socket ID 69 | int32_t& m_iID; 70 | // alias: data/control information 71 | char*& m_pcData; 72 | 73 | // packet header size 74 | static const int m_iPktHdrSize; 75 | 76 | CPacket(); 77 | ~CPacket(); 78 | 79 | // Functionality: 80 | // Get the payload or the control information field length. 81 | // Parameters: 82 | // None. 83 | // Returned value: 84 | // the payload or the control information field length. 85 | int getLength() const; 86 | 87 | // Functionality: 88 | // Set the payload or the control information field length. 89 | // Parameters: 90 | // 0) [in] len: the payload or the control information field length. 91 | // Returned value: 92 | // None. 93 | void setLength(const int& len); 94 | 95 | // Functionality: 96 | // Pack a Control packet. 97 | // Parameters: 98 | // 0) [in] pkttype: packet type filed. 99 | // 1) [in] lparam: pointer to the first data structure, explained by the 100 | // packet type. 101 | // 2) [in] rparam: pointer to the second data structure, explained by the 102 | // packet type. 103 | // 3) [in] size: size of rparam, in number of bytes; 104 | // Returned value: 105 | // None. 106 | void pack(const int& pkttype, 107 | void* lparam = NULL, 108 | void* rparam = NULL, 109 | const int& size = 0); 110 | 111 | // Functionality: 112 | // Read the packet vector. 113 | // Parameters: 114 | // None. 115 | // Returned value: 116 | // Pointer to the packet vector. 117 | iovec* getPacketVector(); 118 | 119 | // Functionality: 120 | // Read the packet flag. 121 | // Parameters: 122 | // None. 123 | // Returned value: 124 | // packet flag (0 or 1). 125 | int getFlag() const; 126 | 127 | // Functionality: 128 | // Read the packet type. 129 | // Parameters: 130 | // None. 131 | // Returned value: 132 | // packet type filed (000 ~ 111). 133 | int getType() const; 134 | 135 | // Functionality: 136 | // Read the extended packet type. 137 | // Parameters: 138 | // None. 139 | // Returned value: 140 | // extended packet type filed (0x000 ~ 0xFFF). 141 | int getExtendedType() const; 142 | 143 | // Functionality: 144 | // Read the ACK-2 seq. no. 145 | // Parameters: 146 | // None. 147 | // Returned value: 148 | // packet header field (bit 16~31). 149 | int32_t getAckSeqNo() const; 150 | 151 | // Functionality: 152 | // Read the message boundary flag bit. 153 | // Parameters: 154 | // None. 155 | // Returned value: 156 | // packet header field [1] (bit 0~1). 157 | int getMsgBoundary() const; 158 | 159 | // Functionality: 160 | // Read the message inorder delivery flag bit. 161 | // Parameters: 162 | // None. 163 | // Returned value: 164 | // packet header field [1] (bit 2). 165 | bool getMsgOrderFlag() const; 166 | 167 | // Functionality: 168 | // Read the message sequence number. 169 | // Parameters: 170 | // None. 171 | // Returned value: 172 | // packet header field [1] (bit 3~31). 173 | int32_t getMsgSeq() const; 174 | 175 | // Functionality: 176 | // Clone this packet. 177 | // Parameters: 178 | // None. 179 | // Returned value: 180 | // Pointer to the new packet. 181 | CPacket* clone() const; 182 | 183 | protected: 184 | // The 128-bit header field 185 | uint32_t m_nHeader[4]; 186 | // The 2-demension vector of UDT packet [header, data] 187 | iovec m_PacketVector[2]; 188 | 189 | int32_t __pad; 190 | 191 | CPacket& operator=(const CPacket&); 192 | }; 193 | 194 | //////////////////////////////////////////////////////////////////////////////// 195 | 196 | class CHandShake { 197 | public: 198 | CHandShake(); 199 | 200 | int serialize(char* buf, int& size); 201 | int deserialize(const char* buf, const int& size); 202 | 203 | // Size of hand shake data 204 | static const int m_iContentSize; 205 | 206 | // UDT version 207 | int32_t m_iVersion; 208 | // UDT socket type 209 | int32_t m_iType; 210 | // random initial sequence number 211 | int32_t m_iISN; 212 | // maximum segment size 213 | int32_t m_iMSS; 214 | // flow control window size 215 | int32_t m_iFlightFlagSize; 216 | // connection request type: 1: regular connection request, 0: rendezvous connection request, -1/-2: response 217 | int32_t m_iReqType; 218 | // socket ID 219 | int32_t m_iID; 220 | // cookie 221 | int32_t m_iCookie; 222 | // The IP address that the peer's UDP port is bound to 223 | uint32_t m_piPeerIP[4]; 224 | }; 225 | 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /src/core/window.cpp: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/22/2011 39 | *****************************************************************************/ 40 | 41 | #include "common.h" 42 | #include "window.h" 43 | 44 | #include 45 | #include 46 | 47 | using namespace std; 48 | 49 | CACKWindow::CACKWindow(const int& size) : m_piACKSeqNo(NULL), 50 | m_piACK(NULL), 51 | m_pTimeStamp(NULL), 52 | m_iSize(size), 53 | m_iHead(0), 54 | m_iTail(0) { 55 | m_piACKSeqNo = new int32_t[m_iSize]; 56 | m_piACK = new int32_t[m_iSize]; 57 | m_pTimeStamp = new uint64_t[m_iSize]; 58 | 59 | m_piACKSeqNo[0] = -1; 60 | } 61 | 62 | CACKWindow::~CACKWindow() { 63 | delete [] m_piACKSeqNo; 64 | delete [] m_piACK; 65 | delete [] m_pTimeStamp; 66 | } 67 | 68 | void CACKWindow::store(const int32_t& seq, const int32_t& ack) { 69 | m_piACKSeqNo[m_iHead] = seq; 70 | m_piACK[m_iHead] = ack; 71 | m_pTimeStamp[m_iHead] = CTimer::getTime(); 72 | 73 | m_iHead = (m_iHead + 1) % m_iSize; 74 | 75 | // overwrite the oldest ACK since it is not likely to be acknowledged 76 | if (m_iHead == m_iTail) { 77 | m_iTail = (m_iTail + 1) % m_iSize; 78 | } 79 | } 80 | 81 | int CACKWindow::acknowledge(const int32_t& seq, int32_t& ack) { 82 | if (m_iHead >= m_iTail) { 83 | // Head has not exceeded the physical boundary of the window 84 | 85 | for (int i = m_iTail, n = m_iHead; i < n; ++i) { 86 | // looking for indentical ACK Seq. No. 87 | if (seq == m_piACKSeqNo[i]) { 88 | // return the Data ACK it carried 89 | ack = m_piACK[i]; 90 | 91 | // calculate RTT 92 | int rtt = int(CTimer::getTime() - m_pTimeStamp[i]); 93 | 94 | if (i + 1 == m_iHead) { 95 | m_iTail = m_iHead = 0; 96 | m_piACKSeqNo[0] = -1; 97 | } else { 98 | m_iTail = (i + 1) % m_iSize; 99 | } 100 | 101 | return rtt; 102 | } 103 | } 104 | 105 | // Bad input, the ACK node has been overwritten 106 | return -1; 107 | } 108 | 109 | // Head has exceeded the physical window boundary, so it is behind tail 110 | for (int j = m_iTail, n = m_iHead + m_iSize; j < n; ++j) { 111 | // looking for indentical ACK seq. no. 112 | if (seq == m_piACKSeqNo[j % m_iSize]) { 113 | // return Data ACK 114 | j %= m_iSize; 115 | ack = m_piACK[j]; 116 | 117 | // calculate RTT 118 | int rtt = int(CTimer::getTime() - m_pTimeStamp[j]); 119 | 120 | if (j == m_iHead) { 121 | m_iTail = m_iHead = 0; 122 | m_piACKSeqNo[0] = -1; 123 | } else { 124 | m_iTail = (j + 1) % m_iSize; 125 | } 126 | 127 | return rtt; 128 | } 129 | } 130 | 131 | // bad input, the ACK node has been overwritten 132 | return -1; 133 | } 134 | 135 | //////////////////////////////////////////////////////////////////////////////// 136 | 137 | CPktTimeWindow::CPktTimeWindow(const int& asize, const int& psize) 138 | : m_iAWSize(asize), 139 | m_piPktWindow(NULL), 140 | m_iPktWindowPtr(0), 141 | m_iPWSize(psize), 142 | m_piProbeWindow(NULL), 143 | m_iProbeWindowPtr(0), 144 | m_iLastSentTime(0), 145 | m_iMinPktSndInt(1000000), 146 | m_LastArrTime(), 147 | m_CurrArrTime(), 148 | m_ProbeTime() { 149 | m_piPktWindow = new int[m_iAWSize]; 150 | m_piPktReplica = new int[m_iAWSize]; 151 | m_piProbeWindow = new int[m_iPWSize]; 152 | m_piProbeReplica = new int[m_iPWSize]; 153 | 154 | m_LastArrTime = CTimer::getTime(); 155 | 156 | for (int i = 0; i < m_iAWSize; ++ i) { 157 | m_piPktWindow[i] = 1000000; 158 | } 159 | 160 | for (int k = 0; k < m_iPWSize; ++ k) { 161 | m_piProbeWindow[k] = 1000; 162 | } 163 | } 164 | 165 | CPktTimeWindow::~CPktTimeWindow() { 166 | delete [] m_piPktWindow; 167 | delete [] m_piPktReplica; 168 | delete [] m_piProbeWindow; 169 | delete [] m_piProbeReplica; 170 | } 171 | 172 | int CPktTimeWindow::getMinPktSndInt() const { 173 | return m_iMinPktSndInt; 174 | } 175 | 176 | int CPktTimeWindow::getPktRcvSpeed() const { 177 | // get median value, but cannot change the original value order in the window 178 | std::copy(m_piPktWindow, m_piPktWindow + m_iAWSize - 1, m_piPktReplica); 179 | std::nth_element(m_piPktReplica, m_piPktReplica + (m_iAWSize / 2), m_piPktReplica + m_iAWSize - 1); 180 | int median = m_piPktReplica[m_iAWSize / 2]; 181 | 182 | int count = 0; 183 | int sum = 0; 184 | int upper = median << 3; 185 | int lower = median >> 3; 186 | 187 | // median filtering 188 | int* p = m_piPktWindow; 189 | for (int i = 0, n = m_iAWSize; i < n; ++i) { 190 | if (*p < upper && *p > lower) { 191 | ++ count; 192 | sum += *p; 193 | } 194 | ++p; 195 | } 196 | 197 | // claculate speed, or return 0 if not enough valid value 198 | if (count > (m_iAWSize >> 1)) { 199 | return (int)ceil(1000000.0 / (sum / count)); 200 | } else { 201 | return 0; 202 | } 203 | } 204 | 205 | int CPktTimeWindow::getBandwidth() const { 206 | // get median value, but cannot change the original value order in the window 207 | std::copy(m_piProbeWindow, m_piProbeWindow + m_iPWSize - 1, m_piProbeReplica); 208 | std::nth_element(m_piProbeReplica, m_piProbeReplica + (m_iPWSize / 2), 209 | m_piProbeReplica + m_iPWSize - 1); 210 | int median = m_piProbeReplica[m_iPWSize / 2]; 211 | 212 | int count = 1; 213 | int sum = median; 214 | int upper = median << 3; 215 | int lower = median >> 3; 216 | 217 | // median filtering 218 | int* p = m_piProbeWindow; 219 | for (int i = 0, n = m_iPWSize; i < n; ++i) { 220 | if (*p < upper && *p > lower) { 221 | ++ count; 222 | sum += *p; 223 | } 224 | ++p; 225 | } 226 | 227 | return (int)ceil(1000000.0 / (double(sum) / double(count))); 228 | } 229 | 230 | void CPktTimeWindow::onPktSent(const int& currtime) { 231 | int interval = currtime - m_iLastSentTime; 232 | 233 | if (interval < m_iMinPktSndInt && interval > 0) { 234 | m_iMinPktSndInt = interval; 235 | } 236 | 237 | m_iLastSentTime = currtime; 238 | } 239 | 240 | void CPktTimeWindow::onPktArrival() { 241 | m_CurrArrTime = CTimer::getTime(); 242 | 243 | // record the packet interval between the current and the last one 244 | *(m_piPktWindow + m_iPktWindowPtr) = int(m_CurrArrTime - m_LastArrTime); 245 | 246 | // the window is logically circular 247 | ++ m_iPktWindowPtr; 248 | if (m_iPktWindowPtr == m_iAWSize) { 249 | m_iPktWindowPtr = 0; 250 | } 251 | 252 | // remember last packet arrival time 253 | m_LastArrTime = m_CurrArrTime; 254 | } 255 | 256 | void CPktTimeWindow::probe1Arrival() { 257 | m_ProbeTime = CTimer::getTime(); 258 | } 259 | 260 | void CPktTimeWindow::probe2Arrival() { 261 | m_CurrArrTime = CTimer::getTime(); 262 | 263 | // record the probing packets interval 264 | *(m_piProbeWindow + m_iProbeWindowPtr) = int(m_CurrArrTime - m_ProbeTime); 265 | // the window is logically circular 266 | ++m_iProbeWindowPtr; 267 | if (m_iProbeWindowPtr == m_iPWSize) { 268 | m_iProbeWindowPtr = 0; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/core/window.h: -------------------------------------------------------------------------------- 1 | /***************************************************************************** 2 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois. 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 | /***************************************************************************** 37 | written by 38 | Yunhong Gu, last updated 01/22/2011 39 | *****************************************************************************/ 40 | 41 | #ifndef __UDT_WINDOW_H__ 42 | #define __UDT_WINDOW_H__ 43 | 44 | #include "udt.h" 45 | 46 | #ifndef WIN32 47 | #include 48 | #include 49 | #endif 50 | 51 | 52 | class CACKWindow { 53 | public: 54 | CACKWindow(const int& size = 1024); 55 | ~CACKWindow(); 56 | 57 | // Functionality: 58 | // Write an ACK record into the window. 59 | // Parameters: 60 | // 0) [in] seq: ACK seq. no. 61 | // 1) [in] ack: DATA ACK no. 62 | // Returned value: 63 | // None. 64 | void store(const int32_t& seq, const int32_t& ack); 65 | 66 | // Functionality: 67 | // Search the ACK-2 "seq" in the window, find out the DATA "ack" and 68 | // caluclate RTT . 69 | // Parameters: 70 | // 0) [in] seq: ACK-2 seq. no. 71 | // 1) [out] ack: the DATA ACK no. that matches the ACK-2 no. 72 | // Returned value: 73 | // RTT. 74 | int acknowledge(const int32_t& seq, int32_t& ack); 75 | 76 | private: 77 | // Seq. No. for the ACK packet 78 | int32_t* m_piACKSeqNo; 79 | // Data Seq. No. carried by the ACK packet 80 | int32_t* m_piACK; 81 | // The timestamp when the ACK was sent 82 | uint64_t* m_pTimeStamp; 83 | 84 | // Size of the ACK history window 85 | int m_iSize; 86 | // Pointer to the lastest ACK record 87 | int m_iHead; 88 | // Pointer to the oldest ACK record 89 | int m_iTail; 90 | 91 | CACKWindow(const CACKWindow&); 92 | CACKWindow& operator=(const CACKWindow&); 93 | }; 94 | 95 | //////////////////////////////////////////////////////////////////////////////// 96 | 97 | class CPktTimeWindow { 98 | public: 99 | CPktTimeWindow(const int& asize = 16, const int& psize = 16); 100 | ~CPktTimeWindow(); 101 | 102 | // Functionality: 103 | // read the minimum packet sending interval. 104 | // Parameters: 105 | // None. 106 | // Returned value: 107 | // minimum packet sending interval (microseconds). 108 | int getMinPktSndInt() const; 109 | 110 | // Functionality: 111 | // Calculate the packes arrival speed. 112 | // Parameters: 113 | // None. 114 | // Returned value: 115 | // Packet arrival speed (packets per second). 116 | int getPktRcvSpeed() const; 117 | 118 | // Functionality: 119 | // Estimate the bandwidth. 120 | // Parameters: 121 | // None. 122 | // Returned value: 123 | // Estimated bandwidth (packets per second). 124 | int getBandwidth() const; 125 | 126 | // Functionality: 127 | // Record time information of a packet sending. 128 | // Parameters: 129 | // 0) currtime: timestamp of the packet sending. 130 | // Returned value: 131 | // None. 132 | void onPktSent(const int& currtime); 133 | 134 | // Functionality: 135 | // Record time information of an arrived packet. 136 | // Parameters: 137 | // None. 138 | // Returned value: 139 | // None. 140 | void onPktArrival(); 141 | 142 | // Functionality: 143 | // Record the arrival time of the first probing packet. 144 | // Parameters: 145 | // None. 146 | // Returned value: 147 | // None. 148 | void probe1Arrival(); 149 | 150 | // Functionality: 151 | // Record the arrival time of the second probing packet and the interval between packet pairs. 152 | // Parameters: 153 | // None. 154 | // Returned value: 155 | // None. 156 | void probe2Arrival(); 157 | 158 | private: 159 | // size of the packet arrival history window 160 | int m_iAWSize; 161 | // packet information window 162 | int* m_piPktWindow; 163 | int* m_piPktReplica; 164 | // position pointer of the packet info. window. 165 | int m_iPktWindowPtr; 166 | 167 | // size of probe history window size 168 | int m_iPWSize; 169 | // record inter-packet time for probing packet pairs 170 | int* m_piProbeWindow; 171 | int* m_piProbeReplica; 172 | // position pointer to the probing window 173 | int m_iProbeWindowPtr; 174 | 175 | // last packet sending time 176 | int m_iLastSentTime; 177 | // Minimum packet sending interval 178 | int m_iMinPktSndInt; 179 | 180 | // last packet arrival time 181 | uint64_t m_LastArrTime; 182 | // current packet arrival time 183 | uint64_t m_CurrArrTime; 184 | // arrival time of the first probing packet 185 | uint64_t m_ProbeTime; 186 | 187 | CPktTimeWindow(const CPktTimeWindow&); 188 | CPktTimeWindow &operator=(const CPktTimeWindow&); 189 | }; 190 | 191 | 192 | #endif 193 | -------------------------------------------------------------------------------- /src/pcc/Makefile: -------------------------------------------------------------------------------- 1 | C++ = g++ -g -std=c++11 2 | 3 | ifndef os 4 | os = LINUX 5 | endif 6 | 7 | ifndef arch 8 | arch = IA32 9 | endif 10 | 11 | CCFLAGS = -fPIC -Wall -Wextra -D$(os) -finline-functions -O3 -fno-strict-aliasing #-msse3 12 | 13 | ifeq ($(arch), IA32) 14 | CCFLAGS += -DIA32 15 | endif 16 | 17 | ifeq ($(arch), POWERPC) 18 | CCFLAGS += -mcpu=powerpc 19 | endif 20 | 21 | ifeq ($(arch), SPARC) 22 | CCFLAGS += -DSPARC 23 | endif 24 | 25 | ifeq ($(arch), IA64) 26 | CCFLAGS += -DIA64 27 | endif 28 | 29 | ifeq ($(arch), AMD64) 30 | CCFLAGS += -DAMD64 31 | endif 32 | 33 | OBJS = pcc_monitor_interval_queue.o pcc_utility_manager.o pcc_sender.o pcc_vivace_sender.o 34 | DIR = $(shell pwd) 35 | 36 | all: $(OBJS) 37 | 38 | %.o: %.cpp %.h 39 | $(C++) $(CCFLAGS) $< -c 40 | 41 | clean: 42 | rm -f *.o 43 | -------------------------------------------------------------------------------- /src/pcc/pcc_monitor_interval_queue.cpp: -------------------------------------------------------------------------------- 1 | #include "pcc_monitor_interval_queue.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | //#include "third_party/pcc_quic/pcc_monitor_interval_queue.h" 8 | 9 | //#include "third_party/quic/core/congestion_control/rtt_stats.h" 10 | 11 | // namespace quic { 12 | 13 | namespace { 14 | // Minimum number of reliable RTT samples per monitor interval. 15 | const size_t kMinReliableRtt = 4; 16 | } 17 | 18 | PacketRttSample::PacketRttSample() 19 | : packet_number(0), 20 | sample_rtt(QuicTime::Delta::Zero()), 21 | ack_timestamp(QuicTime::Zero()), 22 | is_reliable(false), 23 | is_reliable_for_gradient_calculation(false) {} 24 | 25 | PacketRttSample::PacketRttSample(QuicPacketNumber packet_number, 26 | QuicTime::Delta rtt, 27 | QuicTime ack_timestamp, 28 | bool reliability, 29 | bool gradient_reliability) 30 | : packet_number(packet_number), 31 | sample_rtt(rtt), 32 | ack_timestamp(ack_timestamp), 33 | is_reliable(reliability), 34 | is_reliable_for_gradient_calculation(gradient_reliability) {} 35 | 36 | LostPacketSample::LostPacketSample() : packet_number(0), bytes(0) {} 37 | 38 | LostPacketSample::LostPacketSample( 39 | QuicPacketNumber packet_number, 40 | QuicByteCount bytes) : packet_number(packet_number), 41 | bytes(bytes) {} 42 | 43 | 44 | MonitorInterval::MonitorInterval() 45 | : sending_rate(QuicBandwidth::Zero()), 46 | is_useful(false), 47 | rtt_fluctuation_tolerance_ratio(0.0), 48 | first_packet_sent_time(QuicTime::Zero()), 49 | last_packet_sent_time(QuicTime::Zero()), 50 | first_packet_number(0), 51 | last_packet_number(0), 52 | bytes_sent(0), 53 | bytes_acked(0), 54 | bytes_lost(0), 55 | rtt_on_monitor_start(QuicTime::Delta::Zero()), 56 | rtt_on_monitor_end(QuicTime::Delta::Zero()), 57 | min_rtt(QuicTime::Delta::Zero()), 58 | num_reliable_rtt(0), 59 | num_reliable_rtt_for_gradient_calculation(0), 60 | has_enough_reliable_rtt(false), 61 | is_monitor_duration_extended(false) {} 62 | 63 | MonitorInterval::MonitorInterval(QuicBandwidth sending_rate, 64 | bool is_useful, 65 | float rtt_fluctuation_tolerance_ratio, 66 | QuicTime::Delta rtt) 67 | : sending_rate(sending_rate), 68 | is_useful(is_useful), 69 | rtt_fluctuation_tolerance_ratio(rtt_fluctuation_tolerance_ratio), 70 | first_packet_sent_time(QuicTime::Zero()), 71 | last_packet_sent_time(QuicTime::Zero()), 72 | first_packet_number(0), 73 | last_packet_number(0), 74 | bytes_sent(0), 75 | bytes_acked(0), 76 | bytes_lost(0), 77 | rtt_on_monitor_start(rtt), 78 | rtt_on_monitor_end(rtt), 79 | min_rtt(rtt), 80 | num_reliable_rtt(0), 81 | num_reliable_rtt_for_gradient_calculation(0), 82 | has_enough_reliable_rtt(false), 83 | is_monitor_duration_extended(false) {} 84 | 85 | PccMonitorIntervalQueue::PccMonitorIntervalQueue( 86 | PccMonitorIntervalQueueDelegateInterface* delegate) 87 | : pending_rtt_(QuicTime::Delta::Zero()), 88 | pending_avg_rtt_(QuicTime::Delta::Zero()), 89 | pending_ack_interval_(QuicTime::Delta::Zero()), 90 | pending_event_time_(QuicTime::Zero()), 91 | burst_flag_(false), 92 | avg_interval_ratio_(-1.0), 93 | num_useful_intervals_(0), 94 | num_available_intervals_(0), 95 | delegate_(delegate) {} 96 | 97 | void PccMonitorIntervalQueue::EnqueueNewMonitorInterval( 98 | QuicBandwidth sending_rate, 99 | bool is_useful, 100 | float rtt_fluctuation_tolerance_ratio, 101 | QuicTime::Delta rtt) { 102 | if (is_useful) { 103 | ++num_useful_intervals_; 104 | } 105 | 106 | monitor_intervals_.emplace_back(sending_rate, is_useful, 107 | rtt_fluctuation_tolerance_ratio, rtt); 108 | } 109 | 110 | void PccMonitorIntervalQueue::OnPacketSent(QuicTime sent_time, 111 | QuicPacketNumber packet_number, 112 | QuicByteCount bytes, 113 | QuicTime::Delta sent_interval) { 114 | if (monitor_intervals_.empty()) { 115 | std::cerr << "OnPacketSent called with empty queue."; 116 | return; 117 | } 118 | 119 | if (monitor_intervals_.back().bytes_sent == 0) { 120 | // This is the first packet of this interval. 121 | monitor_intervals_.back().first_packet_sent_time = sent_time; 122 | monitor_intervals_.back().first_packet_number = packet_number; 123 | } 124 | 125 | monitor_intervals_.back().last_packet_sent_time = sent_time; 126 | monitor_intervals_.back().last_packet_number = packet_number; 127 | monitor_intervals_.back().bytes_sent += bytes; 128 | 129 | monitor_intervals_.back().packet_sent_intervals.push_back(sent_interval); 130 | } 131 | 132 | void PccMonitorIntervalQueue::OnCongestionEvent( 133 | const AckedPacketVector& acked_packets, 134 | const LostPacketVector& lost_packets, 135 | QuicTime::Delta avg_rtt, 136 | QuicTime::Delta latest_rtt, 137 | QuicTime::Delta min_rtt, 138 | QuicTime event_time, 139 | QuicTime::Delta ack_interval) { 140 | num_available_intervals_ = 0; 141 | if (num_useful_intervals_ == 0) { 142 | // Skip all the received packets if no intervals are useful. 143 | return; 144 | } 145 | 146 | bool has_invalid_utility = false; 147 | for (MonitorInterval& interval : monitor_intervals_) { 148 | if (!interval.is_useful) { 149 | // Skips useless monitor intervals. 150 | continue; 151 | } 152 | 153 | if (IsUtilityAvailable(interval)) { 154 | // Skip intervals with available utilities. 155 | ++num_available_intervals_; 156 | continue; 157 | } 158 | 159 | for (const LostPacket& lost_packet : lost_packets) { 160 | if (IntervalContainsPacket(interval, lost_packet.packet_number)) { 161 | interval.bytes_lost += lost_packet.bytes_lost; 162 | interval.lost_packet_samples.push_back(LostPacketSample( 163 | lost_packet.packet_number, lost_packet.bytes_lost)); 164 | } 165 | } 166 | 167 | for (const AckedPacket& acked_packet : pending_acked_packets_) { 168 | if (IntervalContainsPacket(interval, acked_packet.packet_number)) { 169 | if (interval.bytes_acked == 0) { 170 | // This is the RTT before starting sending at interval.sending_rate. 171 | interval.rtt_on_monitor_start = pending_avg_rtt_; 172 | } 173 | interval.bytes_acked += acked_packet.bytes_acked; 174 | 175 | bool is_reliable = false; 176 | if (!pending_ack_interval_.IsZero()) { 177 | float interval_ratio = 178 | static_cast(pending_ack_interval_.ToMicroseconds()) / 179 | static_cast(ack_interval.ToMicroseconds()); 180 | if (interval_ratio < 1.0) { 181 | interval_ratio = 1.0 / interval_ratio; 182 | } 183 | if (avg_interval_ratio_ < 0) { 184 | avg_interval_ratio_ = interval_ratio; 185 | } 186 | 187 | if (interval_ratio > 50.0 * avg_interval_ratio_) { 188 | burst_flag_ = true; 189 | } else if (burst_flag_) { 190 | if (latest_rtt > pending_rtt_ && pending_rtt_ < pending_avg_rtt_) { 191 | burst_flag_ = false; 192 | } 193 | } else { 194 | is_reliable = true; 195 | interval.num_reliable_rtt++; 196 | } 197 | 198 | avg_interval_ratio_ = 199 | avg_interval_ratio_ * 0.9 + interval_ratio * 0.1; 200 | } 201 | 202 | bool is_reliable_for_gradient_calculation = false; 203 | if (is_reliable) { 204 | //if (latest_rtt > pending_rtt_) { 205 | is_reliable_for_gradient_calculation = true; 206 | interval.num_reliable_rtt_for_gradient_calculation++; 207 | } 208 | 209 | interval.packet_rtt_samples.push_back(PacketRttSample( 210 | acked_packet.packet_number, pending_rtt_, pending_event_time_, 211 | is_reliable, is_reliable_for_gradient_calculation)); 212 | if (interval.num_reliable_rtt >= kMinReliableRtt) { 213 | interval.has_enough_reliable_rtt = true; 214 | } 215 | } 216 | } 217 | 218 | if (IsUtilityAvailable(interval)) { 219 | interval.rtt_on_monitor_end = avg_rtt; 220 | interval.min_rtt = min_rtt; 221 | has_invalid_utility = HasInvalidUtility(&interval); 222 | if (has_invalid_utility) { 223 | break; 224 | } 225 | ++num_available_intervals_; 226 | assert(num_available_intervals_ <= num_useful_intervals_); 227 | } 228 | } 229 | 230 | pending_acked_packets_.clear(); 231 | for (const AckedPacket acked_packet : acked_packets) { 232 | pending_acked_packets_.push_back(acked_packet); 233 | } 234 | pending_rtt_ = latest_rtt; 235 | pending_avg_rtt_ = avg_rtt; 236 | pending_ack_interval_ = ack_interval; 237 | pending_event_time_ = event_time; 238 | 239 | if (num_useful_intervals_ > num_available_intervals_ && 240 | !has_invalid_utility) { 241 | return; 242 | } 243 | 244 | if (!has_invalid_utility) { 245 | assert(num_useful_intervals_ > 0u); 246 | 247 | std::vector useful_intervals; 248 | for (const MonitorInterval& interval : monitor_intervals_) { 249 | if (!interval.is_useful) { 250 | continue; 251 | } 252 | useful_intervals.push_back(&interval); 253 | } 254 | assert(num_available_intervals_ == useful_intervals.size()); 255 | 256 | delegate_->OnUtilityAvailable(useful_intervals, event_time); 257 | } 258 | 259 | // Remove MonitorIntervals from the head of the queue, 260 | // until all useful intervals are removed. 261 | while (num_useful_intervals_ > 0) { 262 | if (monitor_intervals_.front().is_useful) { 263 | --num_useful_intervals_; 264 | } 265 | monitor_intervals_.pop_front(); 266 | } 267 | num_available_intervals_ = 0; 268 | } 269 | 270 | const MonitorInterval& PccMonitorIntervalQueue::front() const { 271 | assert(!monitor_intervals_.empty()); 272 | return monitor_intervals_.front(); 273 | } 274 | 275 | const MonitorInterval& PccMonitorIntervalQueue::current() const { 276 | assert(!monitor_intervals_.empty()); 277 | return monitor_intervals_.back(); 278 | } 279 | 280 | void PccMonitorIntervalQueue::extend_current_interval() { 281 | assert(!monitor_intervals_.empty()); 282 | monitor_intervals_.back().is_monitor_duration_extended = true; 283 | } 284 | 285 | bool PccMonitorIntervalQueue::empty() const { 286 | return monitor_intervals_.empty(); 287 | } 288 | 289 | size_t PccMonitorIntervalQueue::size() const { 290 | return monitor_intervals_.size(); 291 | } 292 | 293 | void PccMonitorIntervalQueue::OnRttInflationInStarting() { 294 | monitor_intervals_.clear(); 295 | num_useful_intervals_ = 0; 296 | num_available_intervals_ = 0; 297 | } 298 | 299 | bool PccMonitorIntervalQueue::IsUtilityAvailable( 300 | const MonitorInterval& interval) const { 301 | return (interval.has_enough_reliable_rtt && 302 | interval.bytes_acked + interval.bytes_lost == interval.bytes_sent); 303 | } 304 | 305 | bool PccMonitorIntervalQueue::IntervalContainsPacket( 306 | const MonitorInterval& interval, 307 | QuicPacketNumber packet_number) const { 308 | return (packet_number >= interval.first_packet_number && 309 | packet_number <= interval.last_packet_number); 310 | } 311 | 312 | bool PccMonitorIntervalQueue::HasInvalidUtility( 313 | const MonitorInterval* interval) const { 314 | return interval->first_packet_sent_time == interval->last_packet_sent_time; 315 | } 316 | 317 | // } // namespace quic 318 | -------------------------------------------------------------------------------- /src/pcc/pcc_monitor_interval_queue.h: -------------------------------------------------------------------------------- 1 | #ifndef THIRD_PARTY_PCC_QUIC_PCC_MONITOR_QUEUE_H_ 2 | #define THIRD_PARTY_PCC_QUIC_PCC_MONITOR_QUEUE_H_ 3 | 4 | #include "quic_types/quic_bandwidth.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | //#include "third_party/quic/core/congestion_control/send_algorithm_interface.h" 11 | //#include "third_party/quic/core/quic_time.h" 12 | //#include "third_party/quic/core/quic_types.h" 13 | 14 | // namespace quic { 15 | 16 | // PacketRttSample, stores packet number and the corresponding RTT. 17 | struct PacketRttSample { 18 | PacketRttSample(); 19 | PacketRttSample(QuicPacketNumber packet_number, 20 | QuicTime::Delta rtt, 21 | QuicTime ack_timestamp, 22 | bool reliability, 23 | bool gradient_reliability); 24 | ~PacketRttSample() {} 25 | 26 | // Packet number of the sampled packet. 27 | QuicPacketNumber packet_number; 28 | // RTT corresponding to the sampled packet. 29 | QuicTime::Delta sample_rtt; 30 | // Timestamp when the ACK of the sampled packet is received. 31 | QuicTime ack_timestamp; 32 | 33 | // Flag representing if the RTT sample is reliable for utility calculation. 34 | bool is_reliable; 35 | bool is_reliable_for_gradient_calculation; 36 | }; 37 | 38 | struct LostPacketSample { 39 | LostPacketSample(); 40 | LostPacketSample(QuicPacketNumber packet_number, 41 | QuicByteCount bytes); 42 | 43 | QuicPacketNumber packet_number; 44 | QuicByteCount bytes; 45 | }; 46 | 47 | // MonitorInterval, as the queue's entry struct, stores the information 48 | // of a PCC monitor interval (MonitorInterval) that can be used to 49 | // - pinpoint a acked/lost packet to the corresponding MonitorInterval, 50 | // - calculate the MonitorInterval's utility value. 51 | struct MonitorInterval { 52 | MonitorInterval(); 53 | MonitorInterval(QuicBandwidth sending_rate, 54 | bool is_useful, 55 | float rtt_fluctuation_tolerance_ratio, 56 | QuicTime::Delta rtt); 57 | ~MonitorInterval() {} 58 | 59 | // Sending rate. 60 | QuicBandwidth sending_rate; 61 | // True if calculating utility for this MonitorInterval. 62 | bool is_useful; 63 | // The tolerable rtt fluctuation ratio. 64 | float rtt_fluctuation_tolerance_ratio; 65 | 66 | // Sent time of the first packet. 67 | QuicTime first_packet_sent_time; 68 | // Sent time of the last packet. 69 | QuicTime last_packet_sent_time; 70 | 71 | // PacketNumber of the first sent packet. 72 | QuicPacketNumber first_packet_number; 73 | // PacketNumber of the last sent packet. 74 | QuicPacketNumber last_packet_number; 75 | 76 | // Number of bytes which are sent in total. 77 | QuicByteCount bytes_sent; 78 | // Number of bytes which have been acked. 79 | QuicByteCount bytes_acked; 80 | // Number of bytes which are considered as lost. 81 | QuicByteCount bytes_lost; 82 | 83 | // Smoothed RTT when the first packet is sent. 84 | QuicTime::Delta rtt_on_monitor_start; 85 | // RTT when all sent packets are either acked or lost. 86 | QuicTime::Delta rtt_on_monitor_end; 87 | // Minimum RTT seen by PCC sender. 88 | QuicTime::Delta min_rtt; 89 | 90 | // Interval since previous sent packet for each packet in the interval. 91 | std::vector packet_sent_intervals; 92 | // Packet RTT sample for each sent packet in the monitor interval. 93 | std::vector packet_rtt_samples; 94 | // Lost packet sample for each lost packet in the monitor interval. 95 | std::vector lost_packet_samples; 96 | 97 | size_t num_reliable_rtt; 98 | size_t num_reliable_rtt_for_gradient_calculation; 99 | // True if the interval has enough number of reliable RTT samples. 100 | bool has_enough_reliable_rtt; 101 | 102 | // True only if the monitor duration is doubled due to lack of reliable RTTs. 103 | bool is_monitor_duration_extended; 104 | }; 105 | 106 | // A delegate interface for further processing when all 107 | // 'useful' MonitorIntervals' utilities are available. 108 | class PccMonitorIntervalQueueDelegateInterface { 109 | public: 110 | virtual ~PccMonitorIntervalQueueDelegateInterface() {} 111 | 112 | virtual void OnUtilityAvailable( 113 | const std::vector& useful_intervals, 114 | QuicTime event_time) = 0; 115 | }; 116 | 117 | // PccMonitorIntervalQueue contains a queue of MonitorIntervals. 118 | // New MonitorIntervals are added to the tail of the queue. 119 | // Existing MonitorIntervals are removed from the queue when all 120 | // 'useful' intervals' utilities are available. 121 | class PccMonitorIntervalQueue { 122 | public: 123 | explicit PccMonitorIntervalQueue( 124 | PccMonitorIntervalQueueDelegateInterface* delegate); 125 | PccMonitorIntervalQueue(const PccMonitorIntervalQueue&) = delete; 126 | PccMonitorIntervalQueue& operator=(const PccMonitorIntervalQueue&) = delete; 127 | PccMonitorIntervalQueue(PccMonitorIntervalQueue&&) = delete; 128 | PccMonitorIntervalQueue& operator=(PccMonitorIntervalQueue&&) = delete; 129 | ~PccMonitorIntervalQueue() {} 130 | 131 | // Creates a new MonitorInterval and add it to the tail of the 132 | // monitor interval queue, provided the necessary variables 133 | // for MonitorInterval initialization. 134 | void EnqueueNewMonitorInterval(QuicBandwidth sending_rate, 135 | bool is_useful, 136 | float rtt_fluctuation_tolerance_ratio, 137 | QuicTime::Delta rtt); 138 | 139 | // Called when a packet belonging to current monitor interval is sent. 140 | void OnPacketSent(QuicTime sent_time, 141 | QuicPacketNumber packet_number, 142 | QuicByteCount bytes, 143 | QuicTime::Delta sent_interval); 144 | 145 | // Called when packets are acked or considered as lost. 146 | void OnCongestionEvent(const AckedPacketVector& acked_packets, 147 | const LostPacketVector& lost_packets, 148 | QuicTime::Delta avg_rtt, 149 | QuicTime::Delta latest_rtt, 150 | QuicTime::Delta min_rtt, 151 | QuicTime event_time, 152 | QuicTime::Delta ack_interval); 153 | 154 | // Called when RTT inflation ratio is greater than 155 | // max_rtt_fluctuation_tolerance_ratio_in_starting. 156 | void OnRttInflationInStarting(); 157 | 158 | // Returns the fisrt MonitorInterval in the front of the queue. The caller 159 | // needs to make sure the queue is not empty before calling this function. 160 | const MonitorInterval& front() const; 161 | // Returns the most recent MonitorInterval in the tail of the queue. The 162 | // caller needs to make sure the queue is not empty before calling this 163 | // function. 164 | const MonitorInterval& current() const; 165 | // Mark the most recent MonitorInterval as already extended. 166 | void extend_current_interval(); 167 | size_t num_useful_intervals() const { return num_useful_intervals_; } 168 | size_t num_available_intervals() const { return num_available_intervals_; } 169 | bool empty() const; 170 | size_t size() const; 171 | 172 | private: 173 | // Returns true if the utility of |interval| is available, i.e., 174 | // when all the interval's packets are either acked or lost. 175 | bool IsUtilityAvailable(const MonitorInterval& interval) const; 176 | 177 | // Retruns true if |packet_number| belongs to |interval|. 178 | bool IntervalContainsPacket(const MonitorInterval& interval, 179 | QuicPacketNumber packet_number) const; 180 | 181 | // Returns true if the utility of |interval| is invalid, i.e., if it only 182 | // contains a single sent packet. 183 | bool HasInvalidUtility(const MonitorInterval* interval) const; 184 | 185 | std::deque monitor_intervals_; 186 | // Vector of acked packets with pending RTT reliability. 187 | std::vector pending_acked_packets_; 188 | // Latest RTT corresponding to pending acked packets. 189 | QuicTime::Delta pending_rtt_; 190 | // Average RTT corresponding to pending acked packets. 191 | QuicTime::Delta pending_avg_rtt_; 192 | // ACK interval corresponding to pending acked packets. 193 | QuicTime::Delta pending_ack_interval_; 194 | // ACK reception time corresponding to pending acked packets. 195 | QuicTime pending_event_time_; 196 | 197 | bool burst_flag_; 198 | 199 | // EWMA of ratio between two consecutive ACK intervals, i.e., interval between 200 | // reception time of two consecutive ACKs. 201 | float avg_interval_ratio_; 202 | 203 | // Number of useful intervals in the queue. 204 | size_t num_useful_intervals_; 205 | // Number of useful intervals in the queue with available utilities. 206 | size_t num_available_intervals_; 207 | // Delegate interface, not owned. 208 | PccMonitorIntervalQueueDelegateInterface* delegate_; 209 | }; 210 | 211 | // } // namespace quic 212 | 213 | #endif // THIRD_PARTY_PCC_QUIC_PCC_MONITOR_QUEUE_H_ 214 | -------------------------------------------------------------------------------- /src/pcc/pcc_sender.h: -------------------------------------------------------------------------------- 1 | // PCC (Performance Oriented Congestion Control) algorithm 2 | 3 | #ifndef NET_QUIC_CORE_CONGESTION_CONTROL_PCC_SENDER_H_ 4 | #define NET_QUIC_CORE_CONGESTION_CONTROL_PCC_SENDER_H_ 5 | 6 | #include "pcc_monitor_interval_queue.h" 7 | #include "pcc_utility_manager.h" 8 | //#include "third_party/pcc_quic/pcc_monitor_interval_queue.h" 9 | 10 | #include 11 | #include 12 | 13 | //#include "base/macros.h" 14 | //#include "third_party/quic/core/congestion_control/bandwidth_sampler.h" 15 | //#include "third_party/quic/core/congestion_control/send_algorithm_interface.h" 16 | //#include "third_party/quic/core/congestion_control/windowed_filter.h" 17 | //#include "third_party/quic/core/quic_bandwidth.h" 18 | //#include "third_party/quic/core/quic_connection_stats.h" 19 | //#include "third_party/quic/core/quic_time.h" 20 | //#include "third_party/quic/core/quic_types.h" 21 | //#include "third_party/quic/core/quic_unacked_packet_map.h" 22 | 23 | // namespace quic { 24 | 25 | // namespace test { 26 | // class PccSenderPeer; 27 | // } // namespace test 28 | 29 | // class RttStats; 30 | 31 | // UtilityInfo is used to store pairs 32 | struct UtilityInfo { 33 | UtilityInfo(); 34 | UtilityInfo(QuicBandwidth rate, float utility); 35 | ~UtilityInfo() {} 36 | 37 | QuicBandwidth sending_rate; 38 | float utility; 39 | }; 40 | 41 | typedef uint64_t QuicRoundTripCount; 42 | 43 | // PccSender implements the PCC congestion control algorithm. PccSender 44 | // evaluates the benefits of different sending rates by comparing their 45 | // utilities, and adjusts the sending rate towards the direction of 46 | // higher utility. 47 | class PccSender 48 | : // public SendAlgorithmInterface, 49 | public PccMonitorIntervalQueueDelegateInterface { 50 | public: 51 | // Sender's mode during a connection. 52 | enum SenderMode { 53 | // Initial phase of the connection. Sending rate gets doubled as 54 | // long as utility keeps increasing, and the sender enters 55 | // PROBING mode when utility decreases. 56 | STARTING, 57 | // Sender tries different sending rates to decide whether higher 58 | // or lower sending rate has greater utility. Sender enters 59 | // DECISION_MADE mode once a decision is made. 60 | PROBING, 61 | // Sender keeps increasing or decreasing sending rate until 62 | // utility decreases, then sender returns to PROBING mode. 63 | // TODO(tongmeng): a better name? 64 | DECISION_MADE 65 | }; 66 | 67 | // Indicates whether sender should increase or decrease sending rate. 68 | enum RateChangeDirection { INCREASE, DECREASE }; 69 | 70 | // Debug state to be exported for purpose of troubleshoot. 71 | /* 72 | struct DebugState { 73 | explicit DebugState(const PccSender& sender); 74 | DebugState(const DebugState& state) = default; 75 | 76 | SenderMode mode; 77 | QuicBandwidth sending_rate; 78 | QuicTime::Delta latest_rtt; 79 | QuicTime::Delta smoothed_rtt; 80 | QuicTime::Delta rtt_dev; 81 | bool is_useful; 82 | QuicTime first_packet_sent_time; 83 | QuicTime last_packet_sent_time; 84 | QuicPacketNumber first_packet_number; 85 | QuicPacketNumber last_packet_number; 86 | QuicByteCount bytes_sent; 87 | QuicByteCount bytes_acked; 88 | QuicByteCount bytes_lost; 89 | QuicTime::Delta rtt_on_monitor_start; 90 | QuicTime::Delta rtt_on_monitor_end; 91 | float latest_utility; 92 | QuicBandwidth bandwidth; 93 | }; 94 | */ 95 | 96 | PccSender(//const RttStats* rtt_stats, 97 | //const QuicUnackedPacketMap* unacked_packets, 98 | QuicPacketCount initial_congestion_window, 99 | QuicPacketCount max_congestion_window); //, QuicRandom* random); 100 | PccSender(const PccSender&) = delete; 101 | PccSender& operator=(const PccSender&) = delete; 102 | PccSender(PccSender&&) = delete; 103 | PccSender& operator=(PccSender&&) = delete; 104 | ~PccSender() /*override*/ {} 105 | 106 | // Start implementation of SendAlgorithmInterface. 107 | /* 108 | bool InSlowStart() const override; 109 | */ 110 | /* 111 | bool InRecovery() const override; 112 | */ 113 | /* 114 | bool ShouldSendProbingPacket() const override; 115 | */ 116 | 117 | /* 118 | void SetFromConfig(const QuicConfig& config, 119 | Perspective perspective) override {} 120 | */ 121 | 122 | /* 123 | void SetInitialCongestionWindowInPackets(QuicPacketCount packets) override {} 124 | */ 125 | 126 | /* 127 | void AdjustNetworkParameters(QuicBandwidth bandwidth, 128 | QuicTime::Delta rtt) override {} 129 | */ 130 | /* 131 | void SetNumEmulatedConnections(int num_connections) override {} 132 | */ 133 | void OnCongestionEvent(bool rtt_updated, QuicTime::Delta rtt, 134 | QuicByteCount bytes_in_flight, 135 | QuicTime event_time, 136 | const AckedPacketVector& acked_packets, 137 | const LostPacketVector& lost_packets) /*override*/; 138 | void OnPacketSent(QuicTime sent_time, 139 | QuicByteCount bytes_in_flight, 140 | QuicPacketNumber packet_number, 141 | QuicByteCount bytes, 142 | HasRetransmittableData is_retransmittable) /*override*/; 143 | /* 144 | void OnRetransmissionTimeout(bool packets_retransmitted) override {} 145 | */ 146 | /* 147 | void OnConnectionMigration() override {} 148 | */ 149 | bool CanSend(QuicByteCount bytes_in_flight) /*override*/; 150 | QuicBandwidth PacingRate(QuicByteCount bytes_in_flight) const /*override*/; 151 | /* 152 | QuicBandwidth BandwidthEstimate() const override; 153 | */ 154 | QuicByteCount GetCongestionWindow() const /*override*/; 155 | /* 156 | QuicByteCount GetSlowStartThreshold() const override; 157 | */ 158 | /* 159 | CongestionControlType GetCongestionControlType() const override; 160 | */ 161 | /* 162 | QuicString GetDebugState() const override; 163 | */ 164 | /* 165 | void OnApplicationLimited(QuicByteCount bytes_in_flight) override; 166 | */ 167 | // End implementation of SendAlgorithmInterface. 168 | 169 | // Implementation of PccMonitorIntervalQueueDelegate. 170 | // Called when all useful intervals' utilities are available, 171 | // so the sender can make a decision. 172 | void OnUtilityAvailable( 173 | const std::vector& useful_intervals, 174 | QuicTime event_time) override; 175 | 176 | size_t GetNumIntervalGroupsInProbing() const; 177 | 178 | // Set the utility function used by pcc sender. 179 | void SetUtilityTag(std::string utility_tag); 180 | // Set the parameter needed by utility function. 181 | void SetUtilityParameter(void* param); 182 | 183 | // Generate PCC DebugState. 184 | /* 185 | DebugState ExportDebugState() const; 186 | */ 187 | 188 | protected: 189 | void UpdateRtt(QuicTime event_time, QuicTime::Delta rtt); 190 | // friend class test::PccSenderPeer; 191 | /*typedef WindowedFilter, 193 | QuicRoundTripCount, 194 | QuicRoundTripCount> 195 | MaxBandwidthFilter;*/ 196 | 197 | // Returns true if a new monitor interval needs to be created. 198 | bool CreateNewInterval(QuicTime event_time); 199 | // Returns true if next created monitor interval is useful, 200 | // i.e., its utility will be used when a decision can be made. 201 | bool CreateUsefulInterval() const; 202 | // Returns the sending rate for non-useful monitor interval. 203 | virtual QuicBandwidth GetSendingRateForNonUsefulInterval() const; 204 | // Maybe set sending_rate_ for next created monitor interval. 205 | void MaybeSetSendingRate(); 206 | // Returns the max RTT fluctuation tolerance according to sender mode. 207 | float GetMaxRttFluctuationTolerance() const; 208 | 209 | // Set sending rate to central probing rate for the coming round of PROBING. 210 | void RestoreCentralSendingRate(); 211 | // Returns true if the sender can enter DECISION_MADE from PROBING mode. 212 | virtual bool CanMakeDecision(const std::vector& utility_info) const; 213 | // Set the sending rate to the central rate used in PROBING mode. 214 | void EnterProbing(); 215 | // Set the sending rate when entering DECISION_MADE from PROBING mode. 216 | void EnterDecisionMade(); 217 | 218 | // Returns true if the RTT inflation is larger than the tolerance. 219 | bool CheckForRttInflation(); 220 | 221 | // Update the bandwidth sampler when OnCongestionEvent is called. 222 | /* 223 | void UpdateBandwidthSampler(QuicTime event_time, 224 | const AckedPacketVector& acked_packets, 225 | const LostPacketVector& lost_packets); 226 | */ 227 | 228 | // Current mode of PccSender. 229 | SenderMode mode_; 230 | // Sending rate for the next monitor intervals. 231 | QuicBandwidth sending_rate_; 232 | // Initialized to be false, and set to true after receiving the first ACK. 233 | bool has_seen_valid_rtt_; 234 | // Most recent utility used when making the last rate change decision. 235 | float latest_utility_; 236 | 237 | QuicTime conn_start_time_; 238 | 239 | // Duration of the current monitor interval. 240 | QuicTime::Delta monitor_duration_; 241 | // Current direction of rate changes. 242 | RateChangeDirection direction_; 243 | // Number of rounds sender remains in current mode. 244 | size_t rounds_; 245 | // Queue of monitor intervals with pending utilities. 246 | PccMonitorIntervalQueue interval_queue_; 247 | 248 | // Smoothed RTT before consecutive inflated RTTs happen. 249 | QuicTime::Delta rtt_on_inflation_start_; 250 | 251 | // Maximum congestion window in bytes, used to cap sending rate. 252 | QuicByteCount max_cwnd_bytes_; 253 | 254 | QuicTime::Delta rtt_deviation_; 255 | QuicTime::Delta min_rtt_deviation_; 256 | QuicTime::Delta latest_rtt_; 257 | QuicTime::Delta min_rtt_; 258 | QuicTime::Delta avg_rtt_; 259 | // const QuicUnackedPacketMap* unacked_packets_; 260 | // QuicRandom* random_; 261 | 262 | // Bandwidth sample provides the bandwidth measurement that is used when 263 | // exiting STARTING phase upon early termination. 264 | // BandwidthSampler sampler_; 265 | // Filter that tracks maximum bandwidth over multiple recent round trips. 266 | // MaxBandwidthFilter max_bandwidth_; 267 | // Packet number for the most recently sent packet. 268 | // QuicPacketNumber last_sent_packet_; 269 | // Largest packet number that is sent in current round trips. 270 | // QuicPacketNumber current_round_trip_end_; 271 | // Number of round trips since connection start. 272 | // QuicRoundTripCount round_trip_count_; 273 | // Latched value of FLAGS_exit_starting_based_on_sampled_bandwidth. 274 | const bool exit_starting_based_on_sampled_bandwidth_; 275 | 276 | // Time when the most recent packet is sent. 277 | QuicTime latest_sent_timestamp_; 278 | // Time when the most recent ACK is received. 279 | QuicTime latest_ack_timestamp_; 280 | 281 | // Utility manager is responsible for utility calculation. 282 | PccUtilityManager utility_manager_; 283 | }; 284 | 285 | // Overload operator for purpose of PCC DebugState printing 286 | /* 287 | QUIC_EXPORT_PRIVATE std::ostream& operator<<( 288 | std::ostream& os, 289 | const PccSender::DebugState& state); 290 | */ 291 | 292 | // } // namespace quic 293 | 294 | #endif 295 | -------------------------------------------------------------------------------- /src/pcc/pcc_utility_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef THIRD_PARTY_PCC_QUIC_PCC_UTILITY_MANAGER_H_ 2 | #define THIRD_PARTY_PCC_QUIC_PCC_UTILITY_MANAGER_H_ 3 | 4 | #include "pcc_monitor_interval_queue.h" 5 | 6 | #include 7 | 8 | //#include "third_party/pcc_quic/pcc_monitor_interval_queue.h" 9 | 10 | // #define PER_MI_DEBUG_ 11 | 12 | // namespace quic { 13 | 14 | // IntervalStats stores the performance metrics for a monitor interval, which 15 | // is used for utility calculation. 16 | struct IntervalStats { 17 | IntervalStats() : min_rtt(-1), max_rtt(-1) {} 18 | ~IntervalStats() {} 19 | 20 | float interval_duration; 21 | float rtt_ratio; 22 | int64_t marked_lost_bytes; 23 | float loss_rate; 24 | float actual_sending_rate_mbps; 25 | float ack_rate_mbps; 26 | 27 | float avg_rtt; 28 | float rtt_dev; 29 | float min_rtt; 30 | float max_rtt; 31 | float approx_rtt_gradient; 32 | 33 | float rtt_gradient; 34 | float rtt_gradient_cut; 35 | float rtt_gradient_error; 36 | 37 | float trending_gradient; 38 | float trending_gradient_cut; 39 | float trending_gradient_error; 40 | 41 | float trending_deviation; 42 | }; 43 | 44 | class PccUtilityManager { 45 | public: 46 | PccUtilityManager(); 47 | 48 | // Utility calculation interface for all pcc senders. 49 | float CalculateUtility(const MonitorInterval* interval, 50 | QuicTime::Delta event_time); 51 | 52 | // Get the utility function used by pcc sender. 53 | const std::string GetUtilityTag() const; 54 | // Get the effective utility tag. 55 | const std::string GetEffectiveUtilityTag() const; 56 | // Set the utility function used by pcc sender. 57 | void SetUtilityTag(std::string utility_tag); 58 | // Set the effective utility tag. 59 | void SetEffectiveUtilityTag(std::string utility_tag); 60 | // Set the parameter needed by utility function. 61 | void SetUtilityParameter(void* param); 62 | // Get the specified utility parameter. 63 | void* GetUtilityParameter(int parameter_index) const; 64 | 65 | private: 66 | // Prepare performance metrics for utility calculation. 67 | void PrepareStatistics(const MonitorInterval* interval); 68 | void PreProcessing(const MonitorInterval* interval); 69 | void ComputeSimpleMetrics(const MonitorInterval* interval); 70 | void ComputeApproxRttGradient(const MonitorInterval* interval); 71 | void ComputeRttGradient(const MonitorInterval* interval); 72 | void ComputeRttGradientError(const MonitorInterval*); 73 | void ComputeRttDeviation(const MonitorInterval* interval); 74 | 75 | void ProcessRttTrend(const MonitorInterval* interval); 76 | void ComputeTrendingGradient(); 77 | void ComputeTrendingGradientError(); 78 | void ComputeTrendingDeviation(); 79 | 80 | void DetermineToleranceGeneral(); 81 | void DetermineToleranceInflation(); 82 | void DetermineToleranceDeviation(); 83 | 84 | // Calculates utility for |interval|. 85 | float CalculateUtilityAllegro(const MonitorInterval* interval); 86 | float CalculateUtilityVivace(const MonitorInterval* interval); 87 | float CalculateUtilityHybridAllegro(const MonitorInterval* interval, 88 | float bound); 89 | float CalculateUtilityProportional(const MonitorInterval* interval, 90 | float latency_coefficient, 91 | float loss_coefficient); 92 | float CalculateUtilityScavenger(const MonitorInterval* interval, 93 | float rtt_variance_coefficient); 94 | float CalculateUtilityHybridVivace(const MonitorInterval* interval, 95 | float bound); 96 | float CalculateUtilityHybridVivace2(const MonitorInterval* interval, 97 | float bound); 98 | float CalculateUtilityRateLimiter(const MonitorInterval* interval, 99 | float rate_limiter_parameter); 100 | float CalculateUtilityLedbat(const MonitorInterval* interval, 101 | float target_delay); 102 | float CalculateUtilityHybrid(const MonitorInterval* interval, 103 | float rate_bound); 104 | float CalculateUtilityTEST(const MonitorInterval* interval, 105 | float latency_coefficient, 106 | float loss_coefficient); 107 | 108 | // Calculates perfect utility with respect to a specifc sending rate, i.e., 109 | // assuming no packet loss and no RTT changes. 110 | float CalculatePerfectUtilityAllegro(float sending_rate_mbps); 111 | float CalculatePerfectUtilityVivace(float sending_rate_mbps); 112 | 113 | // String tag that represents the utility function. 114 | std::string utility_tag_; 115 | // May be different from actual utility tag when using Hybrid utility. 116 | std::string effective_utility_tag_; 117 | // Parameters needed by some utility functions, e.g., sending rate bound used 118 | // in hybrid utility functions. 119 | std::vector utility_parameters_; 120 | 121 | // Performance metrics for latest monitor interval. 122 | IntervalStats interval_stats_; 123 | 124 | size_t lost_bytes_tolerance_quota_; 125 | 126 | float avg_mi_rtt_dev_; 127 | float dev_mi_rtt_dev_; 128 | float min_rtt_; 129 | 130 | std::deque mi_avg_rtt_history_; 131 | float avg_trending_gradient_; 132 | float min_trending_gradient_; 133 | float dev_trending_gradient_; 134 | float last_trending_gradient_; 135 | 136 | std::deque mi_rtt_dev_history_; 137 | float avg_trending_dev_; 138 | float min_trending_dev_; 139 | float dev_trending_dev_; 140 | float last_trending_dev_; 141 | 142 | float ratio_inflated_mi_; 143 | float ratio_fluctuated_mi_; 144 | 145 | bool is_rtt_inflation_tolerable_; 146 | bool is_rtt_dev_tolerable_; 147 | }; 148 | 149 | // } // namespace quic 150 | 151 | #endif 152 | -------------------------------------------------------------------------------- /src/pcc/pcc_vivace_sender.h: -------------------------------------------------------------------------------- 1 | #ifndef PCC_VIVACE_SENDER_H_ 2 | #define PCC_VIVACE_SENDER_H_ 3 | 4 | #include "pcc_sender.h" 5 | 6 | class PccVivaceSender : public PccSender { 7 | public: 8 | PccVivaceSender(//const RttStats* rtt_stats, 9 | //const QuicUnackedPacketMap* unacked_packets, 10 | QuicPacketCount initial_congestion_window, 11 | QuicPacketCount max_congestion_window); //, QuicRandom* random); 12 | PccVivaceSender(const PccVivaceSender&) = delete; 13 | PccVivaceSender& operator=(const PccVivaceSender&) = delete; 14 | PccVivaceSender(PccVivaceSender&&) = delete; 15 | PccVivaceSender& operator=(PccVivaceSender&&) = delete; 16 | ~PccVivaceSender() /*override*/ {} 17 | 18 | QuicBandwidth GetSendingRateForNonUsefulInterval() const override; 19 | 20 | void OnUtilityAvailable( 21 | const std::vector& useful_intervals, 22 | QuicTime event_time) override; 23 | 24 | private: 25 | bool CanMakeDecision( 26 | const std::vector& utility_info) const override; 27 | // Determine rate change direction in PROBING mode based on the utilities of 28 | // a majority of interval groups. 29 | void SetRateChangeDirection(const std::vector& utility_info); 30 | 31 | void EnterProbing(const std::vector& utility_info); 32 | void EnterDecisionMade(const std::vector& utility_info); 33 | QuicBandwidth ComputeRateChange(const std::vector& utility_info); 34 | 35 | // Most recent utility info used when making the last rate change decision. 36 | UtilityInfo latest_utility_info_; 37 | 38 | // Number of incremental rate change step size allowed on basis of initial 39 | // maximum rate change step size. 40 | size_t incremental_rate_change_step_allowance_; 41 | }; 42 | 43 | // } // namespace quic 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/pcc/quic_types/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois, 2 | Google Inc. 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 6 | met: 7 | 8 | * Redistributions of source code must retain the above 9 | copyright notice, this list of conditions and the 10 | following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the 13 | above copyright notice, this list of conditions 14 | and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | * Neither the name of the University of Illinois 18 | nor the names of its contributors may be used to 19 | endorse or promote products derived from this 20 | software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 23 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 24 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 26 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 27 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 28 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 29 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 30 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 31 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /src/pcc/quic_types/Readme.md: -------------------------------------------------------------------------------- 1 | This folder contains the definition of classes necessary to support QUIC-based 2 | PCC implementation. 3 | -------------------------------------------------------------------------------- /src/pcc/quic_types/quic_bandwidth.h: -------------------------------------------------------------------------------- 1 | #ifndef QUIC_BANDWIDTH_ 2 | #define QUIC_BANDWIDTH_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "quic_constants.h" 10 | #include "quic_time.h" 11 | #include "quic_types.h" 12 | 13 | class QuicBandwidth { 14 | public: 15 | static constexpr QuicBandwidth Zero() { return QuicBandwidth(0); } 16 | static constexpr QuicBandwidth Infinite() { 17 | return QuicBandwidth(std::numeric_limits::max()); 18 | } 19 | 20 | static constexpr QuicBandwidth FromBitsPerSecond(int64_t bits_per_second) { 21 | return QuicBandwidth(bits_per_second); 22 | } 23 | 24 | static constexpr QuicBandwidth FromKBitsPerSecond(int64_t k_bits_per_second) { 25 | return QuicBandwidth(k_bits_per_second * 1000); 26 | } 27 | 28 | static constexpr QuicBandwidth FromBytesPerSecond(int64_t bytes_per_second) { 29 | return QuicBandwidth(bytes_per_second * 8); 30 | } 31 | 32 | static constexpr QuicBandwidth FromKBytesPerSecond( 33 | int64_t k_bytes_per_second) { 34 | return QuicBandwidth(k_bytes_per_second * 8000); 35 | } 36 | 37 | static inline QuicBandwidth FromBytesAndTimeDelta(QuicByteCount bytes, 38 | QuicTime::Delta delta) { 39 | return QuicBandwidth((bytes * kNumMicrosPerSecond) / 40 | delta.ToMicroseconds() * 8); 41 | } 42 | 43 | inline int64_t ToBitsPerSecond() const { return bits_per_second_; } 44 | 45 | inline int64_t ToKBitsPerSecond() const { return bits_per_second_ / 1000; } 46 | 47 | inline int64_t ToBytesPerSecond() const { return bits_per_second_ / 8; } 48 | 49 | inline int64_t ToKBytesPerSecond() const { return bits_per_second_ / 8000; } 50 | 51 | inline QuicByteCount ToBytesPerPeriod(QuicTime::Delta time_period) const { 52 | return ToBytesPerSecond() * time_period.ToMicroseconds() / 53 | kNumMicrosPerSecond; 54 | } 55 | 56 | inline int64_t ToKBytesPerPeriod(QuicTime::Delta time_period) const { 57 | return ToKBytesPerSecond() * time_period.ToMicroseconds() / 58 | kNumMicrosPerSecond; 59 | } 60 | 61 | inline bool IsZero() const { return bits_per_second_ == 0; } 62 | 63 | inline QuicTime::Delta TransferTime(QuicByteCount bytes) const { 64 | if (bits_per_second_ == 0) { 65 | return QuicTime::Delta::Zero(); 66 | } 67 | return QuicTime::Delta::FromMicroseconds(bytes * 8 * kNumMicrosPerSecond / 68 | bits_per_second_); 69 | } 70 | 71 | private: 72 | explicit constexpr QuicBandwidth(int64_t bits_per_second) 73 | : bits_per_second_(bits_per_second >= 0 ? bits_per_second : 0) {} 74 | 75 | int64_t bits_per_second_; 76 | 77 | friend QuicBandwidth operator+(QuicBandwidth lhs, QuicBandwidth rhs); 78 | friend QuicBandwidth operator-(QuicBandwidth lhs, QuicBandwidth rhs); 79 | friend QuicBandwidth operator*(QuicBandwidth lhs, float factor); 80 | }; 81 | 82 | // Non-member relational operators for QuicBandwidth. 83 | inline bool operator==(QuicBandwidth lhs, QuicBandwidth rhs) { 84 | return lhs.ToBitsPerSecond() == rhs.ToBitsPerSecond(); 85 | } 86 | inline bool operator!=(QuicBandwidth lhs, QuicBandwidth rhs) { 87 | return !(lhs == rhs); 88 | } 89 | inline bool operator<(QuicBandwidth lhs, QuicBandwidth rhs) { 90 | return lhs.ToBitsPerSecond() < rhs.ToBitsPerSecond(); 91 | } 92 | inline bool operator>(QuicBandwidth lhs, QuicBandwidth rhs) { 93 | return rhs < lhs; 94 | } 95 | inline bool operator<=(QuicBandwidth lhs, QuicBandwidth rhs) { 96 | return !(rhs < lhs); 97 | } 98 | inline bool operator>=(QuicBandwidth lhs, QuicBandwidth rhs) { 99 | return !(lhs < rhs); 100 | } 101 | 102 | // Non-member arithmetic operators for QuicBandwidth. 103 | inline QuicBandwidth operator+(QuicBandwidth lhs, QuicBandwidth rhs) { 104 | return QuicBandwidth(lhs.bits_per_second_ + rhs.bits_per_second_); 105 | } 106 | inline QuicBandwidth operator-(QuicBandwidth lhs, QuicBandwidth rhs) { 107 | return QuicBandwidth(lhs.bits_per_second_ - rhs.bits_per_second_); 108 | } 109 | inline QuicBandwidth operator*(QuicBandwidth lhs, float rhs) { 110 | return QuicBandwidth( 111 | static_cast(std::llround(lhs.bits_per_second_ * rhs))); 112 | } 113 | inline QuicBandwidth operator*(float lhs, QuicBandwidth rhs) { 114 | return rhs * lhs; 115 | } 116 | inline QuicByteCount operator*(QuicBandwidth lhs, QuicTime::Delta rhs) { 117 | return lhs.ToBytesPerPeriod(rhs); 118 | } 119 | inline QuicByteCount operator*(QuicTime::Delta lhs, QuicBandwidth rhs) { 120 | return rhs * lhs; 121 | } 122 | 123 | #endif 124 | -------------------------------------------------------------------------------- /src/pcc/quic_types/quic_constants.h: -------------------------------------------------------------------------------- 1 | #ifndef QUIC_CONSTANTS_ 2 | #define QUIC_CONSTANTS_ 3 | 4 | #include 5 | 6 | const uint64_t kNumMicrosPerSecond = 1000 * 1000; 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/pcc/quic_types/quic_time.h: -------------------------------------------------------------------------------- 1 | #ifndef QUIC_TIME_ 2 | #define QUIC_TIME_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class QuicTime { 10 | public: 11 | class Delta { 12 | public: 13 | explicit inline Delta(int64_t time_offset) : time_offset_(time_offset) {} 14 | 15 | static inline Delta Zero() { return Delta(0); } 16 | static inline Delta Infinite() {return Delta(kQuicInfiniteTimeUs);} 17 | 18 | static inline Delta FromSeconds(int64_t secs) { 19 | return Delta(secs * 1000 * 1000); 20 | } 21 | static inline Delta FromMilliseconds(int64_t ms) {return Delta(ms * 1000);} 22 | static inline Delta FromMicroseconds(int64_t us) {return Delta(us);} 23 | 24 | inline int64_t ToSeconds() const { return time_offset_ / 1000 / 1000; } 25 | inline int64_t ToMilliseconds() const { return time_offset_ / 1000; } 26 | inline int64_t ToMicroseconds() const { return time_offset_; } 27 | 28 | inline bool IsZero() const { return time_offset_ == 0; } 29 | inline bool IsInfinite() const {return time_offset_ == kQuicInfiniteTimeUs;} 30 | 31 | private: 32 | friend inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs); 33 | friend inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs); 34 | friend inline QuicTime::Delta operator<<(QuicTime::Delta lhs, size_t rhs); 35 | friend inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs); 36 | 37 | friend inline QuicTime::Delta operator+(QuicTime::Delta lhs, 38 | QuicTime::Delta rhs); 39 | friend inline QuicTime::Delta operator-(QuicTime::Delta lhs, 40 | QuicTime::Delta rhs); 41 | friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs); 42 | friend inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs); 43 | 44 | friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs); 45 | friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs); 46 | friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs); 47 | 48 | static const int64_t kQuicInfiniteTimeUs = 49 | std::numeric_limits::max(); 50 | 51 | int64_t time_offset_; 52 | friend class QuicTime; 53 | }; 54 | 55 | static inline QuicTime Zero() { return QuicTime(0); } 56 | static inline QuicTime Infinite() { 57 | return QuicTime(Delta::kQuicInfiniteTimeUs); 58 | } 59 | 60 | inline bool IsInitialized() const { return 0 != time_; } 61 | 62 | private: 63 | friend inline bool operator==(QuicTime lhs, QuicTime rhs); 64 | friend inline bool operator<(QuicTime lhs, QuicTime rhs); 65 | friend inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs); 66 | friend inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs); 67 | friend inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs); 68 | 69 | explicit inline QuicTime(int64_t time) : time_(time) {} 70 | 71 | int64_t time_; 72 | }; 73 | 74 | // Non-member relational operators for QuicTime::Delta. 75 | inline bool operator==(QuicTime::Delta lhs, QuicTime::Delta rhs) { 76 | return lhs.time_offset_ == rhs.time_offset_; 77 | } 78 | inline bool operator!=(QuicTime::Delta lhs, QuicTime::Delta rhs) { 79 | return !(lhs == rhs); 80 | } 81 | inline bool operator<(QuicTime::Delta lhs, QuicTime::Delta rhs) { 82 | return lhs.time_offset_ < rhs.time_offset_; 83 | } 84 | inline bool operator>(QuicTime::Delta lhs, QuicTime::Delta rhs) { 85 | return rhs < lhs; 86 | } 87 | inline bool operator<=(QuicTime::Delta lhs, QuicTime::Delta rhs) { 88 | return !(rhs < lhs); 89 | } 90 | inline bool operator>=(QuicTime::Delta lhs, QuicTime::Delta rhs) { 91 | return !(lhs < rhs); 92 | } 93 | inline QuicTime::Delta operator>>(QuicTime::Delta lhs, size_t rhs) { 94 | return QuicTime::Delta(lhs.time_offset_ >> rhs); 95 | } 96 | 97 | // Non-member relational operators for QuicTime. 98 | inline bool operator==(QuicTime lhs, QuicTime rhs) { 99 | return lhs.time_ == rhs.time_; 100 | } 101 | inline bool operator!=(QuicTime lhs, QuicTime rhs) { 102 | return !(lhs == rhs); 103 | } 104 | inline bool operator<(QuicTime lhs, QuicTime rhs) { 105 | return lhs.time_ < rhs.time_; 106 | } 107 | inline bool operator>(QuicTime lhs, QuicTime rhs) { 108 | return rhs < lhs; 109 | } 110 | inline bool operator<=(QuicTime lhs, QuicTime rhs) { 111 | return !(rhs < lhs); 112 | } 113 | inline bool operator>=(QuicTime lhs, QuicTime rhs) { 114 | return !(lhs < rhs); 115 | } 116 | 117 | // Non-member arithmetic operators for QuicTime::Delta. 118 | inline QuicTime::Delta operator+(QuicTime::Delta lhs, QuicTime::Delta rhs) { 119 | return QuicTime::Delta(lhs.time_offset_ + rhs.time_offset_); 120 | } 121 | inline QuicTime::Delta operator-(QuicTime::Delta lhs, QuicTime::Delta rhs) { 122 | return QuicTime::Delta(lhs.time_offset_ - rhs.time_offset_); 123 | } 124 | inline QuicTime::Delta operator*(QuicTime::Delta lhs, int rhs) { 125 | return QuicTime::Delta(lhs.time_offset_ * rhs); 126 | } 127 | inline QuicTime::Delta operator*(QuicTime::Delta lhs, double rhs) { 128 | return QuicTime::Delta( 129 | static_cast(std::llround(lhs.time_offset_ * rhs))); 130 | } 131 | inline QuicTime::Delta operator*(int lhs, QuicTime::Delta rhs) { 132 | return rhs * lhs; 133 | } 134 | inline QuicTime::Delta operator*(double lhs, QuicTime::Delta rhs) { 135 | return rhs * lhs; 136 | } 137 | 138 | // Non-member arithmetic operators for QuicTime and QuicTime::Delta. 139 | inline QuicTime operator+(QuicTime lhs, QuicTime::Delta rhs) { 140 | return QuicTime(lhs.time_ + rhs.time_offset_); 141 | } 142 | inline QuicTime operator-(QuicTime lhs, QuicTime::Delta rhs) { 143 | return QuicTime(lhs.time_ - rhs.time_offset_); 144 | } 145 | inline QuicTime::Delta operator-(QuicTime lhs, QuicTime rhs) { 146 | return QuicTime::Delta(lhs.time_ - rhs.time_); 147 | } 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /src/pcc/quic_types/quic_types.h: -------------------------------------------------------------------------------- 1 | #ifndef QUIC_TYPES_ 2 | #define QUIC_TYPES_ 3 | 4 | #include "quic_time.h" 5 | 6 | #include 7 | #include 8 | 9 | typedef bool HasRetransmittableData; 10 | static bool HAS_RETRANSMITTABLE_DATA = true; 11 | 12 | typedef uint64_t QuicByteCount; 13 | typedef uint64_t QuicPacketCount; 14 | typedef uint64_t QuicPacketLength; 15 | typedef uint64_t QuicPacketNumber; 16 | 17 | struct AckedPacket { 18 | AckedPacket(QuicPacketNumber packet_number, 19 | QuicPacketLength bytes_acked, 20 | QuicTime receive_timestamp) 21 | : packet_number(packet_number), 22 | bytes_acked(bytes_acked), 23 | receive_timestamp(receive_timestamp) {} 24 | 25 | QuicPacketNumber packet_number; 26 | QuicPacketLength bytes_acked; 27 | QuicTime receive_timestamp; 28 | }; 29 | 30 | struct LostPacket { 31 | LostPacket(QuicPacketNumber packet_number, QuicPacketLength bytes_lost) 32 | : packet_number(packet_number), bytes_lost(bytes_lost) {} 33 | 34 | QuicPacketNumber packet_number; 35 | QuicPacketLength bytes_lost; 36 | }; 37 | 38 | typedef std::vector AckedPacketVector; 39 | typedef std::vector LostPacketVector; 40 | 41 | #endif 42 | --------------------------------------------------------------------------------