update libutp, fixing #4915

This commit is contained in:
Mitchell Livingston 2012-05-27 15:27:59 +00:00
parent 8ba32b11c0
commit ca7654d8cd
8 changed files with 3510 additions and 3488 deletions

View File

@ -1,11 +1,11 @@
#if !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_)
#define AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// I don't have anything to put here, but some projects use precompiled headers,
// so I include StdAfx.h anyway, so they don't have to edit the files to compile normally.
#endif // !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_)
#if !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_)
#define AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// I don't have anything to put here, but some projects use precompiled headers,
// so I include StdAfx.h anyway, so they don't have to edit the files to compile normally.
#endif // !defined(AFX_STDAFX_H__C1470942_E9DA_4913_BEF1_9BA7584E595B__INCLUDED_)

View File

@ -1,172 +1,180 @@
#ifndef __TEMPLATES_H__
#define __TEMPLATES_H__
#include "utypes.h"
#include <assert.h>
#if defined(POSIX)
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
doesn't seem to support __attribute__((always_inline)) in -O0 build
(strangely, it works in -Os build) */
#ifndef FORCEINLINE
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
// since Microsoft uses __forceinline to also mean inline,
// and this code is following a Microsoft compatibility model.
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
// as evidenced by multiply-defined symbols found at link time.
#define FORCEINLINE inline __attribute__((always_inline))
#endif
#endif
#ifdef __GNUC__
// Used for gcc tool chains accepting but not supporting pragma pack
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
#define PACKED_ATTRIBUTE __attribute__((__packed__))
#else
#define PACKED_ATTRIBUTE
#endif
// Utility templates
#undef min
#undef max
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
template <typename T> static inline T clamp(T v, T mi, T ma)
{
if (v > ma) v = ma;
if (v < mi) v = mi;
return v;
}
#pragma pack(push,1)
namespace aux
{
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
}
template <class T>
struct PACKED_ATTRIBUTE big_endian
{
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
operator T() const { return aux::network_to_host(m_integer); }
private:
T m_integer;
};
typedef big_endian<int32> int32_big;
typedef big_endian<uint32> uint32_big;
typedef big_endian<uint16> uint16_big;
#pragma pack(pop)
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
typedef int SortCompareProc(const void *, const void *);
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
// WARNING: The template parameter MUST be a POD type!
template <typename T, size_t minsize = 16> class Array {
protected:
T *mem;
size_t alloc,count;
public:
Array(size_t init) { Init(init); }
Array() { Init(); }
~Array() { Free(); }
void inline Init() { mem = NULL; alloc = count = 0; }
void inline Init(size_t init) { Init(); if (init) Resize(init); }
size_t inline GetCount() const { return count; }
size_t inline GetAlloc() const { return alloc; }
void inline SetCount(size_t c) { count = c; }
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
void inline Resize(size_t a) {
if (a == 0) { free(mem); Init(); }
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
}
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
inline size_t Append(const T &t) {
if (count >= alloc) Grow();
size_t r=count++;
mem[r] = t;
return r;
}
T inline &Append() {
if (count >= alloc) Grow();
return mem[count++];
}
void inline Compact() {
Resize(count);
}
void inline Free() {
free(mem);
Init();
}
void inline Clear() {
count = 0;
}
bool inline MoveUpLast(size_t index) {
assert(index < count);
size_t c = --count;
if (index != c) {
mem[index] = mem[c];
return true;
}
return false;
}
bool inline MoveUpLastExist(const T &v) {
return MoveUpLast(LookupElementExist(v));
}
size_t inline LookupElement(const T &v) const {
for(size_t i = 0; i != count; i++)
if (mem[i] == v)
return i;
return (size_t) -1;
}
bool inline HasElement(const T &v) const {
return LookupElement(v) != -1;
}
typedef int SortCompareProc(const T *a, const T *b);
void Sort(SortCompareProc* proc, size_t start, size_t end) {
QuickSortT(&mem[start], end - start, proc);
}
void Sort(SortCompareProc* proc, size_t start) {
Sort(proc, start, count);
}
void Sort(SortCompareProc* proc) {
Sort(proc, 0, count);
}
};
#endif //__TEMPLATES_H__
#ifndef __TEMPLATES_H__
#define __TEMPLATES_H__
#include "utypes.h"
#include <assert.h>
#if defined(POSIX)
/* Allow over-writing FORCEINLINE from makefile because gcc 3.4.4 for buffalo
doesn't seem to support __attribute__((always_inline)) in -O0 build
(strangely, it works in -Os build) */
#ifndef FORCEINLINE
// The always_inline attribute asks gcc to inline the function even if no optimization is being requested.
// This macro should be used exclusive-or with the inline directive (use one or the other but not both)
// since Microsoft uses __forceinline to also mean inline,
// and this code is following a Microsoft compatibility model.
// Just setting the attribute without also specifying the inline directive apparently won't inline the function,
// as evidenced by multiply-defined symbols found at link time.
#define FORCEINLINE inline __attribute__((always_inline))
#endif
#endif
#ifdef __GNUC__
// Used for gcc tool chains accepting but not supporting pragma pack
// See http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html
#define PACKED_ATTRIBUTE __attribute__((__packed__))
#else
#define PACKED_ATTRIBUTE
#endif
// Utility templates
#undef min
#undef max
template <typename T> static inline T min(T a, T b) { if (a < b) return a; return b; }
template <typename T> static inline T max(T a, T b) { if (a > b) return a; return b; }
template <typename T> static inline T min(T a, T b, T c) { return min(min(a,b),c); }
template <typename T> static inline T max(T a, T b, T c) { return max(max(a,b),c); }
template <typename T> static inline T clamp(T v, T mi, T ma)
{
if (v > ma) v = ma;
if (v < mi) v = mi;
return v;
}
#if (defined(__SVR4) && defined(__sun))
#pragma pack(1)
#else
#pragma pack(push,1)
#endif
namespace aux
{
FORCEINLINE uint16 host_to_network(uint16 i) { return htons(i); }
FORCEINLINE uint32 host_to_network(uint32 i) { return htonl(i); }
FORCEINLINE int32 host_to_network(int32 i) { return htonl(i); }
FORCEINLINE uint16 network_to_host(uint16 i) { return ntohs(i); }
FORCEINLINE uint32 network_to_host(uint32 i) { return ntohl(i); }
FORCEINLINE int32 network_to_host(int32 i) { return ntohl(i); }
}
template <class T>
struct PACKED_ATTRIBUTE big_endian
{
T operator=(T i) { m_integer = aux::host_to_network(i); return i; }
operator T() const { return aux::network_to_host(m_integer); }
private:
T m_integer;
};
typedef big_endian<int32> int32_big;
typedef big_endian<uint32> uint32_big;
typedef big_endian<uint16> uint16_big;
#if (defined(__SVR4) && defined(__sun))
#pragma pack(0)
#else
#pragma pack(pop)
#endif
template<typename T> static inline void zeromem(T *a, size_t count = 1) { memset(a, 0, count * sizeof(T)); }
typedef int SortCompareProc(const void *, const void *);
template<typename T> static FORCEINLINE void QuickSortT(T *base, size_t num, int (*comp)(const T *, const T *)) { qsort(base, num, sizeof(T), (SortCompareProc*)comp); }
// WARNING: The template parameter MUST be a POD type!
template <typename T, size_t minsize = 16> class Array {
protected:
T *mem;
size_t alloc,count;
public:
Array(size_t init) { Init(init); }
Array() { Init(); }
~Array() { Free(); }
void inline Init() { mem = NULL; alloc = count = 0; }
void inline Init(size_t init) { Init(); if (init) Resize(init); }
size_t inline GetCount() const { return count; }
size_t inline GetAlloc() const { return alloc; }
void inline SetCount(size_t c) { count = c; }
inline T& operator[](size_t offset) { assert(offset ==0 || offset<alloc); return mem[offset]; }
inline const T& operator[](size_t offset) const { assert(offset ==0 || offset<alloc); return mem[offset]; }
void inline Resize(size_t a) {
if (a == 0) { free(mem); Init(); }
else { mem = (T*)realloc(mem, (alloc=a) * sizeof(T)); }
}
void Grow() { Resize(::max<size_t>(minsize, alloc * 2)); }
inline size_t Append(const T &t) {
if (count >= alloc) Grow();
size_t r=count++;
mem[r] = t;
return r;
}
T inline &Append() {
if (count >= alloc) Grow();
return mem[count++];
}
void inline Compact() {
Resize(count);
}
void inline Free() {
free(mem);
Init();
}
void inline Clear() {
count = 0;
}
bool inline MoveUpLast(size_t index) {
assert(index < count);
size_t c = --count;
if (index != c) {
mem[index] = mem[c];
return true;
}
return false;
}
bool inline MoveUpLastExist(const T &v) {
return MoveUpLast(LookupElementExist(v));
}
size_t inline LookupElement(const T &v) const {
for(size_t i = 0; i != count; i++)
if (mem[i] == v)
return i;
return (size_t) -1;
}
bool inline HasElement(const T &v) const {
return LookupElement(v) != -1;
}
typedef int SortCompareProc(const T *a, const T *b);
void Sort(SortCompareProc* proc, size_t start, size_t end) {
QuickSortT(&mem[start], end - start, proc);
}
void Sort(SortCompareProc* proc, size_t start) {
Sort(proc, start, count);
}
void Sort(SortCompareProc* proc) {
Sort(proc, 0, count);
}
};
#endif //__TEMPLATES_H__

