mirror of
https://github.com/golang/go
synced 2024-11-24 22:57:57 -07:00
net: initial attempt to implement windows version
R=rsc, Mateusz Czaplinski CC=golang-dev https://golang.org/cl/1600041
This commit is contained in:
parent
829896168c
commit
bb9261bf3b
@ -10,8 +10,6 @@ GOFILES=\
|
||||
dnsclient.go\
|
||||
dnsconfig.go\
|
||||
dnsmsg.go\
|
||||
newpollserver.go\
|
||||
fd.go\
|
||||
fd_$(GOOS).go\
|
||||
hosts.go\
|
||||
ip.go\
|
||||
@ -26,4 +24,22 @@ GOFILES=\
|
||||
udpsock.go\
|
||||
unixsock.go\
|
||||
|
||||
GOFILES_freebsd=\
|
||||
newpollserver.go\
|
||||
fd.go\
|
||||
|
||||
GOFILES_darwin=\
|
||||
newpollserver.go\
|
||||
fd.go\
|
||||
|
||||
GOFILES_linux=\
|
||||
newpollserver.go\
|
||||
fd.go\
|
||||
|
||||
GOFILES_nacl=\
|
||||
newpollserver.go\
|
||||
fd.go\
|
||||
|
||||
GOFILES+=$(GOFILES_$(GOOS))
|
||||
|
||||
include ../../Make.pkg
|
||||
|
368
src/pkg/net/fd_windows.go
Normal file
368
src/pkg/net/fd_windows.go
Normal file
@ -0,0 +1,368 @@
|
||||
// Copyright 2010 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"once"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// BUG(brainman): The Windows implementation does not implement SetTimeout.
|
||||
|
||||
// IO completion result parameters.
|
||||
type ioResult struct {
|
||||
key uint32
|
||||
qty uint32
|
||||
errno int
|
||||
}
|
||||
|
||||
// Network file descriptor.
|
||||
type netFD struct {
|
||||
// locking/lifetime of sysfd
|
||||
sysmu sync.Mutex
|
||||
sysref int
|
||||
closing bool
|
||||
|
||||
// immutable until Close
|
||||
sysfd int
|
||||
family int
|
||||
proto int
|
||||
sysfile *os.File
|
||||
cr chan *ioResult
|
||||
cw chan *ioResult
|
||||
net string
|
||||
laddr Addr
|
||||
raddr Addr
|
||||
|
||||
// owned by client
|
||||
rdeadline_delta int64
|
||||
rdeadline int64
|
||||
rio sync.Mutex
|
||||
wdeadline_delta int64
|
||||
wdeadline int64
|
||||
wio sync.Mutex
|
||||
}
|
||||
|
||||
type InvalidConnError struct{}
|
||||
|
||||
func (e *InvalidConnError) String() string { return "invalid net.Conn" }
|
||||
func (e *InvalidConnError) Temporary() bool { return false }
|
||||
func (e *InvalidConnError) Timeout() bool { return false }
|
||||
|
||||
// pollServer will run around waiting for io completion request
|
||||
// to arrive. Every request received will contain channel to signal
|
||||
// io owner about the completion.
|
||||
|
||||
type pollServer struct {
|
||||
iocp int32
|
||||
}
|
||||
|
||||
func newPollServer() (s *pollServer, err os.Error) {
|
||||
s = new(pollServer)
|
||||
var e int
|
||||
if s.iocp, e = syscall.CreateIoCompletionPort(-1, 0, 0, 1); e != 0 {
|
||||
return nil, os.NewSyscallError("CreateIoCompletionPort", e)
|
||||
}
|
||||
go s.Run()
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type ioPacket struct {
|
||||
// Used by IOCP interface,
|
||||
// it must be first field of the struct,
|
||||
// as our code rely on it.
|
||||
o syscall.Overlapped
|
||||
|
||||
// Link to the io owner.
|
||||
c chan *ioResult
|
||||
}
|
||||
|
||||
func (s *pollServer) getCompletedIO() (ov *syscall.Overlapped, result *ioResult, err os.Error) {
|
||||
var r ioResult
|
||||
var o *syscall.Overlapped
|
||||
_, e := syscall.GetQueuedCompletionStatus(s.iocp, &r.qty, &r.key, &o, syscall.INFINITE)
|
||||
switch {
|
||||
case e == 0:
|
||||
// Dequeued successfully completed io packet.
|
||||
return o, &r, nil
|
||||
case e == syscall.WAIT_TIMEOUT && o == nil:
|
||||
// Wait has timed out (should not happen now, but might be used in the future).
|
||||
return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
|
||||
case o == nil:
|
||||
// Failed to dequeue anything -> report the error.
|
||||
return nil, &r, os.NewSyscallError("GetQueuedCompletionStatus", e)
|
||||
default:
|
||||
// Dequeued failed io packet.
|
||||
r.errno = e
|
||||
return o, &r, nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *pollServer) Run() {
|
||||
for {
|
||||
o, r, err := s.getCompletedIO()
|
||||
if err != nil {
|
||||
panic("Run pollServer: " + err.String() + "\n")
|
||||
}
|
||||
p := (*ioPacket)(unsafe.Pointer(o))
|
||||
p.c <- r
|
||||
}
|
||||
}
|
||||
|
||||
// Network FD methods.
|
||||
// All the network FDs use a single pollServer.
|
||||
|
||||
var pollserver *pollServer
|
||||
|
||||
func startServer() {
|
||||
p, err := newPollServer()
|
||||
if err != nil {
|
||||
panic("Start pollServer: " + err.String() + "\n")
|
||||
}
|
||||
pollserver = p
|
||||
}
|
||||
|
||||
var initErr os.Error
|
||||
|
||||
func newFD(fd, family, proto int, net string, laddr, raddr Addr) (f *netFD, err os.Error) {
|
||||
if initErr != nil {
|
||||
return nil, initErr
|
||||
}
|
||||
once.Do(startServer)
|
||||
// Associate our socket with pollserver.iocp.
|
||||
if _, e := syscall.CreateIoCompletionPort(int32(fd), pollserver.iocp, 0, 0); e != 0 {
|
||||
return nil, &OpError{"CreateIoCompletionPort", net, laddr, os.Errno(e)}
|
||||
}
|
||||
f = &netFD{
|
||||
sysfd: fd,
|
||||
family: family,
|
||||
proto: proto,
|
||||
cr: make(chan *ioResult),
|
||||
cw: make(chan *ioResult),
|
||||
net: net,
|
||||
laddr: laddr,
|
||||
raddr: raddr,
|
||||
}
|
||||
var ls, rs string
|
||||
if laddr != nil {
|
||||
ls = laddr.String()
|
||||
}
|
||||
if raddr != nil {
|
||||
rs = raddr.String()
|
||||
}
|
||||
f.sysfile = os.NewFile(fd, net+":"+ls+"->"+rs)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// Add a reference to this fd.
|
||||
func (fd *netFD) incref() {
|
||||
fd.sysmu.Lock()
|
||||
fd.sysref++
|
||||
fd.sysmu.Unlock()
|
||||
}
|
||||
|
||||
// Remove a reference to this FD and close if we've been asked to do so (and
|
||||
// there are no references left.
|
||||
func (fd *netFD) decref() {
|
||||
fd.sysmu.Lock()
|
||||
fd.sysref--
|
||||
if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
|
||||
// In case the user has set linger, switch to blocking mode so
|
||||
// the close blocks. As long as this doesn't happen often, we
|
||||
// can handle the extra OS processes. Otherwise we'll need to
|
||||
// use the pollserver for Close too. Sigh.
|
||||
syscall.SetNonblock(fd.sysfd, false)
|
||||
fd.sysfile.Close()
|
||||
fd.sysfile = nil
|
||||
fd.sysfd = -1
|
||||
}
|
||||
fd.sysmu.Unlock()
|
||||
}
|
||||
|
||||
func (fd *netFD) Close() os.Error {
|
||||
if fd == nil || fd.sysfile == nil {
|
||||
return os.EINVAL
|
||||
}
|
||||
|
||||
fd.incref()
|
||||
syscall.Shutdown(fd.sysfd, syscall.SHUT_RDWR)
|
||||
fd.closing = true
|
||||
fd.decref()
|
||||
return nil
|
||||
}
|
||||
|
||||
func newWSABuf(p []byte) *syscall.WSABuf {
|
||||
return &syscall.WSABuf{uint32(len(p)), (*byte)(unsafe.Pointer(&p[0]))}
|
||||
}
|
||||
|
||||
func (fd *netFD) Read(p []byte) (n int, err os.Error) {
|
||||
if fd == nil {
|
||||
return 0, os.EINVAL
|
||||
}
|
||||
fd.rio.Lock()
|
||||
defer fd.rio.Unlock()
|
||||
fd.incref()
|
||||
defer fd.decref()
|
||||
if fd.sysfile == nil {
|
||||
return 0, os.EINVAL
|
||||
}
|
||||
// Submit receive request.
|
||||
var pckt ioPacket
|
||||
pckt.c = fd.cr
|
||||
var done uint32
|
||||
flags := uint32(0)
|
||||
e := syscall.WSARecv(uint32(fd.sysfd), newWSABuf(p), 1, &done, &flags, &pckt.o, nil)
|
||||
switch e {
|
||||
case 0:
|
||||
// IO completed immediately, but we need to get our completion message anyway.
|
||||
case syscall.ERROR_IO_PENDING:
|
||||
// IO started, and we have to wait for it's completion.
|
||||
default:
|
||||
return 0, &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(e)}
|
||||
}
|
||||
// Wait for our request to complete.
|
||||
r := <-pckt.c
|
||||
if r.errno != 0 {
|
||||
err = &OpError{"WSARecv", fd.net, fd.laddr, os.Errno(r.errno)}
|
||||
}
|
||||
n = int(r.qty)
|
||||
return
|
||||
}
|
||||
|
||||
func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err os.Error) {
|
||||
var r syscall.Sockaddr
|
||||
return 0, r, nil
|
||||
}
|
||||
|
||||
func (fd *netFD) Write(p []byte) (n int, err os.Error) {
|
||||
if fd == nil {
|
||||
return 0, os.EINVAL
|
||||
}
|
||||
fd.wio.Lock()
|
||||
defer fd.wio.Unlock()
|
||||
fd.incref()
|
||||
defer fd.decref()
|
||||
if fd.sysfile == nil {
|
||||
return 0, os.EINVAL
|
||||
}
|
||||
// Submit send request.
|
||||
var pckt ioPacket
|
||||
pckt.c = fd.cw
|
||||
var done uint32
|
||||
e := syscall.WSASend(uint32(fd.sysfd), newWSABuf(p), 1, &done, uint32(0), &pckt.o, nil)
|
||||
switch e {
|
||||
case 0:
|
||||
// IO completed immediately, but we need to get our completion message anyway.
|
||||
case syscall.ERROR_IO_PENDING:
|
||||
// IO started, and we have to wait for it's completion.
|
||||
default:
|
||||
return 0, &OpError{"WSASend", fd.net, fd.laddr, os.Errno(e)}
|
||||
}
|
||||
// Wait for our request to complete.
|
||||
r := <-pckt.c
|
||||
if r.errno != 0 {
|
||||
err = &OpError{"WSASend", fd.net, fd.laddr, os.Errno(r.errno)}
|
||||
}
|
||||
n = int(r.qty)
|
||||
return
|
||||
}
|
||||
|
||||
func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err os.Error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
|
||||
if fd == nil || fd.sysfile == nil {
|
||||
return nil, os.EINVAL
|
||||
}
|
||||
fd.incref()
|
||||
defer fd.decref()
|
||||
|
||||
// Get new socket.
|
||||
// See ../syscall/exec.go for description of ForkLock.
|
||||
syscall.ForkLock.RLock()
|
||||
s, e := syscall.Socket(fd.family, fd.proto, 0)
|
||||
if e != 0 {
|
||||
syscall.ForkLock.RUnlock()
|
||||
return nil, os.Errno(e)
|
||||
}
|
||||
syscall.CloseOnExec(s)
|
||||
syscall.ForkLock.RUnlock()
|
||||
|
||||
// Associate our new socket with IOCP.
|
||||
once.Do(startServer)
|
||||
if _, e = syscall.CreateIoCompletionPort(int32(s), pollserver.iocp, 0, 0); e != 0 {
|
||||
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
|
||||
}
|
||||
|
||||
// Submit accept request.
|
||||
// Will use new unique channel here, because, unlike Read or Write,
|
||||
// Accept is expected to be executed by many goroutines simultaniously.
|
||||
var pckt ioPacket
|
||||
pckt.c = make(chan *ioResult)
|
||||
attrs, e := syscall.AcceptIOCP(fd.sysfd, s, &pckt.o)
|
||||
switch e {
|
||||
case 0:
|
||||
// IO completed immediately, but we need to get our completion message anyway.
|
||||
case syscall.ERROR_IO_PENDING:
|
||||
// IO started, and we have to wait for it's completion.
|
||||
default:
|
||||
syscall.Close(s)
|
||||
return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(e)}
|
||||
}
|
||||
|
||||
// Wait for peer connection.
|
||||
r := <-pckt.c
|
||||
if r.errno != 0 {
|
||||
syscall.Close(s)
|
||||
return nil, &OpError{"AcceptEx", fd.net, fd.laddr, os.Errno(r.errno)}
|
||||
}
|
||||
|
||||
// Inherit properties of the listening socket.
|
||||
e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
|
||||
if e != 0 {
|
||||
syscall.Close(s)
|
||||
return nil, &OpError{"Setsockopt", fd.net, fd.laddr, os.Errno(r.errno)}
|
||||
}
|
||||
|
||||
// Get local and peer addr out of AcceptEx buffer.
|
||||
lsa, rsa := syscall.GetAcceptIOCPSockaddrs(attrs)
|
||||
|
||||
// Create our netFD and return it for further use.
|
||||
laddr := toAddr(lsa)
|
||||
raddr := toAddr(rsa)
|
||||
|
||||
f := &netFD{
|
||||
sysfd: s,
|
||||
family: fd.family,
|
||||
proto: fd.proto,
|
||||
cr: make(chan *ioResult),
|
||||
cw: make(chan *ioResult),
|
||||
net: fd.net,
|
||||
laddr: laddr,
|
||||
raddr: raddr,
|
||||
}
|
||||
var ls, rs string
|
||||
if laddr != nil {
|
||||
ls = laddr.String()
|
||||
}
|
||||
if raddr != nil {
|
||||
rs = raddr.String()
|
||||
}
|
||||
f.sysfile = os.NewFile(s, fd.net+":"+ls+"->"+rs)
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
var d syscall.WSAData
|
||||
e := syscall.WSAStartup(uint32(0x101), &d)
|
||||
if e != 0 {
|
||||
initErr = os.NewSyscallError("WSAStartup", e)
|
||||
}
|
||||
}
|
@ -62,6 +62,8 @@ sub parseparam($) {
|
||||
|
||||
$text = "";
|
||||
$vars = "";
|
||||
$mods = "";
|
||||
$modnames = "";
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
@ -72,17 +74,27 @@ while(<>) {
|
||||
# Line must be of the form
|
||||
# func Open(path string, mode int, perm int) (fd int, errno int)
|
||||
# Split into name, in params, out params.
|
||||
if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval=(.*)\])?\s*(?:=\s*(\w*))?$/) {
|
||||
if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval=(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($func, $in, $out, $failretval, $sysname) = ($1, $2, $3, $4, $5);
|
||||
my ($func, $in, $out, $failretval, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
# Dll file name.
|
||||
if($modname eq "") {
|
||||
$modname = "kernel32";
|
||||
}
|
||||
$modvname = "mod$modname";
|
||||
if($modnames !~ /$modname/) {
|
||||
$modnames .= ".$modname";
|
||||
$mods .= "\t$modvname = loadDll(\"$modname.dll\")\n";
|
||||
}
|
||||
|
||||
# System call name.
|
||||
if($sysname eq "") {
|
||||
$sysname = "$func";
|
||||
@ -104,7 +116,7 @@ while(<>) {
|
||||
}
|
||||
|
||||
# Winapi proc address variable.
|
||||
$vars .= sprintf "\t%s = getSysProcAddr(modKERNEL32, \"%s\")\n", $sysvarname, $sysname;
|
||||
$vars .= sprintf "\t%s = getSysProcAddr(%s, \"%s\")\n", $sysvarname, $modvname, $sysname;
|
||||
|
||||
# Go function header.
|
||||
$text .= sprintf "func %s(%s) (%s) {\n", $func, join(', ', @in), join(', ', @out);
|
||||
@ -198,6 +210,9 @@ while(<>) {
|
||||
if($i == 0) {
|
||||
if($type eq "bool") {
|
||||
$failexpr = "!$name";
|
||||
} elsif($name eq "errno") {
|
||||
$ret[$i] = "r1";
|
||||
$failexpr = "int(r1) == $failretval";
|
||||
} else {
|
||||
$failexpr = "$name == $failretval";
|
||||
}
|
||||
@ -212,7 +227,7 @@ while(<>) {
|
||||
} else {
|
||||
$body .= "\t$name = $type($reg);\n";
|
||||
}
|
||||
push @pout, sprintf "\"%s=\", %s(%s), ", $name, $type, $reg;
|
||||
push @pout, sprintf "\"%s=\", %s, ", $name, $name;
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
|
||||
$text .= "\t$call;\n";
|
||||
@ -241,7 +256,7 @@ package syscall
|
||||
import "unsafe"
|
||||
|
||||
var (
|
||||
modKERNEL32 = loadDll("kernel32.dll")
|
||||
$mods
|
||||
$vars
|
||||
)
|
||||
|
||||
|
@ -128,6 +128,8 @@ func getSysProcAddr(m uint32, pname string) uintptr {
|
||||
//sys SetEndOfFile(handle int32) (ok bool, errno int)
|
||||
//sys GetSystemTimeAsFileTime(time *Filetime)
|
||||
//sys sleep(msec uint32) = Sleep
|
||||
//sys CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int)
|
||||
//sys GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int)
|
||||
|
||||
// syscall interface implementation for other packages
|
||||
|
||||
@ -382,6 +384,191 @@ func Utimes(path string, tv []Timeval) (errno int) {
|
||||
return EWINDOWS
|
||||
}
|
||||
|
||||
// net api calls
|
||||
|
||||
//sys WSAStartup(verreq uint32, data *WSAData) (sockerrno int) = wsock32.WSAStartup
|
||||
//sys WSACleanup() (errno int) [failretval=-1] = wsock32.WSACleanup
|
||||
//sys socket(af int32, typ int32, protocol int32) (handle int32, errno int) [failretval=-1] = wsock32.socket
|
||||
//sys setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) [failretval=-1] = wsock32.setsockopt
|
||||
//sys bind(s int32, name uintptr, namelen int32) (errno int) [failretval=-1] = wsock32.bind
|
||||
//sys connect(s int32, name uintptr, namelen int32) (errno int) [failretval=-1] = wsock32.connect
|
||||
//sys getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval=-1] = wsock32.getsockname
|
||||
//sys getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) [failretval=-1] = wsock32.getpeername
|
||||
//sys listen(s int32, backlog int32) (errno int) [failretval=-1] = wsock32.listen
|
||||
//sys shutdown(s int32, how int32) (errno int) [failretval=-1] = wsock32.shutdown
|
||||
//sys AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, errno int) = wsock32.AcceptEx
|
||||
//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = wsock32.GetAcceptExSockaddrs
|
||||
//sys WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval=-1] = ws2_32.WSARecv
|
||||
//sys WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) [failretval=-1] = ws2_32.WSASend
|
||||
|
||||
type RawSockaddrInet4 struct {
|
||||
Family uint16
|
||||
Port uint16
|
||||
Addr [4]byte /* in_addr */
|
||||
Zero [8]uint8
|
||||
}
|
||||
|
||||
type RawSockaddr struct {
|
||||
Family uint16
|
||||
Data [14]int8
|
||||
}
|
||||
|
||||
type RawSockaddrAny struct {
|
||||
Addr RawSockaddr
|
||||
Pad [96]int8
|
||||
}
|
||||
|
||||
type Sockaddr interface {
|
||||
sockaddr() (ptr uintptr, len int32, errno int) // lowercase; only we can define Sockaddrs
|
||||
}
|
||||
|
||||
type SockaddrInet4 struct {
|
||||
Port int
|
||||
Addr [4]byte
|
||||
raw RawSockaddrInet4
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet4) sockaddr() (uintptr, int32, int) {
|
||||
if sa.Port < 0 || sa.Port > 0xFFFF {
|
||||
return 0, 0, EINVAL
|
||||
}
|
||||
sa.raw.Family = AF_INET
|
||||
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
||||
p[0] = byte(sa.Port >> 8)
|
||||
p[1] = byte(sa.Port)
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.raw.Addr[i] = sa.Addr[i]
|
||||
}
|
||||
return uintptr(unsafe.Pointer(&sa.raw)), int32(unsafe.Sizeof(sa.raw)), 0
|
||||
}
|
||||
|
||||
type SockaddrInet6 struct {
|
||||
Port int
|
||||
Addr [16]byte
|
||||
}
|
||||
|
||||
func (sa *SockaddrInet6) sockaddr() (uintptr, int32, int) {
|
||||
// TODO(brainman): implement SockaddrInet6.sockaddr()
|
||||
return 0, 0, EWINDOWS
|
||||
}
|
||||
|
||||
type SockaddrUnix struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (sa *SockaddrUnix) sockaddr() (uintptr, int32, int) {
|
||||
// TODO(brainman): implement SockaddrUnix.sockaddr()
|
||||
return 0, 0, EWINDOWS
|
||||
}
|
||||
|
||||
func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, int) {
|
||||
switch rsa.Addr.Family {
|
||||
case AF_UNIX:
|
||||
return nil, EWINDOWS
|
||||
|
||||
case AF_INET:
|
||||
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
||||
sa := new(SockaddrInet4)
|
||||
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
||||
sa.Port = int(p[0])<<8 + int(p[1])
|
||||
for i := 0; i < len(sa.Addr); i++ {
|
||||
sa.Addr[i] = pp.Addr[i]
|
||||
}
|
||||
return sa, 0
|
||||
|
||||
case AF_INET6:
|
||||
return nil, EWINDOWS
|
||||
}
|
||||
return nil, EAFNOSUPPORT
|
||||
}
|
||||
|
||||
func Socket(domain, typ, proto int) (fd, errno int) {
|
||||
h, e := socket(int32(domain), int32(typ), int32(proto))
|
||||
return int(h), int(e)
|
||||
}
|
||||
|
||||
func SetsockoptInt(fd, level, opt int, value int) (errno int) {
|
||||
v := int32(value)
|
||||
return int(setsockopt(int32(fd), int32(level), int32(opt), (*byte)(unsafe.Pointer(&v)), int32(unsafe.Sizeof(v))))
|
||||
}
|
||||
|
||||
func Bind(fd int, sa Sockaddr) (errno int) {
|
||||
ptr, n, err := sa.sockaddr()
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return bind(int32(fd), ptr, n)
|
||||
}
|
||||
|
||||
func Connect(fd int, sa Sockaddr) (errno int) {
|
||||
ptr, n, err := sa.sockaddr()
|
||||
if err != 0 {
|
||||
return err
|
||||
}
|
||||
return connect(int32(fd), ptr, n)
|
||||
}
|
||||
|
||||
func Getsockname(fd int) (sa Sockaddr, errno int) {
|
||||
var rsa RawSockaddrAny
|
||||
l := int32(unsafe.Sizeof(rsa))
|
||||
if errno = getsockname(int32(fd), &rsa, &l); errno != 0 {
|
||||
return
|
||||
}
|
||||
return rsa.Sockaddr()
|
||||
}
|
||||
|
||||
func Getpeername(fd int) (sa Sockaddr, errno int) {
|
||||
var rsa RawSockaddrAny
|
||||
l := int32(unsafe.Sizeof(rsa))
|
||||
if errno = getpeername(int32(fd), &rsa, &l); errno != 0 {
|
||||
return
|
||||
}
|
||||
return rsa.Sockaddr()
|
||||
}
|
||||
|
||||
func Listen(s int, n int) (errno int) {
|
||||
return int(listen(int32(s), int32(n)))
|
||||
}
|
||||
|
||||
func Shutdown(fd, how int) (errno int) {
|
||||
return int(shutdown(int32(fd), int32(how)))
|
||||
}
|
||||
|
||||
func AcceptIOCP(iocpfd, fd int, o *Overlapped) (attrs *byte, errno int) {
|
||||
// Will ask for local and remote address only.
|
||||
rsa := make([]RawSockaddrAny, 2)
|
||||
attrs = (*byte)(unsafe.Pointer(&rsa[0]))
|
||||
alen := uint32(unsafe.Sizeof(rsa[0]))
|
||||
var done uint32
|
||||
_, errno = AcceptEx(uint32(iocpfd), uint32(fd), attrs, 0, alen, alen, &done, o)
|
||||
return
|
||||
}
|
||||
|
||||
func GetAcceptIOCPSockaddrs(attrs *byte) (lsa, rsa Sockaddr) {
|
||||
var lrsa, rrsa *RawSockaddrAny
|
||||
var llen, rlen int32
|
||||
alen := uint32(unsafe.Sizeof(*lrsa))
|
||||
GetAcceptExSockaddrs(attrs, 0, alen, alen, &lrsa, &llen, &rrsa, &rlen)
|
||||
lsa, _ = lrsa.Sockaddr()
|
||||
rsa, _ = rrsa.Sockaddr()
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(brainman): fix all needed for net
|
||||
|
||||
func Accept(fd int) (nfd int, sa Sockaddr, errno int) { return 0, nil, EWINDOWS }
|
||||
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, errno int) { return 0, nil, EWINDOWS }
|
||||
func Sendto(fd int, p []byte, flags int, to Sockaddr) (errno int) { return EWINDOWS }
|
||||
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (errno int) { return EWINDOWS }
|
||||
|
||||
type Linger struct {
|
||||
Onoff int32
|
||||
Linger int32
|
||||
}
|
||||
|
||||
func SetsockoptLinger(fd, level, opt int, l *Linger) (errno int) { return EWINDOWS }
|
||||
func BindToDevice(fd int, device string) (errno int) { return EWINDOWS }
|
||||
|
||||
// TODO(brainman): fix all needed for os
|
||||
|
||||
const (
|
||||
|
@ -13,6 +13,7 @@ const (
|
||||
ERROR_MOD_NOT_FOUND = 126
|
||||
ERROR_PROC_NOT_FOUND = 127
|
||||
ERROR_DIRECTORY = 267
|
||||
ERROR_IO_PENDING = 997
|
||||
// TODO(brainman): should use value for EWINDOWS that does not clashes with anything else
|
||||
EWINDOWS = 99999 /* otherwise unused */
|
||||
)
|
||||
|
@ -6,34 +6,53 @@ package syscall
|
||||
import "unsafe"
|
||||
|
||||
var (
|
||||
modKERNEL32 = loadDll("kernel32.dll")
|
||||
procGetLastError = getSysProcAddr(modKERNEL32, "GetLastError")
|
||||
procLoadLibraryW = getSysProcAddr(modKERNEL32, "LoadLibraryW")
|
||||
procFreeLibrary = getSysProcAddr(modKERNEL32, "FreeLibrary")
|
||||
procGetProcAddress = getSysProcAddr(modKERNEL32, "GetProcAddress")
|
||||
procGetVersion = getSysProcAddr(modKERNEL32, "GetVersion")
|
||||
procFormatMessageW = getSysProcAddr(modKERNEL32, "FormatMessageW")
|
||||
procExitProcess = getSysProcAddr(modKERNEL32, "ExitProcess")
|
||||
procCreateFileW = getSysProcAddr(modKERNEL32, "CreateFileW")
|
||||
procReadFile = getSysProcAddr(modKERNEL32, "ReadFile")
|
||||
procWriteFile = getSysProcAddr(modKERNEL32, "WriteFile")
|
||||
procSetFilePointer = getSysProcAddr(modKERNEL32, "SetFilePointer")
|
||||
procCloseHandle = getSysProcAddr(modKERNEL32, "CloseHandle")
|
||||
procGetStdHandle = getSysProcAddr(modKERNEL32, "GetStdHandle")
|
||||
procFindFirstFileW = getSysProcAddr(modKERNEL32, "FindFirstFileW")
|
||||
procFindNextFileW = getSysProcAddr(modKERNEL32, "FindNextFileW")
|
||||
procFindClose = getSysProcAddr(modKERNEL32, "FindClose")
|
||||
procGetFileInformationByHandle = getSysProcAddr(modKERNEL32, "GetFileInformationByHandle")
|
||||
procGetCurrentDirectoryW = getSysProcAddr(modKERNEL32, "GetCurrentDirectoryW")
|
||||
procSetCurrentDirectoryW = getSysProcAddr(modKERNEL32, "SetCurrentDirectoryW")
|
||||
procCreateDirectoryW = getSysProcAddr(modKERNEL32, "CreateDirectoryW")
|
||||
procRemoveDirectoryW = getSysProcAddr(modKERNEL32, "RemoveDirectoryW")
|
||||
procDeleteFileW = getSysProcAddr(modKERNEL32, "DeleteFileW")
|
||||
procMoveFileW = getSysProcAddr(modKERNEL32, "MoveFileW")
|
||||
procGetComputerNameW = getSysProcAddr(modKERNEL32, "GetComputerNameW")
|
||||
procSetEndOfFile = getSysProcAddr(modKERNEL32, "SetEndOfFile")
|
||||
procGetSystemTimeAsFileTime = getSysProcAddr(modKERNEL32, "GetSystemTimeAsFileTime")
|
||||
procSleep = getSysProcAddr(modKERNEL32, "Sleep")
|
||||
modkernel32 = loadDll("kernel32.dll")
|
||||
modwsock32 = loadDll("wsock32.dll")
|
||||
modws2_32 = loadDll("ws2_32.dll")
|
||||
|
||||
procGetLastError = getSysProcAddr(modkernel32, "GetLastError")
|
||||
procLoadLibraryW = getSysProcAddr(modkernel32, "LoadLibraryW")
|
||||
procFreeLibrary = getSysProcAddr(modkernel32, "FreeLibrary")
|
||||
procGetProcAddress = getSysProcAddr(modkernel32, "GetProcAddress")
|
||||
procGetVersion = getSysProcAddr(modkernel32, "GetVersion")
|
||||
procFormatMessageW = getSysProcAddr(modkernel32, "FormatMessageW")
|
||||
procExitProcess = getSysProcAddr(modkernel32, "ExitProcess")
|
||||
procCreateFileW = getSysProcAddr(modkernel32, "CreateFileW")
|
||||
procReadFile = getSysProcAddr(modkernel32, "ReadFile")
|
||||
procWriteFile = getSysProcAddr(modkernel32, "WriteFile")
|
||||
procSetFilePointer = getSysProcAddr(modkernel32, "SetFilePointer")
|
||||
procCloseHandle = getSysProcAddr(modkernel32, "CloseHandle")
|
||||
procGetStdHandle = getSysProcAddr(modkernel32, "GetStdHandle")
|
||||
procFindFirstFileW = getSysProcAddr(modkernel32, "FindFirstFileW")
|
||||
procFindNextFileW = getSysProcAddr(modkernel32, "FindNextFileW")
|
||||
procFindClose = getSysProcAddr(modkernel32, "FindClose")
|
||||
procGetFileInformationByHandle = getSysProcAddr(modkernel32, "GetFileInformationByHandle")
|
||||
procGetCurrentDirectoryW = getSysProcAddr(modkernel32, "GetCurrentDirectoryW")
|
||||
procSetCurrentDirectoryW = getSysProcAddr(modkernel32, "SetCurrentDirectoryW")
|
||||
procCreateDirectoryW = getSysProcAddr(modkernel32, "CreateDirectoryW")
|
||||
procRemoveDirectoryW = getSysProcAddr(modkernel32, "RemoveDirectoryW")
|
||||
procDeleteFileW = getSysProcAddr(modkernel32, "DeleteFileW")
|
||||
procMoveFileW = getSysProcAddr(modkernel32, "MoveFileW")
|
||||
procGetComputerNameW = getSysProcAddr(modkernel32, "GetComputerNameW")
|
||||
procSetEndOfFile = getSysProcAddr(modkernel32, "SetEndOfFile")
|
||||
procGetSystemTimeAsFileTime = getSysProcAddr(modkernel32, "GetSystemTimeAsFileTime")
|
||||
procSleep = getSysProcAddr(modkernel32, "Sleep")
|
||||
procCreateIoCompletionPort = getSysProcAddr(modkernel32, "CreateIoCompletionPort")
|
||||
procGetQueuedCompletionStatus = getSysProcAddr(modkernel32, "GetQueuedCompletionStatus")
|
||||
procWSAStartup = getSysProcAddr(modwsock32, "WSAStartup")
|
||||
procWSACleanup = getSysProcAddr(modwsock32, "WSACleanup")
|
||||
procsocket = getSysProcAddr(modwsock32, "socket")
|
||||
procsetsockopt = getSysProcAddr(modwsock32, "setsockopt")
|
||||
procbind = getSysProcAddr(modwsock32, "bind")
|
||||
procconnect = getSysProcAddr(modwsock32, "connect")
|
||||
procgetsockname = getSysProcAddr(modwsock32, "getsockname")
|
||||
procgetpeername = getSysProcAddr(modwsock32, "getpeername")
|
||||
proclisten = getSysProcAddr(modwsock32, "listen")
|
||||
procshutdown = getSysProcAddr(modwsock32, "shutdown")
|
||||
procAcceptEx = getSysProcAddr(modwsock32, "AcceptEx")
|
||||
procGetAcceptExSockaddrs = getSysProcAddr(modwsock32, "GetAcceptExSockaddrs")
|
||||
procWSARecv = getSysProcAddr(modws2_32, "WSARecv")
|
||||
procWSASend = getSysProcAddr(modws2_32, "WSASend")
|
||||
)
|
||||
|
||||
func GetLastError() (lasterrno int) {
|
||||
@ -321,3 +340,158 @@ func sleep(msec uint32) {
|
||||
Syscall(procSleep, uintptr(msec), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func CreateIoCompletionPort(filehandle int32, cphandle int32, key uint32, threadcnt uint32) (handle int32, errno int) {
|
||||
r0, _, e1 := Syscall6(procCreateIoCompletionPort, uintptr(filehandle), uintptr(cphandle), uintptr(key), uintptr(threadcnt), 0, 0)
|
||||
handle = int32(r0)
|
||||
if handle == 0 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetQueuedCompletionStatus(cphandle int32, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (ok bool, errno int) {
|
||||
r0, _, e1 := Syscall6(procGetQueuedCompletionStatus, uintptr(cphandle), uintptr(unsafe.Pointer(qty)), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(overlapped)), uintptr(timeout), 0)
|
||||
ok = bool(r0 != 0)
|
||||
if !ok {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WSAStartup(verreq uint32, data *WSAData) (sockerrno int) {
|
||||
r0, _, _ := Syscall(procWSAStartup, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
|
||||
sockerrno = int(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func WSACleanup() (errno int) {
|
||||
r1, _, e1 := Syscall(procWSACleanup, 0, 0, 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func socket(af int32, typ int32, protocol int32) (handle int32, errno int) {
|
||||
r0, _, e1 := Syscall(procsocket, uintptr(af), uintptr(typ), uintptr(protocol))
|
||||
handle = int32(r0)
|
||||
if handle == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setsockopt(s int32, level int32, optname int32, optval *byte, optlen int32) (errno int) {
|
||||
r1, _, e1 := Syscall6(procsetsockopt, uintptr(s), uintptr(level), uintptr(optname), uintptr(unsafe.Pointer(optval)), uintptr(optlen), 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func bind(s int32, name uintptr, namelen int32) (errno int) {
|
||||
r1, _, e1 := Syscall(procbind, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func connect(s int32, name uintptr, namelen int32) (errno int) {
|
||||
r1, _, e1 := Syscall(procconnect, uintptr(s), uintptr(name), uintptr(namelen))
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getsockname(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
|
||||
r1, _, e1 := Syscall(procgetsockname, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func getpeername(s int32, rsa *RawSockaddrAny, addrlen *int32) (errno int) {
|
||||
r1, _, e1 := Syscall(procgetpeername, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func listen(s int32, backlog int32) (errno int) {
|
||||
r1, _, e1 := Syscall(proclisten, uintptr(s), uintptr(backlog), 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func shutdown(s int32, how int32) (errno int) {
|
||||
r1, _, e1 := Syscall(procshutdown, uintptr(s), uintptr(how), 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AcceptEx(ls uint32, as uint32, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (ok bool, errno int) {
|
||||
r0, _, e1 := Syscall9(procAcceptEx, uintptr(ls), uintptr(as), uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(overlapped)), 0)
|
||||
ok = bool(r0 != 0)
|
||||
if !ok {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) {
|
||||
Syscall9(procGetAcceptExSockaddrs, uintptr(unsafe.Pointer(buf)), uintptr(rxdatalen), uintptr(laddrlen), uintptr(raddrlen), uintptr(unsafe.Pointer(lrsa)), uintptr(unsafe.Pointer(lrsalen)), uintptr(unsafe.Pointer(rrsa)), uintptr(unsafe.Pointer(rrsalen)), 0)
|
||||
return
|
||||
}
|
||||
|
||||
func WSARecv(s uint32, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (errno int) {
|
||||
r1, _, e1 := Syscall9(procWSARecv, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(recvd)), uintptr(unsafe.Pointer(flags)), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WSASend(s uint32, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (errno int) {
|
||||
r1, _, e1 := Syscall9(procWSASend, uintptr(s), uintptr(unsafe.Pointer(bufs)), uintptr(bufcnt), uintptr(unsafe.Pointer(sent)), uintptr(flags), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(croutine)), 0, 0)
|
||||
if int(r1) == -1 {
|
||||
errno = int(e1)
|
||||
} else {
|
||||
errno = 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -10,19 +10,15 @@ package syscall
|
||||
|
||||
// Constants
|
||||
const (
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
PathMax = 0x1000
|
||||
SizeofSockaddrInet4 = 0x10
|
||||
SizeofSockaddrInet6 = 0x1c
|
||||
SizeofSockaddrAny = 0x70
|
||||
SizeofSockaddrUnix = 0x6e
|
||||
SizeofLinger = 0x8
|
||||
SizeofMsghdr = 0x1c
|
||||
SizeofCmsghdr = 0xc
|
||||
sizeofPtr = 0x4
|
||||
sizeofShort = 0x2
|
||||
sizeofInt = 0x4
|
||||
sizeofLong = 0x4
|
||||
sizeofLongLong = 0x8
|
||||
PathMax = 0x1000
|
||||
SizeofLinger = 0x8
|
||||
SizeofMsghdr = 0x1c
|
||||
SizeofCmsghdr = 0xc
|
||||
)
|
||||
|
||||
const (
|
||||
@ -82,6 +78,10 @@ const (
|
||||
MAX_PATH = 260
|
||||
|
||||
MAX_COMPUTERNAME_LENGTH = 15
|
||||
|
||||
INFINITE = 0xffffffff
|
||||
|
||||
WAIT_TIMEOUT = 258
|
||||
)
|
||||
|
||||
// Types
|
||||
@ -155,6 +155,58 @@ type Stat_t struct {
|
||||
Mode uint32
|
||||
}
|
||||
|
||||
// Socket related.
|
||||
|
||||
const (
|
||||
AF_UNIX = 1
|
||||
AF_INET = 2
|
||||
AF_INET6 = 23
|
||||
|
||||
SOCK_STREAM = 1
|
||||
SOCK_DGRAM = 2
|
||||
SOCK_RAW = 3
|
||||
|
||||
IPPROTO_IP = 0
|
||||
IPPROTO_TCP = 6
|
||||
IPPROTO_UDP = 17
|
||||
|
||||
SOL_SOCKET = 0xffff
|
||||
SO_REUSEADDR = 4
|
||||
SO_KEEPALIVE = 8
|
||||
SO_DONTROUTE = 16
|
||||
SO_BROADCAST = 32
|
||||
SO_LINGER = 128
|
||||
SO_RCVBUF = 0x1002
|
||||
SO_SNDBUF = 0x1001
|
||||
SO_UPDATE_ACCEPT_CONTEXT = 0x700b
|
||||
|
||||
SOMAXCONN = 5
|
||||
|
||||
TCP_NODELAY = 1
|
||||
|
||||
SHUT_RD = 0
|
||||
SHUT_WR = 1
|
||||
SHUT_RDWR = 2
|
||||
|
||||
WSADESCRIPTION_LEN = 256
|
||||
WSASYS_STATUS_LEN = 128
|
||||
)
|
||||
|
||||
type WSAData struct {
|
||||
Version uint16
|
||||
HighVersion uint16
|
||||
Description [WSADESCRIPTION_LEN + 1]byte
|
||||
SystemStatus [WSASYS_STATUS_LEN + 1]byte
|
||||
MaxSockets uint16
|
||||
MaxUdpDg uint16
|
||||
VendorInfo *byte
|
||||
}
|
||||
|
||||
type WSABuf struct {
|
||||
Len uint32
|
||||
Buf *byte
|
||||
}
|
||||
|
||||
// TODO(brainman): fix all needed for os
|
||||
|
||||
const (
|
||||
|
Loading…
Reference in New Issue
Block a user