Merge pull request #523 from spongehah/c/hyper_related

[feat] llgo/c/hyper-related c lib
This commit is contained in:
xushiwei
2024-07-19 08:20:12 +08:00
committed by GitHub
9 changed files with 243 additions and 21 deletions

20
_demo/netdb/netdb.go Normal file
View File

@@ -0,0 +1,20 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/net"
)
func main() {
var hints net.AddrInfo
hints.AiFamily = net.AF_UNSPEC
hints.AiSockType = net.SOCK_STREAM
host := "httpbin.org"
port := "80"
var result *net.AddrInfo
c.Printf(c.Str("%d\n"), net.Getaddrinfo(c.Str(host), c.Str(port), &hints, &result))
c.Printf(c.Str("%d\n"), net.Freeaddrinfo(result))
}

44
_demo/select/select.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/os"
"github.com/goplus/llgo/c/sys"
"github.com/goplus/llgo/c/syscall"
"unsafe"
)
func main() {
var readFds syscall.FdSet
sys.FD_ZERO(&readFds)
sys.FD_SET(0, &readFds)
var tv sys.TimeVal
tv.TvSec = 5
tv.TvUSec = 0
c.Printf(c.Str("Waiting for input on stdin...\n"))
ret := sys.Select(1, &readFds, nil, nil, &tv)
if ret == -1 {
c.Perror(c.Str("select error"))
c.Exit(1)
} else if ret == 0 {
c.Printf(c.Str("Timeout occurred! No data after 5 seconds.\n"))
} else {
if sys.FD_ISSET(0, &readFds) != 0 {
var buffer [100]c.Char
n := os.Read(0, c.Pointer(&buffer[:][0]), unsafe.Sizeof(buffer)-1)
if n == -1 {
c.Perror(c.Str("read error"))
c.Exit(1)
} else if n == 0 {
c.Printf(c.Str("End of file\n"))
} else {
buffer[n] = c.Char(0)
c.Printf(c.Str("Read %ld bytes: %s\n"), n, &buffer[0])
}
}
}
}

87
_demo/select/select2.go Normal file
View File

@@ -0,0 +1,87 @@
package main
import (
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/net"
"github.com/goplus/llgo/c/os"
"github.com/goplus/llgo/c/sys"
"github.com/goplus/llgo/c/syscall"
"unsafe"
)
const (
SERVER_IP = "110.242.68.66" // Get the IP address by ping baidu.com
SERVER_PORT = 80
BUFFER_SIZE = 4096 * 1024
)
func main() {
var server net.SockaddrIn
sendBuf := c.Str("GET / HTTP/1.1\r\nHost: baidu.com\r\n\r\n")
var recvBuf [BUFFER_SIZE]c.Char
var bytes_sent, bytes_received c.Int
// create net
sock := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
if sock < 0 {
c.Perror(c.Str("Socket creation failed"))
return
}
// set server addr
c.Memset(c.Pointer(&server), 0, unsafe.Sizeof(server))
server.Family = net.AF_INET
server.Port = net.Htons(SERVER_PORT)
server.Addr.Addr = net.InetAddr(c.Str(SERVER_IP))
// connect to server
if net.Connect(sock, (*net.SockAddr)(c.Pointer(&server)), c.Uint(unsafe.Sizeof(server))) < 0 {
c.Perror(c.Str("Connect failed"))
return
}
var writefds, readfds syscall.FdSet
var timeout sys.TimeVal
// Monitor socket writes
sys.FD_ZERO(&writefds)
sys.FD_SET(sock, &writefds)
timeout.TvSec = 10
timeout.TvUSec = 0
// Use select to monitor the readiness of writes
if sys.Select(sock+1, nil, &writefds, nil, &timeout) > 0 {
if sys.FD_ISSET(sock, &writefds) != 0 {
bytes_sent = c.Int(net.Send(sock, c.Pointer(sendBuf), c.Strlen(sendBuf), 0))
if bytes_sent < 0 {
c.Perror(c.Str("send failed"))
return
}
}
} else {
c.Perror(c.Str("Select write error"))
return
}
// Monitor socket reads
sys.FD_ZERO(&readfds)
sys.FD_SET(sock, &readfds)
// Use select to monitor the readiness of the read operation
if sys.Select(sock+1, &readfds, nil, nil, &timeout) > 0 {
if sys.FD_ISSET(sock, &writefds) != -1 {
bytes_received = c.Int(net.Recv(sock, c.Pointer(&recvBuf[:][0]), BUFFER_SIZE-1, 0))
if bytes_received < 0 {
c.Perror(c.Str("receive failed"))
return
}
recvBuf[bytes_received] = c.Char(0)
c.Printf(c.Str("Received:\n%s\n"), &recvBuf[0])
}
} else {
c.Perror(c.Str("Select read error"))
return
}
os.Close(sock)
}