File diff suppressed because it is too large Load Diff

View File

@ -1,163 +1,165 @@
#ifndef __UTP_H__
#define __UTP_H__
#include "utypes.h"
#ifdef WIN32
#define _CRT_SECURE_NO_DEPRECATE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct UTPSocket;
// Used to set sockopt on a uTP socket to set the version of uTP
// to use for outgoing connections. This can only be called before
// the uTP socket is connected
#define SO_UTPVERSION 99
enum {
// socket has reveived syn-ack (notification only for outgoing connection completion)
// this implies writability
UTP_STATE_CONNECT = 1,
// socket is able to send more data
UTP_STATE_WRITABLE = 2,
// connection closed
UTP_STATE_EOF = 3,
// socket is being destroyed, meaning all data has been sent if possible.
// it is not valid to refer to the socket after this state change occurs
UTP_STATE_DESTROYING = 4,
};
// Callbacks called by a uTP socket (register with UTP_SetCallbacks)
// The uTP socket layer calls this when bytes have been received from the network.
typedef void UTPOnReadProc(void *userdata, const byte *bytes, size_t count);
// The uTP socket layer calls this to fill the outgoing buffer with bytes.
// The uTP layer takes responsibility that those bytes will be delivered.
typedef void UTPOnWriteProc(void *userdata, byte *bytes, size_t count);
// The uTP socket layer calls this to retrieve number of bytes currently in read buffer
typedef size_t UTPGetRBSize(void *userdata);
// The uTP socket layer calls this whenever the socket becomes writable.
typedef void UTPOnStateChangeProc(void *userdata, int state);
// The uTP socket layer calls this when an error occurs on the socket.
// These errors currently include ECONNREFUSED, ECONNRESET and ETIMEDOUT, but
// could eventually include any BSD socket error.
typedef void UTPOnErrorProc(void *userdata, int errcode);
// The uTP socket layer calls this to report overhead statistics
typedef void UTPOnOverheadProc(void *userdata, bool send, size_t count, int type);
struct UTPFunctionTable {
UTPOnReadProc *on_read;
UTPOnWriteProc *on_write;
UTPGetRBSize *get_rb_size;
UTPOnStateChangeProc *on_state;
UTPOnErrorProc *on_error;
UTPOnOverheadProc *on_overhead;
};
// The uTP socket layer calls this when a new incoming uTP connection is established
// this implies writability
typedef void UTPGotIncomingConnection(void *userdata, struct UTPSocket* s);
// The uTP socket layer calls this to send UDP packets
typedef void SendToProc(void *userdata, const byte *p, size_t len, const struct sockaddr *to, socklen_t tolen);
// Functions which can be called with a uTP socket
// Create a uTP socket
struct UTPSocket *UTP_Create(SendToProc *send_to_proc, void *send_to_userdata,
const struct sockaddr *addr, socklen_t addrlen);
// Setup the callbacks - must be done before connect or on incoming connection
void UTP_SetCallbacks(struct UTPSocket *socket, struct UTPFunctionTable *func, void *userdata);
// Valid options include SO_SNDBUF, SO_RCVBUF and SO_UTPVERSION
bool UTP_SetSockopt(struct UTPSocket *socket, int opt, int val);
// Try to connect to a specified host.
void UTP_Connect(struct UTPSocket *socket);
// Process a UDP packet from the network. This will process a packet for an existing connection,
// or create a new connection and call incoming_proc. Returns true if the packet was processed
// in some way, false if the packet did not appear to be uTP.
bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc,
SendToProc *send_to_proc, void *send_to_userdata,
const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
// Process an ICMP received UDP packet.
bool UTP_HandleICMP(const byte* buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
// Write bytes to the uTP socket.
// Returns true if the socket is still writable.
bool UTP_Write(struct UTPSocket *socket, size_t count);
// Notify the uTP socket of buffer drain
void UTP_RBDrained(struct UTPSocket *socket);
// Call periodically to process timeouts and other periodic events
void UTP_CheckTimeouts(void);
// Retrieves the peer address of the specified socket, stores this address in the
// sockaddr structure pointed to by the addr argument, and stores the length of this
// address in the object pointed to by the addrlen argument.
void UTP_GetPeerName(struct UTPSocket *socket, struct sockaddr *addr, socklen_t *addrlen);
void UTP_GetDelays(struct UTPSocket *socket, int32 *ours, int32 *theirs, uint32 *age);
size_t UTP_GetPacketSize(struct UTPSocket *socket);
#ifdef _DEBUG
struct UTPStats {
uint64 _nbytes_recv; // total bytes received
uint64 _nbytes_xmit; // total bytes transmitted
uint32 _rexmit; // retransmit counter
uint32 _fastrexmit; // fast retransmit counter
uint32 _nxmit; // transmit counter
uint32 _nrecv; // receive counter (total)
uint32 _nduprecv; // duplicate receive counter
};
// Get stats for UTP socket
void UTP_GetStats(struct UTPSocket *socket, UTPStats *stats);
#endif
// Close the UTP socket.
// It is not valid to issue commands for this socket after it is closed.
// This does not actually destroy the socket until outstanding data is sent, at which
// point the socket will change to the UTP_STATE_DESTROYING state.
void UTP_Close(struct UTPSocket *socket);
struct UTPGlobalStats {
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (global)
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (global)
};
void UTP_GetGlobalStats(struct UTPGlobalStats *stats);
#ifdef __cplusplus
}
#endif
#endif //__UTP_H__
#ifndef __UTP_H__
#define __UTP_H__
#include "utypes.h"
#ifdef WIN32
#define _CRT_SECURE_NO_DEPRECATE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
struct UTPSocket;
// Used to set sockopt on a uTP socket to set the version of uTP
// to use for outgoing connections. This can only be called before
// the uTP socket is connected
#define SO_UTPVERSION 99
enum {
// socket has reveived syn-ack (notification only for outgoing connection completion)
// this implies writability
UTP_STATE_CONNECT = 1,
// socket is able to send more data
UTP_STATE_WRITABLE = 2,
// connection closed
UTP_STATE_EOF = 3,
// socket is being destroyed, meaning all data has been sent if possible.
// it is not valid to refer to the socket after this state change occurs
UTP_STATE_DESTROYING = 4,
};
// Callbacks called by a uTP socket (register with UTP_SetCallbacks)
// The uTP socket layer calls this when bytes have been received from the network.
typedef void UTPOnReadProc(void *userdata, const byte *bytes, size_t count);
// The uTP socket layer calls this to fill the outgoing buffer with bytes.
// The uTP layer takes responsibility that those bytes will be delivered.
typedef void UTPOnWriteProc(void *userdata, byte *bytes, size_t count);
// The uTP socket layer calls this to retrieve number of bytes currently in read buffer
typedef size_t UTPGetRBSize(void *userdata);
// The uTP socket layer calls this whenever the socket becomes writable.
typedef void UTPOnStateChangeProc(void *userdata, int state);
// The uTP socket layer calls this when an error occurs on the socket.
// These errors currently include ECONNREFUSED, ECONNRESET and ETIMEDOUT, but
// could eventually include any BSD socket error.
typedef void UTPOnErrorProc(void *userdata, int errcode);
// The uTP socket layer calls this to report overhead statistics
typedef void UTPOnOverheadProc(void *userdata, bool send, size_t count, int type);
struct UTPFunctionTable {
UTPOnReadProc *on_read;
UTPOnWriteProc *on_write;
UTPGetRBSize *get_rb_size;
UTPOnStateChangeProc *on_state;
UTPOnErrorProc *on_error;
UTPOnOverheadProc *on_overhead;
};
// The uTP socket layer calls this when a new incoming uTP connection is established
// this implies writability
typedef void UTPGotIncomingConnection(void *userdata, struct UTPSocket* s);
// The uTP socket layer calls this to send UDP packets
typedef void SendToProc(void *userdata, const byte *p, size_t len, const struct sockaddr *to, socklen_t tolen);
// Functions which can be called with a uTP socket
// Create a uTP socket
struct UTPSocket *UTP_Create(SendToProc *send_to_proc, void *send_to_userdata,
const struct sockaddr *addr, socklen_t addrlen);
// Setup the callbacks - must be done before connect or on incoming connection
void UTP_SetCallbacks(struct UTPSocket *socket, struct UTPFunctionTable *func, void *userdata);
// Valid options include SO_SNDBUF, SO_RCVBUF and SO_UTPVERSION
bool UTP_SetSockopt(struct UTPSocket *socket, int opt, int val);
// Try to connect to a specified host.
void UTP_Connect(struct UTPSocket *socket);
// Process a UDP packet from the network. This will process a packet for an existing connection,
// or create a new connection and call incoming_proc. Returns true if the packet was processed
// in some way, false if the packet did not appear to be uTP.
bool UTP_IsIncomingUTP(UTPGotIncomingConnection *incoming_proc,
SendToProc *send_to_proc, void *send_to_userdata,
const byte *buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
// Process an ICMP received UDP packet.
bool UTP_HandleICMP(const byte* buffer, size_t len, const struct sockaddr *to, socklen_t tolen);
// Write bytes to the uTP socket.
// Returns true if the socket is still writable.
bool UTP_Write(struct UTPSocket *socket, size_t count);
// Notify the uTP socket of buffer drain
void UTP_RBDrained(struct UTPSocket *socket);
// Call periodically to process timeouts and other periodic events
void UTP_CheckTimeouts(void);
// Retrieves the peer address of the specified socket, stores this address in the
// sockaddr structure pointed to by the addr argument, and stores the length of this
// address in the object pointed to by the addrlen argument.
void UTP_GetPeerName(struct UTPSocket *socket, struct sockaddr *addr, socklen_t *addrlen);
void UTP_GetDelays(struct UTPSocket *socket, int32 *ours, int32 *theirs, uint32 *age);
size_t UTP_GetPacketSize(struct UTPSocket *socket);
#ifdef _DEBUG
struct UTPStats {
uint64 _nbytes_recv; // total bytes received
uint64 _nbytes_xmit; // total bytes transmitted
uint32 _rexmit; // retransmit counter
uint32 _fastrexmit; // fast retransmit counter
uint32 _nxmit; // transmit counter
uint32 _nrecv; // receive counter (total)
uint32 _nduprecv; // duplicate receive counter
};
// Get stats for UTP socket
void UTP_GetStats(struct UTPSocket *socket, UTPStats *stats);
#endif
// Close the UTP socket.
// It is not valid to issue commands for this socket after it is closed.
// This does not actually destroy the socket until outstanding data is sent, at which
// point the socket will change to the UTP_STATE_DESTROYING state.
void UTP_Close(struct UTPSocket *socket);
struct UTPGlobalStats {
uint32 _nraw_recv[5]; // total packets recieved less than 300/600/1200/MTU bytes fpr all connections (global)
uint32 _nraw_send[5]; // total packets sent less than 300/600/1200/MTU bytes for all connections (global)
};
void UTP_GetGlobalStats(struct UTPGlobalStats *stats);
#ifdef __cplusplus
}
#endif
#endif //__UTP_H__

