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:
109
_demo/libuv/echo_server.go
Normal file
109
_demo/libuv/echo_server.go
Normal 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)
|
||||
}
|
||||
109
c/libuv/_demo/echo_server/echo_server.go
Normal file
109
c/libuv/_demo/echo_server/echo_server.go
Normal 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)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user