Compare commits

...

85 Commits

Author SHA1 Message Date
yancey
4623f878e0 fix cipher bug 2024-06-10 05:22:12 -04:00
Yancey Wang
e42f0e5732
Update README.md 2023-11-15 15:15:46 -05:00
yancey
f49e6adedf remove Dockerfile 2023-11-06 03:19:46 -05:00
yancey
d1a9bcc4fb try to fix linux 6.5 compile 2023-10-07 08:26:10 -04:00
Yancey Wang
bc8bd8c2f8
Merge pull request #475 from gek64/unified
Fix compile errors on FreeBSD/pfSense/OPNsense
2023-09-21 16:35:45 -04:00
gek64
ca16c3a5e6
Merge branch 'wangyu-:unified' into unified 2023-07-27 21:10:28 +08:00
Yancey Wang
7abe19c7d9
Merge pull request #482 from wangyu-/revert-455-unified
Revert "fix CMakeLists.txt"
2023-07-22 17:31:10 -04:00
Yancey Wang
f3f528e866
Revert "fix CMakeLists.txt" 2023-07-22 17:30:56 -04:00
Yancey Wang
ec6fad552b
Merge pull request #455 from HiGarfield/unified
fix CMakeLists.txt
2023-07-22 17:09:53 -04:00
yancey
87b878a09e fix stack-use-after-scope reported by sanitizer 2023-07-22 14:31:17 -04:00
yancey
e66eddd1d5 fix mem access problem reported by sanitizer 2023-07-22 14:00:03 -04:00
gek64
ec416515f3
Fix compile errors on freebsd 2023-06-14 16:26:10 +08:00
Yancey Wang
d12e540830
Update CMakeLists.txt 2023-06-04 21:44:44 -04:00
Yancey Wang
e7eecc8ef2
Update ISSUE_TEMPLATE.md 2023-05-10 00:08:00 -04:00
HiGarfield
82ba4f7d1b fix CMakeLists.txt 2023-02-09 01:23:51 +08:00
yancey
e5ecd33ec4 add .clang-format 2023-02-07 07:12:02 -05:00
yancey
9217e0e9e6 fix indent with clang-format 2023-02-07 07:11:49 -05:00
yancey
87b0db8862 add cmake 2023-02-07 07:02:13 -05:00
Yancey Wang
8ceaf27eda
Merge pull request #409 from brlin-tw/patch-2
fix typo (stabilization)
2022-01-26 00:59:47 -05:00
Yancey Wang
9f9e8caff6
Merge pull request #408 from brlin-tw/patch-1
fix typo (facktcp -> faketcp)
2022-01-26 00:59:25 -05:00
Yancey Wang
74f3eb90a7
Update README.md 2021-12-09 09:26:32 -05:00
林博仁(Buo-ren, Lin)
38286d5c5b
fix typo (stabilization)
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2021-09-14 00:54:21 +08:00
林博仁(Buo-ren, Lin)
ec849322d7
fix typo (facktcp -> faketcp)
Signed-off-by: 林博仁(Buo-ren, Lin) <Buo.Ren.Lin@gmail.com>
2021-09-14 00:34:07 +08:00
wangyu
b98a467eed fix source argument is the same as destination 2021-03-11 00:45:26 -05:00
wangyu
25d3323427 fix mp compile; fix tcp option bug 2021-02-17 16:58:32 -05:00
wangyu
b8e9095135 add --fix-gro reminder 2021-01-11 05:58:31 -05:00
wangyu
026f97687a fix packet_header->caplen <= max_data_len in network.cpp 2021-01-09 05:10:12 -05:00
wangyu-
f2f90a9a15
Update ISSUE_TEMPLATE.md 2020-09-20 05:16:05 -04:00
wangyu-
cf23f4d656
Update ISSUE_TEMPLATE.md 2020-09-20 05:12:33 -04:00
wangyu
59819db2dd do not quit when got pcap error 2020-08-27 00:32:07 -04:00
wangyu
cc6ea766c4 update makefile 2020-08-18 03:19:18 -04:00
wangyu
509156fc14 change toochain for arm x86 x64 2020-08-17 19:48:23 -04:00
wangyu
cb9059bf3b update readme.md 2020-08-17 18:26:20 -04:00
wangyu
07e2e695a6 put version.txt into release_mp 2020-07-27 11:33:26 -04:00
root
e8daf7c263 more fix of memory access 2020-07-26 19:07:17 +00:00
root
5f907e32d7 fix bad memorry access 2020-07-26 18:15:27 +00:00
wangyu
0e37c1fea4 fix macro in 5a51248cb05 2020-07-15 19:32:14 -04:00
wangyu
606bbec351 add missed file 2020-07-15 17:23:17 -04:00
Kevin Darbyshire-Bryant
3fc23f5cf6 Fix devices and available typos
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2020-07-15 17:06:36 -04:00
Kevin Darbyshire-Bryant
f3c8f70f47 fix missing braces warning
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
2020-07-15 17:02:21 -04:00
wangyu
6c27502757 unified makefile 2020-07-15 16:46:45 -04:00
wangyu
5a51248cb0 unify udpraw linux and mp branch 2020-07-15 15:29:32 -04:00
wangyu
79bb28fd12 introduce huge_buf_len and huge_data_len 2020-07-15 03:59:58 -04:00
wangyu
b3e06de4cb do not drop truncated packet if fix_gro enabled 2020-07-15 02:59:42 -04:00
wangyu
b03ae53df6 update 2020-07-15 01:58:26 -04:00
wangyu
15c15d5bcb aes128cfb_0 2020-07-15 01:37:47 -04:00
wangyu
2f0328a41a update 2020-07-14 14:48:29 -04:00
wangyu
779ebdd37a change gro scheme 2020-07-14 14:30:26 -04:00
wangyu
5340f0726e fix last commit 2020-07-14 12:30:57 -04:00
wangyu
e95ee70351 sync ca4a5d3 2020-07-14 11:46:02 -04:00
root
5cc304a261 partically revert last change 2019-07-16 06:18:44 +00:00
wangyu
7636225414 update cfb 2019-07-16 00:47:36 -04:00
wangyu
f68c6e211d update help page 2019-07-15 13:12:17 -04:00
wangyu
8c81f7673b update --fix-gro 2019-07-15 13:00:16 -04:00
root
c1dfd4e928 --fix-gro works 2019-07-15 15:33:16 +00:00
wangyu
7e55b1e132 --fix-gro update 2019-07-15 10:49:54 -04:00
wangyu
ee787e0d4a added --fix-gro 2019-07-15 08:36:06 -04:00
U-DESKTOP-T772REH\wangyu
7d481d26b9 get_current_time_us() never goes back now 2019-05-02 05:39:39 +00:00
wangyu-
168ae1e2ae
Merge pull request #231 from king6cong/master
fix typo
2018-12-06 23:33:00 +08:00
king6cong
6230569bbb fix typo 2018-12-06 16:13:47 +08:00
U-DESKTOP-T772REH\wangyu
238e85a5e4 fixed get_sock_error() format on windows 2018-11-13 06:40:58 -06:00
wangyu-
0137dba1fd fix bug in random port bind 2018-11-13 02:37:45 -06:00
wangyu-
b6f76827b0
Merge pull request #221 from felixonmars/patch-1
Fix a typo in README
2018-11-13 16:31:03 +08:00
Felix Yan
66eb002528
Fix a typo in README 2018-11-10 17:13:38 +08:00
wangyu-
b1f0498472
fix typo 2018-09-30 09:52:45 +08:00
U-DESKTOP-T772REH\wangyu
e5584c73be turn down log level 2018-09-06 10:35:23 -05:00
U-DESKTOP-T772REH\wangyu
c855a14ae8 bug fix 2018-09-06 10:35:23 -05:00
wangyu-
d77271540f trival 2018-08-31 12:51:27 -05:00
wangyu-
6b8852f269 add warning 2018-08-31 12:45:30 -05:00
root
f0e36d7d7c fixed a core 2018-08-31 17:10:46 +00:00
wangyu-
6153aca5d8 fix last commit 2018-08-29 20:02:42 -05:00
wangyu-
92fcdbb31a reduce diff 2018-08-29 20:00:37 -05:00
wangyu-
c72480110f reduce diff 2018-08-29 17:09:48 -05:00
wangyu-
8331610e7a reduce diff 2018-08-29 16:48:45 -05:00
wangyu-
4a1e01c5a5 remove register var 2018-08-29 14:32:45 -05:00
wangyu-
6ccf6ce3dc delete unused codes, reduce diff with non-mp version 2018-08-29 14:26:34 -05:00
wangyu-
a3535364fa fixed fifo at client side 2018-08-29 12:29:41 -05:00
wangyu-
4e9000c6b5 sync easyfaketcp,fixed a bug in try_to_list_and_bind2 2018-08-29 12:19:09 -05:00
wangyu-
a4aba62656 sync easy-tcp and other options from mp version 2018-08-29 05:25:44 -05:00
wangyu-
7de2f800f9 server works again 2018-08-29 05:01:30 -05:00
wangyu-
233fab4fac change client to libev, server doesnt work yet 2018-08-29 04:01:37 -05:00
wangyu-
6718627e9d added libev files 2018-08-29 02:03:10 -05:00
wangyu-
b9d4264225 split main.cpp into client.cpp and server.cpp 2018-08-29 01:45:57 -05:00
wangyu-
0095f1da5c fixed print of ip address 2018-08-18 12:55:02 -05:00
wangyu-
44fef508a1 supress warning 2018-08-09 02:40:59 -05:00
65 changed files with 30073 additions and 7860 deletions

4
.clang-format Normal file

@ -0,0 +1,4 @@
SortIncludes: false
BasedOnStyle: Google
ColumnLimit: 0
IndentWidth: 4

35
CMakeLists.txt Normal file