View File

@ -1,26 +1,26 @@
#define CCONTROL_TARGET (100 * 1000) // us
#define RATE_CHECK_INTERVAL 10000 // ms
#define DYNAMIC_PACKET_SIZE_ENABLED false
#define DYNAMIC_PACKET_SIZE_FACTOR 2
// This should return the global number of bytes sent, used for determining dynamic
// packet size based on rate
uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) { return 0; }
enum bandwidth_type_t {
payload_bandwidth, connect_overhead,
close_overhead, ack_overhead,
header_overhead, retransmit_overhead
};
#ifdef WIN32
#define I64u "%I64u"
#else
#define I64u "%Lu"
#endif
#ifdef WIN32
#define snprintf _snprintf
#endif
#define g_log_utp 0
#define g_log_utp_verbose 0
void utp_log(char const* fmt, ...);
#define CCONTROL_TARGET (100 * 1000) // us
#define RATE_CHECK_INTERVAL 10000 // ms
#define DYNAMIC_PACKET_SIZE_ENABLED false
#define DYNAMIC_PACKET_SIZE_FACTOR 2
// This should return the global number of bytes sent, used for determining dynamic
// packet size based on rate
uint64 UTP_GetGlobalUTPBytesSent(const struct sockaddr *remote, socklen_t remotelen) { return 0; }
enum bandwidth_type_t {
payload_bandwidth, connect_overhead,
close_overhead, ack_overhead,
header_overhead, retransmit_overhead
};
#ifdef WIN32
#define I64u "%I64u"
#else
#define I64u "%Lu"
#endif
#ifdef WIN32
#define snprintf _snprintf
#endif
#define g_log_utp 0
#define g_log_utp_verbose 0
void utp_log(char const* fmt, ...);

