Compare commits
9 Commits
20200818.0
...
20170809.0
Author | SHA1 | Date | |
---|---|---|---|
|
2d26ae6d8d | ||
|
91a66cf5ad | ||
|
64473cfd11 | ||
|
7262e93623 | ||
|
1dfaafa90f | ||
|
235cd3dc99 | ||
|
3c82199303 | ||
|
3eeafa1cb9 | ||
|
8c7e5d3aff |
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
libev/* linguist-vendored
|
@@ -1,6 +0,0 @@
|
||||
For English speaking user:
|
||||
https://github.com/wangyu-/UDPspeeder/wiki/Issue-Guide
|
||||
|
||||
中文用户请看:
|
||||
https://github.com/wangyu-/UDPspeeder/wiki/发Issue前请看
|
||||
(否则Issue可能被忽略,或被直接关掉)
|
177
README.md
@@ -1,160 +1,105 @@
|
||||
# UDPspeeder
|
||||

|
||||
UDP加速器,降低UDP传输的丢包率。尤其适用于游戏和语音。
|
||||
|
||||
A Tunnel which Improves your Network Quality on a High-latency Lossy Link by using Forward Error Correction.
|
||||
这个是我自己稳定用了一个月的项目,用来玩服务器在美国的brawl stars和服务器在亚洲国外的mobile legend,效果不错。
|
||||
|
||||
When used alone, UDPspeeder improves only UDP connection. Nevertheless, if you used UDPspeeder + any UDP-based VPN together,
|
||||
you can improve any traffic(include TCP/UDP/ICMP), currently OpenVPN/L2TP/ShadowVPN are confirmed to be supported。
|
||||
#### 原理简介
|
||||
目前原理就是简单粗暴的多倍发包(以后会做Reed–Solomon code)。
|
||||
|
||||

|
||||
跟net-speeder比,优势在于client和server会把收到的多余包自动去掉,这个过程对上层透明,没有兼容性问题。而且发出的冗余数据包会做长度和内容的随机化,抓包是看不出发了冗余数据的,所以不用担心vps被封的问题。
|
||||
|
||||
or
|
||||
每个冗余数据包都是间隔数毫秒(可配置)以后延迟发出的,可以避开中间路由器因为瞬时buffer长度过长而连续丢掉所有副本。
|
||||
|
||||

|
||||
可以模拟延迟抖动,这样上层应用计算出来的RTT方差会更大,以等待后续冗余包的到达,不至于过早重传。
|
||||
|
||||
Assume your local network to your server is lossy. Just establish a VPN connection to your server with UDPspeeder + any UDP-based VPN, access your server via this VPN connection, then your connection quality will be significantly improved. With well-tuned parameters , you can easily reduce IP or UDP/ICMP packet-loss-rate to less than 0.01% . Besides reducing packet-loss-rate, UDPspeeder can also significantly improve your TCP latency and TCP single-thread download speed.
|
||||
#### 适用场景
|
||||
绝大部分流量不高的情况。程序本身加速udp,但是配合openvpn可以加速任何流量。网络状况不好时,游戏卡得没法玩,或者网页卡得没法打开,使用起来效果最好。但是不适合大流量的场景,比如BT下载和在线看视频。
|
||||
|
||||
[UDPspeeder Wiki](https://github.com/wangyu-/UDPspeeder/wiki)
|
||||
#### 其他功能
|
||||
输出UDP收发情况报告,便于分析网络。
|
||||
|
||||
[简体中文](/doc/README.zh-cn.md)(内容更丰富)
|
||||
模拟丢包,模拟延迟,模拟jitter。便于通过实验找出应用卡顿的原因。
|
||||
|
||||
# Efficacy
|
||||
tested on a link with 100ms latency and 10% packet loss at both direction
|
||||
重复包过滤功能可以关掉,模拟网络本身有重复包的情况。用来测试应用对重复报的支持情况。
|
||||
|
||||
### Ping Packet Loss
|
||||

|
||||
目前有amd64,x86,ar71xx的binary
|
||||
|
||||
### SCP Copy Speed
|
||||

|
||||
# 简明操作说明
|
||||
|
||||
# Supported Platforms
|
||||
Linux host (including desktop Linux,Android phone/tablet, OpenWRT router, or Raspberry PI).
|
||||
### 环境要求
|
||||
Linux主机,可以使是openwrt路由器,也可以是树莓派。在windows和mac上可以开虚拟机(桥接模式测试可用)。
|
||||
|
||||
For Windows and MacOS You can run UDPspeeder inside [this](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip) 7.5mb virtual machine image.
|
||||
### 安装
|
||||
下载编译好的二进制文件,解压到本地和服务器的任意目录。
|
||||
|
||||
# How does it work
|
||||
https://github.com/wangyu-/UDPspeeder/releases
|
||||
|
||||
UDPspeeder uses FEC(Forward Error Correction) to reduce packet loss rate, at the cost of addtional bandwidth. The algorithm for FEC is called Reed-Solomon.
|
||||
### 运行
|
||||
假设你有一个server,ip为44.55.66.77,有一个服务监听在udp 7777端口。 假设你需要加速本地到44.55.66.77:7777的流量
|
||||
|
||||

|
||||
```
|
||||
在client端运行:
|
||||
./speeder_ar71xx -l0.0.0.0:3323 -r 44.55.66.77:8855 -c -d2
|
||||
|
||||
### Reed-Solomon
|
||||
|
||||
`
|
||||
In coding theory, the Reed–Solomon code belongs to the class of non-binary cyclic error-correcting codes. The Reed–Solomon code is based on univariate polynomials over finite fields.
|
||||
`
|
||||
|
||||
`
|
||||
It is able to detect and correct multiple symbol errors. By adding t check symbols to the data, a Reed–Solomon code can detect any combination of up to t erroneous symbols, or correct up to ⌊t/2⌋ symbols. As an erasure code, it can correct up to t known erasures, or it can detect and correct combinations of errors and erasures. Reed–Solomon codes are also suitable as multiple-burst bit-error correcting codes, since a sequence of b + 1 consecutive bit errors can affect at most two symbols of size b. The choice of t is up to the designer of the code, and may be selected within wide limits.
|
||||
`
|
||||
|
||||

|
||||
|
||||
Check wikipedia for more info, https://en.wikipedia.org/wiki/Reed–Solomon_error_correction
|
||||
|
||||
# Getting Started
|
||||
|
||||
### Installing
|
||||
Download binary release from https://github.com/wangyu-/UDPspeeder/releases
|
||||
|
||||
### Running (improves UDP traffic only)
|
||||
Assume your server ip is 44.55.66.77, you have a service listening on udp port 7777.
|
||||
|
||||
```bash
|
||||
# Run at server side:
|
||||
./speederv2 -s -l0.0.0.0:4096 -r 127.0.0.1:7777 -f20:10 -k "passwd"
|
||||
|
||||
# Run at client side
|
||||
./speederv2 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -f20:10 -k "passwd"
|
||||
在server端运行:
|
||||
./speeder_amd64 -l0.0.0.0:8855 -r127.0.0.1:7777 -s -d2
|
||||
```
|
||||
|
||||
Now connecting to UDP port 3333 at the client side is equivalent to connecting to port 7777 at the server side, and the connection has been boosted by UDPspeeder.
|
||||
现在client和server之间建立起了tunnel。想要连接44.55.66.77:7777,只需要连接 127.0.0.1:3333。来回的所有的udp流量会被加速。
|
||||
|
||||
##### Note
|
||||
# 效果
|
||||
在模拟丢包的网络环境下,架设了vpn服务器(udp模式)。收发各有10%的丢包率
|
||||
|
||||
`-f20:10` means sending 10 redundant packets for every 20 original packets.
|
||||
#### 使用前
|
||||
<img src="images/Capture4.PNG" width="500">
|
||||
#### 使用后
|
||||
3倍冗余数据。
|
||||
|
||||
`-k` enables simple XOR encryption
|
||||
<img src="images/Capture6.PNG" width="500">
|
||||
|
||||
# 进阶操作说明
|
||||
|
||||
# Improves all traffic with OpenVPN + UDPspeeder
|
||||
|
||||
See [UDPspeeder + openvpn config guide](https://github.com/wangyu-/UDPspeeder/wiki/UDPspeeder-openvpn-config-guide).
|
||||
|
||||
# Advanced Topic
|
||||
|
||||
### Full Options
|
||||
### 命令选项
|
||||
```
|
||||
UDPspeeder V2
|
||||
git version: 3e248b414c build date: Aug 5 2018 21:59:52
|
||||
UDPspeeder
|
||||
version: Aug 9 2017 18:13:09
|
||||
repository: https://github.com/wangyu-/UDPspeeder
|
||||
|
||||
usage:
|
||||
run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]
|
||||
run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]
|
||||
|
||||
common options, must be same on both sides:
|
||||
-k,--key <string> key for simple xor encryption. if not set, xor is disabled
|
||||
common option,must be same on both sides:
|
||||
-k,--key <string> key for simple xor encryption,default:"secret key"
|
||||
main options:
|
||||
-f,--fec x:y forward error correction, send y redundant packets for every x packets
|
||||
--timeout <number> how long could a packet be held in queue before doing fec, unit: ms, default: 8ms
|
||||
--report <number> turn on send/recv report, and set a period for reporting, unit: s
|
||||
-d <number> duplicated packet number, -d 0 means no duplicate. default value:0
|
||||
-t <number> duplicated packet delay time, unit: 0.1ms,default value:20(2ms)
|
||||
-j <number> simulated jitter.randomly delay first packet for 0~jitter_value*0.1 ms,to
|
||||
create simulated jitter.default value:0.do not use if you dont
|
||||
know what it means
|
||||
--report <number> turn on udp send/recv report,and set a time interval for reporting,unit:s
|
||||
advanced options:
|
||||
--mode <number> fec-mode,available values: 0,1; mode 0(default) costs less bandwidth,no mtu problem.
|
||||
mode 1 usually introduces less latency, but you have to care about mtu.
|
||||
--mtu <number> mtu. for mode 0, the program will split packet to segment smaller than mtu value.
|
||||
for mode 1, no packet will be split, the program just check if the mtu is exceed.
|
||||
default value: 1250. you typically shouldnt change this value.
|
||||
-q,--queue-len <number> fec queue len, only for mode 0, fec will be performed immediately after queue is full.
|
||||
default value: 200.
|
||||
-j,--jitter <number> simulated jitter. randomly delay first packet for 0~<number> ms, default value: 0.
|
||||
do not use if you dont know what it means.
|
||||
-i,--interval <number> scatter each fec group to a interval of <number> ms, to protect burst packet loss.
|
||||
default value: 0. do not use if you dont know what it means.
|
||||
-f,--fec x1:y1,x2:y2,.. similiar to -f/--fec above,fine-grained fec parameters,may help save bandwidth.
|
||||
example: "-f 1:3,2:4,10:6,20:10". check repo for details
|
||||
--random-drop <number> simulate packet loss, unit: 0.01%. default value: 0.
|
||||
--disable-obscure <number> disable obscure, to save a bit bandwidth and cpu.
|
||||
developer options:
|
||||
--fifo <string> use a fifo(named pipe) for sending commands to the running program, so that you
|
||||
can change fec encode parameters dynamically, check readme.md in repository for
|
||||
supported commands.
|
||||
-j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax
|
||||
-i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax
|
||||
--decode-buf <number> size of buffer of fec decoder,u nit: packet, default: 2000
|
||||
--fix-latency <number> try to stabilize latency, only for mode 0
|
||||
--delay-capacity <number> max number of delayed packets
|
||||
--disable-fec <number> completely disable fec, turn the program into a normal udp tunnel
|
||||
--sock-buf <number> buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024
|
||||
log and help options:
|
||||
-t tmin:tmax simliar to -t above,but delay randomly between tmin and tmax
|
||||
-j jmin:jmax simliar to -j above,but create jitter randomly between jmin and jmax
|
||||
--random-drop <number> simulate packet loss ,unit 0.01%
|
||||
-m <number> max pending packets,to prevent the program from eating up all your memory.
|
||||
other options:
|
||||
--log-level <number> 0:never 1:fatal 2:error 3:warn
|
||||
4:info (default) 5:debug 6:trace
|
||||
--log-position enable file name,function name,line number in log
|
||||
--disable-color disable log color
|
||||
--sock-buf <number> buf size for socket,>=10 and <=10240,unit:kbyte,default:512
|
||||
-h,--help print this help message
|
||||
|
||||
```
|
||||
#### `--fifo` option
|
||||
Use a fifo(named pipe) for sending commands to the running program. For example `--fifo fifo.file`, you can use following commands to change parameters dynamically:
|
||||
```
|
||||
echo fec 19:9 > fifo.file
|
||||
echo mtu 1100 > fifo.file
|
||||
echo timeout 5 > fifo.file
|
||||
echo queue-len 100 > fifo.file
|
||||
echo mode 0 > fifo.file
|
||||
```
|
||||
|
||||
# 应用
|
||||
|
||||
# wiki
|
||||
Check wiki for more info:
|
||||
#### UDPspeeder + openvpn加速任何流量
|
||||
如果你只是需要玩游戏,效果(可能/大概)会比kcp/finalspeed方案更好。可以优化tcp游戏的延迟(通过冗余发包,避免了上层的重传)。比如魔兽世界。
|
||||

|
||||
#### UDPspeeder + kcptun/finalspeed同时加速tcp和udp流量
|
||||
如果你需要用加速的tcp看视频和下载文件,这样效果比vpn方案更好。不论是速度,还是流量的耗费上。
|
||||

|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/wiki
|
||||
|
||||
# Related repo
|
||||
|
||||
You can also try tinyfecVPN, a lightweight high-performance VPN with UDPspeeder's function built-in, repo:
|
||||
|
||||
https://github.com/wangyu-/tinyfecVPN
|
||||
|
||||
You can use udp2raw with UDPspeeder together to get better speed on some ISP with UDP QoS(UDP throttling), repo:
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel
|
||||
|
984
common.cpp
485
common.h
@@ -7,7 +7,7 @@
|
||||
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
//#define __STDC_FORMAT_MACROS 1
|
||||
#define __STDC_FORMAT_MACROS 1
|
||||
#include <inttypes.h>
|
||||
|
||||
#include<stdio.h>
|
||||
@@ -17,47 +17,39 @@
|
||||
|
||||
#include<unistd.h>
|
||||
#include<errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h> //for socket ofcourse
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h> //for exit(0);
|
||||
#include <errno.h> //For errno - the error number
|
||||
//#include <netinet/tcp.h> //Provides declarations for tcp header
|
||||
//#include <netinet/udp.h>
|
||||
//#include <netinet/ip.h> //Provides declarations for ip header
|
||||
//#include <netinet/if_ether.h>
|
||||
#include <netinet/tcp.h> //Provides declarations for tcp header
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip.h> //Provides declarations for ip header
|
||||
#include <netinet/if_ether.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <byteswap.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/filter.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
//#include <netinet/in.h>
|
||||
//#include <net/if.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#if !defined(NO_LIBEV_EMBED)
|
||||
#include <my_ev.h>
|
||||
#else
|
||||
#include "ev.h"
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include<unordered_map>
|
||||
#include<unordered_set>
|
||||
#include<map>
|
||||
#include<list>
|
||||
#include<string>
|
||||
#include<vector>
|
||||
using namespace std;
|
||||
|
||||
|
||||
@@ -67,55 +59,16 @@ typedef long long i64_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef int i32_t;
|
||||
|
||||
typedef unsigned short u16_t;
|
||||
typedef short i16_t;
|
||||
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
int inet_pton(int af, const char *src, void *dst);
|
||||
const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);
|
||||
#define setsockopt(a,b,c,d,e) setsockopt(a,b,c,(const char *)(d),e)
|
||||
#endif
|
||||
|
||||
char *get_sock_error();
|
||||
int get_sock_errno();
|
||||
int init_ws();
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
typedef SOCKET my_fd_t;
|
||||
inline int sock_close(my_fd_t fd)
|
||||
{
|
||||
return closesocket(fd);
|
||||
}
|
||||
#else
|
||||
typedef int my_fd_t;
|
||||
inline int sock_close(my_fd_t fd)
|
||||
{
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
struct my_itimerspec {
|
||||
struct timespec it_interval; /* Timer interval */
|
||||
struct timespec it_value; /* Initial expiration */
|
||||
};
|
||||
|
||||
typedef u64_t my_time_t;
|
||||
|
||||
const int max_addr_len=100;
|
||||
const int max_data_len=3600;
|
||||
const int max_data_len=1600;
|
||||
const int buf_len=max_data_len+200;
|
||||
|
||||
const int default_mtu=1250;
|
||||
|
||||
//const u32_t timer_interval=400;
|
||||
////const u32_t conv_timeout=180000;
|
||||
//const u32_t conv_timeout=40000;//for test
|
||||
const u32_t conv_timeout=180000;
|
||||
const u32_t conv_clear_interval=200;
|
||||
const u32_t timer_interval=400;
|
||||
const int conv_clear_ratio=40;
|
||||
const int conv_clear_min=5;
|
||||
const u32_t conv_timeout=20000;
|
||||
const int max_conv_num=10000;
|
||||
const int max_conn_num=200;
|
||||
|
||||
/*
|
||||
const u32_t max_handshake_conn_num=10000;
|
||||
@@ -126,14 +79,14 @@ const u32_t max_ready_conn_num=1000;
|
||||
const u32_t client_handshake_timeout=5000;
|
||||
const u32_t client_retry_interval=1000;
|
||||
|
||||
const u32_t server_handshake_timeout=10000;// this should be much longer than clients. client retry initially ,server retry passtively*/
|
||||
const u32_t server_handshake_timeout=10000;// this should be much longer than clients. client retry initially ,server retry passtively
|
||||
|
||||
const int conv_clear_ratio=30; //conv grabage collecter check 1/30 of all conv one time
|
||||
const int conn_clear_ratio=50;
|
||||
const int conv_clear_min=1;
|
||||
const int conv_clear_ratio=10; //conv grabage collecter check 1/10 of all conv one time
|
||||
const int conn_clear_ratio=10;
|
||||
const int conv_clear_min=5;
|
||||
const int conn_clear_min=1;
|
||||
|
||||
const u32_t conv_clear_interval=1000;
|
||||
|
||||
const u32_t conn_clear_interval=1000;
|
||||
|
||||
|
||||
@@ -144,14 +97,14 @@ const u32_t heartbeat_interval=1000;
|
||||
const u32_t timer_interval=400;//this should be smaller than heartbeat_interval and retry interval;
|
||||
|
||||
//const uint32_t conv_timeout=120000; //120 second
|
||||
//const u32_t conv_timeout=120000; //for test
|
||||
const u32_t conv_timeout=120000; //for test
|
||||
|
||||
const u32_t client_conn_timeout=10000;
|
||||
const u32_t client_conn_uplink_timeout=client_conn_timeout+2000;
|
||||
|
||||
//const uint32_t server_conn_timeout=conv_timeout+60000;//this should be 60s+ longer than conv_timeout,so that conv_manager can destruct convs gradually,to avoid latency glicth
|
||||
const u32_t server_conn_timeout=conv_timeout+20000;//for test
|
||||
|
||||
const u32_t server_conn_timeout=conv_timeout+60000;//for test
|
||||
*/
|
||||
|
||||
extern int about_to_exit;
|
||||
|
||||
@@ -160,14 +113,9 @@ extern raw_mode_t raw_mode;
|
||||
enum program_mode_t {unset_mode=0,client_mode,server_mode};
|
||||
extern program_mode_t program_mode;
|
||||
extern unordered_map<int, const char*> raw_mode_tostring ;
|
||||
|
||||
enum working_mode_t {unset_working_mode=0,tunnel_mode,tun_dev_mode};
|
||||
extern working_mode_t working_mode;
|
||||
|
||||
extern int socket_buf_size;
|
||||
|
||||
|
||||
//typedef u32_t id_t;
|
||||
typedef u32_t id_t;
|
||||
|
||||
typedef u64_t iv_t;
|
||||
|
||||
@@ -175,223 +123,7 @@ typedef u64_t padding_t;
|
||||
|
||||
typedef u64_t anti_replay_seq_t;
|
||||
|
||||
typedef u64_t fd64_t;
|
||||
|
||||
//enum dest_type{none=0,type_fd64_ip_port,type_fd64,type_fd64_ip_port_conv,type_fd64_conv/*,type_fd*/};
|
||||
enum dest_type{none=0,type_fd64_addr,type_fd64,type_fd,type_write_fd,type_fd_addr/*,type_fd*/};
|
||||
|
||||
/*
|
||||
struct ip_port_t
|
||||
{
|
||||
u32_t ip;
|
||||
int port;
|
||||
void from_u64(u64_t u64);
|
||||
u64_t to_u64();
|
||||
char * to_s();
|
||||
};
|
||||
|
||||
struct fd64_ip_port_t
|
||||
{
|
||||
fd64_t fd64;
|
||||
ip_port_t ip_port;
|
||||
};
|
||||
struct fd_ip_port_t
|
||||
{
|
||||
int fd;
|
||||
ip_port_t ip_port;
|
||||
};*/
|
||||
|
||||
|
||||
struct pseudo_header {
|
||||
u32_t source_address;
|
||||
u32_t dest_address;
|
||||
unsigned char placeholder;
|
||||
unsigned char protocol;
|
||||
unsigned short tcp_length;
|
||||
};
|
||||
|
||||
u32_t djb2(unsigned char *str,int len);
|
||||
u32_t sdbm(unsigned char *str,int len);
|
||||
|
||||
struct address_t //TODO scope id
|
||||
{
|
||||
struct hash_function
|
||||
{
|
||||
u32_t operator()(const address_t &key) const
|
||||
{
|
||||
return sdbm((unsigned char*)&key.inner,sizeof(key.inner));
|
||||
}
|
||||
};
|
||||
|
||||
union storage_t //sockaddr_storage is too huge, we dont use it.
|
||||
{
|
||||
sockaddr_in ipv4;
|
||||
sockaddr_in6 ipv6;
|
||||
};
|
||||
storage_t inner;
|
||||
|
||||
/*address_t()
|
||||
{
|
||||
clear();
|
||||
}*/
|
||||
void clear()
|
||||
{
|
||||
memset(&inner,0,sizeof(inner));
|
||||
}
|
||||
/*
|
||||
int from_ip_port(u32_t ip, int port)
|
||||
{
|
||||
clear();
|
||||
inner.ipv4.sin_family=AF_INET;
|
||||
inner.ipv4.sin_port=htons(port);
|
||||
inner.ipv4.sin_addr.s_addr=ip;
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
int from_ip_port_new(int type, void * ip, int port)
|
||||
{
|
||||
clear();
|
||||
if(type==AF_INET)
|
||||
{
|
||||
inner.ipv4.sin_family=AF_INET;
|
||||
inner.ipv4.sin_port=htons(port);
|
||||
inner.ipv4.sin_addr.s_addr=*((u32_t *)ip);
|
||||
}
|
||||
else if(type==AF_INET6)
|
||||
{
|
||||
inner.ipv6.sin6_family=AF_INET6;
|
||||
inner.ipv6.sin6_port=htons(port);
|
||||
inner.ipv6.sin6_addr=*((in6_addr*)ip);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int from_str(char * str);
|
||||
|
||||
int from_str_ip_only(char * str);
|
||||
|
||||
int from_sockaddr(sockaddr *,socklen_t);
|
||||
|
||||
char* get_str();
|
||||
void to_str(char *);
|
||||
|
||||
inline int is_vaild()
|
||||
{
|
||||
u32_t ret=((sockaddr*)&inner)->sa_family;
|
||||
return (ret==AF_INET||ret==AF_INET6);
|
||||
}
|
||||
|
||||
inline u32_t get_type()
|
||||
{
|
||||
assert(is_vaild());
|
||||
u32_t ret=((sockaddr*)&inner)->sa_family;
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline u32_t get_len()
|
||||
{
|
||||
u32_t type=get_type();
|
||||
switch(type)
|
||||
{
|
||||
case AF_INET:
|
||||
return sizeof(sockaddr_in);
|
||||
case AF_INET6:
|
||||
return sizeof(sockaddr_in6);
|
||||
default:
|
||||
assert(0==1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline u32_t get_port()
|
||||
{
|
||||
u32_t type=get_type();
|
||||
switch(type)
|
||||
{
|
||||
case AF_INET:
|
||||
return ntohs(inner.ipv4.sin_port);
|
||||
case AF_INET6:
|
||||
return ntohs(inner.ipv6.sin6_port);
|
||||
default:
|
||||
assert(0==1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline void set_port(int port)
|
||||
{
|
||||
u32_t type=get_type();
|
||||
switch(type)
|
||||
{
|
||||
case AF_INET:
|
||||
inner.ipv4.sin_port=htons(port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inner.ipv6.sin6_port=htons(port);
|
||||
break;
|
||||
default:
|
||||
assert(0==1);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
bool operator == (const address_t &b) const
|
||||
{
|
||||
//return this->data==b.data;
|
||||
return memcmp(&this->inner,&b.inner,sizeof(this->inner))==0;
|
||||
}
|
||||
|
||||
int new_connected_udp_fd();
|
||||
|
||||
char* get_ip();
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<address_t>
|
||||
{
|
||||
std::size_t operator()(const address_t& key) const
|
||||
{
|
||||
|
||||
//return address_t::hash_function(k);
|
||||
return sdbm((unsigned char*)&key.inner,sizeof(key.inner));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
struct fd64_addr_t
|
||||
{
|
||||
fd64_t fd64;
|
||||
address_t addr;
|
||||
};
|
||||
struct fd_addr_t
|
||||
{
|
||||
int fd;
|
||||
address_t addr;
|
||||
};
|
||||
union inner_t
|
||||
{
|
||||
fd64_t fd64;
|
||||
int fd;
|
||||
fd64_addr_t fd64_addr;
|
||||
fd_addr_t fd_addr;
|
||||
};
|
||||
struct dest_t
|
||||
{
|
||||
dest_type type;
|
||||
inner_t inner;
|
||||
u32_t conv;
|
||||
int cook=0;
|
||||
};
|
||||
|
||||
struct fd_info_t
|
||||
{
|
||||
address_t addr;
|
||||
ev_io io_watcher;
|
||||
};
|
||||
|
||||
u64_t get_current_time();
|
||||
//u64_t get_current_time_rough();
|
||||
u64_t get_current_time_us();
|
||||
u64_t pack_u64(u32_t a,u32_t b);
|
||||
|
||||
@@ -399,166 +131,31 @@ u32_t get_u64_h(u64_t a);
|
||||
|
||||
u32_t get_u64_l(u64_t a);
|
||||
|
||||
void write_u16(char *,u16_t a);
|
||||
u16_t read_u16(char *);
|
||||
|
||||
void write_u32(char *,u32_t a);
|
||||
u32_t read_u32(char *);
|
||||
|
||||
void write_u64(char *,u64_t a);
|
||||
u64_t read_uu64(char *);
|
||||
|
||||
char * my_ntoa(u32_t ip);
|
||||
|
||||
void myexit(int a);
|
||||
void init_random_number_fd();
|
||||
u64_t get_fake_random_number_64();
|
||||
u32_t get_fake_random_number();
|
||||
u32_t get_fake_random_number_nz();
|
||||
u64_t get_true_random_number_64();
|
||||
u32_t get_true_random_number();
|
||||
u32_t get_true_random_number_nz();
|
||||
u64_t ntoh64(u64_t a);
|
||||
u64_t hton64(u64_t a);
|
||||
bool larger_than_u16(uint16_t a,uint16_t b);
|
||||
bool larger_than_u32(u32_t a,u32_t b);
|
||||
void setnonblocking(int sock);
|
||||
int set_buf_size(int fd,int socket_buf_size);
|
||||
int set_buf_size(int fd,int size=socket_buf_size);
|
||||
|
||||
unsigned short csum(const unsigned short *ptr,int nbytes);
|
||||
unsigned short tcp_csum(const pseudo_header & ph,const unsigned short *ptr,int nbytes);
|
||||
|
||||
void signal_handler(int sig);
|
||||
//int numbers_to_char(id_t id1,id_t id2,id_t id3,char * &data,int &len);
|
||||
//int char_to_numbers(const char * data,int len,id_t &id1,id_t &id2,id_t &id3);
|
||||
int numbers_to_char(id_t id1,id_t id2,id_t id3,char * &data,int &len);
|
||||
int char_to_numbers(const char * data,int len,id_t &id1,id_t &id2,id_t &id3);
|
||||
|
||||
void myexit(int a);
|
||||
|
||||
int add_iptables_rule(char *);
|
||||
|
||||
int clear_iptables_rule();
|
||||
void get_fake_random_chars(char * s,int len);
|
||||
int random_between(u32_t a,u32_t b);
|
||||
|
||||
int set_timer_ms(int epollfd,int &timer_fd,u32_t timer_interval);
|
||||
|
||||
int round_up_div(int a,int b);
|
||||
|
||||
int create_fifo(char * file);
|
||||
/*
|
||||
int create_new_udp(int &new_udp_fd,int remote_address_uint32,int remote_port);
|
||||
*/
|
||||
|
||||
int new_listen_socket(int &fd,u32_t ip,int port);
|
||||
|
||||
int new_connected_socket(int &fd,u32_t ip,int port);
|
||||
|
||||
int new_listen_socket2(int &fd,address_t &addr);
|
||||
int new_connected_socket2(int &fd,address_t &addr,address_t *bind_addr,char *out_interface);
|
||||
|
||||
struct not_copy_able_t
|
||||
{
|
||||
not_copy_able_t()
|
||||
{
|
||||
|
||||
}
|
||||
not_copy_able_t(const not_copy_able_t &other)
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
const not_copy_able_t & operator=(const not_copy_able_t &other)
|
||||
{
|
||||
assert(0==1);
|
||||
return other;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class key_t>
|
||||
struct lru_collector_t:not_copy_able_t
|
||||
{
|
||||
//typedef void* key_t;
|
||||
//#define key_t void*
|
||||
struct lru_pair_t
|
||||
{
|
||||
key_t key;
|
||||
my_time_t ts;
|
||||
};
|
||||
|
||||
unordered_map<key_t,typename list<lru_pair_t>::iterator> mp;
|
||||
|
||||
list<lru_pair_t> q;
|
||||
int update(key_t key)
|
||||
{
|
||||
assert(mp.find(key)!=mp.end());
|
||||
auto it=mp[key];
|
||||
q.erase(it);
|
||||
|
||||
my_time_t value=get_current_time();
|
||||
if(!q.empty())
|
||||
{
|
||||
assert(value >=q.front().ts);
|
||||
}
|
||||
lru_pair_t tmp; tmp.key=key; tmp.ts=value;
|
||||
q.push_front( tmp);
|
||||
mp[key]=q.begin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
int new_key(key_t key)
|
||||
{
|
||||
assert(mp.find(key)==mp.end());
|
||||
|
||||
my_time_t value=get_current_time();
|
||||
if(!q.empty())
|
||||
{
|
||||
assert(value >=q.front().ts);
|
||||
}
|
||||
lru_pair_t tmp; tmp.key=key; tmp.ts=value;
|
||||
q.push_front( tmp);
|
||||
mp[key]=q.begin();
|
||||
|
||||
return 0;
|
||||
}
|
||||
int size()
|
||||
{
|
||||
return q.size();
|
||||
}
|
||||
int empty()
|
||||
{
|
||||
return q.empty();
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
mp.clear(); q.clear();
|
||||
}
|
||||
my_time_t ts_of(key_t key)
|
||||
{
|
||||
assert(mp.find(key)!=mp.end());
|
||||
return mp[key]->ts;
|
||||
}
|
||||
|
||||
my_time_t peek_back(key_t &key)
|
||||
{
|
||||
assert(!q.empty());
|
||||
auto it=q.end(); it--;
|
||||
key=it->key;
|
||||
return it->ts;
|
||||
}
|
||||
void erase(key_t key)
|
||||
{
|
||||
assert(mp.find(key)!=mp.end());
|
||||
q.erase(mp[key]);
|
||||
mp.erase(key);
|
||||
}
|
||||
/*
|
||||
void erase_back()
|
||||
{
|
||||
assert(!q.empty());
|
||||
auto it=q.end(); it--;
|
||||
key_t key=it->key;
|
||||
erase(key);
|
||||
}*/
|
||||
};
|
||||
|
||||
|
||||
vector<string> string_to_vec(const char * s,const char * sp) ;
|
||||
void get_true_random_chars(char * s,int len);
|
||||
|
||||
#endif /* COMMON_H_ */
|
||||
|
153
connection.cpp
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* connection.cpp
|
||||
*
|
||||
* Created on: Sep 23, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "connection.h"
|
||||
|
||||
//const int disable_conv_clear=0;//a udp connection in the multiplexer is called conversation in this program,conv for short.
|
||||
|
||||
const int disable_conn_clear=0;//a raw connection is called conn.
|
||||
|
||||
int report_interval=0;
|
||||
|
||||
void server_clear_function(u64_t u64)//used in conv_manager in server mode.for server we have to use one udp fd for one conv(udp connection),
|
||||
//so we have to close the fd when conv expires
|
||||
{
|
||||
fd64_t fd64=u64;
|
||||
assert(fd_manager.exist(fd64));
|
||||
ev_io &watcher= fd_manager.get_info(fd64).io_watcher;
|
||||
|
||||
address_t &addr=fd_manager.get_info(fd64).addr;//
|
||||
assert(conn_manager.exist(addr));//
|
||||
struct ev_loop *loop =conn_manager.find_insert(addr).loop; // overkill ? should we just use ev_default_loop(0)?
|
||||
|
||||
ev_io_stop(loop,&watcher);
|
||||
|
||||
fd_manager.fd64_close(fd64);
|
||||
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
conn_manager_t::conn_manager_t()
|
||||
{
|
||||
mp.reserve(10007);
|
||||
last_clear_time=0;
|
||||
}
|
||||
int conn_manager_t::exist(address_t addr)
|
||||
{
|
||||
|
||||
if(mp.find(addr)!=mp.end())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn_info_t *& conn_manager_t::find_insert_p(address_t addr) //be aware,the adress may change after rehash
|
||||
{
|
||||
// u64_t u64=0;
|
||||
//u64=ip;
|
||||
//u64<<=32u;
|
||||
//u64|=port;
|
||||
unordered_map<address_t,conn_info_t*>::iterator it=mp.find(addr);
|
||||
if(it==mp.end())
|
||||
{
|
||||
mp[addr]=new conn_info_t;
|
||||
//lru.new_key(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//lru.update(addr);
|
||||
}
|
||||
return mp[addr];
|
||||
}
|
||||
conn_info_t & conn_manager_t::find_insert(address_t addr) //be aware,the adress may change after rehash
|
||||
{
|
||||
//u64_t u64=0;
|
||||
//u64=ip;
|
||||
//u64<<=32u;
|
||||
//u64|=port;
|
||||
unordered_map<address_t,conn_info_t*>::iterator it=mp.find(addr);
|
||||
if(it==mp.end())
|
||||
{
|
||||
mp[addr]=new conn_info_t;
|
||||
//lru.new_key(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//lru.update(addr);
|
||||
}
|
||||
return *mp[addr];
|
||||
}
|
||||
int conn_manager_t::erase(unordered_map<address_t,conn_info_t*>::iterator erase_it)
|
||||
{
|
||||
delete(erase_it->second);
|
||||
mp.erase(erase_it->first);
|
||||
return 0;
|
||||
}
|
||||
int conn_manager_t::clear_inactive()
|
||||
{
|
||||
if(get_current_time()-last_clear_time>conn_clear_interval)
|
||||
{
|
||||
last_clear_time=get_current_time();
|
||||
return clear_inactive0();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int conn_manager_t::clear_inactive0()
|
||||
{
|
||||
//mylog(log_info,"called\n");
|
||||
unordered_map<address_t,conn_info_t*>::iterator it;
|
||||
unordered_map<address_t,conn_info_t*>::iterator old_it;
|
||||
|
||||
if(disable_conn_clear) return 0;
|
||||
|
||||
//map<uint32_t,uint64_t>::iterator it;
|
||||
int cnt=0;
|
||||
it=clear_it;//TODO,write it back
|
||||
int size=mp.size();
|
||||
int num_to_clean=size/conn_clear_ratio+conn_clear_min; //clear 1/10 each time,to avoid latency glitch
|
||||
|
||||
//mylog(log_trace,"mp.size() %d\n", size);
|
||||
|
||||
num_to_clean=min(num_to_clean,(int)mp.size());
|
||||
u64_t current_time=get_current_time();
|
||||
|
||||
//mylog(log_info,"here size=%d\n",(int)mp.size());
|
||||
for(;;)
|
||||
{
|
||||
if(cnt>=num_to_clean) break;
|
||||
if(mp.begin()==mp.end()) break;
|
||||
if(it==mp.end())
|
||||
{
|
||||
it=mp.begin();
|
||||
}
|
||||
|
||||
if(it->second->conv_manager.s.get_size() >0)
|
||||
{
|
||||
//mylog(log_info,"[%s:%d]size %d \n",my_ntoa(get_u64_h(it->first)),get_u64_l(it->first),(int)it->second->conv_manager.get_size());
|
||||
it++;
|
||||
}
|
||||
else if(current_time<it->second->last_active_time+server_conn_timeout)
|
||||
{
|
||||
it++;
|
||||
}
|
||||
else
|
||||
{
|
||||
address_t tmp_addr=it->first;// avoid making get_str() const;
|
||||
mylog(log_info,"{%s} inactive conn cleared \n",tmp_addr.get_str());
|
||||
old_it=it;
|
||||
it++;
|
||||
erase(old_it);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
clear_it=it;
|
||||
return 0;
|
||||
}
|
383
connection.h
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* connection.h
|
||||
*
|
||||
* Created on: Sep 23, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef CONNECTION_H_
|
||||
#define CONNECTION_H_
|
||||
|
||||
extern int disable_anti_replay;
|
||||
|
||||
#include "connection.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "delay_manager.h"
|
||||
#include "fd_manager.h"
|
||||
#include "fec_manager.h"
|
||||
|
||||
extern int report_interval;
|
||||
|
||||
const int disable_conv_clear=0;
|
||||
|
||||
void server_clear_function(u64_t u64);
|
||||
|
||||
template <class T>
|
||||
struct conv_manager_t // manage the udp connections
|
||||
{
|
||||
//typedef hash_map map;
|
||||
unordered_map<T,u32_t> data_to_conv; //conv and u64 are both supposed to be uniq
|
||||
unordered_map<u32_t,T> conv_to_data;
|
||||
|
||||
lru_collector_t<u32_t> lru;
|
||||
//unordered_map<u32_t,u64_t> conv_last_active_time;
|
||||
|
||||
//unordered_map<u32_t,u64_t>::iterator clear_it;
|
||||
|
||||
void (*additional_clear_function)(T data) =0;
|
||||
|
||||
long long last_clear_time;
|
||||
|
||||
conv_manager_t()
|
||||
{
|
||||
//clear_it=conv_last_active_time.begin();
|
||||
long long last_clear_time=0;
|
||||
additional_clear_function=0;
|
||||
}
|
||||
~conv_manager_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
int get_size()
|
||||
{
|
||||
return conv_to_data.size();
|
||||
}
|
||||
void reserve()
|
||||
{
|
||||
data_to_conv.reserve(10007);
|
||||
conv_to_data.reserve(10007);
|
||||
//conv_last_active_time.reserve(10007);
|
||||
|
||||
lru.mp.reserve(10007);
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
if(disable_conv_clear) return ;
|
||||
|
||||
if(additional_clear_function!=0)
|
||||
{
|
||||
for(auto it=conv_to_data.begin();it!=conv_to_data.end();it++)
|
||||
{
|
||||
//int fd=int((it->second<<32u)>>32u);
|
||||
additional_clear_function( it->second);
|
||||
}
|
||||
}
|
||||
data_to_conv.clear();
|
||||
conv_to_data.clear();
|
||||
|
||||
lru.clear();
|
||||
//conv_last_active_time.clear();
|
||||
|
||||
//clear_it=conv_last_active_time.begin();
|
||||
|
||||
}
|
||||
u32_t get_new_conv()
|
||||
{
|
||||
u32_t conv=get_fake_random_number_nz();
|
||||
while(conv_to_data.find(conv)!=conv_to_data.end())
|
||||
{
|
||||
conv=get_fake_random_number_nz();
|
||||
}
|
||||
return conv;
|
||||
}
|
||||
int is_conv_used(u32_t conv)
|
||||
{
|
||||
return conv_to_data.find(conv)!=conv_to_data.end();
|
||||
}
|
||||
int is_data_used(T data)
|
||||
{
|
||||
return data_to_conv.find(data)!=data_to_conv.end();
|
||||
}
|
||||
u32_t find_conv_by_data(T data)
|
||||
{
|
||||
return data_to_conv[data];
|
||||
}
|
||||
T find_data_by_conv(u32_t conv)
|
||||
{
|
||||
return conv_to_data[conv];
|
||||
}
|
||||
int update_active_time(u32_t conv)
|
||||
{
|
||||
//return conv_last_active_time[conv]=get_current_time();
|
||||
lru.update(conv);
|
||||
return 0;
|
||||
}
|
||||
int insert_conv(u32_t conv,T data)
|
||||
{
|
||||
data_to_conv[data]=conv;
|
||||
conv_to_data[conv]=data;
|
||||
//conv_last_active_time[conv]=get_current_time();
|
||||
lru.new_key(conv);
|
||||
return 0;
|
||||
}
|
||||
int erase_conv(u32_t conv)
|
||||
{
|
||||
if(disable_conv_clear) return 0;
|
||||
T data=conv_to_data[conv];
|
||||
if(additional_clear_function!=0)
|
||||
{
|
||||
additional_clear_function(data);
|
||||
}
|
||||
conv_to_data.erase(conv);
|
||||
data_to_conv.erase(data);
|
||||
//conv_last_active_time.erase(conv);
|
||||
lru.erase(conv);
|
||||
return 0;
|
||||
}
|
||||
int clear_inactive(char * info=0)
|
||||
{
|
||||
if(get_current_time()-last_clear_time>conv_clear_interval)
|
||||
{
|
||||
last_clear_time=get_current_time();
|
||||
return clear_inactive0(info);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int clear_inactive0(char * info)
|
||||
{
|
||||
if(disable_conv_clear) return 0;
|
||||
|
||||
|
||||
unordered_map<u32_t,u64_t>::iterator it;
|
||||
unordered_map<u32_t,u64_t>::iterator old_it;
|
||||
|
||||
//map<uint32_t,uint64_t>::iterator it;
|
||||
int cnt=0;
|
||||
//it=clear_it;
|
||||
int size=lru.size();
|
||||
int num_to_clean=size/conv_clear_ratio+conv_clear_min; //clear 1/10 each time,to avoid latency glitch
|
||||
|
||||
num_to_clean=min(num_to_clean,size);
|
||||
|
||||
my_time_t current_time=get_current_time();
|
||||
for(;;)
|
||||
{
|
||||
if(cnt>=num_to_clean) break;
|
||||
if(lru.empty()) break;
|
||||
|
||||
u32_t conv;
|
||||
my_time_t ts=lru.peek_back(conv);
|
||||
|
||||
if(current_time- ts < conv_timeout) break;
|
||||
|
||||
erase_conv(conv);
|
||||
if(info==0)
|
||||
{
|
||||
mylog(log_info,"conv %x cleared\n",conv);
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog(log_info,"[%s]conv %x cleared\n",info,conv);
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
conv_manager_t();
|
||||
~conv_manager_t();
|
||||
int get_size();
|
||||
void reserve();
|
||||
void clear();
|
||||
u32_t get_new_conv();
|
||||
int is_conv_used(u32_t conv);
|
||||
int is_u64_used(T u64);
|
||||
u32_t find_conv_by_u64(T u64);
|
||||
T find_u64_by_conv(u32_t conv);
|
||||
int update_active_time(u32_t conv);
|
||||
int insert_conv(u32_t conv,T u64);
|
||||
int erase_conv(u32_t conv);
|
||||
int clear_inactive(char * ip_port=0);
|
||||
int clear_inactive0(char * ip_port);*/
|
||||
};//g_conv_manager;
|
||||
|
||||
|
||||
|
||||
struct inner_stat_t
|
||||
{
|
||||
u64_t input_packet_num;
|
||||
u64_t input_packet_size;
|
||||
u64_t output_packet_num;
|
||||
u64_t output_packet_size;
|
||||
};
|
||||
struct stat_t
|
||||
{
|
||||
u64_t last_report_time;
|
||||
inner_stat_t normal_to_fec;
|
||||
inner_stat_t fec_to_normal;
|
||||
stat_t()
|
||||
{
|
||||
memset(this,0,sizeof(stat_t));
|
||||
}
|
||||
void report_as_client()
|
||||
{
|
||||
if(report_interval!=0 &&get_current_time()-last_report_time>u64_t(report_interval)*1000)
|
||||
{
|
||||
last_report_time=get_current_time();
|
||||
inner_stat_t &a=normal_to_fec;
|
||||
inner_stat_t &b=fec_to_normal;
|
||||
mylog(log_info,"[report]client-->server:(original:%llu pkt;%llu byte) (fec:%llu pkt,%llu byte) server-->client:(original:%llu pkt;%llu byte) (fec:%llu pkt;%llu byte)\n",
|
||||
a.input_packet_num,a.input_packet_size,a.output_packet_num,a.output_packet_size,
|
||||
b.output_packet_num,b.output_packet_size,b.input_packet_num,b.input_packet_size
|
||||
);
|
||||
}
|
||||
}
|
||||
void report_as_server(address_t &addr)
|
||||
{
|
||||
if(report_interval!=0 &&get_current_time()-last_report_time>u64_t(report_interval)*1000)
|
||||
{
|
||||
last_report_time=get_current_time();
|
||||
inner_stat_t &a=fec_to_normal;
|
||||
inner_stat_t &b=normal_to_fec;
|
||||
mylog(log_info,"[report][%s]client-->server:(original:%llu pkt;%llu byte) (fec:%llu pkt;%llu byte) server-->client:(original:%llu pkt;%llu byte) (fec:%llu pkt;%llu byte)\n",
|
||||
addr.get_str(),
|
||||
a.output_packet_num,a.output_packet_size,a.input_packet_num,a.input_packet_size,
|
||||
b.input_packet_num,b.input_packet_size,b.output_packet_num,b.output_packet_size
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct conn_info_t:not_copy_able_t //stores info for a raw connection.for client ,there is only one connection,for server there can be thousand of connection since server can
|
||||
//handle multiple clients
|
||||
{
|
||||
union tmp_union_t
|
||||
{
|
||||
conv_manager_t<address_t> c;
|
||||
conv_manager_t<u64_t> s;
|
||||
//avoid templates here and there, avoid pointer and type cast
|
||||
tmp_union_t()
|
||||
{
|
||||
if(program_mode==client_mode)
|
||||
{
|
||||
new( &c ) conv_manager_t<address_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(program_mode==server_mode);
|
||||
new( &s ) conv_manager_t<u64_t>();
|
||||
}
|
||||
}
|
||||
~tmp_union_t()
|
||||
{
|
||||
if(program_mode==client_mode)
|
||||
{
|
||||
c.~conv_manager_t<address_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(program_mode==server_mode);
|
||||
s.~conv_manager_t<u64_t>();
|
||||
}
|
||||
}
|
||||
}conv_manager;
|
||||
|
||||
|
||||
fec_encode_manager_t fec_encode_manager;
|
||||
fec_decode_manager_t fec_decode_manager;
|
||||
ev_timer timer;
|
||||
//my_timer_t timer;
|
||||
|
||||
u64_t last_active_time;
|
||||
stat_t stat;
|
||||
|
||||
struct ev_loop* loop=0;
|
||||
int local_listen_fd;
|
||||
|
||||
int remote_fd; //only used for client
|
||||
fd64_t remote_fd64;//only used for client
|
||||
|
||||
//ip_port_t ip_port;
|
||||
address_t addr;//only used for server
|
||||
|
||||
conn_info_t()
|
||||
{
|
||||
if(program_mode==server_mode)
|
||||
{
|
||||
conv_manager.s.additional_clear_function=server_clear_function;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(program_mode==client_mode);
|
||||
}
|
||||
}
|
||||
|
||||
~conn_info_t()
|
||||
{
|
||||
if(loop)
|
||||
ev_timer_stop(loop,&timer);
|
||||
}
|
||||
void update_active_time()
|
||||
{
|
||||
last_active_time=get_current_time();
|
||||
}
|
||||
/*
|
||||
conn_info_t(const conn_info_t &b)
|
||||
{
|
||||
assert(0==1);
|
||||
}*/
|
||||
};
|
||||
/*
|
||||
struct conn_manager_t //manager for connections. for client,we dont need conn_manager since there is only one connection.for server we use one conn_manager for all connections
|
||||
{
|
||||
|
||||
unordered_map<u64_t,conn_info_t*> mp;//<ip,port> to conn_info_t;
|
||||
unordered_map<u64_t,conn_info_t*>::iterator clear_it;
|
||||
long long last_clear_time;
|
||||
|
||||
conn_manager_t();
|
||||
conn_manager_t(const conn_info_t &b)
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
int exist(ip_port_t);
|
||||
conn_info_t *& find_p(ip_port_t); //be aware,the adress may change after rehash
|
||||
conn_info_t & find(ip_port_t) ; //be aware,the adress may change after rehash
|
||||
int insert(ip_port_t);
|
||||
|
||||
int erase(unordered_map<u64_t,conn_info_t*>::iterator erase_it);
|
||||
int clear_inactive();
|
||||
int clear_inactive0();
|
||||
|
||||
};*/
|
||||
|
||||
struct conn_manager_t //manager for connections. for client,we dont need conn_manager since there is only one connection.for server we use one conn_manager for all connections
|
||||
{
|
||||
|
||||
|
||||
unordered_map<address_t,conn_info_t*> mp; //put it at end so that it de-consturcts first
|
||||
unordered_map<address_t,conn_info_t*>::iterator clear_it;
|
||||
|
||||
long long last_clear_time;
|
||||
|
||||
conn_manager_t();
|
||||
int exist(address_t addr);
|
||||
conn_info_t *& find_insert_p(address_t addr); //be aware,the adress may change after rehash //not true?
|
||||
conn_info_t & find_insert(address_t addr) ; //be aware,the adress may change after rehash
|
||||
|
||||
int erase(unordered_map<address_t,conn_info_t*>::iterator erase_it);
|
||||
int clear_inactive();
|
||||
int clear_inactive0();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
extern conn_manager_t conn_manager;
|
||||
|
||||
|
||||
#endif /* CONNECTION_H_ */
|
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* delay_manager.cpp
|
||||
*
|
||||
* Created on: Sep 15, 2017
|
||||
* Author: root
|
||||
*/
|
||||
#include "delay_manager.h"
|
||||
#include "log.h"
|
||||
#include "packet.h"
|
||||
|
||||
int delay_data_t::handle()
|
||||
{
|
||||
return my_send(dest,data,len)>=0;
|
||||
}
|
||||
|
||||
|
||||
delay_manager_t::delay_manager_t()
|
||||
{
|
||||
capacity=0;
|
||||
|
||||
//if ((timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) < 0)
|
||||
//{
|
||||
// mylog(log_fatal,"timer_fd create error");
|
||||
// myexit(1);
|
||||
//}
|
||||
|
||||
//itimerspec zero_its;
|
||||
//memset(&zero_its, 0, sizeof(zero_its));
|
||||
|
||||
//timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &zero_its, 0);
|
||||
|
||||
}
|
||||
delay_manager_t::~delay_manager_t()
|
||||
{
|
||||
//TODO ,we currently dont need to deconstruct it
|
||||
}
|
||||
|
||||
/*
|
||||
int delay_manager_t::get_timer_fd()
|
||||
{
|
||||
return timer_fd;
|
||||
}*/
|
||||
|
||||
//int add(my_time_t delay,const dest_t &dest,const char *data,int len);
|
||||
int delay_manager_t::add(my_time_t delay,const dest_t &dest,char *data,int len)
|
||||
{
|
||||
delay_data_t delay_data;
|
||||
delay_data.dest=dest;
|
||||
//delay_data.data=data;
|
||||
delay_data.len=len;
|
||||
|
||||
if(capacity!=0&&int(delay_mp.size()) >=capacity)
|
||||
{
|
||||
mylog(log_warn,"max pending packet reached,ignored\n");
|
||||
return -1;
|
||||
}
|
||||
if(delay==0)
|
||||
{
|
||||
static char buf[buf_len];
|
||||
delay_data.data=buf;
|
||||
memcpy(buf,data,len);
|
||||
int ret=delay_data.handle();
|
||||
if (ret != 0) {
|
||||
mylog(log_trace, "handle() return %d\n", ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay_data_t tmp=delay_data;
|
||||
tmp.data=(char *)malloc(delay_data.len+100);
|
||||
if(!tmp.data)
|
||||
{
|
||||
mylog(log_warn, "malloc() returned null in delay_manager_t::add()");
|
||||
return -1;
|
||||
}
|
||||
memcpy(tmp.data,data,delay_data.len);
|
||||
|
||||
my_time_t tmp_time=get_current_time_us();
|
||||
tmp_time+=delay;
|
||||
|
||||
delay_mp.insert(make_pair(tmp_time,tmp));
|
||||
|
||||
////check(); check everytime when add, is it better ??
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int delay_manager_t::check()
|
||||
{
|
||||
if(!delay_mp.empty())
|
||||
{
|
||||
my_time_t current_time;
|
||||
|
||||
multimap<my_time_t,delay_data_t>::iterator it;
|
||||
while(1)
|
||||
{
|
||||
int ret=0;
|
||||
it=delay_mp.begin();
|
||||
if(it==delay_mp.end()) break;
|
||||
|
||||
current_time=get_current_time_us();
|
||||
if(it->first <= current_time)
|
||||
{
|
||||
ret=it->second.handle();
|
||||
if (ret != 0) {
|
||||
mylog(log_trace, "handle() return %d\n", ret);
|
||||
}
|
||||
free(it->second.data);
|
||||
delay_mp.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if(!delay_mp.empty())
|
||||
{
|
||||
const double m=1000*1000;
|
||||
double timer_value=delay_mp.begin()->first/m -get_current_time_us()/m; // be aware of negative value, and be aware of uint
|
||||
if(timer_value<0) timer_value=0; // set it to 0 if negative, although libev support negative value
|
||||
ev_timer_stop(loop, &timer);
|
||||
ev_timer_set(&timer, timer_value,0 );
|
||||
ev_timer_start(loop, &timer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ev_timer_stop(loop, &timer); //not necessary
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
143
delay_manager.h
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* delay_manager.h
|
||||
*
|
||||
* Created on: Sep 15, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef DELAY_MANAGER_H_
|
||||
#define DELAY_MANAGER_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
#include "log.h"
|
||||
|
||||
//enum delay_type_t {none=0,enum_sendto_u64,enum_send_fd,client_to_local,client_to_remote,server_to_local,server_to_remote};
|
||||
|
||||
/*
|
||||
struct fd_ip_port_t
|
||||
{
|
||||
int fd;
|
||||
u32_t ip;
|
||||
u32_t port;
|
||||
};
|
||||
union dest_t
|
||||
{
|
||||
fd_ip_port_t fd_ip_port;
|
||||
int fd;
|
||||
u64_t u64;
|
||||
};
|
||||
*/
|
||||
/*
|
||||
struct my_timer_t
|
||||
{
|
||||
int timer_fd;
|
||||
fd64_t timer_fd64;
|
||||
my_timer_t()
|
||||
{
|
||||
if ((timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) < 0)
|
||||
{
|
||||
mylog(log_fatal,"timer_fd create error");
|
||||
myexit(1);
|
||||
}
|
||||
timer_fd64=fd_manager.create(timer_fd);
|
||||
}
|
||||
my_timer_t(const my_timer_t &b)
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
~my_timer_t()
|
||||
{
|
||||
fd_manager.fd64_close(timer_fd64);
|
||||
}
|
||||
int add_fd_to_epoll(int epoll_fd)
|
||||
{
|
||||
epoll_event ev;;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.u64 = timer_fd;
|
||||
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &ev);
|
||||
if (ret!= 0) {
|
||||
mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
|
||||
myexit(-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int add_fd64_to_epoll(int epoll_fd)
|
||||
{
|
||||
epoll_event ev;;
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.u64 = timer_fd64;
|
||||
int ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &ev);
|
||||
if (ret!= 0) {
|
||||
mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
|
||||
myexit(-1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int get_timer_fd()
|
||||
{
|
||||
return timer_fd;
|
||||
}
|
||||
fd64_t get_timer_fd64()
|
||||
{
|
||||
return timer_fd64;
|
||||
}
|
||||
int set_timer_repeat_us(my_time_t my_time)
|
||||
{
|
||||
itimerspec its;
|
||||
memset(&its,0,sizeof(its));
|
||||
its.it_interval.tv_sec=my_time/1000000llu;
|
||||
its.it_interval.tv_nsec=my_time%1000000llu*1000llu;
|
||||
its.it_value.tv_nsec=1; //imidiately
|
||||
timerfd_settime(timer_fd,0,&its,0);
|
||||
return 0;
|
||||
}
|
||||
int set_timer_abs_us(my_time_t my_time)
|
||||
{
|
||||
itimerspec its;
|
||||
memset(&its,0,sizeof(its));
|
||||
its.it_value.tv_sec=my_time/1000000llu;
|
||||
its.it_value.tv_nsec=my_time%1000000llu*1000llu;
|
||||
timerfd_settime(timer_fd,TFD_TIMER_ABSTIME,&its,0);
|
||||
return 0;
|
||||
}
|
||||
};*/
|
||||
|
||||
|
||||
struct delay_data_t
|
||||
{
|
||||
dest_t dest;
|
||||
//int left_time;//
|
||||
char * data;
|
||||
int len;
|
||||
int handle();
|
||||
};
|
||||
|
||||
struct delay_manager_t
|
||||
{
|
||||
ev_timer timer;
|
||||
struct ev_loop *loop=0;
|
||||
void (*cb) (struct ev_loop *loop, struct ev_timer *watcher, int revents)=0;
|
||||
|
||||
//int timer_fd;
|
||||
int capacity;
|
||||
multimap<my_time_t,delay_data_t> delay_mp; //unit us,1 us=0.001ms
|
||||
delay_manager_t();
|
||||
delay_manager_t(delay_manager_t &b)
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
void set_loop_and_cb(struct ev_loop *loop,void (*cb) (struct ev_loop *loop, struct ev_timer *watcher, int revents))
|
||||
{
|
||||
this->loop=loop;
|
||||
this->cb=cb;
|
||||
ev_init(&timer,cb);
|
||||
}
|
||||
int set_capacity(int a){capacity=a;return 0;}
|
||||
~delay_manager_t();
|
||||
ev_timer& get_timer();
|
||||
int check();
|
||||
int add(my_time_t delay,const dest_t &dest,char *data,int len);
|
||||
};
|
||||
|
||||
#endif /* DELAY_MANAGER_H_ */
|
@@ -1,230 +0,0 @@
|
||||
# UDPspeeder
|
||||

|
||||
|
||||
双边网络加速工具,软件本身的功能是加速UDP;不过,配合vpn可以加速全流量(包括TCP/UDP/ICMP)。通过合理配置,可以加速游戏,降低游戏的丢包和延迟;也可以加速下载和看视频这种大流量的应用。用1.5倍的流量,就可以把10%的丢包率降低到万分之一以下。跟 kcptun/finalspeed/BBR 等现有方案比,主要优势是可以加速 UDP 和 ICMP,现有方案几乎都只能加速 TCP。
|
||||
|
||||
我自己稳定用了几个月,用来加速美服的Brawl Stars和亚服的Mobile Legend,效果不错,加速前卡得几乎没法玩,加速后就没怎么卡过了。用来看视频也基本满速。
|
||||
|
||||
最新的版本是v2版,在v1版的基础上增加了FEC功能,更省流量。如果你用的是v1版(路由器固件里自带的集成版很可能是v1版的),请看[v1版主页](/doc/README.zh-cn.v1.md)
|
||||
|
||||
配合vpn加速全流量的原理图(已测试支持VPN的有OpenVPN、L2TP、$\*\*\*VPN):
|
||||
|
||||

|
||||
|
||||
[English](/README.md)
|
||||
|
||||
[UDPspeeder Wiki](https://github.com/wangyu-/UDPspeeder/wiki)
|
||||
|
||||
##### 提示
|
||||
|
||||
如果你嫌UDPspeeder+OpenVPN麻烦,你可以尝试tinyfecVPN,一个集成了UDPspeeder功能的VPN:
|
||||
|
||||
tinyfecVPN的repo:
|
||||
|
||||
https://github.com/wangyu-/tinyfecVPN
|
||||
|
||||
|
||||
#### 效果
|
||||

|
||||
|
||||

|
||||
|
||||
|
||||
#### 原理简介
|
||||
主要原理是通过冗余数据来对抗网络的丢包,发送冗余数据的方式支持FEC(Forward Error Correction)和多倍发包,其中FEC算法是Reed-Solomon。
|
||||
|
||||
FEC方式的原理图:
|
||||
|
||||

|
||||
|
||||
#### 其他功能
|
||||
对包的内容和长度做随机化(可以理解为混淆),从抓包看不出你发送了冗余数据,不用担心vps被封。
|
||||
|
||||
在多个冗余包之间引入延迟(时间可配)来对抗突发性的丢包,避开中间路由器因为瞬时buffer长度过长而连续丢掉所有副本。
|
||||
|
||||
模拟一定的延迟抖动(时间可配),这样上层应用计算出来的RTT方差会更大,以等待后续冗余包的到达,不至于发生在冗余包到达之前就触发重传的尴尬。
|
||||
|
||||
输出UDP收发情况报告,可以看出丢包率。
|
||||
|
||||
模拟丢包,模拟延迟,模拟jitter。便于通过实验找出应用卡顿的原因。
|
||||
|
||||
client支持多个udp连接,server也支持多个client
|
||||
|
||||
#### 关键词
|
||||
|
||||
UDP加速器、双边UDP加速、全流量加速、开源加速器、游戏加速、网游加速器
|
||||
|
||||
# 简明操作说明
|
||||
|
||||
### 环境要求
|
||||
Linux主机,可以是桌面版,可以是android手机/平板,可以是openwrt路由器,也可以是树莓派。Release中提供了`amd64`、`x86`、`arm`、`mips_be`、`mips_le`的预编译binary.
|
||||
|
||||
对于windows和mac用户,在虚拟机中可以稳定使用(speeder跑在Linux里,其他应用照常跑在window里,桥接模式测试可用)。可以使用[这个](https://github.com/wangyu-/udp2raw-tunnel/releases/download/20171108.0/lede-17.01.2-x86_virtual_machine_image.zip)虚拟机镜像,大小只有7.5mb,免去在虚拟机里装系统的麻烦;虚拟机自带ssh server,可以scp拷贝文件,可以ssh进去,可以复制粘贴,root密码123456。
|
||||
|
||||
android版需要通过terminal运行。
|
||||
|
||||
##### 注意
|
||||
在使用虚拟机时,建议手动指定桥接到哪个网卡,不要设置成自动。否则可能会桥接到错误的网卡。
|
||||
|
||||
### 安装
|
||||
下载编译好的二进制文件,解压到本地和服务器的任意目录。
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/releases
|
||||
|
||||
### 运行
|
||||
假设你有一个server,ip为44.55.66.77,有一个服务监听在udp 7777端口。 假设你需要加速本地到44.55.66.77:7777的流量。
|
||||
```
|
||||
在server端运行:
|
||||
./speederv2 -s -l0.0.0.0:4096 -r127.0.0.1:7777 -f20:10 -k "passwd" --mode 0
|
||||
|
||||
在client端运行:
|
||||
./speederv2 -c -l0.0.0.0:3333 -r44.55.66.77:4096 -f20:10 -k "passwd" --mode 0
|
||||
```
|
||||
|
||||
现在client和server之间建立起了tunnel。想要连接44.55.66.77:7777,只需要连接 127.0.0.1:3333。来回的所有的udp流量会被加速。
|
||||
|
||||
##### 备注
|
||||
|
||||
`-f20:10`表示对每20个原始数据发送10个冗余包。`-f20:10` 和`-f 20:10`都是可以的,空格可以省略,对于所有的单字节option都是如此。对于双字节option,例如后面会提到的`--mode 0`,空格不可以省略。
|
||||
|
||||
`-k` 指定一个字符串,开启简单的异或加密
|
||||
|
||||
推荐使用`--mode 0`选项,否则你可能需要考虑MTU问题。
|
||||
|
||||
这里推荐的参数是给日常/非游戏情况下使用的;玩游戏请用 [使用经验](https://github.com/wangyu-/UDPspeeder/wiki/使用经验) 里推荐的参数。
|
||||
|
||||
##### 提示
|
||||
|
||||
对于某些运营商,UDPspeeder跟udp2raw配合可以达到更好的速度,udp2raw负责把UDP伪装成TCP,来绕过运营商的UDP限速。
|
||||
|
||||
udp2raw的repo:
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel
|
||||
|
||||
# 进阶操作说明
|
||||
|
||||
### 命令选项
|
||||
```
|
||||
UDPspeeder V2
|
||||
git version: 3e248b414c build date: Aug 5 2018 21:59:52
|
||||
repository: https://github.com/wangyu-/UDPspeeder
|
||||
|
||||
usage:
|
||||
run as client: ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]
|
||||
run as server: ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]
|
||||
|
||||
common options, must be same on both sides:
|
||||
-k,--key <string> key for simple xor encryption. if not set, xor is disabled
|
||||
main options:
|
||||
-f,--fec x:y forward error correction, send y redundant packets for every x packets
|
||||
--timeout <number> how long could a packet be held in queue before doing fec, unit: ms, default: 8ms
|
||||
--report <number> turn on send/recv report, and set a period for reporting, unit: s
|
||||
advanced options:
|
||||
--mode <number> fec-mode,available values: 0,1; mode 0(default) costs less bandwidth,no mtu problem.
|
||||
mode 1 usually introduces less latency, but you have to care about mtu.
|
||||
--mtu <number> mtu. for mode 0, the program will split packet to segment smaller than mtu value.
|
||||
for mode 1, no packet will be split, the program just check if the mtu is exceed.
|
||||
default value: 1250. you typically shouldnt change this value.
|
||||
-q,--queue-len <number> fec queue len, only for mode 0, fec will be performed immediately after queue is full.
|
||||
default value: 200.
|
||||
-j,--jitter <number> simulated jitter. randomly delay first packet for 0~<number> ms, default value: 0.
|
||||
do not use if you dont know what it means.
|
||||
-i,--interval <number> scatter each fec group to a interval of <number> ms, to protect burst packet loss.
|
||||
default value: 0. do not use if you dont know what it means.
|
||||
-f,--fec x1:y1,x2:y2,.. similiar to -f/--fec above,fine-grained fec parameters,may help save bandwidth.
|
||||
example: "-f 1:3,2:4,10:6,20:10". check repo for details
|
||||
--random-drop <number> simulate packet loss, unit: 0.01%. default value: 0.
|
||||
--disable-obscure <number> disable obscure, to save a bit bandwidth and cpu.
|
||||
developer options:
|
||||
--fifo <string> use a fifo(named pipe) for sending commands to the running program, so that you
|
||||
can change fec encode parameters dynamically, check readme.md in repository for
|
||||
supported commands.
|
||||
-j ,--jitter jmin:jmax similiar to -j above, but create jitter randomly between jmin and jmax
|
||||
-i,--interval imin:imax similiar to -i above, but scatter randomly between imin and imax
|
||||
--decode-buf <number> size of buffer of fec decoder,u nit: packet, default: 2000
|
||||
--fix-latency <number> try to stabilize latency, only for mode 0
|
||||
--delay-capacity <number> max number of delayed packets
|
||||
--disable-fec <number> completely disable fec, turn the program into a normal udp tunnel
|
||||
--sock-buf <number> buf size for socket, >=10 and <=10240, unit: kbyte, default: 1024
|
||||
log and help options:
|
||||
--log-level <number> 0: never 1: fatal 2: error 3: warn
|
||||
4: info (default) 5: debug 6: trace
|
||||
--log-position enable file name, function name, line number in log
|
||||
--disable-color disable log color
|
||||
-h,--help print this help message
|
||||
|
||||
```
|
||||
### 包发送选项,两端设置可以不同。 只影响本地包发送。
|
||||
##### `-f` 选项
|
||||
设置fec参数,影响数据的冗余度。
|
||||
##### `--timeout` 选项
|
||||
指定fec编码器在编码时候最多可以引入多大的延迟。越高fec越有效率,调低可以降低延迟,但是会牺牲效率。
|
||||
##### `--mode` 选项 和 `--mtu`选项
|
||||
|
||||
简单来说`--mode 0`更省流量,没有mtu问题;`--mode 1`可以稍微降低一点延迟,需要考虑mtu;另外还有个`--mode 0 -q1`模式,多倍发包专用,没有延迟,也没有mtu问题,适合游戏,但是最耗流量。
|
||||
|
||||
具体见,https://github.com/wangyu-/UDPspeeder/wiki/mode和mtu选项
|
||||
|
||||
对于新手,建议不要纠结这些参数的具体含义,就用我在`使用经验`里推荐的设置,不要乱改参数,尤其是不要改`--mtu`。
|
||||
|
||||
##### `--report` 选项
|
||||
数据发送和接受报告。开启后可以根据此数据推测出包速和丢包率等特征。`--report 10`表示每10秒生成一次报告。
|
||||
|
||||
##### `-i` 选项
|
||||
指定一个时间窗口,长度为n毫秒。同一个fec分组的数据在发送时候会被均匀分散到这n毫秒中,可以对抗突发性的丢包,默认值是0(也就是不开启此功能)。 这个功能很有用,在推荐的参数效果不理想时可以尝试打开,比如用`-i 10`、`-i 20`。这个选项的跟通信原理上常说的`交错fec` `交织fec`的原理是差不多的。
|
||||
|
||||
##### `-j` 选项
|
||||
为原始数据的发送,增加一个延迟抖动值。这样上层应用计算出来的RTT方差会更大,以等待后续冗余包的到达,不至于发生在冗余包到达之前就触发重传的尴尬。配合-t选项使用。正常情况下跨国网络本身的延迟抖动就很大,可以不用设-j。这个功能也需要时钟,默认关掉了,不过一般情况应该不需要这个功能。
|
||||
|
||||
-j选项不但可以模拟延迟抖动,也可以模拟延迟。
|
||||
|
||||
##### `--random-drop` 选项
|
||||
随机丢包。模拟高丢包的网络环境时使用。 `--random-drop`和`-j`选项一起用,可以模拟高延迟(或者高延迟抖动)高丢包的网络,可用于测试FEC参数在各种网络环境下的表现。
|
||||
|
||||
##### `-q` 选项
|
||||
仅对mode 0模式有用。设置fec编码器的最大队列长度。 比如`-q5`的意思是,在编码器积攒了5个数据包后,就立即发送。合理使用可以改善延迟。在下文的`使用经验`里有提到用`--mode 0 -q1` 来多倍发包。
|
||||
|
||||
`-q`和 `--timeout`的作用类似。`-q`决定fec编码器积攒了多少个数据包之后,立即发送。`--timeout`决定编码器收到第一个数据包以后,最多延迟多少毫秒后发送。
|
||||
|
||||
默认值是200,也就是尽可能多得积攒数据。
|
||||
|
||||
建议不要自己调整这个参数,除非是用我在`使用经验`里推荐给你的形式。
|
||||
|
||||
#### `--fifo` option
|
||||
用fifo(命名管道)向运行中的程序发送command。例如`--fifo fifo.file`,可用的command有:
|
||||
```
|
||||
echo fec 19:9 > fifo.file
|
||||
echo mtu 1100 > fifo.file
|
||||
echo timeout 5 > fifo.file
|
||||
echo queue-len 100 > fifo.file
|
||||
echo mode 0 > fifo.file
|
||||
```
|
||||
可以动态改变fec编码器参数。可以从程序的log里看到command是否发送成功。
|
||||
|
||||
### 以下设置两端必须相同。
|
||||
|
||||
##### `-k`选项
|
||||
指定一个字符串,server/client间所有收发的包都会被异或,改变协议特征,防止UDPspeeder的协议被运营商针对。
|
||||
|
||||
##### `--disable-obscure`
|
||||
UDPspeeder默认情况下会对每个发出的数据包随机填充和异或一些字节(4~32字节),这样通过抓包难以发现你发了冗余数据,防止VPS被封。这个功能只是为了小心谨慎,即使你关掉这个功能,基本上也没问题,关掉可以省一些带宽和CPU。`--disable-obscure`可以关掉这个功能。
|
||||
|
||||
# 推荐参数
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/wiki/推荐设置
|
||||
|
||||
# 使用经验
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/wiki/使用经验
|
||||
|
||||
# 编译教程
|
||||
暂时先参考udp2raw的这篇教程,几乎一样的过程。
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel/blob/master/doc/build_guide.zh-cn.md
|
||||
|
||||
# wiki
|
||||
|
||||
更多内容请看 wiki:
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/wiki
|
||||
|
@@ -1,154 +0,0 @@
|
||||
# UDPspeeder (v1)
|
||||

|
||||
UDP双边加速工具,降低丢包率,配合vpn可以加速任何协议,尤其适用于加速游戏和网页打开速度;同时也是一个UDP连接的调试和统计工具。
|
||||
|
||||
这个是我自己稳定用了一个月的项目,用来加速美服的Brawl Stars和亚服的Mobile Legend,效果不错。加速前卡得几乎没法玩,加速后就没怎么卡过了。
|
||||
|
||||
注:目前最新版是v2版,这个是v1版的主页
|
||||
|
||||
#### 效果
|
||||

|
||||
#### 原理简介
|
||||
目前原理是多倍发包。以后会做各种优化,比如:对高频率的短包先合并再冗余;FEC(Forward Error Correction),在包速低的时候多倍发包,包速高时用FEC(这些功能在v2版里已经实现)。
|
||||
|
||||
跟net-speeder比,优势在于client和server会把收到的多余包自动去掉,这个过程对上层透明,没有兼容性问题。而且发出的冗余数据包会做长度和内容的随机化,抓包是看不出发了冗余数据的,所以不用担心vps被封的问题。
|
||||
|
||||
每个冗余数据包都是间隔数毫秒(可配置)以后延迟发出的,可以避开中间路由器因为瞬时buffer长度过长而连续丢掉所有副本。
|
||||
|
||||
模拟一定的延迟抖动,这样上层应用计算出来的RTT方差会更大,以等待后续冗余包的到达,不至于发生在冗余包到达之前就触发重传的尴尬。
|
||||
|
||||
#### 适用场景
|
||||
绝大部分流量不高的情况。程序本身加速udp,但是配合openvpn可以加速任何流量。网络状况不好时,游戏卡得没法玩,或者网页卡得没法打开,使用起来效果最好。对于解决语音通话的断断续续效果也不错。不适合大流量的场景,比如BT下载和在线看视频。 无论从自己使用效果的角度,还是从国际出口带宽占用的角度,都建议不要在大流量环境使用。
|
||||
|
||||
#### 其他功能
|
||||
输出UDP收发情况报告,可以看出丢包率。
|
||||
|
||||
模拟丢包,模拟延迟,模拟jitter。便于通过实验找出应用卡顿的原因。
|
||||
|
||||
重复包过滤功能可以关掉,模拟网络本身有重复包的情况。用来测试应用对重复报的支持情况。
|
||||
|
||||
client支持多个udp连接,server也支持多个client
|
||||
|
||||
目前有amd64,x86,ar71xx,树莓派armv7和android的binary
|
||||
|
||||
如果你需要绕过UDP屏蔽/QoS,或者需要连接复用/连接保持功能,或者是加密。解决方案在另一个repo(可以跟UDPspeeder一起使用):
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel
|
||||
|
||||
# 简明操作说明
|
||||
|
||||
### 环境要求
|
||||
Linux主机,可以是桌面版,可以是android手机/平板,可以是openwrt路由器,也可以是树莓派。在windows和mac上配合虚拟机可以稳定使用(speeder跑在Linux里,其他应用照常跑在window里,桥接模式测试可用)。
|
||||
|
||||
android版需要通过terminal运行。
|
||||
|
||||
### 安装
|
||||
下载编译好的二进制文件,解压到本地和服务器的任意目录。
|
||||
|
||||
https://github.com/wangyu-/UDPspeeder/releases
|
||||
|
||||
### 运行
|
||||
假设你有一个server,ip为44.55.66.77,有一个服务监听在udp 7777端口。 假设你需要加速本地到44.55.66.77:7777的流量。
|
||||
```
|
||||
在client端运行:
|
||||
./speeder_ar71xx -l0.0.0.0:3333 -r 44.55.66.77:8855 -c -d2 -k "passwd"
|
||||
|
||||
在server端运行:
|
||||
./speeder_amd64 -l0.0.0.0:8855 -r127.0.0.1:7777 -s -d2 -k "passwd"
|
||||
```
|
||||
|
||||
现在client和server之间建立起了tunnel。想要连接44.55.66.77:7777,只需要连接 127.0.0.1:3333。来回的所有的udp流量会被加速。
|
||||
|
||||
###### 注:
|
||||
|
||||
-d2 表示除了本来的包以外,额外再发2个冗余包。可调。
|
||||
|
||||
-k 指定一个字符串,server/client间所有收发的包都会被异或,改变协议特征,防止UDPspeeder的协议被运营商针对。
|
||||
|
||||
# 进阶操作说明
|
||||
|
||||
### 命令选项
|
||||
```
|
||||
UDPspeeder
|
||||
git version:b4bd385e88 build date:Sep 11 2017 10:29:25
|
||||
repository: https://github.com/wangyu-/UDPspeeder
|
||||
|
||||
usage:
|
||||
run as client : ./this_program -c -l local_listen_ip:local_port -r server_ip:server_port [options]
|
||||
run as server : ./this_program -s -l server_listen_ip:server_port -r remote_ip:remote_port [options]
|
||||
|
||||
common option,must be same on both sides:
|
||||
-k,--key <string> key for simple xor encryption,default:"secret key"
|
||||
main options:
|
||||
-d <number> duplicated packet number, -d 0 means no duplicate. default value:0
|
||||
-t <number> duplicated packet delay time, unit: 0.1ms,default value:20(2ms)
|
||||
-j <number> simulated jitter.randomly delay first packet for 0~jitter_value*0.1 ms,to
|
||||
create simulated jitter.default value:0.do not use if you dont
|
||||
know what it means
|
||||
--report <number> turn on udp send/recv report,and set a time interval for reporting,unit:s
|
||||
advanced options:
|
||||
-t tmin:tmax simliar to -t above,but delay randomly between tmin and tmax
|
||||
-j jmin:jmax simliar to -j above,but create jitter randomly between jmin and jmax
|
||||
--random-drop <number> simulate packet loss ,unit:0.01%
|
||||
--disable-filter disable duplicate packet filter.
|
||||
-m <number> max pending packets,to prevent the program from eating up all your memory,
|
||||
default value:0(disabled).
|
||||
other options:
|
||||
--log-level <number> 0:never 1:fatal 2:error 3:warn
|
||||
4:info (default) 5:debug 6:trace
|
||||
--log-position enable file name,function name,line number in log
|
||||
--disable-color disable log color
|
||||
--sock-buf <number> buf size for socket,>=10 and <=10240,unit:kbyte,default:1024
|
||||
-h,--help print this help message
|
||||
|
||||
```
|
||||
### 包发送选项,两端设置可以不同。 只影响本地包发送。
|
||||
##### -d 选项
|
||||
设置冗余包数量。
|
||||
##### -t 选项
|
||||
为冗余包的发送,增加一个延迟.对中间路由buffer做优化,应对瞬时Buffer过长导致的连续丢包.对于多个冗余包,依次在前一个包的基础上增加这个延迟。
|
||||
##### -j 选项
|
||||
为原始数据的发送,增加一个延迟抖动值。这样上层应用计算出来的RTT方差会更大,以等待后续冗余包的到达,不至于发生在冗余包到达之前就触发重传的尴尬。配合-t选项使用。正常情况下跨国网络本身的延迟抖动就很大。可以不用设-j
|
||||
|
||||
##### --report 选项
|
||||
数据发送和接受报告。开启后可以根据此数据推测出包速和丢包率等特征。
|
||||
|
||||
##### 加强版 -t 选项
|
||||
跟普通-t类似,允许设置最大值最小值,用随机延迟发送冗余包。
|
||||
|
||||
##### 加强版 -j 选项
|
||||
允许给jitter选项设置最大值最小值。在这个区间随机化jitter。如果最大值最小值一样就是模拟延迟。可以模拟高延迟、高jitter的网络环境。
|
||||
|
||||
##### --random-drop 选项
|
||||
随机丢包。模拟恶劣的网络环境时使用。
|
||||
|
||||
### 包接收选项,两端设置可以不同。只影响本地包接受
|
||||
##### --disable-filter
|
||||
关闭重复包过滤器。这样配合-d 选项可以模拟有重复包的网络环境。
|
||||
|
||||
# 应用
|
||||
|
||||
#### UDPspeeder + openvpn加速任何流量
|
||||
如果你只是需要玩游戏,效果预期会kcp/finalspeed方案更好。可以优化tcp游戏的延迟(通过冗余发包,避免了上层的重传)。比如魔兽世界用的是tcp连接。
|
||||

|
||||
|
||||
跟openvpn via kcptun方式的对比:
|
||||
|
||||
kcptun在udp层有RS code,也是一种冗余传输,通过openvpn把流量转成tcp,再通过kcptun加速是有一定效果的。但是tcp只支持按序到达。按序到达的意思是,如果你发了1 2 3 4 5 6,6个包,如果第一个包丢了,那么必须等第一个包重传成功以后 2 3 4 5 6 才能到达;只要有一个包不到,后续数据包就要一直等待。用tcp承载udp流量会破坏udp的实时性。会造成游戏卡顿更严重。
|
||||
|
||||
udp协议本身是ip协议加上了端口之后的直接封装,udp继承了ip协议的实时/乱序到达特性,更适合中转vpn。
|
||||
|
||||
#### UDPspeeder + kcptun/finalspeed + $*** 同时加速tcp和udp流量
|
||||
如果你需要用加速的tcp看视频和下载文件,这样效果比vpn方案更好。不论是速度,还是流量的耗费上。
|
||||

|
||||
|
||||
#### UDPspeeder + openvpn + $*** 混合方案
|
||||
也是我正在用的方案。优点是可以随时在vpn和$*** 方案间快速切换。
|
||||
实际部署起来比图中看起来的还要简单。不需要改路由表,需要做的只是用openvpn的ip访问$*** server。
|
||||
|
||||

|
||||
(也可以把图中的$*** server换成其他的socks5 server,这样连$*** client也不需要了)
|
||||
# 编译教程
|
||||
暂时先参考udp2raw的这篇教程,几乎一样的过程。
|
||||
|
||||
https://github.com/wangyu-/udp2raw-tunnel/blob/master/doc/build_guide.zh-cn.md
|
@@ -1,107 +0,0 @@
|
||||
|
||||
# UDPspeeder + openvpn config guide
|
||||

|
||||
|
||||
# UDPspeeder command
|
||||
|
||||
#### run at server side
|
||||
```
|
||||
./speederv2 -s -l0.0.0.0:8855 -r 127.0.0.1:7777 -f20:10
|
||||
```
|
||||
|
||||
#### run at client side
|
||||
assume server ip is 45.66.77.88
|
||||
```
|
||||
./speederv2 -c -l0.0.0.0:3333 -r 45.66.77.88:8855 -f20:10
|
||||
```
|
||||
|
||||
# openvpn config
|
||||
|
||||
#### client side config
|
||||
```
|
||||
client
|
||||
dev tun100
|
||||
proto udp
|
||||
|
||||
remote 127.0.0.1 3333
|
||||
resolv-retry infinite
|
||||
nobind
|
||||
persist-key
|
||||
persist-tun
|
||||
|
||||
ca /root/add-on/openvpn/ca.crt
|
||||
cert /root/add-on/openvpn/client.crt
|
||||
key /root/add-on/openvpn/client.key
|
||||
|
||||
keepalive 3 20
|
||||
verb 3
|
||||
mute 20
|
||||
|
||||
comp-lzo no
|
||||
|
||||
fragment 1200 ##### very important you can turn it up a bit. but, the lower the safer
|
||||
mssfix 1200 ##### very important
|
||||
|
||||
sndbuf 2000000 ##### important
|
||||
rcvbuf 2000000 ##### important
|
||||
txqueuelen 4000 ##### suggested
|
||||
```
|
||||
|
||||
|
||||
#### server side config
|
||||
```
|
||||
local 0.0.0.0
|
||||
port 7777
|
||||
proto udp
|
||||
dev tun
|
||||
|
||||
ca /etc/openvpn/easy-rsa/2.0/keys/ca.crt
|
||||
cert /etc/openvpn/easy-rsa/2.0/keys/server.crt
|
||||
key /etc/openvpn/easy-rsa/2.0/keys/server.key
|
||||
dh /etc/openvpn/easy-rsa/2.0/keys/dh1024.pem
|
||||
|
||||
server 10.222.2.0 255.255.255.0
|
||||
ifconfig 10.222.2.1 10.222.2.6
|
||||
|
||||
client-to-client
|
||||
duplicate-cn
|
||||
keepalive 10 60
|
||||
|
||||
max-clients 50
|
||||
|
||||
persist-key
|
||||
persist-tun
|
||||
|
||||
status /etc/openvpn/openvpn-status.log
|
||||
|
||||
verb 3
|
||||
mute 20
|
||||
|
||||
comp-lzo no
|
||||
|
||||
fragment 1200 ##### very important you can turn it up a bit. but, the lower the safer
|
||||
mssfix 1200 ##### very important
|
||||
|
||||
sndbuf 2000000 ##### important
|
||||
rcvbuf 2000000 ##### important
|
||||
txqueuelen 4000 ##### suggested
|
||||
```
|
||||
|
||||
##### Note:
|
||||
If you use the `redirect-gateway` option of OpenVPN, you may need to add a route exception for your remote server ip at client side.Otherwise OpenVPN may hijack UDPspeeder 's traffic.
|
||||
|
||||
For example, depend on your network environment, the command may looks like:
|
||||
```
|
||||
ip route add 44.55.66.77 via 44.55.66.1
|
||||
```
|
||||
or
|
||||
|
||||
```
|
||||
ip route add 44.55.66.77 dev XXX
|
||||
```
|
||||
(run at client side)
|
||||
|
||||
##### Other Info
|
||||
You can also use tinyFecVPN,a lightweight VPN with build-in FEC support:
|
||||
|
||||
https://github.com/wangyu-/tinyFecVPN
|
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* fd_manager.cpp
|
||||
*
|
||||
* Created on: Sep 25, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
|
||||
#include "fd_manager.h"
|
||||
int fd_manager_t::fd_exist(int fd)
|
||||
{
|
||||
return fd_to_fd64_mp.find(fd)!=fd_to_fd64_mp.end();
|
||||
}
|
||||
int fd_manager_t::exist(fd64_t fd64)
|
||||
{
|
||||
return fd64_to_fd_mp.find(fd64)!=fd64_to_fd_mp.end();
|
||||
}
|
||||
int fd_manager_t::to_fd(fd64_t fd64)
|
||||
{
|
||||
assert(exist(fd64));
|
||||
return fd64_to_fd_mp[fd64];
|
||||
}
|
||||
void fd_manager_t::fd64_close(fd64_t fd64)
|
||||
{
|
||||
assert(exist(fd64));
|
||||
int fd=fd64_to_fd_mp[fd64];
|
||||
fd64_to_fd_mp.erase(fd64);
|
||||
fd_to_fd64_mp.erase(fd);
|
||||
if(exist_info(fd64))
|
||||
{
|
||||
fd_info_mp.erase(fd64);
|
||||
}
|
||||
sock_close(fd);
|
||||
}
|
||||
void fd_manager_t::reserve(int n)
|
||||
{
|
||||
fd_to_fd64_mp.reserve(n);
|
||||
fd64_to_fd_mp.reserve(n);
|
||||
fd_info_mp.reserve(n);
|
||||
}
|
||||
u64_t fd_manager_t::create(int fd)
|
||||
{
|
||||
assert(!fd_exist(fd));
|
||||
fd64_t fd64=counter++;
|
||||
fd_to_fd64_mp[fd]=fd64;
|
||||
fd64_to_fd_mp[fd64]=fd;
|
||||
return fd64;
|
||||
}
|
||||
fd_manager_t::fd_manager_t()
|
||||
{
|
||||
counter=u32_t(-1);
|
||||
counter+=100;
|
||||
reserve(10007);
|
||||
}
|
||||
fd_info_t & fd_manager_t::get_info(fd64_t fd64)
|
||||
{
|
||||
assert(exist(fd64));
|
||||
return fd_info_mp[fd64];
|
||||
}
|
||||
int fd_manager_t::exist_info(fd64_t fd64)
|
||||
{
|
||||
return fd_info_mp.find(fd64)!=fd_info_mp.end();
|
||||
}
|
38
fd_manager.h
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* fd_manager.h
|
||||
*
|
||||
* Created on: Sep 25, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef FD_MANAGER_H_
|
||||
#define FD_MANAGER_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "packet.h"
|
||||
|
||||
|
||||
|
||||
struct fd_manager_t //conver fd to a uniq 64bit number,avoid fd value conflict caused by close and re-create
|
||||
//this class is not strictly necessary,it just makes epoll fd handling easier
|
||||
{
|
||||
fd_info_t & get_info(fd64_t fd64);
|
||||
int exist_info(fd64_t);
|
||||
int exist(fd64_t fd64);
|
||||
int to_fd(fd64_t);
|
||||
void fd64_close(fd64_t fd64);
|
||||
void reserve(int n);
|
||||
u64_t create(int fd);
|
||||
fd_manager_t();
|
||||
private:
|
||||
u64_t counter;
|
||||
unordered_map<int,fd64_t> fd_to_fd64_mp;
|
||||
unordered_map<fd64_t,int> fd64_to_fd_mp;
|
||||
unordered_map<fd64_t,fd_info_t> fd_info_mp;
|
||||
int fd_exist(int fd);
|
||||
//void remove_fd(int fd);
|
||||
//fd64_t fd_to_fd64(int fd);
|
||||
};
|
||||
|
||||
extern fd_manager_t fd_manager;
|
||||
#endif /* FD_MANAGER_H_ */
|
927
fec_manager.cpp
@@ -1,927 +0,0 @@
|
||||
/*
|
||||
* fec_manager.cpp
|
||||
*
|
||||
* Created on: Sep 27, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "fec_manager.h"
|
||||
#include "log.h"
|
||||
#include "common.h"
|
||||
#include "lib/rs.h"
|
||||
#include "fd_manager.h"
|
||||
|
||||
//int g_fec_data_num=20;
|
||||
//int g_fec_redundant_num=10;
|
||||
//int g_fec_mtu=1250;
|
||||
//int g_fec_queue_len=200;
|
||||
//int g_fec_timeout=8*1000; //8ms
|
||||
//int g_fec_mode=0;
|
||||
|
||||
fec_parameter_t g_fec_par;
|
||||
|
||||
int debug_fec_enc=0;
|
||||
int debug_fec_dec=0;
|
||||
//int dynamic_update_fec=1;
|
||||
|
||||
const int encode_fast_send=1;
|
||||
const int decode_fast_send=1;
|
||||
|
||||
int short_packet_optimize=1;
|
||||
int header_overhead=40;
|
||||
|
||||
u32_t fec_buff_num=2000;// how many packet can fec_decode_manager hold. shouldnt be very large,or it will cost huge memory
|
||||
|
||||
|
||||
blob_encode_t::blob_encode_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
int blob_encode_t::clear()
|
||||
{
|
||||
counter=0;
|
||||
current_len=(int)sizeof(u32_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blob_encode_t::get_num()
|
||||
{
|
||||
return counter;
|
||||
}
|
||||
int blob_encode_t::get_shard_len(int n)
|
||||
{
|
||||
return round_up_div(current_len,n);
|
||||
}
|
||||
|
||||
int blob_encode_t::get_shard_len(int n,int next_packet_len)
|
||||
{
|
||||
return round_up_div(current_len+(int)sizeof(u16_t)+next_packet_len,n);
|
||||
}
|
||||
|
||||
int blob_encode_t::input(char *s,int len)
|
||||
{
|
||||
assert(current_len+len+sizeof(u16_t) +100<sizeof(input_buf));
|
||||
assert(len<=65535&&len>=0);
|
||||
counter++;
|
||||
assert(counter<=max_blob_packet_num);
|
||||
write_u16(input_buf+current_len,len);
|
||||
current_len+=sizeof(u16_t);
|
||||
memcpy(input_buf+current_len,s,len);
|
||||
current_len+=len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int blob_encode_t::output(int n,char ** &s_arr,int & len)
|
||||
{
|
||||
len=round_up_div(current_len,n);
|
||||
write_u32(input_buf,counter);
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
output_buf[i]=input_buf+len*i;
|
||||
}
|
||||
s_arr=output_buf;
|
||||
return 0;
|
||||
}
|
||||
blob_decode_t::blob_decode_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
int blob_decode_t::clear()
|
||||
{
|
||||
current_len=0;
|
||||
last_len=-1;
|
||||
counter=0;
|
||||
return 0;
|
||||
}
|
||||
int blob_decode_t::input(char *s,int len)
|
||||
{
|
||||
if(last_len!=-1)
|
||||
{
|
||||
assert(last_len==len);
|
||||
}
|
||||
counter++;
|
||||
assert(counter<=max_fec_packet_num);
|
||||
last_len=len;
|
||||
assert(current_len+len+100<(int)sizeof(input_buf));//avoid overflow
|
||||
memcpy(input_buf+current_len,s,len);
|
||||
current_len+=len;
|
||||
return 0;
|
||||
}
|
||||
int blob_decode_t::output(int &n,char ** &s_arr,int *&len_arr)
|
||||
{
|
||||
|
||||
int parser_pos=0;
|
||||
|
||||
if(parser_pos+(int)sizeof(u32_t)>current_len) {mylog(log_info,"failed 0\n");return -1;}
|
||||
|
||||
n=(int)read_u32(input_buf+parser_pos);
|
||||
if(n>max_blob_packet_num) {mylog(log_info,"failed 1\n");return -1;}
|
||||
s_arr=output_buf;
|
||||
len_arr=output_len;
|
||||
|
||||
parser_pos+=sizeof(u32_t);
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
if(parser_pos+(int)sizeof(u16_t)>current_len) {mylog(log_info,"failed2 \n");return -1;}
|
||||
len_arr[i]=(int)read_u16(input_buf+parser_pos);
|
||||
parser_pos+=(int)sizeof(u16_t);
|
||||
if(parser_pos+len_arr[i]>current_len) {mylog(log_info,"failed 3 %d %d %d\n",parser_pos,len_arr[i],current_len);return -1;}
|
||||
s_arr[i]=input_buf+parser_pos;
|
||||
parser_pos+=len_arr[i];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
fec_encode_manager_t::~fec_encode_manager_t()
|
||||
{
|
||||
clear_all();
|
||||
//fd_manager.fd64_close(timer_fd64);
|
||||
}
|
||||
/*
|
||||
u64_t fec_encode_manager_t::get_timer_fd64()
|
||||
{
|
||||
return timer_fd64;
|
||||
}*/
|
||||
|
||||
fec_encode_manager_t::fec_encode_manager_t()
|
||||
{
|
||||
//int timer_fd;
|
||||
|
||||
/*
|
||||
if ((timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK)) < 0)
|
||||
{
|
||||
mylog(log_fatal,"timer_fd create error");
|
||||
myexit(1);
|
||||
}
|
||||
timer_fd64=fd_manager.create(timer_fd);*/
|
||||
|
||||
|
||||
/////reset_fec_parameter(g_fec_data_num,g_fec_redundant_num,g_fec_mtu,g_fec_queue_len,g_fec_timeout,g_fec_mode);
|
||||
|
||||
fec_par.clone(g_fec_par);
|
||||
clear_data();
|
||||
|
||||
}
|
||||
/*
|
||||
int fec_encode_manager_t::reset_fec_parameter(int data_num,int redundant_num,int mtu,int queue_len,int timeout,int mode)
|
||||
{
|
||||
fec_data_num=data_num;
|
||||
fec_redundant_num=redundant_num;
|
||||
fec_mtu=mtu;
|
||||
fec_queue_len=queue_len;
|
||||
fec_timeout=timeout;
|
||||
fec_mode=mode;
|
||||
|
||||
assert(data_num+redundant_num<max_fec_packet_num);
|
||||
|
||||
//clear();
|
||||
|
||||
clear_data();
|
||||
return 0;
|
||||
}*/
|
||||
int fec_encode_manager_t::append(char *s,int len/*,int &is_first_packet*/)
|
||||
{
|
||||
if(counter==0)
|
||||
{
|
||||
first_packet_time=get_current_time_us();
|
||||
|
||||
const double m=1000*1000;
|
||||
|
||||
ev_timer_stop(loop, &timer);
|
||||
ev_timer_set(&timer, fec_par.timeout/m,0 );
|
||||
ev_timer_start(loop, &timer);
|
||||
}
|
||||
if(fec_par.mode==0)//for type 0 use blob
|
||||
{
|
||||
assert(blob_encode.input(s,len)==0);
|
||||
}
|
||||
else if(fec_par.mode==1)//for tpe 1 use input_buf and counter
|
||||
{
|
||||
mylog(log_trace,"counter=%d\n",counter);
|
||||
assert(len<=65535&&len>=0);
|
||||
//assert(len<=fec_mtu);//relax this limitation
|
||||
char * p=input_buf[counter]+sizeof(u32_t)+4*sizeof(char);//copy directly to final position,avoid unnecessary copy.
|
||||
//remember to change this,if protocol is modified
|
||||
|
||||
write_u16(p,(u16_t)((u32_t)len)); //TODO omit this u16 for data packet while sending
|
||||
p+=sizeof(u16_t);
|
||||
memcpy(p,s,len);
|
||||
input_len[counter]=len+sizeof(u16_t);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
counter++;
|
||||
return 0;
|
||||
}
|
||||
int fec_encode_manager_t::input(char *s,int len/*,int &is_first_packet*/)
|
||||
{
|
||||
if(counter==0&&fec_par.version!=g_fec_par.version)
|
||||
{
|
||||
fec_par.clone(g_fec_par);
|
||||
}
|
||||
|
||||
int about_to_fec=0;
|
||||
int delayed_append=0;
|
||||
//int counter_back=counter;
|
||||
assert(fec_par.mode==0||fec_par.mode==1);
|
||||
|
||||
if(fec_par.mode==0&& s!=0 &&counter==0)
|
||||
{
|
||||
int out_len=blob_encode.get_shard_len(fec_par.get_tail().x,len);
|
||||
if(out_len>fec_par.mtu)
|
||||
{
|
||||
mylog(log_warn,"message too long ori_len=%d out_len=%d fec_mtu=%d,ignored\n",len,out_len,fec_par.mtu);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(fec_par.mode==1&&s!=0&&len>fec_par.mtu)
|
||||
{
|
||||
mylog(log_warn,"mode==1,message len=%d,len>fec_mtu,fec_mtu=%d,packet may not be delivered\n",len,fec_par.mtu);
|
||||
//return -1;
|
||||
}
|
||||
if(s==0&&counter==0)
|
||||
{
|
||||
mylog(log_warn,"unexpected s==0&&counter==0\n");
|
||||
return -1;
|
||||
}
|
||||
if(s==0) about_to_fec=1;//now
|
||||
|
||||
if(fec_par.mode==0&& blob_encode.get_shard_len(fec_par.get_tail().x,len)>fec_par.mtu) {about_to_fec=1; delayed_append=1;}//fec then add packet
|
||||
|
||||
if(fec_par.mode==0) assert(counter<fec_par.queue_len);//counter will never equal fec_pending_num,if that happens fec should already been done.
|
||||
if(fec_par.mode==1) assert(counter<fec_par.get_tail().x);
|
||||
|
||||
|
||||
if(s!=0&&!delayed_append)
|
||||
{
|
||||
append(s,len);
|
||||
}
|
||||
|
||||
if(fec_par.mode==0&& counter==fec_par.queue_len) about_to_fec=1;
|
||||
|
||||
if(fec_par.mode==1&& counter==fec_par.get_tail().x) about_to_fec=1;
|
||||
|
||||
|
||||
if(about_to_fec)
|
||||
{
|
||||
char ** blob_output=0;
|
||||
int fec_len=-1;
|
||||
mylog(log_trace,"counter=%d\n",counter);
|
||||
|
||||
if(counter==0)
|
||||
{
|
||||
mylog(log_warn,"unexpected counter==0 here\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int actual_data_num;
|
||||
int actual_redundant_num;
|
||||
|
||||
if(fec_par.mode==0)
|
||||
{
|
||||
|
||||
|
||||
int tail_x=fec_par.get_tail().x;
|
||||
int tail_y=fec_par.get_tail().y;
|
||||
actual_data_num=tail_x;
|
||||
actual_redundant_num=tail_y;
|
||||
|
||||
if(short_packet_optimize)
|
||||
{
|
||||
u32_t best_len=(blob_encode.get_shard_len(tail_x,0)+header_overhead)*(tail_x+tail_y);
|
||||
int best_data_num=tail_x;
|
||||
assert(tail_x<=fec_par.rs_cnt);
|
||||
for(int i=1;i<tail_x;i++)
|
||||
{
|
||||
assert(fec_par.rs_par[i-1].x==i);
|
||||
int tmp_x=fec_par.rs_par[i-1].x;
|
||||
int tmp_y=fec_par.rs_par[i-1].y;
|
||||
assert(tmp_x==i);
|
||||
u32_t shard_len=blob_encode.get_shard_len(tmp_x,0);
|
||||
if(shard_len>(u32_t)fec_par.mtu) continue;
|
||||
|
||||
u32_t new_len=(shard_len+header_overhead)*(tmp_x+tmp_y);
|
||||
if(new_len<best_len)
|
||||
{
|
||||
best_len=new_len;
|
||||
best_data_num=tmp_x;
|
||||
}
|
||||
}
|
||||
actual_data_num=best_data_num;
|
||||
assert(best_data_num>=1&&best_data_num<=fec_par.rs_cnt);
|
||||
actual_redundant_num=fec_par.rs_par[best_data_num-1].y;
|
||||
}
|
||||
|
||||
assert(blob_encode.output(actual_data_num,blob_output,fec_len)==0);
|
||||
|
||||
if(debug_fec_enc)
|
||||
mylog(log_debug,"[enc]seq=%08x x=%d y=%d len=%d cnt=%d\n",seq,actual_data_num,actual_redundant_num,fec_len,counter);
|
||||
else
|
||||
mylog(log_trace,"[enc]seq=%08x x=%d y=%d len=%d cnt=%d\n",seq,actual_data_num,actual_redundant_num,fec_len,counter);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(counter<=fec_par.rs_cnt);
|
||||
actual_data_num=counter;
|
||||
actual_redundant_num=fec_par.rs_par[counter-1].y;
|
||||
|
||||
int sum_ori=0;
|
||||
for(int i=0;i<counter;i++)
|
||||
{
|
||||
sum_ori+=input_len[i];
|
||||
assert(input_len[i]>=0);
|
||||
if(input_len[i]>fec_len) fec_len=input_len[i];
|
||||
}
|
||||
|
||||
int sum=fec_len*counter;
|
||||
|
||||
if(debug_fec_enc)
|
||||
mylog(log_debug,"[enc]seq=%08x x=%d y=%d len=%d sum_ori=%d sum=%d\n",seq,actual_data_num,actual_redundant_num,fec_len,sum_ori,sum);
|
||||
else
|
||||
mylog(log_trace,"[enc]seq=%08x x=%d y=%d len=%d sum_ori=%d sum=%d\n",seq,actual_data_num,actual_redundant_num,fec_len,sum_ori,sum);
|
||||
}
|
||||
|
||||
//mylog(log_trace,"%d %d %d\n",actual_data_num,actual_redundant_num,fec_len);
|
||||
|
||||
char *tmp_output_buf[max_fec_packet_num+5]={0};
|
||||
for(int i=0;i<actual_data_num+actual_redundant_num;i++)
|
||||
{
|
||||
int tmp_idx=0;
|
||||
|
||||
write_u32(input_buf[i] + tmp_idx, seq);
|
||||
tmp_idx += sizeof(u32_t);
|
||||
input_buf[i][tmp_idx++] = (unsigned char) fec_par.mode;
|
||||
if (fec_par.mode == 1 && i < actual_data_num)
|
||||
{
|
||||
input_buf[i][tmp_idx++] = (unsigned char) 0;
|
||||
input_buf[i][tmp_idx++] = (unsigned char) 0;
|
||||
} else
|
||||
{
|
||||
input_buf[i][tmp_idx++] = (unsigned char) actual_data_num;
|
||||
input_buf[i][tmp_idx++] = (unsigned char) actual_redundant_num;
|
||||
}
|
||||
input_buf[i][tmp_idx++] = (unsigned char) i;
|
||||
|
||||
tmp_output_buf[i]=input_buf[i]+tmp_idx; //////caution ,trick here.
|
||||
|
||||
if(fec_par.mode==0)
|
||||
{
|
||||
output_len[i]=tmp_idx+fec_len;
|
||||
if(i<actual_data_num)
|
||||
{
|
||||
memcpy(input_buf[i]+tmp_idx,blob_output[i],fec_len);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(i<actual_data_num)
|
||||
{
|
||||
output_len[i]=tmp_idx+input_len[i];
|
||||
memset(tmp_output_buf[i]+input_len[i],0,fec_len-input_len[i]);
|
||||
}
|
||||
else
|
||||
output_len[i]=tmp_idx+fec_len;
|
||||
|
||||
}
|
||||
output_buf[i]=input_buf[i];//output_buf points to same block of memory with different offset
|
||||
|
||||
}
|
||||
|
||||
if(0)
|
||||
{
|
||||
printf("seq=%u,fec_len=%d,%d %d,before fec\n",seq,fec_len,actual_data_num,actual_redundant_num);
|
||||
|
||||
for(int i=0;i<actual_data_num;i++)
|
||||
{
|
||||
printf("{");
|
||||
for(int j=0;j<8+fec_len;j++)
|
||||
{
|
||||
log_bare(log_warn,"0x%02x,",(u32_t)(unsigned char)input_buf[i][j]);
|
||||
}
|
||||
printf("},\n");
|
||||
//log_bare(log_warn,"")
|
||||
}
|
||||
}
|
||||
//output_len=blob_len+sizeof(u32_t)+4*sizeof(char);/////remember to change this 4,if modified the protocol
|
||||
rs_encode2(actual_data_num,actual_data_num+actual_redundant_num,tmp_output_buf,fec_len);
|
||||
|
||||
if(0)
|
||||
{
|
||||
printf("seq=%u,fec_len=%d,%d %d,after fec\n",seq,fec_len,actual_data_num,actual_redundant_num);
|
||||
for(int i=0;i<actual_data_num+actual_redundant_num;i++)
|
||||
{
|
||||
printf("{");
|
||||
for(int j=0;j<8+fec_len;j++)
|
||||
{
|
||||
log_bare(log_warn,"0x%02x,",(u32_t)(unsigned char)output_buf[i][j]);
|
||||
}
|
||||
printf("},\n");
|
||||
//log_bare(log_warn,"")
|
||||
}
|
||||
}
|
||||
|
||||
//mylog(log_trace,"!!! s= %d\n");
|
||||
assert(ready_for_output==0);
|
||||
ready_for_output=1;
|
||||
first_packet_time_for_output=first_packet_time;
|
||||
first_packet_time=0;
|
||||
seq++;
|
||||
counter=0;
|
||||
output_n=actual_data_num+actual_redundant_num;
|
||||
blob_encode.clear();
|
||||
|
||||
my_itimerspec its;
|
||||
memset(&its,0,sizeof(its));
|
||||
ev_timer_stop(loop, &timer);
|
||||
//timerfd_settime(timer_fd,TFD_TIMER_ABSTIME,&its,0);
|
||||
|
||||
if(encode_fast_send&&fec_par.mode==1)
|
||||
{
|
||||
int packet_to_send[max_fec_packet_num+5]={0};
|
||||
int packet_to_send_counter=0;
|
||||
|
||||
//assert(counter!=0);
|
||||
if(s!=0)
|
||||
packet_to_send[packet_to_send_counter++]=actual_data_num-1;
|
||||
for(int i=actual_data_num;i<actual_data_num+actual_redundant_num;i++)
|
||||
{
|
||||
|
||||
packet_to_send[packet_to_send_counter++]=i;
|
||||
}
|
||||
output_n=packet_to_send_counter;//re write
|
||||
for(int i=0;i<packet_to_send_counter;i++)
|
||||
{
|
||||
output_buf[i]=output_buf[packet_to_send[i]];
|
||||
output_len[i]=output_len[packet_to_send[i]];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(encode_fast_send&&s!=0&&fec_par.mode==1)
|
||||
{
|
||||
assert(counter>=1);
|
||||
assert(counter<=255);
|
||||
int input_buf_idx=counter-1;
|
||||
assert(ready_for_output==0);
|
||||
ready_for_output=1;
|
||||
first_packet_time_for_output=0;
|
||||
output_n=1;
|
||||
|
||||
|
||||
int tmp_idx=0;
|
||||
write_u32(input_buf[input_buf_idx]+tmp_idx,seq);
|
||||
tmp_idx+=sizeof(u32_t);
|
||||
|
||||
input_buf[input_buf_idx][tmp_idx++]=(unsigned char)fec_par.mode;
|
||||
input_buf[input_buf_idx][tmp_idx++]=(unsigned char)0;
|
||||
input_buf[input_buf_idx][tmp_idx++]=(unsigned char)0;
|
||||
input_buf[input_buf_idx][tmp_idx++]=(unsigned char)((u32_t)input_buf_idx);
|
||||
|
||||
output_len[0]=input_len[input_buf_idx]+tmp_idx;
|
||||
output_buf[0]=input_buf[input_buf_idx];
|
||||
|
||||
if(0)
|
||||
{
|
||||
printf("seq=%u,buf_idx=%d\n",seq,input_buf_idx);
|
||||
for(int j=0;j<output_len[0];j++)
|
||||
{
|
||||
log_bare(log_warn,"0x%02x,",(u32_t)(unsigned char)output_buf[0][j]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(s!=0&&delayed_append)
|
||||
{
|
||||
assert(fec_par.mode!=1);
|
||||
append(s,len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fec_encode_manager_t::output(int &n,char ** &s_arr,int *&len)
|
||||
{
|
||||
if(!ready_for_output)
|
||||
{
|
||||
n=-1;
|
||||
len=0;
|
||||
s_arr=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
n=output_n;
|
||||
len=output_len;
|
||||
s_arr=output_buf;
|
||||
ready_for_output=0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int fec_decode_manager_t::re_init()
|
||||
{
|
||||
clear();
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
int fec_decode_manager_t::input(char *s,int len)
|
||||
{
|
||||
assert(s!=0);
|
||||
assert(len+100<buf_len);//guarenteed by upper level
|
||||
|
||||
int tmp_idx=0;
|
||||
int tmp_header_len=sizeof(u32_t)+sizeof(char)*4;
|
||||
if(len<tmp_header_len)
|
||||
{
|
||||
mylog(log_warn,"len =%d\n",len);
|
||||
return -1;
|
||||
}
|
||||
u32_t seq=read_u32(s+tmp_idx);
|
||||
tmp_idx+=sizeof(u32_t);
|
||||
int type=(unsigned char)s[tmp_idx++];
|
||||
int data_num=(unsigned char)s[tmp_idx++];
|
||||
int redundant_num=(unsigned char)s[tmp_idx++];
|
||||
int inner_index=(unsigned char)s[tmp_idx++];
|
||||
len=len-tmp_idx;
|
||||
|
||||
//mylog(log_trace,"input\n");
|
||||
|
||||
if(len<0)
|
||||
{
|
||||
mylog(log_warn,"len<0\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(type==1)
|
||||
{
|
||||
if(len<(int)sizeof(u16_t))
|
||||
{
|
||||
mylog(log_warn,"type==1&&len<2\n");
|
||||
return -1;
|
||||
}
|
||||
if(data_num==0&&(int)( read_u16(s+tmp_idx)+sizeof(u16_t))!=len)
|
||||
{
|
||||
mylog(log_warn,"inner_index<data_num&&read_u16(s+tmp_idx)+sizeof(u16_t)!=len %d %d\n",(int)( read_u16(s+tmp_idx)+sizeof(u16_t)),len);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(type==0&&data_num==0)
|
||||
{
|
||||
mylog(log_warn,"unexpected type==0&&data_num==0\n");
|
||||
return -1;
|
||||
}
|
||||
if(data_num+redundant_num>=max_fec_packet_num)
|
||||
{
|
||||
mylog(log_warn,"data_num+redundant_num>=max_fec_packet_num\n");
|
||||
return -1;
|
||||
}
|
||||
if(!anti_replay.is_vaild(seq))
|
||||
{
|
||||
mylog(log_trace,"!anti_replay.is_vaild(seq) ,seq =%u\n",seq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mp[seq].fec_done!=0)
|
||||
{
|
||||
mylog(log_debug,"fec already done, ignore, seq=%u\n",seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(mp[seq].group_mp.find(inner_index)!=mp[seq].group_mp.end() )
|
||||
{
|
||||
mylog(log_debug,"dup fec index\n");//duplicate can happen on a normal network, so its just log_debug
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
if(mp[seq].type==-1)
|
||||
mp[seq].type=type;
|
||||
else
|
||||
{
|
||||
if(mp[seq].type!=type)
|
||||
{
|
||||
mylog(log_warn,"type mismatch\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(data_num!=0)
|
||||
{
|
||||
//mp[seq].data_counter++;
|
||||
|
||||
if(mp[seq].data_num==-1)
|
||||
{
|
||||
mp[seq].data_num=data_num;
|
||||
mp[seq].redundant_num=redundant_num;
|
||||
mp[seq].len=len;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mp[seq].data_num!=data_num||mp[seq].redundant_num!=redundant_num||mp[seq].len!=len)
|
||||
{
|
||||
mylog(log_warn,"unexpected mp[seq].data_num!=data_num||mp[seq].redundant_num!=redundant_num||mp[seq].len!=len\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//mylog(log_info,"mp.size()=%d index=%d\n",mp.size(),index);
|
||||
|
||||
if(fec_data[index].used!=0)
|
||||
{
|
||||
u32_t tmp_seq=fec_data[index].seq;
|
||||
anti_replay.set_invaild(tmp_seq);
|
||||
|
||||
auto tmp_it=mp.find(tmp_seq);
|
||||
if(tmp_it!=mp.end())
|
||||
{
|
||||
int x=tmp_it->second.data_num;
|
||||
int y=tmp_it->second.redundant_num;
|
||||
int cnt=tmp_it->second.group_mp.size();
|
||||
|
||||
if(cnt<x)
|
||||
{
|
||||
if(debug_fec_dec)
|
||||
mylog(log_debug,"[dec][failed]seq=%08x x=%d y=%d cnt=%d\n",tmp_seq,x,y,cnt);
|
||||
else
|
||||
mylog(log_trace,"[dec][failed]seq=%08x x=%d y=%d cnt=%d\n",tmp_seq,x,y,cnt);
|
||||
}
|
||||
mp.erase(tmp_it);
|
||||
}
|
||||
if(tmp_seq==seq)
|
||||
{
|
||||
mylog(log_warn,"unexpected tmp_seq==seq ,seq=%d\n",seq);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fec_data[index].used=1;
|
||||
fec_data[index].seq=seq;
|
||||
fec_data[index].type=type;
|
||||
fec_data[index].data_num=data_num;
|
||||
fec_data[index].redundant_num=redundant_num;
|
||||
fec_data[index].idx=inner_index;
|
||||
fec_data[index].len=len;
|
||||
assert(0<=index&&index<(int)fec_buff_num);
|
||||
assert(len+100<buf_len);
|
||||
memcpy(fec_data[index].buf,s+tmp_idx,len);
|
||||
mp[seq].group_mp[inner_index]=index;
|
||||
//index++ at end of function
|
||||
|
||||
map<int,int> &inner_mp=mp[seq].group_mp;
|
||||
|
||||
|
||||
int about_to_fec=0;
|
||||
if(type==0)
|
||||
{
|
||||
//assert((int)inner_mp.size()<=data_num);
|
||||
if((int)inner_mp.size()>data_num)
|
||||
{
|
||||
mylog(log_warn,"inner_mp.size()>data_num\n");
|
||||
anti_replay.set_invaild(seq);
|
||||
goto end;
|
||||
}
|
||||
if((int)inner_mp.size()==data_num)
|
||||
about_to_fec=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(mp[seq].data_num!=-1)
|
||||
{
|
||||
if((int)inner_mp.size()>mp[seq].data_num+1)
|
||||
{
|
||||
mylog(log_warn,"inner_mp.size()>data_num+1\n");
|
||||
anti_replay.set_invaild(seq);
|
||||
goto end;
|
||||
}
|
||||
if((int)inner_mp.size()>=mp[seq].data_num)
|
||||
{
|
||||
about_to_fec=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(about_to_fec)
|
||||
{
|
||||
int group_data_num=mp[seq].data_num;
|
||||
int group_redundant_num=mp[seq].redundant_num;
|
||||
|
||||
int x_got=0;
|
||||
int y_got=0;
|
||||
//mylog(log_error,"fec here!\n");
|
||||
if(type==0)
|
||||
{
|
||||
char *fec_tmp_arr[max_fec_packet_num+5]={0};
|
||||
for(auto it=inner_mp.begin();it!=inner_mp.end();it++)
|
||||
{
|
||||
if(it->first <group_data_num)
|
||||
x_got++;
|
||||
else
|
||||
y_got++;
|
||||
fec_tmp_arr[it->first]=fec_data[it->second].buf;
|
||||
}
|
||||
assert(rs_decode2(group_data_num,group_data_num+group_redundant_num,fec_tmp_arr,len)==0); //the input data has been modified in-place
|
||||
//this line should always succeed
|
||||
mp[seq].fec_done=1;
|
||||
|
||||
if(debug_fec_dec)
|
||||
mylog(log_debug,"[dec]seq=%08x x=%d y=%d len=%d cnt=%d X=%d Y=%d\n",seq,group_data_num,group_redundant_num,len,int(inner_mp.size()),x_got,y_got);
|
||||
else
|
||||
mylog(log_trace,"[dec]seq=%08x x=%d y=%d len=%d cnt=%d X=%d Y=%d\n",seq,group_data_num,group_redundant_num,len,int(inner_mp.size()),x_got,y_got);
|
||||
|
||||
blob_decode.clear();
|
||||
for(int i=0;i<group_data_num;i++)
|
||||
{
|
||||
blob_decode.input(fec_tmp_arr[i],len);
|
||||
}
|
||||
if(blob_decode.output(output_n,output_s_arr,output_len_arr)!=0)
|
||||
{
|
||||
mylog(log_warn,"blob_decode failed\n");
|
||||
//ready_for_output=0;
|
||||
anti_replay.set_invaild(seq);
|
||||
goto end;
|
||||
}
|
||||
assert(ready_for_output==0);
|
||||
ready_for_output=1;
|
||||
anti_replay.set_invaild(seq);
|
||||
}
|
||||
else//type==1
|
||||
{
|
||||
|
||||
|
||||
int max_len=-1;
|
||||
int fec_result_ok=1;
|
||||
int data_check_ok=1;
|
||||
int debug_num=inner_mp.size();
|
||||
|
||||
int missed_packet[max_fec_packet_num+5];
|
||||
int missed_packet_counter=0;
|
||||
|
||||
//outupt_s_arr_buf[max_fec_packet_num+5]={0};
|
||||
|
||||
//memset(output_s_arr_buf,0,sizeof(output_s_arr_buf));//in efficient
|
||||
|
||||
for(int i=0;i<group_data_num+group_redundant_num;i++)
|
||||
{
|
||||
output_s_arr_buf[i]=0;
|
||||
}
|
||||
for(auto it=inner_mp.begin();it!=inner_mp.end();it++)
|
||||
{
|
||||
if(it->first <group_data_num)
|
||||
x_got++;
|
||||
else
|
||||
y_got++;
|
||||
|
||||
output_s_arr_buf[it->first]=fec_data[it->second].buf;
|
||||
if(fec_data[it->second].len<(int)sizeof(u16_t))
|
||||
{
|
||||
mylog(log_warn,"fec_data[it->second].len<(int)sizeof(u16_t)");
|
||||
data_check_ok=0;
|
||||
}
|
||||
|
||||
if(fec_data[it->second].len > max_len)
|
||||
max_len=fec_data[it->second].len;
|
||||
}
|
||||
if(max_len!=mp[seq].len)
|
||||
{
|
||||
data_check_ok=0;
|
||||
mylog(log_warn,"max_len!=mp[seq].len");
|
||||
}
|
||||
if(data_check_ok==0)
|
||||
{
|
||||
//ready_for_output=0;
|
||||
mylog(log_warn,"data_check_ok==0\n");
|
||||
anti_replay.set_invaild(seq);
|
||||
goto end;
|
||||
}
|
||||
for(auto it=inner_mp.begin();it!=inner_mp.end();it++)
|
||||
{
|
||||
int tmp_idx=it->second;
|
||||
assert(max_len>=fec_data[tmp_idx].len);//guarenteed by data_check_ok
|
||||
memset(fec_data[tmp_idx].buf+fec_data[tmp_idx].len,0,max_len-fec_data[tmp_idx].len);
|
||||
}
|
||||
|
||||
for(int i=0;i<group_data_num;i++)
|
||||
{
|
||||
if(output_s_arr_buf[i]==0 ||i==inner_index) //only missed packet +current packet
|
||||
{
|
||||
missed_packet[missed_packet_counter++]=i;
|
||||
}
|
||||
}
|
||||
mylog(log_trace,"fec done,%d %d,missed_packet_counter=%d\n",group_data_num,group_redundant_num,missed_packet_counter);
|
||||
|
||||
assert(rs_decode2(group_data_num,group_data_num+group_redundant_num,output_s_arr_buf,max_len)==0);//this should always succeed
|
||||
mp[seq].fec_done=1;
|
||||
|
||||
int sum_ori=0;
|
||||
|
||||
for(int i=0;i<group_data_num;i++)
|
||||
{
|
||||
output_len_arr_buf[i]=read_u16(output_s_arr_buf[i]);
|
||||
sum_ori+=output_len_arr_buf[i];
|
||||
output_s_arr_buf[i]+=sizeof(u16_t);
|
||||
if(output_len_arr_buf[i]>max_data_len)
|
||||
{
|
||||
mylog(log_warn,"invaild len %d,seq= %u,data_num= %d r_num= %d,i= %d\n",output_len_arr_buf[i],seq,group_data_num,group_redundant_num,i);
|
||||
fec_result_ok=0;
|
||||
for(int i=0;i<missed_packet_counter;i++)
|
||||
{
|
||||
log_bare(log_warn,"%d ",missed_packet[i]);
|
||||
}
|
||||
log_bare(log_warn,"\n");
|
||||
//break;
|
||||
}
|
||||
}
|
||||
|
||||
int sum=max_len*group_data_num;
|
||||
|
||||
if(debug_fec_dec)
|
||||
mylog(log_debug,"[dec]seq=%08x x=%d y=%d len=%d sum_ori=%d sum=%d X=%d Y=%d\n",seq,group_data_num,group_redundant_num,max_len,sum_ori,sum,x_got,y_got);
|
||||
else
|
||||
mylog(log_trace,"[dec]seq=%08x x=%d y=%d len=%d sum_ori=%d sum=%d X=%d Y=%d\n",seq,group_data_num,group_redundant_num,max_len,sum_ori,sum,x_got,y_got);
|
||||
|
||||
if(fec_result_ok)
|
||||
{
|
||||
|
||||
output_n=group_data_num;
|
||||
|
||||
if(decode_fast_send)
|
||||
{
|
||||
output_n=missed_packet_counter;
|
||||
for(int i=0;i<missed_packet_counter;i++)
|
||||
{
|
||||
output_s_arr_buf[i]=output_s_arr_buf[missed_packet[i]];
|
||||
output_len_arr_buf[i]=output_len_arr_buf[missed_packet[i]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output_s_arr=output_s_arr_buf;
|
||||
output_len_arr=output_len_arr_buf;
|
||||
assert(ready_for_output==0);
|
||||
ready_for_output=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//fec_not_ok:
|
||||
ready_for_output=0;
|
||||
}
|
||||
anti_replay.set_invaild(seq);
|
||||
}// end of type==1
|
||||
}
|
||||
else //not about_to_fec
|
||||
{
|
||||
|
||||
if(decode_fast_send)
|
||||
{
|
||||
if(type==1&&data_num==0)
|
||||
{
|
||||
assert(ready_for_output==0);
|
||||
output_n=1;
|
||||
int check_len=read_u16(fec_data[index].buf);
|
||||
output_s_arr_buf[0]=fec_data[index].buf+sizeof(u16_t);
|
||||
output_len_arr_buf[0]=fec_data[index].len-sizeof(u16_t);
|
||||
|
||||
if(output_len_arr_buf[0]!=check_len)
|
||||
{
|
||||
mylog(log_warn,"len mismatch %d %d\n",output_len_arr_buf[0],check_len);
|
||||
}
|
||||
output_s_arr=output_s_arr_buf;
|
||||
output_len_arr=output_len_arr_buf;
|
||||
|
||||
ready_for_output=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
index++;
|
||||
if(index==int(fec_buff_num)) index=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
int fec_decode_manager_t::output(int &n,char ** &s_arr,int* &len_arr)
|
||||
{
|
||||
if(!ready_for_output)
|
||||
{
|
||||
n=-1;
|
||||
s_arr=0;
|
||||
len_arr=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ready_for_output=0;
|
||||
n=output_n;
|
||||
s_arr=output_s_arr;
|
||||
len_arr=output_len_arr;
|
||||
}
|
||||
return 0;
|
||||
}
|
487
fec_manager.h
@@ -1,487 +0,0 @@
|
||||
/*
|
||||
* fec_manager.h
|
||||
*
|
||||
* Created on: Sep 27, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef FEC_MANAGER_H_
|
||||
#define FEC_MANAGER_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "lib/rs.h"
|
||||
|
||||
const int max_blob_packet_num=30000;//how many packet can be contain in a blob_t ,can be set very large
|
||||
const u32_t anti_replay_buff_size=30000;//can be set very large
|
||||
|
||||
const int max_fec_packet_num=255;// this is the limitation of the rs lib
|
||||
extern u32_t fec_buff_num;
|
||||
|
||||
const int rs_str_len=max_fec_packet_num*10+100;
|
||||
extern int header_overhead;
|
||||
extern int debug_fec_enc;
|
||||
extern int debug_fec_dec;
|
||||
|
||||
struct fec_parameter_t
|
||||
{
|
||||
int version=0;
|
||||
int mtu=default_mtu;
|
||||
int queue_len=200;
|
||||
int timeout=8*1000;
|
||||
int mode=0;
|
||||
|
||||
int rs_cnt=0;
|
||||
struct rs_parameter_t //parameters for reed solomon
|
||||
{
|
||||
unsigned char x;//AKA fec_data_num (x should be same as <index of rs_par>+1 at the moment)
|
||||
unsigned char y;//fec_redundant_num
|
||||
}rs_par[max_fec_packet_num+10];
|
||||
|
||||
int rs_from_str(char * s)//todo inefficient
|
||||
{
|
||||
vector<string> str_vec=string_to_vec(s,",");
|
||||
if(str_vec.size()<1)
|
||||
{
|
||||
mylog(log_warn,"failed to parse [%s]\n",s);
|
||||
return -1;
|
||||
}
|
||||
vector<rs_parameter_t> par_vec;
|
||||
for(int i=0;i<(int)str_vec.size();i++)
|
||||
{
|
||||
rs_parameter_t tmp_par;
|
||||
string &tmp_str=str_vec[i];
|
||||
int x,y;
|
||||
if(sscanf((char *)tmp_str.c_str(),"%d:%d",&x,&y)!=2)
|
||||
{
|
||||
mylog(log_warn,"failed to parse [%s]\n",tmp_str.c_str());
|
||||
return -1;
|
||||
}
|
||||
if(x<1||y<0||x+y>max_fec_packet_num)
|
||||
{
|
||||
mylog(log_warn,"invaild value x=%d y=%d, x should >=1, y should >=0, x +y should <%d\n",x,y,max_fec_packet_num);
|
||||
return -1;
|
||||
}
|
||||
tmp_par.x=x;
|
||||
tmp_par.y=y;
|
||||
par_vec.push_back(tmp_par);
|
||||
}
|
||||
assert(par_vec.size()==str_vec.size());
|
||||
|
||||
int found_problem=0;
|
||||
for(int i=1;i<(int)par_vec.size();i++)
|
||||
{
|
||||
if(par_vec[i].x<=par_vec[i-1].x)
|
||||
{
|
||||
mylog(log_warn,"error in [%s], x in x:y should be in ascend order\n",s);
|
||||
return -1;
|
||||
}
|
||||
int now_x=par_vec[i].x;
|
||||
int now_y=par_vec[i].y;
|
||||
int pre_x=par_vec[i-1].x;
|
||||
int pre_y=par_vec[i-1].y;
|
||||
|
||||
double now_ratio=double(par_vec[i].y)/par_vec[i].x;
|
||||
double pre_ratio=double(par_vec[i-1].y)/par_vec[i-1].x;
|
||||
|
||||
if(pre_ratio+0.0001<now_ratio)
|
||||
{
|
||||
if(found_problem==0)
|
||||
{
|
||||
mylog(log_warn,"possible problems: %d/%d<%d/%d",pre_y,pre_x,now_y,now_x);
|
||||
found_problem=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_bare(log_warn,", %d/%d<%d/%d",pre_y,pre_x,now_y,now_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(found_problem)
|
||||
{
|
||||
log_bare(log_warn," in %s\n",s);
|
||||
}
|
||||
|
||||
{ //special treatment for first parameter
|
||||
int x=par_vec[0].x;
|
||||
int y=par_vec[0].y;
|
||||
for(int i=1;i<=x;i++)
|
||||
{
|
||||
rs_par[i-1].x=i;
|
||||
rs_par[i-1].y=y;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=1;i<(int)par_vec.size();i++)
|
||||
{
|
||||
int now_x=par_vec[i].x;
|
||||
int now_y=par_vec[i].y;
|
||||
int pre_x=par_vec[i-1].x;
|
||||
int pre_y=par_vec[i-1].y;
|
||||
rs_par[now_x-1].x=now_x;
|
||||
rs_par[now_x-1].y=now_y;
|
||||
|
||||
double now_ratio=double(par_vec[i].y)/par_vec[i].x;
|
||||
double pre_ratio=double(par_vec[i-1].y)/par_vec[i-1].x;
|
||||
|
||||
//double k= double(now_y-pre_y)/double(now_x-pre_x);
|
||||
for(int j=pre_x+1;j<=now_x-1;j++)
|
||||
{
|
||||
int in_x=j;
|
||||
|
||||
//////// int in_y= double(pre_y) + double(in_x-pre_x)*k+ 0.9999;// round to upper
|
||||
|
||||
double distance=now_x-pre_x;
|
||||
/////// double in_ratio=pre_ratio*(1.0-(in_x-pre_x)/distance) + now_ratio *(1.0- (now_x-in_x)/distance);
|
||||
////// int in_y= in_x*in_ratio + 0.9999;
|
||||
int in_y= pre_y +(now_y-pre_y) *(in_x-pre_x)/distance +0.9999;
|
||||
|
||||
if(in_x+in_y>max_fec_packet_num)
|
||||
{
|
||||
in_y=max_fec_packet_num-in_x;
|
||||
assert(in_y>=0&&in_y<=max_fec_packet_num);
|
||||
}
|
||||
|
||||
rs_par[in_x-1].x=in_x;
|
||||
rs_par[in_x-1].y=in_y;
|
||||
}
|
||||
}
|
||||
rs_cnt=par_vec[par_vec.size()-1].x;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *rs_to_str()//todo inefficient
|
||||
{
|
||||
static char res[rs_str_len];
|
||||
string tmp_string;
|
||||
char tmp_buf[100];
|
||||
assert(rs_cnt>=1);
|
||||
for(int i=0;i<rs_cnt;i++)
|
||||
{
|
||||
sprintf(tmp_buf,"%d:%d",int(rs_par[i].x),int(rs_par[i].y));
|
||||
if(i!=0)
|
||||
tmp_string+=",";
|
||||
tmp_string+=tmp_buf;
|
||||
}
|
||||
strcpy(res,tmp_string.c_str());
|
||||
return res;
|
||||
}
|
||||
|
||||
rs_parameter_t get_tail()
|
||||
{
|
||||
assert(rs_cnt>=1);
|
||||
return rs_par[rs_cnt-1];
|
||||
}
|
||||
|
||||
|
||||
int clone(fec_parameter_t & other)
|
||||
{
|
||||
version=other.version;
|
||||
mtu=other.mtu;
|
||||
queue_len=other.queue_len;
|
||||
timeout=other.timeout;
|
||||
mode=other.mode;
|
||||
|
||||
assert(other.rs_cnt>=1);
|
||||
rs_cnt=other.rs_cnt;
|
||||
memcpy(rs_par,other.rs_par,sizeof(rs_parameter_t)*rs_cnt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
extern fec_parameter_t g_fec_par;
|
||||
//extern int dynamic_update_fec;
|
||||
|
||||
const int anti_replay_timeout=120*1000;// 120s
|
||||
|
||||
struct anti_replay_t
|
||||
{
|
||||
|
||||
struct info_t
|
||||
{
|
||||
my_time_t my_time;
|
||||
int index;
|
||||
};
|
||||
|
||||
u64_t replay_buffer[anti_replay_buff_size];
|
||||
unordered_map<u32_t,info_t> mp;
|
||||
int index;
|
||||
anti_replay_t()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
int clear()
|
||||
{
|
||||
memset(replay_buffer,-1,sizeof(replay_buffer));
|
||||
mp.clear();
|
||||
mp.rehash(anti_replay_buff_size*3);
|
||||
index=0;
|
||||
return 0;
|
||||
}
|
||||
void set_invaild(u32_t seq)
|
||||
{
|
||||
|
||||
if(is_vaild(seq)==0)
|
||||
{
|
||||
mylog(log_trace,"seq %u exist\n",seq);
|
||||
//assert(mp.find(seq)!=mp.end());
|
||||
//mp[seq].my_time=get_current_time_rough();
|
||||
return;
|
||||
}
|
||||
if(replay_buffer[index]!=u64_t(i64_t(-1)))
|
||||
{
|
||||
assert(mp.find(replay_buffer[index])!=mp.end());
|
||||
mp.erase(replay_buffer[index]);
|
||||
}
|
||||
replay_buffer[index]=seq;
|
||||
assert(mp.find(seq)==mp.end());
|
||||
mp[seq].my_time=get_current_time();
|
||||
mp[seq].index=index;
|
||||
index++;
|
||||
if(index==int(anti_replay_buff_size)) index=0;
|
||||
}
|
||||
int is_vaild(u32_t seq)
|
||||
{
|
||||
if(mp.find(seq)==mp.end()) return 1;
|
||||
|
||||
if(get_current_time()-mp[seq].my_time>anti_replay_timeout)
|
||||
{
|
||||
replay_buffer[mp[seq].index]=u64_t(i64_t(-1));
|
||||
mp.erase(seq);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct blob_encode_t
|
||||
{
|
||||
char input_buf[(max_fec_packet_num+5)*buf_len];
|
||||
int current_len;
|
||||
int counter;
|
||||
|
||||
char *output_buf[max_fec_packet_num+100];
|
||||
|
||||
blob_encode_t();
|
||||
|
||||
int clear();
|
||||
|
||||
int get_num();
|
||||
int get_shard_len(int n);
|
||||
int get_shard_len(int n,int next_packet_len);
|
||||
|
||||
int input(char *s,int len); //len=use len=0 for second and following packet
|
||||
int output(int n,char ** &s_arr,int & len);
|
||||
};
|
||||
|
||||
struct blob_decode_t
|
||||
{
|
||||
char input_buf[(max_fec_packet_num+5)*buf_len];
|
||||
int current_len;
|
||||
int last_len;
|
||||
int counter;
|
||||
|
||||
char *output_buf[max_blob_packet_num+100];
|
||||
int output_len[max_blob_packet_num+100];
|
||||
|
||||
blob_decode_t();
|
||||
int clear();
|
||||
int input(char *input,int len);
|
||||
int output(int &n,char ** &output,int *&len_arr);
|
||||
};
|
||||
|
||||
class fec_encode_manager_t:not_copy_able_t
|
||||
{
|
||||
|
||||
private:
|
||||
u32_t seq;
|
||||
|
||||
//int fec_mode;
|
||||
//int fec_data_num,fec_redundant_num;
|
||||
//int fec_mtu;
|
||||
//int fec_queue_len;
|
||||
//int fec_timeout;
|
||||
fec_parameter_t fec_par;
|
||||
|
||||
|
||||
my_time_t first_packet_time;
|
||||
my_time_t first_packet_time_for_output;
|
||||
|
||||
|
||||
blob_encode_t blob_encode;
|
||||
char input_buf[max_fec_packet_num+5][buf_len];
|
||||
int input_len[max_fec_packet_num+100];
|
||||
|
||||
char *output_buf[max_fec_packet_num+100];
|
||||
int output_len[max_fec_packet_num+100];
|
||||
|
||||
int counter;
|
||||
//int timer_fd;
|
||||
//u64_t timer_fd64;
|
||||
|
||||
int ready_for_output;
|
||||
u32_t output_n;
|
||||
|
||||
int append(char *s,int len);
|
||||
|
||||
ev_timer timer;
|
||||
struct ev_loop *loop=0;
|
||||
void (*cb) (struct ev_loop *loop, struct ev_timer *watcher, int revents)=0;
|
||||
|
||||
public:
|
||||
fec_encode_manager_t();
|
||||
~fec_encode_manager_t();
|
||||
|
||||
fec_parameter_t & get_fec_par()
|
||||
{
|
||||
return fec_par;
|
||||
}
|
||||
void set_data(void * data)
|
||||
{
|
||||
timer.data=data;
|
||||
}
|
||||
|
||||
|
||||
void set_loop_and_cb(struct ev_loop *loop,void (*cb) (struct ev_loop *loop, struct ev_timer *watcher, int revents))
|
||||
{
|
||||
this->loop=loop;
|
||||
this->cb=cb;
|
||||
ev_init(&timer,cb);
|
||||
}
|
||||
|
||||
int clear_data()
|
||||
{
|
||||
counter=0;
|
||||
blob_encode.clear();
|
||||
ready_for_output=0;
|
||||
|
||||
seq=(u32_t)get_fake_random_number(); //TODO temp solution for a bug.
|
||||
|
||||
if(loop)
|
||||
{
|
||||
ev_timer_stop(loop,&timer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int clear_all()
|
||||
{
|
||||
|
||||
//itimerspec zero_its;
|
||||
//memset(&zero_its, 0, sizeof(zero_its));
|
||||
//timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &zero_its, 0);
|
||||
|
||||
if(loop)
|
||||
{
|
||||
ev_timer_stop(loop,&timer);
|
||||
loop=0;
|
||||
cb=0;
|
||||
}
|
||||
|
||||
clear_data();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
my_time_t get_first_packet_time()
|
||||
{
|
||||
return first_packet_time_for_output;
|
||||
}
|
||||
|
||||
int get_pending_time()
|
||||
{
|
||||
return fec_par.timeout;
|
||||
}
|
||||
|
||||
int get_type()
|
||||
{
|
||||
return fec_par.mode;
|
||||
}
|
||||
//u64_t get_timer_fd64();
|
||||
int reset_fec_parameter(int data_num,int redundant_num,int mtu,int pending_num,int pending_time,int type);
|
||||
int input(char *s,int len/*,int &is_first_packet*/);
|
||||
int output(int &n,char ** &s_arr,int *&len);
|
||||
};
|
||||
struct fec_data_t
|
||||
{
|
||||
int used;
|
||||
u32_t seq;
|
||||
int type;
|
||||
int data_num;
|
||||
int redundant_num;
|
||||
int idx;
|
||||
char buf[buf_len];
|
||||
int len;
|
||||
};
|
||||
struct fec_group_t
|
||||
{
|
||||
int type=-1;
|
||||
int data_num=-1;
|
||||
int redundant_num=-1;
|
||||
int len=-1;
|
||||
int fec_done=0;
|
||||
//int data_counter=0;
|
||||
map<int,int> group_mp;
|
||||
};
|
||||
class fec_decode_manager_t:not_copy_able_t
|
||||
{
|
||||
anti_replay_t anti_replay;
|
||||
fec_data_t *fec_data=0;
|
||||
unordered_map<u32_t, fec_group_t> mp;
|
||||
blob_decode_t blob_decode;
|
||||
|
||||
int index;
|
||||
|
||||
int output_n;
|
||||
char ** output_s_arr;
|
||||
int * output_len_arr;
|
||||
int ready_for_output;
|
||||
|
||||
char *output_s_arr_buf[max_fec_packet_num+100];//only for type=1,for type=0 the buf inside blot_t is used
|
||||
int output_len_arr_buf[max_fec_packet_num+100];//same
|
||||
|
||||
public:
|
||||
fec_decode_manager_t()
|
||||
{
|
||||
fec_data=new fec_data_t[fec_buff_num+5];
|
||||
assert(fec_data!=0);
|
||||
clear();
|
||||
}
|
||||
/*
|
||||
fec_decode_manager_t(const fec_decode_manager_t &b)
|
||||
{
|
||||
assert(0==1);//not allowed to copy
|
||||
}*/
|
||||
~fec_decode_manager_t()
|
||||
{
|
||||
mylog(log_debug,"fec_decode_manager destroyed\n");
|
||||
if(fec_data!=0)
|
||||
{
|
||||
mylog(log_debug,"fec_data freed\n");
|
||||
delete fec_data;
|
||||
}
|
||||
}
|
||||
int clear()
|
||||
{
|
||||
anti_replay.clear();
|
||||
mp.clear();
|
||||
mp.rehash(fec_buff_num*3);
|
||||
|
||||
for(int i=0;i<(int)fec_buff_num;i++)
|
||||
fec_data[i].used=0;
|
||||
ready_for_output=0;
|
||||
index=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//int re_init();
|
||||
int input(char *s,int len);
|
||||
int output(int &n,char ** &s_arr,int* &len_arr);
|
||||
};
|
||||
|
||||
#endif /* FEC_MANAGER_H_ */
|
Before Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 65 KiB |
@@ -1 +0,0 @@
|
||||
|
Before Width: | Height: | Size: 115 KiB |
Before Width: | Height: | Size: 132 KiB |
Before Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 1.1 MiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 33 KiB |
@@ -1 +0,0 @@
|
||||
|
Before Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 669 KiB |
Before Width: | Height: | Size: 1.1 MiB |
BIN
images/en/rs.png
Before Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 34 KiB |
917
lib/fec.cpp
@@ -1,917 +0,0 @@
|
||||
/*
|
||||
* fec.c -- forward error correction based on Vandermonde matrices
|
||||
* 980624
|
||||
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
|
||||
*
|
||||
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
|
||||
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
|
||||
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following parameter defines how many bits are used for
|
||||
* field elements. The code supports any value from 2 to 16
|
||||
* but fastest operation is achieved with 8 bit elements
|
||||
* This is the only parameter you may want to change.
|
||||
*/
|
||||
#ifndef GF_BITS
|
||||
#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef unsigned long u_long;
|
||||
/*
|
||||
* compatibility stuff
|
||||
*/
|
||||
#if defined(MSDOS)||defined(__MINGW32__) /* but also for others, e.g. sun... */
|
||||
#define NEED_BCOPY
|
||||
#define bcmp(a,b,n) memcmp(a,b,n)
|
||||
#endif
|
||||
|
||||
#ifdef NEED_BCOPY
|
||||
#define bcopy(s, d, siz) memcpy((d), (s), (siz))
|
||||
#define bzero(d, siz) memset((d), '\0', (siz))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* stuff used for testing purposes only
|
||||
*/
|
||||
|
||||
#ifdef TEST
|
||||
#define DEB(x)
|
||||
#define DDB(x) x
|
||||
#define DEBUG 0 /* minimal debugging */
|
||||
#ifdef MSDOS
|
||||
#include <time.h>
|
||||
struct timeval {
|
||||
unsigned long ticks;
|
||||
};
|
||||
#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
|
||||
#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
|
||||
typedef unsigned long u_long ;
|
||||
typedef unsigned short u_short ;
|
||||
#else /* typically, unix systems */
|
||||
#include <sys/time.h>
|
||||
#define DIFF_T(a,b) \
|
||||
(1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
|
||||
#endif
|
||||
|
||||
#define TICK(t) \
|
||||
{struct timeval x ; \
|
||||
gettimeofday(&x, NULL) ; \
|
||||
t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
|
||||
}
|
||||
#define TOCK(t) \
|
||||
{ u_long t1 ; TICK(t1) ; \
|
||||
if (t1 < t) t = 256000000 + t1 - t ; \
|
||||
else t = t1 - t ; \
|
||||
if (t == 0) t = 1 ;}
|
||||
|
||||
u_long ticks[10]; /* vars for timekeeping */
|
||||
#else
|
||||
#define DEB(x)
|
||||
#define DDB(x)
|
||||
#define TICK(x)
|
||||
#define TOCK(x)
|
||||
#endif /* TEST */
|
||||
|
||||
/*
|
||||
* You should not need to change anything beyond this point.
|
||||
* The first part of the file implements linear algebra in GF.
|
||||
*
|
||||
* gf is the type used to store an element of the Galois Field.
|
||||
* Must constain at least GF_BITS bits.
|
||||
*
|
||||
* Note: unsigned char will work up to GF(256) but int seems to run
|
||||
* faster on the Pentium. We use int whenever have to deal with an
|
||||
* index, since they are generally faster.
|
||||
*/
|
||||
#if (GF_BITS < 2 && GF_BITS >16)
|
||||
#error "GF_BITS must be 2 .. 16"
|
||||
#endif
|
||||
#if (GF_BITS <= 8)
|
||||
typedef unsigned char gf;
|
||||
#else
|
||||
typedef unsigned short gf;
|
||||
#endif
|
||||
|
||||
#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
|
||||
|
||||
/*
|
||||
* Primitive polynomials - see Lin & Costello, Appendix A,
|
||||
* and Lee & Messerschmitt, p. 453.
|
||||
*/
|
||||
static const char *allPp[] = { /* GF_BITS polynomial */
|
||||
NULL, /* 0 no code */
|
||||
NULL, /* 1 no code */
|
||||
"111", /* 2 1+x+x^2 */
|
||||
"1101", /* 3 1+x+x^3 */
|
||||
"11001", /* 4 1+x+x^4 */
|
||||
"101001", /* 5 1+x^2+x^5 */
|
||||
"1100001", /* 6 1+x+x^6 */
|
||||
"10010001", /* 7 1 + x^3 + x^7 */
|
||||
"101110001", /* 8 1+x^2+x^3+x^4+x^8 */
|
||||
"1000100001", /* 9 1+x^4+x^9 */
|
||||
"10010000001", /* 10 1+x^3+x^10 */
|
||||
"101000000001", /* 11 1+x^2+x^11 */
|
||||
"1100101000001", /* 12 1+x+x^4+x^6+x^12 */
|
||||
"11011000000001", /* 13 1+x+x^3+x^4+x^13 */
|
||||
"110000100010001", /* 14 1+x+x^6+x^10+x^14 */
|
||||
"1100000000000001", /* 15 1+x+x^15 */
|
||||
"11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* To speed up computations, we have tables for logarithm, exponent
|
||||
* and inverse of a number. If GF_BITS <= 8, we use a table for
|
||||
* multiplication as well (it takes 64K, no big deal even on a PDA,
|
||||
* especially because it can be pre-initialized an put into a ROM!),
|
||||
* otherwhise we use a table of logarithms.
|
||||
* In any case the macro gf_mul(x,y) takes care of multiplications.
|
||||
*/
|
||||
|
||||
static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */
|
||||
static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
|
||||
static gf inverse[GF_SIZE+1]; /* inverse of field elem. */
|
||||
/* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
|
||||
|
||||
/*
|
||||
* modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
|
||||
* without a slow divide.
|
||||
*/
|
||||
static inline gf
|
||||
modnn(int x)
|
||||
{
|
||||
while (x >= GF_SIZE) {
|
||||
x -= GF_SIZE;
|
||||
x = (x >> GF_BITS) + (x & GF_SIZE);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
|
||||
|
||||
/*
|
||||
* gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
|
||||
* faster to use a multiplication table.
|
||||
*
|
||||
* USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
|
||||
* many numbers by the same constant. In this case the first
|
||||
* call sets the constant, and others perform the multiplications.
|
||||
* A value related to the multiplication is held in a local variable
|
||||
* declared with USE_GF_MULC . See usage in addmul1().
|
||||
*/
|
||||
#if (GF_BITS <= 8)
|
||||
static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
|
||||
|
||||
#define gf_mul(x,y) gf_mul_table[x][y]
|
||||
|
||||
#define USE_GF_MULC gf * __gf_mulc_
|
||||
#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
|
||||
#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
|
||||
|
||||
static void
|
||||
init_mul_table()
|
||||
{
|
||||
int i, j;
|
||||
for (i=0; i< GF_SIZE+1; i++)
|
||||
for (j=0; j< GF_SIZE+1; j++)
|
||||
gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
|
||||
|
||||
for (j=0; j< GF_SIZE+1; j++)
|
||||
gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
|
||||
}
|
||||
#else /* GF_BITS > 8 */
|
||||
static inline gf
|
||||
gf_mul(x,y)
|
||||
{
|
||||
if ( (x) == 0 || (y)==0 ) return 0;
|
||||
|
||||
return gf_exp[gf_log[x] + gf_log[y] ] ;
|
||||
}
|
||||
#define init_mul_table()
|
||||
|
||||
#define USE_GF_MULC gf * __gf_mulc_
|
||||
#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
|
||||
#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
|
||||
* Lookup tables:
|
||||
* index->polynomial form gf_exp[] contains j= \alpha^i;
|
||||
* polynomial form -> index form gf_log[ j = \alpha^i ] = i
|
||||
* \alpha=x is the primitive element of GF(2^m)
|
||||
*
|
||||
* For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
|
||||
* multiplication of two numbers can be resolved without calling modnn
|
||||
*/
|
||||
|
||||
/*
|
||||
* i use malloc so many times, it is easier to put checks all in
|
||||
* one place.
|
||||
*/
|
||||
static void *
|
||||
my_malloc(int sz, const char *err_string)
|
||||
{
|
||||
void *p = malloc( sz );
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
|
||||
exit(1) ;
|
||||
}
|
||||
return p ;
|
||||
}
|
||||
|
||||
#define NEW_GF_MATRIX(rows, cols) \
|
||||
(gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
|
||||
|
||||
/*
|
||||
* initialize the data structures used for computations in GF.
|
||||
*/
|
||||
static void
|
||||
generate_gf(void)
|
||||
{
|
||||
int i;
|
||||
gf mask;
|
||||
const char *Pp = allPp[GF_BITS] ;
|
||||
|
||||
mask = 1; /* x ** 0 = 1 */
|
||||
gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
|
||||
/*
|
||||
* first, generate the (polynomial representation of) powers of \alpha,
|
||||
* which are stored in gf_exp[i] = \alpha ** i .
|
||||
* At the same time build gf_log[gf_exp[i]] = i .
|
||||
* The first GF_BITS powers are simply bits shifted to the left.
|
||||
*/
|
||||
for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
|
||||
gf_exp[i] = mask;
|
||||
gf_log[gf_exp[i]] = i;
|
||||
/*
|
||||
* If Pp[i] == 1 then \alpha ** i occurs in poly-repr
|
||||
* gf_exp[GF_BITS] = \alpha ** GF_BITS
|
||||
*/
|
||||
if ( Pp[i] == '1' )
|
||||
gf_exp[GF_BITS] ^= mask;
|
||||
}
|
||||
/*
|
||||
* now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
|
||||
* compute its inverse.
|
||||
*/
|
||||
gf_log[gf_exp[GF_BITS]] = GF_BITS;
|
||||
/*
|
||||
* Poly-repr of \alpha ** (i+1) is given by poly-repr of
|
||||
* \alpha ** i shifted left one-bit and accounting for any
|
||||
* \alpha ** GF_BITS term that may occur when poly-repr of
|
||||
* \alpha ** i is shifted.
|
||||
*/
|
||||
mask = 1 << (GF_BITS - 1 ) ;
|
||||
for (i = GF_BITS + 1; i < GF_SIZE; i++) {
|
||||
if (gf_exp[i - 1] >= mask)
|
||||
gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
|
||||
else
|
||||
gf_exp[i] = gf_exp[i - 1] << 1;
|
||||
gf_log[gf_exp[i]] = i;
|
||||
}
|
||||
/*
|
||||
* log(0) is not defined, so use a special value
|
||||
*/
|
||||
gf_log[0] = GF_SIZE ;
|
||||
/* set the extended gf_exp values for fast multiply */
|
||||
for (i = 0 ; i < GF_SIZE ; i++)
|
||||
gf_exp[i + GF_SIZE] = gf_exp[i] ;
|
||||
|
||||
/*
|
||||
* again special cases. 0 has no inverse. This used to
|
||||
* be initialized to GF_SIZE, but it should make no difference
|
||||
* since noone is supposed to read from here.
|
||||
*/
|
||||
inverse[0] = 0 ;
|
||||
inverse[1] = 1;
|
||||
for (i=2; i<=GF_SIZE; i++)
|
||||
inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
|
||||
}
|
||||
|
||||
/*
|
||||
* Various linear algebra operations that i use often.
|
||||
*/
|
||||
|
||||
/*
|
||||
* addmul() computes dst[] = dst[] + c * src[]
|
||||
* This is used often, so better optimize it! Currently the loop is
|
||||
* unrolled 16 times, a good value for 486 and pentium-class machines.
|
||||
* The case c=0 is also optimized, whereas c=1 is not. These
|
||||
* calls are unfrequent in my typical apps so I did not bother.
|
||||
*
|
||||
* Note that gcc on
|
||||
*/
|
||||
#define addmul(dst, src, c, sz) \
|
||||
if (c != 0) addmul1(dst, src, c, sz)
|
||||
|
||||
#define UNROLL 16 /* 1, 4, 8, 16 */
|
||||
static void
|
||||
addmul1(gf *dst1, gf *src1, gf c, int sz)
|
||||
{
|
||||
USE_GF_MULC ;
|
||||
gf *dst = dst1, *src = src1 ;
|
||||
gf *lim = &dst[sz - UNROLL + 1] ;
|
||||
|
||||
GF_MULC0(c) ;
|
||||
|
||||
#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
|
||||
for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
|
||||
GF_ADDMULC( dst[0] , src[0] );
|
||||
GF_ADDMULC( dst[1] , src[1] );
|
||||
GF_ADDMULC( dst[2] , src[2] );
|
||||
GF_ADDMULC( dst[3] , src[3] );
|
||||
#if (UNROLL > 4)
|
||||
GF_ADDMULC( dst[4] , src[4] );
|
||||
GF_ADDMULC( dst[5] , src[5] );
|
||||
GF_ADDMULC( dst[6] , src[6] );
|
||||
GF_ADDMULC( dst[7] , src[7] );
|
||||
#endif
|
||||
#if (UNROLL > 8)
|
||||
GF_ADDMULC( dst[8] , src[8] );
|
||||
GF_ADDMULC( dst[9] , src[9] );
|
||||
GF_ADDMULC( dst[10] , src[10] );
|
||||
GF_ADDMULC( dst[11] , src[11] );
|
||||
GF_ADDMULC( dst[12] , src[12] );
|
||||
GF_ADDMULC( dst[13] , src[13] );
|
||||
GF_ADDMULC( dst[14] , src[14] );
|
||||
GF_ADDMULC( dst[15] , src[15] );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
lim += UNROLL - 1 ;
|
||||
for (; dst < lim; dst++, src++ ) /* final components */
|
||||
GF_ADDMULC( *dst , *src );
|
||||
}
|
||||
|
||||
/*
|
||||
* computes C = AB where A is n*k, B is k*m, C is n*m
|
||||
*/
|
||||
static void
|
||||
matmul(gf *a, gf *b, gf *c, int n, int k, int m)
|
||||
{
|
||||
int row, col, i ;
|
||||
|
||||
for (row = 0; row < n ; row++) {
|
||||
for (col = 0; col < m ; col++) {
|
||||
gf *pa = &a[ row * k ];
|
||||
gf *pb = &b[ col ];
|
||||
gf acc = 0 ;
|
||||
for (i = 0; i < k ; i++, pa++, pb += m )
|
||||
acc ^= gf_mul( *pa, *pb ) ;
|
||||
c[ row * m + col ] = acc ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* returns 1 if the square matrix is identiy
|
||||
* (only for test)
|
||||
*/
|
||||
static int
|
||||
is_identity(gf *m, int k)
|
||||
{
|
||||
int row, col ;
|
||||
for (row=0; row<k; row++)
|
||||
for (col=0; col<k; col++)
|
||||
if ( (row==col && *m != 1) ||
|
||||
(row!=col && *m != 0) )
|
||||
return 0 ;
|
||||
else
|
||||
m++ ;
|
||||
return 1 ;
|
||||
}
|
||||
#endif /* debug */
|
||||
|
||||
/*
|
||||
* invert_mat() takes a matrix and produces its inverse
|
||||
* k is the size of the matrix.
|
||||
* (Gauss-Jordan, adapted from Numerical Recipes in C)
|
||||
* Return non-zero if singular.
|
||||
*/
|
||||
DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
|
||||
static int
|
||||
invert_mat(gf *src, int k)
|
||||
{
|
||||
gf c, *p ;
|
||||
int irow, icol, row, col, i, ix ;
|
||||
|
||||
int error = 1 ;
|
||||
int *indxc = (int*)my_malloc(k*sizeof(int), "indxc");
|
||||
int *indxr = (int*)my_malloc(k*sizeof(int), "indxr");
|
||||
int *ipiv = (int*)my_malloc(k*sizeof(int), "ipiv");
|
||||
gf *id_row = NEW_GF_MATRIX(1, k);
|
||||
gf *temp_row = NEW_GF_MATRIX(1, k);
|
||||
|
||||
bzero(id_row, k*sizeof(gf));
|
||||
DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
|
||||
/*
|
||||
* ipiv marks elements already used as pivots.
|
||||
*/
|
||||
for (i = 0; i < k ; i++)
|
||||
ipiv[i] = 0 ;
|
||||
|
||||
for (col = 0; col < k ; col++) {
|
||||
gf *pivot_row ;
|
||||
/*
|
||||
* Zeroing column 'col', look for a non-zero element.
|
||||
* First try on the diagonal, if it fails, look elsewhere.
|
||||
*/
|
||||
irow = icol = -1 ;
|
||||
if (ipiv[col] != 1 && src[col*k + col] != 0) {
|
||||
irow = col ;
|
||||
icol = col ;
|
||||
goto found_piv ;
|
||||
}
|
||||
for (row = 0 ; row < k ; row++) {
|
||||
if (ipiv[row] != 1) {
|
||||
for (ix = 0 ; ix < k ; ix++) {
|
||||
DEB( pivloops++ ; )
|
||||
if (ipiv[ix] == 0) {
|
||||
if (src[row*k + ix] != 0) {
|
||||
irow = row ;
|
||||
icol = ix ;
|
||||
goto found_piv ;
|
||||
}
|
||||
} else if (ipiv[ix] > 1) {
|
||||
fprintf(stderr, "singular matrix\n");
|
||||
goto fail ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (icol == -1) {
|
||||
fprintf(stderr, "XXX pivot not found!\n");
|
||||
goto fail ;
|
||||
}
|
||||
found_piv:
|
||||
++(ipiv[icol]) ;
|
||||
/*
|
||||
* swap rows irow and icol, so afterwards the diagonal
|
||||
* element will be correct. Rarely done, not worth
|
||||
* optimizing.
|
||||
*/
|
||||
if (irow != icol) {
|
||||
for (ix = 0 ; ix < k ; ix++ ) {
|
||||
SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
|
||||
}
|
||||
}
|
||||
indxr[col] = irow ;
|
||||
indxc[col] = icol ;
|
||||
pivot_row = &src[icol*k] ;
|
||||
c = pivot_row[icol] ;
|
||||
if (c == 0) {
|
||||
fprintf(stderr, "singular matrix 2\n");
|
||||
goto fail ;
|
||||
}
|
||||
if (c != 1 ) { /* otherwhise this is a NOP */
|
||||
/*
|
||||
* this is done often , but optimizing is not so
|
||||
* fruitful, at least in the obvious ways (unrolling)
|
||||
*/
|
||||
DEB( pivswaps++ ; )
|
||||
c = inverse[ c ] ;
|
||||
pivot_row[icol] = 1 ;
|
||||
for (ix = 0 ; ix < k ; ix++ )
|
||||
pivot_row[ix] = gf_mul(c, pivot_row[ix] );
|
||||
}
|
||||
/*
|
||||
* from all rows, remove multiples of the selected row
|
||||
* to zero the relevant entry (in fact, the entry is not zero
|
||||
* because we know it must be zero).
|
||||
* (Here, if we know that the pivot_row is the identity,
|
||||
* we can optimize the addmul).
|
||||
*/
|
||||
id_row[icol] = 1;
|
||||
if (bcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
|
||||
for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
|
||||
if (ix != icol) {
|
||||
c = p[icol] ;
|
||||
p[icol] = 0 ;
|
||||
addmul(p, pivot_row, c, k );
|
||||
}
|
||||
}
|
||||
}
|
||||
id_row[icol] = 0;
|
||||
} /* done all columns */
|
||||
for (col = k-1 ; col >= 0 ; col-- ) {
|
||||
if (indxr[col] <0 || indxr[col] >= k)
|
||||
fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
|
||||
else if (indxc[col] <0 || indxc[col] >= k)
|
||||
fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
|
||||
else
|
||||
if (indxr[col] != indxc[col] ) {
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
error = 0 ;
|
||||
fail:
|
||||
free(indxc);
|
||||
free(indxr);
|
||||
free(ipiv);
|
||||
free(id_row);
|
||||
free(temp_row);
|
||||
return error ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fast code for inverting a vandermonde matrix.
|
||||
* XXX NOTE: It assumes that the matrix
|
||||
* is not singular and _IS_ a vandermonde matrix. Only uses
|
||||
* the second column of the matrix, containing the p_i's.
|
||||
*
|
||||
* Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
|
||||
* largely revised for my purposes.
|
||||
* p = coefficients of the matrix (p_i)
|
||||
* q = values of the polynomial (known)
|
||||
*/
|
||||
|
||||
int
|
||||
invert_vdm(gf *src, int k)
|
||||
{
|
||||
int i, j, row, col ;
|
||||
gf *b, *c, *p;
|
||||
gf t, xx ;
|
||||
|
||||
if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
|
||||
return 0 ;
|
||||
/*
|
||||
* c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
|
||||
* b holds the coefficient for the matrix inversion
|
||||
*/
|
||||
c = NEW_GF_MATRIX(1, k);
|
||||
b = NEW_GF_MATRIX(1, k);
|
||||
|
||||
p = NEW_GF_MATRIX(1, k);
|
||||
|
||||
for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
|
||||
c[i] = 0 ;
|
||||
p[i] = src[j] ; /* p[i] */
|
||||
}
|
||||
/*
|
||||
* construct coeffs. recursively. We know c[k] = 1 (implicit)
|
||||
* and start P_0 = x - p_0, then at each stage multiply by
|
||||
* x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
|
||||
* After k steps we are done.
|
||||
*/
|
||||
c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
|
||||
for (i = 1 ; i < k ; i++ ) {
|
||||
gf p_i = p[i] ; /* see above comment */
|
||||
for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
|
||||
c[j] ^= gf_mul( p_i, c[j+1] ) ;
|
||||
c[k-1] ^= p_i ;
|
||||
}
|
||||
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
/*
|
||||
* synthetic division etc.
|
||||
*/
|
||||
xx = p[row] ;
|
||||
t = 1 ;
|
||||
b[k-1] = 1 ; /* this is in fact c[k] */
|
||||
for (i = k-2 ; i >= 0 ; i-- ) {
|
||||
b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
|
||||
t = gf_mul(xx, t) ^ b[i] ;
|
||||
}
|
||||
for (col = 0 ; col < k ; col++ )
|
||||
src[col*k + row] = gf_mul(inverse[t], b[col] );
|
||||
}
|
||||
free(c) ;
|
||||
free(b) ;
|
||||
free(p) ;
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
static int fec_initialized = 0 ;
|
||||
static void
|
||||
init_fec()
|
||||
{
|
||||
TICK(ticks[0]);
|
||||
generate_gf();
|
||||
TOCK(ticks[0]);
|
||||
DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
|
||||
TICK(ticks[0]);
|
||||
init_mul_table();
|
||||
TOCK(ticks[0]);
|
||||
DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
|
||||
fec_initialized = 1 ;
|
||||
}
|
||||
|
||||
/*
|
||||
* This section contains the proper FEC encoding/decoding routines.
|
||||
* The encoding matrix is computed starting with a Vandermonde matrix,
|
||||
* and then transforming it into a systematic matrix.
|
||||
*/
|
||||
|
||||
#define FEC_MAGIC 0xFECC0DEC
|
||||
|
||||
struct fec_parms {
|
||||
u_long magic ;
|
||||
int k, n ; /* parameters of the code */
|
||||
gf *enc_matrix ;
|
||||
} ;
|
||||
|
||||
void
|
||||
fec_free(void *p0)
|
||||
{
|
||||
struct fec_parms *p= (struct fec_parms *) p0;
|
||||
if (p==NULL ||
|
||||
p->magic != ( ( (FEC_MAGIC ^ p->k) ^ p->n) ^ (int)((long)p->enc_matrix)) ) {
|
||||
fprintf(stderr, "bad parameters to fec_free\n");
|
||||
return ;
|
||||
}
|
||||
free(p->enc_matrix);
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* create a new encoder, returning a descriptor. This contains k,n and
|
||||
* the encoding matrix.
|
||||
*/
|
||||
struct fec_parms *
|
||||
fec_new(int k, int n)
|
||||
{
|
||||
int row, col ;
|
||||
gf *p, *tmp_m ;
|
||||
|
||||
struct fec_parms *retval ;
|
||||
|
||||
if (fec_initialized == 0)
|
||||
init_fec();
|
||||
|
||||
if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
|
||||
fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
|
||||
k, n, GF_SIZE );
|
||||
return NULL ;
|
||||
}
|
||||
retval = (struct fec_parms *)my_malloc(sizeof(struct fec_parms), "new_code");
|
||||
retval->k = k ;
|
||||
retval->n = n ;
|
||||
retval->enc_matrix = NEW_GF_MATRIX(n, k);
|
||||
retval->magic = ( ( FEC_MAGIC ^ k) ^ n) ^ (int)((long)retval->enc_matrix) ;
|
||||
tmp_m = NEW_GF_MATRIX(n, k);
|
||||
/*
|
||||
* fill the matrix with powers of field elements, starting from 0.
|
||||
* The first row is special, cannot be computed with exp. table.
|
||||
*/
|
||||
tmp_m[0] = 1 ;
|
||||
for (col = 1; col < k ; col++)
|
||||
tmp_m[col] = 0 ;
|
||||
for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
|
||||
for ( col = 0 ; col < k ; col ++ )
|
||||
p[col] = gf_exp[modnn(row*col)];
|
||||
}
|
||||
|
||||
/*
|
||||
* quick code to build systematic matrix: invert the top
|
||||
* k*k vandermonde matrix, multiply right the bottom n-k rows
|
||||
* by the inverse, and construct the identity matrix at the top.
|
||||
*/
|
||||
TICK(ticks[3]);
|
||||
invert_vdm(tmp_m, k); /* much faster than invert_mat */
|
||||
matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
|
||||
/*
|
||||
* the upper matrix is I so do not bother with a slow multiply
|
||||
*/
|
||||
bzero(retval->enc_matrix, k*k*sizeof(gf) );
|
||||
for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
|
||||
*p = 1 ;
|
||||
free(tmp_m);
|
||||
TOCK(ticks[3]);
|
||||
|
||||
DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
|
||||
ticks[3]);)
|
||||
DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
|
||||
return retval ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fec_encode accepts as input pointers to n data packets of size sz,
|
||||
* and produces as output a packet pointed to by fec, computed
|
||||
* with index "index".
|
||||
*/
|
||||
void
|
||||
fec_encode(void *code0, void *src0[], void *fec0, int index, int sz)
|
||||
//fec_encode(struct fec_parms *code0, gf *src[], gf *fec, int index, int sz)
|
||||
{
|
||||
struct fec_parms * code= (struct fec_parms *)code0;
|
||||
gf **src=(gf**) src0;
|
||||
gf* fec=(gf*)fec0;
|
||||
int i, k = code->k ;
|
||||
gf *p ;
|
||||
|
||||
if (GF_BITS > 8)
|
||||
sz /= 2 ;
|
||||
|
||||
if (index < k)
|
||||
bcopy(src[index], fec, sz*sizeof(gf) ) ;
|
||||
else if (index < code->n) {
|
||||
p = &(code->enc_matrix[index*k] );
|
||||
bzero(fec, sz*sizeof(gf));
|
||||
for (i = 0; i < k ; i++)
|
||||
addmul(fec, src[i], p[i], sz ) ;
|
||||
} else
|
||||
fprintf(stderr, "Invalid index %d (max %d)\n",
|
||||
index, code->n - 1 );
|
||||
}
|
||||
|
||||
/*
|
||||
* shuffle move src packets in their position
|
||||
*/
|
||||
static int
|
||||
shuffle(gf *pkt[], int index[], int k)
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0 ; i < k ; ) {
|
||||
if (index[i] >= k || index[i] == i)
|
||||
i++ ;
|
||||
else {
|
||||
/*
|
||||
* put pkt in the right position (first check for conflicts).
|
||||
*/
|
||||
int c = index[i] ;
|
||||
|
||||
if (index[c] == c) {
|
||||
DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
|
||||
return 1 ;
|
||||
}
|
||||
SWAP(index[i], index[c], int) ;
|
||||
SWAP(pkt[i], pkt[c], gf *) ;
|
||||
}
|
||||
}
|
||||
DEB( /* just test that it works... */
|
||||
for ( i = 0 ; i < k ; i++ ) {
|
||||
if (index[i] < k && index[i] != i) {
|
||||
fprintf(stderr, "shuffle: after\n");
|
||||
for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
|
||||
fprintf(stderr, "\n");
|
||||
return 1 ;
|
||||
}
|
||||
}
|
||||
)
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
/*
|
||||
* build_decode_matrix constructs the encoding matrix given the
|
||||
* indexes. The matrix must be already allocated as
|
||||
* a vector of k*k elements, in row-major order
|
||||
*/
|
||||
static gf *
|
||||
build_decode_matrix(struct fec_parms *code, gf *pkt[], int index[])
|
||||
{
|
||||
int i , k = code->k ;
|
||||
gf *p, *matrix = NEW_GF_MATRIX(k, k);
|
||||
|
||||
TICK(ticks[9]);
|
||||
for (i = 0, p = matrix ; i < k ; i++, p += k ) {
|
||||
#if 1 /* this is simply an optimization, not very useful indeed */
|
||||
if (index[i] < k) {
|
||||
bzero(p, k*sizeof(gf) );
|
||||
p[i] = 1 ;
|
||||
} else
|
||||
#endif
|
||||
if (index[i] < code->n )
|
||||
bcopy( &(code->enc_matrix[index[i]*k]), p, k*sizeof(gf) );
|
||||
else {
|
||||
fprintf(stderr, "decode: invalid index %d (max %d)\n",
|
||||
index[i], code->n - 1 );
|
||||
free(matrix) ;
|
||||
return NULL ;
|
||||
}
|
||||
}
|
||||
TICK(ticks[9]);
|
||||
if (invert_mat(matrix, k)) {
|
||||
free(matrix);
|
||||
matrix = NULL ;
|
||||
}
|
||||
TOCK(ticks[9]);
|
||||
return matrix ;
|
||||
}
|
||||
|
||||
/*
|
||||
* fec_decode receives as input a vector of packets, the indexes of
|
||||
* packets, and produces the correct vector as output.
|
||||
*
|
||||
* Input:
|
||||
* code: pointer to code descriptor
|
||||
* pkt: pointers to received packets. They are modified
|
||||
* to store the output packets (in place)
|
||||
* index: pointer to packet indexes (modified)
|
||||
* sz: size of each packet
|
||||
*/
|
||||
int
|
||||
fec_decode(void *code0, void *pkt0[], int index[], int sz)
|
||||
//fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
|
||||
{
|
||||
struct fec_parms * code=(struct fec_parms*)code0;
|
||||
gf **pkt=(gf**)pkt0;
|
||||
gf *m_dec ;
|
||||
gf **new_pkt ;
|
||||
int row, col , k = code->k ;
|
||||
|
||||
if (GF_BITS > 8)
|
||||
sz /= 2 ;
|
||||
|
||||
if (shuffle(pkt, index, k)) /* error if true */
|
||||
return 1 ;
|
||||
m_dec = build_decode_matrix(code, pkt, index);
|
||||
|
||||
if (m_dec == NULL)
|
||||
return 1 ; /* error */
|
||||
/*
|
||||
* do the actual decoding
|
||||
*/
|
||||
new_pkt = (gf** )my_malloc (k * sizeof (gf * ), "new pkt pointers" );
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
if (index[row] >= k) {
|
||||
new_pkt[row] = (gf*)my_malloc (sz * sizeof (gf), "new pkt buffer" );
|
||||
bzero(new_pkt[row], sz * sizeof(gf) ) ;
|
||||
for (col = 0 ; col < k ; col++ )
|
||||
addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* move pkts to their final destination
|
||||
*/
|
||||
for (row = 0 ; row < k ; row++ ) {
|
||||
if (index[row] >= k) {
|
||||
bcopy(new_pkt[row], pkt[row], sz*sizeof(gf));
|
||||
free(new_pkt[row]);
|
||||
}
|
||||
}
|
||||
free(new_pkt);
|
||||
free(m_dec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int get_n(void *code0)
|
||||
{
|
||||
struct fec_parms * code= (struct fec_parms *)code0;
|
||||
return code->n;
|
||||
}
|
||||
int get_k(void *code0)
|
||||
{
|
||||
struct fec_parms * code= (struct fec_parms *)code0;
|
||||
return code->k;
|
||||
}
|
||||
/*********** end of FEC code -- beginning of test code ************/
|
||||
|
||||
#if (TEST || DEBUG)
|
||||
void
|
||||
test_gf()
|
||||
{
|
||||
int i ;
|
||||
/*
|
||||
* test gf tables. Sufficiently tested...
|
||||
*/
|
||||
for (i=0; i<= GF_SIZE; i++) {
|
||||
if (gf_exp[gf_log[i]] != i)
|
||||
fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n",
|
||||
i, gf_log[i], gf_exp[gf_log[i]]);
|
||||
|
||||
if (i != 0 && gf_mul(i, inverse[i]) != 1)
|
||||
fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n",
|
||||
i, inverse[i], gf_mul(i, inverse[i]) );
|
||||
if (gf_mul(0,i) != 0)
|
||||
fprintf(stderr, "bad mul table 0,%d\n",i);
|
||||
if (gf_mul(i,0) != 0)
|
||||
fprintf(stderr, "bad mul table %d,0\n",i);
|
||||
}
|
||||
}
|
||||
#endif /* TEST */
|
56
lib/fec.h
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* fec.c -- forward error correction based on Vandermonde matrices
|
||||
* 980614
|
||||
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
|
||||
*
|
||||
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
|
||||
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
|
||||
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
||||
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
* OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The following parameter defines how many bits are used for
|
||||
* field elements. The code supports any value from 2 to 16
|
||||
* but fastest operation is achieved with 8 bit elements
|
||||
* This is the only parameter you may want to change.
|
||||
*/
|
||||
#ifndef GF_BITS
|
||||
#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
|
||||
#endif
|
||||
|
||||
#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
|
||||
void fec_free(void *p) ;
|
||||
void * fec_new(int k, int n) ;//n>=k
|
||||
|
||||
void init_fec() ; //if you never called this,it will be automatically called in fec_new()
|
||||
void fec_encode(void *code, void *src[], void *dst, int index, int sz) ;
|
||||
int fec_decode(void *code, void *pkt[], int index[], int sz) ;
|
||||
|
||||
int get_k(void *code);
|
||||
int get_n(void *code);
|
||||
|
||||
/* end of file */
|
76
lib/rs.cpp
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* rs.c
|
||||
*
|
||||
* Created on: Sep 14, 2017
|
||||
* Author: root
|
||||
*/
|
||||
#include "rs.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
void rs_encode(void *code,char *data[],int size)
|
||||
{
|
||||
int k=get_k(code);
|
||||
int n=get_n(code);
|
||||
for(int i=k;i<n;i++)
|
||||
{
|
||||
fec_encode(code, (void **)data, data[i],i, size);
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
int rs_decode(void *code,char *data[],int size)
|
||||
{
|
||||
int k=get_k(code);
|
||||
int n=get_n(code);
|
||||
int index[n];
|
||||
int count=0;
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
if(data[i]!=0)
|
||||
{
|
||||
index[count++]=i;
|
||||
}
|
||||
}
|
||||
if(count<k)
|
||||
return -1;
|
||||
for(int i=0;i<n;i++)
|
||||
{
|
||||
if(i<count)
|
||||
data[i]=data[index[i]];
|
||||
else
|
||||
data[i]=0;
|
||||
}
|
||||
return fec_decode(code,(void**)data,index,size);
|
||||
}
|
||||
|
||||
static void * (*table)[256]=0;
|
||||
void* get_code(int k,int n)
|
||||
{
|
||||
if (table==0)
|
||||
{
|
||||
table=(void* (*)[256]) malloc(sizeof(void*)*256*256);
|
||||
if(!table)
|
||||
{
|
||||
return table;
|
||||
}
|
||||
memset(table,0,sizeof(void*)*256*256);
|
||||
}
|
||||
if(table[k][n]==0)
|
||||
{
|
||||
table[k][n]=fec_new(k,n);
|
||||
}
|
||||
return table[k][n];
|
||||
}
|
||||
void rs_encode2(int k,int n,char *data[],int size)
|
||||
{
|
||||
void* code=get_code(k,n);
|
||||
rs_encode(code,data,size);
|
||||
}
|
||||
|
||||
int rs_decode2(int k,int n,char *data[],int size)
|
||||
{
|
||||
void* code=get_code(k,n);
|
||||
return rs_decode(code,data,size);
|
||||
}
|
51
lib/rs.h
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* rs.h
|
||||
*
|
||||
* Created on: Sep 14, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef LIB_RS_H_
|
||||
#define LIB_RS_H_
|
||||
|
||||
#include "fec.h"
|
||||
|
||||
// input:
|
||||
// code, generated by fec_new() function from fec.h
|
||||
// data[0....k-1 ], points to original data
|
||||
// size, data length
|
||||
//
|
||||
// output:
|
||||
// data[k....n-1], points to generated redundant data
|
||||
//
|
||||
// info:
|
||||
// the function will always succeed,except malloc fail.if malloc fail,it will call exit()
|
||||
void rs_encode(void *code,char *data[],int size);
|
||||
|
||||
|
||||
// input:
|
||||
// data[0.....n-1] points to original data and redundate data,in right order
|
||||
// if data[i] is missing ,set poniter data[i] to 0 (point it to null)
|
||||
//
|
||||
// outout:
|
||||
// data[0.....k-1] will point to the recovered original data.
|
||||
//
|
||||
// info:
|
||||
// return zero on success
|
||||
// if the number of no-zero pointers is less than k,the function will fail and return non-zero
|
||||
//
|
||||
// advanced info:
|
||||
// 1. rs_decode wont malloc memory for those zero pointers in data[0.....k-1]. instead it will re-use the memory of other non-zero pointers (and let data[0.....k-1] point to those memory).
|
||||
// 2. if the input data[0.....n-1] contains x non-zero pointers,after called rs_decode,there will still be exactly x non-zero poninters in data[0.....n-1],just the order may change.
|
||||
int rs_decode(void *code,char *data[],int size);
|
||||
|
||||
|
||||
void rs_encode2(int k,int n,char *data[],int size);
|
||||
|
||||
int rs_decode2(int k,int n,char *data[],int size);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* LIB_RS_H_ */
|
@@ -1,31 +0,0 @@
|
||||
/Changes/1.315/Wed Jun 21 14:42:30 2017//
|
||||
/LICENSE/1.11/Thu Jan 16 11:51:05 2014//
|
||||
/Makefile.am/1.9/Wed Dec 21 18:16:08 2011//
|
||||
/README/1.21/Fri Mar 30 17:43:55 2012//
|
||||
/README.embed/1.29/Sat Nov 24 10:10:26 2007//
|
||||
/Symbols.ev/1.14/Tue Jan 11 13:45:28 2011//
|
||||
/Symbols.event/1.4/Tue May 8 15:52:13 2012//
|
||||
/autogen.sh/1.3/Mon May 30 15:28:54 2011//
|
||||
/configure.ac/1.42/Wed Dec 28 04:22:06 2016//
|
||||
/ev++.h/1.63/Fri Dec 1 06:37:30 2017//
|
||||
/ev.3/1.107/Wed Jun 21 14:42:30 2017//
|
||||
/ev.c/1.481/Thu Jun 1 20:25:50 2017//
|
||||
/ev.h/1.187/Wed Dec 28 04:22:06 2016//
|
||||
/ev.pod/1.441/Thu Jul 13 10:46:52 2017//
|
||||
/ev_epoll.c/1.72/Wed Jun 21 14:42:30 2017//
|
||||
/ev_kqueue.c/1.56/Thu Feb 18 04:48:05 2016//
|
||||
/ev_poll.c/1.40/Thu Feb 18 04:48:05 2016//
|
||||
/ev_port.c/1.29/Thu Feb 18 04:48:05 2016//
|
||||
/ev_select.c/1.56/Thu Feb 18 04:48:05 2016//
|
||||
/ev_vars.h/1.58/Tue Sep 9 21:51:35 2014//
|
||||
/ev_win32.c/1.18/Thu Nov 12 07:02:37 2015//
|
||||
/ev_wrap.h/1.38/Tue Nov 6 20:56:50 2012//
|
||||
/event.c/1.52/Mon Apr 2 23:14:41 2012//
|
||||
/event.h/1.26/Mon Apr 2 23:15:27 2012//
|
||||
/event_compat.h/1.8/Wed Feb 16 08:02:51 2011//
|
||||
/import_libevent/1.29/Tue Apr 15 04:34:07 2008//
|
||||
/libev.m4/1.16/Mon Oct 28 12:36:44 2013//
|
||||
/update_ev_c/1.2/Wed Jan 18 12:13:14 2012//
|
||||
/update_ev_wrap/1.6/Sun May 6 13:09:29 2012//
|
||||
/update_symbols/1.1/Wed Dec 19 01:59:29 2007//
|
||||
D
|
@@ -1 +0,0 @@
|
||||
libev
|
@@ -1 +0,0 @@
|
||||
:pserver:anonymous@cvs.schmorp.de/schmorpforge
|
517
libev/Changes
@@ -1,517 +0,0 @@
|
||||
Revision history for libev, a high-performance and full-featured event loop.
|
||||
|
||||
- ANDROID => __ANDROID__ (reported by enh@google.com).
|
||||
- disable epoll_create1 on android because it has broken header files
|
||||
and google is unwilling to fix them (reported by enh@google.com).
|
||||
|
||||
4.24 Wed Dec 28 05:19:55 CET 2016
|
||||
- bump version to 4.24, as the release tarball inexplicably
|
||||
didn't have the right version in ev.h, even though the cvs-tagged
|
||||
version did have the right one (reported by Ales Teska).
|
||||
|
||||
4.23 Wed Nov 16 18:23:41 CET 2016
|
||||
- move some declarations at the beginning to help certain retarded
|
||||
microsoft compilers, even though their documentation claims
|
||||
otherwise (reported by Ruslan Osmanov).
|
||||
|
||||
4.22 Sun Dec 20 22:11:50 CET 2015
|
||||
- when epoll detects unremovable fds in the fd set, rebuild
|
||||
only the epoll descriptor, not the signal pipe, to avoid
|
||||
SIGPIPE in ev_async_send. This doesn't solve it on fork,
|
||||
so document what needs to be done in ev_loop_fork
|
||||
(analyzed by Benjamin Mahler).
|
||||
- remove superfluous sys/timeb.h include on win32
|
||||
(analyzed by Jason Madden).
|
||||
- updated libecb.
|
||||
|
||||
4.20 Sat Jun 20 13:01:43 CEST 2015
|
||||
- prefer noexcept over throw () with C++ 11.
|
||||
- update ecb.h due to incompatibilities with c11.
|
||||
- fix a potential aliasing issue when reading and writing
|
||||
watcher callbacks.
|
||||
|
||||
4.19 Thu Sep 25 08:18:25 CEST 2014
|
||||
- ev.h wasn't valid C++ anymore, which tripped compilers other than
|
||||
clang, msvc or gcc (analyzed by Raphael 'kena' Poss). Unfortunately,
|
||||
C++ doesn't support typedefs for function pointers fully, so the affected
|
||||
declarations have to spell out the types each time.
|
||||
- when not using autoconf, tighten the check for clock_gettime and related
|
||||
functionality.
|
||||
|
||||
4.18 Fri Sep 5 17:55:26 CEST 2014
|
||||
- events on files were not always generated properly with the
|
||||
epoll backend (testcase by Assaf Inbal).
|
||||
- mark event pipe fd as cloexec after a fork (analyzed by Sami Farin).
|
||||
- (ecb) support m68k, m88k and sh (patch by Miod Vallat).
|
||||
- use a reasonable fallback for EV_NSIG instead of erroring out
|
||||
when we can't detect the signal set size.
|
||||
- in the absence of autoconf, do not use the clock syscall
|
||||
on glibc >= 2.17 (avoids the syscall AND -lrt on systems
|
||||
doing clock_gettime in userspace).
|
||||
- ensure extern "C" function pointers are used for externally-visible
|
||||
loop callbacks (not watcher callbacks yet).
|
||||
- (ecb) work around memory barriers and volatile apparently both being
|
||||
broken in visual studio 2008 and later (analysed and patch by Nicolas Noble).
|
||||
|
||||
4.15 Fri Mar 1 12:04:50 CET 2013
|
||||
- destroying a non-default loop would stop the global waitpid
|
||||
watcher (Denis Bilenko).
|
||||
- queueing pending watchers of higher priority from a watcher now invokes
|
||||
them in a timely fashion (reported by Denis Bilenko).
|
||||
- add throw() to all libev functions that cannot throw exceptions, for
|
||||
further code size decrease when compiling for C++.
|
||||
- add throw () to callbacks that must not throw exceptions (allocator,
|
||||
syserr, loop acquire/release, periodic reschedule cbs).
|
||||
- fix event_base_loop return code, add event_get_callback, event_base_new,
|
||||
event_base_get_method calls to improve libevent 1.x emulation and add
|
||||
some libevent 2.x functionality (based on a patch by Jeff Davey).
|
||||
- add more memory fences to fix a bug reported by Jeff Davey. Better
|
||||
be overfenced than underprotected.
|
||||
- ev_run now returns a boolean status (true meaning watchers are
|
||||
still active).
|
||||
- ev_once: undef EV_ERROR in ev_kqueue.c, to avoid clashing with
|
||||
libev's EV_ERROR (reported by 191919).
|
||||
- (ecb) add memory fence support for xlC (Darin McBride).
|
||||
- (ecb) add memory fence support for gcc-mips (Anton Kirilov).
|
||||
- (ecb) add memory fence support for gcc-alpha (Christian Weisgerber).
|
||||
- work around some kernels losing file descriptors by leaking
|
||||
the kqueue descriptor in the child.
|
||||
- work around linux inotify not reporting IN_ATTRIB changes for directories
|
||||
in many cases.
|
||||
- include sys/syscall.h instead of plain syscall.h.
|
||||
- check for io watcher loops in ev_verify, check for the most
|
||||
common reported usage bug in ev_io_start.
|
||||
- choose socket vs. WSASocket at compiletime using EV_USE_WSASOCKET.
|
||||
- always use WSASend/WSARecv directly on windows, hoping that this
|
||||
works in all cases (unlike read/write/send/recv...).
|
||||
- try to detect signals around a fork faster (test program by
|
||||
Denis Bilenko).
|
||||
- work around recent glibc versions that leak memory in realloc.
|
||||
- rename ev::embed::set to ev::embed::set_embed to avoid clashing
|
||||
the watcher base set (loop) method.
|
||||
- rewrite the async/signal pipe logic to always keep a valid fd, which
|
||||
simplifies (and hopefully correctifies :) the race checking
|
||||
on fork, at the cost of one extra fd.
|
||||
- add fat, msdos, jffs2, ramfs, ntfs and btrfs to the list of
|
||||
inotify-supporting filesystems.
|
||||
- move orig_CFLAGS assignment to after AC_INIT, as newer autoconf
|
||||
versions ignore it before
|
||||
(https://bugzilla.redhat.com/show_bug.cgi?id=908096).
|
||||
- add some untested android support.
|
||||
- enum expressions must be of type int (reported by Juan Pablo L).
|
||||
|
||||
4.11 Sat Feb 4 19:52:39 CET 2012
|
||||
- INCOMPATIBLE CHANGE: ev_timer_again now clears the pending status, as
|
||||
was documented already, but not implemented in the repeating case.
|
||||
- new compiletime symbols: EV_NO_SMP and EV_NO_THREADS.
|
||||
- fix a race where the workaround against the epoll fork bugs
|
||||
caused signals to not be handled anymore.
|
||||
- correct backend_fudge for most backends, and implement a windows
|
||||
specific workaround to avoid looping because we call both
|
||||
select and Sleep, both with different time resolutions.
|
||||
- document range and guarantees of ev_sleep.
|
||||
- document reasonable ranges for periodics interval and offset.
|
||||
- rename backend_fudge to backend_mintime to avoid future confusion :)
|
||||
- change the default periodic reschedule function to hopefully be more
|
||||
exact and correct even in corner cases or in the far future.
|
||||
- do not rely on -lm anymore: use it when available but use our
|
||||
own floor () if it is missing. This should make it easier to embed,
|
||||
as no external libraries are required.
|
||||
- strategically import macros from libecb and mark rarely-used functions
|
||||
as cache-cold (saving almost 2k code size on typical amd64 setups).
|
||||
- add Symbols.ev and Symbols.event files, that were missing.
|
||||
- fix backend_mintime value for epoll (was 1/1024, is 1/1000 now).
|
||||
- fix #3 "be smart about timeouts" to not "deadlock" when
|
||||
timeout == now, also improve the section overall.
|
||||
- avoid "AVOIDING FINISHING BEFORE RETURNING" idiom.
|
||||
- support new EV_API_STATIC mode to make all libev symbols
|
||||
static.
|
||||
- supply default CFLAGS of -g -O3 with gcc when original CFLAGS
|
||||
were empty.
|
||||
|
||||
4.04 Wed Feb 16 09:01:51 CET 2011
|
||||
- fix two problems in the native win32 backend, where reuse of fd's
|
||||
with different underlying handles caused handles not to be removed
|
||||
or added to the select set (analyzed and tested by Bert Belder).
|
||||
- do no rely on ceil() in ev_e?poll.c.
|
||||
- backport libev to HP-UX versions before 11 v3.
|
||||
- configure did not detect nanosleep and clock_gettime properly when
|
||||
they are available in the libc (as opposed to -lrt).
|
||||
|
||||
4.03 Tue Jan 11 14:37:25 CET 2011
|
||||
- officially support polling files with all backends.
|
||||
- support files, /dev/zero etc. the same way as select in the epoll
|
||||
backend, by generating events on our own.
|
||||
- ports backend: work around solaris bug 6874410 and many related ones
|
||||
(EINTR, maybe more), with no performance loss (note that the solaris
|
||||
bug report is actually wrong, reality is far more bizarre and broken
|
||||
than that).
|
||||
- define EV_READ/EV_WRITE as macros in event.h, as some programs use
|
||||
#ifdef to test for them.
|
||||
- new (experimental) function: ev_feed_signal.
|
||||
- new (to become default) EVFLAG_NOSIGMASK flag.
|
||||
- new EVBACKEND_MASK symbol.
|
||||
- updated COMMON IDIOMS SECTION.
|
||||
|
||||
4.01 Fri Nov 5 21:51:29 CET 2010
|
||||
- automake fucked it up, apparently, --add-missing -f is not quite enough
|
||||
to make it update its files, so 4.00 didn't install ev++.h and
|
||||
event.h on make install. grrr.
|
||||
- ev_loop(count|depth) didn't return anything (Robin Haberkorn).
|
||||
- change EV_UNDEF to 0xffffffff to silence some overzealous compilers.
|
||||
- use "(libev) " prefix for all libev error messages now.
|
||||
|
||||
4.00 Mon Oct 25 12:32:12 CEST 2010
|
||||
- "PORTING FROM LIBEV 3.X TO 4.X" (in ev.pod) is recommended reading.
|
||||
- ev_embed_stop did not correctly stop the watcher (very good
|
||||
testcase by Vladimir Timofeev).
|
||||
- ev_run will now always update the current loop time - it erroneously
|
||||
didn't when idle watchers were active, causing timers not to fire.
|
||||
- fix a bug where a timeout of zero caused the timer not to fire
|
||||
in the libevent emulation (testcase by Péter Szabó).
|
||||
- applied win32 fixes by Michael Lenaghan (also James Mansion).
|
||||
- replace EV_MINIMAL by EV_FEATURES.
|
||||
- prefer EPOLL_CTL_ADD over EPOLL_CTL_MOD in some more cases, as it
|
||||
seems the former is *much* faster than the latter.
|
||||
- linux kernel version detection (for inotify bug workarounds)
|
||||
did not work properly.
|
||||
- reduce the number of spurious wake-ups with the ports backend.
|
||||
- remove dependency on sys/queue.h on freebsd (patch by Vanilla Hsu).
|
||||
- do async init within ev_async_start, not ev_async_set, which avoids
|
||||
an API quirk where the set function must be called in the C++ API
|
||||
even when there is nothing to set.
|
||||
- add (undocumented) EV_ENABLE when adding events with kqueue,
|
||||
this might help with OS X, which seems to need it despite documenting
|
||||
not to need it (helpfully pointed out by Tilghman Lesher).
|
||||
- do not use poll by default on freebsd, it's broken (what isn't
|
||||
on freebsd...).
|
||||
- allow to embed epoll on kernels >= 2.6.32.
|
||||
- configure now prepends -O3, not appends it, so one can still
|
||||
override it.
|
||||
- ev.pod: greatly expanded the portability section, added a porting
|
||||
section, a description of watcher states and made lots of minor fixes.
|
||||
- disable poll backend on AIX, the poll header spams the namespace
|
||||
and it's not worth working around dead platforms (reported
|
||||
and analyzed by Aivars Kalvans).
|
||||
- improve header file compatibility of the standalone eventfd code
|
||||
in an obscure case.
|
||||
- implement EV_AVOID_STDIO option.
|
||||
- do not use sscanf to parse linux version number (smaller, faster,
|
||||
no sscanf dependency).
|
||||
- new EV_CHILD_ENABLE and EV_SIGNAL_ENABLE configurable settings.
|
||||
- update libev.m4 HAVE_CLOCK_SYSCALL test for newer glibcs.
|
||||
- add section on accept() problems to the manpage.
|
||||
- rename EV_TIMEOUT to EV_TIMER.
|
||||
- rename ev_loop_count/depth/verify/loop/unloop.
|
||||
- remove ev_default_destroy and ev_default_fork.
|
||||
- switch to two-digit minor version.
|
||||
- work around an apparent gentoo compiler bug.
|
||||
- define _DARWIN_UNLIMITED_SELECT. just so.
|
||||
- use enum instead of #define for most constants.
|
||||
- improve compatibility to older C++ compilers.
|
||||
- (experimental) ev_run/ev_default_loop/ev_break/ev_loop_new have now
|
||||
default arguments when compiled as C++.
|
||||
- enable automake dependency tracking.
|
||||
- ev_loop_new no longer leaks memory when loop creation failed.
|
||||
- new ev_cleanup watcher type.
|
||||
|
||||
3.9 Thu Dec 31 07:59:59 CET 2009
|
||||
- signalfd is no longer used by default and has to be requested
|
||||
explicitly - this means that easy to catch bugs become hard to
|
||||
catch race conditions, but the users have spoken.
|
||||
- point out the unspecified signal mask in the documentation, and
|
||||
that this is a race condition regardless of EV_SIGNALFD.
|
||||
- backport inotify code to C89.
|
||||
- inotify file descriptors could leak into child processes.
|
||||
- ev_stat watchers could keep an erroneous extra ref on the loop,
|
||||
preventing exit when unregistering all watchers (testcases
|
||||
provided by ry@tinyclouds.org).
|
||||
- implement EV_WIN32_HANDLE_TO_FD and EV_WIN32_CLOSE_FD configuration
|
||||
symbols to make it easier for apps to do their own fd management.
|
||||
- support EV_IDLE_ENABLE being disabled in ev++.h
|
||||
(patch by Didier Spezia).
|
||||
- take advantage of inotify_init1, if available, to set cloexec/nonblock
|
||||
on fd creation, to avoid races.
|
||||
- the signal handling pipe wasn't always initialised under windows
|
||||
(analysed by lekma).
|
||||
- changed minimum glibc requirement from glibc 2.9 to 2.7, for
|
||||
signalfd.
|
||||
- add missing string.h include (Denis F. Latypoff).
|
||||
- only replace ev_stat.prev when we detect an actual difference,
|
||||
so prev is (almost) always different to attr. this might
|
||||
have caused the problems with 04_stat.t.
|
||||
- add ev::timer->remaining () method to C++ API.
|
||||
|
||||
3.8 Sun Aug 9 14:30:45 CEST 2009
|
||||
- incompatible change: do not necessarily reset signal handler
|
||||
to SIG_DFL when a sighandler is stopped.
|
||||
- ev_default_destroy did not properly free or zero some members,
|
||||
potentially causing crashes and memory corruption on repeated
|
||||
ev_default_destroy/ev_default_loop calls.
|
||||
- take advantage of signalfd on GNU/Linux systems.
|
||||
- document that the signal mask might be in an unspecified
|
||||
state when using libev's signal handling.
|
||||
- take advantage of some GNU/Linux calls to set cloexec/nonblock
|
||||
on fd creation, to avoid race conditions.
|
||||
|
||||
3.7 Fri Jul 17 16:36:32 CEST 2009
|
||||
- ev_unloop and ev_loop wrongly used a global variable to exit loops,
|
||||
instead of using a per-loop variable (bug caught by accident...).
|
||||
- the ev_set_io_collect_interval interpretation has changed.
|
||||
- add new functionality: ev_set_userdata, ev_userdata,
|
||||
ev_set_invoke_pending_cb, ev_set_loop_release_cb,
|
||||
ev_invoke_pending, ev_pending_count, together with a long example
|
||||
about thread locking.
|
||||
- add ev_timer_remaining (as requested by Denis F. Latypoff).
|
||||
- add ev_loop_depth.
|
||||
- calling ev_unloop in fork/prepare watchers will no longer poll
|
||||
for new events.
|
||||
- Denis F. Latypoff corrected many typos in example code snippets.
|
||||
- honor autoconf detection of EV_USE_CLOCK_SYSCALL, also double-
|
||||
check that the syscall number is available before trying to
|
||||
use it (reported by ry@tinyclouds).
|
||||
- use GetSystemTimeAsFileTime instead of _timeb on windows, for
|
||||
slightly higher accuracy.
|
||||
- properly declare ev_loop_verify and ev_now_update even when
|
||||
!EV_MULTIPLICITY.
|
||||
- do not compile in any priority code when EV_MAXPRI == EV_MINPRI.
|
||||
- support EV_MINIMAL==2 for a reduced API.
|
||||
- actually 0-initialise struct sigaction when installing signals.
|
||||
- add section on hibernate and stopped processes to ev_timer docs.
|
||||
|
||||
3.6 Tue Apr 28 02:49:30 CEST 2009
|
||||
- multiple timers becoming ready within an event loop iteration
|
||||
will be invoked in the "correct" order now.
|
||||
- do not leave the event loop early just because we have no active
|
||||
watchers, fixing a problem when embedding a kqueue loop
|
||||
that has active kernel events but no registered watchers
|
||||
(reported by blacksand blacksand).
|
||||
- correctly zero the idx values for arrays, so destroying and
|
||||
reinitialising the default loop actually works (patch by
|
||||
Malek Hadj-Ali).
|
||||
- implement ev_suspend and ev_resume.
|
||||
- new EV_CUSTOM revents flag for use by applications.
|
||||
- add documentation section about priorities.
|
||||
- add a glossary to the documentation.
|
||||
- extend the ev_fork description slightly.
|
||||
- optimize a jump out of call_pending.
|
||||
|
||||
3.53 Sun Feb 15 02:38:20 CET 2009
|
||||
- fix a bug in event pipe creation on win32 that would cause a
|
||||
failed assertion on event loop creation (patch by Malek Hadj-Ali).
|
||||
- probe for CLOCK_REALTIME support at runtime as well and fall
|
||||
back to gettimeofday if there is an error, to support older
|
||||
operating systems with newer header files/libraries.
|
||||
- prefer gettimeofday over clock_gettime with USE_CLOCK_SYSCALL
|
||||
(default most everywhere), otherwise not.
|
||||
|
||||
3.52 Wed Jan 7 21:43:02 CET 2009
|
||||
- fix compilation of select backend in fd_set mode when NFDBITS is
|
||||
missing (to get it to compile on QNX, reported by Rodrigo Campos).
|
||||
- better select-nfds handling when select backend is in fd_set mode.
|
||||
- diagnose fd_set overruns when select backend is in fd_set mode.
|
||||
- due to a thinko, instead of disabling everything but
|
||||
select on the borked OS X platform, everything but select was
|
||||
allowed (reported by Emanuele Giaquinta).
|
||||
- actually verify that local and remote port are matching in
|
||||
libev's socketpair emulation, which makes denial-of-service
|
||||
attacks harder (but not impossible - it's windows). Make sure
|
||||
it even works under vista, which thinks that getpeer/sockname
|
||||
should return fantasy port numbers.
|
||||
- include "libev" in all assertion messages for potentially
|
||||
clearer diagnostics.
|
||||
- event_get_version (libevent compatibility) returned
|
||||
a useless string instead of the expected version string
|
||||
(patch by W.C.A. Wijngaards).
|
||||
|
||||
3.51 Wed Dec 24 23:00:11 CET 2008
|
||||
- fix a bug where an inotify watcher was added twice, causing
|
||||
freezes on hash collisions (reported and analysed by Graham Leggett).
|
||||
- new config symbol, EV_USE_CLOCK_SYSCALL, to make libev use
|
||||
a direct syscall - slower, but no dependency on librt et al.
|
||||
- assume negative return values != -1 signals success of port_getn
|
||||
(http://cvs.epicsol.org/cgi/viewcvs.cgi/epic5/source/newio.c?rev=1.52)
|
||||
(no known failure reports, but it doesn't hurt).
|
||||
- fork detection in ev_embed now stops and restarts the watcher
|
||||
automatically.
|
||||
- EXPERIMENTAL: default the method to operator () in ev++.h,
|
||||
to make it nicer to use functors (requested by Benedek László).
|
||||
- fixed const object callbacks in ev++.h.
|
||||
- replaced loop_ref argument of watcher.set (loop) by a direct
|
||||
ev_loop * in ev++.h, to avoid clashes with functor patch.
|
||||
- do not try to watch the empty string via inotify.
|
||||
- inotify watchers could be leaked under certain circumstances.
|
||||
- OS X 10.5 is actually even more broken than earlier versions,
|
||||
so fall back to select on that piece of garbage.
|
||||
- fixed some weirdness in the ev_embed documentation.
|
||||
|
||||
3.49 Wed Nov 19 11:26:53 CET 2008
|
||||
- ev_stat watchers will now use inotify as a mere hint on
|
||||
kernels <2.6.25, or if the filesystem is not in the
|
||||
"known to be good" list.
|
||||
- better mingw32 compatibility (it's not as borked as native win32)
|
||||
(analysed by Roger Pack).
|
||||
- include stdio.h in the example program, as too many people are
|
||||
confused by the weird C language otherwise. I guess the next thing
|
||||
I get told is that the "..." ellipses in the examples don't compile
|
||||
with their C compiler.
|
||||
|
||||
3.48 Thu Oct 30 09:02:37 CET 2008
|
||||
- further optimise away the EPOLL_CTL_ADD/MOD combo in the epoll
|
||||
backend by assuming the kernel event mask hasn't changed if
|
||||
ADD fails with EEXIST.
|
||||
- work around spurious event notification bugs in epoll by using
|
||||
a 32-bit generation counter. recreate kernel state if we receive
|
||||
spurious notifications or unwanted events. this is very costly,
|
||||
but I didn't come up with this horrible design.
|
||||
- use memset to initialise most arrays now and do away with the
|
||||
init functions.
|
||||
- expand time-out strategies into a "Be smart about timeouts" section.
|
||||
- drop the "struct" from all ev_watcher declarations in the
|
||||
documentation and did other clarifications (yeah, it was a mistake
|
||||
to have a struct AND a function called ev_loop).
|
||||
- fix a bug where ev_default would not initialise the default
|
||||
loop again after it was destroyed with ev_default_destroy.
|
||||
- rename syserr to ev_syserr to avoid name clashes when embedding,
|
||||
do similar changes for event.c.
|
||||
|
||||
3.45 Tue Oct 21 21:59:26 CEST 2008
|
||||
- disable inotify usage on linux <2.6.25, as it is broken
|
||||
(reported by Yoann Vandoorselaere).
|
||||
- ev_stat erroneously would try to add inotify watchers
|
||||
even when inotify wasn't available (this should only
|
||||
have a performance impact).
|
||||
- ev_once now passes both timeout and io to the callback if both
|
||||
occur concurrently, instead of giving timeouts precedence.
|
||||
- disable EV_USE_INOTIFY when sys/inotify.h is too old.
|
||||
|
||||
3.44 Mon Sep 29 05:18:39 CEST 2008
|
||||
- embed watchers now automatically invoke ev_loop_fork on the
|
||||
embedded loop when the parent loop forks.
|
||||
- new function: ev_now_update (loop).
|
||||
- verify_watcher was not marked static.
|
||||
- improve the "associating..." manpage section.
|
||||
- documentation tweaks here and there.
|
||||
|
||||
3.43 Sun Jul 6 05:34:41 CEST 2008
|
||||
- include more include files on windows to get struct _stati64
|
||||
(reported by Chris Hulbert, but doesn't quite fix his issue).
|
||||
- add missing #include <io.h> in ev.c on windows (reported by
|
||||
Matt Tolton).
|
||||
|
||||
3.42 Tue Jun 17 12:12:07 CEST 2008
|
||||
- work around yet another windows bug: FD_SET actually adds fd's
|
||||
multiple times to the fd_*SET*, despite official MSN docs claiming
|
||||
otherwise. Reported and well-analysed by Matt Tolton.
|
||||
- define NFDBITS to 0 when EV_SELECT_IS_WINSOCKET to make it compile
|
||||
(reported any analysed by Chris Hulbert).
|
||||
- fix a bug in ev_ebadf (this function is only used to catch
|
||||
programming errors in the libev user). reported by Matt Tolton.
|
||||
- fix a bug in fd_intern on win32 (could lead to compile errors
|
||||
under some circumstances, but would work correctly if it compiles).
|
||||
reported by Matt Tolton.
|
||||
- (try to) work around missing lstat on windows.
|
||||
- pass in the write fd set as except fd set under windows. windows
|
||||
is so uncontrollably lame that it requires this. this means that
|
||||
switching off oobinline is not supported (but tcp/ip doesn't
|
||||
have oob, so that would be stupid anyways.
|
||||
- use posix module symbol to auto-detect monotonic clock presence
|
||||
and some other default values.
|
||||
|
||||
3.41 Fri May 23 18:42:54 CEST 2008
|
||||
- work around an obscure bug in winsocket select: if you
|
||||
provide only empty fd sets then select returns WSAEINVAL. how sucky.
|
||||
- improve timer scheduling stability and reduce use of time_epsilon.
|
||||
- use 1-based 2-heap for EV_MINIMAL, simplifies code, reduces
|
||||
codesize and makes for better cache-efficiency.
|
||||
- use 3-based 4-heap for !EV_MINIMAL. this makes better use
|
||||
of cpu cache lines and gives better growth behaviour than
|
||||
2-based heaps.
|
||||
- cache timestamp within heap for !EV_MINIMAL, to avoid random
|
||||
memory accesses.
|
||||
- document/add EV_USE_4HEAP and EV_HEAP_CACHE_AT.
|
||||
- fix a potential aliasing issue in ev_timer_again.
|
||||
- add/document ev_periodic_at, retract direct access to ->at.
|
||||
- improve ev_stat docs.
|
||||
- add portability requirements section.
|
||||
- fix manpage headers etc.
|
||||
- normalise WSA error codes to lower range on windows.
|
||||
- add consistency check code that can be called automatically
|
||||
or on demand to check for internal structures (ev_loop_verify).
|
||||
|
||||
3.31 Wed Apr 16 20:45:04 CEST 2008
|
||||
- added last minute fix for ev_poll.c by Brandon Black.
|
||||
|
||||
3.3 Wed Apr 16 19:04:10 CEST 2008
|
||||
- event_base_loopexit should return 0 on success
|
||||
(W.C.A. Wijngaards).
|
||||
- added linux eventfd support.
|
||||
- try to autodetect epoll and inotify support
|
||||
by libc header version if not using autoconf.
|
||||
- new symbols: EV_DEFAULT_UC and EV_DEFAULT_UC_.
|
||||
- declare functions defined in ev.h as inline if
|
||||
C99 or gcc are available.
|
||||
- enable inlining with gcc versions 2 and 3.
|
||||
- work around broken poll implementations potentially
|
||||
not clearing revents field in ev_poll (Brandon Black)
|
||||
(no such systems are known at this time).
|
||||
- work around a bug in realloc on openbsd and darwin,
|
||||
also makes the erroneous valgrind complaints
|
||||
go away (noted by various people).
|
||||
- fix ev_async_pending, add c++ wrapper for ev_async
|
||||
(based on patch sent by Johannes Deisenhofer).
|
||||
- add sensible set method to ev::embed.
|
||||
- made integer constants type int in ev.h.
|
||||
|
||||
3.2 Wed Apr 2 17:11:19 CEST 2008
|
||||
- fix a 64 bit overflow issue in the select backend,
|
||||
by using fd_mask instead of int for the mask.
|
||||
- rename internal sighandler to avoid clash with very old perls.
|
||||
- entering ev_loop will not clear the ONESHOT or NONBLOCKING
|
||||
flags of any outer loops anymore.
|
||||
- add ev_async_pending.
|
||||
|
||||
3.1 Thu Mar 13 13:45:22 CET 2008
|
||||
- implement ev_async watchers.
|
||||
- only initialise signal pipe on demand.
|
||||
- make use of sig_atomic_t configurable.
|
||||
- improved documentation.
|
||||
|
||||
3.0 Mon Jan 28 13:14:47 CET 2008
|
||||
- API/ABI bump to version 3.0.
|
||||
- ev++.h includes "ev.h" by default now, not <ev.h>.
|
||||
- slightly improved documentation.
|
||||
- speed up signal detection after a fork.
|
||||
- only optionally return trace status changed in ev_child
|
||||
watchers.
|
||||
- experimental (and undocumented) loop wrappers for ev++.h.
|
||||
|
||||
2.01 Tue Dec 25 08:04:41 CET 2007
|
||||
- separate Changes file.
|
||||
- fix ev_path_set => ev_stat_set typo.
|
||||
- remove event_compat.h from the libev tarball.
|
||||
- change how include files are found.
|
||||
- doc updates.
|
||||
- update licenses, explicitly allow for GPL relicensing.
|
||||
|
||||
2.0 Sat Dec 22 17:47:03 CET 2007
|
||||
- new ev_sleep, ev_set_(io|timeout)_collect_interval.
|
||||
- removed epoll from embeddable fd set.
|
||||
- fix embed watchers.
|
||||
- renamed ev_embed.loop to other.
|
||||
- added exported Symbol tables.
|
||||
- undefine member wrapper macros at the end of ev.c.
|
||||
- respect EV_H in ev++.h.
|
||||
|
||||
1.86 Tue Dec 18 02:36:57 CET 2007
|
||||
- fix memleak on loop destroy (not relevant for perl).
|
||||
|
||||
1.85 Fri Dec 14 20:32:40 CET 2007
|
||||
- fix some aliasing issues w.r.t. timers and periodics
|
||||
(not relevant for perl).
|
||||
|
||||
(for historic versions refer to EV/Changes, found in the Perl interface)
|
||||
|
||||
0.1 Wed Oct 31 21:31:48 CET 2007
|
||||
- original version; hacked together in <24h.
|
||||
|
@@ -1,37 +0,0 @@
|
||||
All files in libev are
|
||||
Copyright (c)2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Alternatively, the contents of this package may be used under the terms
|
||||
of the GNU General Public License ("GPL") version 2 or any later version,
|
||||
in which case the provisions of the GPL are applicable instead of the
|
||||
above. If you wish to allow the use of your version of this package only
|
||||
under the terms of the GPL and not to allow others to use your version of
|
||||
this file under the BSD license, indicate your decision by deleting the
|
||||
provisions above and replace them with the notice and other provisions
|
||||
required by the GPL in this and the other files of this package. If you do
|
||||
not delete the provisions above, a recipient may use your version of this
|
||||
file under either the BSD or the GPL.
|
@@ -1,20 +0,0 @@
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
VERSION_INFO = 4:0:0
|
||||
|
||||
EXTRA_DIST = LICENSE Changes libev.m4 autogen.sh \
|
||||
ev_vars.h ev_wrap.h \
|
||||
ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c \
|
||||
ev.3 ev.pod Symbols.ev Symbols.event
|
||||
|
||||
man_MANS = ev.3
|
||||
|
||||
include_HEADERS = ev.h ev++.h event.h
|
||||
|
||||
lib_LTLIBRARIES = libev.la
|
||||
|
||||
libev_la_SOURCES = ev.c event.c
|
||||
libev_la_LDFLAGS = -version-info $(VERSION_INFO)
|
||||
|
||||
ev.3: ev.pod
|
||||
pod2man -n LIBEV -r "libev-$(VERSION)" -c "libev - high performance full featured event loop" -s3 <$< >$@
|
58
libev/README
@@ -1,58 +0,0 @@
|
||||
libev is a high-performance event loop/event model with lots of features.
|
||||
(see benchmark at http://libev.schmorp.de/bench.html)
|
||||
|
||||
|
||||
ABOUT
|
||||
|
||||
Homepage: http://software.schmorp.de/pkg/libev
|
||||
Mailinglist: libev@lists.schmorp.de
|
||||
http://lists.schmorp.de/cgi-bin/mailman/listinfo/libev
|
||||
Library Documentation: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod
|
||||
|
||||
Libev is modelled (very losely) after libevent and the Event perl
|
||||
module, but is faster, scales better and is more correct, and also more
|
||||
featureful. And also smaller. Yay.
|
||||
|
||||
Some of the specialties of libev not commonly found elsewhere are:
|
||||
|
||||
- extensive and detailed, readable documentation (not doxygen garbage).
|
||||
- fully supports fork, can detect fork in various ways and automatically
|
||||
re-arms kernel mechanisms that do not support fork.
|
||||
- highly optimised select, poll, epoll, kqueue and event ports backends.
|
||||
- filesystem object (path) watching (with optional linux inotify support).
|
||||
- wallclock-based times (using absolute time, cron-like).
|
||||
- relative timers/timeouts (handle time jumps).
|
||||
- fast intra-thread communication between multiple
|
||||
event loops (with optional fast linux eventfd backend).
|
||||
- extremely easy to embed (fully documented, no dependencies,
|
||||
autoconf supported but optional).
|
||||
- very small codebase, no bloated library, simple code.
|
||||
- fully extensible by being able to plug into the event loop,
|
||||
integrate other event loops, integrate other event loop users.
|
||||
- very little memory use (small watchers, small event loop data).
|
||||
- optional C++ interface allowing method and function callbacks
|
||||
at no extra memory or runtime overhead.
|
||||
- optional Perl interface with similar characteristics (capable
|
||||
of running Glib/Gtk2 on libev).
|
||||
- support for other languages (multiple C++ interfaces, D, Ruby,
|
||||
Python) available from third-parties.
|
||||
|
||||
Examples of programs that embed libev: the EV perl module, node.js,
|
||||
auditd, rxvt-unicode, gvpe (GNU Virtual Private Ethernet), the
|
||||
Deliantra MMORPG server (http://www.deliantra.net/), Rubinius (a
|
||||
next-generation Ruby VM), the Ebb web server, the Rev event toolkit.
|
||||
|
||||
|
||||
CONTRIBUTORS
|
||||
|
||||
libev was written and designed by Marc Lehmann and Emanuele Giaquinta.
|
||||
|
||||
The following people sent in patches or made other noteworthy
|
||||
contributions to the design (for minor patches, see the Changes
|
||||
file. If I forgot to include you, please shout at me, it was an
|
||||
accident):
|
||||
|
||||
W.C.A. Wijngaards
|
||||
Christopher Layne
|
||||
Chris Brody
|
||||
|
@@ -1,3 +0,0 @@
|
||||
This file is now included in the main libev documentation, see
|
||||
|
||||
http://cvs.schmorp.de/libev/ev.html
|
@@ -1,73 +0,0 @@
|
||||
ev_async_send
|
||||
ev_async_start
|
||||
ev_async_stop
|
||||
ev_backend
|
||||
ev_break
|
||||
ev_check_start
|
||||
ev_check_stop
|
||||
ev_child_start
|
||||
ev_child_stop
|
||||
ev_cleanup_start
|
||||
ev_cleanup_stop
|
||||
ev_clear_pending
|
||||
ev_default_loop
|
||||
ev_default_loop_ptr
|
||||
ev_depth
|
||||
ev_embed_start
|
||||
ev_embed_stop
|
||||
ev_embed_sweep
|
||||
ev_embeddable_backends
|
||||
ev_feed_event
|
||||
ev_feed_fd_event
|
||||
ev_feed_signal
|
||||
ev_feed_signal_event
|
||||
ev_fork_start
|
||||
ev_fork_stop
|
||||
ev_idle_start
|
||||
ev_idle_stop
|
||||
ev_invoke
|
||||
ev_invoke_pending
|
||||
ev_io_start
|
||||
ev_io_stop
|
||||
ev_iteration
|
||||
ev_loop_destroy
|
||||
ev_loop_fork
|
||||
ev_loop_new
|
||||
ev_now
|
||||
ev_now_update
|
||||
ev_once
|
||||
ev_pending_count
|
||||
ev_periodic_again
|
||||
ev_periodic_start
|
||||
ev_periodic_stop
|
||||
ev_prepare_start
|
||||
ev_prepare_stop
|
||||
ev_recommended_backends
|
||||
ev_ref
|
||||
ev_resume
|
||||
ev_run
|
||||
ev_set_allocator
|
||||
ev_set_invoke_pending_cb
|
||||
ev_set_io_collect_interval
|
||||
ev_set_loop_release_cb
|
||||
ev_set_syserr_cb
|
||||
ev_set_timeout_collect_interval
|
||||
ev_set_userdata
|
||||
ev_signal_start
|
||||
ev_signal_stop
|
||||
ev_sleep
|
||||
ev_stat_start
|
||||
ev_stat_stat
|
||||
ev_stat_stop
|
||||
ev_supported_backends
|
||||
ev_suspend
|
||||
ev_time
|
||||
ev_timer_again
|
||||
ev_timer_remaining
|
||||
ev_timer_start
|
||||
ev_timer_stop
|
||||
ev_unref
|
||||
ev_userdata
|
||||
ev_verify
|
||||
ev_version_major
|
||||
ev_version_minor
|
@@ -1,24 +0,0 @@
|
||||
event_active
|
||||
event_add
|
||||
event_base_dispatch
|
||||
event_base_free
|
||||
event_base_get_method
|
||||
event_base_loop
|
||||
event_base_loopexit
|
||||
event_base_new
|
||||
event_base_once
|
||||
event_base_priority_init
|
||||
event_base_set
|
||||
event_del
|
||||
event_dispatch
|
||||
event_get_callback
|
||||
event_get_method
|
||||
event_get_version
|
||||
event_init
|
||||
event_loop
|
||||
event_loopexit
|
||||
event_once
|
||||
event_pending
|
||||
event_priority_init
|
||||
event_priority_set
|
||||
event_set
|
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
autoreconf --install --symlink --force
|
@@ -1,27 +0,0 @@
|
||||
AC_INIT
|
||||
|
||||
orig_CFLAGS="$CFLAGS"
|
||||
|
||||
AC_CONFIG_SRCDIR([ev_epoll.c])
|
||||
|
||||
dnl also update ev.h!
|
||||
AM_INIT_AUTOMAKE(libev,4.24)
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_PROG_CC
|
||||
|
||||
dnl Supply default CFLAGS, if not specified
|
||||
if test -z "$orig_CFLAGS"; then
|
||||
if test x$GCC = xyes; then
|
||||
CFLAGS="-g -O3"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
m4_include([libev.m4])
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
816
libev/ev++.h
@@ -1,816 +0,0 @@
|
||||
/*
|
||||
* libev simple C++ wrapper classes
|
||||
*
|
||||
* Copyright (c) 2007,2008,2010 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef EVPP_H__
|
||||
#define EVPP_H__
|
||||
|
||||
#ifdef EV_H
|
||||
# include EV_H
|
||||
#else
|
||||
# include "ev.h"
|
||||
#endif
|
||||
|
||||
#ifndef EV_USE_STDEXCEPT
|
||||
# define EV_USE_STDEXCEPT 1
|
||||
#endif
|
||||
|
||||
#if EV_USE_STDEXCEPT
|
||||
# include <stdexcept>
|
||||
#endif
|
||||
|
||||
namespace ev {
|
||||
|
||||
typedef ev_tstamp tstamp;
|
||||
|
||||
enum {
|
||||
UNDEF = EV_UNDEF,
|
||||
NONE = EV_NONE,
|
||||
READ = EV_READ,
|
||||
WRITE = EV_WRITE,
|
||||
#if EV_COMPAT3
|
||||
TIMEOUT = EV_TIMEOUT,
|
||||
#endif
|
||||
TIMER = EV_TIMER,
|
||||
PERIODIC = EV_PERIODIC,
|
||||
SIGNAL = EV_SIGNAL,
|
||||
CHILD = EV_CHILD,
|
||||
STAT = EV_STAT,
|
||||
IDLE = EV_IDLE,
|
||||
CHECK = EV_CHECK,
|
||||
PREPARE = EV_PREPARE,
|
||||
FORK = EV_FORK,
|
||||
ASYNC = EV_ASYNC,
|
||||
EMBED = EV_EMBED,
|
||||
# undef ERROR // some systems stupidly #define ERROR
|
||||
ERROR = EV_ERROR
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
AUTO = EVFLAG_AUTO,
|
||||
NOENV = EVFLAG_NOENV,
|
||||
FORKCHECK = EVFLAG_FORKCHECK,
|
||||
|
||||
SELECT = EVBACKEND_SELECT,
|
||||
POLL = EVBACKEND_POLL,
|
||||
EPOLL = EVBACKEND_EPOLL,
|
||||
KQUEUE = EVBACKEND_KQUEUE,
|
||||
DEVPOLL = EVBACKEND_DEVPOLL,
|
||||
PORT = EVBACKEND_PORT
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
#if EV_COMPAT3
|
||||
NONBLOCK = EVLOOP_NONBLOCK,
|
||||
ONESHOT = EVLOOP_ONESHOT,
|
||||
#endif
|
||||
NOWAIT = EVRUN_NOWAIT,
|
||||
ONCE = EVRUN_ONCE
|
||||
};
|
||||
|
||||
enum how_t
|
||||
{
|
||||
ONE = EVBREAK_ONE,
|
||||
ALL = EVBREAK_ALL
|
||||
};
|
||||
|
||||
struct bad_loop
|
||||
#if EV_USE_STDEXCEPT
|
||||
: std::runtime_error
|
||||
#endif
|
||||
{
|
||||
#if EV_USE_STDEXCEPT
|
||||
bad_loop ()
|
||||
: std::runtime_error ("libev event loop cannot be initialized, bad value of LIBEV_FLAGS?")
|
||||
{
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef EV_AX
|
||||
# undef EV_AX
|
||||
#endif
|
||||
|
||||
#ifdef EV_AX_
|
||||
# undef EV_AX_
|
||||
#endif
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
# define EV_AX raw_loop
|
||||
# define EV_AX_ raw_loop,
|
||||
#else
|
||||
# define EV_AX
|
||||
# define EV_AX_
|
||||
#endif
|
||||
|
||||
struct loop_ref
|
||||
{
|
||||
loop_ref (EV_P) throw ()
|
||||
#if EV_MULTIPLICITY
|
||||
: EV_AX (EV_A)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
bool operator == (const loop_ref &other) const throw ()
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
return EV_AX == other.EV_AX;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool operator != (const loop_ref &other) const throw ()
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
return ! (*this == other);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
bool operator == (const EV_P) const throw ()
|
||||
{
|
||||
return this->EV_AX == EV_A;
|
||||
}
|
||||
|
||||
bool operator != (const EV_P) const throw ()
|
||||
{
|
||||
return ! (*this == EV_A);
|
||||
}
|
||||
|
||||
operator struct ev_loop * () const throw ()
|
||||
{
|
||||
return EV_AX;
|
||||
}
|
||||
|
||||
operator const struct ev_loop * () const throw ()
|
||||
{
|
||||
return EV_AX;
|
||||
}
|
||||
|
||||
bool is_default () const throw ()
|
||||
{
|
||||
return EV_AX == ev_default_loop (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if EV_COMPAT3
|
||||
void loop (int flags = 0)
|
||||
{
|
||||
ev_run (EV_AX_ flags);
|
||||
}
|
||||
|
||||
void unloop (how_t how = ONE) throw ()
|
||||
{
|
||||
ev_break (EV_AX_ how);
|
||||
}
|
||||
#endif
|
||||
|
||||
void run (int flags = 0)
|
||||
{
|
||||
ev_run (EV_AX_ flags);
|
||||
}
|
||||
|
||||
void break_loop (how_t how = ONE) throw ()
|
||||
{
|
||||
ev_break (EV_AX_ how);
|
||||
}
|
||||
|
||||
void post_fork () throw ()
|
||||
{
|
||||
ev_loop_fork (EV_AX);
|
||||
}
|
||||
|
||||
unsigned int backend () const throw ()
|
||||
{
|
||||
return ev_backend (EV_AX);
|
||||
}
|
||||
|
||||
tstamp now () const throw ()
|
||||
{
|
||||
return ev_now (EV_AX);
|
||||
}
|
||||
|
||||
void ref () throw ()
|
||||
{
|
||||
ev_ref (EV_AX);
|
||||
}
|
||||
|
||||
void unref () throw ()
|
||||
{
|
||||
ev_unref (EV_AX);
|
||||
}
|
||||
|
||||
#if EV_FEATURE_API
|
||||
unsigned int iteration () const throw ()
|
||||
{
|
||||
return ev_iteration (EV_AX);
|
||||
}
|
||||
|
||||
unsigned int depth () const throw ()
|
||||
{
|
||||
return ev_depth (EV_AX);
|
||||
}
|
||||
|
||||
void set_io_collect_interval (tstamp interval) throw ()
|
||||
{
|
||||
ev_set_io_collect_interval (EV_AX_ interval);
|
||||
}
|
||||
|
||||
void set_timeout_collect_interval (tstamp interval) throw ()
|
||||
{
|
||||
ev_set_timeout_collect_interval (EV_AX_ interval);
|
||||
}
|
||||
#endif
|
||||
|
||||
// function callback
|
||||
void once (int fd, int events, tstamp timeout, void (*cb)(int, void *), void *arg = 0) throw ()
|
||||
{
|
||||
ev_once (EV_AX_ fd, events, timeout, cb, arg);
|
||||
}
|
||||
|
||||
// method callback
|
||||
template<class K, void (K::*method)(int)>
|
||||
void once (int fd, int events, tstamp timeout, K *object) throw ()
|
||||
{
|
||||
once (fd, events, timeout, method_thunk<K, method>, object);
|
||||
}
|
||||
|
||||
// default method == operator ()
|
||||
template<class K>
|
||||
void once (int fd, int events, tstamp timeout, K *object) throw ()
|
||||
{
|
||||
once (fd, events, timeout, method_thunk<K, &K::operator ()>, object);
|
||||
}
|
||||
|
||||
template<class K, void (K::*method)(int)>
|
||||
static void method_thunk (int revents, void *arg)
|
||||
{
|
||||
(static_cast<K *>(arg)->*method)
|
||||
(revents);
|
||||
}
|
||||
|
||||
// no-argument method callback
|
||||
template<class K, void (K::*method)()>
|
||||
void once (int fd, int events, tstamp timeout, K *object) throw ()
|
||||
{
|
||||
once (fd, events, timeout, method_noargs_thunk<K, method>, object);
|
||||
}
|
||||
|
||||
template<class K, void (K::*method)()>
|
||||
static void method_noargs_thunk (int revents, void *arg)
|
||||
{
|
||||
(static_cast<K *>(arg)->*method)
|
||||
();
|
||||
}
|
||||
|
||||
// simpler function callback
|
||||
template<void (*cb)(int)>
|
||||
void once (int fd, int events, tstamp timeout) throw ()
|
||||
{
|
||||
once (fd, events, timeout, simpler_func_thunk<cb>);
|
||||
}
|
||||
|
||||
template<void (*cb)(int)>
|
||||
static void simpler_func_thunk (int revents, void *arg)
|
||||
{
|
||||
(*cb)
|
||||
(revents);
|
||||
}
|
||||
|
||||
// simplest function callback
|
||||
template<void (*cb)()>
|
||||
void once (int fd, int events, tstamp timeout) throw ()
|
||||
{
|
||||
once (fd, events, timeout, simplest_func_thunk<cb>);
|
||||
}
|
||||
|
||||
template<void (*cb)()>
|
||||
static void simplest_func_thunk (int revents, void *arg)
|
||||
{
|
||||
(*cb)
|
||||
();
|
||||
}
|
||||
|
||||
void feed_fd_event (int fd, int revents) throw ()
|
||||
{
|
||||
ev_feed_fd_event (EV_AX_ fd, revents);
|
||||
}
|
||||
|
||||
void feed_signal_event (int signum) throw ()
|
||||
{
|
||||
ev_feed_signal_event (EV_AX_ signum);
|
||||
}
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
struct ev_loop* EV_AX;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
struct dynamic_loop : loop_ref
|
||||
{
|
||||
|
||||
dynamic_loop (unsigned int flags = AUTO) throw (bad_loop)
|
||||
: loop_ref (ev_loop_new (flags))
|
||||
{
|
||||
if (!EV_AX)
|
||||
throw bad_loop ();
|
||||
}
|
||||
|
||||
~dynamic_loop () throw ()
|
||||
{
|
||||
ev_loop_destroy (EV_AX);
|
||||
EV_AX = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
dynamic_loop (const dynamic_loop &);
|
||||
|
||||
dynamic_loop & operator= (const dynamic_loop &);
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
struct default_loop : loop_ref
|
||||
{
|
||||
default_loop (unsigned int flags = AUTO) throw (bad_loop)
|
||||
#if EV_MULTIPLICITY
|
||||
: loop_ref (ev_default_loop (flags))
|
||||
#endif
|
||||
{
|
||||
if (
|
||||
#if EV_MULTIPLICITY
|
||||
!EV_AX
|
||||
#else
|
||||
!ev_default_loop (flags)
|
||||
#endif
|
||||
)
|
||||
throw bad_loop ();
|
||||
}
|
||||
|
||||
private:
|
||||
default_loop (const default_loop &);
|
||||
default_loop &operator = (const default_loop &);
|
||||
};
|
||||
|
||||
inline loop_ref get_default_loop () throw ()
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
return ev_default_loop (0);
|
||||
#else
|
||||
return loop_ref ();
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef EV_AX
|
||||
#undef EV_AX_
|
||||
|
||||
#undef EV_PX
|
||||
#undef EV_PX_
|
||||
#if EV_MULTIPLICITY
|
||||
# define EV_PX loop_ref EV_A
|
||||
# define EV_PX_ loop_ref EV_A_
|
||||
#else
|
||||
# define EV_PX
|
||||
# define EV_PX_
|
||||
#endif
|
||||
|
||||
template<class ev_watcher, class watcher>
|
||||
struct base : ev_watcher
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
EV_PX;
|
||||
|
||||
// loop set
|
||||
void set (EV_P) throw ()
|
||||
{
|
||||
this->EV_A = EV_A;
|
||||
}
|
||||
#endif
|
||||
|
||||
base (EV_PX) throw ()
|
||||
#if EV_MULTIPLICITY
|
||||
: EV_A (EV_A)
|
||||
#endif
|
||||
{
|
||||
ev_init (this, 0);
|
||||
}
|
||||
|
||||
void set_ (const void *data, void (*cb)(EV_P_ ev_watcher *w, int revents)) throw ()
|
||||
{
|
||||
this->data = (void *)data;
|
||||
ev_set_cb (static_cast<ev_watcher *>(this), cb);
|
||||
}
|
||||
|
||||
// function callback
|
||||
template<void (*function)(watcher &w, int)>
|
||||
void set (void *data = 0) throw ()
|
||||
{
|
||||
set_ (data, function_thunk<function>);
|
||||
}
|
||||
|
||||
template<void (*function)(watcher &w, int)>
|
||||
static void function_thunk (EV_P_ ev_watcher *w, int revents)
|
||||
{
|
||||
function
|
||||
(*static_cast<watcher *>(w), revents);
|
||||
}
|
||||
|
||||
// method callback
|
||||
template<class K, void (K::*method)(watcher &w, int)>
|
||||
void set (K *object) throw ()
|
||||
{
|
||||
set_ (object, method_thunk<K, method>);
|
||||
}
|
||||
|
||||
// default method == operator ()
|
||||
template<class K>
|
||||
void set (K *object) throw ()
|
||||
{
|
||||
set_ (object, method_thunk<K, &K::operator ()>);
|
||||
}
|
||||
|
||||
template<class K, void (K::*method)(watcher &w, int)>
|
||||
static void method_thunk (EV_P_ ev_watcher *w, int revents)
|
||||
{
|
||||
(static_cast<K *>(w->data)->*method)
|
||||
(*static_cast<watcher *>(w), revents);
|
||||
}
|
||||
|
||||
// no-argument callback
|
||||
template<class K, void (K::*method)()>
|
||||
void set (K *object) throw ()
|
||||
{
|
||||
set_ (object, method_noargs_thunk<K, method>);
|
||||
}
|
||||
|
||||
template<class K, void (K::*method)()>
|
||||
static void method_noargs_thunk (EV_P_ ev_watcher *w, int revents)
|
||||
{
|
||||
(static_cast<K *>(w->data)->*method)
|
||||
();
|
||||
}
|
||||
|
||||
void operator ()(int events = EV_UNDEF)
|
||||
{
|
||||
return
|
||||
ev_cb (static_cast<ev_watcher *>(this))
|
||||
(static_cast<ev_watcher *>(this), events);
|
||||
}
|
||||
|
||||
bool is_active () const throw ()
|
||||
{
|
||||
return ev_is_active (static_cast<const ev_watcher *>(this));
|
||||
}
|
||||
|
||||
bool is_pending () const throw ()
|
||||
{
|
||||
return ev_is_pending (static_cast<const ev_watcher *>(this));
|
||||
}
|
||||
|
||||
void feed_event (int revents) throw ()
|
||||
{
|
||||
ev_feed_event (EV_A_ static_cast<ev_watcher *>(this), revents);
|
||||
}
|
||||
};
|
||||
|
||||
inline tstamp now (EV_P) throw ()
|
||||
{
|
||||
return ev_now (EV_A);
|
||||
}
|
||||
|
||||
inline void delay (tstamp interval) throw ()
|
||||
{
|
||||
ev_sleep (interval);
|
||||
}
|
||||
|
||||
inline int version_major () throw ()
|
||||
{
|
||||
return ev_version_major ();
|
||||
}
|
||||
|
||||
inline int version_minor () throw ()
|
||||
{
|
||||
return ev_version_minor ();
|
||||
}
|
||||
|
||||
inline unsigned int supported_backends () throw ()
|
||||
{
|
||||
return ev_supported_backends ();
|
||||
}
|
||||
|
||||
inline unsigned int recommended_backends () throw ()
|
||||
{
|
||||
return ev_recommended_backends ();
|
||||
}
|
||||
|
||||
inline unsigned int embeddable_backends () throw ()
|
||||
{
|
||||
return ev_embeddable_backends ();
|
||||
}
|
||||
|
||||
inline void set_allocator (void *(*cb)(void *ptr, long size) throw ()) throw ()
|
||||
{
|
||||
ev_set_allocator (cb);
|
||||
}
|
||||
|
||||
inline void set_syserr_cb (void (*cb)(const char *msg) throw ()) throw ()
|
||||
{
|
||||
ev_set_syserr_cb (cb);
|
||||
}
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
#define EV_CONSTRUCT(cppstem,cstem) \
|
||||
(EV_PX = get_default_loop ()) throw () \
|
||||
: base<ev_ ## cstem, cppstem> (EV_A) \
|
||||
{ \
|
||||
}
|
||||
#else
|
||||
#define EV_CONSTRUCT(cppstem,cstem) \
|
||||
() throw () \
|
||||
{ \
|
||||
}
|
||||
#endif
|
||||
|
||||
/* using a template here would require quite a few more lines,
|
||||
* so a macro solution was chosen */
|
||||
#define EV_BEGIN_WATCHER(cppstem,cstem) \
|
||||
\
|
||||
struct cppstem : base<ev_ ## cstem, cppstem> \
|
||||
{ \
|
||||
void start () throw () \
|
||||
{ \
|
||||
ev_ ## cstem ## _start (EV_A_ static_cast<ev_ ## cstem *>(this)); \
|
||||
} \
|
||||
\
|
||||
void stop () throw () \
|
||||
{ \
|
||||
ev_ ## cstem ## _stop (EV_A_ static_cast<ev_ ## cstem *>(this)); \
|
||||
} \
|
||||
\
|
||||
cppstem EV_CONSTRUCT(cppstem,cstem) \
|
||||
\
|
||||
~cppstem () throw () \
|
||||
{ \
|
||||
stop (); \
|
||||
} \
|
||||
\
|
||||
using base<ev_ ## cstem, cppstem>::set; \
|
||||
\
|
||||
private: \
|
||||
\
|
||||
cppstem (const cppstem &o); \
|
||||
\
|
||||
cppstem &operator =(const cppstem &o); \
|
||||
\
|
||||
public:
|
||||
|
||||
#define EV_END_WATCHER(cppstem,cstem) \
|
||||
};
|
||||
|
||||
EV_BEGIN_WATCHER (io, io)
|
||||
void set (int fd, int events) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_io_set (static_cast<ev_io *>(this), fd, events);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void set (int events) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_io_set (static_cast<ev_io *>(this), fd, events);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (int fd, int events) throw ()
|
||||
{
|
||||
set (fd, events);
|
||||
start ();
|
||||
}
|
||||
EV_END_WATCHER (io, io)
|
||||
|
||||
EV_BEGIN_WATCHER (timer, timer)
|
||||
void set (ev_tstamp after, ev_tstamp repeat = 0.) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_timer_set (static_cast<ev_timer *>(this), after, repeat);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (ev_tstamp after, ev_tstamp repeat = 0.) throw ()
|
||||
{
|
||||
set (after, repeat);
|
||||
start ();
|
||||
}
|
||||
|
||||
void again () throw ()
|
||||
{
|
||||
ev_timer_again (EV_A_ static_cast<ev_timer *>(this));
|
||||
}
|
||||
|
||||
ev_tstamp remaining ()
|
||||
{
|
||||
return ev_timer_remaining (EV_A_ static_cast<ev_timer *>(this));
|
||||
}
|
||||
EV_END_WATCHER (timer, timer)
|
||||
|
||||
#if EV_PERIODIC_ENABLE
|
||||
EV_BEGIN_WATCHER (periodic, periodic)
|
||||
void set (ev_tstamp at, ev_tstamp interval = 0.) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_periodic_set (static_cast<ev_periodic *>(this), at, interval, 0);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (ev_tstamp at, ev_tstamp interval = 0.) throw ()
|
||||
{
|
||||
set (at, interval);
|
||||
start ();
|
||||
}
|
||||
|
||||
void again () throw ()
|
||||
{
|
||||
ev_periodic_again (EV_A_ static_cast<ev_periodic *>(this));
|
||||
}
|
||||
EV_END_WATCHER (periodic, periodic)
|
||||
#endif
|
||||
|
||||
#if EV_SIGNAL_ENABLE
|
||||
EV_BEGIN_WATCHER (sig, signal)
|
||||
void set (int signum) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_signal_set (static_cast<ev_signal *>(this), signum);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (int signum) throw ()
|
||||
{
|
||||
set (signum);
|
||||
start ();
|
||||
}
|
||||
EV_END_WATCHER (sig, signal)
|
||||
#endif
|
||||
|
||||
#if EV_CHILD_ENABLE
|
||||
EV_BEGIN_WATCHER (child, child)
|
||||
void set (int pid, int trace = 0) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_child_set (static_cast<ev_child *>(this), pid, trace);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (int pid, int trace = 0) throw ()
|
||||
{
|
||||
set (pid, trace);
|
||||
start ();
|
||||
}
|
||||
EV_END_WATCHER (child, child)
|
||||
#endif
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
EV_BEGIN_WATCHER (stat, stat)
|
||||
void set (const char *path, ev_tstamp interval = 0.) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_stat_set (static_cast<ev_stat *>(this), path, interval);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (const char *path, ev_tstamp interval = 0.) throw ()
|
||||
{
|
||||
stop ();
|
||||
set (path, interval);
|
||||
start ();
|
||||
}
|
||||
|
||||
void update () throw ()
|
||||
{
|
||||
ev_stat_stat (EV_A_ static_cast<ev_stat *>(this));
|
||||
}
|
||||
EV_END_WATCHER (stat, stat)
|
||||
#endif
|
||||
|
||||
#if EV_IDLE_ENABLE
|
||||
EV_BEGIN_WATCHER (idle, idle)
|
||||
void set () throw () { }
|
||||
EV_END_WATCHER (idle, idle)
|
||||
#endif
|
||||
|
||||
#if EV_PREPARE_ENABLE
|
||||
EV_BEGIN_WATCHER (prepare, prepare)
|
||||
void set () throw () { }
|
||||
EV_END_WATCHER (prepare, prepare)
|
||||
#endif
|
||||
|
||||
#if EV_CHECK_ENABLE
|
||||
EV_BEGIN_WATCHER (check, check)
|
||||
void set () throw () { }
|
||||
EV_END_WATCHER (check, check)
|
||||
#endif
|
||||
|
||||
#if EV_EMBED_ENABLE
|
||||
EV_BEGIN_WATCHER (embed, embed)
|
||||
void set_embed (struct ev_loop *embedded_loop) throw ()
|
||||
{
|
||||
int active = is_active ();
|
||||
if (active) stop ();
|
||||
ev_embed_set (static_cast<ev_embed *>(this), embedded_loop);
|
||||
if (active) start ();
|
||||
}
|
||||
|
||||
void start (struct ev_loop *embedded_loop) throw ()
|
||||
{
|
||||
set (embedded_loop);
|
||||
start ();
|
||||
}
|
||||
|
||||
void sweep ()
|
||||
{
|
||||
ev_embed_sweep (EV_A_ static_cast<ev_embed *>(this));
|
||||
}
|
||||
EV_END_WATCHER (embed, embed)
|
||||
#endif
|
||||
|
||||
#if EV_FORK_ENABLE
|
||||
EV_BEGIN_WATCHER (fork, fork)
|
||||
void set () throw () { }
|
||||
EV_END_WATCHER (fork, fork)
|
||||
#endif
|
||||
|
||||
#if EV_ASYNC_ENABLE
|
||||
EV_BEGIN_WATCHER (async, async)
|
||||
void send () throw ()
|
||||
{
|
||||
ev_async_send (EV_A_ static_cast<ev_async *>(this));
|
||||
}
|
||||
|
||||
bool async_pending () throw ()
|
||||
{
|
||||
return ev_async_pending (static_cast<ev_async *>(this));
|
||||
}
|
||||
EV_END_WATCHER (async, async)
|
||||
#endif
|
||||
|
||||
#undef EV_PX
|
||||
#undef EV_PX_
|
||||
#undef EV_CONSTRUCT
|
||||
#undef EV_BEGIN_WATCHER
|
||||
#undef EV_END_WATCHER
|
||||
}
|
||||
|
||||
#endif
|
||||
|
5647
libev/ev.3
5143
libev/ev.c
854
libev/ev.h
@@ -1,854 +0,0 @@
|
||||
/*
|
||||
* libev native API header
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011,2012,2015 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef EV_H_
|
||||
#define EV_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define EV_CPP(x) x
|
||||
# if __cplusplus >= 201103L
|
||||
# define EV_THROW noexcept
|
||||
# else
|
||||
# define EV_THROW throw ()
|
||||
# endif
|
||||
#else
|
||||
# define EV_CPP(x)
|
||||
# define EV_THROW
|
||||
#endif
|
||||
|
||||
EV_CPP(extern "C" {)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* pre-4.0 compatibility */
|
||||
#ifndef EV_COMPAT3
|
||||
# define EV_COMPAT3 1
|
||||
#endif
|
||||
|
||||
#ifndef EV_FEATURES
|
||||
# if defined __OPTIMIZE_SIZE__
|
||||
# define EV_FEATURES 0x7c
|
||||
# else
|
||||
# define EV_FEATURES 0x7f
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define EV_FEATURE_CODE ((EV_FEATURES) & 1)
|
||||
#define EV_FEATURE_DATA ((EV_FEATURES) & 2)
|
||||
#define EV_FEATURE_CONFIG ((EV_FEATURES) & 4)
|
||||
#define EV_FEATURE_API ((EV_FEATURES) & 8)
|
||||
#define EV_FEATURE_WATCHERS ((EV_FEATURES) & 16)
|
||||
#define EV_FEATURE_BACKENDS ((EV_FEATURES) & 32)
|
||||
#define EV_FEATURE_OS ((EV_FEATURES) & 64)
|
||||
|
||||
/* these priorities are inclusive, higher priorities will be invoked earlier */
|
||||
#ifndef EV_MINPRI
|
||||
# define EV_MINPRI (EV_FEATURE_CONFIG ? -2 : 0)
|
||||
#endif
|
||||
#ifndef EV_MAXPRI
|
||||
# define EV_MAXPRI (EV_FEATURE_CONFIG ? +2 : 0)
|
||||
#endif
|
||||
|
||||
#ifndef EV_MULTIPLICITY
|
||||
# define EV_MULTIPLICITY EV_FEATURE_CONFIG
|
||||
#endif
|
||||
|
||||
#ifndef EV_PERIODIC_ENABLE
|
||||
# define EV_PERIODIC_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_STAT_ENABLE
|
||||
# define EV_STAT_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_PREPARE_ENABLE
|
||||
# define EV_PREPARE_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_CHECK_ENABLE
|
||||
# define EV_CHECK_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_IDLE_ENABLE
|
||||
# define EV_IDLE_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_FORK_ENABLE
|
||||
# define EV_FORK_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_CLEANUP_ENABLE
|
||||
# define EV_CLEANUP_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_SIGNAL_ENABLE
|
||||
# define EV_SIGNAL_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_CHILD_ENABLE
|
||||
# ifdef _WIN32
|
||||
# define EV_CHILD_ENABLE 0
|
||||
# else
|
||||
# define EV_CHILD_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EV_ASYNC_ENABLE
|
||||
# define EV_ASYNC_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_EMBED_ENABLE
|
||||
# define EV_EMBED_ENABLE EV_FEATURE_WATCHERS
|
||||
#endif
|
||||
|
||||
#ifndef EV_WALK_ENABLE
|
||||
# define EV_WALK_ENABLE 0 /* not yet */
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#if EV_CHILD_ENABLE && !EV_SIGNAL_ENABLE
|
||||
# undef EV_SIGNAL_ENABLE
|
||||
# define EV_SIGNAL_ENABLE 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef double ev_tstamp;
|
||||
|
||||
#include <string.h> /* for memmove */
|
||||
|
||||
#ifndef EV_ATOMIC_T
|
||||
# include <signal.h>
|
||||
# define EV_ATOMIC_T sig_atomic_t volatile
|
||||
#endif
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
# ifdef _WIN32
|
||||
# include <time.h>
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
/* support multiple event loops? */
|
||||
#if EV_MULTIPLICITY
|
||||
struct ev_loop;
|
||||
# define EV_P struct ev_loop *loop /* a loop as sole parameter in a declaration */
|
||||
# define EV_P_ EV_P, /* a loop as first of multiple parameters */
|
||||
# define EV_A loop /* a loop as sole argument to a function call */
|
||||
# define EV_A_ EV_A, /* a loop as first of multiple arguments */
|
||||
# define EV_DEFAULT_UC ev_default_loop_uc_ () /* the default loop, if initialised, as sole arg */
|
||||
# define EV_DEFAULT_UC_ EV_DEFAULT_UC, /* the default loop as first of multiple arguments */
|
||||
# define EV_DEFAULT ev_default_loop (0) /* the default loop as sole arg */
|
||||
# define EV_DEFAULT_ EV_DEFAULT, /* the default loop as first of multiple arguments */
|
||||
#else
|
||||
# define EV_P void
|
||||
# define EV_P_
|
||||
# define EV_A
|
||||
# define EV_A_
|
||||
# define EV_DEFAULT
|
||||
# define EV_DEFAULT_
|
||||
# define EV_DEFAULT_UC
|
||||
# define EV_DEFAULT_UC_
|
||||
# undef EV_EMBED_ENABLE
|
||||
#endif
|
||||
|
||||
/* EV_INLINE is used for functions in header files */
|
||||
#if __STDC_VERSION__ >= 199901L || __GNUC__ >= 3
|
||||
# define EV_INLINE static inline
|
||||
#else
|
||||
# define EV_INLINE static
|
||||
#endif
|
||||
|
||||
#ifdef EV_API_STATIC
|
||||
# define EV_API_DECL static
|
||||
#else
|
||||
# define EV_API_DECL extern
|
||||
#endif
|
||||
|
||||
/* EV_PROTOTYPES can be used to switch of prototype declarations */
|
||||
#ifndef EV_PROTOTYPES
|
||||
# define EV_PROTOTYPES 1
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define EV_VERSION_MAJOR 4
|
||||
#define EV_VERSION_MINOR 24
|
||||
|
||||
/* eventmask, revents, events... */
|
||||
enum {
|
||||
EV_UNDEF = (int)0xFFFFFFFF, /* guaranteed to be invalid */
|
||||
EV_NONE = 0x00, /* no events */
|
||||
EV_READ = 0x01, /* ev_io detected read will not block */
|
||||
EV_WRITE = 0x02, /* ev_io detected write will not block */
|
||||
EV__IOFDSET = 0x80, /* internal use only */
|
||||
EV_IO = EV_READ, /* alias for type-detection */
|
||||
EV_TIMER = 0x00000100, /* timer timed out */
|
||||
#if EV_COMPAT3
|
||||
EV_TIMEOUT = EV_TIMER, /* pre 4.0 API compatibility */
|
||||
#endif
|
||||
EV_PERIODIC = 0x00000200, /* periodic timer timed out */
|
||||
EV_SIGNAL = 0x00000400, /* signal was received */
|
||||
EV_CHILD = 0x00000800, /* child/pid had status change */
|
||||
EV_STAT = 0x00001000, /* stat data changed */
|
||||
EV_IDLE = 0x00002000, /* event loop is idling */
|
||||
EV_PREPARE = 0x00004000, /* event loop about to poll */
|
||||
EV_CHECK = 0x00008000, /* event loop finished poll */
|
||||
EV_EMBED = 0x00010000, /* embedded event loop needs sweep */
|
||||
EV_FORK = 0x00020000, /* event loop resumed in child */
|
||||
EV_CLEANUP = 0x00040000, /* event loop resumed in child */
|
||||
EV_ASYNC = 0x00080000, /* async intra-loop signal */
|
||||
EV_CUSTOM = 0x01000000, /* for use by user code */
|
||||
EV_ERROR = (int)0x80000000 /* sent when an error occurs */
|
||||
};
|
||||
|
||||
/* can be used to add custom fields to all watchers, while losing binary compatibility */
|
||||
#ifndef EV_COMMON
|
||||
# define EV_COMMON void *data;
|
||||
#endif
|
||||
|
||||
#ifndef EV_CB_DECLARE
|
||||
# define EV_CB_DECLARE(type) void (*cb)(EV_P_ struct type *w, int revents);
|
||||
#endif
|
||||
#ifndef EV_CB_INVOKE
|
||||
# define EV_CB_INVOKE(watcher,revents) (watcher)->cb (EV_A_ (watcher), (revents))
|
||||
#endif
|
||||
|
||||
/* not official, do not use */
|
||||
#define EV_CB(type,name) void name (EV_P_ struct ev_ ## type *w, int revents)
|
||||
|
||||
/*
|
||||
* struct member types:
|
||||
* private: you may look at them, but not change them,
|
||||
* and they might not mean anything to you.
|
||||
* ro: can be read anytime, but only changed when the watcher isn't active.
|
||||
* rw: can be read and modified anytime, even when the watcher is active.
|
||||
*
|
||||
* some internal details that might be helpful for debugging:
|
||||
*
|
||||
* active is either 0, which means the watcher is not active,
|
||||
* or the array index of the watcher (periodics, timers)
|
||||
* or the array index + 1 (most other watchers)
|
||||
* or simply 1 for watchers that aren't in some array.
|
||||
* pending is either 0, in which case the watcher isn't,
|
||||
* or the array index + 1 in the pendings array.
|
||||
*/
|
||||
|
||||
#if EV_MINPRI == EV_MAXPRI
|
||||
# define EV_DECL_PRIORITY
|
||||
#elif !defined (EV_DECL_PRIORITY)
|
||||
# define EV_DECL_PRIORITY int priority;
|
||||
#endif
|
||||
|
||||
/* shared by all watchers */
|
||||
#define EV_WATCHER(type) \
|
||||
int active; /* private */ \
|
||||
int pending; /* private */ \
|
||||
EV_DECL_PRIORITY /* private */ \
|
||||
EV_COMMON /* rw */ \
|
||||
EV_CB_DECLARE (type) /* private */
|
||||
|
||||
#define EV_WATCHER_LIST(type) \
|
||||
EV_WATCHER (type) \
|
||||
struct ev_watcher_list *next; /* private */
|
||||
|
||||
#define EV_WATCHER_TIME(type) \
|
||||
EV_WATCHER (type) \
|
||||
ev_tstamp at; /* private */
|
||||
|
||||
/* base class, nothing to see here unless you subclass */
|
||||
typedef struct ev_watcher
|
||||
{
|
||||
EV_WATCHER (ev_watcher)
|
||||
} ev_watcher;
|
||||
|
||||
/* base class, nothing to see here unless you subclass */
|
||||
typedef struct ev_watcher_list
|
||||
{
|
||||
EV_WATCHER_LIST (ev_watcher_list)
|
||||
} ev_watcher_list;
|
||||
|
||||
/* base class, nothing to see here unless you subclass */
|
||||
typedef struct ev_watcher_time
|
||||
{
|
||||
EV_WATCHER_TIME (ev_watcher_time)
|
||||
} ev_watcher_time;
|
||||
|
||||
/* invoked when fd is either EV_READable or EV_WRITEable */
|
||||
/* revent EV_READ, EV_WRITE */
|
||||
typedef struct ev_io
|
||||
{
|
||||
EV_WATCHER_LIST (ev_io)
|
||||
|
||||
int fd; /* ro */
|
||||
int events; /* ro */
|
||||
} ev_io;
|
||||
|
||||
/* invoked after a specific time, repeatable (based on monotonic clock) */
|
||||
/* revent EV_TIMEOUT */
|
||||
typedef struct ev_timer
|
||||
{
|
||||
EV_WATCHER_TIME (ev_timer)
|
||||
|
||||
ev_tstamp repeat; /* rw */
|
||||
} ev_timer;
|
||||
|
||||
/* invoked at some specific time, possibly repeating at regular intervals (based on UTC) */
|
||||
/* revent EV_PERIODIC */
|
||||
typedef struct ev_periodic
|
||||
{
|
||||
EV_WATCHER_TIME (ev_periodic)
|
||||
|
||||
ev_tstamp offset; /* rw */
|
||||
ev_tstamp interval; /* rw */
|
||||
ev_tstamp (*reschedule_cb)(struct ev_periodic *w, ev_tstamp now) EV_THROW; /* rw */
|
||||
} ev_periodic;
|
||||
|
||||
/* invoked when the given signal has been received */
|
||||
/* revent EV_SIGNAL */
|
||||
typedef struct ev_signal
|
||||
{
|
||||
EV_WATCHER_LIST (ev_signal)
|
||||
|
||||
int signum; /* ro */
|
||||
} ev_signal;
|
||||
|
||||
/* invoked when sigchld is received and waitpid indicates the given pid */
|
||||
/* revent EV_CHILD */
|
||||
/* does not support priorities */
|
||||
typedef struct ev_child
|
||||
{
|
||||
EV_WATCHER_LIST (ev_child)
|
||||
|
||||
int flags; /* private */
|
||||
int pid; /* ro */
|
||||
int rpid; /* rw, holds the received pid */
|
||||
int rstatus; /* rw, holds the exit status, use the macros from sys/wait.h */
|
||||
} ev_child;
|
||||
|
||||
#if EV_STAT_ENABLE
|
||||
/* st_nlink = 0 means missing file or other error */
|
||||
# ifdef _WIN32
|
||||
typedef struct _stati64 ev_statdata;
|
||||
# else
|
||||
typedef struct stat ev_statdata;
|
||||
# endif
|
||||
|
||||
/* invoked each time the stat data changes for a given path */
|
||||
/* revent EV_STAT */
|
||||
typedef struct ev_stat
|
||||
{
|
||||
EV_WATCHER_LIST (ev_stat)
|
||||
|
||||
ev_timer timer; /* private */
|
||||
ev_tstamp interval; /* ro */
|
||||
const char *path; /* ro */
|
||||
ev_statdata prev; /* ro */
|
||||
ev_statdata attr; /* ro */
|
||||
|
||||
int wd; /* wd for inotify, fd for kqueue */
|
||||
} ev_stat;
|
||||
#endif
|
||||
|
||||
#if EV_IDLE_ENABLE
|
||||
/* invoked when the nothing else needs to be done, keeps the process from blocking */
|
||||
/* revent EV_IDLE */
|
||||
typedef struct ev_idle
|
||||
{
|
||||
EV_WATCHER (ev_idle)
|
||||
} ev_idle;
|
||||
#endif
|
||||
|
||||
/* invoked for each run of the mainloop, just before the blocking call */
|
||||
/* you can still change events in any way you like */
|
||||
/* revent EV_PREPARE */
|
||||
typedef struct ev_prepare
|
||||
{
|
||||
EV_WATCHER (ev_prepare)
|
||||
} ev_prepare;
|
||||
|
||||
/* invoked for each run of the mainloop, just after the blocking call */
|
||||
/* revent EV_CHECK */
|
||||
typedef struct ev_check
|
||||
{
|
||||
EV_WATCHER (ev_check)
|
||||
} ev_check;
|
||||
|
||||
#if EV_FORK_ENABLE
|
||||
/* the callback gets invoked before check in the child process when a fork was detected */
|
||||
/* revent EV_FORK */
|
||||
typedef struct ev_fork
|
||||
{
|
||||
EV_WATCHER (ev_fork)
|
||||
} ev_fork;
|
||||
#endif
|
||||
|
||||
#if EV_CLEANUP_ENABLE
|
||||
/* is invoked just before the loop gets destroyed */
|
||||
/* revent EV_CLEANUP */
|
||||
typedef struct ev_cleanup
|
||||
{
|
||||
EV_WATCHER (ev_cleanup)
|
||||
} ev_cleanup;
|
||||
#endif
|
||||
|
||||
#if EV_EMBED_ENABLE
|
||||
/* used to embed an event loop inside another */
|
||||
/* the callback gets invoked when the event loop has handled events, and can be 0 */
|
||||
typedef struct ev_embed
|
||||
{
|
||||
EV_WATCHER (ev_embed)
|
||||
|
||||
struct ev_loop *other; /* ro */
|
||||
ev_io io; /* private */
|
||||
ev_prepare prepare; /* private */
|
||||
ev_check check; /* unused */
|
||||
ev_timer timer; /* unused */
|
||||
ev_periodic periodic; /* unused */
|
||||
ev_idle idle; /* unused */
|
||||
ev_fork fork; /* private */
|
||||
#if EV_CLEANUP_ENABLE
|
||||
ev_cleanup cleanup; /* unused */
|
||||
#endif
|
||||
} ev_embed;
|
||||
#endif
|
||||
|
||||
#if EV_ASYNC_ENABLE
|
||||
/* invoked when somebody calls ev_async_send on the watcher */
|
||||
/* revent EV_ASYNC */
|
||||
typedef struct ev_async
|
||||
{
|
||||
EV_WATCHER (ev_async)
|
||||
|
||||
EV_ATOMIC_T sent; /* private */
|
||||
} ev_async;
|
||||
|
||||
# define ev_async_pending(w) (+(w)->sent)
|
||||
#endif
|
||||
|
||||
/* the presence of this union forces similar struct layout */
|
||||
union ev_any_watcher
|
||||
{
|
||||
struct ev_watcher w;
|
||||
struct ev_watcher_list wl;
|
||||
|
||||
struct ev_io io;
|
||||
struct ev_timer timer;
|
||||
struct ev_periodic periodic;
|
||||
struct ev_signal signal;
|
||||
struct ev_child child;
|
||||
#if EV_STAT_ENABLE
|
||||
struct ev_stat stat;
|
||||
#endif
|
||||
#if EV_IDLE_ENABLE
|
||||
struct ev_idle idle;
|
||||
#endif
|
||||
struct ev_prepare prepare;
|
||||
struct ev_check check;
|
||||
#if EV_FORK_ENABLE
|
||||
struct ev_fork fork;
|
||||
#endif
|
||||
#if EV_CLEANUP_ENABLE
|
||||
struct ev_cleanup cleanup;
|
||||
#endif
|
||||
#if EV_EMBED_ENABLE
|
||||
struct ev_embed embed;
|
||||
#endif
|
||||
#if EV_ASYNC_ENABLE
|
||||
struct ev_async async;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* flag bits for ev_default_loop and ev_loop_new */
|
||||
enum {
|
||||
/* the default */
|
||||
EVFLAG_AUTO = 0x00000000U, /* not quite a mask */
|
||||
/* flag bits */
|
||||
EVFLAG_NOENV = 0x01000000U, /* do NOT consult environment */
|
||||
EVFLAG_FORKCHECK = 0x02000000U, /* check for a fork in each iteration */
|
||||
/* debugging/feature disable */
|
||||
EVFLAG_NOINOTIFY = 0x00100000U, /* do not attempt to use inotify */
|
||||
#if EV_COMPAT3
|
||||
EVFLAG_NOSIGFD = 0, /* compatibility to pre-3.9 */
|
||||
#endif
|
||||
EVFLAG_SIGNALFD = 0x00200000U, /* attempt to use signalfd */
|
||||
EVFLAG_NOSIGMASK = 0x00400000U /* avoid modifying the signal mask */
|
||||
};
|
||||
|
||||
/* method bits to be ored together */
|
||||
enum {
|
||||
EVBACKEND_SELECT = 0x00000001U, /* available just about anywhere */
|
||||
EVBACKEND_POLL = 0x00000002U, /* !win, !aix, broken on osx */
|
||||
EVBACKEND_EPOLL = 0x00000004U, /* linux */
|
||||
EVBACKEND_KQUEUE = 0x00000008U, /* bsd, broken on osx */
|
||||
EVBACKEND_DEVPOLL = 0x00000010U, /* solaris 8 */ /* NYI */
|
||||
EVBACKEND_PORT = 0x00000020U, /* solaris 10 */
|
||||
EVBACKEND_ALL = 0x0000003FU, /* all known backends */
|
||||
EVBACKEND_MASK = 0x0000FFFFU /* all future backends */
|
||||
};
|
||||
|
||||
#if EV_PROTOTYPES
|
||||
EV_API_DECL int ev_version_major (void) EV_THROW;
|
||||
EV_API_DECL int ev_version_minor (void) EV_THROW;
|
||||
|
||||
EV_API_DECL unsigned int ev_supported_backends (void) EV_THROW;
|
||||
EV_API_DECL unsigned int ev_recommended_backends (void) EV_THROW;
|
||||
EV_API_DECL unsigned int ev_embeddable_backends (void) EV_THROW;
|
||||
|
||||
EV_API_DECL ev_tstamp ev_time (void) EV_THROW;
|
||||
EV_API_DECL void ev_sleep (ev_tstamp delay) EV_THROW; /* sleep for a while */
|
||||
|
||||
/* Sets the allocation function to use, works like realloc.
|
||||
* It is used to allocate and free memory.
|
||||
* If it returns zero when memory needs to be allocated, the library might abort
|
||||
* or take some potentially destructive action.
|
||||
* The default is your system realloc function.
|
||||
*/
|
||||
EV_API_DECL void ev_set_allocator (void *(*cb)(void *ptr, long size) EV_THROW) EV_THROW;
|
||||
|
||||
/* set the callback function to call on a
|
||||
* retryable syscall error
|
||||
* (such as failed select, poll, epoll_wait)
|
||||
*/
|
||||
EV_API_DECL void ev_set_syserr_cb (void (*cb)(const char *msg) EV_THROW) EV_THROW;
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
|
||||
/* the default loop is the only one that handles signals and child watchers */
|
||||
/* you can call this as often as you like */
|
||||
EV_API_DECL struct ev_loop *ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW;
|
||||
|
||||
#ifdef EV_API_STATIC
|
||||
EV_API_DECL struct ev_loop *ev_default_loop_ptr;
|
||||
#endif
|
||||
|
||||
EV_INLINE struct ev_loop *
|
||||
ev_default_loop_uc_ (void) EV_THROW
|
||||
{
|
||||
extern struct ev_loop *ev_default_loop_ptr;
|
||||
|
||||
return ev_default_loop_ptr;
|
||||
}
|
||||
|
||||
EV_INLINE int
|
||||
ev_is_default_loop (EV_P) EV_THROW
|
||||
{
|
||||
return EV_A == EV_DEFAULT_UC;
|
||||
}
|
||||
|
||||
/* create and destroy alternative loops that don't handle signals */
|
||||
EV_API_DECL struct ev_loop *ev_loop_new (unsigned int flags EV_CPP (= 0)) EV_THROW;
|
||||
|
||||
EV_API_DECL ev_tstamp ev_now (EV_P) EV_THROW; /* time w.r.t. timers and the eventloop, updated after each poll */
|
||||
|
||||
#else
|
||||
|
||||
EV_API_DECL int ev_default_loop (unsigned int flags EV_CPP (= 0)) EV_THROW; /* returns true when successful */
|
||||
|
||||
EV_API_DECL ev_tstamp ev_rt_now;
|
||||
|
||||
EV_INLINE ev_tstamp
|
||||
ev_now (void) EV_THROW
|
||||
{
|
||||
return ev_rt_now;
|
||||
}
|
||||
|
||||
/* looks weird, but ev_is_default_loop (EV_A) still works if this exists */
|
||||
EV_INLINE int
|
||||
ev_is_default_loop (void) EV_THROW
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* multiplicity */
|
||||
|
||||
/* destroy event loops, also works for the default loop */
|
||||
EV_API_DECL void ev_loop_destroy (EV_P);
|
||||
|
||||
/* this needs to be called after fork, to duplicate the loop */
|
||||
/* when you want to re-use it in the child */
|
||||
/* you can call it in either the parent or the child */
|
||||
/* you can actually call it at any time, anywhere :) */
|
||||
EV_API_DECL void ev_loop_fork (EV_P) EV_THROW;
|
||||
|
||||
EV_API_DECL unsigned int ev_backend (EV_P) EV_THROW; /* backend in use by loop */
|
||||
|
||||
EV_API_DECL void ev_now_update (EV_P) EV_THROW; /* update event loop time */
|
||||
|
||||
#if EV_WALK_ENABLE
|
||||
/* walk (almost) all watchers in the loop of a given type, invoking the */
|
||||
/* callback on every such watcher. The callback might stop the watcher, */
|
||||
/* but do nothing else with the loop */
|
||||
EV_API_DECL void ev_walk (EV_P_ int types, void (*cb)(EV_P_ int type, void *w)) EV_THROW;
|
||||
#endif
|
||||
|
||||
#endif /* prototypes */
|
||||
|
||||
/* ev_run flags values */
|
||||
enum {
|
||||
EVRUN_NOWAIT = 1, /* do not block/wait */
|
||||
EVRUN_ONCE = 2 /* block *once* only */
|
||||
};
|
||||
|
||||
/* ev_break how values */
|
||||
enum {
|
||||
EVBREAK_CANCEL = 0, /* undo unloop */
|
||||
EVBREAK_ONE = 1, /* unloop once */
|
||||
EVBREAK_ALL = 2 /* unloop all loops */
|
||||
};
|
||||
|
||||
#if EV_PROTOTYPES
|
||||
EV_API_DECL int ev_run (EV_P_ int flags EV_CPP (= 0));
|
||||
EV_API_DECL void ev_break (EV_P_ int how EV_CPP (= EVBREAK_ONE)) EV_THROW; /* break out of the loop */
|
||||
|
||||
/*
|
||||
* ref/unref can be used to add or remove a refcount on the mainloop. every watcher
|
||||
* keeps one reference. if you have a long-running watcher you never unregister that
|
||||
* should not keep ev_loop from running, unref() after starting, and ref() before stopping.
|
||||
*/
|
||||
EV_API_DECL void ev_ref (EV_P) EV_THROW;
|
||||
EV_API_DECL void ev_unref (EV_P) EV_THROW;
|
||||
|
||||
/*
|
||||
* convenience function, wait for a single event, without registering an event watcher
|
||||
* if timeout is < 0, do wait indefinitely
|
||||
*/
|
||||
EV_API_DECL void ev_once (EV_P_ int fd, int events, ev_tstamp timeout, void (*cb)(int revents, void *arg), void *arg) EV_THROW;
|
||||
|
||||
# if EV_FEATURE_API
|
||||
EV_API_DECL unsigned int ev_iteration (EV_P) EV_THROW; /* number of loop iterations */
|
||||
EV_API_DECL unsigned int ev_depth (EV_P) EV_THROW; /* #ev_loop enters - #ev_loop leaves */
|
||||
EV_API_DECL void ev_verify (EV_P) EV_THROW; /* abort if loop data corrupted */
|
||||
|
||||
EV_API_DECL void ev_set_io_collect_interval (EV_P_ ev_tstamp interval) EV_THROW; /* sleep at least this time, default 0 */
|
||||
EV_API_DECL void ev_set_timeout_collect_interval (EV_P_ ev_tstamp interval) EV_THROW; /* sleep at least this time, default 0 */
|
||||
|
||||
/* advanced stuff for threading etc. support, see docs */
|
||||
EV_API_DECL void ev_set_userdata (EV_P_ void *data) EV_THROW;
|
||||
EV_API_DECL void *ev_userdata (EV_P) EV_THROW;
|
||||
typedef void (*ev_loop_callback)(EV_P);
|
||||
EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_THROW;
|
||||
/* C++ doesn't allow the use of the ev_loop_callback typedef here, so we need to spell it out */
|
||||
EV_API_DECL void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_THROW, void (*acquire)(EV_P) EV_THROW) EV_THROW;
|
||||
|
||||
EV_API_DECL unsigned int ev_pending_count (EV_P) EV_THROW; /* number of pending events, if any */
|
||||
EV_API_DECL void ev_invoke_pending (EV_P); /* invoke all pending watchers */
|
||||
|
||||
/*
|
||||
* stop/start the timer handling.
|
||||
*/
|
||||
EV_API_DECL void ev_suspend (EV_P) EV_THROW;
|
||||
EV_API_DECL void ev_resume (EV_P) EV_THROW;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/* these may evaluate ev multiple times, and the other arguments at most once */
|
||||
/* either use ev_init + ev_TYPE_set, or the ev_TYPE_init macro, below, to first initialise a watcher */
|
||||
#define ev_init(ev,cb_) do { \
|
||||
((ev_watcher *)(void *)(ev))->active = \
|
||||
((ev_watcher *)(void *)(ev))->pending = 0; \
|
||||
ev_set_priority ((ev), 0); \
|
||||
ev_set_cb ((ev), cb_); \
|
||||
} while (0)
|
||||
|
||||
#define ev_io_set(ev,fd_,events_) do { (ev)->fd = (fd_); (ev)->events = (events_) | EV__IOFDSET; } while (0)
|
||||
#define ev_timer_set(ev,after_,repeat_) do { ((ev_watcher_time *)(ev))->at = (after_); (ev)->repeat = (repeat_); } while (0)
|
||||
#define ev_periodic_set(ev,ofs_,ival_,rcb_) do { (ev)->offset = (ofs_); (ev)->interval = (ival_); (ev)->reschedule_cb = (rcb_); } while (0)
|
||||
#define ev_signal_set(ev,signum_) do { (ev)->signum = (signum_); } while (0)
|
||||
#define ev_child_set(ev,pid_,trace_) do { (ev)->pid = (pid_); (ev)->flags = !!(trace_); } while (0)
|
||||
#define ev_stat_set(ev,path_,interval_) do { (ev)->path = (path_); (ev)->interval = (interval_); (ev)->wd = -2; } while (0)
|
||||
#define ev_idle_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#define ev_prepare_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#define ev_check_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#define ev_embed_set(ev,other_) do { (ev)->other = (other_); } while (0)
|
||||
#define ev_fork_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#define ev_cleanup_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
#define ev_async_set(ev) /* nop, yes, this is a serious in-joke */
|
||||
|
||||
#define ev_io_init(ev,cb,fd,events) do { ev_init ((ev), (cb)); ev_io_set ((ev),(fd),(events)); } while (0)
|
||||
#define ev_timer_init(ev,cb,after,repeat) do { ev_init ((ev), (cb)); ev_timer_set ((ev),(after),(repeat)); } while (0)
|
||||
#define ev_periodic_init(ev,cb,ofs,ival,rcb) do { ev_init ((ev), (cb)); ev_periodic_set ((ev),(ofs),(ival),(rcb)); } while (0)
|
||||
#define ev_signal_init(ev,cb,signum) do { ev_init ((ev), (cb)); ev_signal_set ((ev), (signum)); } while (0)
|
||||
#define ev_child_init(ev,cb,pid,trace) do { ev_init ((ev), (cb)); ev_child_set ((ev),(pid),(trace)); } while (0)
|
||||
#define ev_stat_init(ev,cb,path,interval) do { ev_init ((ev), (cb)); ev_stat_set ((ev),(path),(interval)); } while (0)
|
||||
#define ev_idle_init(ev,cb) do { ev_init ((ev), (cb)); ev_idle_set ((ev)); } while (0)
|
||||
#define ev_prepare_init(ev,cb) do { ev_init ((ev), (cb)); ev_prepare_set ((ev)); } while (0)
|
||||
#define ev_check_init(ev,cb) do { ev_init ((ev), (cb)); ev_check_set ((ev)); } while (0)
|
||||
#define ev_embed_init(ev,cb,other) do { ev_init ((ev), (cb)); ev_embed_set ((ev),(other)); } while (0)
|
||||
#define ev_fork_init(ev,cb) do { ev_init ((ev), (cb)); ev_fork_set ((ev)); } while (0)
|
||||
#define ev_cleanup_init(ev,cb) do { ev_init ((ev), (cb)); ev_cleanup_set ((ev)); } while (0)
|
||||
#define ev_async_init(ev,cb) do { ev_init ((ev), (cb)); ev_async_set ((ev)); } while (0)
|
||||
|
||||
#define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */
|
||||
#define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */
|
||||
|
||||
#define ev_cb_(ev) (ev)->cb /* rw */
|
||||
#define ev_cb(ev) (memmove (&ev_cb_ (ev), &((ev_watcher *)(ev))->cb, sizeof (ev_cb_ (ev))), (ev)->cb)
|
||||
|
||||
#if EV_MINPRI == EV_MAXPRI
|
||||
# define ev_priority(ev) ((ev), EV_MINPRI)
|
||||
# define ev_set_priority(ev,pri) ((ev), (pri))
|
||||
#else
|
||||
# define ev_priority(ev) (+(((ev_watcher *)(void *)(ev))->priority))
|
||||
# define ev_set_priority(ev,pri) ( (ev_watcher *)(void *)(ev))->priority = (pri)
|
||||
#endif
|
||||
|
||||
#define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at)
|
||||
|
||||
#ifndef ev_set_cb
|
||||
# define ev_set_cb(ev,cb_) (ev_cb_ (ev) = (cb_), memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev))))
|
||||
#endif
|
||||
|
||||
/* stopping (enabling, adding) a watcher does nothing if it is already running */
|
||||
/* stopping (disabling, deleting) a watcher does nothing unless it's already running */
|
||||
#if EV_PROTOTYPES
|
||||
|
||||
/* feeds an event into a watcher as if the event actually occurred */
|
||||
/* accepts any ev_watcher type */
|
||||
EV_API_DECL void ev_feed_event (EV_P_ void *w, int revents) EV_THROW;
|
||||
EV_API_DECL void ev_feed_fd_event (EV_P_ int fd, int revents) EV_THROW;
|
||||
#if EV_SIGNAL_ENABLE
|
||||
EV_API_DECL void ev_feed_signal (int signum) EV_THROW;
|
||||
EV_API_DECL void ev_feed_signal_event (EV_P_ int signum) EV_THROW;
|
||||
#endif
|
||||
EV_API_DECL void ev_invoke (EV_P_ void *w, int revents);
|
||||
EV_API_DECL int ev_clear_pending (EV_P_ void *w) EV_THROW;
|
||||
|
||||
EV_API_DECL void ev_io_start (EV_P_ ev_io *w) EV_THROW;
|
||||
EV_API_DECL void ev_io_stop (EV_P_ ev_io *w) EV_THROW;
|
||||
|
||||
EV_API_DECL void ev_timer_start (EV_P_ ev_timer *w) EV_THROW;
|
||||
EV_API_DECL void ev_timer_stop (EV_P_ ev_timer *w) EV_THROW;
|
||||
/* stops if active and no repeat, restarts if active and repeating, starts if inactive and repeating */
|
||||
EV_API_DECL void ev_timer_again (EV_P_ ev_timer *w) EV_THROW;
|
||||
/* return remaining time */
|
||||
EV_API_DECL ev_tstamp ev_timer_remaining (EV_P_ ev_timer *w) EV_THROW;
|
||||
|
||||
#if EV_PERIODIC_ENABLE
|
||||
EV_API_DECL void ev_periodic_start (EV_P_ ev_periodic *w) EV_THROW;
|
||||
EV_API_DECL void ev_periodic_stop (EV_P_ ev_periodic *w) EV_THROW;
|
||||
EV_API_DECL void ev_periodic_again (EV_P_ ev_periodic *w) EV_THROW;
|
||||
#endif
|
||||
|
||||
/* only supported in the default loop */
|
||||
#if EV_SIGNAL_ENABLE
|
||||
EV_API_DECL void ev_signal_start (EV_P_ ev_signal *w) EV_THROW;
|
||||
EV_API_DECL void ev_signal_stop (EV_P_ ev_signal *w) EV_THROW;
|
||||
#endif
|
||||
|
||||
/* only supported in the default loop */
|
||||
# if EV_CHILD_ENABLE
|
||||
EV_API_DECL void ev_child_start (EV_P_ ev_child *w) EV_THROW;
|
||||
EV_API_DECL void ev_child_stop (EV_P_ ev_child *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
# if EV_STAT_ENABLE
|
||||
EV_API_DECL void ev_stat_start (EV_P_ ev_stat *w) EV_THROW;
|
||||
EV_API_DECL void ev_stat_stop (EV_P_ ev_stat *w) EV_THROW;
|
||||
EV_API_DECL void ev_stat_stat (EV_P_ ev_stat *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
# if EV_IDLE_ENABLE
|
||||
EV_API_DECL void ev_idle_start (EV_P_ ev_idle *w) EV_THROW;
|
||||
EV_API_DECL void ev_idle_stop (EV_P_ ev_idle *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
#if EV_PREPARE_ENABLE
|
||||
EV_API_DECL void ev_prepare_start (EV_P_ ev_prepare *w) EV_THROW;
|
||||
EV_API_DECL void ev_prepare_stop (EV_P_ ev_prepare *w) EV_THROW;
|
||||
#endif
|
||||
|
||||
#if EV_CHECK_ENABLE
|
||||
EV_API_DECL void ev_check_start (EV_P_ ev_check *w) EV_THROW;
|
||||
EV_API_DECL void ev_check_stop (EV_P_ ev_check *w) EV_THROW;
|
||||
#endif
|
||||
|
||||
# if EV_FORK_ENABLE
|
||||
EV_API_DECL void ev_fork_start (EV_P_ ev_fork *w) EV_THROW;
|
||||
EV_API_DECL void ev_fork_stop (EV_P_ ev_fork *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
# if EV_CLEANUP_ENABLE
|
||||
EV_API_DECL void ev_cleanup_start (EV_P_ ev_cleanup *w) EV_THROW;
|
||||
EV_API_DECL void ev_cleanup_stop (EV_P_ ev_cleanup *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
# if EV_EMBED_ENABLE
|
||||
/* only supported when loop to be embedded is in fact embeddable */
|
||||
EV_API_DECL void ev_embed_start (EV_P_ ev_embed *w) EV_THROW;
|
||||
EV_API_DECL void ev_embed_stop (EV_P_ ev_embed *w) EV_THROW;
|
||||
EV_API_DECL void ev_embed_sweep (EV_P_ ev_embed *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
# if EV_ASYNC_ENABLE
|
||||
EV_API_DECL void ev_async_start (EV_P_ ev_async *w) EV_THROW;
|
||||
EV_API_DECL void ev_async_stop (EV_P_ ev_async *w) EV_THROW;
|
||||
EV_API_DECL void ev_async_send (EV_P_ ev_async *w) EV_THROW;
|
||||
# endif
|
||||
|
||||
#if EV_COMPAT3
|
||||
#define EVLOOP_NONBLOCK EVRUN_NOWAIT
|
||||
#define EVLOOP_ONESHOT EVRUN_ONCE
|
||||
#define EVUNLOOP_CANCEL EVBREAK_CANCEL
|
||||
#define EVUNLOOP_ONE EVBREAK_ONE
|
||||
#define EVUNLOOP_ALL EVBREAK_ALL
|
||||
#if EV_PROTOTYPES
|
||||
EV_INLINE void ev_loop (EV_P_ int flags) { ev_run (EV_A_ flags); }
|
||||
EV_INLINE void ev_unloop (EV_P_ int how ) { ev_break (EV_A_ how ); }
|
||||
EV_INLINE void ev_default_destroy (void) { ev_loop_destroy (EV_DEFAULT); }
|
||||
EV_INLINE void ev_default_fork (void) { ev_loop_fork (EV_DEFAULT); }
|
||||
#if EV_FEATURE_API
|
||||
EV_INLINE unsigned int ev_loop_count (EV_P) { return ev_iteration (EV_A); }
|
||||
EV_INLINE unsigned int ev_loop_depth (EV_P) { return ev_depth (EV_A); }
|
||||
EV_INLINE void ev_loop_verify (EV_P) { ev_verify (EV_A); }
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
typedef struct ev_loop ev_loop;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
EV_CPP(})
|
||||
|
||||
#endif
|
||||
|
5570
libev/ev.pod
285
libev/ev_epoll.c
@@ -1,285 +0,0 @@
|
||||
/*
|
||||
* libev epoll fd activity backend
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* general notes about epoll:
|
||||
*
|
||||
* a) epoll silently removes fds from the fd set. as nothing tells us
|
||||
* that an fd has been removed otherwise, we have to continually
|
||||
* "rearm" fds that we suspect *might* have changed (same
|
||||
* problem with kqueue, but much less costly there).
|
||||
* b) the fact that ADD != MOD creates a lot of extra syscalls due to a)
|
||||
* and seems not to have any advantage.
|
||||
* c) the inability to handle fork or file descriptors (think dup)
|
||||
* limits the applicability over poll, so this is not a generic
|
||||
* poll replacement.
|
||||
* d) epoll doesn't work the same as select with many file descriptors
|
||||
* (such as files). while not critical, no other advanced interface
|
||||
* seems to share this (rather non-unixy) limitation.
|
||||
* e) epoll claims to be embeddable, but in practise you never get
|
||||
* a ready event for the epoll fd (broken: <=2.6.26, working: >=2.6.32).
|
||||
* f) epoll_ctl returning EPERM means the fd is always ready.
|
||||
*
|
||||
* lots of "weird code" and complication handling in this file is due
|
||||
* to these design problems with epoll, as we try very hard to avoid
|
||||
* epoll_ctl syscalls for common usage patterns and handle the breakage
|
||||
* ensuing from receiving events for closed and otherwise long gone
|
||||
* file descriptors.
|
||||
*/
|
||||
|
||||
#include <sys/epoll.h>
|
||||
|
||||
#define EV_EMASK_EPERM 0x80
|
||||
|
||||
static void
|
||||
epoll_modify (EV_P_ int fd, int oev, int nev)
|
||||
{
|
||||
struct epoll_event ev;
|
||||
unsigned char oldmask;
|
||||
|
||||
/*
|
||||
* we handle EPOLL_CTL_DEL by ignoring it here
|
||||
* on the assumption that the fd is gone anyways
|
||||
* if that is wrong, we have to handle the spurious
|
||||
* event in epoll_poll.
|
||||
* if the fd is added again, we try to ADD it, and, if that
|
||||
* fails, we assume it still has the same eventmask.
|
||||
*/
|
||||
if (!nev)
|
||||
return;
|
||||
|
||||
oldmask = anfds [fd].emask;
|
||||
anfds [fd].emask = nev;
|
||||
|
||||
/* store the generation counter in the upper 32 bits, the fd in the lower 32 bits */
|
||||
ev.data.u64 = (uint64_t)(uint32_t)fd
|
||||
| ((uint64_t)(uint32_t)++anfds [fd].egen << 32);
|
||||
ev.events = (nev & EV_READ ? EPOLLIN : 0)
|
||||
| (nev & EV_WRITE ? EPOLLOUT : 0);
|
||||
|
||||
if (expect_true (!epoll_ctl (backend_fd, oev && oldmask != nev ? EPOLL_CTL_MOD : EPOLL_CTL_ADD, fd, &ev)))
|
||||
return;
|
||||
|
||||
if (expect_true (errno == ENOENT))
|
||||
{
|
||||
/* if ENOENT then the fd went away, so try to do the right thing */
|
||||
if (!nev)
|
||||
goto dec_egen;
|
||||
|
||||
if (!epoll_ctl (backend_fd, EPOLL_CTL_ADD, fd, &ev))
|
||||
return;
|
||||
}
|
||||
else if (expect_true (errno == EEXIST))
|
||||
{
|
||||
/* EEXIST means we ignored a previous DEL, but the fd is still active */
|
||||
/* if the kernel mask is the same as the new mask, we assume it hasn't changed */
|
||||
if (oldmask == nev)
|
||||
goto dec_egen;
|
||||
|
||||
if (!epoll_ctl (backend_fd, EPOLL_CTL_MOD, fd, &ev))
|
||||
return;
|
||||
}
|
||||
else if (expect_true (errno == EPERM))
|
||||
{
|
||||
/* EPERM means the fd is always ready, but epoll is too snobbish */
|
||||
/* to handle it, unlike select or poll. */
|
||||
anfds [fd].emask = EV_EMASK_EPERM;
|
||||
|
||||
/* add fd to epoll_eperms, if not already inside */
|
||||
if (!(oldmask & EV_EMASK_EPERM))
|
||||
{
|
||||
array_needsize (int, epoll_eperms, epoll_epermmax, epoll_epermcnt + 1, EMPTY2);
|
||||
epoll_eperms [epoll_epermcnt++] = fd;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
fd_kill (EV_A_ fd);
|
||||
|
||||
dec_egen:
|
||||
/* we didn't successfully call epoll_ctl, so decrement the generation counter again */
|
||||
--anfds [fd].egen;
|
||||
}
|
||||
|
||||
static void
|
||||
epoll_poll (EV_P_ ev_tstamp timeout)
|
||||
{
|
||||
int i;
|
||||
int eventcnt;
|
||||
|
||||
if (expect_false (epoll_epermcnt))
|
||||
timeout = 0.;
|
||||
|
||||
/* epoll wait times cannot be larger than (LONG_MAX - 999UL) / HZ msecs, which is below */
|
||||
/* the default libev max wait time, however. */
|
||||
EV_RELEASE_CB;
|
||||
eventcnt = epoll_wait (backend_fd, epoll_events, epoll_eventmax, timeout * 1e3);
|
||||
EV_ACQUIRE_CB;
|
||||
|
||||
if (expect_false (eventcnt < 0))
|
||||
{
|
||||
if (errno != EINTR)
|
||||
ev_syserr ("(libev) epoll_wait");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < eventcnt; ++i)
|
||||
{
|
||||
struct epoll_event *ev = epoll_events + i;
|
||||
|
||||
int fd = (uint32_t)ev->data.u64; /* mask out the lower 32 bits */
|
||||
int want = anfds [fd].events;
|
||||
int got = (ev->events & (EPOLLOUT | EPOLLERR | EPOLLHUP) ? EV_WRITE : 0)
|
||||
| (ev->events & (EPOLLIN | EPOLLERR | EPOLLHUP) ? EV_READ : 0);
|
||||
|
||||
/*
|
||||
* check for spurious notification.
|
||||
* this only finds spurious notifications on egen updates
|
||||
* other spurious notifications will be found by epoll_ctl, below
|
||||
* we assume that fd is always in range, as we never shrink the anfds array
|
||||
*/
|
||||
if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32)))
|
||||
{
|
||||
/* recreate kernel state */
|
||||
postfork |= 2;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (expect_false (got & ~want))
|
||||
{
|
||||
anfds [fd].emask = want;
|
||||
|
||||
/*
|
||||
* we received an event but are not interested in it, try mod or del
|
||||
* this often happens because we optimistically do not unregister fds
|
||||
* when we are no longer interested in them, but also when we get spurious
|
||||
* notifications for fds from another process. this is partially handled
|
||||
* above with the gencounter check (== our fd is not the event fd), and
|
||||
* partially here, when epoll_ctl returns an error (== a child has the fd
|
||||
* but we closed it).
|
||||
*/
|
||||
ev->events = (want & EV_READ ? EPOLLIN : 0)
|
||||
| (want & EV_WRITE ? EPOLLOUT : 0);
|
||||
|
||||
/* pre-2.6.9 kernels require a non-null pointer with EPOLL_CTL_DEL, */
|
||||
/* which is fortunately easy to do for us. */
|
||||
if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev))
|
||||
{
|
||||
postfork |= 2; /* an error occurred, recreate kernel state */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
fd_event (EV_A_ fd, got);
|
||||
}
|
||||
|
||||
/* if the receive array was full, increase its size */
|
||||
if (expect_false (eventcnt == epoll_eventmax))
|
||||
{
|
||||
ev_free (epoll_events);
|
||||
epoll_eventmax = array_nextsize (sizeof (struct epoll_event), epoll_eventmax, epoll_eventmax + 1);
|
||||
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);
|
||||
}
|
||||
|
||||
/* now synthesize events for all fds where epoll fails, while select works... */
|
||||
for (i = epoll_epermcnt; i--; )
|
||||
{
|
||||
int fd = epoll_eperms [i];
|
||||
unsigned char events = anfds [fd].events & (EV_READ | EV_WRITE);
|
||||
|
||||
if (anfds [fd].emask & EV_EMASK_EPERM && events)
|
||||
fd_event (EV_A_ fd, events);
|
||||
else
|
||||
{
|
||||
epoll_eperms [i] = epoll_eperms [--epoll_epermcnt];
|
||||
anfds [fd].emask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline_size
|
||||
int
|
||||
epoll_init (EV_P_ int flags)
|
||||
{
|
||||
#if defined EPOLL_CLOEXEC && !defined __ANDROID__
|
||||
backend_fd = epoll_create1 (EPOLL_CLOEXEC);
|
||||
|
||||
if (backend_fd < 0 && (errno == EINVAL || errno == ENOSYS))
|
||||
#endif
|
||||
backend_fd = epoll_create (256);
|
||||
|
||||
if (backend_fd < 0)
|
||||
return 0;
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
backend_mintime = 1e-3; /* epoll does sometimes return early, this is just to avoid the worst */
|
||||
backend_modify = epoll_modify;
|
||||
backend_poll = epoll_poll;
|
||||
|
||||
epoll_eventmax = 64; /* initial number of events receivable per poll */
|
||||
epoll_events = (struct epoll_event *)ev_malloc (sizeof (struct epoll_event) * epoll_eventmax);
|
||||
|
||||
return EVBACKEND_EPOLL;
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
epoll_destroy (EV_P)
|
||||
{
|
||||
ev_free (epoll_events);
|
||||
array_free (epoll_eperm, EMPTY);
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
epoll_fork (EV_P)
|
||||
{
|
||||
close (backend_fd);
|
||||
|
||||
while ((backend_fd = epoll_create (256)) < 0)
|
||||
ev_syserr ("(libev) epoll_create");
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
fd_rearm_all (EV_A);
|
||||
}
|
||||
|
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
* libev kqueue backend
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/event.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
inline_speed
|
||||
void
|
||||
kqueue_change (EV_P_ int fd, int filter, int flags, int fflags)
|
||||
{
|
||||
++kqueue_changecnt;
|
||||
array_needsize (struct kevent, kqueue_changes, kqueue_changemax, kqueue_changecnt, EMPTY2);
|
||||
|
||||
EV_SET (&kqueue_changes [kqueue_changecnt - 1], fd, filter, flags, fflags, 0, 0);
|
||||
}
|
||||
|
||||
/* OS X at least needs this */
|
||||
#ifndef EV_ENABLE
|
||||
# define EV_ENABLE 0
|
||||
#endif
|
||||
#ifndef NOTE_EOF
|
||||
# define NOTE_EOF 0
|
||||
#endif
|
||||
|
||||
static void
|
||||
kqueue_modify (EV_P_ int fd, int oev, int nev)
|
||||
{
|
||||
if (oev != nev)
|
||||
{
|
||||
if (oev & EV_READ)
|
||||
kqueue_change (EV_A_ fd, EVFILT_READ , EV_DELETE, 0);
|
||||
|
||||
if (oev & EV_WRITE)
|
||||
kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_DELETE, 0);
|
||||
}
|
||||
|
||||
/* to detect close/reopen reliably, we have to re-add */
|
||||
/* event requests even when oev == nev */
|
||||
|
||||
if (nev & EV_READ)
|
||||
kqueue_change (EV_A_ fd, EVFILT_READ , EV_ADD | EV_ENABLE, NOTE_EOF);
|
||||
|
||||
if (nev & EV_WRITE)
|
||||
kqueue_change (EV_A_ fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, NOTE_EOF);
|
||||
}
|
||||
|
||||
static void
|
||||
kqueue_poll (EV_P_ ev_tstamp timeout)
|
||||
{
|
||||
int res, i;
|
||||
struct timespec ts;
|
||||
|
||||
/* need to resize so there is enough space for errors */
|
||||
if (kqueue_changecnt > kqueue_eventmax)
|
||||
{
|
||||
ev_free (kqueue_events);
|
||||
kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_changecnt);
|
||||
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
|
||||
}
|
||||
|
||||
EV_RELEASE_CB;
|
||||
EV_TS_SET (ts, timeout);
|
||||
res = kevent (backend_fd, kqueue_changes, kqueue_changecnt, kqueue_events, kqueue_eventmax, &ts);
|
||||
EV_ACQUIRE_CB;
|
||||
kqueue_changecnt = 0;
|
||||
|
||||
if (expect_false (res < 0))
|
||||
{
|
||||
if (errno != EINTR)
|
||||
ev_syserr ("(libev) kevent");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < res; ++i)
|
||||
{
|
||||
int fd = kqueue_events [i].ident;
|
||||
|
||||
if (expect_false (kqueue_events [i].flags & EV_ERROR))
|
||||
{
|
||||
int err = kqueue_events [i].data;
|
||||
|
||||
/* we are only interested in errors for fds that we are interested in :) */
|
||||
if (anfds [fd].events)
|
||||
{
|
||||
if (err == ENOENT) /* resubmit changes on ENOENT */
|
||||
kqueue_modify (EV_A_ fd, 0, anfds [fd].events);
|
||||
else if (err == EBADF) /* on EBADF, we re-check the fd */
|
||||
{
|
||||
if (fd_valid (fd))
|
||||
kqueue_modify (EV_A_ fd, 0, anfds [fd].events);
|
||||
else
|
||||
fd_kill (EV_A_ fd);
|
||||
}
|
||||
else /* on all other errors, we error out on the fd */
|
||||
fd_kill (EV_A_ fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
fd_event (
|
||||
EV_A_
|
||||
fd,
|
||||
kqueue_events [i].filter == EVFILT_READ ? EV_READ
|
||||
: kqueue_events [i].filter == EVFILT_WRITE ? EV_WRITE
|
||||
: 0
|
||||
);
|
||||
}
|
||||
|
||||
if (expect_false (res == kqueue_eventmax))
|
||||
{
|
||||
ev_free (kqueue_events);
|
||||
kqueue_eventmax = array_nextsize (sizeof (struct kevent), kqueue_eventmax, kqueue_eventmax + 1);
|
||||
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
|
||||
}
|
||||
}
|
||||
|
||||
inline_size
|
||||
int
|
||||
kqueue_init (EV_P_ int flags)
|
||||
{
|
||||
/* initialize the kernel queue */
|
||||
kqueue_fd_pid = getpid ();
|
||||
if ((backend_fd = kqueue ()) < 0)
|
||||
return 0;
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
|
||||
|
||||
backend_mintime = 1e-9; /* apparently, they did the right thing in freebsd */
|
||||
backend_modify = kqueue_modify;
|
||||
backend_poll = kqueue_poll;
|
||||
|
||||
kqueue_eventmax = 64; /* initial number of events receivable per poll */
|
||||
kqueue_events = (struct kevent *)ev_malloc (sizeof (struct kevent) * kqueue_eventmax);
|
||||
|
||||
kqueue_changes = 0;
|
||||
kqueue_changemax = 0;
|
||||
kqueue_changecnt = 0;
|
||||
|
||||
return EVBACKEND_KQUEUE;
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
kqueue_destroy (EV_P)
|
||||
{
|
||||
ev_free (kqueue_events);
|
||||
ev_free (kqueue_changes);
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
kqueue_fork (EV_P)
|
||||
{
|
||||
/* some BSD kernels don't just destroy the kqueue itself,
|
||||
* but also close the fd, which isn't documented, and
|
||||
* impossible to support properly.
|
||||
* we remember the pid of the kqueue call and only close
|
||||
* the fd if the pid is still the same.
|
||||
* this leaks fds on sane kernels, but BSD interfaces are
|
||||
* notoriously buggy and rarely get fixed.
|
||||
*/
|
||||
pid_t newpid = getpid ();
|
||||
|
||||
if (newpid == kqueue_fd_pid)
|
||||
close (backend_fd);
|
||||
|
||||
kqueue_fd_pid = newpid;
|
||||
while ((backend_fd = kqueue ()) < 0)
|
||||
ev_syserr ("(libev) kqueue");
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* re-register interest in fds */
|
||||
fd_rearm_all (EV_A);
|
||||
}
|
||||
|
||||
/* sys/event.h defines EV_ERROR */
|
||||
#undef EV_ERROR
|
||||
|
151
libev/ev_poll.c
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
* libev poll fd activity backend
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
inline_size
|
||||
void
|
||||
pollidx_init (int *base, int count)
|
||||
{
|
||||
/* consider using memset (.., -1, ...), which is practically guaranteed
|
||||
* to work on all systems implementing poll */
|
||||
while (count--)
|
||||
*base++ = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
poll_modify (EV_P_ int fd, int oev, int nev)
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (oev == nev)
|
||||
return;
|
||||
|
||||
array_needsize (int, pollidxs, pollidxmax, fd + 1, pollidx_init);
|
||||
|
||||
idx = pollidxs [fd];
|
||||
|
||||
if (idx < 0) /* need to allocate a new pollfd */
|
||||
{
|
||||
pollidxs [fd] = idx = pollcnt++;
|
||||
array_needsize (struct pollfd, polls, pollmax, pollcnt, EMPTY2);
|
||||
polls [idx].fd = fd;
|
||||
}
|
||||
|
||||
assert (polls [idx].fd == fd);
|
||||
|
||||
if (nev)
|
||||
polls [idx].events =
|
||||
(nev & EV_READ ? POLLIN : 0)
|
||||
| (nev & EV_WRITE ? POLLOUT : 0);
|
||||
else /* remove pollfd */
|
||||
{
|
||||
pollidxs [fd] = -1;
|
||||
|
||||
if (expect_true (idx < --pollcnt))
|
||||
{
|
||||
polls [idx] = polls [pollcnt];
|
||||
pollidxs [polls [idx].fd] = idx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
poll_poll (EV_P_ ev_tstamp timeout)
|
||||
{
|
||||
struct pollfd *p;
|
||||
int res;
|
||||
|
||||
EV_RELEASE_CB;
|
||||
res = poll (polls, pollcnt, timeout * 1e3);
|
||||
EV_ACQUIRE_CB;
|
||||
|
||||
if (expect_false (res < 0))
|
||||
{
|
||||
if (errno == EBADF)
|
||||
fd_ebadf (EV_A);
|
||||
else if (errno == ENOMEM && !syserr_cb)
|
||||
fd_enomem (EV_A);
|
||||
else if (errno != EINTR)
|
||||
ev_syserr ("(libev) poll");
|
||||
}
|
||||
else
|
||||
for (p = polls; res; ++p)
|
||||
{
|
||||
assert (("libev: poll() returned illegal result, broken BSD kernel?", p < polls + pollcnt));
|
||||
|
||||
if (expect_false (p->revents)) /* this expect is debatable */
|
||||
{
|
||||
--res;
|
||||
|
||||
if (expect_false (p->revents & POLLNVAL))
|
||||
fd_kill (EV_A_ p->fd);
|
||||
else
|
||||
fd_event (
|
||||
EV_A_
|
||||
p->fd,
|
||||
(p->revents & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0)
|
||||
| (p->revents & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline_size
|
||||
int
|
||||
poll_init (EV_P_ int flags)
|
||||
{
|
||||
backend_mintime = 1e-3;
|
||||
backend_modify = poll_modify;
|
||||
backend_poll = poll_poll;
|
||||
|
||||
pollidxs = 0; pollidxmax = 0;
|
||||
polls = 0; pollmax = 0; pollcnt = 0;
|
||||
|
||||
return EVBACKEND_POLL;
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
poll_destroy (EV_P)
|
||||
{
|
||||
ev_free (pollidxs);
|
||||
ev_free (polls);
|
||||
}
|
||||
|
189
libev/ev_port.c
@@ -1,189 +0,0 @@
|
||||
/*
|
||||
* libev solaris event port backend
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
/* useful reading:
|
||||
*
|
||||
* http://bugs.opensolaris.org/view_bug.do?bug_id=6268715 (random results)
|
||||
* http://bugs.opensolaris.org/view_bug.do?bug_id=6455223 (just totally broken)
|
||||
* http://bugs.opensolaris.org/view_bug.do?bug_id=6873782 (manpage ETIME)
|
||||
* http://bugs.opensolaris.org/view_bug.do?bug_id=6874410 (implementation ETIME)
|
||||
* http://www.mail-archive.com/networking-discuss@opensolaris.org/msg11898.html ETIME vs. nget
|
||||
* http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libc/port/gen/event_port.c (libc)
|
||||
* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/fs/portfs/port.c#1325 (kernel)
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <poll.h>
|
||||
#include <port.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
inline_speed
|
||||
void
|
||||
port_associate_and_check (EV_P_ int fd, int ev)
|
||||
{
|
||||
if (0 >
|
||||
port_associate (
|
||||
backend_fd, PORT_SOURCE_FD, fd,
|
||||
(ev & EV_READ ? POLLIN : 0)
|
||||
| (ev & EV_WRITE ? POLLOUT : 0),
|
||||
0
|
||||
)
|
||||
)
|
||||
{
|
||||
if (errno == EBADFD)
|
||||
fd_kill (EV_A_ fd);
|
||||
else
|
||||
ev_syserr ("(libev) port_associate");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
port_modify (EV_P_ int fd, int oev, int nev)
|
||||
{
|
||||
/* we need to reassociate no matter what, as closes are
|
||||
* once more silently being discarded.
|
||||
*/
|
||||
if (!nev)
|
||||
{
|
||||
if (oev)
|
||||
port_dissociate (backend_fd, PORT_SOURCE_FD, fd);
|
||||
}
|
||||
else
|
||||
port_associate_and_check (EV_A_ fd, nev);
|
||||
}
|
||||
|
||||
static void
|
||||
port_poll (EV_P_ ev_tstamp timeout)
|
||||
{
|
||||
int res, i;
|
||||
struct timespec ts;
|
||||
uint_t nget = 1;
|
||||
|
||||
/* we initialise this to something we will skip in the loop, as */
|
||||
/* port_getn can return with nget unchanged, but no indication */
|
||||
/* whether it was the original value or has been updated :/ */
|
||||
port_events [0].portev_source = 0;
|
||||
|
||||
EV_RELEASE_CB;
|
||||
EV_TS_SET (ts, timeout);
|
||||
res = port_getn (backend_fd, port_events, port_eventmax, &nget, &ts);
|
||||
EV_ACQUIRE_CB;
|
||||
|
||||
/* port_getn may or may not set nget on error */
|
||||
/* so we rely on port_events [0].portev_source not being updated */
|
||||
if (res == -1 && errno != ETIME && errno != EINTR)
|
||||
ev_syserr ("(libev) port_getn (see http://bugs.opensolaris.org/view_bug.do?bug_id=6268715, try LIBEV_FLAGS=3 env variable)");
|
||||
|
||||
for (i = 0; i < nget; ++i)
|
||||
{
|
||||
if (port_events [i].portev_source == PORT_SOURCE_FD)
|
||||
{
|
||||
int fd = port_events [i].portev_object;
|
||||
|
||||
fd_event (
|
||||
EV_A_
|
||||
fd,
|
||||
(port_events [i].portev_events & (POLLOUT | POLLERR | POLLHUP) ? EV_WRITE : 0)
|
||||
| (port_events [i].portev_events & (POLLIN | POLLERR | POLLHUP) ? EV_READ : 0)
|
||||
);
|
||||
|
||||
fd_change (EV_A_ fd, EV__IOFDSET);
|
||||
}
|
||||
}
|
||||
|
||||
if (expect_false (nget == port_eventmax))
|
||||
{
|
||||
ev_free (port_events);
|
||||
port_eventmax = array_nextsize (sizeof (port_event_t), port_eventmax, port_eventmax + 1);
|
||||
port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax);
|
||||
}
|
||||
}
|
||||
|
||||
inline_size
|
||||
int
|
||||
port_init (EV_P_ int flags)
|
||||
{
|
||||
/* Initialize the kernel queue */
|
||||
if ((backend_fd = port_create ()) < 0)
|
||||
return 0;
|
||||
|
||||
assert (("libev: PORT_SOURCE_FD must not be zero", PORT_SOURCE_FD));
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC); /* not sure if necessary, hopefully doesn't hurt */
|
||||
|
||||
/* if my reading of the opensolaris kernel sources are correct, then
|
||||
* opensolaris does something very stupid: it checks if the time has already
|
||||
* elapsed and doesn't round up if that is the case,m otherwise it DOES round
|
||||
* up. Since we can't know what the case is, we need to guess by using a
|
||||
* "large enough" timeout. Normally, 1e-9 would be correct.
|
||||
*/
|
||||
backend_mintime = 1e-3; /* needed to compensate for port_getn returning early */
|
||||
backend_modify = port_modify;
|
||||
backend_poll = port_poll;
|
||||
|
||||
port_eventmax = 64; /* initial number of events receivable per poll */
|
||||
port_events = (port_event_t *)ev_malloc (sizeof (port_event_t) * port_eventmax);
|
||||
|
||||
return EVBACKEND_PORT;
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
port_destroy (EV_P)
|
||||
{
|
||||
ev_free (port_events);
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
port_fork (EV_P)
|
||||
{
|
||||
close (backend_fd);
|
||||
|
||||
while ((backend_fd = port_create ()) < 0)
|
||||
ev_syserr ("(libev) port");
|
||||
|
||||
fcntl (backend_fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
/* re-register interest in fds */
|
||||
fd_rearm_all (EV_A);
|
||||
}
|
||||
|
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
* libev select fd activity backend
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
/* for unix systems */
|
||||
# include <inttypes.h>
|
||||
# ifndef __hpux
|
||||
/* for REAL unix systems */
|
||||
# include <sys/select.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef EV_SELECT_USE_FD_SET
|
||||
# ifdef NFDBITS
|
||||
# define EV_SELECT_USE_FD_SET 0
|
||||
# else
|
||||
# define EV_SELECT_USE_FD_SET 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
# undef EV_SELECT_USE_FD_SET
|
||||
# define EV_SELECT_USE_FD_SET 1
|
||||
# undef NFDBITS
|
||||
# define NFDBITS 0
|
||||
#endif
|
||||
|
||||
#if !EV_SELECT_USE_FD_SET
|
||||
# define NFDBYTES (NFDBITS / 8)
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static void
|
||||
select_modify (EV_P_ int fd, int oev, int nev)
|
||||
{
|
||||
if (oev == nev)
|
||||
return;
|
||||
|
||||
{
|
||||
#if EV_SELECT_USE_FD_SET
|
||||
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
SOCKET handle = anfds [fd].handle;
|
||||
#else
|
||||
int handle = fd;
|
||||
#endif
|
||||
|
||||
assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
|
||||
|
||||
/* FD_SET is broken on windows (it adds the fd to a set twice or more,
|
||||
* which eventually leads to overflows). Need to call it only on changes.
|
||||
*/
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
if ((oev ^ nev) & EV_READ)
|
||||
#endif
|
||||
if (nev & EV_READ)
|
||||
FD_SET (handle, (fd_set *)vec_ri);
|
||||
else
|
||||
FD_CLR (handle, (fd_set *)vec_ri);
|
||||
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
if ((oev ^ nev) & EV_WRITE)
|
||||
#endif
|
||||
if (nev & EV_WRITE)
|
||||
FD_SET (handle, (fd_set *)vec_wi);
|
||||
else
|
||||
FD_CLR (handle, (fd_set *)vec_wi);
|
||||
|
||||
#else
|
||||
|
||||
int word = fd / NFDBITS;
|
||||
fd_mask mask = 1UL << (fd % NFDBITS);
|
||||
|
||||
if (expect_false (vec_max <= word))
|
||||
{
|
||||
int new_max = word + 1;
|
||||
|
||||
vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
|
||||
vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
|
||||
vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
|
||||
vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
|
||||
#ifdef _WIN32
|
||||
vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
|
||||
#endif
|
||||
|
||||
for (; vec_max < new_max; ++vec_max)
|
||||
((fd_mask *)vec_ri) [vec_max] =
|
||||
((fd_mask *)vec_wi) [vec_max] = 0;
|
||||
}
|
||||
|
||||
((fd_mask *)vec_ri) [word] |= mask;
|
||||
if (!(nev & EV_READ))
|
||||
((fd_mask *)vec_ri) [word] &= ~mask;
|
||||
|
||||
((fd_mask *)vec_wi) [word] |= mask;
|
||||
if (!(nev & EV_WRITE))
|
||||
((fd_mask *)vec_wi) [word] &= ~mask;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
select_poll (EV_P_ ev_tstamp timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
int res;
|
||||
int fd_setsize;
|
||||
|
||||
EV_RELEASE_CB;
|
||||
EV_TV_SET (tv, timeout);
|
||||
|
||||
#if EV_SELECT_USE_FD_SET
|
||||
fd_setsize = sizeof (fd_set);
|
||||
#else
|
||||
fd_setsize = vec_max * NFDBYTES;
|
||||
#endif
|
||||
|
||||
memcpy (vec_ro, vec_ri, fd_setsize);
|
||||
memcpy (vec_wo, vec_wi, fd_setsize);
|
||||
|
||||
#ifdef _WIN32
|
||||
/* pass in the write set as except set.
|
||||
* the idea behind this is to work around a windows bug that causes
|
||||
* errors to be reported as an exception and not by setting
|
||||
* the writable bit. this is so uncontrollably lame.
|
||||
*/
|
||||
memcpy (vec_eo, vec_wi, fd_setsize);
|
||||
res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);
|
||||
#elif EV_SELECT_USE_FD_SET
|
||||
fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;
|
||||
res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
|
||||
#else
|
||||
res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
|
||||
#endif
|
||||
EV_ACQUIRE_CB;
|
||||
|
||||
if (expect_false (res < 0))
|
||||
{
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
errno = WSAGetLastError ();
|
||||
#endif
|
||||
#ifdef WSABASEERR
|
||||
/* on windows, select returns incompatible error codes, fix this */
|
||||
if (errno >= WSABASEERR && errno < WSABASEERR + 1000)
|
||||
if (errno == WSAENOTSOCK)
|
||||
errno = EBADF;
|
||||
else
|
||||
errno -= WSABASEERR;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
/* select on windows erroneously returns EINVAL when no fd sets have been
|
||||
* provided (this is documented). what microsoft doesn't tell you that this bug
|
||||
* exists even when the fd sets _are_ provided, so we have to check for this bug
|
||||
* here and emulate by sleeping manually.
|
||||
* we also get EINVAL when the timeout is invalid, but we ignore this case here
|
||||
* and assume that EINVAL always means: you have to wait manually.
|
||||
*/
|
||||
if (errno == EINVAL)
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
unsigned long ms = timeout * 1e3;
|
||||
Sleep (ms ? ms : 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (errno == EBADF)
|
||||
fd_ebadf (EV_A);
|
||||
else if (errno == ENOMEM && !syserr_cb)
|
||||
fd_enomem (EV_A);
|
||||
else if (errno != EINTR)
|
||||
ev_syserr ("(libev) select");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if EV_SELECT_USE_FD_SET
|
||||
|
||||
{
|
||||
int fd;
|
||||
|
||||
for (fd = 0; fd < anfdmax; ++fd)
|
||||
if (anfds [fd].events)
|
||||
{
|
||||
int events = 0;
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
SOCKET handle = anfds [fd].handle;
|
||||
#else
|
||||
int handle = fd;
|
||||
#endif
|
||||
|
||||
if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
|
||||
if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
|
||||
#ifdef _WIN32
|
||||
if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
|
||||
#endif
|
||||
|
||||
if (expect_true (events))
|
||||
fd_event (EV_A_ fd, events);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
{
|
||||
int word, bit;
|
||||
for (word = vec_max; word--; )
|
||||
{
|
||||
fd_mask word_r = ((fd_mask *)vec_ro) [word];
|
||||
fd_mask word_w = ((fd_mask *)vec_wo) [word];
|
||||
#ifdef _WIN32
|
||||
word_w |= ((fd_mask *)vec_eo) [word];
|
||||
#endif
|
||||
|
||||
if (word_r || word_w)
|
||||
for (bit = NFDBITS; bit--; )
|
||||
{
|
||||
fd_mask mask = 1UL << bit;
|
||||
int events = 0;
|
||||
|
||||
events |= word_r & mask ? EV_READ : 0;
|
||||
events |= word_w & mask ? EV_WRITE : 0;
|
||||
|
||||
if (expect_true (events))
|
||||
fd_event (EV_A_ word * NFDBITS + bit, events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline_size
|
||||
int
|
||||
select_init (EV_P_ int flags)
|
||||
{
|
||||
backend_mintime = 1e-6;
|
||||
backend_modify = select_modify;
|
||||
backend_poll = select_poll;
|
||||
|
||||
#if EV_SELECT_USE_FD_SET
|
||||
vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);
|
||||
vec_ro = ev_malloc (sizeof (fd_set));
|
||||
vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);
|
||||
vec_wo = ev_malloc (sizeof (fd_set));
|
||||
#ifdef _WIN32
|
||||
vec_eo = ev_malloc (sizeof (fd_set));
|
||||
#endif
|
||||
#else
|
||||
vec_max = 0;
|
||||
vec_ri = 0;
|
||||
vec_ro = 0;
|
||||
vec_wi = 0;
|
||||
vec_wo = 0;
|
||||
#ifdef _WIN32
|
||||
vec_eo = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return EVBACKEND_SELECT;
|
||||
}
|
||||
|
||||
inline_size
|
||||
void
|
||||
select_destroy (EV_P)
|
||||
{
|
||||
ev_free (vec_ri);
|
||||
ev_free (vec_ro);
|
||||
ev_free (vec_wi);
|
||||
ev_free (vec_wo);
|
||||
#ifdef _WIN32
|
||||
ev_free (vec_eo);
|
||||
#endif
|
||||
}
|
||||
|
204
libev/ev_vars.h
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* loop member variable declarations
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2011,2012,2013 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#define VARx(type,name) VAR(name, type name)
|
||||
|
||||
VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */
|
||||
VARx(ev_tstamp, mn_now) /* monotonic clock "now" */
|
||||
VARx(ev_tstamp, rtmn_diff) /* difference realtime - monotonic time */
|
||||
|
||||
/* for reverse feeding of events */
|
||||
VARx(W *, rfeeds)
|
||||
VARx(int, rfeedmax)
|
||||
VARx(int, rfeedcnt)
|
||||
|
||||
VAR (pendings, ANPENDING *pendings [NUMPRI])
|
||||
VAR (pendingmax, int pendingmax [NUMPRI])
|
||||
VAR (pendingcnt, int pendingcnt [NUMPRI])
|
||||
VARx(int, pendingpri) /* highest priority currently pending */
|
||||
VARx(ev_prepare, pending_w) /* dummy pending watcher */
|
||||
|
||||
VARx(ev_tstamp, io_blocktime)
|
||||
VARx(ev_tstamp, timeout_blocktime)
|
||||
|
||||
VARx(int, backend)
|
||||
VARx(int, activecnt) /* total number of active events ("refcount") */
|
||||
VARx(EV_ATOMIC_T, loop_done) /* signal by ev_break */
|
||||
|
||||
VARx(int, backend_fd)
|
||||
VARx(ev_tstamp, backend_mintime) /* assumed typical timer resolution */
|
||||
VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))
|
||||
VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout))
|
||||
|
||||
VARx(ANFD *, anfds)
|
||||
VARx(int, anfdmax)
|
||||
|
||||
VAR (evpipe, int evpipe [2])
|
||||
VARx(ev_io, pipe_w)
|
||||
VARx(EV_ATOMIC_T, pipe_write_wanted)
|
||||
VARx(EV_ATOMIC_T, pipe_write_skipped)
|
||||
|
||||
#if !defined(_WIN32) || EV_GENWRAP
|
||||
VARx(pid_t, curpid)
|
||||
#endif
|
||||
|
||||
VARx(char, postfork) /* true if we need to recreate kernel state after fork */
|
||||
|
||||
#if EV_USE_SELECT || EV_GENWRAP
|
||||
VARx(void *, vec_ri)
|
||||
VARx(void *, vec_ro)
|
||||
VARx(void *, vec_wi)
|
||||
VARx(void *, vec_wo)
|
||||
#if defined(_WIN32) || EV_GENWRAP
|
||||
VARx(void *, vec_eo)
|
||||
#endif
|
||||
VARx(int, vec_max)
|
||||
#endif
|
||||
|
||||
#if EV_USE_POLL || EV_GENWRAP
|
||||
VARx(struct pollfd *, polls)
|
||||
VARx(int, pollmax)
|
||||
VARx(int, pollcnt)
|
||||
VARx(int *, pollidxs) /* maps fds into structure indices */
|
||||
VARx(int, pollidxmax)
|
||||
#endif
|
||||
|
||||
#if EV_USE_EPOLL || EV_GENWRAP
|
||||
VARx(struct epoll_event *, epoll_events)
|
||||
VARx(int, epoll_eventmax)
|
||||
VARx(int *, epoll_eperms)
|
||||
VARx(int, epoll_epermcnt)
|
||||
VARx(int, epoll_epermmax)
|
||||
#endif
|
||||
|
||||
#if EV_USE_KQUEUE || EV_GENWRAP
|
||||
VARx(pid_t, kqueue_fd_pid)
|
||||
VARx(struct kevent *, kqueue_changes)
|
||||
VARx(int, kqueue_changemax)
|
||||
VARx(int, kqueue_changecnt)
|
||||
VARx(struct kevent *, kqueue_events)
|
||||
VARx(int, kqueue_eventmax)
|
||||
#endif
|
||||
|
||||
#if EV_USE_PORT || EV_GENWRAP
|
||||
VARx(struct port_event *, port_events)
|
||||
VARx(int, port_eventmax)
|
||||
#endif
|
||||
|
||||
#if EV_USE_IOCP || EV_GENWRAP
|
||||
VARx(HANDLE, iocp)
|
||||
#endif
|
||||
|
||||
VARx(int *, fdchanges)
|
||||
VARx(int, fdchangemax)
|
||||
VARx(int, fdchangecnt)
|
||||
|
||||
VARx(ANHE *, timers)
|
||||
VARx(int, timermax)
|
||||
VARx(int, timercnt)
|
||||
|
||||
#if EV_PERIODIC_ENABLE || EV_GENWRAP
|
||||
VARx(ANHE *, periodics)
|
||||
VARx(int, periodicmax)
|
||||
VARx(int, periodiccnt)
|
||||
#endif
|
||||
|
||||
#if EV_IDLE_ENABLE || EV_GENWRAP
|
||||
VAR (idles, ev_idle **idles [NUMPRI])
|
||||
VAR (idlemax, int idlemax [NUMPRI])
|
||||
VAR (idlecnt, int idlecnt [NUMPRI])
|
||||
#endif
|
||||
VARx(int, idleall) /* total number */
|
||||
|
||||
VARx(struct ev_prepare **, prepares)
|
||||
VARx(int, preparemax)
|
||||
VARx(int, preparecnt)
|
||||
|
||||
VARx(struct ev_check **, checks)
|
||||
VARx(int, checkmax)
|
||||
VARx(int, checkcnt)
|
||||
|
||||
#if EV_FORK_ENABLE || EV_GENWRAP
|
||||
VARx(struct ev_fork **, forks)
|
||||
VARx(int, forkmax)
|
||||
VARx(int, forkcnt)
|
||||
#endif
|
||||
|
||||
#if EV_CLEANUP_ENABLE || EV_GENWRAP
|
||||
VARx(struct ev_cleanup **, cleanups)
|
||||
VARx(int, cleanupmax)
|
||||
VARx(int, cleanupcnt)
|
||||
#endif
|
||||
|
||||
#if EV_ASYNC_ENABLE || EV_GENWRAP
|
||||
VARx(EV_ATOMIC_T, async_pending)
|
||||
VARx(struct ev_async **, asyncs)
|
||||
VARx(int, asyncmax)
|
||||
VARx(int, asynccnt)
|
||||
#endif
|
||||
|
||||
#if EV_USE_INOTIFY || EV_GENWRAP
|
||||
VARx(int, fs_fd)
|
||||
VARx(ev_io, fs_w)
|
||||
VARx(char, fs_2625) /* whether we are running in linux 2.6.25 or newer */
|
||||
VAR (fs_hash, ANFS fs_hash [EV_INOTIFY_HASHSIZE])
|
||||
#endif
|
||||
|
||||
VARx(EV_ATOMIC_T, sig_pending)
|
||||
#if EV_USE_SIGNALFD || EV_GENWRAP
|
||||
VARx(int, sigfd)
|
||||
VARx(ev_io, sigfd_w)
|
||||
VARx(sigset_t, sigfd_set)
|
||||
#endif
|
||||
|
||||
VARx(unsigned int, origflags) /* original loop flags */
|
||||
|
||||
#if EV_FEATURE_API || EV_GENWRAP
|
||||
VARx(unsigned int, loop_count) /* total number of loop iterations/blocks */
|
||||
VARx(unsigned int, loop_depth) /* #ev_run enters - #ev_run leaves */
|
||||
|
||||
VARx(void *, userdata)
|
||||
/* C++ doesn't support the ev_loop_callback typedef here. stinks. */
|
||||
VAR (release_cb, void (*release_cb)(EV_P) EV_THROW)
|
||||
VAR (acquire_cb, void (*acquire_cb)(EV_P) EV_THROW)
|
||||
VAR (invoke_cb , ev_loop_callback invoke_cb)
|
||||
#endif
|
||||
|
||||
#undef VARx
|
||||
|
162
libev/ev_win32.c
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
* libev win32 compatibility cruft (_not_ a backend)
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* note: the comment below could not be substantiated, but what would I care */
|
||||
/* MSDN says this is required to handle SIGFPE */
|
||||
/* my wild guess would be that using something floating-pointy is required */
|
||||
/* for the crt to do something about it */
|
||||
volatile double SIGFPE_REQ = 0.0f;
|
||||
|
||||
static SOCKET
|
||||
ev_tcp_socket (void)
|
||||
{
|
||||
#if EV_USE_WSASOCKET
|
||||
return WSASocket (AF_INET, SOCK_STREAM, 0, 0, 0, 0);
|
||||
#else
|
||||
return socket (AF_INET, SOCK_STREAM, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* oh, the humanity! */
|
||||
static int
|
||||
ev_pipe (int filedes [2])
|
||||
{
|
||||
struct sockaddr_in addr = { 0 };
|
||||
int addr_size = sizeof (addr);
|
||||
struct sockaddr_in adr2;
|
||||
int adr2_size = sizeof (adr2);
|
||||
SOCKET listener;
|
||||
SOCKET sock [2] = { -1, -1 };
|
||||
|
||||
if ((listener = ev_tcp_socket ()) == INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
|
||||
addr.sin_port = 0;
|
||||
|
||||
if (bind (listener, (struct sockaddr *)&addr, addr_size))
|
||||
goto fail;
|
||||
|
||||
if (getsockname (listener, (struct sockaddr *)&addr, &addr_size))
|
||||
goto fail;
|
||||
|
||||
if (listen (listener, 1))
|
||||
goto fail;
|
||||
|
||||
if ((sock [0] = ev_tcp_socket ()) == INVALID_SOCKET)
|
||||
goto fail;
|
||||
|
||||
if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
|
||||
goto fail;
|
||||
|
||||
/* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */
|
||||
/* when convenient, probably by just removing error checking altogether? */
|
||||
if ((sock [1] = accept (listener, 0, 0)) < 0)
|
||||
goto fail;
|
||||
|
||||
/* windows vista returns fantasy port numbers for sockets:
|
||||
* example for two interconnected tcp sockets:
|
||||
*
|
||||
* (Socket::unpack_sockaddr_in getsockname $sock0)[0] == 53364
|
||||
* (Socket::unpack_sockaddr_in getpeername $sock0)[0] == 53363
|
||||
* (Socket::unpack_sockaddr_in getsockname $sock1)[0] == 53363
|
||||
* (Socket::unpack_sockaddr_in getpeername $sock1)[0] == 53365
|
||||
*
|
||||
* wow! tridirectional sockets!
|
||||
*
|
||||
* this way of checking ports seems to work:
|
||||
*/
|
||||
if (getpeername (sock [0], (struct sockaddr *)&addr, &addr_size))
|
||||
goto fail;
|
||||
|
||||
if (getsockname (sock [1], (struct sockaddr *)&adr2, &adr2_size))
|
||||
goto fail;
|
||||
|
||||
errno = WSAEINVAL;
|
||||
if (addr_size != adr2_size
|
||||
|| addr.sin_addr.s_addr != adr2.sin_addr.s_addr /* just to be sure, I mean, it's windows */
|
||||
|| addr.sin_port != adr2.sin_port)
|
||||
goto fail;
|
||||
|
||||
closesocket (listener);
|
||||
|
||||
#if EV_SELECT_IS_WINSOCKET
|
||||
filedes [0] = EV_WIN32_HANDLE_TO_FD (sock [0]);
|
||||
filedes [1] = EV_WIN32_HANDLE_TO_FD (sock [1]);
|
||||
#else
|
||||
/* when select isn't winsocket, we also expect socket, connect, accept etc.
|
||||
* to work on fds */
|
||||
filedes [0] = sock [0];
|
||||
filedes [1] = sock [1];
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
closesocket (listener);
|
||||
|
||||
if (sock [0] != INVALID_SOCKET) closesocket (sock [0]);
|
||||
if (sock [1] != INVALID_SOCKET) closesocket (sock [1]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef pipe
|
||||
#define pipe(filedes) ev_pipe (filedes)
|
||||
|
||||
#define EV_HAVE_EV_TIME 1
|
||||
ev_tstamp
|
||||
ev_time (void)
|
||||
{
|
||||
FILETIME ft;
|
||||
ULARGE_INTEGER ui;
|
||||
|
||||
GetSystemTimeAsFileTime (&ft);
|
||||
ui.u.LowPart = ft.dwLowDateTime;
|
||||
ui.u.HighPart = ft.dwHighDateTime;
|
||||
|
||||
/* msvc cannot convert ulonglong to double... yes, it is that sucky */
|
||||
return (LONGLONG)(ui.QuadPart - 116444736000000000) * 1e-7;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
200
libev/ev_wrap.h
@@ -1,200 +0,0 @@
|
||||
/* DO NOT EDIT, automatically generated by update_ev_wrap */
|
||||
#ifndef EV_WRAP_H
|
||||
#define EV_WRAP_H
|
||||
#define acquire_cb ((loop)->acquire_cb)
|
||||
#define activecnt ((loop)->activecnt)
|
||||
#define anfdmax ((loop)->anfdmax)
|
||||
#define anfds ((loop)->anfds)
|
||||
#define async_pending ((loop)->async_pending)
|
||||
#define asynccnt ((loop)->asynccnt)
|
||||
#define asyncmax ((loop)->asyncmax)
|
||||
#define asyncs ((loop)->asyncs)
|
||||
#define backend ((loop)->backend)
|
||||
#define backend_fd ((loop)->backend_fd)
|
||||
#define backend_mintime ((loop)->backend_mintime)
|
||||
#define backend_modify ((loop)->backend_modify)
|
||||
#define backend_poll ((loop)->backend_poll)
|
||||
#define checkcnt ((loop)->checkcnt)
|
||||
#define checkmax ((loop)->checkmax)
|
||||
#define checks ((loop)->checks)
|
||||
#define cleanupcnt ((loop)->cleanupcnt)
|
||||
#define cleanupmax ((loop)->cleanupmax)
|
||||
#define cleanups ((loop)->cleanups)
|
||||
#define curpid ((loop)->curpid)
|
||||
#define epoll_epermcnt ((loop)->epoll_epermcnt)
|
||||
#define epoll_epermmax ((loop)->epoll_epermmax)
|
||||
#define epoll_eperms ((loop)->epoll_eperms)
|
||||
#define epoll_eventmax ((loop)->epoll_eventmax)
|
||||
#define epoll_events ((loop)->epoll_events)
|
||||
#define evpipe ((loop)->evpipe)
|
||||
#define fdchangecnt ((loop)->fdchangecnt)
|
||||
#define fdchangemax ((loop)->fdchangemax)
|
||||
#define fdchanges ((loop)->fdchanges)
|
||||
#define forkcnt ((loop)->forkcnt)
|
||||
#define forkmax ((loop)->forkmax)
|
||||
#define forks ((loop)->forks)
|
||||
#define fs_2625 ((loop)->fs_2625)
|
||||
#define fs_fd ((loop)->fs_fd)
|
||||
#define fs_hash ((loop)->fs_hash)
|
||||
#define fs_w ((loop)->fs_w)
|
||||
#define idleall ((loop)->idleall)
|
||||
#define idlecnt ((loop)->idlecnt)
|
||||
#define idlemax ((loop)->idlemax)
|
||||
#define idles ((loop)->idles)
|
||||
#define invoke_cb ((loop)->invoke_cb)
|
||||
#define io_blocktime ((loop)->io_blocktime)
|
||||
#define iocp ((loop)->iocp)
|
||||
#define kqueue_changecnt ((loop)->kqueue_changecnt)
|
||||
#define kqueue_changemax ((loop)->kqueue_changemax)
|
||||
#define kqueue_changes ((loop)->kqueue_changes)
|
||||
#define kqueue_eventmax ((loop)->kqueue_eventmax)
|
||||
#define kqueue_events ((loop)->kqueue_events)
|
||||
#define kqueue_fd_pid ((loop)->kqueue_fd_pid)
|
||||
#define loop_count ((loop)->loop_count)
|
||||
#define loop_depth ((loop)->loop_depth)
|
||||
#define loop_done ((loop)->loop_done)
|
||||
#define mn_now ((loop)->mn_now)
|
||||
#define now_floor ((loop)->now_floor)
|
||||
#define origflags ((loop)->origflags)
|
||||
#define pending_w ((loop)->pending_w)
|
||||
#define pendingcnt ((loop)->pendingcnt)
|
||||
#define pendingmax ((loop)->pendingmax)
|
||||
#define pendingpri ((loop)->pendingpri)
|
||||
#define pendings ((loop)->pendings)
|
||||
#define periodiccnt ((loop)->periodiccnt)
|
||||
#define periodicmax ((loop)->periodicmax)
|
||||
#define periodics ((loop)->periodics)
|
||||
#define pipe_w ((loop)->pipe_w)
|
||||
#define pipe_write_skipped ((loop)->pipe_write_skipped)
|
||||
#define pipe_write_wanted ((loop)->pipe_write_wanted)
|
||||
#define pollcnt ((loop)->pollcnt)
|
||||
#define pollidxmax ((loop)->pollidxmax)
|
||||
#define pollidxs ((loop)->pollidxs)
|
||||
#define pollmax ((loop)->pollmax)
|
||||
#define polls ((loop)->polls)
|
||||
#define port_eventmax ((loop)->port_eventmax)
|
||||
#define port_events ((loop)->port_events)
|
||||
#define postfork ((loop)->postfork)
|
||||
#define preparecnt ((loop)->preparecnt)
|
||||
#define preparemax ((loop)->preparemax)
|
||||
#define prepares ((loop)->prepares)
|
||||
#define release_cb ((loop)->release_cb)
|
||||
#define rfeedcnt ((loop)->rfeedcnt)
|
||||
#define rfeedmax ((loop)->rfeedmax)
|
||||
#define rfeeds ((loop)->rfeeds)
|
||||
#define rtmn_diff ((loop)->rtmn_diff)
|
||||
#define sig_pending ((loop)->sig_pending)
|
||||
#define sigfd ((loop)->sigfd)
|
||||
#define sigfd_set ((loop)->sigfd_set)
|
||||
#define sigfd_w ((loop)->sigfd_w)
|
||||
#define timeout_blocktime ((loop)->timeout_blocktime)
|
||||
#define timercnt ((loop)->timercnt)
|
||||
#define timermax ((loop)->timermax)
|
||||
#define timers ((loop)->timers)
|
||||
#define userdata ((loop)->userdata)
|
||||
#define vec_eo ((loop)->vec_eo)
|
||||
#define vec_max ((loop)->vec_max)
|
||||
#define vec_ri ((loop)->vec_ri)
|
||||
#define vec_ro ((loop)->vec_ro)
|
||||
#define vec_wi ((loop)->vec_wi)
|
||||
#define vec_wo ((loop)->vec_wo)
|
||||
#else
|
||||
#undef EV_WRAP_H
|
||||
#undef acquire_cb
|
||||
#undef activecnt
|
||||
#undef anfdmax
|
||||
#undef anfds
|
||||
#undef async_pending
|
||||
#undef asynccnt
|
||||
#undef asyncmax
|
||||
#undef asyncs
|
||||
#undef backend
|
||||
#undef backend_fd
|
||||
#undef backend_mintime
|
||||
#undef backend_modify
|
||||
#undef backend_poll
|
||||
#undef checkcnt
|
||||
#undef checkmax
|
||||
#undef checks
|
||||
#undef cleanupcnt
|
||||
#undef cleanupmax
|
||||
#undef cleanups
|
||||
#undef curpid
|
||||
#undef epoll_epermcnt
|
||||
#undef epoll_epermmax
|
||||
#undef epoll_eperms
|
||||
#undef epoll_eventmax
|
||||
#undef epoll_events
|
||||
#undef evpipe
|
||||
#undef fdchangecnt
|
||||
#undef fdchangemax
|
||||
#undef fdchanges
|
||||
#undef forkcnt
|
||||
#undef forkmax
|
||||
#undef forks
|
||||
#undef fs_2625
|
||||
#undef fs_fd
|
||||
#undef fs_hash
|
||||
#undef fs_w
|
||||
#undef idleall
|
||||
#undef idlecnt
|
||||
#undef idlemax
|
||||
#undef idles
|
||||
#undef invoke_cb
|
||||
#undef io_blocktime
|
||||
#undef iocp
|
||||
#undef kqueue_changecnt
|
||||
#undef kqueue_changemax
|
||||
#undef kqueue_changes
|
||||
#undef kqueue_eventmax
|
||||
#undef kqueue_events
|
||||
#undef kqueue_fd_pid
|
||||
#undef loop_count
|
||||
#undef loop_depth
|
||||
#undef loop_done
|
||||
#undef mn_now
|
||||
#undef now_floor
|
||||
#undef origflags
|
||||
#undef pending_w
|
||||
#undef pendingcnt
|
||||
#undef pendingmax
|
||||
#undef pendingpri
|
||||
#undef pendings
|
||||
#undef periodiccnt
|
||||
#undef periodicmax
|
||||
#undef periodics
|
||||
#undef pipe_w
|
||||
#undef pipe_write_skipped
|
||||
#undef pipe_write_wanted
|
||||
#undef pollcnt
|
||||
#undef pollidxmax
|
||||
#undef pollidxs
|
||||
#undef pollmax
|
||||
#undef polls
|
||||
#undef port_eventmax
|
||||
#undef port_events
|
||||
#undef postfork
|
||||
#undef preparecnt
|
||||
#undef preparemax
|
||||
#undef prepares
|
||||
#undef release_cb
|
||||
#undef rfeedcnt
|
||||
#undef rfeedmax
|
||||
#undef rfeeds
|
||||
#undef rtmn_diff
|
||||
#undef sig_pending
|
||||
#undef sigfd
|
||||
#undef sigfd_set
|
||||
#undef sigfd_w
|
||||
#undef timeout_blocktime
|
||||
#undef timercnt
|
||||
#undef timermax
|
||||
#undef timers
|
||||
#undef userdata
|
||||
#undef vec_eo
|
||||
#undef vec_max
|
||||
#undef vec_ri
|
||||
#undef vec_ro
|
||||
#undef vec_wi
|
||||
#undef vec_wo
|
||||
#endif
|
425
libev/event.c
@@ -1,425 +0,0 @@
|
||||
/*
|
||||
* libevent compatibility layer
|
||||
*
|
||||
* Copyright (c) 2007,2008,2009,2010,2012 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef EV_EVENT_H
|
||||
# include EV_EVENT_H
|
||||
#else
|
||||
# include "event.h"
|
||||
#endif
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
# define dLOOPev struct ev_loop *loop = (struct ev_loop *)ev->ev_base
|
||||
# define dLOOPbase struct ev_loop *loop = (struct ev_loop *)base
|
||||
#else
|
||||
# define dLOOPev
|
||||
# define dLOOPbase
|
||||
#endif
|
||||
|
||||
/* never accessed, will always be cast from/to ev_loop */
|
||||
struct event_base
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
static struct event_base *ev_x_cur;
|
||||
|
||||
static ev_tstamp
|
||||
ev_tv_get (struct timeval *tv)
|
||||
{
|
||||
if (tv)
|
||||
{
|
||||
ev_tstamp after = tv->tv_sec + tv->tv_usec * 1e-6;
|
||||
return after ? after : 1e-6;
|
||||
}
|
||||
else
|
||||
return -1.;
|
||||
}
|
||||
|
||||
#define EVENT_STRINGIFY(s) # s
|
||||
#define EVENT_VERSION(a,b) EVENT_STRINGIFY (a) "." EVENT_STRINGIFY (b)
|
||||
|
||||
const char *
|
||||
event_get_version (void)
|
||||
{
|
||||
/* returns ABI, not API or library, version */
|
||||
return EVENT_VERSION (EV_VERSION_MAJOR, EV_VERSION_MINOR);
|
||||
}
|
||||
|
||||
const char *
|
||||
event_get_method (void)
|
||||
{
|
||||
return "libev";
|
||||
}
|
||||
|
||||
void *event_init (void)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
if (ev_x_cur)
|
||||
ev_x_cur = (struct event_base *)ev_loop_new (EVFLAG_AUTO);
|
||||
else
|
||||
ev_x_cur = (struct event_base *)ev_default_loop (EVFLAG_AUTO);
|
||||
#else
|
||||
assert (("libev: multiple event bases not supported when not compiled with EV_MULTIPLICITY", !ev_x_cur));
|
||||
|
||||
ev_x_cur = (struct event_base *)(long)ev_default_loop (EVFLAG_AUTO);
|
||||
#endif
|
||||
|
||||
return ev_x_cur;
|
||||
}
|
||||
|
||||
const char *
|
||||
event_base_get_method (const struct event_base *base)
|
||||
{
|
||||
return "libev";
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
event_base_new (void)
|
||||
{
|
||||
#if EV_MULTIPLICITY
|
||||
return (struct event_base *)ev_loop_new (EVFLAG_AUTO);
|
||||
#else
|
||||
assert (("libev: multiple event bases not supported when not compiled with EV_MULTIPLICITY"));
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void event_base_free (struct event_base *base)
|
||||
{
|
||||
dLOOPbase;
|
||||
|
||||
#if EV_MULTIPLICITY
|
||||
if (!ev_is_default_loop (loop))
|
||||
ev_loop_destroy (loop);
|
||||
#endif
|
||||
}
|
||||
|
||||
int event_dispatch (void)
|
||||
{
|
||||
return event_base_dispatch (ev_x_cur);
|
||||
}
|
||||
|
||||
#ifdef EV_STANDALONE
|
||||
void event_set_log_callback (event_log_cb cb)
|
||||
{
|
||||
/* nop */
|
||||
}
|
||||
#endif
|
||||
|
||||
int event_loop (int flags)
|
||||
{
|
||||
return event_base_loop (ev_x_cur, flags);
|
||||
}
|
||||
|
||||
int event_loopexit (struct timeval *tv)
|
||||
{
|
||||
return event_base_loopexit (ev_x_cur, tv);
|
||||
}
|
||||
|
||||
event_callback_fn event_get_callback
|
||||
(const struct event *ev)
|
||||
{
|
||||
return ev->ev_callback;
|
||||
}
|
||||
|
||||
static void
|
||||
ev_x_cb (struct event *ev, int revents)
|
||||
{
|
||||
revents &= EV_READ | EV_WRITE | EV_TIMER | EV_SIGNAL;
|
||||
|
||||
ev->ev_res = revents;
|
||||
ev->ev_callback (ev->ev_fd, (short)revents, ev->ev_arg);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_x_cb_sig (EV_P_ struct ev_signal *w, int revents)
|
||||
{
|
||||
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, iosig.sig));
|
||||
|
||||
if (revents & EV_ERROR)
|
||||
event_del (ev);
|
||||
|
||||
ev_x_cb (ev, revents);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_x_cb_io (EV_P_ struct ev_io *w, int revents)
|
||||
{
|
||||
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, iosig.io));
|
||||
|
||||
if ((revents & EV_ERROR) || !(ev->ev_events & EV_PERSIST))
|
||||
event_del (ev);
|
||||
|
||||
ev_x_cb (ev, revents);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_x_cb_to (EV_P_ struct ev_timer *w, int revents)
|
||||
{
|
||||
struct event *ev = (struct event *)(((char *)w) - offsetof (struct event, to));
|
||||
|
||||
event_del (ev);
|
||||
|
||||
ev_x_cb (ev, revents);
|
||||
}
|
||||
|
||||
void event_set (struct event *ev, int fd, short events, void (*cb)(int, short, void *), void *arg)
|
||||
{
|
||||
if (events & EV_SIGNAL)
|
||||
ev_init (&ev->iosig.sig, ev_x_cb_sig);
|
||||
else
|
||||
ev_init (&ev->iosig.io, ev_x_cb_io);
|
||||
|
||||
ev_init (&ev->to, ev_x_cb_to);
|
||||
|
||||
ev->ev_base = ev_x_cur; /* not threadsafe, but it's how libevent works */
|
||||
ev->ev_fd = fd;
|
||||
ev->ev_events = events;
|
||||
ev->ev_pri = 0;
|
||||
ev->ev_callback = cb;
|
||||
ev->ev_arg = arg;
|
||||
ev->ev_res = 0;
|
||||
ev->ev_flags = EVLIST_INIT;
|
||||
}
|
||||
|
||||
int event_once (int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv)
|
||||
{
|
||||
return event_base_once (ev_x_cur, fd, events, cb, arg, tv);
|
||||
}
|
||||
|
||||
int event_add (struct event *ev, struct timeval *tv)
|
||||
{
|
||||
dLOOPev;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
{
|
||||
if (!ev_is_active (&ev->iosig.sig))
|
||||
{
|
||||
ev_signal_set (&ev->iosig.sig, ev->ev_fd);
|
||||
ev_signal_start (EV_A_ &ev->iosig.sig);
|
||||
|
||||
ev->ev_flags |= EVLIST_SIGNAL;
|
||||
}
|
||||
}
|
||||
else if (ev->ev_events & (EV_READ | EV_WRITE))
|
||||
{
|
||||
if (!ev_is_active (&ev->iosig.io))
|
||||
{
|
||||
ev_io_set (&ev->iosig.io, ev->ev_fd, ev->ev_events & (EV_READ | EV_WRITE));
|
||||
ev_io_start (EV_A_ &ev->iosig.io);
|
||||
|
||||
ev->ev_flags |= EVLIST_INSERTED;
|
||||
}
|
||||
}
|
||||
|
||||
if (tv)
|
||||
{
|
||||
ev->to.repeat = ev_tv_get (tv);
|
||||
ev_timer_again (EV_A_ &ev->to);
|
||||
ev->ev_flags |= EVLIST_TIMEOUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
ev_timer_stop (EV_A_ &ev->to);
|
||||
ev->ev_flags &= ~EVLIST_TIMEOUT;
|
||||
}
|
||||
|
||||
ev->ev_flags |= EVLIST_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_del (struct event *ev)
|
||||
{
|
||||
dLOOPev;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
ev_signal_stop (EV_A_ &ev->iosig.sig);
|
||||
else if (ev->ev_events & (EV_READ | EV_WRITE))
|
||||
ev_io_stop (EV_A_ &ev->iosig.io);
|
||||
|
||||
if (ev_is_active (&ev->to))
|
||||
ev_timer_stop (EV_A_ &ev->to);
|
||||
|
||||
ev->ev_flags = EVLIST_INIT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void event_active (struct event *ev, int res, short ncalls)
|
||||
{
|
||||
dLOOPev;
|
||||
|
||||
if (res & EV_TIMEOUT)
|
||||
ev_feed_event (EV_A_ &ev->to, res & EV_TIMEOUT);
|
||||
|
||||
if (res & EV_SIGNAL)
|
||||
ev_feed_event (EV_A_ &ev->iosig.sig, res & EV_SIGNAL);
|
||||
|
||||
if (res & (EV_READ | EV_WRITE))
|
||||
ev_feed_event (EV_A_ &ev->iosig.io, res & (EV_READ | EV_WRITE));
|
||||
}
|
||||
|
||||
int event_pending (struct event *ev, short events, struct timeval *tv)
|
||||
{
|
||||
short revents = 0;
|
||||
dLOOPev;
|
||||
|
||||
if (ev->ev_events & EV_SIGNAL)
|
||||
{
|
||||
/* sig */
|
||||
if (ev_is_active (&ev->iosig.sig) || ev_is_pending (&ev->iosig.sig))
|
||||
revents |= EV_SIGNAL;
|
||||
}
|
||||
else if (ev->ev_events & (EV_READ | EV_WRITE))
|
||||
{
|
||||
/* io */
|
||||
if (ev_is_active (&ev->iosig.io) || ev_is_pending (&ev->iosig.io))
|
||||
revents |= ev->ev_events & (EV_READ | EV_WRITE);
|
||||
}
|
||||
|
||||
if (ev->ev_events & EV_TIMEOUT || ev_is_active (&ev->to) || ev_is_pending (&ev->to))
|
||||
{
|
||||
revents |= EV_TIMEOUT;
|
||||
|
||||
if (tv)
|
||||
{
|
||||
ev_tstamp at = ev_now (EV_A);
|
||||
|
||||
tv->tv_sec = (long)at;
|
||||
tv->tv_usec = (long)((at - (ev_tstamp)tv->tv_sec) * 1e6);
|
||||
}
|
||||
}
|
||||
|
||||
return events & revents;
|
||||
}
|
||||
|
||||
int event_priority_init (int npri)
|
||||
{
|
||||
return event_base_priority_init (ev_x_cur, npri);
|
||||
}
|
||||
|
||||
int event_priority_set (struct event *ev, int pri)
|
||||
{
|
||||
ev->ev_pri = pri;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_base_set (struct event_base *base, struct event *ev)
|
||||
{
|
||||
ev->ev_base = base;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_base_loop (struct event_base *base, int flags)
|
||||
{
|
||||
dLOOPbase;
|
||||
|
||||
return !ev_run (EV_A_ flags);
|
||||
}
|
||||
|
||||
int event_base_dispatch (struct event_base *base)
|
||||
{
|
||||
return event_base_loop (base, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ev_x_loopexit_cb (int revents, void *base)
|
||||
{
|
||||
dLOOPbase;
|
||||
|
||||
ev_break (EV_A_ EVBREAK_ONE);
|
||||
}
|
||||
|
||||
int event_base_loopexit (struct event_base *base, struct timeval *tv)
|
||||
{
|
||||
ev_tstamp after = ev_tv_get (tv);
|
||||
dLOOPbase;
|
||||
|
||||
ev_once (EV_A_ -1, 0, after >= 0. ? after : 0., ev_x_loopexit_cb, (void *)base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ev_x_once
|
||||
{
|
||||
int fd;
|
||||
void (*cb)(int, short, void *);
|
||||
void *arg;
|
||||
};
|
||||
|
||||
static void
|
||||
ev_x_once_cb (int revents, void *arg)
|
||||
{
|
||||
struct ev_x_once *once = (struct ev_x_once *)arg;
|
||||
|
||||
once->cb (once->fd, (short)revents, once->arg);
|
||||
free (once);
|
||||
}
|
||||
|
||||
int event_base_once (struct event_base *base, int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv)
|
||||
{
|
||||
struct ev_x_once *once = (struct ev_x_once *)malloc (sizeof (struct ev_x_once));
|
||||
dLOOPbase;
|
||||
|
||||
if (!once)
|
||||
return -1;
|
||||
|
||||
once->fd = fd;
|
||||
once->cb = cb;
|
||||
once->arg = arg;
|
||||
|
||||
ev_once (EV_A_ fd, events & (EV_READ | EV_WRITE), ev_tv_get (tv), ev_x_once_cb, (void *)once);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_base_priority_init (struct event_base *base, int npri)
|
||||
{
|
||||
/*dLOOPbase;*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
177
libev/event.h
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* libevent compatibility header, only core events supported
|
||||
*
|
||||
* Copyright (c) 2007,2008,2010,2012 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modifica-
|
||||
* tion, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
|
||||
* CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
|
||||
* CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
|
||||
* ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* the GNU General Public License ("GPL") version 2 or any later version,
|
||||
* in which case the provisions of the GPL are applicable instead of
|
||||
* the above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use your
|
||||
* version of this file under the BSD license, indicate your decision
|
||||
* by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file under
|
||||
* either the BSD or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef EVENT_H_
|
||||
#define EVENT_H_
|
||||
|
||||
#ifdef EV_H
|
||||
# include EV_H
|
||||
#else
|
||||
# include "ev.h"
|
||||
#endif
|
||||
|
||||
#ifndef EVLOOP_NONBLOCK
|
||||
# define EVLOOP_NONBLOCK EVRUN_NOWAIT
|
||||
#endif
|
||||
#ifndef EVLOOP_ONESHOT
|
||||
# define EVLOOP_ONESHOT EVRUN_ONCE
|
||||
#endif
|
||||
#ifndef EV_TIMEOUT
|
||||
# define EV_TIMEOUT EV_TIMER
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* we need sys/time.h for struct timeval only */
|
||||
#if !defined (WIN32) || defined (__MINGW32__)
|
||||
# include <time.h> /* mingw seems to need this, for whatever reason */
|
||||
# include <sys/time.h>
|
||||
#endif
|
||||
|
||||
struct event_base;
|
||||
|
||||
#define EVLIST_TIMEOUT 0x01
|
||||
#define EVLIST_INSERTED 0x02
|
||||
#define EVLIST_SIGNAL 0x04
|
||||
#define EVLIST_ACTIVE 0x08
|
||||
#define EVLIST_INTERNAL 0x10
|
||||
#define EVLIST_INIT 0x80
|
||||
|
||||
typedef void (*event_callback_fn)(int, short, void *);
|
||||
|
||||
struct event
|
||||
{
|
||||
/* libev watchers we map onto */
|
||||
union {
|
||||
struct ev_io io;
|
||||
struct ev_signal sig;
|
||||
} iosig;
|
||||
struct ev_timer to;
|
||||
|
||||
/* compatibility slots */
|
||||
struct event_base *ev_base;
|
||||
event_callback_fn ev_callback;
|
||||
void *ev_arg;
|
||||
int ev_fd;
|
||||
int ev_pri;
|
||||
int ev_res;
|
||||
int ev_flags;
|
||||
short ev_events;
|
||||
};
|
||||
|
||||
event_callback_fn event_get_callback (const struct event *ev);
|
||||
|
||||
#define EV_READ EV_READ
|
||||
#define EV_WRITE EV_WRITE
|
||||
#define EV_PERSIST 0x10
|
||||
#define EV_ET 0x20 /* nop */
|
||||
|
||||
#define EVENT_SIGNAL(ev) ((int) (ev)->ev_fd)
|
||||
#define EVENT_FD(ev) ((int) (ev)->ev_fd)
|
||||
|
||||
#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
|
||||
|
||||
#define evtimer_add(ev,tv) event_add (ev, tv)
|
||||
#define evtimer_set(ev,cb,data) event_set (ev, -1, 0, cb, data)
|
||||
#define evtimer_del(ev) event_del (ev)
|
||||
#define evtimer_pending(ev,tv) event_pending (ev, EV_TIMEOUT, tv)
|
||||
#define evtimer_initialized(ev) event_initialized (ev)
|
||||
|
||||
#define timeout_add(ev,tv) evtimer_add (ev, tv)
|
||||
#define timeout_set(ev,cb,data) evtimer_set (ev, cb, data)
|
||||
#define timeout_del(ev) evtimer_del (ev)
|
||||
#define timeout_pending(ev,tv) evtimer_pending (ev, tv)
|
||||
#define timeout_initialized(ev) evtimer_initialized (ev)
|
||||
|
||||
#define signal_add(ev,tv) event_add (ev, tv)
|
||||
#define signal_set(ev,sig,cb,data) event_set (ev, sig, EV_SIGNAL | EV_PERSIST, cb, data)
|
||||
#define signal_del(ev) event_del (ev)
|
||||
#define signal_pending(ev,tv) event_pending (ev, EV_SIGNAL, tv)
|
||||
#define signal_initialized(ev) event_initialized (ev)
|
||||
|
||||
const char *event_get_version (void);
|
||||
const char *event_get_method (void);
|
||||
|
||||
void *event_init (void);
|
||||
void event_base_free (struct event_base *base);
|
||||
|
||||
#define EVLOOP_ONCE EVLOOP_ONESHOT
|
||||
int event_loop (int);
|
||||
int event_loopexit (struct timeval *tv);
|
||||
int event_dispatch (void);
|
||||
|
||||
#define _EVENT_LOG_DEBUG 0
|
||||
#define _EVENT_LOG_MSG 1
|
||||
#define _EVENT_LOG_WARN 2
|
||||
#define _EVENT_LOG_ERR 3
|
||||
typedef void (*event_log_cb)(int severity, const char *msg);
|
||||
void event_set_log_callback(event_log_cb cb);
|
||||
|
||||
void event_set (struct event *ev, int fd, short events, void (*cb)(int, short, void *), void *arg);
|
||||
int event_once (int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv);
|
||||
|
||||
int event_add (struct event *ev, struct timeval *tv);
|
||||
int event_del (struct event *ev);
|
||||
void event_active (struct event *ev, int res, short ncalls); /* ncalls is being ignored */
|
||||
|
||||
int event_pending (struct event *ev, short, struct timeval *tv);
|
||||
|
||||
int event_priority_init (int npri);
|
||||
int event_priority_set (struct event *ev, int pri);
|
||||
|
||||
struct event_base *event_base_new (void);
|
||||
const char *event_base_get_method (const struct event_base *);
|
||||
int event_base_set (struct event_base *base, struct event *ev);
|
||||
int event_base_loop (struct event_base *base, int);
|
||||
int event_base_loopexit (struct event_base *base, struct timeval *tv);
|
||||
int event_base_dispatch (struct event_base *base);
|
||||
int event_base_once (struct event_base *base, int fd, short events, void (*cb)(int, short, void *), void *arg, struct timeval *tv);
|
||||
int event_base_priority_init (struct event_base *base, int fd);
|
||||
|
||||
/* next line is different in the libevent+libev version */
|
||||
/*libevent-include*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -1,226 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
|
||||
* Copyright (c) 2008 Marc Alexander Lehmann <libev@schmorp.de>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
# undef WIN32_LEAN_AND_MEAN
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned short u_short;
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Fix so that ppl dont have to run with <sys/queue.h> */
|
||||
#ifndef TAILQ_ENTRY
|
||||
#define _EVENT_DEFINED_TQENTRY
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
#endif /* !TAILQ_ENTRY */
|
||||
#ifndef RB_ENTRY
|
||||
#define _EVENT_DEFINED_RBENTRY
|
||||
#define RB_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *rbe_left; /* left element */ \
|
||||
struct type *rbe_right; /* right element */ \
|
||||
struct type *rbe_parent; /* parent element */ \
|
||||
int rbe_color; /* node color */ \
|
||||
}
|
||||
#endif /* !RB_ENTRY */
|
||||
|
||||
/*
|
||||
* Key-Value pairs. Can be used for HTTP headers but also for
|
||||
* query argument parsing.
|
||||
*/
|
||||
struct evkeyval {
|
||||
TAILQ_ENTRY(evkeyval) next;
|
||||
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
|
||||
#ifdef _EVENT_DEFINED_TQENTRY
|
||||
#undef TAILQ_ENTRY
|
||||
struct event_list;
|
||||
struct evkeyvalq;
|
||||
#undef _EVENT_DEFINED_TQENTRY
|
||||
#else
|
||||
TAILQ_HEAD (event_list, event);
|
||||
TAILQ_HEAD (evkeyvalq, evkeyval);
|
||||
#endif /* _EVENT_DEFINED_TQENTRY */
|
||||
#ifdef _EVENT_DEFINED_RBENTRY
|
||||
#undef RB_ENTRY
|
||||
#undef _EVENT_DEFINED_RBENTRY
|
||||
#endif /* _EVENT_DEFINED_RBENTRY */
|
||||
|
||||
struct eventop {
|
||||
char *name;
|
||||
void *(*init)(struct event_base *);
|
||||
int (*add)(void *, struct event *);
|
||||
int (*del)(void *, struct event *);
|
||||
int (*recalc)(struct event_base *, void *, int);
|
||||
int (*dispatch)(struct event_base *, void *, struct timeval *);
|
||||
void (*dealloc)(struct event_base *, void *);
|
||||
};
|
||||
|
||||
/* These functions deal with buffering input and output */
|
||||
|
||||
struct evbuffer {
|
||||
u_char *buffer;
|
||||
u_char *orig_buffer;
|
||||
|
||||
size_t misalign;
|
||||
size_t totallen;
|
||||
size_t off;
|
||||
|
||||
void (*cb)(struct evbuffer *, size_t, size_t, void *);
|
||||
void *cbarg;
|
||||
};
|
||||
|
||||
/* Just for error reporting - use other constants otherwise */
|
||||
#define EVBUFFER_READ 0x01
|
||||
#define EVBUFFER_WRITE 0x02
|
||||
#define EVBUFFER_EOF 0x10
|
||||
#define EVBUFFER_ERROR 0x20
|
||||
#define EVBUFFER_TIMEOUT 0x40
|
||||
|
||||
struct bufferevent;
|
||||
typedef void (*evbuffercb)(struct bufferevent *, void *);
|
||||
typedef void (*everrorcb)(struct bufferevent *, short what, void *);
|
||||
|
||||
struct event_watermark {
|
||||
size_t low;
|
||||
size_t high;
|
||||
};
|
||||
|
||||
struct bufferevent {
|
||||
struct event ev_read;
|
||||
struct event ev_write;
|
||||
|
||||
struct evbuffer *input;
|
||||
struct evbuffer *output;
|
||||
|
||||
struct event_watermark wm_read;
|
||||
struct event_watermark wm_write;
|
||||
|
||||
evbuffercb readcb;
|
||||
evbuffercb writecb;
|
||||
everrorcb errorcb;
|
||||
void *cbarg;
|
||||
|
||||
int timeout_read; /* in seconds */
|
||||
int timeout_write; /* in seconds */
|
||||
|
||||
short enabled; /* events that are currently enabled */
|
||||
};
|
||||
|
||||
struct bufferevent *bufferevent_new(int fd,
|
||||
evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
|
||||
int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
|
||||
int bufferevent_priority_set(struct bufferevent *bufev, int pri);
|
||||
void bufferevent_free(struct bufferevent *bufev);
|
||||
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);
|
||||
int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
|
||||
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
|
||||
int bufferevent_enable(struct bufferevent *bufev, short event);
|
||||
int bufferevent_disable(struct bufferevent *bufev, short event);
|
||||
void bufferevent_settimeout(struct bufferevent *bufev,
|
||||
int timeout_read, int timeout_write);
|
||||
|
||||
#define EVBUFFER_LENGTH(x) (x)->off
|
||||
#define EVBUFFER_DATA(x) (x)->buffer
|
||||
#define EVBUFFER_INPUT(x) (x)->input
|
||||
#define EVBUFFER_OUTPUT(x) (x)->output
|
||||
|
||||
struct evbuffer *evbuffer_new(void);
|
||||
void evbuffer_free(struct evbuffer *);
|
||||
int evbuffer_expand(struct evbuffer *, size_t);
|
||||
int evbuffer_add(struct evbuffer *, const void *, size_t);
|
||||
int evbuffer_remove(struct evbuffer *, void *, size_t);
|
||||
char *evbuffer_readline(struct evbuffer *);
|
||||
int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
|
||||
int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...);
|
||||
int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
|
||||
void evbuffer_drain(struct evbuffer *, size_t);
|
||||
int evbuffer_write(struct evbuffer *, int);
|
||||
int evbuffer_read(struct evbuffer *, int, int);
|
||||
u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
|
||||
void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
|
||||
|
||||
/*
|
||||
* Marshaling tagged data - We assume that all tags are inserted in their
|
||||
* numeric order - so that unknown tags will always be higher than the
|
||||
* known ones - and we can just ignore the end of an event buffer.
|
||||
*/
|
||||
|
||||
void evtag_init(void);
|
||||
|
||||
void evtag_marshal(struct evbuffer *evbuf, uint32_t tag, const void *data,
|
||||
uint32_t len);
|
||||
|
||||
void encode_int(struct evbuffer *evbuf, uint32_t number);
|
||||
|
||||
void evtag_marshal_int(struct evbuffer *evbuf, uint32_t tag, uint32_t integer);
|
||||
|
||||
void evtag_marshal_string(struct evbuffer *buf, uint32_t tag,
|
||||
const char *string);
|
||||
|
||||
void evtag_marshal_timeval(struct evbuffer *evbuf, uint32_t tag,
|
||||
struct timeval *tv);
|
||||
|
||||
int evtag_unmarshal(struct evbuffer *src, uint32_t *ptag, struct evbuffer *dst);
|
||||
int evtag_peek(struct evbuffer *evbuf, uint32_t *ptag);
|
||||
int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength);
|
||||
int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength);
|
||||
int evtag_consume(struct evbuffer *evbuf);
|
||||
|
||||
int evtag_unmarshal_int(struct evbuffer *evbuf, uint32_t need_tag,
|
||||
uint32_t *pinteger);
|
||||
|
||||
int evtag_unmarshal_fixed(struct evbuffer *src, uint32_t need_tag, void *data,
|
||||
size_t len);
|
||||
|
||||
int evtag_unmarshal_string(struct evbuffer *evbuf, uint32_t need_tag,
|
||||
char **pstring);
|
||||
|
||||
int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint32_t need_tag,
|
||||
struct timeval *ptv);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@@ -1,131 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
LE=../libevent-1.4.3-stable
|
||||
|
||||
if ! [ -e evbuffer.c ]; then
|
||||
echo do not run this programm unless you know what you are doing
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# this program combines libev and libevent into a single package
|
||||
|
||||
cvs update -AdP libev
|
||||
rsync -avP libev/. . --exclude CVS
|
||||
|
||||
rm -f configure.ac
|
||||
|
||||
cp $LE/evdns.h .
|
||||
|
||||
perl -i -pe 's%^/.libevent-include./%#include "event_compat.h"%' event.h
|
||||
|
||||
perl -ne '
|
||||
s/\s+char buf\[64\];/\tchar buf[96];/;
|
||||
if (/#include "event.h"/) {
|
||||
print "#ifndef EV_STANDALONE\n$_#endif\n";
|
||||
next;
|
||||
}
|
||||
if (/#include "misc.h"/) {
|
||||
print "#ifndef EV_STANDALONE\n$_#endif\n";
|
||||
next;
|
||||
}
|
||||
if (/#include "(unistd.h|sys\/time.h)"/) {
|
||||
print "#ifndef WIN32\n$_#endif\n";
|
||||
next;
|
||||
}
|
||||
next if /#include "log.h"/;
|
||||
|
||||
print;
|
||||
' <$LE/evdns.c >evdns.c
|
||||
|
||||
cp $LE/autogen.sh .
|
||||
cp $LE/epoll_sub.c .
|
||||
cp $LE/evbuffer.c .
|
||||
cp $LE/buffer.c .
|
||||
cp $LE/evhttp.h .
|
||||
cp $LE/evutil.h .
|
||||
cp $LE/evutil.c .
|
||||
cp $LE/event-config.h .
|
||||
cp $LE/event-internal.h .
|
||||
cp $LE/evrpc.h .
|
||||
cp $LE/evrpc.c .
|
||||
cp $LE/evrpc-internal.h .
|
||||
cp $LE/http.c .
|
||||
cp $LE/event_tagging.c .
|
||||
cp $LE/http-internal.h .
|
||||
cp $LE/strlcpy-internal.h .
|
||||
cp $LE/log.c .
|
||||
cp $LE/log.h .
|
||||
cp $LE/strlcpy.c .
|
||||
rsync -a $LE/WIN32* $LE/sample $LE/test $LE/compat . --del
|
||||
#rename 's/libevent/libev/' WIN32-Prj/lib*
|
||||
cp $LE/aclocal.m4 .
|
||||
#cp $LE/acconfig.h .
|
||||
cp $LE/config.h.in .
|
||||
cp $LE/event_rpcgen.py .
|
||||
cp $LE/*.3 .
|
||||
|
||||
#perl -i -pe 's/libevent/libev/g' sample/Makefile.am
|
||||
#perl -i -pe 's/libevent/libev/g' test/Makefile.am
|
||||
|
||||
perl -i -pe 's/#include <event.h>$/#include "event.h"/' test/*.c
|
||||
|
||||
perl -i -ne '
|
||||
next if /"event-internal.h"/;
|
||||
s/base\d?->sig.ev_signal_added/0/;
|
||||
s/base\d?->sig.ev_signal_pair\[0\]/-1/;
|
||||
s/base->sig.evsignal_caught/0/;
|
||||
next if /^\ttest_signal_(dealloc|pipeloss|switchbase|assert|restore)\(\)/;
|
||||
next if /^\ttest_simplesignal\(\)/; # non-default-loop
|
||||
next if /^\ttest_immediatesignal\(\)/; # non-default-loop
|
||||
next if /test_priorities\(\d\)/;
|
||||
print;
|
||||
' test/regress.c
|
||||
|
||||
perl -ne '
|
||||
s/\bmin_heap.h\b//g;
|
||||
s/\bsignal.c\b//g;
|
||||
s/\bevport.c\b//g;
|
||||
s/\bkqueue.c\b//g;
|
||||
s/\bdevpoll.c\b//g;
|
||||
s/\brtsig.c\b//g;
|
||||
s/\bselect.c\b//g;
|
||||
s/\bpoll.c\b//g;
|
||||
s/\bepoll.c\b//g;
|
||||
s/\bepoll_sub.c\b//g;
|
||||
s/\bevent-internal.h\b//g;
|
||||
s/\bevsignal.h\b//g;
|
||||
s/^(man_MANS\s*=)/$1 ev.3 /;
|
||||
s/^(EXTRA_DIST\s*=)/$1 libev.m4 ev.h ev_vars.h ev_wrap.h event_compat.h ev++.h ev_epoll.c ev_select.c ev_poll.c ev_kqueue.c ev_port.c ev_win32.c ev.3 ev.pod /;
|
||||
s/^(include_HEADERS\s*=)/$1 ev.h event_compat.h ev++.h /;
|
||||
s/^(CORE_SRC\s*=)/$1 ev.c /;
|
||||
s/^(SYS_LIBS\s*=)/$1 -lm /;
|
||||
#s/libevent/libev/g;
|
||||
print;
|
||||
' <$LE/Makefile.am >Makefile.am
|
||||
|
||||
perl -ne '
|
||||
#s/-Wall/-Wall -Wno-comment -Wunused-function -Wno-unused-value/;
|
||||
s/-Wall//g;
|
||||
#s/libevent/libev/g;
|
||||
#VERSION
|
||||
s/AM_INIT_AUTOMAKE\s*\(.*,(.*)\)/AM_INIT_AUTOMAKE(libevent-$1+libev,3.1)/;
|
||||
s/AC_LIBOBJ\(select\)/: ;/g;
|
||||
s/AC_LIBOBJ\(poll\)/: ;/g;
|
||||
s/AC_LIBOBJ\(kqueue\)/: ;/g;
|
||||
s/AC_LIBOBJ\(epoll\)/: ;/g;
|
||||
s/AC_LIBOBJ\(devpoll\)/: ;/g;
|
||||
s/AC_LIBOBJ\(evport\)/: ;/g;
|
||||
s/AC_LIBOBJ\(signal\)/: ;/g;
|
||||
s/AC_LIBOBJ\(rtsig\)/: ;/g;
|
||||
print "m4_include([libev.m4])\n" if /^AC_OUTPUT/;
|
||||
print;
|
||||
' <$LE/configure.in >configure.in
|
||||
|
||||
aclocal-1.7
|
||||
automake-1.7 --add-missing
|
||||
autoconf
|
||||
autoheader
|
||||
libtoolize
|
||||
CC="ccache gcc" ./configure --prefix=/opt/libev --disable-shared "$@"
|
||||
|
||||
|
@@ -1,42 +0,0 @@
|
||||
dnl this file is part of libev, do not make local modifications
|
||||
dnl http://software.schmorp.de/pkg/libev
|
||||
|
||||
dnl libev support
|
||||
AC_CHECK_HEADERS(sys/inotify.h sys/epoll.h sys/event.h port.h poll.h sys/select.h sys/eventfd.h sys/signalfd.h)
|
||||
|
||||
AC_CHECK_FUNCS(inotify_init epoll_ctl kqueue port_create poll select eventfd signalfd)
|
||||
|
||||
AC_CHECK_FUNCS(clock_gettime, [], [
|
||||
dnl on linux, try syscall wrapper first
|
||||
if test $(uname) = Linux; then
|
||||
AC_MSG_CHECKING(for clock_gettime syscall)
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM(
|
||||
[#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <time.h>],
|
||||
[struct timespec ts; int status = syscall (SYS_clock_gettime, CLOCK_REALTIME, &ts)])],
|
||||
[ac_have_clock_syscall=1
|
||||
AC_DEFINE(HAVE_CLOCK_SYSCALL, 1, Define to 1 to use the syscall interface for clock_gettime)
|
||||
AC_MSG_RESULT(yes)],
|
||||
[AC_MSG_RESULT(no)])
|
||||
fi
|
||||
if test -z "$LIBEV_M4_AVOID_LIBRT" && test -z "$ac_have_clock_syscall"; then
|
||||
AC_CHECK_LIB(rt, clock_gettime)
|
||||
unset ac_cv_func_clock_gettime
|
||||
AC_CHECK_FUNCS(clock_gettime)
|
||||
fi
|
||||
])
|
||||
|
||||
AC_CHECK_FUNCS(nanosleep, [], [
|
||||
if test -z "$LIBEV_M4_AVOID_LIBRT"; then
|
||||
AC_CHECK_LIB(rt, nanosleep)
|
||||
unset ac_cv_func_nanosleep
|
||||
AC_CHECK_FUNCS(nanosleep)
|
||||
fi
|
||||
])
|
||||
|
||||
if test -z "$LIBEV_M4_AVOID_LIBM"; then
|
||||
LIBM=m
|
||||
fi
|
||||
AC_SEARCH_LIBS(floor, $LIBM, [AC_DEFINE(HAVE_FLOOR, 1, Define to 1 if the floor function is available)])
|
||||
|
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
(
|
||||
sed -ne '1,\%/\* ECB.H BEGIN \*/%p' ev.c
|
||||
cat ~/src/libecb/ecb.h
|
||||
sed -ne '\%/\* ECB.H END \*/%,$p' ev.c
|
||||
) >ev.c~ && mv ev.c~ ev.c
|
||||
|
@@ -1,19 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
(
|
||||
echo '#define VAR(name,decl) name'
|
||||
echo '#define EV_GENWRAP 1'
|
||||
cat ev_vars.h
|
||||
) | cc -E -o - - | perl -ne '
|
||||
while (<>) {
|
||||
push @syms, $1 if /(^\w+)/;
|
||||
}
|
||||
print "/* DO NOT EDIT, automatically generated by update_ev_wrap */\n",
|
||||
"#ifndef EV_WRAP_H\n",
|
||||
"#define EV_WRAP_H\n",
|
||||
(map "#define $_ ((loop)->$_)\n", sort @syms),
|
||||
"#else\n",
|
||||
"#undef EV_WRAP_H\n",
|
||||
(map "#undef $_\n", sort @syms),
|
||||
"#endif\n";
|
||||
' >ev_wrap.h
|
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
make ev.o event.o || exit
|
||||
|
||||
nm ev.o | perl -ne 'print "$1\n" if /\S+ [A-Z] (\S+)/' > Symbols.ev
|
||||
nm event.o | perl -ne 'print "$1\n" if /\S+ [A-Z] (\S+)/' > Symbols.event
|
||||
|
42
log.h
@@ -2,16 +2,56 @@
|
||||
#ifndef _LOG_MYLOG_H_
|
||||
#define _LOG_MYLOG_H_
|
||||
|
||||
|
||||
#include<stdio.h>
|
||||
#include<string.h>
|
||||
#include<sys/socket.h>
|
||||
#include<arpa/inet.h>
|
||||
#include<stdlib.h>
|
||||
#include<getopt.h>
|
||||
#include <unistd.h>
|
||||
#include<errno.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
//#include"aes.h"
|
||||
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include<map>
|
||||
#include<string>
|
||||
#include<vector>
|
||||
|
||||
|
||||
#include <sys/socket.h> //for socket ofcourse
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h> //for exit(0);
|
||||
#include <errno.h> //For errno - the error number
|
||||
#include <netinet/tcp.h> //Provides declarations for tcp header
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/ip.h> //Provides declarations for ip header
|
||||
#include <netinet/if_ether.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <byteswap.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/filter.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <sys/timerfd.h>
|
||||
#include <set>
|
||||
//#include <encrypt.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
133
makefile
Executable file → Normal file
@@ -1,119 +1,18 @@
|
||||
cc_cross=/home/wangyu/Desktop/arm-2014.05/bin/arm-none-linux-gnueabi-g++
|
||||
cc_local=g++
|
||||
cc_mips24kc_be=/toolchains/lede-sdk-17.01.2-ar71xx-generic_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mips_24kc_gcc-5.4.0_musl-1.1.16/bin/mips-openwrt-linux-musl-g++
|
||||
cc_mips24kc_le=/toolchains/lede-sdk-17.01.2-ramips-mt7621_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-mipsel_24kc_gcc-5.4.0_musl-1.1.16/bin/mipsel-openwrt-linux-musl-g++
|
||||
cc_arm= /toolchains/lede-sdk-17.01.2-bcm53xx_gcc-5.4.0_musl-1.1.16_eabi.Linux-x86_64/staging_dir/toolchain-arm_cortex-a9_gcc-5.4.0_musl-1.1.16_eabi/bin/arm-openwrt-linux-c++
|
||||
cc_mingw_cross=i686-w64-mingw32-g++-posix
|
||||
cc_mac_cross=o64-clang++ -stdlib=libc++
|
||||
cc_x86=/toolchains/lede-sdk-17.01.2-x86-generic_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-i386_pentium4_gcc-5.4.0_musl-1.1.16/bin/i486-openwrt-linux-c++
|
||||
cc_amd64=/toolchains/lede-sdk-17.01.2-x86-64_gcc-5.4.0_musl-1.1.16.Linux-x86_64/staging_dir/toolchain-x86_64_gcc-5.4.0_musl-1.1.16/bin/x86_64-openwrt-linux-c++
|
||||
#cc_bcm2708=/home/wangyu/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++
|
||||
cross_cc=mips-openwrt-linux-g++
|
||||
FLAGS=-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -ggdb
|
||||
FLAGS2= -O3
|
||||
all:
|
||||
g++ main.cpp common.cpp log.cpp -I. -o speeder -static -lrt -std=c++11 ${FLAGS} ${FLAGS2}
|
||||
release:
|
||||
g++ main.cpp common.cpp log.cpp -I. -o speeder_amd64 -static -lrt -std=c++11 ${FLAGS} ${FLAGS2}
|
||||
g++ -m32 main.cpp common.cpp log.cpp -I. -o speeder_x86 -static -lrt -std=c++11 ${FLAGS} ${FLAGS2}
|
||||
${cross_cc} main.cpp common.cpp log.cpp -I. -o speeder_ar71xx -lrt -std=c++11 ${FLAGS} ${FLAGS2}
|
||||
tar -zcvf udp_speeder_binaries.tar.gz speeder_amd64 speeder_x86 speeder_ar71xx
|
||||
cross:
|
||||
${cross_cc} main.cpp common.cpp log.cpp -I. -o speeder_cross -lrt -std=c++11 ${FLAGS} ${FLAGS2}
|
||||
|
||||
debug:
|
||||
g++ main.cpp common.cpp log.cpp -I. -o speeder -static -lrt -std=c++11 ${FLAGS} -Wformat-nonliteral -D MY_DEBUG
|
||||
|
||||
SOURCES0=main.cpp log.cpp common.cpp lib/fec.cpp lib/rs.cpp packet.cpp delay_manager.cpp fd_manager.cpp connection.cpp fec_manager.cpp misc.cpp tunnel_client.cpp tunnel_server.cpp
|
||||
SOURCES=${SOURCES0} my_ev.cpp -isystem libev
|
||||
NAME=speederv2
|
||||
|
||||
|
||||
FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers ${OPT}
|
||||
|
||||
TARGETS=amd64 arm mips24kc_be x86 mips24kc_le
|
||||
|
||||
TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/${NAME}_\1/g'` version.txt
|
||||
|
||||
export STAGING_DIR=/tmp/ #just for supress warning of staging_dir not define
|
||||
|
||||
# targets for nativei (non-cross) compile
|
||||
all:git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2
|
||||
|
||||
freebsd:git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2
|
||||
|
||||
mingw:git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -ggdb -static -O2 -lws2_32
|
||||
|
||||
mingw_wepoll:git_version #to compile you need a pacthed version of libev with wepoll backend
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES0} ${FLAGS} -ggdb -static -O2 -DNO_LIBEV_EMBED -D_WIN32 -lev -lws2_32
|
||||
|
||||
mac:git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -ggdb -O2
|
||||
|
||||
cygwin:git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2 -D_GNU_SOURCE
|
||||
|
||||
#targes for general cross compile
|
||||
|
||||
cross:git_version
|
||||
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -O2
|
||||
|
||||
cross2:git_version
|
||||
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -lgcc_eh -O2
|
||||
|
||||
cross3:git_version
|
||||
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -O2
|
||||
|
||||
#targets only for debug purpose
|
||||
fast: git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -ggdb
|
||||
debug: git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -D MY_DEBUG -ggdb
|
||||
debug2: git_version
|
||||
rm -f ${NAME}
|
||||
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -ggdb
|
||||
|
||||
#targets only for 'make release'
|
||||
|
||||
mips24kc_be: git_version
|
||||
${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O2
|
||||
|
||||
mips24kc_le: git_version
|
||||
${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O2
|
||||
|
||||
amd64:git_version
|
||||
${cc_amd64} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh -ggdb
|
||||
|
||||
x86:git_version #to build this you need 'g++-multilib' installed
|
||||
${cc_x86} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh -ggdb
|
||||
arm:git_version
|
||||
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh
|
||||
|
||||
|
||||
release: ${TARGETS}
|
||||
cp git_version.h version.txt
|
||||
tar -zcvf ${TAR}
|
||||
|
||||
#targets for cross compile windows targets on linux
|
||||
|
||||
mingw_cross:git_version #to build this and the below one you need 'mingw-w64' installed (the cross compile version on linux)
|
||||
${cc_mingw_cross} -o ${NAME}.exe -I. ${SOURCES} ${FLAGS} -ggdb -static -O2 -lws2_32
|
||||
|
||||
mingw_cross_wepoll:git_version #to compile you need a pacthed version of libev with wepoll backend installed
|
||||
${cc_mingw_cross} -o ${NAME}_wepoll.exe -I. ${SOURCES0} ${FLAGS} -ggdb -static -O2 -DNO_LIBEV_EMBED -D_WIN32 -lev -lws2_32
|
||||
|
||||
#targets for cross compile macos targets on linux
|
||||
|
||||
mac_cross:git_version #need to install 'osxcross' first.
|
||||
${cc_mac_cross} -o ${NAME}_mac -I. ${SOURCES} ${FLAGS} -ggdb -O2
|
||||
|
||||
#release2 includes all binary in 'release' plus win and mac cross compile targets
|
||||
|
||||
release2: ${TARGETS} mingw_cross mingw_cross_wepoll mac_cross
|
||||
cp git_version.h version.txt
|
||||
tar -zcvf ${TAR} ${NAME}.exe ${NAME}_wepoll.exe ${NAME}_mac
|
||||
|
||||
clean:
|
||||
rm -f ${TAR}
|
||||
rm -f ${NAME} ${NAME}_cross ${NAME}.exe ${NAME}_wepoll.exe ${NAME}_mac
|
||||
rm -f git_version.h
|
||||
|
||||
git_version:
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > git_version.h
|
||||
#g++ forward.cpp aes.c -o forward -static
|
||||
# ${ccarm} forward.cpp aes.c -o forwardarm -static -lgcc_eh
|
||||
|
83
misc.h
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* misc.h
|
||||
*
|
||||
* Created on: Oct 26, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef MISC_H_
|
||||
#define MISC_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "connection.h"
|
||||
#include "fd_manager.h"
|
||||
#include "delay_manager.h"
|
||||
#include "fec_manager.h"
|
||||
|
||||
|
||||
|
||||
extern char fifo_file[1000];
|
||||
|
||||
extern int mtu_warn;
|
||||
|
||||
extern int disable_mtu_warn;
|
||||
extern int disable_fec;
|
||||
extern int disable_checksum;
|
||||
|
||||
extern int debug_force_flush_fec;
|
||||
|
||||
|
||||
extern int jitter_min;
|
||||
extern int jitter_max;
|
||||
|
||||
extern int output_interval_min;
|
||||
extern int output_interval_max;
|
||||
|
||||
extern int fix_latency;
|
||||
|
||||
//extern u32_t local_ip_uint32,remote_ip_uint32;
|
||||
//extern char local_ip[100], remote_ip[100];
|
||||
//extern int local_port, remote_port;
|
||||
|
||||
|
||||
extern address_t local_addr,remote_addr;
|
||||
|
||||
extern address_t *out_addr;
|
||||
extern char *out_interface;
|
||||
|
||||
extern conn_manager_t conn_manager;
|
||||
extern delay_manager_t delay_manager;
|
||||
extern fd_manager_t fd_manager;
|
||||
|
||||
extern int time_mono_test;
|
||||
|
||||
extern int delay_capacity;
|
||||
|
||||
extern int keep_reconnect;
|
||||
|
||||
extern int tun_mtu;
|
||||
|
||||
extern int mssfix;
|
||||
|
||||
extern int manual_set_tun;
|
||||
extern int persist_tun;
|
||||
|
||||
|
||||
int from_normal_to_fec(conn_info_t & conn_info,char *data,int len,int & out_n,char **&out_arr,int *&out_len,my_time_t *&out_delay);
|
||||
int from_fec_to_normal(conn_info_t & conn_info,char *data,int len,int & out_n,char **&out_arr,int *&out_len,my_time_t *&out_delay);
|
||||
|
||||
int delay_send(my_time_t delay,const dest_t &dest,char *data,int len);
|
||||
int print_parameter();
|
||||
int handle_command(char *s);
|
||||
|
||||
int unit_test();
|
||||
|
||||
//void print_help();
|
||||
|
||||
void process_arg(int argc, char *argv[]);
|
||||
|
||||
extern char sub_net[100];
|
||||
extern u32_t sub_net_uint32;
|
||||
extern char tun_dev[100];
|
||||
|
||||
#endif /* MISC_H_ */
|
16
my_ev.cpp
@@ -1,16 +0,0 @@
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
#pragma GCC diagnostic ignored "-Wcomment"
|
||||
#pragma GCC diagnostic ignored "-Wparentheses"
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#pragma GCC diagnostic ignored "-Wunused-value"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-W"
|
||||
|
||||
#include "my_ev_common.h"
|
||||
#include "ev.c"
|
||||
|
||||
#pragma GCC diagnostic pop
|
@@ -1,13 +0,0 @@
|
||||
|
||||
#define EV_STANDALONE 1
|
||||
#define EV_COMMON void *data; unsigned long long u64;
|
||||
#define EV_COMPAT3 0
|
||||
//#define EV_VERIFY 2
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
# define EV_FD_TO_WIN32_HANDLE(fd) (fd)
|
||||
# define EV_WIN32_HANDLE_TO_FD(handle) (handle)
|
||||
# define EV_WIN32_CLOSE_FD(fd) closesocket (fd)
|
||||
# define FD_SETSIZE 4096
|
||||
|
||||
#endif
|
411
packet.cpp
@@ -1,411 +0,0 @@
|
||||
/*
|
||||
* packet.cpp
|
||||
*
|
||||
* Created on: Sep 15, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "packet.h"
|
||||
#include "misc.h"
|
||||
|
||||
int iv_min=4;
|
||||
int iv_max=32;//< 256;
|
||||
u64_t packet_send_count=0;
|
||||
u64_t dup_packet_send_count=0;
|
||||
u64_t packet_recv_count=0;
|
||||
u64_t dup_packet_recv_count=0;
|
||||
|
||||
typedef u64_t anti_replay_seq_t;
|
||||
int disable_replay_filter=0;
|
||||
|
||||
int disable_obscure=0;
|
||||
int disable_xor=0;
|
||||
|
||||
int random_drop=0;
|
||||
|
||||
char key_string[1000]= "";
|
||||
|
||||
//int local_listen_fd=-1;
|
||||
|
||||
|
||||
void encrypt_0(char * input,int &len,char *key)
|
||||
{
|
||||
int i,j;
|
||||
if(key[0]==0) return;
|
||||
for(i=0,j=0;i<len;i++,j++)
|
||||
{
|
||||
if(key[j]==0)j=0;
|
||||
input[i]^=key[j];
|
||||
}
|
||||
}
|
||||
|
||||
void decrypt_0(char * input,int &len,char *key)
|
||||
{
|
||||
int i,j;
|
||||
if(key[0]==0) return;
|
||||
for(i=0,j=0;i<len;i++,j++)
|
||||
{
|
||||
if(key[j]==0)j=0;
|
||||
input[i]^=key[j];
|
||||
}
|
||||
}
|
||||
int do_obscure_old(const char * input, int in_len,char *output,int &out_len)
|
||||
{
|
||||
//memcpy(output,input,in_len);
|
||||
// out_len=in_len;
|
||||
//return 0;
|
||||
|
||||
int i, j, k;
|
||||
if (in_len > 65535||in_len<0)
|
||||
return -1;
|
||||
int iv_len=iv_min+rand()%(iv_max-iv_min);
|
||||
get_fake_random_chars(output,iv_len);
|
||||
memcpy(output+iv_len,input,in_len);
|
||||
|
||||
output[iv_len+in_len]=(uint8_t)iv_len;
|
||||
|
||||
output[iv_len+in_len]^=output[0];
|
||||
output[iv_len+in_len]^=key_string[0];
|
||||
|
||||
for(i=0,j=0,k=1;i<in_len;i++,j++,k++)
|
||||
{
|
||||
if(j==iv_len) j=0;
|
||||
if(key_string[k]==0)k=0;
|
||||
output[iv_len+i]^=output[j];
|
||||
output[iv_len+i]^=key_string[k];
|
||||
}
|
||||
|
||||
|
||||
out_len=iv_len+in_len+1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_obscure(char * data,int &len)
|
||||
{
|
||||
assert(len>=0);
|
||||
assert(len<buf_len);
|
||||
|
||||
int iv_len=random_between(iv_min,iv_max);
|
||||
get_fake_random_chars(data+len,iv_len);
|
||||
data[iv_len+len]=(uint8_t)iv_len;
|
||||
for(int i=0,j=0;i<len;i++,j++)
|
||||
{
|
||||
if(j==iv_len)j=0;
|
||||
data[i]^=data[len+j];
|
||||
}
|
||||
|
||||
len=len+iv_len+1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int de_obscure(char * data,int &len)
|
||||
{
|
||||
if(len<1) return -1;
|
||||
int iv_len=int ((uint8_t) data[len-1]);
|
||||
|
||||
if(len<1+iv_len) return -1;
|
||||
|
||||
len=len-1-iv_len;
|
||||
for(int i=0,j=0;i<len;i++,j++)
|
||||
{
|
||||
if(j==iv_len)j=0;
|
||||
data[i]^=data[len+j];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int de_obscure_old(const char * input, int in_len,char *output,int &out_len)
|
||||
{
|
||||
//memcpy(output,input,in_len);
|
||||
//out_len=in_len;
|
||||
//return 0;
|
||||
|
||||
int i, j, k;
|
||||
if (in_len > 65535||in_len<0)
|
||||
{
|
||||
mylog(log_debug,"in_len > 65535||in_len<0 , %d",in_len);
|
||||
return -1;
|
||||
}
|
||||
int iv_len= int ((uint8_t)(input[in_len-1]^input[0]^key_string[0]) );
|
||||
out_len=in_len-1-iv_len;
|
||||
if(out_len<0)
|
||||
{
|
||||
mylog(log_debug,"%d %d\n",in_len,out_len);
|
||||
return -1;
|
||||
}
|
||||
for(i=0,j=0,k=1;i<in_len;i++,j++,k++)
|
||||
{
|
||||
if(j==iv_len) j=0;
|
||||
if(key_string[k]==0)k=0;
|
||||
output[i]=input[iv_len+i]^input[j]^key_string[k];
|
||||
|
||||
}
|
||||
dup_packet_recv_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
int sendto_fd_ip_port (int fd,u32_t ip,int port,char * buf, int len,int flags)
|
||||
{
|
||||
|
||||
sockaddr_in tmp_sockaddr;
|
||||
|
||||
memset(&tmp_sockaddr,0,sizeof(tmp_sockaddr));
|
||||
tmp_sockaddr.sin_family = AF_INET;
|
||||
tmp_sockaddr.sin_addr.s_addr = ip;
|
||||
tmp_sockaddr.sin_port = htons(uint16_t(port));
|
||||
|
||||
return sendto(fd, buf,
|
||||
len , 0,
|
||||
(struct sockaddr *) &tmp_sockaddr,
|
||||
sizeof(tmp_sockaddr));
|
||||
}*/
|
||||
|
||||
int sendto_fd_addr (int fd,address_t addr,char * buf, int len,int flags)
|
||||
{
|
||||
|
||||
return sendto(fd, buf,
|
||||
len , 0,
|
||||
(struct sockaddr *) &addr.inner,
|
||||
addr.get_len());
|
||||
}
|
||||
/*
|
||||
int sendto_ip_port (u32_t ip,int port,char * buf, int len,int flags)
|
||||
{
|
||||
return sendto_fd_ip_port(local_listen_fd,ip,port,buf,len,flags);
|
||||
}*/
|
||||
|
||||
int send_fd (int fd,char * buf, int len,int flags)
|
||||
{
|
||||
return send(fd,buf,len,flags);
|
||||
}
|
||||
|
||||
int my_send(const dest_t &dest,char *data,int len)
|
||||
{
|
||||
if(dest.cook)
|
||||
{
|
||||
do_cook(data,len);
|
||||
}
|
||||
switch(dest.type)
|
||||
{
|
||||
case type_fd_addr:
|
||||
{
|
||||
return sendto_fd_addr(dest.inner.fd,dest.inner.fd_addr.addr,data,len,0);
|
||||
break;
|
||||
}
|
||||
case type_fd64_addr:
|
||||
{
|
||||
if(!fd_manager.exist(dest.inner.fd64)) return -1;
|
||||
int fd=fd_manager.to_fd(dest.inner.fd64);
|
||||
|
||||
return sendto_fd_addr(fd,dest.inner.fd64_addr.addr,data,len,0);
|
||||
break;
|
||||
}
|
||||
case type_fd:
|
||||
{
|
||||
return send_fd(dest.inner.fd,data,len,0);
|
||||
break;
|
||||
}
|
||||
case type_write_fd:
|
||||
{
|
||||
return write(dest.inner.fd,data,len);
|
||||
break;
|
||||
}
|
||||
case type_fd64:
|
||||
{
|
||||
|
||||
if(!fd_manager.exist(dest.inner.fd64)) return -1;
|
||||
int fd=fd_manager.to_fd(dest.inner.fd64);
|
||||
|
||||
return send_fd(fd,data,len,0);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
case type_fd64_ip_port_conv:
|
||||
{
|
||||
if(!fd_manager.exist(dest.inner.fd64)) return -1;
|
||||
int fd=fd_manager.to_fd(dest.inner.fd64);
|
||||
|
||||
char *new_data;
|
||||
int new_len;
|
||||
|
||||
put_conv(dest.conv,data,len,new_data,new_len);
|
||||
return sendto_fd_ip_port(fd,dest.inner.fd64_ip_port.ip_port.ip,dest.inner.fd64_ip_port.ip_port.port,new_data,new_len,0);
|
||||
break;
|
||||
}*/
|
||||
|
||||
/*
|
||||
case type_fd64_conv:
|
||||
{
|
||||
char *new_data;
|
||||
int new_len;
|
||||
put_conv(dest.conv,data,len,new_data,new_len);
|
||||
|
||||
if(!fd_manager.exist(dest.inner.fd64)) return -1;
|
||||
int fd=fd_manager.to_fd(dest.inner.fd64);
|
||||
return send_fd(fd,new_data,new_len,0);
|
||||
}*/
|
||||
/*
|
||||
case type_fd:
|
||||
{
|
||||
send_fd(dest.inner.fd,data,len,0);
|
||||
break;
|
||||
}*/
|
||||
default:
|
||||
assert(0==1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function comes from http://www.hackersdelight.org/hdcodetxt/crc.c.txt
|
||||
*/
|
||||
unsigned int crc32h(unsigned char *message,int len) {
|
||||
assert(len>=0);
|
||||
int i, crc;
|
||||
unsigned int byte, c;
|
||||
const unsigned int g0 = 0xEDB88320, g1 = g0>>1,
|
||||
g2 = g0>>2, g3 = g0>>3, g4 = g0>>4, g5 = g0>>5,
|
||||
g6 = (g0>>6)^g0, g7 = ((g0>>6)^g0)>>1;
|
||||
|
||||
i = 0;
|
||||
crc = 0xFFFFFFFF;
|
||||
while (i!=len) { // Get next byte.
|
||||
byte = message[i];
|
||||
crc = crc ^ byte;
|
||||
c = ((crc<<31>>31) & g7) ^ ((crc<<30>>31) & g6) ^
|
||||
((crc<<29>>31) & g5) ^ ((crc<<28>>31) & g4) ^
|
||||
((crc<<27>>31) & g3) ^ ((crc<<26>>31) & g2) ^
|
||||
((crc<<25>>31) & g1) ^ ((crc<<24>>31) & g0);
|
||||
crc = ((unsigned)crc >> 8) ^ c;
|
||||
i = i + 1;
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
int put_conv0(u32_t conv,const char * input,int len_in,char *&output,int &len_out)
|
||||
{
|
||||
assert(len_in>=0);
|
||||
static char buf[buf_len];
|
||||
output=buf;
|
||||
u32_t n_conv=htonl(conv);
|
||||
memcpy(output,&n_conv,sizeof(n_conv));
|
||||
memcpy(output+sizeof(n_conv),input,len_in);
|
||||
u32_t crc32=crc32h((unsigned char *)output,len_in+sizeof(crc32));
|
||||
u32_t crc32_n=htonl(crc32);
|
||||
len_out=len_in+(int)(sizeof(n_conv))+(int)sizeof(crc32_n);
|
||||
memcpy(output+len_in+(int)(sizeof(n_conv)),&crc32_n,sizeof(crc32_n));
|
||||
return 0;
|
||||
}
|
||||
int get_conv0(u32_t &conv,const char *input,int len_in,char *&output,int &len_out )
|
||||
{
|
||||
assert(len_in>=0);
|
||||
u32_t n_conv;
|
||||
memcpy(&n_conv,input,sizeof(n_conv));
|
||||
conv=ntohl(n_conv);
|
||||
output=(char *)input+sizeof(n_conv);
|
||||
u32_t crc32_n;
|
||||
len_out=len_in-(int)sizeof(n_conv)-(int)sizeof(crc32_n);
|
||||
if(len_out<0)
|
||||
{
|
||||
mylog(log_debug,"len_out<0\n");
|
||||
return -1;
|
||||
}
|
||||
memcpy(&crc32_n,input+len_in-(int)sizeof(crc32_n),sizeof(crc32_n));
|
||||
u32_t crc32=ntohl(crc32_n);
|
||||
if(crc32!=crc32h((unsigned char *)input,len_in-(int)sizeof(crc32_n)))
|
||||
{
|
||||
mylog(log_debug,"crc32 check failed\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int put_crc32(char * s,int &len)
|
||||
{
|
||||
if(disable_checksum)return 0;
|
||||
assert(len>=0);
|
||||
//if(len<0) return -1;
|
||||
u32_t crc32=crc32h((unsigned char *)s,len);
|
||||
write_u32(s+len,crc32);
|
||||
len+=sizeof(u32_t);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_cook(char * data,int &len)
|
||||
{
|
||||
put_crc32(data,len);
|
||||
if(!disable_obscure)do_obscure(data,len);
|
||||
if(!disable_xor)encrypt_0(data,len,key_string);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int de_cook(char * s,int &len)
|
||||
{
|
||||
if(!disable_xor)decrypt_0(s,len,key_string);
|
||||
if(!disable_obscure)
|
||||
{
|
||||
int ret=de_obscure(s,len);
|
||||
if(ret!=0)
|
||||
{
|
||||
mylog(log_debug,"de_obscure fail\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
int ret=rm_crc32(s,len);
|
||||
if(ret!=0)
|
||||
{
|
||||
mylog(log_debug,"rm_crc32 fail\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int rm_crc32(char * s,int &len)
|
||||
{
|
||||
if(disable_checksum)return 0;
|
||||
assert(len>=0);
|
||||
len-=sizeof(u32_t);
|
||||
if(len<0) return -1;
|
||||
u32_t crc32_in=read_u32(s+len);
|
||||
u32_t crc32=crc32h((unsigned char *)s,len);
|
||||
if(crc32!=crc32_in) return -1;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int do_obs()
|
||||
{
|
||||
|
||||
}
|
||||
int de_obs()*/
|
||||
int put_conv(u32_t conv,const char * input,int len_in,char *&output,int &len_out)
|
||||
{
|
||||
static char buf[buf_len];
|
||||
output=buf;
|
||||
u32_t n_conv=htonl(conv);
|
||||
memcpy(output,&n_conv,sizeof(n_conv));
|
||||
memcpy(output+sizeof(n_conv),input,len_in);
|
||||
len_out=len_in+(int)(sizeof(n_conv));
|
||||
|
||||
return 0;
|
||||
}
|
||||
int get_conv(u32_t &conv,const char *input,int len_in,char *&output,int &len_out )
|
||||
{
|
||||
u32_t n_conv;
|
||||
memcpy(&n_conv,input,sizeof(n_conv));
|
||||
conv=ntohl(n_conv);
|
||||
output=(char *)input+sizeof(n_conv);
|
||||
len_out=len_in-(int)sizeof(n_conv);
|
||||
if(len_out<0)
|
||||
{
|
||||
mylog(log_debug,"len_out<0\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
47
packet.h
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* packet.h
|
||||
*
|
||||
* Created on: Sep 15, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef PACKET_H_
|
||||
#define PACKET_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "fd_manager.h"
|
||||
|
||||
extern int iv_min;
|
||||
extern int iv_max;//< 256;
|
||||
|
||||
extern u64_t packet_send_count;
|
||||
extern u64_t dup_packet_send_count;
|
||||
extern u64_t packet_recv_count;
|
||||
extern u64_t dup_packet_recv_count;
|
||||
extern char key_string[1000];
|
||||
extern int disable_replay_filter;
|
||||
extern int random_drop;
|
||||
extern int disable_obscure;
|
||||
extern int disable_xor;
|
||||
|
||||
|
||||
int my_send(const dest_t &dest,char *data,int len);
|
||||
|
||||
void encrypt_0(char * input,int &len,char *key);
|
||||
void decrypt_0(char * input,int &len,char *key);
|
||||
int add_seq(char * data,int &data_len );
|
||||
int remove_seq(char * data,int &data_len);
|
||||
int do_obscure(const char * input, int in_len,char *output,int &out_len);
|
||||
int de_obscure(const char * input, int in_len,char *output,int &out_len);
|
||||
|
||||
//int sendto_fd_u64 (int fd,u64_t u64,char * buf, int len,int flags);
|
||||
int sendto_ip_port (u32_t ip,int port,char * buf, int len,int flags);
|
||||
int send_fd (int fd,char * buf, int len,int flags);
|
||||
|
||||
int put_conv(u32_t conv,const char * input,int len_in,char *&output,int &len_out);
|
||||
int get_conv(u32_t &conv,const char *input,int len_in,char *&output,int &len_out );
|
||||
int put_crc32(char * s,int &len);
|
||||
int rm_crc32(char * s,int &len);
|
||||
int do_cook(char * data,int &len);
|
||||
int de_cook(char * s,int &len);
|
||||
#endif /* PACKET_H_ */
|
17
tunnel.h
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
* tunnel.h
|
||||
*
|
||||
* Created on: Oct 26, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#ifndef TUNNEL_H_
|
||||
#define TUNNEL_H_
|
||||
|
||||
|
||||
#include "misc.h"
|
||||
|
||||
int tunnel_client_event_loop();
|
||||
int tunnel_server_event_loop();
|
||||
|
||||
#endif /* TUNNEL_H_ */
|
@@ -1,439 +0,0 @@
|
||||
#include "tunnel.h"
|
||||
|
||||
void data_from_local_or_fec_timeout(conn_info_t & conn_info,int is_time_out)
|
||||
{
|
||||
fd64_t &remote_fd64=conn_info.remote_fd64;
|
||||
int & local_listen_fd=conn_info.local_listen_fd;
|
||||
|
||||
char data[buf_len];
|
||||
int data_len;
|
||||
address_t addr;
|
||||
u32_t conv;
|
||||
int out_n;char **out_arr;int *out_len;my_time_t *out_delay;
|
||||
dest_t dest;
|
||||
dest.type=type_fd64;
|
||||
dest.inner.fd64=remote_fd64;
|
||||
dest.cook=1;
|
||||
|
||||
if(is_time_out)
|
||||
{
|
||||
//fd64_t fd64=events[idx].data.u64;
|
||||
mylog(log_trace,"events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64()\n");
|
||||
|
||||
//uint64_t value;
|
||||
//if(!fd_manager.exist(fd64)) //fd64 has been closed
|
||||
//{
|
||||
// mylog(log_trace,"!fd_manager.exist(fd64)");
|
||||
// continue;
|
||||
//}
|
||||
//if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8)
|
||||
//{
|
||||
// mylog(log_trace,"(ret=read(fd_manager.to_fd(fd64), &value, 8))!=8,ret=%d\n",ret);
|
||||
// continue;
|
||||
//}
|
||||
//if(value==0)
|
||||
//{
|
||||
// mylog(log_debug,"value==0\n");
|
||||
// continue;
|
||||
//}
|
||||
//assert(value==1);
|
||||
from_normal_to_fec(conn_info,0,0,out_n,out_arr,out_len,out_delay);
|
||||
}
|
||||
else//events[idx].data.u64 == (u64_t)local_listen_fd
|
||||
{
|
||||
mylog(log_trace,"events[idx].data.u64 == (u64_t)local_listen_fd\n");
|
||||
address_t::storage_t udp_new_addr_in={0};
|
||||
socklen_t udp_new_addr_len = sizeof(address_t::storage_t);
|
||||
if ((data_len = recvfrom(local_listen_fd, data, max_data_len, 0,
|
||||
(struct sockaddr *) &udp_new_addr_in, &udp_new_addr_len)) == -1) {
|
||||
mylog(log_debug,"recv_from error,this shouldnt happen,err=%s,but we can try to continue\n",get_sock_error());
|
||||
return;
|
||||
};
|
||||
|
||||
if(!disable_mtu_warn&&data_len>=mtu_warn)
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",data_len,mtu_warn);
|
||||
}
|
||||
|
||||
|
||||
addr.from_sockaddr((struct sockaddr *) &udp_new_addr_in,udp_new_addr_len);
|
||||
|
||||
mylog(log_trace,"Received packet from %s, len: %d\n", addr.get_str(),data_len);
|
||||
|
||||
//u64_t u64=ip_port.to_u64();
|
||||
|
||||
if(!conn_info.conv_manager.c.is_data_used(addr))
|
||||
{
|
||||
if(conn_info.conv_manager.c.get_size() >=max_conv_num)
|
||||
{
|
||||
mylog(log_warn,"ignored new udp connect bc max_conv_num exceed\n");
|
||||
return;
|
||||
}
|
||||
conv=conn_info.conv_manager.c.get_new_conv();
|
||||
conn_info.conv_manager.c.insert_conv(conv,addr);
|
||||
mylog(log_info,"new packet from %s,conv_id=%x\n",addr.get_str(),conv);
|
||||
}
|
||||
else
|
||||
{
|
||||
conv=conn_info.conv_manager.c.find_conv_by_data(addr);
|
||||
mylog(log_trace,"conv=%d\n",conv);
|
||||
}
|
||||
conn_info.conv_manager.c.update_active_time(conv);
|
||||
char * new_data;
|
||||
int new_len;
|
||||
put_conv(conv,data,data_len,new_data,new_len);
|
||||
|
||||
|
||||
mylog(log_trace,"data_len=%d new_len=%d\n",data_len,new_len);
|
||||
from_normal_to_fec(conn_info,new_data,new_len,out_n,out_arr,out_len,out_delay);
|
||||
|
||||
}
|
||||
mylog(log_trace,"out_n=%d\n",out_n);
|
||||
for(int i=0;i<out_n;i++)
|
||||
{
|
||||
delay_send(out_delay[i],dest,out_arr[i],out_len[i]);
|
||||
}
|
||||
}
|
||||
static void local_listen_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
data_from_local_or_fec_timeout(conn_info,0);
|
||||
}
|
||||
|
||||
static void remote_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
char data[buf_len];
|
||||
if(!fd_manager.exist(watcher->u64)) //fd64 has been closed
|
||||
{
|
||||
mylog(log_trace,"!fd_manager.exist(events[idx].data.u64)");
|
||||
return;
|
||||
}
|
||||
fd64_t &remote_fd64=conn_info.remote_fd64;
|
||||
int &remote_fd=conn_info.remote_fd;
|
||||
|
||||
assert(watcher->u64==remote_fd64);
|
||||
|
||||
int fd=fd_manager.to_fd(remote_fd64);
|
||||
|
||||
int data_len =recv(fd,data,max_data_len,0);
|
||||
mylog(log_trace, "received data from udp fd %d, len=%d\n", remote_fd,data_len);
|
||||
if(data_len<0)
|
||||
{
|
||||
if(get_sock_errno()==ECONNREFUSED)
|
||||
{
|
||||
mylog(log_debug, "recv failed %d ,udp_fd%d,errno:%s\n", data_len,remote_fd,get_sock_error());
|
||||
}
|
||||
|
||||
mylog(log_warn, "recv failed %d ,udp_fd%d,errno:%s\n", data_len,remote_fd,get_sock_error());
|
||||
return;
|
||||
}
|
||||
if(!disable_mtu_warn&&data_len>mtu_warn)
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",data_len,mtu_warn);
|
||||
}
|
||||
|
||||
if(de_cook(data,data_len)!=0)
|
||||
{
|
||||
mylog(log_debug,"de_cook error");
|
||||
return;
|
||||
}
|
||||
|
||||
int out_n;char **out_arr;int *out_len;my_time_t *out_delay;
|
||||
from_fec_to_normal(conn_info,data,data_len,out_n,out_arr,out_len,out_delay);
|
||||
|
||||
mylog(log_trace,"out_n=%d\n",out_n);
|
||||
|
||||
for(int i=0;i<out_n;i++)
|
||||
{
|
||||
u32_t conv;
|
||||
char *new_data;
|
||||
int new_len;
|
||||
if(get_conv(conv,out_arr[i],out_len[i],new_data,new_len)!=0)
|
||||
{
|
||||
mylog(log_debug,"get_conv(conv,out_arr[i],out_len[i],new_data,new_len)!=0");
|
||||
continue;
|
||||
}
|
||||
if(!conn_info.conv_manager.c.is_conv_used(conv))
|
||||
{
|
||||
mylog(log_trace,"!conn_info.conv_manager.is_conv_used(conv)");
|
||||
continue;
|
||||
}
|
||||
|
||||
conn_info.conv_manager.c.update_active_time(conv);
|
||||
|
||||
address_t addr=conn_info.conv_manager.c.find_data_by_conv(conv);
|
||||
dest_t dest;
|
||||
dest.inner.fd_addr.fd=conn_info.local_listen_fd;
|
||||
dest.inner.fd_addr.addr=addr;
|
||||
dest.type=type_fd_addr;
|
||||
|
||||
delay_send(out_delay[i],dest,new_data,new_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
int fifo_fd=watcher->fd;
|
||||
|
||||
char buf[buf_len];
|
||||
int len=read (fifo_fd, buf, sizeof (buf));
|
||||
if(len<0)
|
||||
{
|
||||
mylog(log_warn,"fifo read failed len=%d,errno=%s\n",len,get_sock_error());
|
||||
return;
|
||||
}
|
||||
buf[len]=0;
|
||||
handle_command(buf);
|
||||
}
|
||||
|
||||
static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
//uint64_t value;
|
||||
//read(delay_manager.get_timer_fd(), &value, 8);
|
||||
//mylog(log_trace,"events[idx].data.u64 == (u64_t)delay_manager.get_timer_fd()\n");
|
||||
|
||||
//do nothing
|
||||
}
|
||||
|
||||
static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
data_from_local_or_fec_timeout(conn_info,1);
|
||||
|
||||
}
|
||||
|
||||
static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
uint64_t value;
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
//read(conn_info.timer.get_timer_fd(), &value, 8);
|
||||
conn_info.conv_manager.c.clear_inactive();
|
||||
mylog(log_trace,"events[idx].data.u64==(u64_t)conn_info.timer.get_timer_fd()\n");
|
||||
|
||||
conn_info.stat.report_as_client();
|
||||
|
||||
if(debug_force_flush_fec)
|
||||
{
|
||||
int out_n;char **out_arr;int *out_len;my_time_t *out_delay;
|
||||
dest_t dest;
|
||||
dest.type=type_fd64;
|
||||
dest.inner.fd64=conn_info.remote_fd64;
|
||||
dest.cook=1;
|
||||
from_normal_to_fec(conn_info,0,0,out_n,out_arr,out_len,out_delay);
|
||||
for(int i=0;i<out_n;i++)
|
||||
{
|
||||
delay_send(out_delay[i],dest,out_arr[i],out_len[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
delay_manager.check();
|
||||
}
|
||||
|
||||
int tunnel_client_event_loop()
|
||||
{
|
||||
int i, j, k;int ret;
|
||||
int yes = 1;
|
||||
//int epoll_fd;
|
||||
|
||||
|
||||
conn_info_t *conn_info_p=new conn_info_t;
|
||||
conn_info_t &conn_info=*conn_info_p; //huge size of conn_info,do not allocate on stack
|
||||
|
||||
int &local_listen_fd=conn_info.local_listen_fd;
|
||||
new_listen_socket2(local_listen_fd,local_addr);
|
||||
|
||||
//epoll_fd = epoll_create1(0);
|
||||
//assert(epoll_fd>0);
|
||||
|
||||
//const int max_events = 4096;
|
||||
//struct epoll_event ev, events[max_events];
|
||||
//if (epoll_fd < 0) {
|
||||
// mylog(log_fatal,"epoll return %d\n", epoll_fd);
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
struct ev_loop * loop= ev_default_loop(0);
|
||||
assert(loop != NULL);
|
||||
|
||||
conn_info.loop=loop;
|
||||
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = local_listen_fd;
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, local_listen_fd, &ev);
|
||||
//if (ret!=0) {
|
||||
// mylog(log_fatal,"add udp_listen_fd error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
struct ev_io local_listen_watcher;
|
||||
local_listen_watcher.data=&conn_info;
|
||||
|
||||
ev_io_init(&local_listen_watcher, local_listen_cb, local_listen_fd, EV_READ);
|
||||
ev_io_start(loop, &local_listen_watcher);
|
||||
|
||||
int & remote_fd=conn_info.remote_fd;
|
||||
fd64_t &remote_fd64=conn_info.remote_fd64;
|
||||
|
||||
assert(new_connected_socket2(remote_fd,remote_addr,out_addr,out_interface)==0);
|
||||
remote_fd64=fd_manager.create(remote_fd);
|
||||
|
||||
mylog(log_debug,"remote_fd64=%llu\n",remote_fd64);
|
||||
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = remote_fd64;
|
||||
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, remote_fd, &ev);
|
||||
//if (ret!= 0) {
|
||||
// mylog(log_fatal,"add raw_fd error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
struct ev_io remote_watcher;
|
||||
remote_watcher.data=&conn_info;
|
||||
remote_watcher.u64=remote_fd64;
|
||||
|
||||
ev_io_init(&remote_watcher, remote_cb, remote_fd, EV_READ);
|
||||
ev_io_start(loop, &remote_watcher);
|
||||
|
||||
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = delay_manager.get_timer_fd();
|
||||
|
||||
//mylog(log_debug,"delay_manager.get_timer_fd()=%d\n",delay_manager.get_timer_fd());
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev);
|
||||
//if (ret!= 0) {
|
||||
// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
delay_manager.set_loop_and_cb(loop,delay_manager_cb);
|
||||
|
||||
conn_info.fec_encode_manager.set_data(&conn_info);
|
||||
conn_info.fec_encode_manager.set_loop_and_cb(loop,fec_encode_cb);
|
||||
|
||||
//u64_t tmp_fd64=conn_info.fec_encode_manager.get_timer_fd64();
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = tmp_fd64;
|
||||
|
||||
//mylog(log_debug,"conn_info.fec_encode_manager.get_timer_fd64()=%llu\n",conn_info.fec_encode_manager.get_timer_fd64());
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(tmp_fd64), &ev);
|
||||
//if (ret!= 0) {
|
||||
// mylog(log_fatal,"add fec_encode_manager.get_timer_fd64() error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
conn_info.timer.data=&conn_info;
|
||||
ev_init(&conn_info.timer,conn_timer_cb);
|
||||
ev_timer_set(&conn_info.timer, 0, timer_interval/1000.0 );
|
||||
ev_timer_start(loop,&conn_info.timer);
|
||||
//conn_info.timer.add_fd_to_epoll(epoll_fd);
|
||||
//conn_info.timer.set_timer_repeat_us(timer_interval*1000);
|
||||
|
||||
//mylog(log_debug,"conn_info.timer.get_timer_fd()=%d\n",conn_info.timer.get_timer_fd());
|
||||
|
||||
|
||||
|
||||
|
||||
struct ev_io fifo_watcher;
|
||||
|
||||
int fifo_fd=-1;
|
||||
|
||||
if(fifo_file[0]!=0)
|
||||
{
|
||||
fifo_fd=create_fifo(fifo_file);
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = fifo_fd;
|
||||
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fifo_fd, &ev);
|
||||
//if (ret!= 0) {
|
||||
// mylog(log_fatal,"add fifo_fd to epoll error %s\n",strerror(errno));
|
||||
// myexit(-1);
|
||||
//}
|
||||
mylog(log_info,"fifo_file=%s\n",fifo_file);
|
||||
|
||||
ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ);
|
||||
ev_io_start(loop, &fifo_watcher);
|
||||
|
||||
}
|
||||
|
||||
ev_prepare prepare_watcher;
|
||||
ev_init(&prepare_watcher,prepare_cb);
|
||||
ev_prepare_start(loop,&prepare_watcher);
|
||||
|
||||
mylog(log_info,"now listening at %s\n",local_addr.get_str());
|
||||
|
||||
ev_run(loop, 0);
|
||||
|
||||
mylog(log_warn,"ev_run returned\n");
|
||||
myexit(0);
|
||||
|
||||
/*
|
||||
while(1)////////////////////////
|
||||
{
|
||||
if(about_to_exit) myexit(0);
|
||||
|
||||
int nfds = epoll_wait(epoll_fd, events, max_events, 180 * 1000);
|
||||
if (nfds < 0) { //allow zero
|
||||
if(errno==EINTR )
|
||||
{
|
||||
mylog(log_info,"epoll interrupted by signal continue\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog(log_fatal,"epoll_wait return %d,%s\n", nfds,strerror(errno));
|
||||
myexit(-1);
|
||||
}
|
||||
}
|
||||
int idx;
|
||||
for (idx = 0; idx < nfds; ++idx) {
|
||||
if(events[idx].data.u64==(u64_t)conn_info.timer.get_timer_fd())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
else if (events[idx].data.u64 == (u64_t)fifo_fd)
|
||||
{
|
||||
|
||||
}
|
||||
else if (events[idx].data.u64 == (u64_t)local_listen_fd||events[idx].data.u64 == conn_info.fec_encode_manager.get_timer_fd64())
|
||||
{
|
||||
|
||||
}
|
||||
else if (events[idx].data.u64 == (u64_t)delay_manager.get_timer_fd()) {
|
||||
|
||||
}
|
||||
else if(events[idx].data.u64>u32_t(-1) )
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog(log_fatal,"unknown fd,this should never happen\n");
|
||||
myexit(-1);
|
||||
}
|
||||
}
|
||||
//delay_manager.check();
|
||||
}*/
|
||||
return 0;
|
||||
}
|
@@ -1,491 +0,0 @@
|
||||
/*
|
||||
* tunnel.cpp
|
||||
*
|
||||
* Created on: Oct 26, 2017
|
||||
* Author: root
|
||||
*/
|
||||
|
||||
#include "tunnel.h"
|
||||
|
||||
static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents);
|
||||
static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents);
|
||||
static void remote_cb(struct ev_loop *loop, struct ev_io *watcher, int revents);
|
||||
|
||||
enum tmp_mode_t{is_from_remote=0,is_fec_timeout,is_conn_timer};
|
||||
|
||||
void data_from_remote_or_fec_timeout_or_conn_timer(conn_info_t & conn_info,fd64_t fd64,tmp_mode_t mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
char data[buf_len];
|
||||
int data_len;
|
||||
u32_t conv;
|
||||
//fd64_t fd64=events[idx].data.u64;
|
||||
//mylog(log_trace,"events[idx].data.u64 >u32_t(-1),%llu\n",(u64_t)events[idx].data.u64);
|
||||
|
||||
|
||||
//assert(fd_manager.exist_info(fd64));
|
||||
//ip_port_t ip_port=fd_manager.get_info(fd64).ip_port;
|
||||
|
||||
|
||||
//conn_info_t &conn_info=conn_manager.find(ip_port);
|
||||
address_t &addr=conn_info.addr;
|
||||
assert(conn_manager.exist(addr));
|
||||
|
||||
int &local_listen_fd=conn_info.local_listen_fd;
|
||||
|
||||
int out_n=-2;char **out_arr;int *out_len;my_time_t *out_delay;
|
||||
|
||||
dest_t dest;
|
||||
dest.inner.fd_addr.fd=local_listen_fd;
|
||||
dest.inner.fd_addr.addr=addr;
|
||||
dest.type=type_fd_addr;
|
||||
dest.cook=1;
|
||||
|
||||
if(mode==is_fec_timeout)
|
||||
{
|
||||
assert(fd64==0);
|
||||
//uint64_t value;
|
||||
//if((ret=read(fd_manager.to_fd(fd64), &value, 8))!=8)
|
||||
//{
|
||||
// mylog(log_trace,"fd_manager.to_fd(fd64), &value, 8)!=8 ,%d\n",ret);
|
||||
// continue;
|
||||
//}
|
||||
//if(value==0)
|
||||
//{
|
||||
// mylog(log_trace,"value==0\n");
|
||||
// continue;
|
||||
//}
|
||||
//assert(value==1);
|
||||
from_normal_to_fec(conn_info,0,0,out_n,out_arr,out_len,out_delay);
|
||||
}
|
||||
else if(mode==is_conn_timer)
|
||||
{
|
||||
assert(fd64==0);
|
||||
//uint64_t value;
|
||||
//read(conn_info.timer.get_timer_fd(), &value, 8);
|
||||
conn_info.conv_manager.s.clear_inactive();
|
||||
if(debug_force_flush_fec)
|
||||
{
|
||||
from_normal_to_fec(conn_info,0,0,out_n,out_arr,out_len,out_delay);
|
||||
}
|
||||
|
||||
conn_info.stat.report_as_server(addr);
|
||||
return;
|
||||
}
|
||||
else if(mode==is_from_remote)
|
||||
{
|
||||
if(!fd_manager.exist(fd64)) //fd64 has been closed
|
||||
{
|
||||
mylog(log_warn,"!fd_manager.exist(fd64)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//fd64_t &fd64 =conn_info.remote_fd64;
|
||||
assert(conn_info.conv_manager.s.is_data_used(fd64));
|
||||
|
||||
conv=conn_info.conv_manager.s.find_conv_by_data(fd64);
|
||||
conn_info.conv_manager.s.update_active_time(conv);
|
||||
conn_info.update_active_time();
|
||||
|
||||
int fd=fd_manager.to_fd(fd64);
|
||||
data_len=recv(fd,data,max_data_len,0);
|
||||
|
||||
mylog(log_trace,"received a packet from udp_fd,len:%d,conv=%d\n",data_len,conv);
|
||||
|
||||
if(data_len<0)
|
||||
{
|
||||
mylog(log_debug,"udp fd,recv_len<0 continue,%s\n",get_sock_error());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!disable_mtu_warn&&data_len>=mtu_warn)
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",data_len,mtu_warn);
|
||||
}
|
||||
|
||||
char * new_data;
|
||||
int new_len;
|
||||
put_conv(conv,data,data_len,new_data,new_len);
|
||||
|
||||
from_normal_to_fec(conn_info,new_data,new_len,out_n,out_arr,out_len,out_delay);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0==1);
|
||||
}
|
||||
|
||||
mylog(log_trace,"out_n=%d\n",out_n);
|
||||
for(int i=0;i<out_n;i++)
|
||||
{
|
||||
delay_send(out_delay[i],dest,out_arr[i],out_len[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void local_listen_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
int local_listen_fd=watcher->fd;
|
||||
int ret;
|
||||
|
||||
mylog(log_trace,"events[idx].data.u64 == (u64_t)local_listen_fd\n");
|
||||
char data[buf_len];
|
||||
int data_len;
|
||||
address_t::storage_t udp_new_addr_in={0};
|
||||
socklen_t udp_new_addr_len = sizeof(address_t::storage_t);
|
||||
if ((data_len = recvfrom(local_listen_fd, data, max_data_len, 0,
|
||||
(struct sockaddr *) &udp_new_addr_in, &udp_new_addr_len)) == -1) {
|
||||
mylog(log_error,"recv_from error,this shouldnt happen,err=%s,but we can try to continue\n",get_sock_error());
|
||||
return;
|
||||
};
|
||||
|
||||
address_t addr;
|
||||
addr.from_sockaddr((struct sockaddr *) &udp_new_addr_in,udp_new_addr_len);
|
||||
|
||||
mylog(log_trace,"Received packet from %s,len: %d\n", addr.get_str(),data_len);
|
||||
|
||||
if(!disable_mtu_warn&&data_len>=mtu_warn)///////////////////////delete this for type 0 in furture
|
||||
{
|
||||
mylog(log_warn,"huge packet,data len=%d (>=%d).strongly suggested to set a smaller mtu at upper level,to get rid of this warn\n ",data_len,mtu_warn);
|
||||
}
|
||||
|
||||
|
||||
if(de_cook(data,data_len)!=0)
|
||||
{
|
||||
mylog(log_debug,"de_cook error");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(!conn_manager.exist(addr))
|
||||
{
|
||||
if(conn_manager.mp.size() >=max_conn_num)
|
||||
{
|
||||
mylog(log_warn,"new connection %s ignored bc max_conn_num exceed\n",addr.get_str());
|
||||
return;
|
||||
}
|
||||
|
||||
//conn_manager.insert(addr);
|
||||
conn_info_t &conn_info=conn_manager.find_insert(addr);
|
||||
conn_info.addr=addr;
|
||||
conn_info.loop=ev_default_loop(0);
|
||||
conn_info.local_listen_fd=local_listen_fd;
|
||||
|
||||
//u64_t fec_fd64=conn_info.fec_encode_manager.get_timer_fd64();
|
||||
//mylog(log_debug,"fec_fd64=%llu\n",fec_fd64);
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = fec_fd64;
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd_manager.to_fd(fec_fd64), &ev);
|
||||
|
||||
//fd_manager.get_info(fec_fd64).ip_port=ip_port;
|
||||
|
||||
conn_info.timer.data=&conn_info;
|
||||
ev_init(&conn_info.timer,conn_timer_cb);
|
||||
ev_timer_set(&conn_info.timer, 0, timer_interval/1000.0 );
|
||||
ev_timer_start(loop,&conn_info.timer);
|
||||
|
||||
//conn_info.timer.add_fd64_to_epoll(epoll_fd);
|
||||
//conn_info.timer.set_timer_repeat_us(timer_interval*1000);
|
||||
|
||||
//mylog(log_debug,"conn_info.timer.get_timer_fd64()=%llu\n",conn_info.timer.get_timer_fd64());
|
||||
|
||||
//u64_t timer_fd64=conn_info.timer.get_timer_fd64();
|
||||
//fd_manager.get_info(timer_fd64).ip_port=ip_port;
|
||||
|
||||
|
||||
|
||||
conn_info.fec_encode_manager.set_data(&conn_info);
|
||||
conn_info.fec_encode_manager.set_loop_and_cb(loop,fec_encode_cb);
|
||||
|
||||
|
||||
mylog(log_info,"new connection from %s\n",addr.get_str());
|
||||
|
||||
}
|
||||
conn_info_t &conn_info=conn_manager.find_insert(addr);
|
||||
|
||||
conn_info.update_active_time();
|
||||
int out_n;char **out_arr;int *out_len;my_time_t *out_delay;
|
||||
from_fec_to_normal(conn_info,data,data_len,out_n,out_arr,out_len,out_delay);
|
||||
|
||||
mylog(log_trace,"out_n= %d\n",out_n);
|
||||
for(int i=0;i<out_n;i++)
|
||||
{
|
||||
u32_t conv;
|
||||
char *new_data;
|
||||
int new_len;
|
||||
if(get_conv(conv,out_arr[i],out_len[i],new_data,new_len)!=0)
|
||||
{
|
||||
mylog(log_debug,"get_conv failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!conn_info.conv_manager.s.is_conv_used(conv))
|
||||
{
|
||||
if(conn_info.conv_manager.s.get_size() >=max_conv_num)
|
||||
{
|
||||
mylog(log_warn,"ignored new udp connect bc max_conv_num exceed\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int new_udp_fd;
|
||||
ret=new_connected_socket2(new_udp_fd,remote_addr,out_addr,out_interface);
|
||||
|
||||
if (ret != 0) {
|
||||
mylog(log_warn, "[%s]new_connected_socket failed\n",addr.get_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
fd64_t fd64 = fd_manager.create(new_udp_fd);
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = fd64;
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_udp_fd, &ev);
|
||||
|
||||
conn_info.conv_manager.s.insert_conv(conv, fd64);
|
||||
fd_manager.get_info(fd64).addr=addr;
|
||||
|
||||
ev_io &io_watcher=fd_manager.get_info(fd64).io_watcher;
|
||||
io_watcher.u64=fd64;
|
||||
io_watcher.data=&conn_info;
|
||||
|
||||
ev_init(&io_watcher,remote_cb);
|
||||
ev_io_set(&io_watcher,new_udp_fd,EV_READ);
|
||||
ev_io_start(conn_info.loop,&io_watcher);
|
||||
|
||||
|
||||
mylog(log_info,"[%s]new conv %x,fd %d created,fd64=%llu\n",addr.get_str(),conv,new_udp_fd,fd64);
|
||||
}
|
||||
conn_info.conv_manager.s.update_active_time(conv);
|
||||
fd64_t fd64= conn_info.conv_manager.s.find_data_by_conv(conv);
|
||||
dest_t dest;
|
||||
dest.type=type_fd64;
|
||||
dest.inner.fd64=fd64;
|
||||
delay_send(out_delay[i],dest,new_data,new_len);
|
||||
}
|
||||
}
|
||||
|
||||
static void remote_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
fd64_t fd64=watcher->u64;
|
||||
|
||||
data_from_remote_or_fec_timeout_or_conn_timer(conn_info,fd64,is_from_remote);
|
||||
}
|
||||
|
||||
static void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
int fifo_fd=watcher->fd;
|
||||
|
||||
char buf[buf_len];
|
||||
int len=read (fifo_fd, buf, sizeof (buf));
|
||||
if(len<0)
|
||||
{
|
||||
mylog(log_warn,"fifo read failed len=%d,errno=%s\n",len,get_sock_error());
|
||||
return;
|
||||
}
|
||||
buf[len]=0;
|
||||
handle_command(buf);
|
||||
}
|
||||
|
||||
static void delay_manager_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
//uint64_t value;
|
||||
//read(delay_manager.get_timer_fd(), &value, 8);
|
||||
//mylog(log_trace,"events[idx].data.u64 == (u64_t)delay_manager.get_timer_fd()\n");
|
||||
|
||||
//do nothing
|
||||
|
||||
}
|
||||
|
||||
static void fec_encode_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
data_from_remote_or_fec_timeout_or_conn_timer(conn_info,0,is_fec_timeout);
|
||||
}
|
||||
|
||||
static void conn_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
conn_info_t & conn_info= *((conn_info_t*)watcher->data);
|
||||
|
||||
data_from_remote_or_fec_timeout_or_conn_timer(conn_info,0,is_conn_timer);
|
||||
}
|
||||
|
||||
static void prepare_cb(struct ev_loop *loop, struct ev_prepare *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
delay_manager.check();
|
||||
}
|
||||
|
||||
static void global_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents)
|
||||
{
|
||||
assert(!(revents&EV_ERROR));
|
||||
|
||||
//uint64_t value;
|
||||
//read(timer.get_timer_fd(), &value, 8);
|
||||
conn_manager.clear_inactive();
|
||||
mylog(log_trace,"events[idx].data.u64==(u64_t)timer.get_timer_fd()\n");
|
||||
}
|
||||
|
||||
int tunnel_server_event_loop()
|
||||
{
|
||||
|
||||
int i, j, k;int ret;
|
||||
int yes = 1;
|
||||
//int epoll_fd;
|
||||
//int remote_fd;
|
||||
|
||||
int local_listen_fd;
|
||||
new_listen_socket2(local_listen_fd,local_addr);
|
||||
|
||||
//epoll_fd = epoll_create1(0);
|
||||
//assert(epoll_fd>0);
|
||||
|
||||
//const int max_events = 4096;
|
||||
//struct epoll_event ev, events[max_events];
|
||||
//if (epoll_fd < 0) {
|
||||
// mylog(log_fatal,"epoll return %d\n", epoll_fd);
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
struct ev_loop * loop= ev_default_loop(0);
|
||||
assert(loop != NULL);
|
||||
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = local_listen_fd;
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, local_listen_fd, &ev);
|
||||
//if (ret!=0) {
|
||||
// mylog(log_fatal,"add udp_listen_fd error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
struct ev_io local_listen_watcher;
|
||||
ev_io_init(&local_listen_watcher, local_listen_cb, local_listen_fd, EV_READ);
|
||||
ev_io_start(loop, &local_listen_watcher);
|
||||
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = delay_manager.get_timer_fd();
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, delay_manager.get_timer_fd(), &ev);
|
||||
//if (ret!= 0) {
|
||||
// mylog(log_fatal,"add delay_manager.get_timer_fd() error\n");
|
||||
// myexit(-1);
|
||||
//}
|
||||
|
||||
delay_manager.set_loop_and_cb(loop,delay_manager_cb);
|
||||
|
||||
//mylog(log_debug," delay_manager.get_timer_fd() =%d\n", delay_manager.get_timer_fd());
|
||||
|
||||
mylog(log_info,"now listening at %s\n",local_addr.get_str());
|
||||
|
||||
//my_timer_t timer;
|
||||
//timer.add_fd_to_epoll(epoll_fd);
|
||||
//timer.set_timer_repeat_us(timer_interval*1000);
|
||||
|
||||
ev_timer global_timer;
|
||||
ev_init(&global_timer,global_timer_cb);
|
||||
ev_timer_set(&global_timer, 0, timer_interval/1000.0 );
|
||||
ev_timer_start(loop,&global_timer);
|
||||
|
||||
//mylog(log_debug," timer.get_timer_fd() =%d\n",timer.get_timer_fd());
|
||||
|
||||
struct ev_io fifo_watcher;
|
||||
|
||||
int fifo_fd=-1;
|
||||
|
||||
if(fifo_file[0]!=0)
|
||||
{
|
||||
fifo_fd=create_fifo(fifo_file);
|
||||
//ev.events = EPOLLIN;
|
||||
//ev.data.u64 = fifo_fd;
|
||||
|
||||
//ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fifo_fd, &ev);
|
||||
//if (ret!= 0) {
|
||||
//mylog(log_fatal,"add fifo_fd to epoll error %s\n",strerror(errno));
|
||||
//myexit(-1);
|
||||
//}
|
||||
ev_io_init(&fifo_watcher, fifo_cb, fifo_fd, EV_READ);
|
||||
ev_io_start(loop, &fifo_watcher);
|
||||
|
||||
mylog(log_info,"fifo_file=%s\n",fifo_file);
|
||||
}
|
||||
|
||||
ev_prepare prepare_watcher;
|
||||
ev_init(&prepare_watcher,prepare_cb);
|
||||
ev_prepare_start(loop,&prepare_watcher);
|
||||
|
||||
|
||||
ev_run(loop, 0);
|
||||
|
||||
mylog(log_warn,"ev_run returned\n");
|
||||
myexit(0);
|
||||
|
||||
/*
|
||||
while(1)////////////////////////
|
||||
{
|
||||
|
||||
if(about_to_exit) myexit(0);
|
||||
|
||||
int nfds = epoll_wait(epoll_fd, events, max_events, 180 * 1000);
|
||||
if (nfds < 0) { //allow zero
|
||||
if(errno==EINTR )
|
||||
{
|
||||
mylog(log_info,"epoll interrupted by signal,continue\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog(log_fatal,"epoll_wait return %d,%s\n", nfds,strerror(errno));
|
||||
myexit(-1);
|
||||
}
|
||||
}
|
||||
int idx;
|
||||
for (idx = 0; idx < nfds; ++idx)
|
||||
{
|
||||
if(events[idx].data.u64==(u64_t)timer.get_timer_fd())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
else if (events[idx].data.u64 == (u64_t)fifo_fd)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
else if (events[idx].data.u64 == (u64_t)local_listen_fd)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
else if (events[idx].data.u64 == (u64_t)delay_manager.get_timer_fd()) {
|
||||
|
||||
}
|
||||
else if (events[idx].data.u64 >u32_t(-1))
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mylog(log_fatal,"unknown fd,this should never happen\n");
|
||||
myexit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
}
|