Skip to content

Commit

Permalink
[IMP]Use the CGO callback function to transfer data from C to GO, an …
Browse files Browse the repository at this point in the history
…alternative to the UNIX Domain Socket scheme
  • Loading branch information
randolphcyg committed Dec 25, 2023
1 parent f381664 commit 95f8e91
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 250 deletions.
2 changes: 1 addition & 1 deletion README-zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ apt install bison
- [x] 离线数据包文件解析并输出 JSON 格式结果
- [x] 离线数据包解析获取16进制相关数据
- [x] 实时监听接口并捕获数据包
- [x] 封装 go 调用实时解析的逻辑——通过 Unix 域套接字(AF_UNIX)将实时解析结果传输到 golang
- [x] 封装 go 调用实时解析的逻辑——通过回调函数将实时解析结果传输到 golang
- [x] 封装 go 对收到的 Golang 调用实时数据包解析结果的处理
- [x] 优化代码并解决内存泄漏问题,使实时接口可以长时间运行
- [x] 支持停止实时接口
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ apt install bison
- [x] Offline packet files parse and output JSON format
- [x] Offline packet parsing to obtain base-16 related data
- [x] Listen to interfaces in real time and capture packets
- [x] Encapsulates the logic for go to invoke real-time parsing - transmits real-time parsing results to golang via Unix domain sockets (AF_UNIX)
- [x] Encapsulates the logic for go to invoke real-time parsing - transmits real-time parsing results to golang
- [x] Encapsulates Golang's processing of the received real-time packet parsing results for Golang calling
- [x] Optimize code to resolve memory leaks
- [x] Stop real-time packet capture parsing
Expand Down
80 changes: 26 additions & 54 deletions gowireshark.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ import "C"
import (
"encoding/json"
"log/slog"
"net"
"os"
"strconv"
"syscall"
"unsafe"

"github.com/pkg/errors"
Expand All @@ -41,6 +39,9 @@ var (
// result of a single data packet, which is convenient for converting c char to go string
const SINGLEPKTMAXLEN = 6553500

// DissectResChans dissect result chan map
var DissectResChans = make(map[string]chan FrameDissectRes)

// Init policies、WTAP mod、EPAN mod.
func init() {
initEnvRes := C.init_env()
Expand Down Expand Up @@ -525,78 +526,49 @@ func SetIfaceNonblockStatus(deviceName string, isNonblock bool) (status bool, er
return
}

// RunSock Unix domain socket(AF_UNIX) server: start socket and read data.
func RunSock(sockServerPath string, sockBuffSize int, listener *net.UnixConn, pkgChan chan FrameDissectRes) (err error) {
if sockServerPath == "" {
err = errors.Wrap(err, "sockServerPath is blank")
return
//export GoDataCallback
func GoDataCallback(data *C.char, length C.int, deviceName *C.char) {
goPacket := ""
if data != nil {
goPacket = C.GoStringN(data, length)
}

addr, err := net.ResolveUnixAddr("unixgram", sockServerPath)
if err != nil {
err = errors.Wrap(err, "fail to resolve UnixAddr")
panic(err)
deviceNameStr := ""
if deviceName != nil {
deviceNameStr = C.GoString(deviceName)
}

syscall.Unlink(sockServerPath)
if listener == nil {
listener, err = net.ListenUnixgram("unixgram", addr)
if err != nil {
err = errors.Wrap(err, "fail to start Unix domain socket(AF_UNIX) server")
return
}
// unmarshal each pkg dissect result
singleFrameData, err := UnmarshalDissectResult(string(goPacket))
if err != nil {
err = errors.Wrap(ErrUnmarshalObj, "WsIndex: "+singleFrameData.WsIndex)
slog.Warn(err.Error())
}

// read data from c client
go readSock(listener, pkgChan, sockBuffSize)

return
}

// readSock Unix domain socket(AF_UNIX) server: read data func
func readSock(listener *net.UnixConn, pkgChan chan FrameDissectRes, sockBuffSize int) {
for {
buf := make([]byte, sockBuffSize)
size, _, err := listener.ReadFromUnix(buf)
if err != nil {
err = errors.Wrap(err, "fail to read from Unix domain socket(AF_UNIX) client")
panic(err)
}

// handle each pkg
// unmarshal dissect result
singleFrameData, err := UnmarshalDissectResult(string(buf[:size]))
if err != nil {
err = errors.Wrap(ErrUnmarshalObj, "WsIndex: "+singleFrameData.WsIndex)
slog.Warn(err.Error())
}

// write packet dissect result to go pipe
pkgChan <- singleFrameData
// write packet dissect result to go pipe
if ch, ok := DissectResChans[deviceNameStr]; ok {
ch <- singleFrameData
}
}

// DissectPktLive
//
// @Description: Start up Unix domain socket(AF_UNIX) client, capture and dissect packet.
// @Description: Set up callback function, capture and dissect packet.
// @param deviceName
// @param bpfFilter bpf filter
// @param sockServerPath
// @param num
// @param promisc: 0 indicates a non-promiscuous mode, and any other value indicates a promiscuous mode
// @param timeout
func DissectPktLive(deviceName, bpfFilter, sockServerPath string, num, promisc, timeout int) (err error) {
func DissectPktLive(deviceName, bpfFilter string, num, promisc, timeout int) (err error) {
// Set up callback function
C.setDataCallback((C.DataCallback)(C.GoDataCallback))

if deviceName == "" {
err = errors.Wrap(err, "device name is blank")
return
}

if sockServerPath == "" {
err = errors.Wrap(err, "sockServerPath is blank")
return
}

errMsg := C.handle_packet(C.CString(deviceName), C.CString(bpfFilter), C.CString(sockServerPath), C.int(num), C.int(promisc), C.int(timeout))
errMsg := C.handle_packet(C.CString(deviceName), C.CString(bpfFilter), C.int(num), C.int(promisc), C.int(timeout))
if C.strlen(errMsg) != 0 {
// transfer c char to go string
errMsgStr := CChar2GoStr(errMsg)
Expand All @@ -607,7 +579,7 @@ func DissectPktLive(deviceName, bpfFilter, sockServerPath string, num, promisc,
return
}

// StopDissectPktLive Stop capture packet live、 free all memory allocated、close socket.
// StopDissectPktLive Stop capture packet live、 free all memory allocated.
func StopDissectPktLive(deviceName string) (err error) {
if deviceName == "" {
err = errors.Wrap(err, "device name is blank")
Expand Down
13 changes: 9 additions & 4 deletions include/online.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@ int get_if_nonblock_status(char *device_name);
// Set interface nonblock status
int set_if_nonblock_status(char *device_name, int nonblock);
// Capture and dissect packet in real time
char *handle_packet(char *device_name, char *bpf_expr, char *sock_server_path,
int num, int promisc, int to_ms);
// Stop capture packet live、 free all memory allocated、close socket.
char *stop_dissect_capture_pkg(char *device_name);
char *handle_packet(char *device_name, char *bpf_expr, int num, int promisc,
int to_ms);
// Stop capture packet live、 free all memory allocated
char *stop_dissect_capture_pkg(char *device_name);

// Set up callback function for send packet to Go
typedef void (*DataCallback)(const char *, int, const char *);
void GoDataCallback(char *data, int length, char *device_name);
void setDataCallback(DataCallback callback);
Loading

0 comments on commit 95f8e91

Please sign in to comment.