View File

@ -1,210 +1,210 @@
#include "StdAfx.h"
#include "utypes.h"
#include <assert.h>
#include <stdlib.h>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
static GetTickCount64Proc *pt2GetTickCount64;
static GetTickCount64Proc *pt2RealGetTickCount;
static uint64 startPerformanceCounter;
static uint64 startGetTickCount;
// MSVC 6 standard doesn't like division with uint64s
static double counterPerMicrosecond;
uint64 UTGetTickCount64()
{
if (pt2GetTickCount64) {
return pt2GetTickCount64();
}
if (pt2RealGetTickCount) {
uint64 v = pt2RealGetTickCount();
// fix return value from GetTickCount
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
}
return (uint64)GetTickCount();
}
void Time_Initialize()
{
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
// not a typo. GetTickCount actually returns 64 bits
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
uint64 frequency;
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
counterPerMicrosecond = (double)frequency / 1000000.0f;
startGetTickCount = UTGetTickCount64();
}
int64 abs64(int64 x) { return x < 0 ? -x : x; }
static uint64 GetMicroseconds()
{
static bool time_init = false;
if (!time_init) {
time_init = true;
Time_Initialize();
}
uint64 counter;
uint64 tick;
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
tick = UTGetTickCount64();
// unfortunately, QueryPerformanceCounter is not guaranteed
// to be monotonic. Make it so.
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
// if the QPC clock leaps more than one second off GetTickCount64()
// something is seriously fishy. Adjust QPC to stay monotonic
int64 tick_diff = tick - startGetTickCount;
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
}
return ret;
}
#else //!WIN32
#include <time.h>
#include <sys/time.h> // Linux needs both time.h and sys/time.h
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
static uint64 GetMicroseconds()
{
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
// http://www.macresearch.org/tutorial_performance_and_time
static mach_timebase_info_data_t sTimebaseInfo;
static uint64_t start_tick = 0;
uint64_t tick;
// Returns a counter in some fraction of a nanoseconds
tick = mach_absolute_time();
if (sTimebaseInfo.denom == 0) {
// Get the timer ratio to convert mach_absolute_time to nanoseconds
mach_timebase_info(&sTimebaseInfo);
start_tick = tick;
}
// Calculate the elapsed time, convert it to microseconds and return it.
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
}
#else //!__APPLE__
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
POSIX clocks work -- we could be running a recent libc with an ancient
kernel (think OpenWRT). -- jch */
static uint64_t GetMicroseconds()
{
static int have_posix_clocks = -1;
int rc;
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
if (have_posix_clocks < 0) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rc < 0) {
have_posix_clocks = 0;
} else {
have_posix_clocks = 1;
}
}
if (have_posix_clocks) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
return uint64(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
}
#endif
{
struct timeval tv;
rc = gettimeofday(&tv, NULL);
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
}
}
#endif //!__APPLE__
#endif //!WIN32
uint64 UTP_GetMicroseconds()
{
static uint64 offset = 0, previous = 0;
uint64 now = GetMicroseconds() + offset;
if (previous > now) {
/* Eek! */
offset += previous - now;
now = previous;
}
previous = now;
return now;
}
uint32 UTP_GetMilliseconds()
{
return UTP_GetMicroseconds() / 1000;
}
#define ETHERNET_MTU 1500
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
#define UDP_HEADER_SIZE 8
#define GRE_HEADER_SIZE 24
#define PPPOE_HEADER_SIZE 8
#define MPPE_HEADER_SIZE 2
// packets have been observed in the wild that were fragmented
// with a payload of 1416 for the first fragment
// There are reports of routers that have MTU sizes as small as 1392
#define FUDGE_HEADER_SIZE 36
#define TEREDO_MTU 1280
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_TEREDO_MTU (TEREDO_MTU - UDP_HEADER_SIZE)
uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen)
{
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return remote->sa_family == AF_INET6 ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
}
uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen)
{
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return remote->sa_family == AF_INET6 ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
}
uint32 UTP_Random()
{
return rand();
}
void UTP_DelaySample(const struct sockaddr *remote, int sample_ms) {}
size_t UTP_GetPacketSize(const struct sockaddr *remote) { return 1500; }
#include "StdAfx.h"
#include "utypes.h"
#include <assert.h>
#include <stdlib.h>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
typedef ULONGLONG (WINAPI GetTickCount64Proc)(void);
static GetTickCount64Proc *pt2GetTickCount64;
static GetTickCount64Proc *pt2RealGetTickCount;
static uint64 startPerformanceCounter;
static uint64 startGetTickCount;
// MSVC 6 standard doesn't like division with uint64s
static double counterPerMicrosecond;
uint64 UTGetTickCount64()
{
if (pt2GetTickCount64) {
return pt2GetTickCount64();
}
if (pt2RealGetTickCount) {
uint64 v = pt2RealGetTickCount();
// fix return value from GetTickCount
return (DWORD)v | ((v >> 0x18) & 0xFFFFFFFF00000000);
}
return (uint64)GetTickCount();
}
void Time_Initialize()
{
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
pt2GetTickCount64 = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount64");
// not a typo. GetTickCount actually returns 64 bits
pt2RealGetTickCount = (GetTickCount64Proc*)GetProcAddress(kernel32, "GetTickCount");
uint64 frequency;
QueryPerformanceCounter((LARGE_INTEGER*)&startPerformanceCounter);
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
counterPerMicrosecond = (double)frequency / 1000000.0f;
startGetTickCount = UTGetTickCount64();
}
int64 abs64(int64 x) { return x < 0 ? -x : x; }
static uint64 GetMicroseconds()
{
static bool time_init = false;
if (!time_init) {
time_init = true;
Time_Initialize();
}
uint64 counter;
uint64 tick;
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
tick = UTGetTickCount64();
// unfortunately, QueryPerformanceCounter is not guaranteed
// to be monotonic. Make it so.
int64 ret = (int64)(((int64)counter - (int64)startPerformanceCounter) / counterPerMicrosecond);
// if the QPC clock leaps more than one second off GetTickCount64()
// something is seriously fishy. Adjust QPC to stay monotonic
int64 tick_diff = tick - startGetTickCount;
if (abs64(ret / 100000 - tick_diff / 100) > 10) {
startPerformanceCounter -= (uint64)((int64)(tick_diff * 1000 - ret) * counterPerMicrosecond);
ret = (int64)((counter - startPerformanceCounter) / counterPerMicrosecond);
}
return ret;
}
#else //!WIN32
#include <time.h>
#include <sys/time.h> // Linux needs both time.h and sys/time.h
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
static uint64 GetMicroseconds()
{
// http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
// http://www.macresearch.org/tutorial_performance_and_time
static mach_timebase_info_data_t sTimebaseInfo;
static uint64_t start_tick = 0;
uint64_t tick;
// Returns a counter in some fraction of a nanoseconds
tick = mach_absolute_time();
if (sTimebaseInfo.denom == 0) {
// Get the timer ratio to convert mach_absolute_time to nanoseconds
mach_timebase_info(&sTimebaseInfo);
start_tick = tick;
}
// Calculate the elapsed time, convert it to microseconds and return it.
return ((tick - start_tick) * sTimebaseInfo.numer) / (sTimebaseInfo.denom * 1000);
}
#else //!__APPLE__
/* Unfortunately, #ifdef CLOCK_MONOTONIC is not enough to make sure that
POSIX clocks work -- we could be running a recent libc with an ancient
kernel (think OpenWRT). -- jch */
static uint64_t GetMicroseconds()
{
static int have_posix_clocks = -1;
int rc;
#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC)
if (have_posix_clocks < 0) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rc < 0) {
have_posix_clocks = 0;
} else {
have_posix_clocks = 1;
}
}
if (have_posix_clocks) {
struct timespec ts;
rc = clock_gettime(CLOCK_MONOTONIC, &ts);
return uint64(ts.tv_sec) * 1000000 + ts.tv_nsec / 1000;
}
#endif
{
struct timeval tv;
rc = gettimeofday(&tv, NULL);
return uint64(tv.tv_sec) * 1000000 + tv.tv_usec;
}
}
#endif //!__APPLE__
#endif //!WIN32
uint64 UTP_GetMicroseconds()
{
static uint64 offset = 0, previous = 0;
uint64 now = GetMicroseconds() + offset;
if (previous > now) {
/* Eek! */
offset += previous - now;
now = previous;
}
previous = now;
return now;
}
uint32 UTP_GetMilliseconds()
{
return UTP_GetMicroseconds() / 1000;
}
#define ETHERNET_MTU 1500
#define IPV4_HEADER_SIZE 20
#define IPV6_HEADER_SIZE 40
#define UDP_HEADER_SIZE 8
#define GRE_HEADER_SIZE 24
#define PPPOE_HEADER_SIZE 8
#define MPPE_HEADER_SIZE 2
// packets have been observed in the wild that were fragmented
// with a payload of 1416 for the first fragment
// There are reports of routers that have MTU sizes as small as 1392
#define FUDGE_HEADER_SIZE 36
#define TEREDO_MTU 1280
#define UDP_IPV4_OVERHEAD (IPV4_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_IPV6_OVERHEAD (IPV6_HEADER_SIZE + UDP_HEADER_SIZE)
#define UDP_TEREDO_OVERHEAD (UDP_IPV4_OVERHEAD + UDP_IPV6_OVERHEAD)
#define UDP_IPV4_MTU (ETHERNET_MTU - IPV4_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_IPV6_MTU (ETHERNET_MTU - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - GRE_HEADER_SIZE - PPPOE_HEADER_SIZE - MPPE_HEADER_SIZE - FUDGE_HEADER_SIZE)
#define UDP_TEREDO_MTU (TEREDO_MTU - UDP_HEADER_SIZE)
uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen)
{
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return remote->sa_family == AF_INET6 ? UDP_TEREDO_MTU : UDP_IPV4_MTU;
}
uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen)
{
// Since we don't know the local address of the interface,
// be conservative and assume all IPv6 connections are Teredo.
return remote->sa_family == AF_INET6 ? UDP_TEREDO_OVERHEAD : UDP_IPV4_OVERHEAD;
}
uint32 UTP_Random()
{
return rand();
}
void UTP_DelaySample(const struct sockaddr *remote, int sample_ms) {}
size_t UTP_GetPacketSize(const struct sockaddr *remote) { return 1500; }

