feat(c/libuv/demo): Add libuv demo echo_server

refactor(c/libuv): Adjust comments and file names to accommodate merge
This commit is contained in:
赵英杰
2024-07-22 18:02:09 +08:00
committed by hackerchai
parent e9d4328fad
commit c63580ee38
6 changed files with 252 additions and 128 deletions

109
_demo/libuv/echo_server.go Normal file
View File

@@ -0,0 +1,109 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/net"
"unsafe"
)
var DEFAULT_PORT c.Int = 8080
var DEFAULT_BACKLOG c.Int = 128
var loop *libuv.Loop
type WriteReq struct {
req libuv.Write
buf libuv.Buf
}
func FreeWriteReq(req *libuv.Write) {
wr := (*WriteReq)(c.Pointer(req))
c.Free(c.Pointer(wr.buf.Base))
c.Free(c.Pointer(wr))
}
func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
buf.Len = suggestedSize
}
func EchoWrite(req *libuv.Write, status c.Int) {
if status != 0 {
c.Fprintf(c.Stderr, c.Str("write error: %s\n"), libuv.Strerror(status))
}
defer FreeWriteReq(req)
}
func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
if nread > 0 {
req := (*WriteReq)(c.Malloc(unsafe.Sizeof(WriteReq{})))
if req == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for write request\n"))
defer c.Free(c.Pointer(buf.Base))
return
}
req.buf = libuv.InitBuf(buf.Base, c.Uint(nread))
(*libuv.Write)(c.Pointer(req)).Write(client, []libuv.Buf{req.buf}, 1, EchoWrite)
return
}
if nread < 0 {
if (libuv.Errno)(nread) != libuv.EOF {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(c.Int(nread)))
}
(*libuv.Handle)(client).Close(nil)
}
if buf.Base != nil {
c.Free(c.Pointer(buf.Base))
}
}
func OnNewConnection(server *libuv.Stream, status c.Int) {
if status < 0 {
c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(status))
return
}
client := (*libuv.Tcp)(c.Malloc(unsafe.Sizeof(libuv.Tcp{})))
if client == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for client\n"))
return
}
if libuv.InitTcp(loop, client) < 0 {
c.Fprintf(c.Stderr, c.Str("Failed to initialize client\n"))
c.Free(c.Pointer(client))
return
}
if server.Accept((*libuv.Stream)(client)) == 0 {
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead)
} else {
(*libuv.Handle)(client).Close(nil)
}
}
func main() {
// Initialize the default event loop
loop = libuv.DefaultLoop()
// Initialize a TCP server
var server libuv.Tcp
libuv.InitTcp(loop, &server)
// Set up the address to bind the server to
var addr net.SockaddrIn
libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr)
// Bind the server to the specified address and port
(&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0)
res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection)
if res != 0 {
c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res))
return
}
// Start listening for incoming connections
loop.Run(libuv.RUN_DEFAULT)
}

View File

@@ -0,0 +1,109 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/libuv"
"github.com/goplus/llgo/c/net"
"unsafe"
)
var DEFAULT_PORT c.Int = 8080
var DEFAULT_BACKLOG c.Int = 128
var loop *libuv.Loop
type WriteReq struct {
req libuv.Write
buf libuv.Buf
}
func FreeWriteReq(req *libuv.Write) {
wr := (*WriteReq)(c.Pointer(req))
c.Free(c.Pointer(wr.buf.Base))
c.Free(c.Pointer(wr))
}
func AllocBuffer(handle *libuv.Handle, suggestedSize uintptr, buf *libuv.Buf) {
buf.Base = (*c.Char)(c.Malloc(suggestedSize))
buf.Len = suggestedSize
}
func EchoWrite(req *libuv.Write, status c.Int) {
if status != 0 {
c.Fprintf(c.Stderr, c.Str("write error: %s\n"), libuv.Strerror(status))
}
defer FreeWriteReq(req)
}
func EchoRead(client *libuv.Stream, nread c.Long, buf *libuv.Buf) {
if nread > 0 {
req := (*WriteReq)(c.Malloc(unsafe.Sizeof(WriteReq{})))
if req == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for write request\n"))
defer c.Free(c.Pointer(buf.Base))
return
}
req.buf = libuv.InitBuf(buf.Base, c.Uint(nread))
(*libuv.Write)(c.Pointer(req)).Write(client, []libuv.Buf{req.buf}, 1, EchoWrite)
return
}
if nread < 0 {
if (libuv.Errno)(nread) != libuv.EOF {
c.Fprintf(c.Stderr, c.Str("Read error: %s\n"), libuv.Strerror(c.Int(nread)))
}
(*libuv.Handle)(client).Close(nil)
}
if buf.Base != nil {
c.Free(c.Pointer(buf.Base))
}
}
func OnNewConnection(server *libuv.Stream, status c.Int) {
if status < 0 {
c.Fprintf(c.Stderr, c.Str("New connection error: %s\n"), libuv.Strerror(status))
return
}
client := (*libuv.Tcp)(c.Malloc(unsafe.Sizeof(libuv.Tcp{})))
if client == nil {
c.Fprintf(c.Stderr, c.Str("Failed to allocate memory for client\n"))
return
}
if libuv.InitTcp(loop, client) < 0 {
c.Fprintf(c.Stderr, c.Str("Failed to initialize client\n"))
c.Free(c.Pointer(client))
return
}
if server.Accept((*libuv.Stream)(client)) == 0 {
(*libuv.Stream)(client).StartRead(AllocBuffer, EchoRead)
} else {
(*libuv.Handle)(client).Close(nil)
}
}
func main() {
// Initialize the default event loop
loop = libuv.DefaultLoop()
// Initialize a TCP server
var server libuv.Tcp
libuv.InitTcp(loop, &server)
// Set up the address to bind the server to
var addr net.SockaddrIn
libuv.Ip4Addr(c.Str("0.0.0.0"), DEFAULT_PORT, &addr)
// Bind the server to the specified address and port
(&server).Bind((*net.SockAddr)(c.Pointer(&addr)), 0)
res := (*libuv.Stream)(&server).Listen(DEFAULT_BACKLOG, OnNewConnection)
if res != 0 {
c.Fprintf(c.Stderr, c.Str("Listen error: %s\n"), libuv.Strerror(res))
return
}
// Start listening for incoming connections
loop.Run(libuv.RUN_DEFAULT)
}

