update libutp, fixing #4915
This commit is contained in:
parent
8ba32b11c0
commit
ca7654d8cd
|
@ -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_)
|
||||
|
|
|
@ -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
|
@ -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__
|
||||
|
|
|
@ -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, ...);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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__
|
||||
|
|
Loading…
Reference in New Issue