View File

@ -1,16 +1,16 @@
// This should return the MTU to the destination
uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen);
// This should return the number of bytes of UDP overhead for one packet to the
// destination, for overhead calculation only
uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen);
// This should return monotonically increasing milliseconds, start point does not matter
uint32 UTP_GetMilliseconds();
// This should return monotonically increasing microseconds, start point does not matter
uint64 UTP_GetMicroseconds();
// This should return a random uint32
uint32 UTP_Random();
// This is called every time we have a delay sample is made
void UTP_DelaySample(const struct sockaddr *remote, int sample_ms);
// Should return the max packet size to use when sending to the given address
size_t UTP_GetPacketSize(const struct sockaddr *remote);
// This should return the MTU to the destination
uint16 UTP_GetUDPMTU(const struct sockaddr *remote, socklen_t remotelen);
// This should return the number of bytes of UDP overhead for one packet to the
// destination, for overhead calculation only
uint16 UTP_GetUDPOverhead(const struct sockaddr *remote, socklen_t remotelen);
// This should return monotonically increasing milliseconds, start point does not matter
uint32 UTP_GetMilliseconds();
// This should return monotonically increasing microseconds, start point does not matter
uint64 UTP_GetMicroseconds();
// This should return a random uint32
uint32 UTP_Random();
// This is called every time we have a delay sample is made
void UTP_DelaySample(const struct sockaddr *remote, int sample_ms);
// Should return the max packet size to use when sending to the given address
size_t UTP_GetPacketSize(const struct sockaddr *remote);