View File

@@ -93,93 +93,6 @@ const (
ERRNO_MAX
)
//var errnoDescriptions = map[Errno]string{
// E2BIG: "argument list too long",
// EACCES: "permission denied",
// EADDRINUSE: "address already in use",
// EADDRNOTAVAIL: "address not available",
// EAFNOSUPPORT: "address family not supported",
// EAGAIN: "resource temporarily unavailable",
// EAI_ADDRFAMILY: "address family not supported",
// EAI_AGAIN: "temporary failure",
// EAI_BADFLAGS: "bad ai_flags value",
// EAI_BADHINTS: "invalid value for hints",
// EAI_CANCELED: "request canceled",
// EAI_FAIL: "permanent failure",
// EAI_FAMILY: "ai_family not supported",
// EAI_MEMORY: "out of memory",
// EAI_NODATA: "no address",
// EAI_NONAME: "unknown node or service",
// EAI_OVERFLOW: "argument buffer overflow",
// EAI_PROTOCOL: "resolved protocol is unknown",
// EAI_SERVICE: "service not available for socket type",
// EAI_SOCKTYPE: "socket type not supported",
// EALREADY: "connection already in progress",
// EBADF: "bad file descriptor",
// EBUSY: "resource busy or locked",
// ECANCELED: "operation canceled",
// ECHARSET: "invalid Unicode character",
// ECONNABORTED: "software caused connection abort",
// ECONNREFUSED: "connection refused",
// ECONNRESET: "connection reset by peer",
// EDESTADDRREQ: "destination address required",
// EEXIST: "file already exists",
// EFAULT: "bad address in system call argument",
// EFBIG: "file too large",
// EHOSTUNREACH: "host is unreachable",
// EINTR: "interrupted system call",
// EINVAL: "invalid argument",
// EIO: "i/o error",
// EISCONN: "socket is already connected",
// EISDIR: "illegal operation on a directory",
// ELOOP: "too many symbolic links encountered",
// EMFILE: "too many open files",
// EMSGSIZE: "message too long",
// ENAMETOOLONG: "name too long",
// ENETDOWN: "network is down",
// ENETUNREACH: "network is unreachable",
// ENFILE: "file table overflow",
// ENOBUFS: "no buffer space available",
// ENODEV: "no such device",
// ENOENT: "no such file or directory",
// ENOMEM: "not enough memory",
// ENONET: "machine is not on the network",
// ENOPROTOOPT: "protocol not available",
// ENOSPC: "no space left on device",
// ENOSYS: "function not implemented",
// ENOTCONN: "socket is not connected",
// ENOTDIR: "not a directory",
// ENOTEMPTY: "directory not empty",
// ENOTSOCK: "socket operation on non-socket",
// ENOTSUP: "operation not supported on socket",
// EOVERFLOW: "value too large for defined data type",
// EPERM: "operation not permitted",
// EPIPE: "broken pipe",
// EPROTO: "protocol error",
// EPROTONOSUPPORT: "protocol not supported",
// EPROTOTYPE: "protocol wrong type for socket",
// ERANGE: "result too large",
// EROFS: "read-only file system",
// ESHUTDOWN: "cannot send after transport endpoint shutdown",
// ESPIPE: "invalid seek",
// ESRCH: "no such process",
// ETIMEDOUT: "connection timed out",
// ETXTBSY: "text file is busy",
// EXDEV: "cross-device link not permitted",
// UNKNOWN: "unknown error",
// EOF: "end of file",
// ENXIO: "no such device or address",
// EMLINK: "too many links",
// EHOSTDOWN: "host is down",
// EREMOTEIO: "remote I/O error",
// ENOTTY: "inappropriate ioctl for device",
// EFTYPE: "inappropriate file type or format",
// EILSEQ: "illegal byte sequence",
// ESOCKTNOSUPPORT: "socket type not supported",
// ENODATA: "no data available",
// EUNATCH: "protocol driver not attached",
//}
type Errno c.Int
//go:linkname TranslateSysError C.uv_translate_sys_error

