mirror of
				https://github.com/xjasonlyu/tun2socks.git
				synced 2025-11-01 04:22:44 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			166 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | |
| 	}
 | |
| }
 | 