View File

@ -1,38 +1,42 @@
#ifndef __UTYPES_H__
#define __UTYPES_H__
// standard types
typedef unsigned char byte;
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short uint16;
typedef signed short int16;
typedef unsigned int uint;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef _MSC_VER
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#else
typedef unsigned long long uint64;
typedef long long int64;
#endif
/* compile-time assert */
#ifndef CASSERT
#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ];
#endif
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
#ifndef INT64_MAX
#define INT64_MAX 0x7fffffffffffffffLL
#endif
// always ANSI
typedef const char * cstr;
typedef char * str;
#endif //__UTYPES_H__
#ifndef __UTYPES_H__
#define __UTYPES_H__
// standard types
typedef unsigned char byte;
typedef unsigned char uint8;
typedef signed char int8;
typedef unsigned short uint16;
typedef signed short int16;
typedef unsigned int uint;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef _MSC_VER
typedef unsigned __int64 uint64;
typedef signed __int64 int64;
#else
typedef unsigned long long uint64;
typedef long long int64;
#endif
/* compile-time assert */
#ifndef CASSERT
#define CASSERT( exp, name ) typedef int is_not_##name [ (exp ) ? 1 : -1 ];
#endif
CASSERT(8 == sizeof(uint64), sizeof_uint64_is_8)
CASSERT(8 == sizeof(int64), sizeof_int64_is_8)
#ifndef INT64_MAX
#define INT64_MAX 0x7fffffffffffffffLL
#endif
// always ANSI
typedef const char * cstr;
typedef char * str;
#ifndef __cplusplus
typedef uint8 bool;
#endif
#endif //__UTYPES_H__