@ -0,0 +1,35 @@
#note: experimental
# currently only used for generating `compile_commands.json` for clangd.
# to build this project, it's suggested to use `makefile` instead
cmake_minimum_required(VERSION 3.7)
project(udp2raw)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES
main.cpp
lib/md5.cpp
lib/pbkdf2-sha1.cpp
lib/pbkdf2-sha256.cpp
encrypt.cpp
log.cpp
network.cpp
common.cpp
connection.cpp
misc.cpp
fd_manager.cpp
client.cpp
server.cpp
lib/aes_faster_c/aes.cpp
lib/aes_faster_c/wrapper.cpp
my_ev.cpp
)
set(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers -O2 -g -fsanitize=address,undefined")
add_executable(udp2raw ${SOURCE_FILES})
target_link_libraries(udp2raw rt)
target_link_libraries(udp2raw pthread)
include_directories(SYSTEM "libev")
include_directories(".")

@ -1,13 +0,0 @@
FROM alpine:3.6 as builder
WORKDIR /
RUN apk add --no-cache git build-base linux-headers && \
git clone https://github.com/wangyu-/udp2raw-tunnel.git && \
cd udp2raw-tunnel && \
make dynamic
FROM alpine:3.6
RUN apk add --no-cache libstdc++ iptables
COPY --from=builder /udp2raw-tunnel/udp2raw_dynamic /bin/
ENTRYPOINT [ "/bin/udp2raw_dynamic" ]

@ -1,6 +1 @@
For English speaking user
https://github.com/wangyu-/UDPspeeder/wiki/Issue-Guide
中文用户请看:
https://github.com/wangyu-/UDPspeeder/wiki/发Issue前请看
(否则Issue可能被忽略或被直接关掉)
English Only.

109
README.md

@ -1,43 +1,45 @@
# Udp2raw-tunnel
A Tunnel which turns UDP Traffic into Encrypted FakeTCP/UDP/ICMP Traffic by using Raw Socket, helps you Bypass UDP FireWalls(or Unstable UDP Environment). It can defend Replay-Attack and supports Multiplexing. It also acts as a Connection Stabilizer.
A Tunnel which turns UDP Traffic into Encrypted FakeTCP/UDP/ICMP Traffic by using Raw Socket, helps you Bypass UDP FireWalls(or Unstable UDP Environment).
When used alone,udp2raw tunnels only UDP traffic. Nevertheless,if you used udp2raw + any UDP-based VPN together,you can tunnel any traffic(include TCP/UDP/ICMP),currently OpenVPN/L2TP/ShadowVPN and [tinyfecVPN](https://github.com/wangyu-/tinyfecVPN) are confirmed to be supported.
![image0](images/image0.PNG)
When used alone,udp2raw tunnels only UDP traffic. Nevertheless,if you used udp2raw + any UDP-based VPN together,you can tunnel any traffic(include TCP/UDP/ICMP),currently OpenVPN/L2TP/ShadowVPN and [tinyfecVPN](https://github.com/wangyu-/tinyfecVPN) are confirmed to be supported.
or
![image_vpn](images/udp2rawopenvpn.PNG)
[简体中文](/doc/README.zh-cn.md)(内容更丰富)
[udp2raw wiki](https://github.com/wangyu-/udp2raw-tunnel/wiki)
[简体中文](/doc/README.zh-cn.md)
# Support Platforms
Linux host (including desktop Linux,Android phone/tablet,OpenWRT router,or Raspberry PI) with root access.
Linux host (including desktop Linux,Android phone/tablet,OpenWRT router,or Raspberry PI) with root account or cap_net_raw capability.
For Windows and MacOS users, use the udp2raw in [this repo](https://github.com/wangyu-/udp2raw-multiplatform).
<del>For Windows and MacOS You can run udp2raw 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(make sure network adapter runs at bridged mode).</del>
# Features
# Features
### Send/Receive UDP Packets with ICMP/FakeTCP/UDP headers
ICMP/FakeTCP headers help you bypass UDP blocking, UDP QOS or improper UDP NAT behavior on some ISPs. In ICMP header mode,udp2raw works like an ICMP tunnel.
ICMP/FakeTCP headers help you bypass UDP blocking, UDP QOS or improper UDP NAT behavior on some ISPs. In ICMP header mode,udp2raw works like an ICMP tunnel.
UDP headers are also supported. In UDP header mode, it behaves just like a normal UDP tunnel, and you can just make use of the other features (such as encrytion, anti-replay, or connection stalization).
UDP headers are also supported. In UDP header mode, it behaves just like a normal UDP tunnel, and you can just make use of the other features (such as encryption, anti-replay, or connection stabilization).
### Simulated TCP with Real-time/Out-of-Order Delivery
In FakeTCP header mode,udp2raw simulates 3-way handshake while establishing a connection,simulates seq and ack_seq while data transferring. It also simulates following TCP options: `MSS`, `sackOk`, `TS`, `TS_ack`, `wscale`.Firewalls will regard FakeTCP as a TCP connection, but its essentially UDP: it supports real-time/out-of-order delivery(just as normal UDP does), no congrestion control or re-transmission. So there wont be any TCP over TCP problem when using OpenVPN.
In FakeTCP header mode,udp2raw simulates 3-way handshake while establishing a connection,simulates seq and ack_seq while data transferring. It also simulates a few TCP options such as: `MSS`, `sackOk`, `TS`, `TS_ack`, `wscale`. Firewalls will regard FakeTCP as a TCP connection, but its essentially UDP: it supports real-time/out-of-order delivery(just as normal UDP does), no congestion control or re-transmission. So there wont be any TCP over TCP problem when using OpenVPN.
### Encrpytion, Anti-Replay
### Encryption, Anti-Replay
* Encrypt your traffic with AES-128-CBC.
* Protect data integrity by HMAC-SHA1 (or weaker MD5/CRC32).
* Defense replay attack with an anti-replay window, smiliar to IPSec and OpenVPN.
* Defense replay attack with anti-replay window.
### Failure Dectection & Stablization (Connection Recovery)
Conection failures are detected by heartbeats. If timed-out, client will automatically change port number and reconnect. If reconnection is successful, the previous connection will be recovered, and all existing UDP conversations will stay vaild.
[Notes on encryption](https://github.com/wangyu-/udp2raw-tunnel/wiki/Notes-on-encryption)
### Failure Dectection & Stabilization (Connection Recovery)
Conection failures are detected by heartbeats. If timed-out, client will automatically change port number and reconnect. If reconnection is successful, the previous connection will be recovered, and all existing UDP conversations will stay vaild.
For example, if you use udp2raw + OpenVPN, OpenVPN won't lose connection after any reconnect, **even if network cable is re-plugged or WiFi access point is changed**.
@ -59,7 +61,7 @@ For example, if you use udp2raw + OpenVPN, OpenVPN won't lose connection after a
### Installing
Download binary release from https://github.com/wangyu-/udp2raw-tunnel/releases
### Running
### Running
Assume your UDP is blocked or being QOS-ed or just poorly supported. Assume your server ip is 44.55.66.77, you have a service listening on udp port 7777.
```bash
@ -79,9 +81,9 @@ Assume your UDP is blocked or being QOS-ed or just poorly supported. Assume your
Now,an encrypted raw tunnel has been established between client and server through TCP port 4096. Connecting to UDP port 3333 at the client side is equivalent to connecting to port 7777 at the server side. No UDP traffic will be exposed.
### Note
To run on Android, check [Android_Guide](/doc/android_guide.md)
To run on Android, check [Android_Guide](https://github.com/wangyu-/udp2raw/wiki/Android-Guide)
`-a` option automatically adds an iptables rule (or a few iptables rules) for you, udp2raw relys on this iptables rule to work stably. Be aware you dont forget `-a` (its a common mistake). If you dont want udp2raw to add iptables rule automatically, you can add it manually(take a look at `-g` option) and omit `-a`.
`-a` option automatically adds an iptables rule (or a few iptables rules) for you, udp2raw relies on this iptables rule to work stably. Be aware you dont forget `-a` (its a common mistake). If you dont want udp2raw to add iptables rule automatically, you can add it manually(take a look at `-g` option) and omit `-a`.
# Advanced Topic
@ -141,11 +143,11 @@ other options:
### Iptables rules,`-a` and `-g`
This program sends packets via raw socket. In FakeTCP mode, Linux kernel TCP packet processing has to be blocked by a iptables rule on both sides, otherwise the kernel will automatically send RST for an unrecongized TCP packet and you will sustain from stability / peformance problems. You can use `-a` option to let the program automatically add / delete iptables rule on start / exit. You can also use the `-g` option to generate iptables rule and add it manually.
### `--cipher-mode` and `--auth-mode`
### `--cipher-mode` and `--auth-mode`
It is suggested to use `aes128cbc` + `hmac_sha1` to obtain maximum security. If you want to run the program on a router, you can try `xor` + `simple`, which can fool packet inspection by firewalls the most of time, but it cannot protect you from serious attacks. Mode none is only for debugging purpose. It is not recommended to set the cipher-mode or auth-mode to none.
### `--seq-mode`
The FakeTCP mode does not behave 100% like a real tcp connection. ISPs may be able to distinguish the simulated tcp traffic from the real TCP traffic (though it's costly). seq-mode can help you change the seq increase behavior slightly. If you experience connection problems, try to change the value.
The FakeTCP mode does not behave 100% like a real tcp connection. ISPs may be able to distinguish the simulated tcp traffic from the real TCP traffic (though it's costly). seq-mode can help you change the seq increase behavior slightly. If you experience connection problems, try to change the value.
### `--lower-level`
`--lower-level` allows you to send packet at OSI level 2(link level),so that you can bypass any local iptables rules. If you have a complicated iptables rules which conflicts with udp2raw and you cant(or too lazy to) edit the iptables rules,`--lower-level` can be very useful. Try `--lower-level auto` to auto detect the parameters,you can specify it manually if `auto` fails.
@ -192,12 +194,12 @@ At client side,you can use `echo reconnect >fifo.file` to force client to reconn
# Peformance Test
#### Test method:
iperf3 TCP via OpenVPN + udp2raw
iperf3 TCP via OpenVPN + udp2raw
(iperf3 UDP mode is not used because of a bug mentioned in this issue: https://github.com/esnet/iperf/issues/296 . Instead, we package the TCP traffic into UDP by OpenVPN to test the performance. Read [Application](https://github.com/wangyu-/udp2raw-tunnel#application) for details.
#### iperf3 command:
#### iperf3 command:
```
iperf3 -c 10.222.2.1 -P40
iperf3 -c 10.222.2.1 -P40
iperf3 -c 10.222.2.1 -P40 -R
```
#### Environments
@ -218,63 +220,6 @@ raw_mode: faketcp cipher_mode: aes128cbc  auth_mode: md5
(reverse speed was simliar and not uploaded)
# Application
## Tunneling any traffic via raw traffic by using udp2raw +openvpn
![image_vpn](images/udp2rawopenvpn.PNG)
1. Bypasses UDP block/UDP QOS
2. No TCP over TCP problem (TCP over TCP problem http://sites.inka.de/bigred/devel/tcp-tcp.html ,https://community.openvpn.net/openvpn/ticket/2 )
3. OpenVpn over ICMP also becomes a choice
4. Supports almost any UDP-based VPN
More details at [openvpn+udp2raw_guide](https://github.com/wangyu-/udp2raw-tunnel/wiki/udp2raw-openvpn-config-guide)
## Speed-up tcp connection via raw traffic by using udp2raw+kcptun
kcptun is a tcp connection speed-up program,it speeds-up tcp connection by using kcp protocol on-top of udp.by using udp2raw,you can use kcptun while udp is QoSed or blocked.
(kcptun, https://github.com/xtaci/kcptun)
## Speed-up tcp connection via raw traffic by using udp2raw+finalspeed
finalspeed is a tcp connection speed-up program similiar to kcptun,it speeds-up tcp connection by using kcp protocol on-top of udp or tcp.but its tcp mode doesnt support openvz,you can bypass this problem if you use udp2raw+finalspeed together,and icmp mode also becomes avaliable.
# How to build
read [build_guide](/doc/build_guide.md)
# Other
### Easier installation on ArchLinux
```
yaourt -S udp2raw-tunnel # or
pacaur -S udp2raw-tunnel
```
# Related work
### kcptun-raw
udp2raw was inspired by kcptun-raw,which modified kcptun to support tcp mode.
https://github.com/Chion82/kcptun-raw
### relayRawSocket
kcptun-raw was inspired by relayRawSocket. A simple udp to raw tunnel,wrote in python
https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket
### kcpraw
another project of kcptun with tcp mode
https://github.com/ccsexyz/kcpraw
### icmptunnel
Transparently tunnel your IP traffic through ICMP echo and reply packets.
https://github.com/DhavalKapil/icmptunnel
### Tcp Minion
Tcp Minion is a project which modifid the code of tcp stack in kernel,and implemented real-time out-order udp packet delivery through this modified tcp stack.I failed to find the implementation,but there are some papers avaliable:
https://arxiv.org/abs/1103.0463
http://korz.cs.yale.edu/2009/tng/papers/pfldnet10.pdf
https://pdfs.semanticscholar.org/9e6f/e2306f4385b4eb5416d1fcab16e9361d6ba3.pdf
# wiki
Check wiki for more info:

895
client.cpp Normal file

@ -0,0 +1,895 @@
#include "common.h"
#include "network.h"
#include "connection.h"
#include "misc.h"
#include "log.h"
#include "lib/md5.h"
#include "encrypt.h"
#include "fd_manager.h"
#ifdef UDP2RAW_MP
u32_t detect_interval = 1500;
u64_t laste_detect_time = 0;
int use_udp_for_detection = 0;
int use_tcp_for_detection = 1;
extern pcap_t *pcap_handle;
extern int pcap_captured_full_len;
#endif
int client_on_timer(conn_info_t &conn_info) // for client. called when a timer is ready in epoll
{
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
raw_info_t &raw_info = conn_info.raw_info;
conn_info.blob->conv_manager.c.clear_inactive();
mylog(log_trace, "timer!\n");
mylog(log_trace, "roller my %d,oppsite %d,%lld\n", int(conn_info.my_roller), int(conn_info.oppsite_roller), conn_info.last_oppsite_roller_time);
mylog(log_trace, "<client_on_timer,send_info.ts_ack= %u>\n", send_info.ts_ack);
#ifdef UDP2RAW_MP
// mylog(log_debug,"pcap cnt :%d\n",pcap_cnt);
if (send_with_pcap && !pcap_header_captured) {
if (get_current_time() - laste_detect_time > detect_interval) {
laste_detect_time = get_current_time();
} else {
return 0;
}
/*
struct sockaddr_in remote_addr_in={0};
socklen_t slen = sizeof(sockaddr_in);
int port=get_true_random_number()%65534+1;
remote_addr_in.sin_family = AF_INET;
remote_addr_in.sin_port = htons(port);
remote_addr_in.sin_addr.s_addr = remote_ip_uint32;*/
int port = get_true_random_number() % 65534 + 1;
address_t tmp_addr = remote_addr;
tmp_addr.set_port(port);
if (use_udp_for_detection) {
int new_udp_fd = socket(tmp_addr.get_type(), SOCK_DGRAM, IPPROTO_UDP);
if (new_udp_fd < 0) {
mylog(log_warn, "create new_udp_fd error\n");
return -1;
}
setnonblocking(new_udp_fd);
u64_t tmp = get_true_random_number();
int ret = sendto(new_udp_fd, (char *)(&tmp), sizeof(tmp), 0, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());
if (ret == -1) {
mylog(log_warn, "sendto() failed\n");
}
sock_close(new_udp_fd);
}
if (use_tcp_for_detection) {
static int last_tcp_fd = -1;
int new_tcp_fd = socket(tmp_addr.get_type(), SOCK_STREAM, IPPROTO_TCP);
if (new_tcp_fd < 0) {
mylog(log_warn, "create new_tcp_fd error\n");
return -1;
}
setnonblocking(new_tcp_fd);
connect(new_tcp_fd, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());
if (last_tcp_fd != -1)
sock_close(last_tcp_fd);
last_tcp_fd = new_tcp_fd;
// close(new_tcp_fd);
}
mylog(log_info, "waiting for a use-able packet to be captured\n");
return 0;
}
#endif
if (raw_info.disabled) {
conn_info.state.client_current_state = client_idle;
conn_info.my_id = get_true_random_number_nz();
mylog(log_info, "state back to client_idle\n");
}
if (conn_info.state.client_current_state == client_idle) {
raw_info.rst_received = 0;
raw_info.disabled = 0;
fail_time_counter++;
if (max_fail_time > 0 && fail_time_counter > max_fail_time) {
mylog(log_fatal, "max_fail_time exceed\n");
myexit(-1);
}
conn_info.blob->anti_replay.re_init();
conn_info.my_id = get_true_random_number_nz(); /// todo no need to do this everytime
address_t tmp_addr;
// u32_t new_ip=0;
if (!force_source_ip) {
if (get_src_adress2(tmp_addr, remote_addr) != 0) {
mylog(log_warn, "get_src_adress() failed\n");
return -1;
}
// source_addr=new_addr;
// source_addr.set_port(0);
mylog(log_info, "source_addr is now %s\n", tmp_addr.get_ip());
/*
if(new_ip!=source_ip_uint32)
{
mylog(log_info,"source ip changed from %s to ",my_ntoa(source_ip_uint32));
log_bare(log_info,"%s\n",my_ntoa(new_ip));
source_ip_uint32=new_ip;
send_info.src_ip=new_ip;
}*/
} else {
tmp_addr = source_addr;
}
send_info.new_src_ip.from_address_t(tmp_addr);
if (force_source_port == 0) {
send_info.src_port = client_bind_to_a_new_port2(bind_fd, tmp_addr);
} else {
send_info.src_port = source_port;
}
if (raw_mode == mode_icmp) {
send_info.dst_port = send_info.src_port;
}
mylog(log_info, "using port %d\n", send_info.src_port);
init_filter(send_info.src_port);
if (raw_mode == mode_icmp || raw_mode == mode_udp) {
conn_info.state.client_current_state = client_handshake1;
mylog(log_info, "state changed from client_idle to client_pre_handshake\n");
}
if (raw_mode == mode_faketcp) {
if (use_tcp_dummy_socket) {
setnonblocking(bind_fd);
int ret = connect(bind_fd, (struct sockaddr *)&remote_addr.inner, remote_addr.get_len());
mylog(log_debug, "ret=%d,errno=%s, %d %s\n", ret, get_sock_error(), bind_fd, remote_addr.get_str());
// mylog(log_info,"ret=%d,errno=,%d %s\n",ret,bind_fd,remote_addr.get_str());
conn_info.state.client_current_state = client_tcp_handshake_dummy;
mylog(log_info, "state changed from client_idle to client_tcp_handshake_dummy\n");
} else {
conn_info.state.client_current_state = client_tcp_handshake;
mylog(log_info, "state changed from client_idle to client_tcp_handshake\n");
}
}
conn_info.last_state_time = get_current_time();
conn_info.last_hb_sent_time = 0;
// dont return;
}
if (conn_info.state.client_current_state == client_tcp_handshake) // send and resend syn
{
assert(raw_mode == mode_faketcp);
if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
conn_info.state.client_current_state = client_idle;
mylog(log_info, "state back to client_idle from client_tcp_handshake\n");
return 0;
} else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
if (raw_mode == mode_faketcp) {
if (conn_info.last_hb_sent_time == 0) {
send_info.psh = 0;
send_info.syn = 1;
send_info.ack = 0;
send_info.ts_ack = 0;
send_info.seq = get_true_random_number();
send_info.ack_seq = get_true_random_number();
}
}
send_raw0(raw_info, 0, 0);
conn_info.last_hb_sent_time = get_current_time();
mylog(log_info, "(re)sent tcp syn\n");
return 0;
} else {
return 0;
}
return 0;
} else if (conn_info.state.client_current_state == client_tcp_handshake_dummy) {
assert(raw_mode == mode_faketcp);
if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
conn_info.state.client_current_state = client_idle;
mylog(log_info, "state back to client_idle from client_tcp_handshake_dummy\n");
return 0;
}
} else if (conn_info.state.client_current_state == client_handshake1) // send and resend handshake1
{
if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
conn_info.state.client_current_state = client_idle;
mylog(log_info, "state back to client_idle from client_handshake1\n");
return 0;
} else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
if (raw_mode == mode_faketcp) {
if (conn_info.last_hb_sent_time == 0) {
send_info.seq++;
send_info.ack_seq = recv_info.seq + 1;
send_info.ts_ack = recv_info.ts;
raw_info.reserved_send_seq = send_info.seq;
}
send_info.seq = raw_info.reserved_send_seq;
send_info.psh = 0;
send_info.syn = 0;
send_info.ack = 1;
if (!use_tcp_dummy_socket)
send_raw0(raw_info, 0, 0);
send_handshake(raw_info, conn_info.my_id, 0, const_id);
send_info.seq += raw_info.send_info.data_len;
} else {
send_handshake(raw_info, conn_info.my_id, 0, const_id);
if (raw_mode == mode_icmp)
send_info.my_icmp_seq++;
}
conn_info.last_hb_sent_time = get_current_time();
mylog(log_info, "(re)sent handshake1\n");
return 0;
} else {
return 0;
}
return 0;
} else if (conn_info.state.client_current_state == client_handshake2) {
if (get_current_time() - conn_info.last_state_time > client_handshake_timeout) {
conn_info.state.client_current_state = client_idle;
mylog(log_info, "state back to client_idle from client_handshake2\n");
return 0;
} else if (get_current_time() - conn_info.last_hb_sent_time > client_retry_interval) {
if (raw_mode == mode_faketcp) {
if (conn_info.last_hb_sent_time == 0) {
send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len;
send_info.ts_ack = recv_info.ts;
raw_info.reserved_send_seq = send_info.seq;
}
send_info.seq = raw_info.reserved_send_seq;
send_handshake(raw_info, conn_info.my_id, conn_info.oppsite_id, const_id);
send_info.seq += raw_info.send_info.data_len;
} else {
send_handshake(raw_info, conn_info.my_id, conn_info.oppsite_id, const_id);
if (raw_mode == mode_icmp)
send_info.my_icmp_seq++;
}
conn_info.last_hb_sent_time = get_current_time();
mylog(log_info, "(re)sent handshake2\n");
return 0;
} else {
return 0;
}
return 0;
} else if (conn_info.state.client_current_state == client_ready) {
fail_time_counter = 0;
mylog(log_trace, "time %llu,%llu\n", get_current_time(), conn_info.last_state_time);
if (get_current_time() - conn_info.last_hb_recv_time > client_conn_timeout) {
conn_info.state.client_current_state = client_idle;
conn_info.my_id = get_true_random_number_nz();
mylog(log_info, "state back to client_idle from client_ready bc of server-->client direction timeout\n");
return 0;
}
if (get_current_time() - conn_info.last_oppsite_roller_time > client_conn_uplink_timeout) {
conn_info.state.client_current_state = client_idle;
conn_info.my_id = get_true_random_number_nz();
mylog(log_info, "state back to client_idle from client_ready bc of client-->server direction timeout\n");
}
if (get_current_time() - conn_info.last_hb_sent_time < heartbeat_interval) {
return 0;
}
mylog(log_debug, "heartbeat sent <%x,%x>\n", conn_info.oppsite_id, conn_info.my_id);
if (hb_mode == 0)
send_safer(conn_info, 'h', hb_buf, 0); /////////////send
else
send_safer(conn_info, 'h', hb_buf, hb_len);
conn_info.last_hb_sent_time = get_current_time();
return 0;
} else {
mylog(log_fatal, "unknown state,this shouldnt happen.\n");
myexit(-1);
}
return 0;
}
int client_on_raw_recv_hs2_or_ready(conn_info_t &conn_info, char type, char *data, int data_len) {
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
mylog(log_warn, "unexpected adress %s %s %d %d,this shouldnt happen.\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
return -1;
}
if (conn_info.state.client_current_state == client_handshake2) {
mylog(log_info, "changed state from to client_handshake2 to client_ready\n");
conn_info.state.client_current_state = client_ready;
conn_info.last_hb_sent_time = 0;
conn_info.last_hb_recv_time = get_current_time();
conn_info.last_oppsite_roller_time = conn_info.last_hb_recv_time;
client_on_timer(conn_info);
}
if (data_len >= 0 && type == 'h') {
mylog(log_debug, "[hb]heart beat received,oppsite_roller=%d\n", int(conn_info.oppsite_roller));
conn_info.last_hb_recv_time = get_current_time();
return 0;
} else if (data_len >= int(sizeof(u32_t)) && type == 'd') {
mylog(log_trace, "received a data from fake tcp,len:%d\n", data_len);
if (hb_mode == 0)
conn_info.last_hb_recv_time = get_current_time();
u32_t tmp_conv_id;
memcpy(&tmp_conv_id, &data[0], sizeof(tmp_conv_id));
tmp_conv_id = ntohl(tmp_conv_id);
if (!conn_info.blob->conv_manager.c.is_conv_used(tmp_conv_id)) {
mylog(log_info, "unknow conv %d,ignore\n", tmp_conv_id);
return 0;
}
conn_info.blob->conv_manager.c.update_active_time(tmp_conv_id);
// u64_t u64=conn_info.blob->conv_manager.c.find_data_by_conv(tmp_conv_id);
address_t tmp_addr = conn_info.blob->conv_manager.c.find_data_by_conv(tmp_conv_id);
// sockaddr_in tmp_sockaddr={0};
// tmp_sockaddr.sin_family = AF_INET;
// tmp_sockaddr.sin_addr.s_addr=(u64>>32u);
// tmp_sockaddr.sin_port= htons(uint16_t((u64<<32u)>>32u));
int ret = sendto(udp_fd, data + sizeof(u32_t), data_len - (sizeof(u32_t)), 0, (struct sockaddr *)&tmp_addr.inner, tmp_addr.get_len());
if (ret < 0) {
mylog(log_warn, "sento returned %d,%s,%02x,%s\n", ret, get_sock_error(), int(tmp_addr.get_type()), tmp_addr.get_str());
// perror("ret<0");
}
} else {
mylog(log_warn, "unknown packet,this shouldnt happen.\n");
return -1;
}
return 0;
}
int client_on_raw_recv(conn_info_t &conn_info) // called when raw fd received a packet.
{
char *data;
int data_len;
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
raw_info_t &raw_info = conn_info.raw_info;
mylog(log_trace, "<client_on_raw_recv,send_info.ts_ack= %u>\n", send_info.ts_ack);
#ifdef UDP2RAW_LINUX
if (pre_recv_raw_packet() < 0) return -1;
#endif
if (conn_info.state.client_current_state == client_idle) {
discard_raw_packet();
// recv(raw_recv_fd, 0,0, 0 );
} else if (conn_info.state.client_current_state == client_tcp_handshake || conn_info.state.client_current_state == client_tcp_handshake_dummy) // received syn ack
{
assert(raw_mode == mode_faketcp);
if (recv_raw0(raw_info, data, data_len) < 0) {
return -1;
}
if (data_len >= max_data_len + 1) {
mylog(log_debug, "data_len=%d >= max_data_len+1,ignored", data_len);
return -1;
}
if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
mylog(log_debug, "unexpected adress %s %s %d %d\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
return -1;
}
if (data_len == 0 && raw_info.recv_info.syn == 1 && raw_info.recv_info.ack == 1) {
if (conn_info.state.client_current_state == client_tcp_handshake) {
if (recv_info.ack_seq != send_info.seq + 1) {
mylog(log_debug, "seq ack_seq mis match\n");
return -1;
}
mylog(log_info, "state changed from client_tcp_handshake to client_handshake1\n");
} else {
send_info.seq = recv_info.ack_seq - 1;
mylog(log_info, "state changed from client_tcp_dummy to client_handshake1\n");
// send_info.ack_seq=recv_info.seq+1;
}
conn_info.state.client_current_state = client_handshake1;
conn_info.last_state_time = get_current_time();
conn_info.last_hb_sent_time = 0;
client_on_timer(conn_info);
return 0;
} else {
mylog(log_debug, "unexpected packet type,expected:syn ack\n");
return -1;
}
} else if (conn_info.state.client_current_state == client_handshake1) // recevied respond of handshake1
{
if (recv_bare(raw_info, data, data_len) != 0) {
mylog(log_debug, "recv_bare failed!\n");
return -1;
}
if (!recv_info.new_src_ip.equal(send_info.new_dst_ip) || recv_info.src_port != send_info.dst_port) {
mylog(log_debug, "unexpected adress %s %s %d %d\n", recv_info.new_src_ip.get_str1(), send_info.new_dst_ip.get_str2(), recv_info.src_port, send_info.dst_port);
return -1;
}
if (data_len < int(3 * sizeof(my_id_t))) {
mylog(log_debug, "too short to be a handshake\n");
return -1;
}
my_id_t tmp_oppsite_id;
memcpy(&tmp_oppsite_id, &data[0], sizeof(tmp_oppsite_id));
tmp_oppsite_id = ntohl(tmp_oppsite_id);
my_id_t tmp_my_id;
memcpy(&tmp_my_id, &data[sizeof(my_id_t)], sizeof(tmp_my_id));
tmp_my_id = ntohl(tmp_my_id);
my_id_t tmp_oppsite_const_id;
memcpy(&tmp_oppsite_const_id, &data[sizeof(my_id_t) * 2], sizeof(tmp_oppsite_const_id));
tmp_oppsite_const_id = ntohl(tmp_oppsite_const_id);
if (tmp_my_id != conn_info.my_id) {
mylog(log_debug, "tmp_my_id doesnt match\n");
return -1;
}
if (raw_mode == mode_faketcp) {
if (recv_info.ack_seq != send_info.seq) {
mylog(log_debug, "seq ack_seq mis match\n");
return -1;
}
if (recv_info.seq != send_info.ack_seq) {
mylog(log_debug, "seq ack_seq mis match\n");
return -1;
}
}
conn_info.oppsite_id = tmp_oppsite_id;
mylog(log_info, "changed state from to client_handshake1 to client_handshake2,my_id is %x,oppsite id is %x\n", conn_info.my_id, conn_info.oppsite_id);
conn_info.state.client_current_state = client_handshake2;
conn_info.last_state_time = get_current_time();
conn_info.last_hb_sent_time = 0;
client_on_timer(conn_info);
return 0;
} else if (conn_info.state.client_current_state == client_handshake2 || conn_info.state.client_current_state == client_ready) // received heartbeat or data
{
vector<char> type_vec;
vector<string> data_vec;
recv_safer_multi(conn_info, type_vec, data_vec);
if (data_vec.empty()) {
mylog(log_debug, "recv_safer failed!\n");
return -1;
}
for (int i = 0; i < (int)type_vec.size(); i++) {
char type = type_vec[i];
char *data = (char *)data_vec[i].c_str(); // be careful, do not append data to it
int data_len = data_vec[i].length();
client_on_raw_recv_hs2_or_ready(conn_info, type, data, data_len);
}
return 0;
} else {
mylog(log_fatal, "unknown state,this shouldnt happen.\n");
myexit(-1);
}
return 0;
}
int client_on_udp_recv(conn_info_t &conn_info) {
int recv_len;
char buf[buf_len];
address_t::storage_t udp_new_addr_in = {{0}};
socklen_t udp_new_addr_len = sizeof(address_t::storage_t);
if ((recv_len = recvfrom(udp_fd, buf, max_data_len + 1, 0,
(struct sockaddr *)&udp_new_addr_in, &udp_new_addr_len)) == -1) {
mylog(log_debug, "recv_from error,%s\n", get_sock_error());
return -1;
// myexit(1);
};
if (recv_len == max_data_len + 1) {
mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
return -1;
}
if (recv_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 ", recv_len, mtu_warn);
}
address_t tmp_addr;
tmp_addr.from_sockaddr((sockaddr *)&udp_new_addr_in, udp_new_addr_len);
u32_t conv;
if (!conn_info.blob->conv_manager.c.is_data_used(tmp_addr)) {
if (conn_info.blob->conv_manager.c.get_size() >= max_conv_num) {
mylog(log_warn, "ignored new udp connect bc max_conv_num exceed\n");
return -1;
}
conv = conn_info.blob->conv_manager.c.get_new_conv();
conn_info.blob->conv_manager.c.insert_conv(conv, tmp_addr);
mylog(log_info, "new packet from %s,conv_id=%x\n", tmp_addr.get_str(), conv);
} else {
conv = conn_info.blob->conv_manager.c.find_conv_by_data(tmp_addr);
}
conn_info.blob->conv_manager.c.update_active_time(conv);
if (conn_info.state.client_current_state == client_ready) {
send_data_safer(conn_info, buf, recv_len, conv);
}
return 0;
}
void udp_accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
conn_info_t &conn_info = *((conn_info_t *)watcher->data);
client_on_udp_recv(conn_info);
}
void raw_recv_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
if (is_udp2raw_mp) assert(0 == 1);
conn_info_t &conn_info = *((conn_info_t *)watcher->data);
client_on_raw_recv(conn_info);
}
#ifdef UDP2RAW_MP
void async_cb(struct ev_loop *loop, struct ev_async *watcher, int revents) {
conn_info_t &conn_info = *((conn_info_t *)watcher->data);
if (send_with_pcap && !pcap_header_captured) {
int empty = 0;
char *p;
int len;
pthread_mutex_lock(&queue_mutex);
empty = my_queue.empty();
if (!empty) {
my_queue.peek_front(p, len);
my_queue.pop_front();
}
pthread_mutex_unlock(&queue_mutex);
if (empty) return;
pcap_header_captured = 1;
assert(pcap_link_header_len != -1);
memcpy(pcap_header_buf, p, max_data_len);
log_bare(log_info, "link level header captured:\n");
unsigned char *tmp = (unsigned char *)pcap_header_buf;
pcap_captured_full_len = len;
for (int i = 0; i < pcap_link_header_len; i++)
log_bare(log_info, "<%x>", (u32_t)tmp[i]);
log_bare(log_info, "\n");
return;
}
// mylog(log_info,"async_cb called\n");
while (1) {
int empty = 0;
char *p;
int len;
pthread_mutex_lock(&queue_mutex);
empty = my_queue.empty();
if (!empty) {
my_queue.peek_front(p, len);
my_queue.pop_front();
}
pthread_mutex_unlock(&queue_mutex);
if (empty) break;
if (g_fix_gro == 0 && len > max_data_len) {
mylog(log_warn, "huge packet %d > %d, dropped. maybe you need to turn down mtu at upper level, or maybe you need the --fix-gro option\n", len, max_data_len);
break;
}
int new_len = len - pcap_link_header_len;
memcpy(g_packet_buf, p + pcap_link_header_len, new_len);
g_packet_buf_len = new_len;
assert(g_packet_buf_cnt == 0);
g_packet_buf_cnt++;
client_on_raw_recv(conn_info);
}
}
#endif
void clear_timer_cb(struct ev_loop *loop, struct ev_timer *watcher, int revents) {
conn_info_t &conn_info = *((conn_info_t *)watcher->data);
client_on_timer(conn_info);
}
void fifo_cb(struct ev_loop *loop, struct ev_io *watcher, int revents) {
conn_info_t &conn_info = *((conn_info_t *)watcher->data);
char buf[buf_len];
int fifo_fd = watcher->fd;
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;
while (len >= 1 && buf[len - 1] == '\n')
buf[len - 1] = 0;
mylog(log_info, "got data from fifo,len=%d,s=[%s]\n", len, buf);
if (strcmp(buf, "reconnect") == 0) {
mylog(log_info, "received command: reconnect\n");
conn_info.state.client_current_state = client_idle;
conn_info.my_id = get_true_random_number_nz();
} else {
mylog(log_info, "unknown command\n");
}
}
int client_event_loop() {
char buf[buf_len];
conn_info_t conn_info;
conn_info.my_id = get_true_random_number_nz();
conn_info.prepare();
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
#ifdef UDP2RAW_LINUX
if (lower_level) {
if (lower_level_manual) {
int index;
init_ifindex(if_name, raw_send_fd, index);
// init_ifindex(if_name);
memset(&send_info.addr_ll, 0, sizeof(send_info.addr_ll));
send_info.addr_ll.sll_family = AF_PACKET;
send_info.addr_ll.sll_ifindex = index;
send_info.addr_ll.sll_halen = ETHER_ADDR_LEN;
send_info.addr_ll.sll_protocol = htons(ETH_P_IP);
memcpy(&send_info.addr_ll.sll_addr, dest_hw_addr, ETHER_ADDR_LEN);
mylog(log_info, "we are running at lower-level (manual) mode\n");
} else {
u32_t dest_ip;
string if_name_string;
string hw_string;
assert(remote_addr.get_type() == AF_INET);
if (retry_on_error == 0) {
if (find_lower_level_info(remote_addr.inner.ipv4.sin_addr.s_addr, dest_ip, if_name_string, hw_string) != 0) {
mylog(log_fatal, "auto detect lower-level info failed for %s,specific it manually\n", remote_addr.get_ip());
myexit(-1);
}
} else {
int ok = 0;
while (!ok) {
if (find_lower_level_info(remote_addr.inner.ipv4.sin_addr.s_addr, dest_ip, if_name_string, hw_string) != 0) {
mylog(log_warn, "auto detect lower-level info failed for %s,retry in %d seconds\n", remote_addr.get_ip(), retry_on_error_interval);
sleep(retry_on_error_interval);
} else {
ok = 1;
}
}
}
mylog(log_info, "we are running at lower-level (auto) mode,%s %s %s\n", my_ntoa(dest_ip), if_name_string.c_str(), hw_string.c_str());
u32_t hw[6];
memset(hw, 0, sizeof(hw));
sscanf(hw_string.c_str(), "%x:%x:%x:%x:%x:%x", &hw[0], &hw[1], &hw[2],
&hw[3], &hw[4], &hw[5]);
mylog(log_warn,
"make sure this is correct: if_name=<%s> dest_mac_adress=<%02x:%02x:%02x:%02x:%02x:%02x> \n",
if_name_string.c_str(), hw[0], hw[1], hw[2], hw[3], hw[4], hw[5]);
for (int i = 0; i < 6; i++) {
dest_hw_addr[i] = uint8_t(hw[i]);
}
// mylog(log_fatal,"--lower-level auto for client hasnt been implemented\n");
int index;
init_ifindex(if_name_string.c_str(), raw_send_fd, index);
memset(&send_info.addr_ll, 0, sizeof(send_info.addr_ll));
send_info.addr_ll.sll_family = AF_PACKET;
send_info.addr_ll.sll_ifindex = index;
send_info.addr_ll.sll_halen = ETHER_ADDR_LEN;
send_info.addr_ll.sll_protocol = htons(ETH_P_IP);
memcpy(&send_info.addr_ll.sll_addr, dest_hw_addr, ETHER_ADDR_LEN);
// mylog(log_info,"we are running at lower-level (manual) mode\n");
}
}
#endif
#ifdef UDP2RAW_MP
address_t tmp_addr;
if (get_src_adress2(tmp_addr, remote_addr) != 0) {
mylog(log_error, "get_src_adress() failed\n");
myexit(-1);
}
if (strcmp(dev, "") == 0) {
mylog(log_info, "--dev have not been set, trying to detect automatically, available devices:\n");
mylog(log_info, "available device(device name: ip address ; description):\n");
char errbuf[PCAP_ERRBUF_SIZE];
int found = 0;
pcap_if_t *interfaces, *d;
if (pcap_findalldevs(&interfaces, errbuf) == -1) {
mylog(log_fatal, "error in pcap_findalldevs(),%s\n", errbuf);
myexit(-1);
}
for (pcap_if_t *d = interfaces; d != NULL; d = d->next) {
log_bare(log_warn, "%s:", d->name);
int cnt = 0;
for (pcap_addr_t *a = d->addresses; a != NULL; a = a->next) {
if (a->addr == NULL) {
log_bare(log_debug, " [a->addr==NULL]");
continue;
}
if (a->addr->sa_family == AF_INET || a->addr->sa_family == AF_INET6) {
cnt++;
if (a->addr->sa_family == AF_INET) {
char s[max_addr_len];
inet_ntop(AF_INET, &((struct sockaddr_in *)a->addr)->sin_addr, s, max_addr_len);
log_bare(log_warn, " [%s]", s);
if (a->addr->sa_family == raw_ip_version) {
if (((struct sockaddr_in *)a->addr)->sin_addr.s_addr == tmp_addr.inner.ipv4.sin_addr.s_addr) {
found++;
strcpy(dev, d->name);
}
}
} else {
assert(a->addr->sa_family == AF_INET6);
char s[max_addr_len];
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)a->addr)->sin6_addr, s, max_addr_len);
log_bare(log_warn, " [%s]", s);
if (a->addr->sa_family == raw_ip_version) {
if (memcmp(&((struct sockaddr_in6 *)a->addr)->sin6_addr, &tmp_addr.inner.ipv6.sin6_addr, sizeof(struct in6_addr)) == 0) {
found++;
strcpy(dev, d->name);
}
}
}
} else {
log_bare(log_debug, " [unknow:%d]", int(a->addr->sa_family));
}
}
if (cnt == 0) log_bare(log_warn, " [no ip found]");
if (d->description == 0) {
log_bare(log_warn, "; (no description available)");
} else {
log_bare(log_warn, "; %s", d->description);
}
log_bare(log_warn, "\n");
}
if (found == 0) {
mylog(log_fatal, "no matched device found for ip: [%s]\n", tmp_addr.get_ip());
myexit(-1);
} else if (found == 1) {
mylog(log_info, "using device:[%s], ip: [%s]\n", dev, tmp_addr.get_ip());
} else {
mylog(log_fatal, "more than one devices found for ip: [%s] , you need to use --dev manually\n", tmp_addr.get_ip());
myexit(-1);
}
} else {
mylog(log_info, "--dev has been manually set, using device:[%s]\n", dev);
}
#endif
send_info.src_port = 0;
memset(&send_info.new_src_ip, 0, sizeof(send_info.new_src_ip));
int i, j, k;
int ret;
send_info.new_dst_ip.from_address_t(remote_addr);
send_info.dst_port = remote_addr.get_port();
udp_fd = socket(local_addr.get_type(), SOCK_DGRAM, IPPROTO_UDP);
set_buf_size(udp_fd, socket_buf_size);
if (::bind(udp_fd, (struct sockaddr *)&local_addr.inner, local_addr.get_len()) == -1) {
mylog(log_fatal, "socket bind error\n");
// perror("socket bind error");
myexit(1);
}
setnonblocking(udp_fd);
// epollfd = epoll_create1(0);
// const int max_events = 4096;
// struct epoll_event ev, events[max_events];
// if (epollfd < 0) {
// mylog(log_fatal,"epoll return %d\n", epollfd);
// myexit(-1);
// }
struct ev_loop *loop = ev_default_loop(0);
assert(loop != NULL);
// ev.events = EPOLLIN;
// ev.data.u64 = udp_fd;
// ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, udp_fd, &ev);
// if (ret!=0) {
// mylog(log_fatal,"add udp_listen_fd error\n");
// myexit(-1);
// }
struct ev_io udp_accept_watcher;
udp_accept_watcher.data = &conn_info;
ev_io_init(&udp_accept_watcher, udp_accept_cb, udp_fd, EV_READ);
ev_io_start(loop, &udp_accept_watcher);
// ev.events = EPOLLIN;
// ev.data.u64 = raw_recv_fd;
// ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, raw_recv_fd, &ev);
// if (ret!= 0) {
// mylog(log_fatal,"add raw_fd error\n");
// myexit(-1);
// }
#ifdef UDP2RAW_LINUX
struct ev_io raw_recv_watcher;
raw_recv_watcher.data = &conn_info;
ev_io_init(&raw_recv_watcher, raw_recv_cb, raw_recv_fd, EV_READ);
ev_io_start(loop, &raw_recv_watcher);
#endif
#ifdef UDP2RAW_MP
g_default_loop = loop;
async_watcher.data = &conn_info;
ev_async_init(&async_watcher, async_cb);
ev_async_start(loop, &async_watcher);
init_raw_socket(); // must be put after dev detection
#endif
// set_timer(epollfd,timer_fd);
struct ev_timer clear_timer;
clear_timer.data = &conn_info;
ev_timer_init(&clear_timer, clear_timer_cb, 0, timer_interval / 1000.0);
ev_timer_start(loop, &clear_timer);
mylog(log_debug, "send_raw : from %s %d to %s %d\n", send_info.new_src_ip.get_str1(), send_info.src_port, send_info.new_dst_ip.get_str2(), send_info.dst_port);
int fifo_fd = -1;
struct ev_io fifo_watcher;
fifo_watcher.data = &conn_info;
if (fifo_file[0] != 0) {
fifo_fd = create_fifo(fifo_file);
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_run(loop, 0);
return 0;
}

1797
common.cpp

File diff suppressed because it is too large Load Diff

649
common.h

@ -10,57 +10,63 @@
#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<getopt.h>
#include<unistd.h>
#include<errno.h>
//#include <sys/epoll.h>
//#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <stdlib.h> //for exit(0);
#include <errno.h> //For errno - the error number
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <assert.h>
#include <pthread.h>
#if defined(UDP2RAW_MP)
#ifndef USE_LIBNET
#define NO_LIBNET
#endif
#if defined(UDP2RAW_MP)
const int is_udp2raw_mp = 1;
#if !defined(__CYGWIN__) && !defined(__MINGW32__)
#include <pcap.h>
#else
#include <pcap_wrapper.h>
#define NO_LIBNET
#endif
#ifndef NO_LIBNET
#include <libnet.h>
#endif
#include <my_ev.h>
#else
#define UDP2RAW_LINUX
const int is_udp2raw_mp = 0;
//#include <linux/if_ether.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <sys/epoll.h>
#include <sys/wait.h>
//#include <sys/wait.h> //signal
#include <netinet/if_ether.h>
#include <net/if.h>
#include <sys/timerfd.h>
#endif
#if !defined(NO_LIBEV_EMBED)
#include <my_ev.h>
#else
#include "ev.h"
#endif
#if defined(__MINGW32__)
#include <winsock2.h>
#include <ws2ipdef.h>
typedef unsigned char u_int8_t;
typedef unsigned short u_int16_t;
typedef unsigned int u_int32_t;
@ -69,53 +75,51 @@ typedef int socklen_t;
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#endif
#include<unordered_map>
#include <unordered_map>
#include <fstream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <list>
using namespace std;
using namespace std;
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \
defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ || \
defined(__BIG_ENDIAN__) || \
defined(__ARMEB__) || \
defined(__THUMBEB__) || \
defined(__AARCH64EB__) || \
defined(__BIG_ENDIAN__) || \
defined(__ARMEB__) || \
defined(__THUMBEB__) || \
defined(__AARCH64EB__) || \
defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__)
#define UDP2RAW_BIG_ENDIAN 1
#endif
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
#if defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN || \
defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ || \
defined(__LITTLE_ENDIAN__) || \
defined(__ARMEL__) || \
defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
defined(__LITTLE_ENDIAN__) || \
defined(__ARMEL__) || \
defined(__THUMBEL__) || \
defined(__AARCH64EL__) || \
defined(_MIPSEL) || defined(__MIPSEL) || defined(__MIPSEL__)
#define UDP2RAW_LITTLE_ENDIAN 1
#endif
#if defined(UDP2RAW_BIG_ENDIAN) &&defined(UDP2RAW_LITTLE_ENDIAN)
#if defined(UDP2RAW_BIG_ENDIAN) && defined(UDP2RAW_LITTLE_ENDIAN)
#error "endian detection conflicts"
#endif
#if !defined(UDP2RAW_BIG_ENDIAN) && !defined(UDP2RAW_LITTLE_ENDIAN)
#error "endian detection failed"
#endif
#if defined(__MINGW32__)
#define setsockopt(a,b,c,d,e) setsockopt(a,b,c,(const char *)(d),e)
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();
@ -123,20 +127,18 @@ int get_sock_errno();
#if defined(__MINGW32__)
typedef SOCKET my_fd_t;
inline int sock_close(my_fd_t fd)
{
return closesocket(fd);
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);
inline int sock_close(my_fd_t fd) {
return close(fd);
}
#endif
typedef unsigned long long u64_t; //this works on most platform,avoid using the PRId64
typedef unsigned long long u64_t; // this works on most platform,avoid using the PRId64
typedef long long i64_t;
typedef unsigned int u32_t;
@ -155,210 +157,233 @@ typedef u64_t anti_replay_seq_t;
typedef u64_t my_time_t;
const int max_addr_len=100;
const int max_addr_len = 100;
extern int force_socket_buf;
extern int g_fix_gro;
/*
struct ip_port_t
{
u32_t ip;
int port;
void from_u64(u64_t u64);
u64_t to_u64();
char * to_s();
u32_t ip;
int port;
void from_u64(u64_t u64);
u64_t to_u64();
char * to_s();
};*/
typedef u64_t fd64_t;
u32_t djb2(unsigned char *str,int len);
u32_t sdbm(unsigned char *str,int len);
u32_t djb2(unsigned char *str, int len);
u32_t sdbm(unsigned char *str, int len);
struct address_t //TODO scope id
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));
}
};
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 u32_t get_type()
{
u32_t ret=((sockaddr*)&inner)->sa_family;
assert(ret==AF_INET||ret==AF_INET6);
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
union storage_t // sockaddr_storage is too huge, we dont use it.
{
//return this->data==b.data;
return memcmp(&this->inner,&b.inner,sizeof(this->inner))==0;
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 u32_t get_type() {
u32_t ret = ((sockaddr *)&inner)->sa_family;
assert(ret == AF_INET || ret == AF_INET6);
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();
char *get_ip();
};
namespace std {
template <>
struct hash<address_t>
{
std::size_t operator()(const address_t& key) const
{
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));
}
};
} // namespace std
//return address_t::hash_function(k);
return sdbm((unsigned char*)&key.inner,sizeof(key.inner));
}
};
}
union my_ip_t //just a simple version of address_t,stores ip only
union my_ip_t // just a simple version of address_t,stores ip only
{
u32_t v4;
in6_addr v6;
u32_t v4;
in6_addr v6;
bool equal (const my_ip_t &b) const;
bool equal(const my_ip_t &b) const;
//int from_str(char * str);
char * get_str1() const;
char * get_str2() const;
// int from_str(char * str);
char *get_str1() const;
char *get_str2() const;
int from_address_t(address_t a);
};
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;
}
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;
}
};
const int huge_data_len = 65535 + 100; // a packet with link level header might be larger than 65535
const int huge_buf_len = huge_data_len + 100;
const int max_data_len=1800;
const int buf_len=max_data_len+400;
const int max_data_len = 1800;
const int buf_len = max_data_len + 400;
//const int max_address_len=512;
// const int max_address_len=512;
#ifdef UDP2RAW_MP
const int queue_len = 200;
struct queue_t {
char data[queue_len][huge_buf_len];
int data_len[queue_len];
int head = 0;
int tail = 0;
void clear() {
head = tail = 0;
}
int empty() {
if (head == tail)
return 1;
else
return 0;
}
int full() {
if ((tail + 1) % queue_len == head)
return 1;
else
return 0;
}
void peek_front(char *&p, int &len) {
assert(!empty());
p = data[head];
len = data_len[head];
}
void pop_front() {
assert(!empty());
head++;
head %= queue_len;
}
void push_back(char *p, int len) {
assert(!full());
memcpy(data[tail], p, len);
data_len[tail] = len;
tail++;
tail %= queue_len;
}
};
int init_ws();
#endif
u64_t get_current_time();
u64_t pack_u64(u32_t a,u32_t b);
u64_t pack_u64(u32_t a, u32_t b);
u32_t get_u64_h(u64_t a);
u32_t get_u64_l(u64_t a);
char * my_ntoa(u32_t ip);
char *my_ntoa(u32_t ip);
void init_random_number_fd();
u64_t get_true_random_number_64();
@ -367,143 +392,131 @@ u32_t get_true_random_number_nz();
u64_t ntoh64(u64_t a);
u64_t hton64(u64_t a);
void write_u16(char *,u16_t a);// network order
void write_u16(char *, u16_t a); // network order
u16_t read_u16(char *);
void write_u32(char *,u32_t a);// network order
void write_u32(char *, u32_t a); // network order
u32_t read_u32(char *);
void write_u64(char *, u64_t a);
u64_t read_u64(char *);
void write_u64(char *,u64_t a);
u64_t read_uu64(char *);
bool larger_than_u16(uint16_t a,uint16_t b);
bool larger_than_u32(u32_t a,u32_t b);
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 socket_buf_size);
void myexit(int a);
unsigned short csum(const unsigned short *ptr,int nbytes);
unsigned short csum_with_header(char* header,int hlen,const unsigned short *ptr,int nbytes);
unsigned short csum(const unsigned short *ptr, int nbytes);
unsigned short csum_with_header(char *header, int hlen, const unsigned short *ptr, int nbytes);
int numbers_to_char(my_id_t id1,my_id_t id2,my_id_t id3,char * &data,int &len);
int char_to_numbers(const char * data,int len,my_id_t &id1,my_id_t &id2,my_id_t &id3);
int numbers_to_char(my_id_t id1, my_id_t id2, my_id_t id3, char *&data, int &len);
int char_to_numbers(const char *data, int len, my_id_t &id1, my_id_t &id2, my_id_t &id3);
const int show_none=0;
const int show_command=0x1;
const int show_log=0x2;
const int show_all=show_command|show_log;
const int show_none = 0;
const int show_command = 0x1;
const int show_log = 0x2;
const int show_all = show_command | show_log;
int run_command(string command,char * &output,int flag=show_all);
//int run_command_no_log(string command,char * &output);
int read_file(const char * file,string &output);
int run_command(string command, char *&output, int flag = show_all);
// int run_command_no_log(string command,char * &output);
int read_file(const char *file, string &output);
vector<string> string_to_vec(const char * s,const char * sp);
vector< vector <string> > string_to_vec2(const char * s);
vector<string> string_to_vec(const char *s, const char *sp);
vector<vector<string> > string_to_vec2(const char *s);
string trim(const string& str, char c);
string trim(const string &str, char c);
string trim_conf_line(const string& str);
string trim_conf_line(const string &str);
vector<string> parse_conf_line(const string& s);
vector<string> parse_conf_line(const string &s);
int hex_to_u32_with_endian(const string & a,u32_t &output);
int hex_to_u32(const string & a,u32_t &output);
//extern string iptables_pattern;
int hex_to_u32_with_endian(const string &a, u32_t &output);
int hex_to_u32(const string &a, u32_t &output);
// extern string iptables_pattern;
int create_fifo(char * file);
void print_binary_chars(const char * a,int len);
int create_fifo(char *file);
void print_binary_chars(const char *a, int len);
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;
};
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;
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);
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();
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());
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();
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;
}
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);
}*/
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);
}*/
};
#endif /* COMMON_H_ */

File diff suppressed because it is too large Load Diff

@ -16,335 +16,298 @@ extern int disable_anti_replay;
#include "network.h"
#include "misc.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_conv_clear = 0; // a udp connection in the multiplexer is called conversation in this program,conv for short.
struct anti_replay_t //its for anti replay attack,similar to openvpn/ipsec 's anti replay window
struct anti_replay_t // its for anti replay attack,similar to openvpn/ipsec 's anti replay window
{
u64_t max_packet_received;
char window[anti_replay_window_size];
anti_replay_seq_t anti_replay_seq;
anti_replay_seq_t get_new_seq_for_send();
anti_replay_t();
void re_init();
u64_t max_packet_received;
char window[anti_replay_window_size];
anti_replay_seq_t anti_replay_seq;
anti_replay_seq_t get_new_seq_for_send();
anti_replay_t();
void re_init();
int is_vaild(u64_t seq);
};//anti_replay;
int is_vaild(u64_t seq);
}; // anti_replay;
void server_clear_function(u64_t u64);
#include <type_traits>
template <class T>
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;
// 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;
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;
// unordered_map<u32_t,u64_t>::iterator clear_it;
void (*additional_clear_function)(T data) =0;
void (*additional_clear_function)(T data) = 0;
long long last_clear_time;
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);
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 ;
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();
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();
lru.clear();
// conv_last_active_time.clear();
//clear_it=conv_last_active_time.begin();
// clear_it=conv_last_active_time.begin();
}
u32_t get_new_conv() {
u32_t conv = get_true_random_number_nz();
while (conv_to_data.find(conv) != conv_to_data.end()) {
conv = get_true_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;
}
u32_t get_new_conv()
{
u32_t conv=get_true_random_number_nz();
while(conv_to_data.find(conv)!=conv_to_data.end())
{
conv=get_true_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
unordered_map<u32_t,u64_t>::iterator it;
unordered_map<u32_t,u64_t>::iterator old_it;
num_to_clean = min(num_to_clean, size);
//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
my_time_t current_time = get_current_time();
for (;;) {
if (cnt >= num_to_clean) break;
if (lru.empty()) break;
num_to_clean=min(num_to_clean,size);
u32_t conv;
my_time_t ts = lru.peek_back(conv);
my_time_t current_time=get_current_time();
for(;;)
{
if(cnt>=num_to_clean) break;
if(lru.empty()) break;
if (current_time - ts < conv_timeout) break;
u32_t conv;
my_time_t ts=lru.peek_back(conv);
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;
}
if(current_time- ts < conv_timeout) break;
/*
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;
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 blob_t:not_copy_able_t //used in conn_info_t.
struct blob_t : not_copy_able_t // used in conn_info_t.
{
union tmp_union_t//conv_manager_t is here to avoid copying when a connection is recovered
{
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;
union tmp_union_t // conv_manager_t is here to avoid copying when a connection is recovered
{
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;
anti_replay_t anti_replay;//anti_replay_t is here bc its huge,its allocation is delayed.
anti_replay_t anti_replay; // anti_replay_t is here bc its huge,its allocation is delayed.
};
struct conn_info_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
struct conn_info_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
{
current_state_t state;
current_state_t state;
raw_info_t raw_info;
u64_t last_state_time;
u64_t last_hb_sent_time; //client re-use this for retry
u64_t last_hb_recv_time;
//long long last_resent_time;
raw_info_t raw_info;
u64_t last_state_time;
u64_t last_hb_sent_time; // client re-use this for retry
u64_t last_hb_recv_time;
// long long last_resent_time;
my_id_t my_id;
my_id_t oppsite_id;
my_id_t my_id;
my_id_t oppsite_id;
fd64_t timer_fd64;
fd64_t udp_fd64;
fd64_t timer_fd64;
fd64_t udp_fd64;
my_id_t oppsite_const_id;
my_id_t oppsite_const_id;
blob_t *blob;
blob_t *blob;
uint8_t my_roller;
uint8_t oppsite_roller;
u64_t last_oppsite_roller_time;
uint8_t my_roller;
uint8_t oppsite_roller;
u64_t last_oppsite_roller_time;
// ip_port_t ip_port;
// ip_port_t ip_port;
/*
const uint32_t &ip=raw_info.recv_info.src_ip;
const uint16_t &port=raw_info.recv_info.src_port;
/*
const uint32_t &ip=raw_info.recv_info.src_ip;
const uint16_t &port=raw_info.recv_info.src_port;
*/
void recover(const conn_info_t &conn_info);
void re_init();
conn_info_t();
void prepare();
conn_info_t(const conn_info_t &b);
conn_info_t &operator=(const conn_info_t &b);
~conn_info_t();
}; // g_conn_info;
*/
void recover(const conn_info_t &conn_info);
void re_init();
conn_info_t();
void prepare();
conn_info_t(const conn_info_t&b);
conn_info_t& operator=(const conn_info_t& b);
~conn_info_t();
};//g_conn_info;
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
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
{
u32_t ready_num;
u32_t ready_num;
// unordered_map<int,conn_info_t *> udp_fd_mp; //a bit dirty to used pointer,but can void unordered_map search
// unordered_map<int,conn_info_t *> timer_fd_mp;//we can use pointer here since unordered_map.rehash() uses shallow copy
//unordered_map<int,conn_info_t *> udp_fd_mp; //a bit dirty to used pointer,but can void unordered_map search
//unordered_map<int,conn_info_t *> timer_fd_mp;//we can use pointer here since unordered_map.rehash() uses shallow copy
unordered_map<my_id_t, conn_info_t *> const_id_mp;
unordered_map<my_id_t,conn_info_t *> const_id_mp;
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*> mp; //put it at end so that it de-consturcts first
// lru_collector_t<address_t> lru;
//lru_collector_t<address_t> lru;
unordered_map<address_t, conn_info_t *>::iterator clear_it;
unordered_map<address_t,conn_info_t*>::iterator clear_it;
long long last_clear_time;
long long last_clear_time;
conn_manager_t();
int exist(address_t addr);
/*
int insert(uint32_t ip,uint16_t port)
{
uint64_t u64=0;
u64=ip;
u64<<=32u;
u64|=port;
mp[u64];
return 0;
}*/
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();
conn_manager_t();
int exist(address_t addr);
/*
int insert(uint32_t ip,uint16_t port)
{
uint64_t u64=0;
u64=ip;
u64<<=32u;
u64|=port;
mp[u64];
return 0;
}*/
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;
void server_clear_function(u64_t u64);
int send_bare(raw_info_t &raw_info,const char* data,int len);//send function with encryption but no anti replay,this is used when client and server verifys each other
//you have to design the protocol carefully, so that you wont be affect by relay attack
//int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare
int recv_bare(raw_info_t &raw_info,char* & data,int & len);//recv function with encryption but no anti replay,this is used when client and server verifys each other
//you have to design the protocol carefully, so that you wont be affect by relay attack
int send_handshake(raw_info_t &raw_info,my_id_t id1,my_id_t id2,my_id_t id3);// a warp for send_bare for sending handshake(this is not tcp handshake) easily
int send_safer(conn_info_t &conn_info,char type,const char* data,int len); //safer transfer function with anti-replay,when mutually verification is done.
int send_data_safer(conn_info_t &conn_info,const char* data,int len,u32_t conv_num);//a wrap for send_safer for transfer data.
//int reserved_parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len);//subfunction for recv_safer,allow overlap
int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len);///safer transfer function with anti-replay,when mutually verification is done.
#endif /* CONNECTION_H_ */
int send_bare(raw_info_t &raw_info, const char *data, int len); // send function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
// int reserved_parse_bare(const char *input,int input_len,char* & data,int & len); // a sub function used in recv_bare
int recv_bare(raw_info_t &raw_info, char *&data, int &len); // recv function with encryption but no anti replay,this is used when client and server verifys each other
// you have to design the protocol carefully, so that you wont be affect by relay attack
int send_handshake(raw_info_t &raw_info, my_id_t id1, my_id_t id2, my_id_t id3); // a warp for send_bare for sending handshake(this is not tcp handshake) easily
int send_safer(conn_info_t &conn_info, char type, const char *data, int len); // safer transfer function with anti-replay,when mutually verification is done.
int send_data_safer(conn_info_t &conn_info, const char *data, int len, u32_t conv_num); // a wrap for send_safer for transfer data.
// int reserved_parse_safer(conn_info_t &conn_info,const char * input,int input_len,char &type,char* &data,int &len);//subfunction for recv_safer,allow overlap
// int recv_safer(conn_info_t &conn_info,char &type,char* &data,int &len);///safer transfer function with anti-replay,when mutually verification is done.
int recv_safer_multi(conn_info_t &conn_info, vector<char> &type_arr, vector<string> &data_arr); // new api for handle gro
#endif /* CONNECTION_H_ */

@ -14,21 +14,19 @@ udp2raw tunnel通过raw socket给UDP包加上TCP或ICMP header进而绕过
**提示:**
udp2raw不是加速器只是一个帮助你绕过UDP限制的工具。如果你需要UDP加速器请看UDPspeeder。
udp2raw不是加速器只是一个帮助你绕过UDP限制的工具。如果你需要UDP加速器” (改善UDP丢包)请看UDPspeeder。
UDPspeeder的repo:
https://github.com/wangyu-/UDPspeeder
# 支持的平台
Linux主机有root权限。可以是PC、android手机/平板、openwrt路由器、树莓派。主机上最好安装了iptables命令(apt/yum很容易安装)。
Linux主机有root权限或cap_net_raw capability.。可以是PC、android手机/平板、openwrt路由器、树莓派。主机上最好安装了iptables命令(apt/yum很容易安装)。
Release中提供了`amd64`、`x86`、`arm`、`mips_be`、`mips_le`的预编译binary.
##### 对于windows和mac用户
可以用[这个repo](https://github.com/wangyu-/udp2raw-multiplatform)里的udp2raw原生运行。
<del>可以把udp2raw运行在虚拟机上(网络必须是桥接模式)。可以参考: https://github.com/wangyu-/udp2raw-tunnel/wiki/在windows-mac上运行udp2raw客户端带图形界面 </del>
可以用[这个repo](https://github.com/wangyu-/udp2raw-multiplatform)里的udp2raw。
##### 对于ios和游戏主机用户
@ -44,10 +42,10 @@ Release中提供了`amd64`、`x86`、`arm`、`mips_be`、`mips_le`的预编译bi
### 心跳保活、自动重连,连接恢复
心跳保活、自动重连udp2raw重连可以恢复上次的连接重连后上层连接继续有效底层掉线上层不掉线。有效解决上层连接断开的问题。 (功能借鉴自[kcptun-raw](https://github.com/Chion82/kcptun-raw)**就算你拔掉网线重插或者重新拨号获得新ip上层应用也不会断线**
### 加密 防重放攻击
### 加密防重放攻击
用aes128cbc加密(或更弱的xor)hmac-sha1(或更弱的md5/crc32/simple)做数据完整校验。用类似ipsec/openvpn的replay window机制来防止重放攻击。
设计目标是即使攻击者可以监听到tunnel的所有包可以选择性丢弃tunnel的任意包可以重放任意包攻击者也没办法获得tunnel承载的任何数据也没办法向tunnel的数据流中通过包构造/包重放插入任何数据。
[Notes on encryption](https://github.com/wangyu-/udp2raw-tunnel/wiki/Notes-on-encryption)
### 其他特性
信道复用client的udp端支持多个连接。
@ -56,7 +54,7 @@ server支持多个client也能正确处理多个连接的重连和连接恢
NAT 穿透 tcp icmp udp模式都支持nat穿透。
支持Openvz配合finalspeed使用可以在openvz上用tcp模式的finalspeed
支持Openvz配合finalspeed使用可以在openvz上用tcp模式的finalspeed.
支持Openwrt没有编译依赖容易编译到任何平台上。
@ -113,10 +111,10 @@ usage:
run as server : ./this_program -s -l server_listen_ip:server_port -r remote_address:remote_port [options]
common options,these options must be same on both side:
--raw-mode <string> avaliable values:faketcp(default),udp,icmp
--raw-mode <string> available values:faketcp(default),udp,icmp
-k,--key <string> password to gen symetric key,default:"secret key"
--cipher-mode <string> avaliable values:aes128cbc(default),xor,none
--auth-mode <string> avaliable values:hmac_sha1,md5(default),crc32,simple,none
--cipher-mode <string> available values:aes128cbc(default),xor,none
--auth-mode <string> available values:hmac_sha1,md5(default),crc32,simple,none
-a,--auto-rule auto add (and delete) iptables rule
-g,--gen-rule generate iptables rule then exit,so that you can copy and
add it manually.overrides -a
@ -163,7 +161,7 @@ other options:
如果要最大的安全性建议用aes128cbc+hmac_sha1。如果要运行在路由器上建议用xor+simple可以节省CPU。但是注意xor+simple只能骗过防火墙的包检测不能防止真正的攻击者。
### `--seq-mode`
facktcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和真正的tcp流量区分开来虽然大部分ISP不太可能做这种程度的包检测。seq-mode可以改变一些seq ack的行为。如果遇到了连接问题可以尝试更改。在我这边的移动线路用3种模式都没问题。
faketcp模式并没有模拟tcp的全部。所以理论上有办法把faketcp和真正的tcp流量区分开来虽然大部分ISP不太可能做这种程度的包检测。seq-mode可以改变一些seq ack的行为。如果遇到了连接问题可以尝试更改。在我这边的移动线路用3种模式都没问题。
### `--keep-rule`
定期主动检查iptables如果udp2raw添加的iptables规则丢了就重新添加。在一些iptables可能会被其他程序清空的情况下(比如梅林固件和openwrt的路由器)格外有用。
@ -264,25 +262,6 @@ raw_mode: faketcp cipher_mode: aes128cbc  auth_mode: md5
[udp2raw+kcptun step_by_step教程](kcptun_step_by_step.md)
### 中转 finalspeed
[udp2raw+finalspeed step_by_step教程](finalspeed_step_by_step.md)
# 如何自己编译
[编译教程](build_guide.zh-cn.md)
# 相关repo
### kcptun-raw
udp2raw was inspired by kcptun-raw,which modified kcptun to support tcp mode.
https://github.com/Chion82/kcptun-raw
### relayRawSocket
kcptun-raw was inspired by relayRawSocket. A simple udp to raw tunnel,wrote in python
https://github.com/linhua55/some_kcptun_tools/tree/master/relayRawSocket
### kcpraw
another project of kcptun with tcp mode
https://github.com/ccsexyz/kcpraw
### icmptunnel
Transparently tunnel your IP traffic through ICMP echo and reply packets.
https://github.com/DhavalKapil/icmptunnel
# wiki

930
encrypt.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

44
encrypt.h Executable file → Normal file

@ -1,32 +1,35 @@
#ifndef UDP2RAW_ENCRYPTION_H_
#define UDP2RAW_ENCRYPTION_H_
//#include "aes.h"
//#include "md5.h"
#include "common.h"
// using namespace std;
// extern char key[16];
//using namespace std;
//extern char key[16];
const int aes_key_optimize = 1; // if enabled,once you used a key for aes,you cant change it anymore
extern int aes128cfb_old;
const int aes_key_optimize=1; //if enabled,once you used a key for aes,you cant change it anymore
int my_init_keys(const char *, int);
int my_init_keys(const char *,int);
int my_encrypt(const char *data, char *output, int &len);
int my_decrypt(const char *data, char *output, int &len);
int my_encrypt(const char *data,char *output,int &len);
int my_decrypt(const char *data,char *output,int &len);
unsigned short csum(const unsigned short *ptr, int nbytes);
enum auth_mode_t { auth_none = 0,
auth_md5,
auth_crc32,
auth_simple,
auth_hmac_sha1,
auth_end };
unsigned short csum(const unsigned short *ptr,int nbytes) ;
enum auth_mode_t {auth_none=0,auth_md5,auth_crc32,auth_simple,auth_hmac_sha1,auth_end};
enum cipher_mode_t {cipher_none=0,cipher_aes128cbc,cipher_xor,cipher_aes128cfb,cipher_end};
enum cipher_mode_t { cipher_none = 0,
cipher_aes128cbc,
cipher_xor,
cipher_aes128cfb,
cipher_end };
extern auth_mode_t auth_mode;
extern cipher_mode_t cipher_mode;
@ -34,10 +37,15 @@ extern cipher_mode_t cipher_mode;
extern unordered_map<int, const char *> auth_mode_tostring;
extern unordered_map<int, const char *> cipher_mode_tostring;
extern char gro_xor[256 + 100];
int cipher_decrypt(const char *data, char *output, int &len, char *key); // internal interface ,exposed for test only
int cipher_encrypt(const char *data, char *output, int &len, char *key); // internal interface ,exposed for test only
void aes_ecb_encrypt(const char *data, char *output);
void aes_ecb_decrypt(const char *data, char *output);
int cipher_decrypt(const char *data,char *output,int &len,char * key);//internal interface ,exposed for test only
int cipher_encrypt(const char *data,char *output,int &len,char * key);//internal interface ,exposed for test only
void aes_ecb_encrypt1(char *data);
void aes_ecb_decrypt1(char *data);
#endif

@ -5,59 +5,49 @@
* 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::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::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];
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);
}
assert(close(fd)==0);
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);
}
// assert(close(fd)==0);
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);
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;
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_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];
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();
int fd_manager_t::exist_info(fd64_t fd64) {
return fd_info_mp.find(fd64) != fd_info_mp.end();
}

@ -12,31 +12,31 @@
//#include "packet.h"
#include "connection.h"
struct fd_info_t
{
//ip_port_t ip_port;
conn_info_t *p_conn_info;
struct fd_info_t {
// ip_port_t ip_port;
conn_info_t *p_conn_info;
};
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
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);
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;

@ -7,9 +7,8 @@
#include <stdint.h>
//not used
//void AES_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length);
//void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length);
void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output);
void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output);
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);
void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);

@ -366,32 +366,25 @@ void AES_CBC_decrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, co
decrypt_cbc(rk, length, iv_tmp, input, output);
}
/*
void AES_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t* output, const uint32_t length)
void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t* output)
{
uint8_t rk[AES_RKSIZE];
static uint8_t rk[AES_RKSIZE];
if (key == NULL)
{
return;
}
aeshw_init();
setkey_enc(rk, key);
if(key!=NULL)
setkey_enc(rk, key);
encrypt_ecb(AES_NR, rk, input, output);
}
void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length)
void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output)
{
uint8_t rk[AES_RKSIZE];
static uint8_t rk[AES_RKSIZE];
if (key == NULL)
{
return;
}
aeshw_init();
setkey_dec(rk, key);
if(key!=NULL)
setkey_dec(rk, key);
decrypt_ecb(AES_NR, rk, input, output);
}*/
}
static void encrypt_cfb( uint8_t* rk,
uint32_t length,size_t *iv_off,

@ -12,15 +12,29 @@
#endif
void AES_ECB_encrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length)
void AES_ECB_encrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output)
{
printf("AES_ECB_encrypt not implemented\n");
exit(-1);
static aes_context ctx;
if(key!=0)
{
aes_init( &ctx);
aes_setkey_enc(&ctx,key,AES_KEYSIZE);
}
int ret=aes_crypt_ecb( &ctx, AES_ENCRYPT, (const unsigned char*)input,(unsigned char*) output );
assert(ret==0);
return ;
}
void AES_ECB_decrypt(const uint8_t* input, const uint8_t* key, uint8_t *output, const uint32_t length)
void AES_ECB_decrypt_buffer(const uint8_t* input, const uint8_t* key, uint8_t *output)
{
printf("AES_ECB_encrypt not implemented\n");
exit(-1);
static aes_context ctx;
if(key!=0)
{
aes_init( &ctx);
aes_setkey_dec(&ctx,key,AES_KEYSIZE);
}
int ret=aes_crypt_ecb( &ctx, AES_DECRYPT, (const unsigned char*)input,(unsigned char*) output );
assert(ret==0);
return ;
}
void AES_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv)

31
libev/CVS/Entries Normal file

@ -0,0 +1,31 @@
/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
libev/CVS/Repository Normal file

@ -0,0 +1 @@
libev

1
libev/CVS/Root Normal file

@ -0,0 +1 @@
:pserver:anonymous@cvs.schmorp.de/schmorpforge

517
libev/Changes Normal file

@ -0,0 +1,517 @@
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.

37
libev/LICENSE Normal file

@ -0,0 +1,37 @@
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.

20
libev/Makefile.am Normal file

@ -0,0 +1,20 @@
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 Normal file

@ -0,0 +1,58 @@
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

3
libev/README.embed Normal file

@ -0,0 +1,3 @@
This file is now included in the main libev documentation, see
http://cvs.schmorp.de/libev/ev.html

73
libev/Symbols.ev Normal file

@ -0,0 +1,73 @@
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

24
libev/Symbols.event Normal file

@ -0,0 +1,24 @@
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

3
libev/autogen.sh Normal file

@ -0,0 +1,3 @@
#!/bin/sh
autoreconf --install --symlink --force

27
libev/configure.ac Normal file

@ -0,0 +1,27 @@
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 Normal file

@ -0,0 +1,816 @@
/*
* 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 Normal file

File diff suppressed because it is too large Load Diff

5144
libev/ev.c Normal file

File diff suppressed because it is too large Load Diff

854
libev/ev.h Normal file

@ -0,0 +1,854 @@
/*
* 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 Normal file

File diff suppressed because it is too large Load Diff

285
libev/ev_epoll.c Normal file

@ -0,0 +1,285 @@
/*
* 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);
}

218
libev/ev_kqueue.c Normal file

@ -0,0 +1,218 @@
/*
* 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 Normal file

@ -0,0 +1,151 @@
/*
* 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 Normal file

@ -0,0 +1,189 @@
/*
* 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);
}

316
libev/ev_select.c Normal file

@ -0,0 +1,316 @@
/*
* 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 Normal file

@ -0,0 +1,204 @@
/*
* 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 Normal file

@ -0,0 +1,162 @@
/*
* 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 Normal file

@ -0,0 +1,200 @@
/* 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 Normal file

@ -0,0 +1,425 @@
/*
* 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 Normal file

@ -0,0 +1,177 @@
/*
* 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

226
libev/event_compat.h Normal file

@ -0,0 +1,226 @@
/*
* 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

131
libev/import_libevent Executable file

@ -0,0 +1,131 @@
#!/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 "$@"

42
libev/libev.m4 Normal file

@ -0,0 +1,42 @@
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)])

8
libev/update_ev_c Executable file

@ -0,0 +1,8 @@
#!/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

19
libev/update_ev_wrap Executable file

@ -0,0 +1,19 @@
#!/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

7
libev/update_symbols Executable file

@ -0,0 +1,7 @@
#!/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

87
log.cpp Executable file → Normal file

@ -1,62 +1,57 @@
#include "log.h"
#include "misc.h"
int log_level=log_info;
int log_level = log_info;
int enable_log_position=0;
int enable_log_color=1;
int enable_log_position = 0;
int enable_log_color = 1;
void log0(const char * file,const char * function,int line,int level,const char* str, ...) {
void log0(const char* file, const char* function, int line, int level, const char* str, ...) {
if (level > log_level) return;
if (level > log_trace || level < 0) return;
if(level>log_level) return ;
if(level>log_trace||level<0) return ;
time_t timer;
char buffer[100];
struct tm* tm_info;
time(&timer);
tm_info = localtime(&timer);
time_t timer;
char buffer[100];
struct tm* tm_info;
if (enable_log_color)
printf("%s", log_color[level]);
time(&timer);
tm_info = localtime(&timer);
strftime(buffer, 100, "%Y-%m-%d %H:%M:%S", tm_info);
printf("[%s][%s]", buffer, log_text[level]);
if(enable_log_color)
printf("%s",log_color[level]);
if (enable_log_position) printf("[%s,func:%s,line:%d]", file, function, line);
strftime(buffer, 100, "%Y-%m-%d %H:%M:%S", tm_info);
printf("[%s][%s]",buffer,log_text[level]);
va_list vlist;
va_start(vlist, str);
vfprintf(stdout, str, vlist);
va_end(vlist);
if (enable_log_color)
printf("%s", RESET);
if(enable_log_position)printf("[%s,func:%s,line:%d]",file,function,line);
// printf("\n");
// if(enable_log_color)
// printf(log_color[level]);
fflush(stdout);
va_list vlist;
va_start(vlist, str);
vfprintf(stdout, str, vlist);
va_end(vlist);
if(enable_log_color)
printf("%s",RESET);
//printf("\n");
//if(enable_log_color)
//printf(log_color[level]);
fflush(stdout);
if(log_level==log_fatal)
{
about_to_exit=1;
}
if (log_level == log_fatal) {
about_to_exit = 1;
}
}
void log_bare(int level,const char* str, ...)
{
if(level>log_level) return ;
if(level>log_trace||level<0) return ;
if(enable_log_color)
printf("%s",log_color[level]);
va_list vlist;
va_start(vlist, str);
vfprintf(stdout, str, vlist);
va_end(vlist);
if(enable_log_color)
printf("%s",RESET);
fflush(stdout);
void log_bare(int level, const char* str, ...) {
if (level > log_level) return;
if (level > log_trace || level < 0) return;
if (enable_log_color)
printf("%s", log_color[level]);
va_list vlist;
va_start(vlist, str);
vfprintf(stdout, str, vlist);
va_end(vlist);
if (enable_log_color)
printf("%s", RESET);
fflush(stdout);
}

49
log.h Executable file → Normal file

@ -2,53 +2,46 @@
#ifndef UDP2RAW_LOG_MYLOG_H_
#define UDP2RAW_LOG_MYLOG_H_
#include "common.h"
using namespace std;
#define RED "\x1B[31m"
#define GRN "\x1B[32m"
#define YEL "\x1B[33m"
#define BLU "\x1B[34m"
#define MAG "\x1B[35m"
#define CYN "\x1B[36m"
#define WHT "\x1B[37m"
#define RED "\x1B[31m"
#define GRN "\x1B[32m"
#define YEL "\x1B[33m"
#define BLU "\x1B[34m"
#define MAG "\x1B[35m"
#define CYN "\x1B[36m"
#define WHT "\x1B[37m"
#define RESET "\x1B[0m"
const int log_never = 0;
const int log_fatal = 1;
const int log_error = 2;
const int log_warn = 3;
const int log_info = 4;
const int log_debug = 5;
const int log_trace = 6;
const int log_end = 7;
const int log_never=0;
const int log_fatal=1;
const int log_error=2;
const int log_warn=3;
const int log_info=4;
const int log_debug=5;
const int log_trace=6;
const int log_end=7;
const char log_text[][20]={"NEVER","FATAL","ERROR","WARN","INFO","DEBUG","TRACE",""};
const char log_color[][20]={RED,RED,RED,YEL,GRN,MAG,""};
const char log_text[][20] = {"NEVER", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE", ""};
const char log_color[][20] = {RED, RED, RED, YEL, GRN, MAG, ""};
extern int log_level;
extern int enable_log_position;
extern int enable_log_color;
#ifdef MY_DEBUG
#define mylog(__first_argu__dummy_abcde__,...) printf(__VA_ARGS__)
#define mylog(__first_argu__dummy_abcde__, ...) printf(__VA_ARGS__)
#else
#define mylog(...) log0(__FILE__,__FUNCTION__,__LINE__,__VA_ARGS__)
#define mylog(...) log0(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#endif
//#define mylog(__first_argu__dummy_abcde__,...) {;}
void log0(const char * file,const char * function,int line,int level,const char* str, ...);
void log_bare(int level,const char* str, ...);
void log0(const char* file, const char* function, int line, int level, const char* str, ...);
void log_bare(int level, const char* str, ...);
#endif

1914
main.cpp Executable file → Normal file

File diff suppressed because it is too large Load Diff

145
makefile

@ -1,91 +1,134 @@
cc_cross=/home/wangyu/Desktop/arm-2014.05/bin/arm-none-linux-gnueabi-g++
cc_local=g++
#cc_local=/opt/cross/x86_64-linux-musl/bin/x86_64-linux-musl-g++
#cc_mips34kc=/toolchains/OpenWrt-SDK-ar71xx-for-linux-x86_64-gcc-4.8-linaro_uClibc-0.9.33.2/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mips-openwrt-linux-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/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bin/arm-linux-gnueabi-g++ -march=armv6 -marm
cc_arm= /toolchains/arm-2014.05/bin/arm-none-linux-gnueabi-g++
#cc_arm=/toolchains/lede-sdk-17.01.2-brcm2708-bcm2708_gcc-5.4.0_musl-1.1.16_eabi.Linux-x86_64/staging_dir/toolchain-arm_arm1176jzf-s+vfp_gcc-5.4.0_musl-1.1.16_eabi/bin/arm-openwrt-linux-muslgnueabi-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++
FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers ${OPT}
COMMON=main.cpp lib/md5.cpp lib/pbkdf2-sha1.cpp lib/pbkdf2-sha256.cpp encrypt.cpp log.cpp network.cpp common.cpp connection.cpp misc.cpp fd_manager.cpp -lpthread
SOURCES= $(COMMON) lib/aes_faster_c/aes.cpp lib/aes_faster_c/wrapper.cpp
SOURCES_TINY_AES= $(COMMON) lib/aes.c
SOURCES_AES_ACC=$(COMMON) $(wildcard lib/aes_acc/aes*.c)
FLAGS= -std=c++11 -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers ${OPT}
COMMON=main.cpp lib/md5.cpp lib/pbkdf2-sha1.cpp lib/pbkdf2-sha256.cpp encrypt.cpp log.cpp network.cpp common.cpp connection.cpp misc.cpp fd_manager.cpp client.cpp server.cpp -lpthread
SOURCES0= $(COMMON) lib/aes_faster_c/aes.cpp lib/aes_faster_c/wrapper.cpp
SOURCES= ${SOURCES0} my_ev.cpp -isystem libev
SOURCES_AES_ACC= $(COMMON) $(wildcard lib/aes_acc/aes*.c) my_ev.cpp -isystem libev
PCAP="-lpcap"
MP="-DUDP2RAW_MP"
NAME=udp2raw
TARGETS=amd64 arm amd64_hw_aes arm_asm_aes mips24kc_be mips24kc_be_asm_aes x86 x86_asm_aes mips24kc_le mips24kc_le_asm_aes
TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/udp2raw_\1/g'` version.txt
TARGETS=amd64 arm amd64_hw_aes arm_asm_aes mips24kc_be mips24kc_be_asm_aes x86 x86_asm_aes mips24kc_le mips24kc_le_asm_aes
TAR=${NAME}_binaries.tar.gz `echo ${TARGETS}|sed -r 's/([^ ]+)/${NAME}_\1/g'` version.txt
TARGETS_MP= mingw_cross mingw_cross_wepoll mac_cross
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 -O3
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -ggdb -static -O2
#dynamic link
dynamic: git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -O2
#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
${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
${cc_local} -o ${NAME} -I. ${SOURCES} ${FLAGS} -lrt -Wformat-nonliteral -ggdb -fsanitize=address
dynamic: git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -O3
#targets only for 'make release'
mips24kc_be: git_version
${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3
${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O2
mips24kc_be_asm_aes: git_version
${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -lgcc_eh -static -O3 lib/aes_acc/asm/mips_be.S
${cc_mips24kc_be} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -lgcc_eh -static -O2 lib/aes_acc/asm/mips_be.S
mips24kc_le: git_version
${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O3
${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -lgcc_eh -static -O2
mips24kc_le_asm_aes: git_version
${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -lgcc_eh -static -O3 lib/aes_acc/asm/mips.S
#bcm2708:
# ${cc_bcm2708} -o ${NAME}_bcm2708 -I. ${SOURCES} ${FLAGS} -lrt -static -O3
${cc_mips24kc_le} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -lgcc_eh -static -O2 lib/aes_acc/asm/mips.S
amd64:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
amd64_perf:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O0 -fno-omit-frame-pointer -g
${cc_amd64} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh -ggdb
amd64_hw_aes:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O3 lib/aes_acc/asm/x64.S
${cc_amd64} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O2 lib/aes_acc/asm/x64.S -lgcc_eh -ggdb
x86:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3 -m32
${cc_x86} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh -ggdb
x86_asm_aes:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O3 -m32 lib/aes_acc/asm/x86.S
${cc_x86} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O2 lib/aes_acc/asm/x86.S -lgcc_eh -ggdb
arm:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O3
arm_perf:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -mapcs-frame -fno-omit-frame-pointer -g -O0 -lgcc_eh
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES} ${FLAGS} -lrt -static -O2 -lgcc_eh
arm_asm_aes:git_version
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O3 lib/aes_acc/asm/arm.S
${cc_arm} -o ${NAME}_$@ -I. ${SOURCES_AES_ACC} ${FLAGS} -lrt -static -O2 lib/aes_acc/asm/arm.S -lgcc_eh
cross:git_version
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -O3
cross2:git_version
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -lgcc_eh -O3
cross3:git_version
${cc_cross} -o ${NAME}_cross -I. ${SOURCES} ${FLAGS} -lrt -static -O3
release: ${TARGETS}
release: ${TARGETS}
cp git_version.h version.txt
tar -zcvf ${TAR}
#targets for multi-platform version (native compile)
cygwin:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} pcap_wrapper.cpp ${FLAGS} -lrt -ggdb -static -O2 -D_GNU_SOURCE ${MP}
mingw:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} pcap_wrapper.cpp ${FLAGS} -ggdb -static -O2 -lws2_32 ${MP}
mingw_wepoll:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES0} pcap_wrapper.cpp ${FLAGS} -ggdb -static -O2 -DNO_LIBEV_EMBED -D_WIN32 -lev -lws2_32 ${MP}
linux:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${PCAP} ${FLAGS} -lrt -ggdb -static -O2 ${MP}
freebsd:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${PCAP} ${FLAGS} -lrt -ggdb -static -libverbs -O2 ${MP}
mac:git_version
${cc_local} -o ${NAME}_$@ -I. ${SOURCES} ${PCAP} ${FLAGS} -ggdb -O2 ${MP}
#targets for multi-platform version (cross compile)
mingw_cross:git_version
${cc_mingw_cross} -o ${NAME}_mp.exe -I. ${SOURCES} pcap_wrapper.cpp ${FLAGS} -ggdb -static -O2 -lws2_32 ${MP}
mingw_cross_wepoll:git_version
${cc_mingw_cross} -o ${NAME}_mp_wepoll.exe -I. ${SOURCES0} pcap_wrapper.cpp ${FLAGS} -ggdb -static -O2 -DNO_LIBEV_EMBED -D_WIN32 -lev -lws2_32 ${MP}
mac_cross:git_version
${cc_mac_cross} -o ${NAME}_mp_mac -I. ${SOURCES} ${PCAP} ${FLAGS} -ggdb -O2 ${MP}
release_mp:${TARGETS_MP}
cp git_version.h version.txt
tar -zcvf ${NAME}_mp_binaries.tar.gz ${NAME}_mp.exe ${NAME}_mp_wepoll.exe ${NAME}_mp_mac version.txt
clean:
rm -f ${TAR}
rm -f udp2raw udp2raw_cross udp2raw_cmake udp2raw_dynamic
rm -f ${NAME} ${NAME}_cross ${NAME}.exe ${NAME}_wepoll.exe ${NAME}_mac
rm -f ${NAME}_mp_binaries.tar.gz ${NAME}_mp.exe ${NAME}_mp_wepoll.exe ${NAME}_mp_mac
rm -f git_version.h
git_version:
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > git_version.h

2285
misc.cpp

File diff suppressed because it is too large Load Diff

142
misc.h

@ -8,13 +8,14 @@
#ifndef MISC_H_
#define MISC_H_
#include "common.h"
#include "log.h"
#include "network.h"
extern int hb_mode;
extern int hb_len;
extern char hb_buf[buf_len];
extern int mtu_warn;
extern int max_rst_allowed;
@ -24,128 +25,131 @@ extern int enable_dns_resolve;
extern int ttl_value;
const u32_t max_handshake_conn_num = 10000;
const u32_t max_ready_conn_num = 1000;
const u32_t anti_replay_window_size = 4000;
const int max_conv_num = 10000;
const u32_t max_handshake_conn_num=10000;
const u32_t max_ready_conn_num=1000;
const u32_t anti_replay_window_size=4000;
const int max_conv_num=10000;
const u32_t client_handshake_timeout = 5000; // unit ms
const u32_t client_retry_interval = 1000; // ms
const u32_t client_handshake_timeout=5000;//unit ms
const u32_t client_retry_interval=1000;//ms
const u32_t server_handshake_timeout = client_handshake_timeout + 5000; // this should be longer than clients. client retry initially ,server retry passtively
const u32_t server_handshake_timeout=client_handshake_timeout+5000;// this should be 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 conn_clear_min = 1;
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 conn_clear_min=1;
const u32_t conv_clear_interval = 1000; // ms
const u32_t conn_clear_interval = 1000; // ms
const u32_t conv_clear_interval=1000;//ms
const u32_t conn_clear_interval=1000;//ms
const i32_t max_fail_time = 0; // disable
const u32_t heartbeat_interval = 600; // ms
const i32_t max_fail_time=0;//disable
const u32_t timer_interval = 400; // ms. this should be smaller than heartbeat_interval and retry interval;
const u32_t heartbeat_interval=600;//ms
const uint32_t conv_timeout = 180000; // ms. 120 second
// const u32_t conv_timeout=30000; //for test
const u32_t timer_interval=400;//ms. this should be smaller than heartbeat_interval and retry interval;
const u32_t client_conn_timeout = 10000; // ms.
const u32_t client_conn_uplink_timeout = client_conn_timeout + 2000; // ms
const uint32_t conv_timeout=180000; //ms. 120 second
//const u32_t conv_timeout=30000; //for test
const uint32_t server_conn_timeout = conv_timeout + 60000; // ms. 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+10000;//for test
const u32_t client_conn_timeout=10000;//ms.
const u32_t client_conn_uplink_timeout=client_conn_timeout+2000;//ms
const u32_t iptables_rule_keep_interval = 20; // unit: second;
const uint32_t server_conn_timeout=conv_timeout+60000;//ms. 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+10000;//for test
enum server_current_state_t { server_idle = 0,
server_handshake1,
server_ready }; // server state machine
enum client_current_state_t { client_idle = 0,
client_tcp_handshake,
client_handshake1,
client_handshake2,
client_ready,
client_tcp_handshake_dummy }; // client state machine
const u32_t iptables_rule_keep_interval=20;//unit: second;
enum raw_mode_t { mode_faketcp = 0,
mode_udp,
mode_icmp,
mode_end };
enum program_mode_t { unset_mode = 0,
client_mode,
server_mode };
enum server_current_state_t {server_idle=0,server_handshake1,server_ready}; //server state machine
enum client_current_state_t {client_idle=0,client_tcp_handshake,client_handshake1,client_handshake2,client_ready};//client state machine
enum raw_mode_t{mode_faketcp=0,mode_udp,mode_icmp,mode_end};
enum program_mode_t {unset_mode=0,client_mode,server_mode};
union current_state_t
{
server_current_state_t server_current_state;
client_current_state_t client_current_state;
union current_state_t {
server_current_state_t server_current_state;
client_current_state_t client_current_state;
};
//extern char remote_address[max_address_len];
//extern char local_ip[100], remote_ip[100],source_ip[100];//local_ip is for -l option,remote_ip for -r option,source for --source-ip
//extern u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line.
//extern int local_port , remote_port,source_port;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled
// extern char remote_address[max_address_len];
// extern char local_ip[100], remote_ip[100],source_ip[100];//local_ip is for -l option,remote_ip for -r option,source for --source-ip
// extern u32_t local_ip_uint32,remote_ip_uint32,source_ip_uint32;//convert from last line.
// extern int local_port , remote_port,source_port;//similiar to local_ip remote_ip,buf for port.source_port=0 indicates --source-port is not enabled
extern address_t local_addr,remote_addr,source_addr;
extern address_t local_addr, remote_addr, source_addr;
extern my_ip_t bind_addr;
extern int bind_addr_used;
extern int force_source_ip; //if --source-ip is enabled
extern int force_source_ip; // if --source-ip is enabled
extern int force_source_port;
extern int source_port;
extern my_id_t const_id;//an id used for connection recovery,its generated randomly,it never change since its generated
extern my_id_t const_id; // an id used for connection recovery,its generated randomly,it never change since its generated
extern int udp_fd; //for client only. client use this fd to listen and handle udp connection
extern int bind_fd; //bind only,never send or recv. its just a dummy fd for bind,so that other program wont occupy the same port
extern int epollfd; //fd for epoll
extern int timer_fd; //the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd.
extern int fail_time_counter;//determine if the max_fail_time is reached
extern int epoll_trigger_counter;//for debug only
extern int debug_flag;//for debug only
extern int udp_fd; // for client only. client use this fd to listen and handle udp connection
extern int bind_fd; // bind only,never send or recv. its just a dummy fd for bind,so that other program wont occupy the same port
extern int epollfd; // fd for epoll
extern int timer_fd; // the general timer fd for client and server.for server this is not the only timer find,every connection has a timer fd.
extern int fail_time_counter; // determine if the max_fail_time is reached
extern int epoll_trigger_counter; // for debug only
extern int debug_flag; // for debug only
extern int simple_rule; //deprecated.
extern int keep_rule; //whether to monitor the iptables rule periodly,re-add if losted
extern int auto_add_iptables_rule;//if -a is set
extern int generate_iptables_rule;//if -g is set
extern int generate_iptables_rule_add;// if --gen-add is set
extern int simple_rule; // deprecated.
extern int keep_rule; // whether to monitor the iptables rule periodly,re-add if losted
extern int auto_add_iptables_rule; // if -a is set
extern int generate_iptables_rule; // if -g is set
extern int generate_iptables_rule_add; // if --gen-add is set
extern int retry_on_error;
const int retry_on_error_interval=10;
const int retry_on_error_interval = 10;
extern int debug_resend; // debug only
extern int debug_resend; // debug only
extern char key_string[1000];// -k option
extern char key_string[1000]; // -k option
extern char fifo_file[1000];
extern raw_mode_t raw_mode;
extern u32_t raw_ip_version;
extern program_mode_t program_mode;
extern unordered_map<int, const char*> raw_mode_tostring ;
extern unordered_map<int, const char *> raw_mode_tostring;
extern int about_to_exit;
extern int socket_buf_size;
extern pthread_t keep_thread;
extern int keep_thread_running;
int process_lower_level_arg();
void print_help();
void iptables_rule();
void pre_process_arg(int argc, char *argv[]);//mainly for load conf file;
void pre_process_arg(int argc, char *argv[]); // mainly for load conf file;
int unit_test();
int set_timer(int epollfd,int &timer_fd);
int set_timer_server(int epollfd,int &timer_fd,fd64_t &fd64);
int set_timer(int epollfd, int &timer_fd);
int set_timer_server(int epollfd, int &timer_fd, fd64_t &fd64);
int handle_lower_level(raw_info_t &raw_info);
int add_iptables_rule(const char *);
int clear_iptables_rule();
int iptables_gen_add(const char * s,u32_t const_id);
int iptables_rule_init(const char * s,u32_t const_id,int keep);
int iptables_gen_add(const char *s, u32_t const_id);
int iptables_rule_init(const char *s, u32_t const_id, int keep);
int keep_iptables_rule();
void signal_handler(int sig);
void signal_handler(int sig);
#endif /* MISC_H_ */

16
my_ev.cpp Normal file

@ -0,0 +1,16 @@
#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

4
my_ev.h Normal file

@ -0,0 +1,4 @@
#pragma once
#include "my_ev_common.h"
#include "ev.h"

19
my_ev_common.h Normal file

@ -0,0 +1,19 @@
#define EV_STANDALONE 1
#define EV_COMMON \
void *data; \
unsigned long long u64;
#define EV_COMPAT3 0
//#include <wepoll.h>
#if defined(__MINGW32__)
//#define EV_USE_SELECT 1
//#define EV_SELECT_IS_WINSOCKET 1
#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
//#define EV_VERIFY 2

File diff suppressed because it is too large Load Diff

341
network.h

@ -10,10 +10,11 @@
extern int raw_recv_fd;
extern int raw_send_fd;
extern int use_tcp_dummy_socket;
extern int seq_mode;
extern int max_seq_mode;
extern int filter_port;
//extern u32_t bind_address_uint32;
// extern u32_t bind_address_uint32;
extern int disable_bpf_filter;
extern int lower_level;
@ -26,19 +27,42 @@ extern int random_drop;
extern int ifindex;
extern char g_packet_buf[buf_len];
extern char g_packet_buf[huge_buf_len];
extern int g_packet_buf_len;
extern int g_packet_buf_cnt;
#ifdef UDP2RAW_MP
extern queue_t my_queue;
extern ev_async async_watcher;
extern struct ev_loop *g_default_loop;
struct my_iphdr
{
extern pthread_mutex_t queue_mutex;
extern int use_pcap_mutex;
extern int pcap_cnt;
extern int pcap_link_header_len;
extern int send_with_pcap;
extern int pcap_header_captured;
extern int pcap_header_buf[buf_len];
struct icmphdr {
uint8_t type;
uint8_t code;
uint16_t check_sum;
uint16_t id;
uint16_t seq;
};
#endif
struct my_iphdr {
#ifdef UDP2RAW_LITTLE_ENDIAN
unsigned char ihl:4;
unsigned char version:4;
unsigned char ihl : 4;
unsigned char version : 4;
#else
unsigned char version:4;
unsigned char ihl:4;
unsigned char version : 4;
unsigned char ihl : 4;
#endif
u_int8_t tos;
u_int16_t tot_len;
@ -50,105 +74,98 @@ struct my_iphdr
u_int32_t saddr;
u_int32_t daddr;
/*The options start here. */
};
struct my_udphdr
{
/*__extension__*/ union
{
struct
{
u_int16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */
u_int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
};
};
struct my_tcphdr
{
/*__extension__*/ union
{
struct
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */
# ifdef UDP2RAW_LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t tc_off:4; /* data offset */
# else
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
# endif
u_int8_t th_flags;
# define TH_FIN 0x01
# define TH_SYN 0x02
# define TH_RST 0x04
# define TH_PUSH 0x08
# define TH_ACK 0x10
# define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int32_t seq;
u_int32_t ack_seq;
# ifdef UDP2RAW_LITTLE_ENDIAN
u_int16_t res1:4;
u_int16_t doff:4;
u_int16_t fin:1;
u_int16_t syn:1;
u_int16_t rst:1;
u_int16_t psh:1;
u_int16_t ack:1;
u_int16_t urg:1;
u_int16_t res2:2;
# else
u_int16_t doff:4;
u_int16_t res1:4;
u_int16_t res2:2;
u_int16_t urg:1;
u_int16_t ack:1;
u_int16_t psh:1;
u_int16_t rst:1;
u_int16_t syn:1;
u_int16_t fin:1;
# endif
u_int16_t window;
u_int16_t check;
u_int16_t urg_ptr;
};
struct my_udphdr {
/*__extension__*/ union {
struct
{
u_int16_t uh_sport; /* source port */
u_int16_t uh_dport; /* destination port */
u_int16_t uh_ulen; /* udp length */
u_int16_t uh_sum; /* udp checksum */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int16_t len;
u_int16_t check;
};
};
};
struct my_ip6hdr
{
# ifdef UDP2RAW_LITTLE_ENDIAN
uint8_t traffic_class_high:4;
uint8_t version:4;
uint8_t flow_label_high:4;
uint8_t traffic_class_low:4;
struct my_tcphdr {
/*__extension__*/ union {
struct
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */
#ifdef UDP2RAW_LITTLE_ENDIAN
u_int8_t th_x2 : 4; /* (unused) */
u_int8_t tc_off : 4; /* data offset */
#else
uint8_t version:4;
uint8_t traffic_class_high:4;
uint8_t traffic_class_low:4;
uint8_t flow_label_high:4;
u_int8_t th_off : 4; /* data offset */
u_int8_t th_x2 : 4; /* (unused) */
#endif
u_int8_t th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct
{
u_int16_t source;
u_int16_t dest;
u_int32_t seq;
u_int32_t ack_seq;
#ifdef UDP2RAW_LITTLE_ENDIAN
u_int16_t res1 : 4;
u_int16_t doff : 4;
u_int16_t fin : 1;
u_int16_t syn : 1;
u_int16_t rst : 1;
u_int16_t psh : 1;
u_int16_t ack : 1;
u_int16_t urg : 1;
u_int16_t res2 : 2;
#else
u_int16_t doff : 4;
u_int16_t res1 : 4;
u_int16_t res2 : 2;
u_int16_t urg : 1;
u_int16_t ack : 1;
u_int16_t psh : 1;
u_int16_t rst : 1;
u_int16_t syn : 1;
u_int16_t fin : 1;
#endif
u_int16_t window;
u_int16_t check;
u_int16_t urg_ptr;
};
};
};
struct my_ip6hdr {
#ifdef UDP2RAW_LITTLE_ENDIAN
uint8_t traffic_class_high : 4;
uint8_t version : 4;
uint8_t flow_label_high : 4;
uint8_t traffic_class_low : 4;
#else
uint8_t version : 4;
uint8_t traffic_class_high : 4;
uint8_t traffic_class_low : 4;
uint8_t flow_label_high : 4;
#endif
u_int16_t flow_label_low;
u_int16_t payload_len;
@ -157,15 +174,14 @@ struct my_ip6hdr
struct in6_addr src;
struct in6_addr dst;
};
};
struct my_icmphdr
{
uint8_t type;
uint8_t code;
uint16_t check_sum;
uint16_t id;
uint16_t seq;
struct my_icmphdr {
uint8_t type;
uint8_t code;
uint16_t check_sum;
uint16_t id;
uint16_t seq;
};
struct pseudo_header {
@ -185,55 +201,53 @@ struct pseudo_header6 {
u_int8_t next_header;
};
struct packet_info_t //todo change this to union
struct packet_info_t // todo change this to union
{
uint8_t protocol;
uint8_t protocol;
// u32_t src_ip;
// u32_t dst_ip;
my_ip_t new_src_ip;
my_ip_t new_dst_ip;
//u32_t src_ip;
//u32_t dst_ip;
my_ip_t new_src_ip;
my_ip_t new_dst_ip;
uint16_t src_port;
uint16_t dst_port;
uint16_t src_port;
uint16_t dst_port;
// tcp_part:
bool syn, ack, psh, rst;
//tcp_part:
bool syn,ack,psh,rst;
u32_t seq, ack_seq;
u32_t seq,ack_seq;
u32_t ack_seq_counter;
u32_t ack_seq_counter;
u32_t ts, ts_ack;
u32_t ts,ts_ack;
uint16_t my_icmp_seq;
bool has_ts;
uint16_t my_icmp_seq;
i32_t data_len;
bool has_ts;
#ifdef UDP2RAW_LINUX
sockaddr_ll addr_ll;
#endif
sockaddr_ll addr_ll;
i32_t data_len;
packet_info_t();
packet_info_t();
};
struct raw_info_t
{
packet_info_t send_info;
packet_info_t recv_info;
//int last_send_len;
//int last_recv_len;
bool peek=0;
//bool csum=1;
u32_t reserved_send_seq;
//uint32_t first_seq,first_ack_seq;
int rst_received=0;
bool disabled=0;
};//g_raw_info;
struct raw_info_t {
packet_info_t send_info;
packet_info_t recv_info;
// int last_send_len;
// int last_recv_len;
bool peek = 0;
// bool csum=1;
u32_t reserved_send_seq;
// uint32_t first_seq,first_ack_seq;
int rst_received = 0;
bool disabled = 0;
}; // g_raw_info;
int init_raw_socket();
@ -241,51 +255,56 @@ void init_filter(int port);
void remove_filter();
int init_ifindex(const char * if_name,int fd,int &index);
#ifdef UDP2RAW_LINUX
int init_ifindex(const char *if_name, int fd, int &index);
#endif
int find_lower_level_info(u32_t ip,u32_t &dest_ip,string &if_name,string &hw);
#ifdef UDP2RAW_MP
int init_ifindex(const char *if_name, int &index);
#endif
int get_src_adress(u32_t &ip,u32_t remote_ip_uint32,int remote_port); //a trick to get src adress for a dest adress,so that we can use the src address in raw socket as source ip
int find_lower_level_info(u32_t ip, u32_t &dest_ip, string &if_name, string &hw);
int get_src_adress2(address_t &output_addr,address_t remote_addr);
int get_src_adress(u32_t &ip, u32_t remote_ip_uint32, int remote_port); // a trick to get src adress for a dest adress,so that we can use the src address in raw socket as source ip
int get_src_adress2(address_t &output_addr, address_t remote_addr);
int try_to_list_and_bind(int & bind_fd,u32_t local_ip_uint32,int port); //try to bind to a port,may fail.
int try_to_list_and_bind(int &bind_fd, u32_t local_ip_uint32, int port); // try to bind to a port,may fail.
int try_to_list_and_bind2(int &fd, address_t address);
int client_bind_to_a_new_port(int & bind_fd,u32_t local_ip_uint32);//find a free port and bind to it.
int client_bind_to_a_new_port2(int &fd,const address_t& address);
int client_bind_to_a_new_port(int &bind_fd, u32_t local_ip_uint32); // find a free port and bind to it.
int client_bind_to_a_new_port2(int &fd, const address_t &address);
int discard_raw_packet();
int pre_recv_raw_packet();
int send_raw_ip(raw_info_t &raw_info,const char * payload,int payloadlen);
int send_raw_ip(raw_info_t &raw_info, const char *payload, int payloadlen);
int peek_raw(raw_info_t &peek_info);
int recv_raw_ip(raw_info_t &raw_info,char * &payload,int &payloadlen);
int recv_raw_ip(raw_info_t &raw_info, char *&payload, int &payloadlen);
int send_raw_icmp(raw_info_t &raw_info, const char * payload, int payloadlen);
int send_raw_icmp(raw_info_t &raw_info, const char *payload, int payloadlen);
int send_raw_udp(raw_info_t &raw_info, const char * payload, int payloadlen);
int send_raw_udp(raw_info_t &raw_info, const char *payload, int payloadlen);
int send_raw_tcp(raw_info_t &raw_info,const char * payload, int payloadlen);
int send_raw_tcp(raw_info_t &raw_info, const char *payload, int payloadlen);
int recv_raw_icmp(raw_info_t &raw_info, char *&payload, int &payloadlen);
int recv_raw_udp(raw_info_t &raw_info, char *&payload, int &payloadlen);
int recv_raw_tcp(raw_info_t &raw_info,char * &payload,int &payloadlen);
int recv_raw_tcp(raw_info_t &raw_info, char *&payload, int &payloadlen);
//int send_raw(raw_info_t &raw_info,const char * payload,int payloadlen);
// int send_raw(raw_info_t &raw_info,const char * payload,int payloadlen);
//int recv_raw(raw_info_t &raw_info,char * &payload,int &payloadlen);
// int recv_raw(raw_info_t &raw_info,char * &payload,int &payloadlen);
int send_raw0(raw_info_t &raw_info,const char * payload,int payloadlen);
int send_raw0(raw_info_t &raw_info, const char *payload, int payloadlen);
int recv_raw0(raw_info_t &raw_info,char * &payload,int &payloadlen);
int recv_raw0(raw_info_t &raw_info, char *&payload, int &payloadlen);
int after_send_raw0(raw_info_t &raw_info);
int after_recv_raw0(raw_info_t &raw_info);
#endif /* NETWORK_H_ */

119
pcap_wrapper.cpp Normal file

@ -0,0 +1,119 @@
#include <windows.h>
#include <pcap_wrapper.h>
#include <assert.h>
#include <stdio.h>
int (*pcap_loop)(pcap_t *, int, pcap_handler, u_char *);
int (*pcap_breakloop)(pcap_t *);
pcap_t *(*pcap_create)(const char *, char *);
int (*pcap_set_snaplen)(pcap_t *, int) = 0;
int (*pcap_set_promisc)(pcap_t *, int) = 0;
int (*pcap_can_set_rfmon)(pcap_t *) = 0;
int (*pcap_set_rfmon)(pcap_t *, int) = 0;
int (*pcap_set_timeout)(pcap_t *, int) = 0;
int (*pcap_set_buffer_size)(pcap_t *, int) = 0;
int (*pcap_activate)(pcap_t *) = 0;
int (*pcap_setfilter)(pcap_t *, struct bpf_program *) = 0;
int (*pcap_setdirection)(pcap_t *, pcap_direction_t) = 0;
int (*pcap_datalink)(pcap_t *) = 0;
void (*pcap_freecode)(struct bpf_program *) = 0;
int (*pcap_compile)(pcap_t *, struct bpf_program *, const char *, int,
bpf_u_int32) = 0;
char *(*pcap_geterr)(pcap_t *) = 0;
int (*pcap_sendpacket)(pcap_t *, const u_char *, int) = 0;
char *(*pcap_lookupdev)(char *) = 0;
int (*pcap_findalldevs)(pcap_if_t **, char *) = 0;
struct init_pcap_t {
init_pcap_t() {
init_pcap();
}
} do_it;
static void init_npcap_dll_path() {
BOOL(WINAPI * SetDllDirectory)
(LPCTSTR);
char sysdir_name[512];
int len;
SetDllDirectory = (BOOL(WINAPI *)(LPCTSTR))GetProcAddress(GetModuleHandle("kernel32.dll"), "SetDllDirectoryA");
if (SetDllDirectory == NULL) {
printf("Error in SetDllDirectory\n");
} else {
len = GetSystemDirectory(sysdir_name, 480); // be safe
if (!len)
printf("Error in GetSystemDirectory (%d)\n", (int)GetLastError());
strcat(sysdir_name, "\\Npcap");
if (SetDllDirectory(sysdir_name) == 0)
printf("Error in SetDllDirectory(\"System32\\Npcap\")\n");
}
}
#define EXPORT_FUN(XXX) \
do { \
XXX = (__typeof__(XXX))GetProcAddress(wpcap, #XXX); \
} while (0)
int init_pcap() {
HMODULE wpcap = LoadLibrary("wpcap.dll");
if (wpcap != 0) {
printf("using system32/wpcap.dll\n");
} else {
init_npcap_dll_path();
// SetDllDirectory("C:\\Windows\\System32\\Npcap\\");
wpcap = LoadLibrary("wpcap.dll");
if (wpcap != 0)
printf("using system32/npcap/wpcap.dll\n");
}
if (wpcap == 0) {
printf("cant not open wpcap.dll, make sure winpcap/npcap is installed\n");
exit(-1);
}
assert(wpcap != 0);
EXPORT_FUN(pcap_loop);
EXPORT_FUN(pcap_breakloop);
EXPORT_FUN(pcap_create);
EXPORT_FUN(pcap_set_snaplen);
EXPORT_FUN(pcap_set_promisc);
EXPORT_FUN(pcap_set_timeout);
EXPORT_FUN(pcap_activate);
EXPORT_FUN(pcap_setfilter);
EXPORT_FUN(pcap_setdirection);
EXPORT_FUN(pcap_datalink);
EXPORT_FUN(pcap_freecode);
EXPORT_FUN(pcap_compile);
EXPORT_FUN(pcap_geterr);
EXPORT_FUN(pcap_sendpacket);
EXPORT_FUN(pcap_lookupdev);
EXPORT_FUN(pcap_findalldevs);
/*
pcap_loop = (__typeof__(pcap_loop))GetProcAddress(wpcap, "pcap_loop");
pcap_create = (__typeof__(pcap_create))GetProcAddress(wpcap, "pcap_create");
pcap_set_snaplen = (__typeof__(pcap_set_snaplen))GetProcAddress(wpcap, "pcap_set_snaplen");
pcap_set_promisc = (__typeof__(pcap_set_promisc))GetProcAddress(wpcap, "pcap_set_promisc");
pcap_set_timeout = (__typeof__(pcap_set_timeout))GetProcAddress(wpcap, "pcap_set_timeout");
pcap_activate = (__typeof__(pcap_activate))GetProcAddress(wpcap, "pcap_activate");
pcap_setfilter = (__typeof__(pcap_setfilter))GetProcAddress(wpcap, "pcap_setfilter");
pcap_setdirection = (__typeof__(pcap_setdirection))GetProcAddress(wpcap, "pcap_setdirection");
pcap_datalink = (__typeof__(pcap_datalink))GetProcAddress(wpcap, "pcap_datalink");
pcap_freecode = (__typeof__(pcap_freecode))GetProcAddress(wpcap, "pcap_freecode");
pcap_compile = (__typeof__(pcap_compile))GetProcAddress(wpcap, "pcap_compile");
pcap_geterr = (__typeof__(pcap_geterr))GetProcAddress(wpcap, "pcap_geterr");
pcap_sendpacket = (__typeof__(pcap_sendpacket))GetProcAddress(wpcap, "pcap_sendpacket");
pcap_lookupdev = (__typeof__(pcap_lookupdev))GetProcAddress(wpcap, "pcap_lookupdev");
pcap_findalldevs = (__typeof__(pcap_findalldevs))GetProcAddress(wpcap, "pcap_findalldevs");
//pcap_loop = (__typeof__(pcap_loop))GetProcAddress(wpcap, "pcap_loop");
//pcap_loop = (__typeof__(pcap_loop))GetProcAddress(wpcap, "pcap_loop");
//pcap_loop = (__typeof__(pcap_loop))GetProcAddress(wpcap, "pcap_loop");
*/
return 0;
}

117
pcap_wrapper.h Normal file

@ -0,0 +1,117 @@
#pragma once
//#ifdef __cplusplus
// extern "C" {
//#endif
//#include <sys/time.h>
//#include <stdint.h>
struct bpf_program {
char a[4096];
};
struct pcap_t {
char a[4096];
};
typedef unsigned int bpf_u_int32;
typedef struct my_timeval {
int tv_sec;
int tv_usec;
} my_timeval;
struct pcap_pkthdr {
struct my_timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
};
typedef enum {
PCAP_D_INOUT = 0,
PCAP_D_IN,
PCAP_D_OUT
} pcap_direction_t;
struct pcap_addr {
struct pcap_addr *next;
struct sockaddr *addr; /* address */
struct sockaddr *netmask; /* netmask for that address */
struct sockaddr *broadaddr; /* broadcast address for that address */
struct sockaddr *dstaddr; /* P2P destination address for that address */
};
struct pcap_if {
struct pcap_if *next;
char *name; /* name to hand to "pcap_open_live()" */
char *description; /* textual description of interface, or NULL */
struct pcap_addr *addresses;
bpf_u_int32 flags; /* PCAP_IF_ interface flags */
};
typedef struct pcap_if pcap_if_t;
typedef struct pcap_addr pcap_addr_t;
typedef unsigned char u_char;
#define PCAP_ERRBUF_SIZE 256
#define DLT_NULL 0 /* BSD loopback encapsulation */
#define DLT_EN10MB 1 /* Ethernet (10Mb) */
#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
#define DLT_AX25 3 /* Amateur Radio AX.25 */
#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
#define DLT_CHAOS 5 /* Chaos */
#define DLT_IEEE802 6 /* 802.5 Token Ring */
#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */
#define DLT_SLIP 8 /* Serial Line IP */
#define DLT_PPP 9 /* Point-to-point Protocol */
#define DLT_FDDI 10 /* FDDI */
#define DLT_LINUX_SLL 113
#define PCAP_NETMASK_UNKNOWN 0xffffffff
typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
const u_char *);
extern int (*pcap_loop)(pcap_t *, int, pcap_handler, u_char *);
extern int (*pcap_breakloop)(pcap_t *);
extern pcap_t *(*pcap_create)(const char *, char *);
extern int (*pcap_set_snaplen)(pcap_t *, int);
extern int (*pcap_set_promisc)(pcap_t *, int);
extern int (*pcap_can_set_rfmon)(pcap_t *);
extern int (*pcap_set_rfmon)(pcap_t *, int);
extern int (*pcap_set_timeout)(pcap_t *, int);
extern int (*pcap_set_buffer_size)(pcap_t *, int);
extern int (*pcap_activate)(pcap_t *);
extern int (*pcap_setfilter)(pcap_t *, struct bpf_program *);
extern int (*pcap_setdirection)(pcap_t *, pcap_direction_t);
extern int (*pcap_datalink)(pcap_t *);
extern void (*pcap_freecode)(struct bpf_program *);
extern int (*pcap_compile)(pcap_t *, struct bpf_program *, const char *, int,
bpf_u_int32);
extern char *(*pcap_geterr)(pcap_t *);
extern int (*pcap_sendpacket)(pcap_t *, const u_char *, int);
extern char *(*pcap_lookupdev)(char *);
extern int (*pcap_findalldevs)(pcap_if_t **, char *);
inline int pcap_set_immediate_mode(pcap_t *, int) {
return 0;
}
//#ifdef __cplusplus
//}
//#endif
int init_pcap();

800
server.cpp Normal file

@ -0,0 +1,800 @@
/*
* server.cpp
*
* Created on: Aug 29, 2018
* Author: root
*/
#ifndef UDP2RAW_MP
#include "common.h"
#include "network.h"
#include "connection.h"
#include "misc.h"
#include "log.h"
#include "lib/md5.h"
#include "encrypt.h"
#include "fd_manager.h"
int server_on_timer_multi(conn_info_t &conn_info) // for server. called when a timer is ready in epoll.for server,there will be one timer for every connection
// there is also a global timer for server,but its not handled here
{
char ip_port[max_addr_len];
// u32_t ip=conn_info.raw_info.send_info.dst_ip;
// u32_t port=conn_info.raw_info.send_info.dst_port;
address_t tmp_addr;
tmp_addr.from_ip_port_new(raw_ip_version, &conn_info.raw_info.send_info.new_dst_ip, conn_info.raw_info.send_info.dst_port);
// sprintf(ip_port,"%s:%d",my_ntoa(ip),port);
tmp_addr.to_str(ip_port);
// keep_iptables_rule();
mylog(log_trace, "server timer!\n");
raw_info_t &raw_info = conn_info.raw_info;
assert(conn_info.state.server_current_state == server_ready);
if (conn_info.state.server_current_state == server_ready) {
conn_info.blob->conv_manager.s.clear_inactive(ip_port);
/*
if( get_current_time()-conn_info.last_hb_recv_time>heartbeat_timeout )
{
mylog(log_trace,"%lld %lld\n",get_current_time(),conn_info.last_state_time);
conn_info.server_current_state=server_nothing;
//conn_manager.current_ready_ip=0;
//conn_manager.current_ready_port=0;
mylog(log_info,"changed state to server_nothing\n");
return 0;
}*/
// dont need to do this at server,conn_manger will clear expired connections
if (get_current_time() - conn_info.last_hb_sent_time < heartbeat_interval) {
return 0;
}
if (hb_mode == 0)
send_safer(conn_info, 'h', hb_buf, 0); /////////////send
else
send_safer(conn_info, 'h', hb_buf, hb_len);
conn_info.last_hb_sent_time = get_current_time();
mylog(log_debug, "heart beat sent<%x,%x>\n", conn_info.my_id, conn_info.oppsite_id);
} else {
mylog(log_fatal, "this shouldnt happen!\n");
myexit(-1);
}
return 0;
}
int server_on_raw_recv_ready(conn_info_t &conn_info, char *ip_port, char type, char *data, int data_len) // called while the state for a connection is server_ready
// receives data and heart beat by recv_safer.
{
raw_info_t &raw_info = conn_info.raw_info;
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
// char ip_port[40];
// sprintf(ip_port,"%s:%d",my_ntoa(recv_info.src_ip),recv_info.src_port);
/*
if (recv_info.src_ip != send_info.dst_ip
|| recv_info.src_port != send_info.dst_port) {
mylog(log_debug, "unexpected adress\n");
return 0;
}*/
if (type == 'h' && data_len >= 0) {
// u32_t tmp = ntohl(*((u32_t *) &data[sizeof(u32_t)]));
mylog(log_debug, "[%s][hb]received hb \n", ip_port);
conn_info.last_hb_recv_time = get_current_time();
return 0;
} else if (type == 'd' && data_len >= int(sizeof(u32_t))) {
// u32_t tmp_conv_id = ntohl(*((u32_t *) &data[0]));
my_id_t tmp_conv_id;
memcpy(&tmp_conv_id, &data[0], sizeof(tmp_conv_id));
tmp_conv_id = ntohl(tmp_conv_id);
if (hb_mode == 0)
conn_info.last_hb_recv_time = get_current_time();
mylog(log_trace, "conv:%u\n", tmp_conv_id);
if (!conn_info.blob->conv_manager.s.is_conv_used(tmp_conv_id)) {
if (conn_info.blob->conv_manager.s.get_size() >= max_conv_num) {
mylog(log_warn,
"[%s]ignored new conv %x connect bc max_conv_num exceed\n", ip_port,
tmp_conv_id);
return 0;
}
/*
struct sockaddr_in remote_addr_in={0};
socklen_t slen = sizeof(sockaddr_in);
//memset(&remote_addr_in, 0, sizeof(remote_addr_in));
remote_addr_in.sin_family = AF_INET;
remote_addr_in.sin_port = htons(remote_port);
remote_addr_in.sin_addr.s_addr = remote_ip_uint32;
int new_udp_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (new_udp_fd < 0) {
mylog(log_warn, "[%s]create udp_fd error\n",ip_port);
return -1;
}
setnonblocking(new_udp_fd);
set_buf_size(new_udp_fd,socket_buf_size);
mylog(log_debug, "[%s]created new udp_fd %d\n",ip_port, new_udp_fd);
int ret = connect(new_udp_fd, (struct sockaddr *) &remote_addr_in,
slen);
if (ret != 0) {
mylog(log_warn, "udp fd connect fail\n");
close(new_udp_fd);
return -1;
}*/
int new_udp_fd = remote_addr.new_connected_udp_fd();
if (new_udp_fd < 0) {
mylog(log_warn, "[%s]new_connected_udp_fd() failed\n", ip_port);
return -1;
}
struct epoll_event ev;
fd64_t new_udp_fd64 = fd_manager.create(new_udp_fd);
fd_manager.get_info(new_udp_fd64).p_conn_info = &conn_info;
mylog(log_trace, "[%s]u64: %lld\n", ip_port, new_udp_fd64);
ev.events = EPOLLIN;
ev.data.u64 = new_udp_fd64;
int ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, new_udp_fd, &ev);
if (ret != 0) {
mylog(log_warn, "[%s]add udp_fd error\n", ip_port);
close(new_udp_fd);
return -1;
}
conn_info.blob->conv_manager.s.insert_conv(tmp_conv_id, new_udp_fd64);
// assert(conn_manager.udp_fd_mp.find(new_udp_fd)==conn_manager.udp_fd_mp.end());
// conn_manager.udp_fd_mp[new_udp_fd] = &conn_info;
// pack_u64(conn_info.raw_info.recv_info.src_ip,conn_info.raw_info.recv_info.src_port);
mylog(log_info, "[%s]new conv conv_id=%x, assigned fd=%d\n", ip_port,
tmp_conv_id, new_udp_fd);
}
fd64_t fd64 = conn_info.blob->conv_manager.s.find_data_by_conv(tmp_conv_id);
conn_info.blob->conv_manager.s.update_active_time(tmp_conv_id);
int fd = fd_manager.to_fd(fd64);
mylog(log_trace, "[%s]received a data from fake tcp,len:%d\n", ip_port, data_len);
int ret = send(fd, data + sizeof(u32_t),
data_len - (sizeof(u32_t)), 0);
mylog(log_trace, "[%s]%d byte sent ,fd :%d\n ", ip_port, ret, fd);
if (ret < 0) {
mylog(log_warn, "send returned %d\n", ret);
// perror("what happened????");
}
return 0;
}
return 0;
}
int server_on_raw_recv_pre_ready(conn_info_t &conn_info, char *ip_port, u32_t tmp_oppsite_const_id) // do prepare work before state change to server ready for a specifc connection
// connection recovery is also handle here
{
// u32_t ip;uint16_t port;
// ip=conn_info.raw_info.recv_info.src_ip;
// port=conn_info.raw_info.recv_info.src_port;
// char ip_port[40];
// sprintf(ip_port,"%s:%d",my_ntoa(ip),port);
mylog(log_info, "[%s]received handshake oppsite_id:%x my_id:%x\n", ip_port, conn_info.oppsite_id, conn_info.my_id);
mylog(log_info, "[%s]oppsite const_id:%x \n", ip_port, tmp_oppsite_const_id);
if (conn_manager.const_id_mp.find(tmp_oppsite_const_id) == conn_manager.const_id_mp.end()) {
// conn_manager.const_id_mp=
if (conn_manager.ready_num >= max_ready_conn_num) {
mylog(log_info, "[%s]max_ready_conn_num,cant turn to ready\n", ip_port);
conn_info.state.server_current_state = server_idle;
return 0;
}
conn_info.prepare();
conn_info.state.server_current_state = server_ready;
conn_info.oppsite_const_id = tmp_oppsite_const_id;
conn_manager.ready_num++;
conn_manager.const_id_mp[tmp_oppsite_const_id] = &conn_info;
// conn_info.last_state_time=get_current_time(); //dont change this!!!!!!!!!!!!!!!!!!!!!!!!!
// conn_manager.current_ready_ip=ip;
// conn_manager.current_ready_port=port;
// my_id=conn_info.my_id;
// oppsite_id=conn_info.oppsite_id;
conn_info.last_hb_recv_time = get_current_time();
conn_info.last_hb_sent_time = conn_info.last_hb_recv_time; //=get_current_time()
if (hb_mode == 0)
send_safer(conn_info, 'h', hb_buf, 0); /////////////send
else
send_safer(conn_info, 'h', hb_buf, hb_len);
mylog(log_info, "[%s]changed state to server_ready\n", ip_port);
conn_info.blob->anti_replay.re_init();
// g_conn_info=conn_info;
int new_timer_fd;
set_timer_server(epollfd, new_timer_fd, conn_info.timer_fd64);
fd_manager.get_info(conn_info.timer_fd64).p_conn_info = &conn_info;
// assert(conn_manager.timer_fd_mp.find(new_timer_fd)==conn_manager.timer_fd_mp.end());
// conn_manager.timer_fd_mp[new_timer_fd] = &conn_info;//pack_u64(ip,port);
// timer_fd_mp[new_timer_fd]
/*
if(oppsite_const_id!=0&&tmp_oppsite_const_id!=oppsite_const_id) //TODO MOVE TO READY
{
mylog(log_info,"cleared all conv bc of const id doesnt match\n");
conv_manager.clear();
}*/
// oppsite_const_id=tmp_oppsite_const_id;
} else {
conn_info_t &ori_conn_info = *conn_manager.const_id_mp[tmp_oppsite_const_id];
if (ori_conn_info.state.server_current_state == server_ready) {
if (conn_info.last_state_time < ori_conn_info.last_state_time) {
mylog(log_info, "[%s]conn_info.last_state_time<ori_conn_info.last_state_time. ignored new handshake\n", ip_port);
conn_info.state.server_current_state = server_idle;
conn_info.oppsite_const_id = 0;
return 0;
}
address_t addr1;
addr1.from_ip_port_new(raw_ip_version, &ori_conn_info.raw_info.recv_info.new_src_ip, ori_conn_info.raw_info.recv_info.src_port);
if (!conn_manager.exist(addr1)) // TODO remove this
{
mylog(log_fatal, "[%s]this shouldnt happen\n", ip_port);
myexit(-1);
}
address_t addr2;
addr2.from_ip_port_new(raw_ip_version, &conn_info.raw_info.recv_info.new_src_ip, conn_info.raw_info.recv_info.src_port);
if (!conn_manager.exist(addr2)) // TODO remove this
{
mylog(log_fatal, "[%s]this shouldnt happen2\n", ip_port);
myexit(-1);
}
conn_info_t *&p_ori = conn_manager.find_insert_p(addr1);
conn_info_t *&p = conn_manager.find_insert_p(addr2);
conn_info_t *tmp = p;
p = p_ori;
p_ori = tmp;
mylog(log_info, "[%s]grabbed a connection\n", ip_port);
// ori_conn_info.state.server_current_state=server_ready;
ori_conn_info.recover(conn_info);
// send_safer(ori_conn_info, 'h',hb_buf, hb_len);
// ori_conn_info.blob->anti_replay.re_init();
if (hb_mode == 0)
send_safer(ori_conn_info, 'h', hb_buf, 0); /////////////send
else
send_safer(ori_conn_info, 'h', hb_buf, hb_len);
ori_conn_info.last_hb_recv_time = get_current_time();
conn_info.state.server_current_state = server_idle;
conn_info.oppsite_const_id = 0;
} else {
mylog(log_fatal, "[%s]this should never happen\n", ip_port);
myexit(-1);
}
return 0;
}
return 0;
}
int server_on_raw_recv_handshake1(conn_info_t &conn_info, char *ip_port, char *data, int data_len) // called when server received a handshake1 packet from client
{
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
raw_info_t &raw_info = conn_info.raw_info;
// u32_t ip=conn_info.raw_info.recv_info.src_ip;
// uint16_t port=conn_info.raw_info.recv_info.src_port;
// char ip_port[40];
// sprintf(ip_port,"%s:%d",my_ntoa(ip),port);
if (data_len < int(3 * sizeof(my_id_t))) {
mylog(log_debug, "[%s] data_len=%d too short to be a handshake\n", ip_port, data_len);
return -1;
}
// id_t tmp_oppsite_id= ntohl(* ((u32_t *)&data[0]));
my_id_t tmp_oppsite_id;
memcpy(&tmp_oppsite_id, (u32_t *)&data[0], sizeof(tmp_oppsite_id));
tmp_oppsite_id = ntohl(tmp_oppsite_id);
// id_t tmp_my_id=ntohl(* ((u32_t *)&data[sizeof(id_t)]));
my_id_t tmp_my_id;
memcpy(&tmp_my_id, &data[sizeof(my_id_t)], sizeof(tmp_my_id));
tmp_my_id = ntohl(tmp_my_id);
if (tmp_my_id == 0) // received init handshake again
{
if (raw_mode == mode_faketcp) {
send_info.seq = recv_info.ack_seq;
send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len;
send_info.ts_ack = recv_info.ts;
}
if (raw_mode == mode_icmp) {
send_info.my_icmp_seq = recv_info.my_icmp_seq;
}
send_handshake(raw_info, conn_info.my_id, tmp_oppsite_id, const_id); //////////////send
mylog(log_info, "[%s]changed state to server_handshake1,my_id is %x\n", ip_port, conn_info.my_id);
} else if (tmp_my_id == conn_info.my_id) {
conn_info.oppsite_id = tmp_oppsite_id;
// id_t tmp_oppsite_const_id=ntohl(* ((u32_t *)&data[sizeof(id_t)*2]));
my_id_t tmp_oppsite_const_id;
memcpy(&tmp_oppsite_const_id, &data[sizeof(my_id_t) * 2], sizeof(tmp_oppsite_const_id));
tmp_oppsite_const_id = ntohl(tmp_oppsite_const_id);
if (raw_mode == mode_faketcp) {
send_info.seq = recv_info.ack_seq;
send_info.ack_seq = recv_info.seq + raw_info.recv_info.data_len;
send_info.ts_ack = recv_info.ts;
}
if (raw_mode == mode_icmp) {
send_info.my_icmp_seq = recv_info.my_icmp_seq;
}
server_on_raw_recv_pre_ready(conn_info, ip_port, tmp_oppsite_const_id);
} else {
mylog(log_debug, "[%s]invalid my_id %x,my_id is %x\n", ip_port, tmp_my_id, conn_info.my_id);
}
return 0;
}
int server_on_recv_safer_multi(conn_info_t &conn_info, char type, char *data, int data_len) {
return 0;
}
int server_on_raw_recv_multi() // called when server received an raw packet
{
char dummy_buf[buf_len];
raw_info_t peek_raw_info;
peek_raw_info.peek = 1;
packet_info_t &peek_info = peek_raw_info.recv_info;
mylog(log_trace, "got a packet\n");
if (pre_recv_raw_packet() < 0) return -1;
if (peek_raw(peek_raw_info) < 0) {
discard_raw_packet();
// recv(raw_recv_fd, 0,0, 0 );//
// struct sockaddr saddr;
// socklen_t saddr_size=sizeof(saddr);
/// recvfrom(raw_recv_fd, 0,0, 0 ,&saddr , &saddr_size);//
mylog(log_trace, "peek_raw failed\n");
return -1;
} else {
mylog(log_trace, "peek_raw success\n");
}
// u32_t ip=peek_info.src_ip;uint16_t port=peek_info.src_port;
int data_len;
char *data;
address_t addr;
addr.from_ip_port_new(raw_ip_version, &peek_info.new_src_ip, peek_info.src_port);
char ip_port[max_addr_len];
addr.to_str(ip_port);
// sprintf(ip_port,"%s:%d",my_ntoa(ip),port);
mylog(log_trace, "[%s]peek_raw\n", ip_port);
if (raw_mode == mode_faketcp && peek_info.syn == 1) {
if (!conn_manager.exist(addr) || conn_manager.find_insert(addr).state.server_current_state != server_ready) { // reply any syn ,before state become ready
raw_info_t tmp_raw_info;
if (recv_raw0(tmp_raw_info, data, data_len) < 0) {
return 0;
}
if (data_len >= max_data_len + 1) {
mylog(log_debug, "data_len=%d >= max_data_len+1,ignored", data_len);
return -1;
}
if (use_tcp_dummy_socket != 0)
return 0;
raw_info_t &raw_info = tmp_raw_info;
packet_info_t &send_info = raw_info.send_info;
packet_info_t &recv_info = raw_info.recv_info;
send_info.new_src_ip = recv_info.new_dst_ip;
send_info.src_port = recv_info.dst_port;
send_info.dst_port = recv_info.src_port;
send_info.new_dst_ip = recv_info.new_src_ip;
if (lower_level) {
handle_lower_level(raw_info);
}
if (data_len == 0 && raw_info.recv_info.syn == 1 && raw_info.recv_info.ack == 0) {
send_info.ack_seq = recv_info.seq + 1;
send_info.psh = 0;
send_info.syn = 1;
send_info.ack = 1;
send_info.ts_ack = recv_info.ts;
mylog(log_info, "[%s]received syn,sent syn ack back\n", ip_port);
send_raw0(raw_info, 0, 0);
return 0;
}
} else {
discard_raw_packet();
// recv(raw_recv_fd, 0,0,0);
}
return 0;
}
if (!conn_manager.exist(addr)) {
if (conn_manager.mp.size() >= max_handshake_conn_num) {
mylog(log_info, "[%s]reached max_handshake_conn_num,ignored new handshake\n", ip_port);
discard_raw_packet();
// recv(raw_recv_fd, 0,0, 0 );//
return 0;
}
raw_info_t tmp_raw_info;
if (raw_mode == mode_icmp) {
tmp_raw_info.send_info.dst_port = tmp_raw_info.send_info.src_port = addr.get_port();
}
if (recv_bare(tmp_raw_info, data, data_len) < 0) {
return 0;
}
if (data_len < int(3 * sizeof(my_id_t))) {
mylog(log_debug, "[%s]too short to be a handshake\n", ip_port);
return -1;
}
// id_t zero=ntohl(* ((u32_t *)&data[sizeof(id_t)]));
my_id_t zero;
memcpy(&zero, &data[sizeof(my_id_t)], sizeof(zero));
zero = ntohl(zero);
if (zero != 0) {
mylog(log_debug, "[%s]not a invalid initial handshake\n", ip_port);
return -1;
}
mylog(log_info, "[%s]got packet from a new ip\n", ip_port);
conn_info_t &conn_info = conn_manager.find_insert(addr);
conn_info.raw_info = tmp_raw_info;
raw_info_t &raw_info = conn_info.raw_info;
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
// conn_info.ip_port.ip=ip;
// conn_info.ip_port.port=port;
send_info.new_src_ip = recv_info.new_dst_ip;
send_info.src_port = recv_info.dst_port;
send_info.dst_port = recv_info.src_port;
send_info.new_dst_ip = recv_info.new_src_ip;
if (lower_level) {
handle_lower_level(raw_info);
}
// id_t tmp_oppsite_id= ntohl(* ((u32_t *)&data[0]));
// mylog(log_info,"[%s]handshake1 received %x\n",ip_port,tmp_oppsite_id);
conn_info.my_id = get_true_random_number_nz();
mylog(log_info, "[%s]created new conn,state: server_handshake1,my_id is %x\n", ip_port, conn_info.my_id);
conn_info.state.server_current_state = server_handshake1;
conn_info.last_state_time = get_current_time();
server_on_raw_recv_handshake1(conn_info, ip_port, data, data_len);
return 0;
}
conn_info_t &conn_info = conn_manager.find_insert(addr); // insert if not exist
packet_info_t &send_info = conn_info.raw_info.send_info;
packet_info_t &recv_info = conn_info.raw_info.recv_info;
raw_info_t &raw_info = conn_info.raw_info;
if (conn_info.state.server_current_state == server_handshake1) {
if (recv_bare(raw_info, data, data_len) != 0) {
return -1;
}
return server_on_raw_recv_handshake1(conn_info, ip_port, data, data_len);
}
if (conn_info.state.server_current_state == server_ready) {
vector<char> type_vec;
vector<string> data_vec;
recv_safer_multi(conn_info, type_vec, data_vec);
if (data_vec.empty()) {
mylog(log_debug, "recv_safer failed!\n");
return -1;
}
for (int i = 0; i < (int)type_vec.size(); i++) {
char type = type_vec[i];
char *data = (char *)data_vec[i].c_str(); // be careful, do not append data to it
int data_len = data_vec[i].length();
server_on_raw_recv_ready(conn_info, ip_port, type, data, data_len);
}
return 0;
}
if (conn_info.state.server_current_state == server_idle) {
discard_raw_packet();
// recv(raw_recv_fd, 0,0, 0 );//
return 0;
}
mylog(log_fatal, "we should never run to here\n");
myexit(-1);
return -1;
}
int server_on_udp_recv(conn_info_t &conn_info, fd64_t fd64) {
char buf[buf_len];
if (conn_info.state.server_current_state != server_ready) // TODO remove this for peformance
{
mylog(log_fatal, "p_conn_info->state.server_current_state!=server_ready!!!this shouldnt happen\n");
myexit(-1);
}
// conn_info_t &conn_info=*p_conn_info;
assert(conn_info.blob->conv_manager.s.is_data_used(fd64));
u32_t conv_id = conn_info.blob->conv_manager.s.find_conv_by_data(fd64);
int fd = fd_manager.to_fd(fd64);
int recv_len = recv(fd, buf, max_data_len + 1, 0);
mylog(log_trace, "received a packet from udp_fd,len:%d\n", recv_len);
if (recv_len == max_data_len + 1) {
mylog(log_warn, "huge packet, data_len > %d,dropped\n", max_data_len);
return -1;
}
if (recv_len < 0) {
mylog(log_debug, "udp fd,recv_len<0 continue,%s\n", strerror(errno));
return -1;
}
if (recv_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 ", recv_len, mtu_warn);
}
// conn_info.conv_manager->update_active_time(conv_id); server dosnt update from upd side,only update from raw side. (client updates at both side)
if (conn_info.state.server_current_state == server_ready) {
send_data_safer(conn_info, buf, recv_len, conv_id);
// send_data(g_packet_info_send,buf,recv_len,my_id,oppsite_id,conv_id);
mylog(log_trace, "send_data_safer ,sent !!\n");
}
return 0;
}
int server_event_loop() {
char buf[buf_len];
int i, j, k;
int ret;
if (raw_ip_version == AF_INET) {
if (local_addr.inner.ipv4.sin_addr.s_addr != 0) {
bind_addr_used = 1;
bind_addr.v4 = local_addr.inner.ipv4.sin_addr.s_addr;
}
} else {
assert(raw_ip_version == AF_INET6);
char zero_arr[16] = {0};
if (memcmp(&local_addr.inner.ipv6.sin6_addr, zero_arr, 16) != 0) {
bind_addr_used = 1;
bind_addr.v6 = local_addr.inner.ipv6.sin6_addr;
}
}
// bind_address_uint32=local_ip_uint32;//only server has bind adress,client sets it to zero
if (lower_level) {
if (lower_level_manual) {
init_ifindex(if_name, raw_send_fd, ifindex);
mylog(log_info, "we are running at lower-level (manual) mode\n");
} else {
mylog(log_info, "we are running at lower-level (auto) mode\n");
}
}
if (raw_mode == mode_faketcp) {
bind_fd = socket(local_addr.get_type(), SOCK_STREAM, 0);
} else if (raw_mode == mode_udp || raw_mode == mode_icmp) // bind an adress to avoid collision,for icmp,there is no port,just bind a udp port
{
bind_fd = socket(local_addr.get_type(), SOCK_DGRAM, 0);
}
// struct sockaddr_in temp_bind_addr={0};
// bzero(&temp_bind_addr, sizeof(temp_bind_addr));
// temp_bind_addr.sin_family = AF_INET;
// temp_bind_addr.sin_port = local_addr.get_port();
// temp_bind_addr.sin_addr.s_addr = local_addr.inner.ipv4.sin_addr.s_addr;
if (bind(bind_fd, (struct sockaddr *)&local_addr.inner, local_addr.get_len()) != 0) {
mylog(log_fatal, "bind fail\n");
myexit(-1);
}
if (raw_mode == mode_faketcp) {
if (listen(bind_fd, SOMAXCONN) != 0) {
mylog(log_fatal, "listen fail\n");
myexit(-1);
}
}
// init_raw_socket();
init_filter(local_addr.get_port()); // bpf filter
epollfd = epoll_create1(0);
const int max_events = 4096;
struct epoll_event ev, events[max_events];
if (epollfd < 0) {
mylog(log_fatal, "epoll return %d\n", epollfd);
myexit(-1);
}
ev.events = EPOLLIN;
ev.data.u64 = raw_recv_fd;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, raw_recv_fd, &ev);
if (ret != 0) {
mylog(log_fatal, "add raw_fd error\n");
myexit(-1);
}
int timer_fd;
set_timer(epollfd, timer_fd);
u64_t begin_time = 0;
u64_t end_time = 0;
mylog(log_info, "now listening at %s\n", local_addr.get_str());
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(epollfd, 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);
}
while (1) ////////////////////////
{
if (about_to_exit) myexit(0);
int nfds = epoll_wait(epollfd, events, max_events, 180 * 1000);
if (nfds < 0) { // allow zero
if (errno == EINTR) {
mylog(log_info, "epoll interrupted by signal,continue\n");
// myexit(0);
} else {
mylog(log_fatal, "epoll_wait return %d,%s\n", nfds, strerror(errno));
myexit(-1);
}
}
int idx;
for (idx = 0; idx < nfds; ++idx) {
// mylog(log_debug,"ndfs: %d \n",nfds);
epoll_trigger_counter++;
// printf("%d %d %d %d\n",timer_fd,raw_recv_fd,raw_send_fd,n);
if ((events[idx].data.u64) == (u64_t)timer_fd) {
if (debug_flag) begin_time = get_current_time();
conn_manager.clear_inactive();
u64_t dummy;
int unused = read(timer_fd, &dummy, 8);
// current_time_rough=get_current_time();
if (debug_flag) {
end_time = get_current_time();
mylog(log_debug, "timer_fd,%llu,%llu,%llu\n", begin_time, end_time, end_time - begin_time);
}
mylog(log_trace, "epoll_trigger_counter: %d \n", epoll_trigger_counter);
epoll_trigger_counter = 0;
} else if (events[idx].data.u64 == (u64_t)raw_recv_fd) {
if (debug_flag) begin_time = get_current_time();
server_on_raw_recv_multi();
if (debug_flag) {
end_time = get_current_time();
mylog(log_debug, "raw_recv_fd,%llu,%llu,%llu \n", begin_time, end_time, end_time - begin_time);
}
} else if (events[idx].data.u64 == (u64_t)fifo_fd) {
int len = read(fifo_fd, buf, sizeof(buf));
if (len < 0) {
mylog(log_warn, "fifo read failed len=%d,errno=%s\n", len, strerror(errno));
continue;
}
// assert(len>=0);
buf[len] = 0;
while (len >= 1 && buf[len - 1] == '\n')
buf[len - 1] = 0;
mylog(log_info, "got data from fifo,len=%d,s=[%s]\n", len, buf);
mylog(log_info, "unknown command\n");
} else if (events[idx].data.u64 > u32_t(-1)) {
fd64_t fd64 = events[idx].data.u64;
if (!fd_manager.exist(fd64)) {
mylog(log_trace, "fd64 no longer exist\n");
return -1;
}
assert(fd_manager.exist_info(fd64));
conn_info_t *p_conn_info = fd_manager.get_info(fd64).p_conn_info;
conn_info_t &conn_info = *p_conn_info;
if (fd64 == conn_info.timer_fd64) //////////timer_fd64
{
if (debug_flag) begin_time = get_current_time();
int fd = fd_manager.to_fd(fd64);
u64_t dummy;
int unused = read(fd, &dummy, 8);
assert(conn_info.state.server_current_state == server_ready); // TODO remove this for peformance
server_on_timer_multi(conn_info);
if (debug_flag) {
end_time = get_current_time();
mylog(log_debug, "(events[idx].data.u64 >>32u) == 2u ,%llu,%llu,%llu \n", begin_time, end_time, end_time - begin_time);
}
} else // udp_fd64
{
if (debug_flag) begin_time = get_current_time();
server_on_udp_recv(conn_info, fd64);
if (debug_flag) {
end_time = get_current_time();
mylog(log_debug, "(events[idx].data.u64 >>32u) == 1u,%lld,%lld,%lld \n", begin_time, end_time, end_time - begin_time);
}
}
} else {
mylog(log_fatal, "unknown fd,this should never happen\n");
myexit(-1);
}
}
}
return 0;
}
#endif