mirror of
https://github.com/xjasonlyu/tun2socks.git
synced 2025-10-08 18:20:41 +08:00
add go-tun2socks code
This commit is contained in:
165
core/tcp_callback_export.go
Normal file
165
core/tcp_callback_export.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package core
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -I./c/include
|
||||
#include "lwip/tcp.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// These exported callback functions must be placed in a seperated file.
|
||||
//
|
||||
// See also:
|
||||
// https://github.com/golang/go/issues/20639
|
||||
// https://golang.org/cmd/cgo/#hdr-C_references_to_Go
|
||||
|
||||
//export tcpAcceptFn
|
||||
func tcpAcceptFn(arg unsafe.Pointer, newpcb *C.struct_tcp_pcb, err C.err_t) C.err_t {
|
||||
if err != C.ERR_OK {
|
||||
return err
|
||||
}
|
||||
|
||||
if tcpConnHandler == nil {
|
||||
panic("must register a TCP connection handler")
|
||||
}
|
||||
|
||||
if _, nerr := newTCPConn(newpcb, tcpConnHandler); nerr != nil {
|
||||
switch nerr.(*lwipError).Code {
|
||||
case LWIP_ERR_ABRT:
|
||||
return C.ERR_ABRT
|
||||
case LWIP_ERR_OK:
|
||||
return C.ERR_OK
|
||||
default:
|
||||
return C.ERR_CONN
|
||||
}
|
||||
}
|
||||
|
||||
return C.ERR_OK
|
||||
}
|
||||
|
||||
//export tcpRecvFn
|
||||
func tcpRecvFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb, p *C.struct_pbuf, err C.err_t) C.err_t {
|
||||
if err != C.ERR_OK && err != C.ERR_ABRT {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only free the pbuf when returning ERR_OK or ERR_ABRT,
|
||||
// otherwise must not free the pbuf.
|
||||
shouldFreePbuf := true
|
||||
defer func() {
|
||||
if p != nil && shouldFreePbuf {
|
||||
C.pbuf_free(p)
|
||||
}
|
||||
}()
|
||||
|
||||
conn, ok := tcpConns.Load(getConnKeyVal(arg))
|
||||
if !ok {
|
||||
// The connection does not exists.
|
||||
C.tcp_abort(tpcb)
|
||||
return C.ERR_ABRT
|
||||
}
|
||||
|
||||
if p == nil {
|
||||
// Peer closed, EOF.
|
||||
err := conn.(TCPConn).LocalClosed()
|
||||
switch err.(*lwipError).Code {
|
||||
case LWIP_ERR_ABRT:
|
||||
return C.ERR_ABRT
|
||||
case LWIP_ERR_OK:
|
||||
return C.ERR_OK
|
||||
default:
|
||||
panic("unexpected error")
|
||||
}
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
var totlen = int(p.tot_len)
|
||||
if p.tot_len == p.len {
|
||||
buf = (*[1 << 30]byte)(unsafe.Pointer(p.payload))[:totlen:totlen]
|
||||
} else {
|
||||
buf = NewBytes(totlen)
|
||||
defer FreeBytes(buf)
|
||||
C.pbuf_copy_partial(p, unsafe.Pointer(&buf[0]), p.tot_len, 0)
|
||||
}
|
||||
|
||||
rerr := conn.(TCPConn).Receive(buf[:totlen])
|
||||
if rerr != nil {
|
||||
switch rerr.(*lwipError).Code {
|
||||
case LWIP_ERR_ABRT:
|
||||
return C.ERR_ABRT
|
||||
case LWIP_ERR_OK:
|
||||
return C.ERR_OK
|
||||
case LWIP_ERR_CONN:
|
||||
shouldFreePbuf = false
|
||||
// Tell lwip we can't receive data at the moment,
|
||||
// lwip will store it and try again later.
|
||||
return C.ERR_CONN
|
||||
case LWIP_ERR_CLSD:
|
||||
shouldFreePbuf = false
|
||||
// lwip won't handle ERR_CLSD error for us, manually
|
||||
// shuts down the rx side.
|
||||
C.tcp_shutdown(tpcb, 1, 0)
|
||||
return C.ERR_CLSD
|
||||
default:
|
||||
panic("unexpected error")
|
||||
}
|
||||
}
|
||||
|
||||
return C.ERR_OK
|
||||
}
|
||||
|
||||
//export tcpSentFn
|
||||
func tcpSentFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb, len C.u16_t) C.err_t {
|
||||
if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok {
|
||||
err := conn.(TCPConn).Sent(uint16(len))
|
||||
switch err.(*lwipError).Code {
|
||||
case LWIP_ERR_ABRT:
|
||||
return C.ERR_ABRT
|
||||
case LWIP_ERR_OK:
|
||||
return C.ERR_OK
|
||||
default:
|
||||
panic("unexpected error")
|
||||
}
|
||||
} else {
|
||||
C.tcp_abort(tpcb)
|
||||
return C.ERR_ABRT
|
||||
}
|
||||
}
|
||||
|
||||
//export tcpErrFn
|
||||
func tcpErrFn(arg unsafe.Pointer, err C.err_t) {
|
||||
if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok {
|
||||
switch err {
|
||||
case C.ERR_ABRT:
|
||||
// Aborted through tcp_abort or by a TCP timer
|
||||
conn.(TCPConn).Err(errors.New("connection aborted"))
|
||||
case C.ERR_RST:
|
||||
// The connection was reset by the remote host
|
||||
conn.(TCPConn).Err(errors.New("connection reseted"))
|
||||
default:
|
||||
conn.(TCPConn).Err(errors.New(fmt.Sprintf("lwip error code %v", int(err))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//export tcpPollFn
|
||||
func tcpPollFn(arg unsafe.Pointer, tpcb *C.struct_tcp_pcb) C.err_t {
|
||||
if conn, ok := tcpConns.Load(getConnKeyVal(arg)); ok {
|
||||
err := conn.(TCPConn).Poll()
|
||||
switch err.(*lwipError).Code {
|
||||
case LWIP_ERR_ABRT:
|
||||
return C.ERR_ABRT
|
||||
case LWIP_ERR_OK:
|
||||
return C.ERR_OK
|
||||
default:
|
||||
panic("unexpected error")
|
||||
}
|
||||
} else {
|
||||
C.tcp_abort(tpcb)
|
||||
return C.ERR_ABRT
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user