summaryrefslogtreecommitdiff
path: root/src/pkg/syscall/syscall_windows.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/syscall/syscall_windows.go')
-rw-r--r--src/pkg/syscall/syscall_windows.go319
1 files changed, 248 insertions, 71 deletions
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index 6b544f1d4..d7c3265a1 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -7,6 +7,8 @@
package syscall
import (
+ errorspkg "errors"
+ "sync"
"unicode/utf16"
"unsafe"
)
@@ -15,46 +17,28 @@ type Handle uintptr
const InvalidHandle = ^Handle(0)
-/*
-
-small demo to detect version of windows you are running:
-
-package main
-
-import (
- "syscall"
-)
-
-func abort(funcname string, err error) {
- panic(funcname + " failed: " + err.Error())
-}
-
-func print_version(v uint32) {
- major := byte(v)
- minor := uint8(v >> 8)
- build := uint16(v >> 16)
- print("windows version ", major, ".", minor, " (Build ", build, ")\n")
-}
-
-func main() {
- h, err := syscall.LoadLibrary("kernel32.dll")
- if err != nil {
- abort("LoadLibrary", err)
- }
- defer syscall.FreeLibrary(h)
- proc, err := syscall.GetProcAddress(h, "GetVersion")
+// StringToUTF16 is deprecated. Use UTF16FromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
+func StringToUTF16(s string) []uint16 {
+ a, err := UTF16FromString(s)
if err != nil {
- abort("GetProcAddress", err)
+ panic("syscall: string with NUL passed to StringToUTF16")
}
- r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
- print_version(uint32(r))
+ return a
}
-*/
-
-// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
-// with a terminating NUL added.
-func StringToUTF16(s string) []uint16 { return utf16.Encode([]rune(s + "\x00")) }
+// UTF16FromString returns the UTF-16 encoding of the UTF-8 string
+// s, with a terminating NUL added. If s contains a NUL byte at any
+// location, it returns (nil, EINVAL).
+func UTF16FromString(s string) ([]uint16, error) {
+ for i := 0; i < len(s); i++ {
+ if s[i] == 0 {
+ return nil, EINVAL
+ }
+ }
+ return utf16.Encode([]rune(s + "\x00")), nil
+}
// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed.
@@ -68,10 +52,22 @@ func UTF16ToString(s []uint16) string {
return string(utf16.Decode(s))
}
-// StringToUTF16Ptr returns pointer to the UTF-16 encoding of
-// the UTF-8 string s, with a terminating NUL added.
+// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
+// UTF16PtrFromString returns pointer to the UTF-16 encoding of
+// the UTF-8 string s, with a terminating NUL added. If s
+// contains a NUL byte at any location, it returns (nil, EINVAL).
+func UTF16PtrFromString(s string) (*uint16, error) {
+ a, err := UTF16FromString(s)
+ if err != nil {
+ return nil, err
+ }
+ return &a[0], nil
+}
+
func Getpagesize() int { return 4096 }
// Errno is the Windows error number.
@@ -90,9 +86,10 @@ func (e Errno) Error() string {
b := make([]uint16, 300)
n, err := FormatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
if err != nil {
- // TODO(brainman): Call FormatMessage again asking for "native" error message.
- // http://code.google.com/p/go/issues/detail?id=3376 must be resolved first.
- return "winapi error #" + itoa(int(e))
+ n, err = FormatMessage(flags, 0, uint32(e), 0, b, nil)
+ if err != nil {
+ return "winapi error #" + itoa(int(e))
+ }
}
// trim terminating \r and \n
for ; n > 0 && (b[n-1] == '\n' || b[n-1] == '\r'); n-- {
@@ -111,7 +108,7 @@ func (e Errno) Timeout() bool {
// Converts a Go function to a function pointer conforming
// to the stdcall calling convention. This is useful when
// interoperating with Windows code requiring callbacks.
-// Implemented in ../runtime/windows/syscall.goc
+// Implemented in ../runtime/syscall_windows.goc
func NewCallback(fn interface{}) uintptr
// windows api calls
@@ -147,6 +144,7 @@ func NewCallback(fn interface{}) uintptr
//sys GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
//sys PostQueuedCompletionStatus(cphandle Handle, qty uint32, key uint32, overlapped *Overlapped) (err error)
//sys CancelIo(s Handle) (err error)
+//sys CancelIoEx(s Handle, o *Overlapped) (err error)
//sys CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityAttributes, threadSecurity *SecurityAttributes, inheritHandles bool, creationFlags uint32, env *uint16, currentDir *uint16, startupInfo *StartupInfo, outProcInfo *ProcessInformation) (err error) = CreateProcessW
//sys OpenProcess(da uint32, inheritHandle bool, pid uint32) (handle Handle, err error)
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
@@ -201,7 +199,10 @@ func NewCallback(fn interface{}) uintptr
//sys RegQueryInfoKey(key Handle, class *uint16, classLen *uint32, reserved *uint32, subkeysLen *uint32, maxSubkeyLen *uint32, maxClassLen *uint32, valuesLen *uint32, maxValueNameLen *uint32, maxValueLen *uint32, saLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegQueryInfoKeyW
//sys RegEnumKeyEx(key Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, class *uint16, classLen *uint32, lastWriteTime *Filetime) (regerrno error) = advapi32.RegEnumKeyExW
//sys RegQueryValueEx(key Handle, name *uint16, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegQueryValueExW
-//sys getCurrentProcessId() (pid uint32) = kernel32.getCurrentProcessId
+//sys getCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
+//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
+//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
+//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
// syscall interface implementation for other packages
@@ -218,6 +219,10 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
if len(path) == 0 {
return InvalidHandle, ERROR_FILE_NOT_FOUND
}
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return InvalidHandle, err
+ }
var access uint32
switch mode & (O_RDONLY | O_WRONLY | O_RDWR) {
case O_RDONLY:
@@ -252,7 +257,7 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
default:
createmode = OPEN_EXISTING
}
- h, e := CreateFile(StringToUTF16Ptr(path), access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
+ h, e := CreateFile(pathp, access, sharemode, sa, createmode, FILE_ATTRIBUTE_NORMAL, 0)
return h, e
}
@@ -266,10 +271,16 @@ func Read(fd Handle, p []byte) (n int, err error) {
}
return 0, e
}
+ if raceenabled {
+ raceAcquire(unsafe.Pointer(&ioSync))
+ }
return int(done), nil
}
func Write(fd Handle, p []byte) (n int, err error) {
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
var done uint32
e := WriteFile(fd, p, &done, nil)
if e != nil {
@@ -278,6 +289,8 @@ func Write(fd Handle, p []byte) (n int, err error) {
return int(done), nil
}
+var ioSync int64
+
func Seek(fd Handle, offset int64, whence int) (newoffset int64, err error) {
var w uint32
switch whence {
@@ -330,24 +343,46 @@ func Getwd() (wd string, err error) {
}
func Chdir(path string) (err error) {
- return SetCurrentDirectory(&StringToUTF16(path)[0])
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return SetCurrentDirectory(pathp)
}
func Mkdir(path string, mode uint32) (err error) {
- return CreateDirectory(&StringToUTF16(path)[0], nil)
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return CreateDirectory(pathp, nil)
}
func Rmdir(path string) (err error) {
- return RemoveDirectory(&StringToUTF16(path)[0])
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return RemoveDirectory(pathp)
}
func Unlink(path string) (err error) {
- return DeleteFile(&StringToUTF16(path)[0])
+ pathp, err := UTF16PtrFromString(path)
+ if err != nil {
+ return err
+ }
+ return DeleteFile(pathp)
}
func Rename(oldpath, newpath string) (err error) {
- from := &StringToUTF16(oldpath)[0]
- to := &StringToUTF16(newpath)[0]
+ from, err := UTF16PtrFromString(oldpath)
+ if err != nil {
+ return err
+ }
+ to, err := UTF16PtrFromString(newpath)
+ if err != nil {
+ return err
+ }
return MoveFile(from, to)
}
@@ -403,7 +438,11 @@ func Utimes(path string, tv []Timeval) (err error) {
if len(tv) != 2 {
return EINVAL
}
- h, e := CreateFile(StringToUTF16Ptr(path),
+ pathp, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
+ h, e := CreateFile(pathp,
FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
if e != nil {
@@ -415,6 +454,26 @@ func Utimes(path string, tv []Timeval) (err error) {
return SetFileTime(h, nil, &a, &w)
}
+func UtimesNano(path string, ts []Timespec) (err error) {
+ if len(ts) != 2 {
+ return EINVAL
+ }
+ pathp, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
+ h, e := CreateFile(pathp,
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_WRITE, nil,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
+ if e != nil {
+ return e
+ }
+ defer Close(h)
+ a := NsecToFiletime(TimespecToNsec(ts[0]))
+ w := NsecToFiletime(TimespecToNsec(ts[1]))
+ return SetFileTime(h, nil, &a, &w)
+}
+
func Fsync(fd Handle) (err error) {
return FlushFileBuffers(fd)
}
@@ -423,7 +482,10 @@ func Chmod(path string, mode uint32) (err error) {
if mode == 0 {
return EINVAL
}
- p := StringToUTF16Ptr(path)
+ p, e := UTF16PtrFromString(path)
+ if e != nil {
+ return e
+ }
attrs, e := GetFileAttributes(p)
if e != nil {
return e
@@ -436,32 +498,41 @@ func Chmod(path string, mode uint32) (err error) {
return SetFileAttributes(p, attrs)
}
+func LoadCancelIoEx() error {
+ return procCancelIoEx.Find()
+}
+
// net api calls
+const socket_error = uintptr(^uint32(0))
+
//sys WSAStartup(verreq uint32, data *WSAData) (sockerr error) = ws2_32.WSAStartup
-//sys WSACleanup() (err error) [failretval==-1] = ws2_32.WSACleanup
-//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==-1] = ws2_32.WSAIoctl
+//sys WSACleanup() (err error) [failretval==socket_error] = ws2_32.WSACleanup
+//sys WSAIoctl(s Handle, iocc uint32, inbuf *byte, cbif uint32, outbuf *byte, cbob uint32, cbbr *uint32, overlapped *Overlapped, completionRoutine uintptr) (err error) [failretval==socket_error] = ws2_32.WSAIoctl
//sys socket(af int32, typ int32, protocol int32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.socket
-//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==-1] = ws2_32.setsockopt
-//sys bind(s Handle, name uintptr, namelen int32) (err error) [failretval==-1] = ws2_32.bind
-//sys connect(s Handle, name uintptr, namelen int32) (err error) [failretval==-1] = ws2_32.connect
-//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==-1] = ws2_32.getsockname
-//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==-1] = ws2_32.getpeername
-//sys listen(s Handle, backlog int32) (err error) [failretval==-1] = ws2_32.listen
-//sys shutdown(s Handle, how int32) (err error) [failretval==-1] = ws2_32.shutdown
-//sys Closesocket(s Handle) (err error) [failretval==-1] = ws2_32.closesocket
+//sys Setsockopt(s Handle, level int32, optname int32, optval *byte, optlen int32) (err error) [failretval==socket_error] = ws2_32.setsockopt
+//sys Getsockopt(s Handle, level int32, optname int32, optval *byte, optlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockopt
+//sys bind(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.bind
+//sys connect(s Handle, name uintptr, namelen int32) (err error) [failretval==socket_error] = ws2_32.connect
+//sys getsockname(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getsockname
+//sys getpeername(s Handle, rsa *RawSockaddrAny, addrlen *int32) (err error) [failretval==socket_error] = ws2_32.getpeername
+//sys listen(s Handle, backlog int32) (err error) [failretval==socket_error] = ws2_32.listen
+//sys shutdown(s Handle, how int32) (err error) [failretval==socket_error] = ws2_32.shutdown
+//sys Closesocket(s Handle) (err error) [failretval==socket_error] = ws2_32.closesocket
//sys AcceptEx(ls Handle, as Handle, buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, recvd *uint32, overlapped *Overlapped) (err error) = mswsock.AcceptEx
//sys GetAcceptExSockaddrs(buf *byte, rxdatalen uint32, laddrlen uint32, raddrlen uint32, lrsa **RawSockaddrAny, lrsalen *int32, rrsa **RawSockaddrAny, rrsalen *int32) = mswsock.GetAcceptExSockaddrs
-//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSARecv
-//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSASend
-//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSARecvFrom
-//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==-1] = ws2_32.WSASendTo
+//sys WSARecv(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecv
+//sys WSASend(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASend
+//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
+//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
//sys GetProtoByName(name string) (p *Protoent, err error) [failretval==nil] = ws2_32.getprotobyname
//sys DnsQuery(name string, qtype uint16, options uint32, extra *byte, qrs **DNSRecord, pr *byte) (status error) = dnsapi.DnsQuery_W
//sys DnsRecordListFree(rl *DNSRecord, freetype uint32) = dnsapi.DnsRecordListFree
+//sys GetAddrInfoW(nodename *uint16, servicename *uint16, hints *AddrinfoW, result **AddrinfoW) (sockerr error) = ws2_32.GetAddrInfoW
+//sys FreeAddrInfoW(addrinfo *AddrinfoW) = ws2_32.FreeAddrInfoW
//sys GetIfEntry(pIfRow *MibIfRow) (errcode error) = iphlpapi.GetIfEntry
//sys GetAdaptersInfo(ai *IpAdapterInfo, ol *uint32) (errcode error) = iphlpapi.GetAdaptersInfo
@@ -476,6 +547,14 @@ type RawSockaddrInet4 struct {
Zero [8]uint8
}
+type RawSockaddrInet6 struct {
+ Family uint16
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
type RawSockaddr struct {
Family uint16
Data [14]int8
@@ -514,11 +593,22 @@ type SockaddrInet6 struct {
Port int
ZoneId uint32
Addr [16]byte
+ raw RawSockaddrInet6
}
func (sa *SockaddrInet6) sockaddr() (uintptr, int32, error) {
- // TODO(brainman): implement SockaddrInet6.sockaddr()
- return 0, 0, EWINDOWS
+ if sa.Port < 0 || sa.Port > 0xFFFF {
+ return 0, 0, EINVAL
+ }
+ sa.raw.Family = AF_INET6
+ p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
+ p[0] = byte(sa.Port >> 8)
+ p[1] = byte(sa.Port)
+ sa.raw.Scope_id = sa.ZoneId
+ 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)), nil
}
type SockaddrUnix struct {
@@ -546,7 +636,15 @@ func (rsa *RawSockaddrAny) Sockaddr() (Sockaddr, error) {
return sa, nil
case AF_INET6:
- return nil, EWINDOWS
+ pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
+ sa := new(SockaddrInet6)
+ p := (*[2]byte)(unsafe.Pointer(&pp.Port))
+ sa.Port = int(p[0])<<8 + int(p[1])
+ sa.ZoneId = pp.Scope_id
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, nil
}
return nil, EAFNOSUPPORT
}
@@ -613,6 +711,60 @@ func WSASendto(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32
return WSASendTo(s, bufs, bufcnt, sent, flags, (*RawSockaddrAny)(unsafe.Pointer(rsa)), l, overlapped, croutine)
}
+func LoadGetAddrInfo() error {
+ return procGetAddrInfoW.Find()
+}
+
+var connectExFunc struct {
+ once sync.Once
+ addr uintptr
+ err error
+}
+
+func LoadConnectEx() error {
+ connectExFunc.once.Do(func() {
+ var s Handle
+ s, connectExFunc.err = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
+ if connectExFunc.err != nil {
+ return
+ }
+ defer CloseHandle(s)
+ var n uint32
+ connectExFunc.err = WSAIoctl(s,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ (*byte)(unsafe.Pointer(&WSAID_CONNECTEX)),
+ uint32(unsafe.Sizeof(WSAID_CONNECTEX)),
+ (*byte)(unsafe.Pointer(&connectExFunc.addr)),
+ uint32(unsafe.Sizeof(connectExFunc.addr)),
+ &n, nil, 0)
+ })
+ return connectExFunc.err
+}
+
+func connectEx(s Handle, name uintptr, namelen int32, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) (err error) {
+ r1, _, e1 := Syscall9(connectExFunc.addr, 7, uintptr(s), uintptr(name), uintptr(namelen), uintptr(unsafe.Pointer(sendBuf)), uintptr(sendDataLen), uintptr(unsafe.Pointer(bytesSent)), uintptr(unsafe.Pointer(overlapped)), 0, 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = error(e1)
+ } else {
+ err = EINVAL
+ }
+ }
+ return
+}
+
+func ConnectEx(fd Handle, sa Sockaddr, sendBuf *byte, sendDataLen uint32, bytesSent *uint32, overlapped *Overlapped) error {
+ err := LoadConnectEx()
+ if err != nil {
+ return errorspkg.New("failed to find ConnectEx: " + err.Error())
+ }
+ ptr, n, err := sa.sockaddr()
+ if err != nil {
+ return err
+ }
+ return connectEx(fd, ptr, n, sendBuf, sendDataLen, bytesSent, overlapped)
+}
+
// Invented structures to support what package os expects.
type Rusage struct {
CreationTime Filetime
@@ -650,6 +802,14 @@ type Timespec struct {
Nsec int64
}
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+ ts.Sec = nsec / 1e9
+ ts.Nsec = nsec % 1e9
+ return
+}
+
// TODO(brainman): fix all needed for net
func Accept(fd Handle) (nfd Handle, sa Sockaddr, err error) { return 0, nil, EWINDOWS }
@@ -659,11 +819,23 @@ func Recvfrom(fd Handle, p []byte, flags int) (n int, from Sockaddr, err error)
func Sendto(fd Handle, p []byte, flags int, to Sockaddr) (err error) { return EWINDOWS }
func SetsockoptTimeval(fd Handle, level, opt int, tv *Timeval) (err error) { return EWINDOWS }
+// The Linger struct is wrong but we only noticed after Go 1.
+// sysLinger is the real system call structure.
+
+// BUG(brainman): The definition of Linger is not appropriate for direct use
+// with Setsockopt and Getsockopt.
+// Use SetsockoptLinger instead.
+
type Linger struct {
Onoff int32
Linger int32
}
+type sysLinger struct {
+ Onoff uint16
+ Linger uint16
+}
+
type IPMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
@@ -674,8 +846,13 @@ type IPv6Mreq struct {
Interface uint32
}
-func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS }
-func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) { return EWINDOWS }
+func GetsockoptInt(fd Handle, level, opt int) (int, error) { return -1, EWINDOWS }
+
+func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
+ sys := sysLinger{Onoff: uint16(l.Onoff), Linger: uint16(l.Linger)}
+ return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&sys)), int32(unsafe.Sizeof(sys)))
+}
+
func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
}