View File

@@ -17,12 +17,6 @@ const (
METRICS_IDLE_TIME
)
const (
RUN_DEFAULT RunMode = iota
RUN_ONCE
RUN_NOWAIT
)
const (
UV_LEAVE_GROUP Membership = iota
UV_JOIN_GROUP
@@ -68,8 +62,6 @@ const (
type LoopOption c.Int
type RunMode c.Int
type Membership c.Int
type HandleType c.Int
@@ -85,9 +77,6 @@ type OsFd c.Int
// ----------------------------------------------
/* Handle types. */
type Loop struct {
Unused [0]byte
}
type Handle struct {
Unused [0]byte
@@ -101,14 +90,6 @@ type Stream struct {
Unused [0]byte
}
type Tcp struct {
Unused [0]byte
}
type Udp struct {
Unused [0]byte
}
type Pipe struct {
Unused [0]byte
}
@@ -121,10 +102,6 @@ type Poll struct {
Unused [0]byte
}
type Timer struct {
Unused [0]byte
}
type Prepare struct {
Unused [0]byte
}
@@ -183,17 +160,6 @@ type Connect struct {
Unused [0]byte
}
type UdpSend struct {
Unused [0]byte
}
// ----------------------------------------------
type Buf struct {
Base *c.Char
Len uintptr
}
// ----------------------------------------------
/* Function type */
@@ -257,7 +223,7 @@ func (shutdown *Shutdown) Shutdown(stream *Stream, shutdownCb ShutdownCb) c.Int
// ----------------------------------------------
/* HandleT related function and method */
/* Handle related function and method */
// llgo:link (*Handle).Ref C.uv_ref
func (handle *Handle) Ref() {}
@@ -317,9 +283,6 @@ func (handle *Handle) Fileno(fd *OsFd) c.Int {
return 0
}
//go:linkname InitBuf C.uv_buf_init
func InitBuf(base *c.Char, len c.Uint) Buf
//go:linkname UvPipe C.uv_pipe
func UvPipe(fds [2]Uv_File, readFlags c.Int, writeFlags c.Int) c.Int {
return 0

View File

@@ -62,6 +62,24 @@ type UdpFlags c.Int
// ----------------------------------------------
/* Handle types. */
type Tcp struct {
Unused [0]byte
}
type Udp struct {
Unused [0]byte
}
/* Request types. */
type UdpSend struct {
Unused [0]byte
}
// ----------------------------------------------
/* Function type */
// llgo:type C
@@ -78,7 +96,7 @@ type UdpRecvCb func(handle *Udp, nread c.Long, buf *Buf, addr *net.SockAddr, fla
// ----------------------------------------------
/* TcpT related function and method */
/* Tcp related function and method */
//go:linkname InitTcp C.uv_tcp_init
func InitTcp(loop *Loop, tcp *Tcp) c.Int
@@ -131,7 +149,7 @@ func TcpConnect(req *Connect, tcp *Tcp, addr *net.SockAddr, connectCb ConnectCb)
// ----------------------------------------------
/* UdpT related function and method */
/* Udp related function and method */
//go:linkname InitUdp C.uv_udp_init
func InitUdp(loop *Loop, udp *Udp) c.Int

View File

@@ -5,10 +5,22 @@ import (
_ "unsafe"
)
// ----------------------------------------------
/* Handle types. */
type Timer struct {
Unused [0]byte
}
// ----------------------------------------------
// llgo:type C
type TimerCb func(timer *Timer)
/* TimerT related function and method */
// ----------------------------------------------
/* Timer related function and method */
//go:linkname InitTimer C.uv_timer_init
func InitTimer(loop *Loop, timer *Timer) c.Int