View File

@@ -4,27 +4,27 @@ import (
"unsafe" "unsafe"
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/net"
"github.com/goplus/llgo/c/os" "github.com/goplus/llgo/c/os"
"github.com/goplus/llgo/c/socket"
) )
func main() { func main() {
sockfd := socket.Socket(socket.AF_INET, socket.SOCK_STREAM, 0) sockfd := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
msg := c.Str("Hello, World!") msg := c.Str("Hello, World!")
defer os.Close(sockfd) defer os.Close(sockfd)
server := socket.GetHostByName(c.Str("localhost")) server := net.GetHostByName(c.Str("localhost"))
if server == nil { if server == nil {
c.Perror(c.Str("hostname get error")) c.Perror(c.Str("hostname get error"))
return return
} }
servAddr := &socket.SockaddrIn{} servAddr := &net.SockaddrIn{}
servAddr.Family = socket.AF_INET servAddr.Family = net.AF_INET
servAddr.Port = socket.Htons(uint16(1234)) servAddr.Port = net.Htons(uint16(1234))
c.Memcpy(unsafe.Pointer(&servAddr.Addr.Addr), unsafe.Pointer(*server.AddrList), uintptr(server.Length)) c.Memcpy(unsafe.Pointer(&servAddr.Addr.Addr), unsafe.Pointer(*server.AddrList), uintptr(server.Length))
if res := socket.Connect(sockfd, (*socket.SockAddr)(unsafe.Pointer(servAddr)), c.Uint(16)); res < 0 { if res := net.Connect(sockfd, (*net.SockAddr)(unsafe.Pointer(servAddr)), c.Uint(16)); res < 0 {
c.Perror(c.Str("connect error")) c.Perror(c.Str("connect error"))
return return
} }

View File

@@ -4,36 +4,36 @@ import (
"unsafe" "unsafe"
"github.com/goplus/llgo/c" "github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/net"
"github.com/goplus/llgo/c/os" "github.com/goplus/llgo/c/os"
"github.com/goplus/llgo/c/socket"
) )
func main() { func main() {
var buffer [256]c.Char var buffer [256]c.Char
sockfd := socket.Socket(socket.AF_INET, socket.SOCK_STREAM, 0) sockfd := net.Socket(net.AF_INET, net.SOCK_STREAM, 0)
defer os.Close(sockfd) defer os.Close(sockfd)
servAddr := &socket.SockaddrIn{ servAddr := &net.SockaddrIn{
Family: socket.AF_INET, Family: net.AF_INET,
Port: socket.Htons(uint16(1234)), Port: net.Htons(uint16(1234)),
Addr: socket.InAddr{Addr: 0x00000000}, Addr: net.InAddr{Addr: 0x00000000},
Zero: [8]c.Char{0, 0, 0, 0, 0, 0, 0, 0}, Zero: [8]c.Char{0, 0, 0, 0, 0, 0, 0, 0},
} }
if res := socket.Bind(sockfd, servAddr, c.Uint(unsafe.Sizeof(*servAddr))); res < 0 { if res := net.Bind(sockfd, servAddr, c.Uint(unsafe.Sizeof(*servAddr))); res < 0 {
c.Perror(c.Str("bind error")) c.Perror(c.Str("bind error"))
return return
} }
if socket.Listen(sockfd, 5) < 0 { if net.Listen(sockfd, 5) < 0 {
c.Printf(c.Str("listen error")) c.Printf(c.Str("listen error"))
return return
} }
c.Printf(c.Str("Listening on port 1234...\n")) c.Printf(c.Str("Listening on port 1234...\n"))
cliAddr, clilen := &socket.SockaddrIn{}, c.Uint(unsafe.Sizeof(servAddr)) cliAddr, clilen := &net.SockaddrIn{}, c.Uint(unsafe.Sizeof(servAddr))
newsockfd := socket.Accept(sockfd, cliAddr, &clilen) newsockfd := net.Accept(sockfd, cliAddr, &clilen)
defer os.Close(newsockfd) defer os.Close(newsockfd)
c.Printf(c.Str("Connection accepted.")) c.Printf(c.Str("Connection accepted."))

View File

@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package socket package net
import ( import (
_ "unsafe" _ "unsafe"
@@ -101,7 +101,6 @@ type SockAddr struct {
Data [14]c.Char Data [14]c.Char
} }
// (TODO) merge to netdb
type Hostent struct { type Hostent struct {
Name *c.Char // official name of host Name *c.Char // official name of host
Aliases **c.Char // null-terminated array of alternate names for the host Aliases **c.Char // null-terminated array of alternate names for the host
@@ -110,6 +109,17 @@ type Hostent struct {
AddrList **c.Char // null-terminated array of addresses for the host AddrList **c.Char // null-terminated array of addresses for the host
} }
type AddrInfo struct {
AiFlags c.Int
AiFamily c.Int
AiSockType c.Int
AiProtocol c.Int
AiAddrLen c.Uint
AiCanOnName *c.Char
AiAddr *SockAddr
AiNext *AddrInfo
}
//go:linkname Socket C.socket //go:linkname Socket C.socket
func Socket(domain c.Int, typ c.Int, protocol c.Int) c.Int func Socket(domain c.Int, typ c.Int, protocol c.Int) c.Int
@@ -125,8 +135,6 @@ func Listen(sockfd c.Int, backlog c.Int) c.Int
//go:linkname Accept C.accept //go:linkname Accept C.accept
func Accept(sockfd c.Int, addr *SockaddrIn, addrlen *c.Uint) c.Int func Accept(sockfd c.Int, addr *SockaddrIn, addrlen *c.Uint) c.Int
// (TODO) merge to netdb
//
//go:linkname GetHostByName C.gethostbyname //go:linkname GetHostByName C.gethostbyname
func GetHostByName(name *c.Char) *Hostent func GetHostByName(name *c.Char) *Hostent
@@ -142,3 +150,18 @@ func SwapInt16(data uint16) uint16 {
func Htons(x uint16) uint16 { func Htons(x uint16) uint16 {
return SwapInt16(x) return SwapInt16(x)
} }
//go:linkname InetAddr C.inet_addr
func InetAddr(s *c.Char) c.Uint
//go:linkname Send C.send
func Send(c.Int, c.Pointer, uintptr, c.Int) c.Long
//go:linkname Recv C.recv
func Recv(c.Int, c.Pointer, uintptr, c.Int) c.Long
//go:linkname Getaddrinfo C.getaddrinfo
func Getaddrinfo(host *c.Char, port *c.Char, addrInfo *AddrInfo, result **AddrInfo) c.Int
//go:linkname Freeaddrinfo C.freeaddrinfo
func Freeaddrinfo(addrInfo *AddrInfo) c.Int

View File

@@ -58,6 +58,10 @@ const (
O_TRUNC = 0x00000400 O_TRUNC = 0x00000400
) )
const (
EAGAIN = 35
)
type ( type (
ModeT C.mode_t ModeT C.mode_t
UidT C.uid_t UidT C.uid_t

13
c/sys/_wrap/fddef.c Normal file
View File

@@ -0,0 +1,13 @@
#include <sys/types.h>
int fd_isset(int n, fd_set *fd) {
return FD_ISSET(n, fd);
}
void fdSet(int n, fd_set *fd) {
FD_SET(n, fd);
}
void fd_zero(fd_set *fd) {
FD_ZERO(fd);
}

31
c/sys/select.go Normal file
View File

@@ -0,0 +1,31 @@
package sys
import (
"github.com/goplus/llgo/c/syscall"
_ "unsafe"
"github.com/goplus/llgo/c"
)
const (
LLGoFiles = "_wrap/fddef.c"
LLGoPackage = "link"
)
// (TODO) merge to timeval
type TimeVal struct {
TvSec c.Long
TvUSec c.Int
}
//go:linkname FD_ZERO C.fd_zero
func FD_ZERO(fdSet *syscall.FdSet)
//go:linkname FD_SET C.fdSet
func FD_SET(fd c.Int, fdSet *syscall.FdSet)
//go:linkname FD_ISSET C.fd_isset
func FD_ISSET(fd c.Int, fdSet *syscall.FdSet) c.Int
//go:linkname Select C.select
func Select(n c.Int, r *syscall.FdSet, w *syscall.FdSet, e *syscall.FdSet, timeout *TimeVal) c.Int