<commit_before>// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.

// 配置管理.
// 配置文件格式支持：json, xml, toml, yaml/yml
package gcfg

import (
    "sync"
    "strings"
    "gitee.com/johng/gf/g/os/gfile"
    "gitee.com/johng/gf/g/container/gmap"
    "gitee.com/johng/gf/g/encoding/gjson"
)

const (
    gDEFAULT_CONFIG_FILE = "config.yml" // 默认的配置管理文件名称
)

// 配置管理对象
type Config struct {
    mu    sync.RWMutex             // 并发互斥锁
    path  string                   // 配置文件存放目录，绝对路径
    jsons *gmap.StringInterfaceMap // 配置文件对象
}

// 生成一个配置管理对象
func New(path string) *Config {
    return &Config {
        path  : path,
        jsons : gmap.NewStringInterfaceMap(),
    }
}

// 判断从哪个配置文件中获取内容
func (c *Config) filePath(files []string) string {
    file := gDEFAULT_CONFIG_FILE
    if len(files) > 0 {
        file = files[0]
    }
    c.mu.RLock()
    fpath := c.path + gfile.Separator + file
    c.mu.RUnlock()
    return fpath
}

// 设置配置管理器的配置文件存放目录绝对路径
func (c *Config) SetPath(path string) {
    c.mu.Lock()
    if strings.Compare(c.path, path) != 0 {
        c.path  = path
        c.jsons = gmap.NewStringInterfaceMap()
    }
    c.mu.Unlock()
}

// 添加配置文件到配置管理器中，第二个参数为非必须，如果不输入表示添加进入默认的配置名称中
func (c *Config) getJson(files []string) *gjson.Json {
    fpath := c.filePath(files)
    if r := c.jsons.Get(fpath); r != nil {
        return r.(*gjson.Json)
    }
    if j, err := gjson.Load(fpath); err == nil {
        c.jsons.Set(fpath, j)
        return j
    }
    return nil
}

// 获取配置项，当不存在时返回nil
func (c *Config) Get(pattern string, files...string) interface{} {
    if j := c.getJson(files); j != nil {
        return j.Get(pattern)
    }
    return nil
}

// 获得一个键值对关联数组/哈希表，方便操作，不需要自己做类型转换
// 注意，如果获取的值不存在，或者类型与json类型不匹配，那么将会返回nil
func (c *Config) GetMap(pattern string, files...string)  map[string]interface{} {
    if j := c.getJson(files); j != nil {
        return j.GetMap(pattern)
    }
    return nil
}

// 获得一个数组[]interface{}，方便操作，不需要自己做类型转换
// 注意，如果获取的值不存在，或者类型与json类型不匹配，那么将会返回nil
func (c *Config) GetArray(pattern string, files...string)  []interface{} {
    if j := c.getJson(files); j != nil {
        return j.GetArray(pattern)
    }
    return nil
}

// 返回指定json中的string
func (c *Config) GetString(pattern string, files...string) string {
    if j := c.getJson(files); j != nil {
        return j.GetString(pattern)
    }
    return ""
}

// 返回指定json中的bool
func (c *Config) GetBool(pattern string, files...string) bool {
    if j := c.getJson(files); j != nil {
        return j.GetBool(pattern)
    }
    return false
}

// 返回指定json中的float32
func (c *Config) GetFloat32(pattern string, files...string) float32 {
    if j := c.getJson(files); j != nil {
        return j.GetFloat32(pattern)
    }
    return 0
}

// 返回指定json中的float64
func (c *Config) GetFloat64(pattern string, files...string) float64 {
    if j := c.getJson(files); j != nil {
        return j.GetFloat64(pattern)
    }
    return 0
}

// 返回指定json中的float64->int
func (c *Config) GetInt(pattern string, files...string)  int {
    if j := c.getJson(files); j != nil {
        return j.GetInt(pattern)
    }
    return 0
}

// 返回指定json中的float64->uint
func (c *Config) GetUint(pattern string, files...string)  uint {
    if j := c.getJson(files); j != nil {
        return j.GetUint(pattern)
    }
    return 0
}<commit_msg>gcfg增加GetPath方法<commit_after>// Copyright 2017 gf Author(https://gitee.com/johng/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://gitee.com/johng/gf.

// 配置管理.
// 配置文件格式支持：json, xml, toml, yaml/yml
package gcfg

import (
    "sync"
    "strings"
    "gitee.com/johng/gf/g/os/gfile"
    "gitee.com/johng/gf/g/container/gmap"
    "gitee.com/johng/gf/g/encoding/gjson"
    "gitee.com/johng/gf/g/container/gtype"
)

const (
    gDEFAULT_CONFIG_FILE = "config.yml" // 默认的配置管理文件名称
)

// 配置管理对象
type Config struct {
    mu    sync.RWMutex             // 并发互斥锁
    path  *gtype.String            // 配置文件存放目录，绝对路径
    jsons *gmap.StringInterfaceMap // 配置文件对象
}

// 生成一个配置管理对象
func New(path string) *Config {
    return &Config {
        path  : gtype.NewString(),
        jsons : gmap.NewStringInterfaceMap(),
    }
}

// 判断从哪个配置文件中获取内容
func (c *Config) filePath(files []string) string {
    file := gDEFAULT_CONFIG_FILE
    if len(files) > 0 {
        file = files[0]
    }
    fpath := c.path.Val() + gfile.Separator + file
    return fpath
}

// 设置配置管理器的配置文件存放目录绝对路径
func (c *Config) SetPath(path string) {
    if strings.Compare(c.path.Val(), path) != 0 {
        c.path.Set(path)
        c.mu.Lock()
        c.jsons = gmap.NewStringInterfaceMap()
        c.mu.Unlock()
    }
}

// 设置配置管理器的配置文件存放目录绝对路径
func (c *Config) GetPath() string {
    return c.path.Val()
}

// 添加配置文件到配置管理器中，第二个参数为非必须，如果不输入表示添加进入默认的配置名称中
func (c *Config) getJson(files []string) *gjson.Json {
    fpath := c.filePath(files)
    if r := c.jsons.Get(fpath); r != nil {
        return r.(*gjson.Json)
    }
    if j, err := gjson.Load(fpath); err == nil {
        c.jsons.Set(fpath, j)
        return j
    }
    return nil
}

// 获取配置项，当不存在时返回nil
func (c *Config) Get(pattern string, files...string) interface{} {
    if j := c.getJson(files); j != nil {
        return j.Get(pattern)
    }
    return nil
}

// 获得一个键值对关联数组/哈希表，方便操作，不需要自己做类型转换
// 注意，如果获取的值不存在，或者类型与json类型不匹配，那么将会返回nil
func (c *Config) GetMap(pattern string, files...string)  map[string]interface{} {
    if j := c.getJson(files); j != nil {
        return j.GetMap(pattern)
    }
    return nil
}

// 获得一个数组[]interface{}，方便操作，不需要自己做类型转换
// 注意，如果获取的值不存在，或者类型与json类型不匹配，那么将会返回nil
func (c *Config) GetArray(pattern string, files...string)  []interface{} {
    if j := c.getJson(files); j != nil {
        return j.GetArray(pattern)
    }
    return nil
}

// 返回指定json中的string
func (c *Config) GetString(pattern string, files...string) string {
    if j := c.getJson(files); j != nil {
        return j.GetString(pattern)
    }
    return ""
}

// 返回指定json中的bool
func (c *Config) GetBool(pattern string, files...string) bool {
    if j := c.getJson(files); j != nil {
        return j.GetBool(pattern)
    }
    return false
}

// 返回指定json中的float32
func (c *Config) GetFloat32(pattern string, files...string) float32 {
    if j := c.getJson(files); j != nil {
        return j.GetFloat32(pattern)
    }
    return 0
}

// 返回指定json中的float64
func (c *Config) GetFloat64(pattern string, files...string) float64 {
    if j := c.getJson(files); j != nil {
        return j.GetFloat64(pattern)
    }
    return 0
}

// 返回指定json中的float64->int
func (c *Config) GetInt(pattern string, files...string)  int {
    if j := c.getJson(files); j != nil {
        return j.GetInt(pattern)
    }
    return 0
}

// 返回指定json中的float64->uint
func (c *Config) GetUint(pattern string, files...string)  uint {
    if j := c.getJson(files); j != nil {
        return j.GetUint(pattern)
    }
    return 0
}<|endoftext|>


<commit_before>// 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)
	}
}
<commit_msg>net(windows): properly handle EOF in (*netFD).Read().<commit_after>// 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)
	if err == nil && n == 0 {
		err = os.EOF
	}
	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)
	}
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// TODO(cw): ListenPacket test, Read() test, ipv6 test &
// Dial()/Listen() level tests

package net

import (
	"bytes"
	"flag"
	"os"
	"runtime"
	"testing"
)

const ICMP_ECHO_REQUEST = 8
const ICMP_ECHO_REPLY = 0

// returns a suitable 'ping request' packet, with id & seq and a
// payload length of pktlen
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
	p := make([]byte, pktlen)
	copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))

	p[0] = ICMP_ECHO_REQUEST // type
	p[1] = 0                 // code
	p[2] = 0                 // cksum
	p[3] = 0                 // cksum
	p[4] = uint8(id >> 8)    // id
	p[5] = uint8(id & 0xff)  // id
	p[6] = uint8(seq >> 8)   // sequence
	p[7] = uint8(seq & 0xff) // sequence

	// calculate icmp checksum
	cklen := len(p)
	s := uint32(0)
	for i := 0; i < (cklen - 1); i += 2 {
		s += uint32(p[i+1])<<8 | uint32(p[i])
	}
	if cklen&1 == 1 {
		s += uint32(p[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)

	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	p[2] ^= uint8(^s & 0xff)
	p[3] ^= uint8(^s >> 8)

	return p
}

func parsePingReply(p []byte) (id, seq int) {
	id = int(p[4])<<8 | int(p[5])
	seq = int(p[6])<<8 | int(p[7])
	return
}

var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
// 127.0.0.1 because this is an IPv4-specific test.
var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")

// test (raw) IP socket using ICMP
func TestICMP(t *testing.T) {
	if runtime.GOOS != "windows" && os.Getuid() != 0 {
		t.Logf("test disabled; must be root")
		return
	}

	var (
		laddr *IPAddr
		err   os.Error
	)
	if *srchost != "" {
		laddr, err = ResolveIPAddr("ip4", *srchost)
		if err != nil {
			t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
		}
	}

	raddr, err := ResolveIPAddr("ip4", *dsthost)
	if err != nil {
		t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
	}

	c, err := ListenIP("ip4:icmp", laddr)
	if err != nil {
		t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
	}

	sendid := os.Getpid() & 0xffff
	const sendseq = 61455
	const pingpktlen = 128
	sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))

	n, err := c.WriteToIP(sendpkt, raddr)
	if err != nil || n != pingpktlen {
		t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
	}

	c.SetTimeout(100e6)
	resp := make([]byte, 1024)
	for {
		n, from, err := c.ReadFrom(resp)
		if err != nil {
			t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
		}
		if resp[0] != ICMP_ECHO_REPLY {
			continue
		}
		rcvid, rcvseq := parsePingReply(resp)
		if rcvid != sendid || rcvseq != sendseq {
			t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
		}
		return
	}
	t.Fatalf("saw no ping return")
}
<commit_msg>net: skip ICMP test on Windows too unless uid 0<commit_after>// Copyright 2009 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.

// TODO(cw): ListenPacket test, Read() test, ipv6 test &
// Dial()/Listen() level tests

package net

import (
	"bytes"
	"flag"
	"os"
	"testing"
)

const ICMP_ECHO_REQUEST = 8
const ICMP_ECHO_REPLY = 0

// returns a suitable 'ping request' packet, with id & seq and a
// payload length of pktlen
func makePingRequest(id, seq, pktlen int, filler []byte) []byte {
	p := make([]byte, pktlen)
	copy(p[8:], bytes.Repeat(filler, (pktlen-8)/len(filler)+1))

	p[0] = ICMP_ECHO_REQUEST // type
	p[1] = 0                 // code
	p[2] = 0                 // cksum
	p[3] = 0                 // cksum
	p[4] = uint8(id >> 8)    // id
	p[5] = uint8(id & 0xff)  // id
	p[6] = uint8(seq >> 8)   // sequence
	p[7] = uint8(seq & 0xff) // sequence

	// calculate icmp checksum
	cklen := len(p)
	s := uint32(0)
	for i := 0; i < (cklen - 1); i += 2 {
		s += uint32(p[i+1])<<8 | uint32(p[i])
	}
	if cklen&1 == 1 {
		s += uint32(p[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)

	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	p[2] ^= uint8(^s & 0xff)
	p[3] ^= uint8(^s >> 8)

	return p
}

func parsePingReply(p []byte) (id, seq int) {
	id = int(p[4])<<8 | int(p[5])
	seq = int(p[6])<<8 | int(p[7])
	return
}

var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request")
// 127.0.0.1 because this is an IPv4-specific test.
var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request")

// test (raw) IP socket using ICMP
func TestICMP(t *testing.T) {
	if os.Getuid() != 0 {
		t.Logf("test disabled; must be root")
		return
	}

	var (
		laddr *IPAddr
		err   os.Error
	)
	if *srchost != "" {
		laddr, err = ResolveIPAddr("ip4", *srchost)
		if err != nil {
			t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
		}
	}

	raddr, err := ResolveIPAddr("ip4", *dsthost)
	if err != nil {
		t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
	}

	c, err := ListenIP("ip4:icmp", laddr)
	if err != nil {
		t.Fatalf(`net.ListenIP("ip4:icmp", %v) = %v, %v`, *srchost, c, err)
	}

	sendid := os.Getpid() & 0xffff
	const sendseq = 61455
	const pingpktlen = 128
	sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Go Gadget Ping!!!"))

	n, err := c.WriteToIP(sendpkt, raddr)
	if err != nil || n != pingpktlen {
		t.Fatalf(`net.WriteToIP(..., %v) = %v, %v`, raddr, n, err)
	}

	c.SetTimeout(100e6)
	resp := make([]byte, 1024)
	for {
		n, from, err := c.ReadFrom(resp)
		if err != nil {
			t.Fatalf(`ReadFrom(...) = %v, %v, %v`, n, from, err)
		}
		if resp[0] != ICMP_ECHO_REPLY {
			continue
		}
		rcvid, rcvseq := parsePingReply(resp)
		if rcvid != sendid || rcvseq != sendseq {
			t.Fatalf(`Ping reply saw id,seq=0x%x,0x%x (expected 0x%x, 0x%x)`, rcvid, rcvseq, sendid, sendseq)
		}
		return
	}
	t.Fatalf("saw no ping return")
}
<|endoftext|>


<commit_before>// Copyright 2009 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.

// +build !plan9

package net

import (
	"bytes"
	"os"
	"syscall"
	"testing"
	"time"
)

var icmpTests = []struct {
	net   string
	laddr string
	raddr string
	ipv6  bool // test with underlying AF_INET6 socket
}{
	{"ip4:icmp", "", "127.0.0.1", false},
	{"ip6:icmp", "", "::1", true},
}

func TestICMP(t *testing.T) {
	if os.Getuid() != 0 {
		t.Logf("skipping test; must be root")
		return
	}

	seqnum := 61455
	for _, tt := range icmpTests {
		if tt.ipv6 && !supportsIPv6 {
			continue
		}
		id := os.Getpid() & 0xffff
		seqnum++
		echo := newICMPEchoRequest(tt.net, id, seqnum, 128, []byte("Go Go Gadget Ping!!!"))
		exchangeICMPEcho(t, tt.net, tt.laddr, tt.raddr, echo)
	}
}

func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, echo []byte) {
	c, err := ListenPacket(net, laddr)
	if err != nil {
		t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
		return
	}
	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
	defer c.Close()

	ra, err := ResolveIPAddr(net, raddr)
	if err != nil {
		t.Errorf("ResolveIPAddr(%q, %q) failed: %v", net, raddr, err)
		return
	}

	waitForReady := make(chan bool)
	go icmpEchoTransponder(t, net, raddr, waitForReady)
	<-waitForReady

	_, err = c.WriteTo(echo, ra)
	if err != nil {
		t.Errorf("WriteTo failed: %v", err)
		return
	}

	reply := make([]byte, 256)
	for {
		_, _, err := c.ReadFrom(reply)
		if err != nil {
			t.Errorf("ReadFrom failed: %v", err)
			return
		}
		switch c.(*IPConn).fd.family {
		case syscall.AF_INET:
			if reply[0] != ICMP4_ECHO_REPLY {
				continue
			}
		case syscall.AF_INET6:
			if reply[0] != ICMP6_ECHO_REPLY {
				continue
			}
		}
		xid, xseqnum := parseICMPEchoReply(echo)
		rid, rseqnum := parseICMPEchoReply(reply)
		if rid != xid || rseqnum != xseqnum {
			t.Errorf("ID = %v, Seqnum = %v, want ID = %v, Seqnum = %v", rid, rseqnum, xid, xseqnum)
			return
		}
		break
	}
}

func icmpEchoTransponder(t *testing.T, net, raddr string, waitForReady chan bool) {
	c, err := Dial(net, raddr)
	if err != nil {
		waitForReady <- true
		t.Errorf("Dial(%q, %q) failed: %v", net, raddr, err)
		return
	}
	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
	defer c.Close()
	waitForReady <- true

	echo := make([]byte, 256)
	var nr int
	for {
		nr, err = c.Read(echo)
		if err != nil {
			t.Errorf("Read failed: %v", err)
			return
		}
		switch c.(*IPConn).fd.family {
		case syscall.AF_INET:
			if echo[0] != ICMP4_ECHO_REQUEST {
				continue
			}
		case syscall.AF_INET6:
			if echo[0] != ICMP6_ECHO_REQUEST {
				continue
			}
		}
		break
	}

	switch c.(*IPConn).fd.family {
	case syscall.AF_INET:
		echo[0] = ICMP4_ECHO_REPLY
	case syscall.AF_INET6:
		echo[0] = ICMP6_ECHO_REPLY
	}

	_, err = c.Write(echo[:nr])
	if err != nil {
		t.Errorf("Write failed: %v", err)
		return
	}
}

const (
	ICMP4_ECHO_REQUEST = 8
	ICMP4_ECHO_REPLY   = 0
	ICMP6_ECHO_REQUEST = 128
	ICMP6_ECHO_REPLY   = 129
)

func newICMPEchoRequest(net string, id, seqnum, msglen int, filler []byte) []byte {
	afnet, _, _ := parseDialNetwork(net)
	switch afnet {
	case "ip4":
		return newICMPv4EchoRequest(id, seqnum, msglen, filler)
	case "ip6":
		return newICMPv6EchoRequest(id, seqnum, msglen, filler)
	}
	return nil
}

func newICMPv4EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
	b := newICMPInfoMessage(id, seqnum, msglen, filler)
	b[0] = ICMP4_ECHO_REQUEST

	// calculate ICMP checksum
	cklen := len(b)
	s := uint32(0)
	for i := 0; i < cklen-1; i += 2 {
		s += uint32(b[i+1])<<8 | uint32(b[i])
	}
	if cklen&1 == 1 {
		s += uint32(b[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)
	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	b[2] ^= uint8(^s & 0xff)
	b[3] ^= uint8(^s >> 8)

	return b
}

func newICMPv6EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
	b := newICMPInfoMessage(id, seqnum, msglen, filler)
	b[0] = ICMP6_ECHO_REQUEST
	return b
}

func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
	b := make([]byte, msglen)
	copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
	b[0] = 0                    // type
	b[1] = 0                    // code
	b[2] = 0                    // checksum
	b[3] = 0                    // checksum
	b[4] = uint8(id >> 8)       // identifier
	b[5] = uint8(id & 0xff)     // identifier
	b[6] = uint8(seqnum >> 8)   // sequence number
	b[7] = uint8(seqnum & 0xff) // sequence number
	return b
}

func parseICMPEchoReply(b []byte) (id, seqnum int) {
	id = int(b[4])<<8 | int(b[5])
	seqnum = int(b[6])<<8 | int(b[7])
	return
}
<commit_msg>net: fix protocol number for IPv6 test<commit_after>// Copyright 2009 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.

// +build !plan9

package net

import (
	"bytes"
	"os"
	"syscall"
	"testing"
	"time"
)

var icmpTests = []struct {
	net   string
	laddr string
	raddr string
	ipv6  bool // test with underlying AF_INET6 socket
}{
	{"ip4:icmp", "", "127.0.0.1", false},
	{"ip6:ipv6-icmp", "", "::1", true},
}

func TestICMP(t *testing.T) {
	if os.Getuid() != 0 {
		t.Logf("skipping test; must be root")
		return
	}

	seqnum := 61455
	for _, tt := range icmpTests {
		if tt.ipv6 && !supportsIPv6 {
			continue
		}
		id := os.Getpid() & 0xffff
		seqnum++
		echo := newICMPEchoRequest(tt.net, id, seqnum, 128, []byte("Go Go Gadget Ping!!!"))
		exchangeICMPEcho(t, tt.net, tt.laddr, tt.raddr, echo)
	}
}

func exchangeICMPEcho(t *testing.T, net, laddr, raddr string, echo []byte) {
	c, err := ListenPacket(net, laddr)
	if err != nil {
		t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
		return
	}
	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
	defer c.Close()

	ra, err := ResolveIPAddr(net, raddr)
	if err != nil {
		t.Errorf("ResolveIPAddr(%q, %q) failed: %v", net, raddr, err)
		return
	}

	waitForReady := make(chan bool)
	go icmpEchoTransponder(t, net, raddr, waitForReady)
	<-waitForReady

	_, err = c.WriteTo(echo, ra)
	if err != nil {
		t.Errorf("WriteTo failed: %v", err)
		return
	}

	reply := make([]byte, 256)
	for {
		_, _, err := c.ReadFrom(reply)
		if err != nil {
			t.Errorf("ReadFrom failed: %v", err)
			return
		}
		switch c.(*IPConn).fd.family {
		case syscall.AF_INET:
			if reply[0] != ICMP4_ECHO_REPLY {
				continue
			}
		case syscall.AF_INET6:
			if reply[0] != ICMP6_ECHO_REPLY {
				continue
			}
		}
		xid, xseqnum := parseICMPEchoReply(echo)
		rid, rseqnum := parseICMPEchoReply(reply)
		if rid != xid || rseqnum != xseqnum {
			t.Errorf("ID = %v, Seqnum = %v, want ID = %v, Seqnum = %v", rid, rseqnum, xid, xseqnum)
			return
		}
		break
	}
}

func icmpEchoTransponder(t *testing.T, net, raddr string, waitForReady chan bool) {
	c, err := Dial(net, raddr)
	if err != nil {
		waitForReady <- true
		t.Errorf("Dial(%q, %q) failed: %v", net, raddr, err)
		return
	}
	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
	defer c.Close()
	waitForReady <- true

	echo := make([]byte, 256)
	var nr int
	for {
		nr, err = c.Read(echo)
		if err != nil {
			t.Errorf("Read failed: %v", err)
			return
		}
		switch c.(*IPConn).fd.family {
		case syscall.AF_INET:
			if echo[0] != ICMP4_ECHO_REQUEST {
				continue
			}
		case syscall.AF_INET6:
			if echo[0] != ICMP6_ECHO_REQUEST {
				continue
			}
		}
		break
	}

	switch c.(*IPConn).fd.family {
	case syscall.AF_INET:
		echo[0] = ICMP4_ECHO_REPLY
	case syscall.AF_INET6:
		echo[0] = ICMP6_ECHO_REPLY
	}

	_, err = c.Write(echo[:nr])
	if err != nil {
		t.Errorf("Write failed: %v", err)
		return
	}
}

const (
	ICMP4_ECHO_REQUEST = 8
	ICMP4_ECHO_REPLY   = 0
	ICMP6_ECHO_REQUEST = 128
	ICMP6_ECHO_REPLY   = 129
)

func newICMPEchoRequest(net string, id, seqnum, msglen int, filler []byte) []byte {
	afnet, _, _ := parseDialNetwork(net)
	switch afnet {
	case "ip4":
		return newICMPv4EchoRequest(id, seqnum, msglen, filler)
	case "ip6":
		return newICMPv6EchoRequest(id, seqnum, msglen, filler)
	}
	return nil
}

func newICMPv4EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
	b := newICMPInfoMessage(id, seqnum, msglen, filler)
	b[0] = ICMP4_ECHO_REQUEST

	// calculate ICMP checksum
	cklen := len(b)
	s := uint32(0)
	for i := 0; i < cklen-1; i += 2 {
		s += uint32(b[i+1])<<8 | uint32(b[i])
	}
	if cklen&1 == 1 {
		s += uint32(b[cklen-1])
	}
	s = (s >> 16) + (s & 0xffff)
	s = s + (s >> 16)
	// place checksum back in header; using ^= avoids the
	// assumption the checksum bytes are zero
	b[2] ^= uint8(^s & 0xff)
	b[3] ^= uint8(^s >> 8)

	return b
}

func newICMPv6EchoRequest(id, seqnum, msglen int, filler []byte) []byte {
	b := newICMPInfoMessage(id, seqnum, msglen, filler)
	b[0] = ICMP6_ECHO_REQUEST
	return b
}

func newICMPInfoMessage(id, seqnum, msglen int, filler []byte) []byte {
	b := make([]byte, msglen)
	copy(b[8:], bytes.Repeat(filler, (msglen-8)/len(filler)+1))
	b[0] = 0                    // type
	b[1] = 0                    // code
	b[2] = 0                    // checksum
	b[3] = 0                    // checksum
	b[4] = uint8(id >> 8)       // identifier
	b[5] = uint8(id & 0xff)     // identifier
	b[6] = uint8(seqnum >> 8)   // sequence number
	b[7] = uint8(seqnum & 0xff) // sequence number
	return b
}

func parseICMPEchoReply(b []byte) (id, seqnum int) {
	id = int(b[4])<<8 | int(b[5])
	seqnum = int(b[6])<<8 | int(b[7])
	return
}
<|endoftext|>


<commit_before>package ai

import (
	"bytes"
	"log"
	"math/rand"
	"time"

	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

const (
	maxEval      int64 = 1 << 30
	minEval            = -maxEval
	winThreshold       = 1 << 29
)

type MinimaxAI struct {
	depth int
	size  uint
	rand  *rand.Rand

	Debug bool

	st      stats
	c       bitboard.Constants
	regions []uint64
	rd      int
}

type stats struct {
	generated uint64
	evaluated uint64
	cutoffs   uint64
}

func formatpv(ms []tak.Move) string {
	var out bytes.Buffer
	out.WriteString("[")
	for i, m := range ms {
		if i != 0 {
			out.WriteString(" ")
		}
		out.WriteString(ptn.FormatMove(&m))
	}
	out.WriteString("]")
	return out.String()
}

func (m *MinimaxAI) GetMove(p *tak.Position, limit time.Duration) tak.Move {
	ms, _ := m.Analyze(p, limit)
	return ms[0]
}

func (m *MinimaxAI) Analyze(p *tak.Position, limit time.Duration) ([]tak.Move, int64) {
	if m.size != uint(p.Size()) {
		panic("Analyze: wrong size")
	}
	seed := time.Now().Unix()
	m.rand = rand.New(rand.NewSource(seed))
	if m.Debug {
		log.Printf("seed=%d", seed)
	}

	var ms []tak.Move
	var v int64
	top := time.Now()
	var prevEval uint64
	var branchSum uint64
	for i := 1; i <= m.depth; i++ {
		m.st = stats{}
		start := time.Now()
		ms, v = m.minimax(p, i, ms, minEval-1, maxEval+1)
		timeUsed := time.Now().Sub(top)
		timeMove := time.Now().Sub(start)
		if m.Debug {
			log.Printf("[minimax] depth=%d val=%d pv=%s time=%s total=%s evaluated=%d branch=%d",
				i, v, formatpv(ms),
				timeMove,
				timeUsed,
				m.st.evaluated,
				m.st.evaluated/(prevEval+1),
			)
		}
		if i > 1 {
			branchSum += m.st.evaluated / (prevEval + 1)
		}
		prevEval = m.st.evaluated
		if v > winThreshold || v < -winThreshold {
			break
		}
		if i > 2 {
			estimate := timeUsed + time.Now().Sub(start)*time.Duration(branchSum/uint64(i-1))
			if estimate > limit {
				if m.Debug {
					log.Printf("time cutoff depth=%d used=%s estimate=%s",
						i, timeUsed, estimate)
				}
				break
			}
		}
	}
	return ms, v
}

func (ai *MinimaxAI) minimax(
	p *tak.Position,
	depth int,
	pv []tak.Move,
	α, β int64) ([]tak.Move, int64) {
	over, _ := p.GameOver()
	if depth == 0 || over {
		ai.st.evaluated++
		return nil, ai.evaluate(p)
	}

	if p.MoveNumber() < 2 {
		for _, c := range [][]int{{0, 0}, {p.Size() - 1, 0}, {0, p.Size() - 1}, {p.Size() - 1, p.Size() - 1}} {
			x, y := c[0], c[1]
			if len(p.At(x, y)) == 0 {
				return []tak.Move{{X: x, Y: y, Type: tak.PlaceFlat}}, 0
			}
		}
	}
	moves := p.AllMoves()
	ai.st.generated += uint64(len(moves))
	if depth == ai.depth {
		for i := len(moves) - 1; i > 0; i-- {
			j := ai.rand.Int31n(int32(i))
			moves[j], moves[i] = moves[i], moves[j]
		}
	}
	if len(pv) > 0 {
		for i, m := range moves {
			if m.Equal(&pv[0]) {
				moves[0], moves[i] = moves[i], moves[0]
				break
			}
		}
	}

	best := make([]tak.Move, 0, depth)
	max := minEval - 1
	for _, m := range moves {
		child, e := p.Move(&m)
		if e != nil {
			continue
		}
		var ms []tak.Move
		var v int64
		if len(best) == 0 {
			ms, v = ai.minimax(child, depth-1, nil, -β, -α)
		} else {
			ms, v = ai.minimax(child, depth-1, best[1:], -β, -α)
		}
		v = -v
		if v > max {
			max = v
			best = append(best[:0], m)
			best = append(best, ms...)
		}
		if v > α {
			α = v
			if α >= β {
				ai.st.cutoffs++
				break
			}
		}
	}
	return best, max
}

func imin(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func imax(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func iabs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

const (
	weightFlat       = 200
	weightCaptured   = 100
	weightControlled = 500
	weightCapstone   = -50
	weightThreat     = 150
	weightAdvantage  = 50
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	analysis := p.Analysis()
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			addw(sq[0].Color(), weightControlled)
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}

			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}
	for _, r := range m.regions {
		w := bitboard.Popcount(analysis.White & r)
		b := bitboard.Popcount(analysis.Black & r)
		if w > b {
			addw(tak.White, (w-b)*weightAdvantage)
		} else {
			addw(tak.Black, (b-w)*weightAdvantage)
		}
	}
	o := analysis.White | analysis.Black
	addw(tak.White, weightThreat*m.threats(analysis.WhiteGroups, o))
	addw(tak.Black, weightThreat*m.threats(analysis.BlackGroups, o))

	return int64(mine - theirs)
}

func (m *MinimaxAI) threats(groups []uint64, filled uint64) int {
	count := 0
	empty := ^filled
	s := m.size
	for _, g := range groups {
		if g&m.c.L != 0 {
			if g&(m.c.R<<1) != 0 && empty&m.c.R != 0 {
				count++
			}
		}
		if g&m.c.R != 0 {
			if g&(m.c.L>>1) != 0 && empty&m.c.L != 0 {
				count++
			}
		}
		if g&m.c.B != 0 {
			if g&(m.c.T>>s) != 0 && empty&m.c.T != 0 {
				count++
			}
		}
		if g&m.c.T != 0 {
			if g&(m.c.B<<s) != 0 && empty&m.c.B != 0 {
				count++
			}
		}
	}
	return count
}

func (m *MinimaxAI) precompute() {
	m.c = bitboard.Precompute(m.size)
	if m.size == 5 { // TODO(board-size)
		br := uint64((1 << 3) - 1)
		br |= br<<m.size | br<<(2*m.size)
		m.regions = []uint64{
			br, br << 2,
			br << (2 * m.size), br << (2*m.size + 2),
		}
		m.rd = 2
	}
}

func NewMinimax(size int, depth int) *MinimaxAI {
	m := &MinimaxAI{size: uint(size), depth: depth}
	m.precompute()
	return m
}
<commit_msg>increase the capstone penalty<commit_after>package ai

import (
	"bytes"
	"log"
	"math/rand"
	"time"

	"github.com/nelhage/taktician/bitboard"
	"github.com/nelhage/taktician/ptn"
	"github.com/nelhage/taktician/tak"
)

const (
	maxEval      int64 = 1 << 30
	minEval            = -maxEval
	winThreshold       = 1 << 29
)

type MinimaxAI struct {
	depth int
	size  uint
	rand  *rand.Rand

	Debug bool

	st      stats
	c       bitboard.Constants
	regions []uint64
	rd      int
}

type stats struct {
	generated uint64
	evaluated uint64
	cutoffs   uint64
}

func formatpv(ms []tak.Move) string {
	var out bytes.Buffer
	out.WriteString("[")
	for i, m := range ms {
		if i != 0 {
			out.WriteString(" ")
		}
		out.WriteString(ptn.FormatMove(&m))
	}
	out.WriteString("]")
	return out.String()
}

func (m *MinimaxAI) GetMove(p *tak.Position, limit time.Duration) tak.Move {
	ms, _ := m.Analyze(p, limit)
	return ms[0]
}

func (m *MinimaxAI) Analyze(p *tak.Position, limit time.Duration) ([]tak.Move, int64) {
	if m.size != uint(p.Size()) {
		panic("Analyze: wrong size")
	}
	seed := time.Now().Unix()
	m.rand = rand.New(rand.NewSource(seed))
	if m.Debug {
		log.Printf("seed=%d", seed)
	}

	var ms []tak.Move
	var v int64
	top := time.Now()
	var prevEval uint64
	var branchSum uint64
	for i := 1; i <= m.depth; i++ {
		m.st = stats{}
		start := time.Now()
		ms, v = m.minimax(p, i, ms, minEval-1, maxEval+1)
		timeUsed := time.Now().Sub(top)
		timeMove := time.Now().Sub(start)
		if m.Debug {
			log.Printf("[minimax] depth=%d val=%d pv=%s time=%s total=%s evaluated=%d branch=%d",
				i, v, formatpv(ms),
				timeMove,
				timeUsed,
				m.st.evaluated,
				m.st.evaluated/(prevEval+1),
			)
		}
		if i > 1 {
			branchSum += m.st.evaluated / (prevEval + 1)
		}
		prevEval = m.st.evaluated
		if v > winThreshold || v < -winThreshold {
			break
		}
		if i > 2 {
			estimate := timeUsed + time.Now().Sub(start)*time.Duration(branchSum/uint64(i-1))
			if estimate > limit {
				if m.Debug {
					log.Printf("time cutoff depth=%d used=%s estimate=%s",
						i, timeUsed, estimate)
				}
				break
			}
		}
	}
	return ms, v
}

func (ai *MinimaxAI) minimax(
	p *tak.Position,
	depth int,
	pv []tak.Move,
	α, β int64) ([]tak.Move, int64) {
	over, _ := p.GameOver()
	if depth == 0 || over {
		ai.st.evaluated++
		return nil, ai.evaluate(p)
	}

	if p.MoveNumber() < 2 {
		for _, c := range [][]int{{0, 0}, {p.Size() - 1, 0}, {0, p.Size() - 1}, {p.Size() - 1, p.Size() - 1}} {
			x, y := c[0], c[1]
			if len(p.At(x, y)) == 0 {
				return []tak.Move{{X: x, Y: y, Type: tak.PlaceFlat}}, 0
			}
		}
	}
	moves := p.AllMoves()
	ai.st.generated += uint64(len(moves))
	if depth == ai.depth {
		for i := len(moves) - 1; i > 0; i-- {
			j := ai.rand.Int31n(int32(i))
			moves[j], moves[i] = moves[i], moves[j]
		}
	}
	if len(pv) > 0 {
		for i, m := range moves {
			if m.Equal(&pv[0]) {
				moves[0], moves[i] = moves[i], moves[0]
				break
			}
		}
	}

	best := make([]tak.Move, 0, depth)
	max := minEval - 1
	for _, m := range moves {
		child, e := p.Move(&m)
		if e != nil {
			continue
		}
		var ms []tak.Move
		var v int64
		if len(best) == 0 {
			ms, v = ai.minimax(child, depth-1, nil, -β, -α)
		} else {
			ms, v = ai.minimax(child, depth-1, best[1:], -β, -α)
		}
		v = -v
		if v > max {
			max = v
			best = append(best[:0], m)
			best = append(best, ms...)
		}
		if v > α {
			α = v
			if α >= β {
				ai.st.cutoffs++
				break
			}
		}
	}
	return best, max
}

func imin(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func imax(a, b int) int {
	if a > b {
		return a
	}
	return b
}

func iabs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

const (
	weightFlat       = 200
	weightCaptured   = 100
	weightControlled = 500
	weightCapstone   = -150
	weightThreat     = 150
	weightAdvantage  = 50
)

func (m *MinimaxAI) evaluate(p *tak.Position) int64 {
	if over, winner := p.GameOver(); over {
		switch winner {
		case tak.NoColor:
			return 0
		case p.ToMove():
			return maxEval - int64(p.MoveNumber())
		default:
			return minEval + int64(p.MoveNumber())
		}
	}
	mine, theirs := 0, 0
	me := p.ToMove()
	addw := func(c tak.Color, w int) {
		if c == me {
			mine += w
		} else {
			theirs += w
		}
	}
	analysis := p.Analysis()
	for x := 0; x < p.Size(); x++ {
		for y := 0; y < p.Size(); y++ {
			sq := p.At(x, y)
			if len(sq) == 0 {
				continue
			}
			addw(sq[0].Color(), weightControlled)
			if sq[0].Kind() == tak.Capstone {
				addw(sq[0].Color(), weightCapstone)
			}

			for i, stone := range sq {
				if i > 0 && i < p.Size() {
					addw(sq[0].Color(), weightCaptured)
				}
				if stone.Kind() == tak.Flat {
					addw(stone.Color(), weightFlat)
				}
			}
		}
	}
	for _, r := range m.regions {
		w := bitboard.Popcount(analysis.White & r)
		b := bitboard.Popcount(analysis.Black & r)
		if w > b {
			addw(tak.White, (w-b)*weightAdvantage)
		} else {
			addw(tak.Black, (b-w)*weightAdvantage)
		}
	}
	o := analysis.White | analysis.Black
	addw(tak.White, weightThreat*m.threats(analysis.WhiteGroups, o))
	addw(tak.Black, weightThreat*m.threats(analysis.BlackGroups, o))

	return int64(mine - theirs)
}

func (m *MinimaxAI) threats(groups []uint64, filled uint64) int {
	count := 0
	empty := ^filled
	s := m.size
	for _, g := range groups {
		if g&m.c.L != 0 {
			if g&(m.c.R<<1) != 0 && empty&m.c.R != 0 {
				count++
			}
		}
		if g&m.c.R != 0 {
			if g&(m.c.L>>1) != 0 && empty&m.c.L != 0 {
				count++
			}
		}
		if g&m.c.B != 0 {
			if g&(m.c.T>>s) != 0 && empty&m.c.T != 0 {
				count++
			}
		}
		if g&m.c.T != 0 {
			if g&(m.c.B<<s) != 0 && empty&m.c.B != 0 {
				count++
			}
		}
	}
	return count
}

func (m *MinimaxAI) precompute() {
	m.c = bitboard.Precompute(m.size)
	if m.size == 5 { // TODO(board-size)
		br := uint64((1 << 3) - 1)
		br |= br<<m.size | br<<(2*m.size)
		m.regions = []uint64{
			br, br << 2,
			br << (2 * m.size), br << (2*m.size + 2),
		}
		m.rd = 2
	}
}

func NewMinimax(size int, depth int) *MinimaxAI {
	m := &MinimaxAI{size: uint(size), depth: depth}
	m.precompute()
	return m
}
<|endoftext|>


<commit_before>// 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 netchan

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Import

// impLog is a logging convenience function.  The first argument must be a string.
func impLog(args ...interface{}) {
	args[0] = "netchan import: " + args[0].(string)
	log.Print(args...)
}

// An Importer allows a set of channels to be imported from a single
// remote machine/network port.  A machine may have multiple
// importers, even from the same machine/network port.
type Importer struct {
	*encDec
	conn     net.Conn
	chanLock sync.Mutex // protects access to channel map
	names    map[string]*netChan
	chans    map[int]*netChan
	errors   chan os.Error
	maxId    int
}

// NewImporter creates a new Importer object to import channels
// from an Exporter at the network and remote address as defined in net.Dial.
// The Exporter must be available and serving when the Importer is
// created.
func NewImporter(network, remoteaddr string) (*Importer, os.Error) {
	conn, err := net.Dial(network, "", remoteaddr)
	if err != nil {
		return nil, err
	}
	imp := new(Importer)
	imp.encDec = newEncDec(conn)
	imp.conn = conn
	imp.chans = make(map[int]*netChan)
	imp.names = make(map[string]*netChan)
	imp.errors = make(chan os.Error, 10)
	go imp.run()
	return imp, nil
}

// shutdown closes all channels for which we are receiving data from the remote side.
func (imp *Importer) shutdown() {
	imp.chanLock.Lock()
	for _, ich := range imp.chans {
		if ich.dir == Recv {
			ich.close()
		}
	}
	imp.chanLock.Unlock()
}

// Handle the data from a single imported data stream, which will
// have the form
//	(response, data)*
// The response identifies by name which channel is transmitting data.
func (imp *Importer) run() {
	// Loop on responses; requests are sent by ImportNValues()
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	ackHdr := new(header)
	err := new(error)
	errValue := reflect.NewValue(err)
	for {
		*hdr = header{}
		if e := imp.decode(hdrValue); e != nil {
			impLog("header:", e)
			imp.shutdown()
			return
		}
		switch hdr.PayloadType {
		case payData:
			// done lower in loop
		case payError:
			if e := imp.decode(errValue); e != nil {
				impLog("error:", e)
				return
			}
			if err.Error != "" {
				impLog("response error:", err.Error)
				if sent := imp.errors <- os.ErrorString(err.Error); !sent {
					imp.shutdown()
					return
				}
				continue // errors are not acknowledged.
			}
		case payClosed:
			nch := imp.getChan(hdr.Id, false)
			if nch != nil {
				nch.close()
			}
			continue // closes are not acknowledged.
		case payAckSend:
			// we can receive spurious acks if the channel is
			// hung up, so we ask getChan to ignore any errors.
			nch := imp.getChan(hdr.Id, true)
			if nch != nil {
				nch.acked()
			}
			continue
		default:
			impLog("unexpected payload type:", hdr.PayloadType)
			return
		}
		nch := imp.getChan(hdr.Id, false)
		if nch == nil {
			continue
		}
		if nch.dir != Recv {
			impLog("cannot happen: receive from non-Recv channel")
			return
		}
		// Acknowledge receipt
		ackHdr.Id = hdr.Id
		ackHdr.SeqNum = hdr.SeqNum
		imp.encode(ackHdr, payAck, nil)
		// Create a new value for each received item.
		value := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
		if e := imp.decode(value); e != nil {
			impLog("importer value decode:", e)
			return
		}
		nch.send(value)
	}
}

func (imp *Importer) getChan(id int, errOk bool) *netChan {
	imp.chanLock.Lock()
	ich := imp.chans[id]
	imp.chanLock.Unlock()
	if ich == nil {
		if !errOk {
			impLog("unknown id in netchan request: ", id)
		}
		return nil
	}
	return ich
}

// Errors returns a channel from which transmission and protocol errors
// can be read. Clients of the importer are not required to read the error
// channel for correct execution. However, if too many errors occur
// without being read from the error channel, the importer will shut down.
func (imp *Importer) Errors() chan os.Error {
	return imp.errors
}

// Import imports a channel of the given type, size and specified direction.
// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error {
	return imp.ImportNValues(name, chT, dir, size, -1)
}

// ImportNValues imports a channel of the given type and specified
// direction and then receives or transmits up to n values on that
// channel.  A value of n==-1 implies an unbounded number of values.  The
// channel will have buffer space for size values, or 1 value if size < 1.
// The channel to be bound to the remote site's channel is provided
// in the call and may be of arbitrary channel type.
// Despite the literal signature, the effective signature is
//	ImportNValues(name string, chT chan T, dir Dir, n int) os.Error
// Example usage:
//	imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
//	if err != nil { log.Exit(err) }
//	ch := make(chan myType)
//	err = imp.ImportNValues("name", ch, Recv, 1)
//	if err != nil { log.Exit(err) }
//	fmt.Printf("%+v\n", <-ch)
func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	imp.chanLock.Lock()
	defer imp.chanLock.Unlock()
	_, present := imp.names[name]
	if present {
		return os.ErrorString("channel name already being imported:" + name)
	}
	if size < 1 {
		size = 1
	}
	id := imp.maxId
	imp.maxId++
	nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n))
	imp.names[name] = nch
	imp.chans[id] = nch
	// Tell the other side about this channel.
	hdr := &header{Id: id}
	req := &request{Name: name, Count: int64(n), Dir: dir, Size: size}
	if err = imp.encode(hdr, payRequest, req); err != nil {
		impLog("request encode:", err)
		return err
	}
	if dir == Send {
		go func() {
			for i := 0; n == -1 || i < n; i++ {
				val, closed := nch.recv()
				if closed {
					if err = imp.encode(hdr, payClosed, nil); err != nil {
						impLog("error encoding client closed message:", err)
					}
					return
				}
				if err = imp.encode(hdr, payData, val.Interface()); err != nil {
					impLog("error encoding client send:", err)
					return
				}
			}
		}()
	}
	return nil
}

// Hangup disassociates the named channel from the Importer and closes
// the channel.  Messages in flight for the channel may be dropped.
func (imp *Importer) Hangup(name string) os.Error {
	imp.chanLock.Lock()
	nc, ok := imp.names[name]
	if ok {
		imp.names[name] = nil, false
		imp.chans[nc.id] = nil, false
	}
	imp.chanLock.Unlock()
	if !ok {
		return os.ErrorString("netchan import: hangup: no such channel: " + name)
	}
	nc.close()
	return nil
}
<commit_msg>Fixed documentation for netchan import()<commit_after>// 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 netchan

import (
	"log"
	"net"
	"os"
	"reflect"
	"sync"
)

// Import

// impLog is a logging convenience function.  The first argument must be a string.
func impLog(args ...interface{}) {
	args[0] = "netchan import: " + args[0].(string)
	log.Print(args...)
}

// An Importer allows a set of channels to be imported from a single
// remote machine/network port.  A machine may have multiple
// importers, even from the same machine/network port.
type Importer struct {
	*encDec
	conn     net.Conn
	chanLock sync.Mutex // protects access to channel map
	names    map[string]*netChan
	chans    map[int]*netChan
	errors   chan os.Error
	maxId    int
}

// NewImporter creates a new Importer object to import channels
// from an Exporter at the network and remote address as defined in net.Dial.
// The Exporter must be available and serving when the Importer is
// created.
func NewImporter(network, remoteaddr string) (*Importer, os.Error) {
	conn, err := net.Dial(network, "", remoteaddr)
	if err != nil {
		return nil, err
	}
	imp := new(Importer)
	imp.encDec = newEncDec(conn)
	imp.conn = conn
	imp.chans = make(map[int]*netChan)
	imp.names = make(map[string]*netChan)
	imp.errors = make(chan os.Error, 10)
	go imp.run()
	return imp, nil
}

// shutdown closes all channels for which we are receiving data from the remote side.
func (imp *Importer) shutdown() {
	imp.chanLock.Lock()
	for _, ich := range imp.chans {
		if ich.dir == Recv {
			ich.close()
		}
	}
	imp.chanLock.Unlock()
}

// Handle the data from a single imported data stream, which will
// have the form
//	(response, data)*
// The response identifies by name which channel is transmitting data.
func (imp *Importer) run() {
	// Loop on responses; requests are sent by ImportNValues()
	hdr := new(header)
	hdrValue := reflect.NewValue(hdr)
	ackHdr := new(header)
	err := new(error)
	errValue := reflect.NewValue(err)
	for {
		*hdr = header{}
		if e := imp.decode(hdrValue); e != nil {
			impLog("header:", e)
			imp.shutdown()
			return
		}
		switch hdr.PayloadType {
		case payData:
			// done lower in loop
		case payError:
			if e := imp.decode(errValue); e != nil {
				impLog("error:", e)
				return
			}
			if err.Error != "" {
				impLog("response error:", err.Error)
				if sent := imp.errors <- os.ErrorString(err.Error); !sent {
					imp.shutdown()
					return
				}
				continue // errors are not acknowledged.
			}
		case payClosed:
			nch := imp.getChan(hdr.Id, false)
			if nch != nil {
				nch.close()
			}
			continue // closes are not acknowledged.
		case payAckSend:
			// we can receive spurious acks if the channel is
			// hung up, so we ask getChan to ignore any errors.
			nch := imp.getChan(hdr.Id, true)
			if nch != nil {
				nch.acked()
			}
			continue
		default:
			impLog("unexpected payload type:", hdr.PayloadType)
			return
		}
		nch := imp.getChan(hdr.Id, false)
		if nch == nil {
			continue
		}
		if nch.dir != Recv {
			impLog("cannot happen: receive from non-Recv channel")
			return
		}
		// Acknowledge receipt
		ackHdr.Id = hdr.Id
		ackHdr.SeqNum = hdr.SeqNum
		imp.encode(ackHdr, payAck, nil)
		// Create a new value for each received item.
		value := reflect.MakeZero(nch.ch.Type().(*reflect.ChanType).Elem())
		if e := imp.decode(value); e != nil {
			impLog("importer value decode:", e)
			return
		}
		nch.send(value)
	}
}

func (imp *Importer) getChan(id int, errOk bool) *netChan {
	imp.chanLock.Lock()
	ich := imp.chans[id]
	imp.chanLock.Unlock()
	if ich == nil {
		if !errOk {
			impLog("unknown id in netchan request: ", id)
		}
		return nil
	}
	return ich
}

// Errors returns a channel from which transmission and protocol errors
// can be read. Clients of the importer are not required to read the error
// channel for correct execution. However, if too many errors occur
// without being read from the error channel, the importer will shut down.
func (imp *Importer) Errors() chan os.Error {
	return imp.errors
}

// Import imports a channel of the given type, size and specified direction.
// It is equivalent to ImportNValues with a count of -1, meaning unbounded.
func (imp *Importer) Import(name string, chT interface{}, dir Dir, size int) os.Error {
	return imp.ImportNValues(name, chT, dir, size, -1)
}

// ImportNValues imports a channel of the given type and specified
// direction and then receives or transmits up to n values on that
// channel.  A value of n==-1 implies an unbounded number of values.  The
// channel will have buffer space for size values, or 1 value if size < 1.
// The channel to be bound to the remote site's channel is provided
// in the call and may be of arbitrary channel type.
// Despite the literal signature, the effective signature is
//	ImportNValues(name string, chT chan T, dir Dir, size, n int) os.Error
// Example usage:
//	imp, err := NewImporter("tcp", "netchanserver.mydomain.com:1234")
//	if err != nil { log.Exit(err) }
//	ch := make(chan myType)
//	err = imp.ImportNValues("name", ch, Recv, 1, 1)
//	if err != nil { log.Exit(err) }
//	fmt.Printf("%+v\n", <-ch)
func (imp *Importer) ImportNValues(name string, chT interface{}, dir Dir, size, n int) os.Error {
	ch, err := checkChan(chT, dir)
	if err != nil {
		return err
	}
	imp.chanLock.Lock()
	defer imp.chanLock.Unlock()
	_, present := imp.names[name]
	if present {
		return os.ErrorString("channel name already being imported:" + name)
	}
	if size < 1 {
		size = 1
	}
	id := imp.maxId
	imp.maxId++
	nch := newNetChan(name, id, &chanDir{ch, dir}, imp.encDec, size, int64(n))
	imp.names[name] = nch
	imp.chans[id] = nch
	// Tell the other side about this channel.
	hdr := &header{Id: id}
	req := &request{Name: name, Count: int64(n), Dir: dir, Size: size}
	if err = imp.encode(hdr, payRequest, req); err != nil {
		impLog("request encode:", err)
		return err
	}
	if dir == Send {
		go func() {
			for i := 0; n == -1 || i < n; i++ {
				val, closed := nch.recv()
				if closed {
					if err = imp.encode(hdr, payClosed, nil); err != nil {
						impLog("error encoding client closed message:", err)
					}
					return
				}
				if err = imp.encode(hdr, payData, val.Interface()); err != nil {
					impLog("error encoding client send:", err)
					return
				}
			}
		}()
	}
	return nil
}

// Hangup disassociates the named channel from the Importer and closes
// the channel.  Messages in flight for the channel may be dropped.
func (imp *Importer) Hangup(name string) os.Error {
	imp.chanLock.Lock()
	nc, ok := imp.names[name]
	if ok {
		imp.names[name] = nil, false
		imp.chans[nc.id] = nil, false
	}
	imp.chanLock.Unlock()
	if !ok {
		return os.ErrorString("netchan import: hangup: no such channel: " + name)
	}
	nc.close()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/hawx/alexandria/data"
	"github.com/hawx/alexandria/web/assets"
	"github.com/hawx/alexandria/web/events"
	"github.com/hawx/alexandria/web/filters"
	"github.com/hawx/alexandria/web/handlers"
	"github.com/hawx/alexandria/web/persona"

	"github.com/BurntSushi/toml"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"

	"flag"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
)

var (
	settingsPath = flag.String("settings", "./settings.toml", "")
	port         = flag.String("port", "8080", "")
	socket       = flag.String("socket", "", "")
)

func main() {
	flag.Parse()

	var conf struct {
		Users     []string
		Secret    string
		Audience  string
		DbPath    string `toml:"database"`
		BooksPath string `toml:"library"`
	}
	if _, err := toml.DecodeFile(*settingsPath, &conf); err != nil {
		log.Fatal("toml:", err)
	}

	store := persona.NewStore(conf.Secret)
	persona := persona.New(store, conf.Audience, conf.Users)

	db := data.Open(conf.DbPath)
	defer db.Close()

	es := events.New()
	defer es.Close()

	r := mux.NewRouter()

	r.Path("/").Methods("GET").Handler(persona.Switch(handlers.List(true), handlers.List(false)))

	booksHandler := handlers.Books(db, es)
	r.Path("/books").Methods("GET").Handler(persona.Protect(booksHandler.GetAll))
	r.Path("/books/{id}").Methods("GET").Handler(persona.Protect(booksHandler.Get))
	r.Path("/books/{id}").Methods("PATCH").Handler(persona.Protect(booksHandler.Update))
	r.Path("/books/{id}").Methods("DELETE").Handler(persona.Protect(booksHandler.Delete))

	editionsHandler := handlers.Editions(db)
	r.Path("/editions/{id}").Methods("GET").Handler(persona.Protect(editionsHandler.Get))

	uploadHandler := handlers.Upload(db, es, conf.BooksPath)
	r.Path("/upload").Methods("POST").Handler(persona.Protect(uploadHandler.Upload))

	r.Path("/sign-in").Methods("POST").Handler(persona.SignIn)
	r.Path("/sign-out").Methods("GET").Handler(persona.SignOut)

	http.Handle("/", r)
	http.Handle("/events", es)
	http.Handle("/assets/", http.StripPrefix("/assets/", assets.Server(map[string]string{
		"main.js":        assets.MainJs,
		"mustache.js":    assets.MustacheJs,
		"tablesorter.js": assets.TablesorterJs,
		"tablefilter.js": assets.TablefilterJs,
		"styles.css":     assets.StylesCss,
	})))

	if *socket == "" {
		go func() {
			log.Print("listening on :" + *port)
			log.Fatal(http.ListenAndServe(":"+*port, context.ClearHandler(filters.Log(http.DefaultServeMux))))
		}()

	} else {
		l, err := net.Listen("unix", *socket)
		if err != nil {
			log.Fatal(err)
		}

		defer l.Close()

		go func() {
			log.Println("listening on", *socket)
			log.Fatal(http.Serve(l, context.ClearHandler(filters.Log(http.DefaultServeMux))))
		}()
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	s := <-c
	log.Printf("caught %s: shutting down", s)
}
<commit_msg>ExtractVariable<commit_after>package main

import (
	"github.com/hawx/alexandria/data"
	"github.com/hawx/alexandria/web/assets"
	"github.com/hawx/alexandria/web/events"
	"github.com/hawx/alexandria/web/filters"
	"github.com/hawx/alexandria/web/handlers"
	"github.com/hawx/alexandria/web/persona"

	"github.com/BurntSushi/toml"
	"github.com/gorilla/context"
	"github.com/gorilla/mux"

	"flag"
	"log"
	"net"
	"net/http"
	"os"
	"os/signal"
)

var (
	settingsPath = flag.String("settings", "./settings.toml", "")
	port         = flag.String("port", "8080", "")
	socket       = flag.String("socket", "", "")
)

func main() {
	flag.Parse()

	var conf struct {
		Users     []string
		Secret    string
		Audience  string
		DbPath    string `toml:"database"`
		BooksPath string `toml:"library"`
	}
	if _, err := toml.DecodeFile(*settingsPath, &conf); err != nil {
		log.Fatal("toml:", err)
	}

	store := persona.NewStore(conf.Secret)
	persona := persona.New(store, conf.Audience, conf.Users)

	db := data.Open(conf.DbPath)
	defer db.Close()

	es := events.New()
	defer es.Close()

	r := mux.NewRouter()

	r.Path("/").Methods("GET").Handler(persona.Switch(handlers.List(true), handlers.List(false)))

	booksHandler := handlers.Books(db, es)
	r.Path("/books").Methods("GET").Handler(persona.Protect(booksHandler.GetAll))
	r.Path("/books/{id}").Methods("GET").Handler(persona.Protect(booksHandler.Get))
	r.Path("/books/{id}").Methods("PATCH").Handler(persona.Protect(booksHandler.Update))
	r.Path("/books/{id}").Methods("DELETE").Handler(persona.Protect(booksHandler.Delete))

	editionsHandler := handlers.Editions(db)
	r.Path("/editions/{id}").Methods("GET").Handler(persona.Protect(editionsHandler.Get))

	uploadHandler := handlers.Upload(db, es, conf.BooksPath)
	r.Path("/upload").Methods("POST").Handler(persona.Protect(uploadHandler.Upload))

	r.Path("/sign-in").Methods("POST").Handler(persona.SignIn)
	r.Path("/sign-out").Methods("GET").Handler(persona.SignOut)

	http.Handle("/", r)
	http.Handle("/events", es)
	http.Handle("/assets/", http.StripPrefix("/assets/", assets.Server(map[string]string{
		"main.js":        assets.MainJs,
		"mustache.js":    assets.MustacheJs,
		"tablesorter.js": assets.TablesorterJs,
		"tablefilter.js": assets.TablefilterJs,
		"styles.css":     assets.StylesCss,
	})))

	mux := context.ClearHandler(filters.Log(http.DefaultServeMux))
	if *socket == "" {
		go func() {
			log.Print("listening on :" + *port)
			log.Fatal(http.ListenAndServe(":"+*port, mux))
		}()

	} else {
		l, err := net.Listen("unix", *socket)
		if err != nil {
			log.Fatal(err)
		}

		defer l.Close()

		go func() {
			log.Println("listening on", *socket)
			log.Fatal(http.Serve(l, mux))
		}()
	}

	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt, os.Kill)

	s := <-c
	log.Printf("caught %s: shutting down", s)
}
<|endoftext|>


<commit_before>package ccgen

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"go/format"
	"os"
	"strings"
	"text/template"

	"golang.org/x/tools/imports"
)

type Generator struct {
	zwClasses *ZwClasses
	tpl       *template.Template
}

func NewGenerator() (*Generator, error) {
	gen := &Generator{}

	if err := gen.initTemplates(); err != nil {
		return nil, err
	}

	fp, err := os.Open("ccgen/zwave-defs.xml")
	if err != nil {
		return nil, err
	}

	decoder := xml.NewDecoder(fp)

	zw := ZwClasses{}
	err = decoder.Decode(&zw)
	if err != nil {
		return nil, err
	}

	gen.zwClasses = &zw

	return gen, nil
}

func (g *Generator) GenDevices() (string, error) {
	buf := bytes.NewBuffer([]byte{})
	err := g.tpl.ExecuteTemplate(buf, "devices.tpl", g.zwClasses)
	if err != nil {
		return "", err
	}

	return string(buf.Bytes()), nil
}

func (g *Generator) GenCommandClasses() (string, error) {
	buf := bytes.NewBuffer([]byte{})

	for _, cc := range g.zwClasses.CommandClasses {
		// fmt.Println(cc.Name)
		buf := bytes.NewBuffer([]byte{})
		err := g.tpl.ExecuteTemplate(buf, "commandClass.tpl", cc)
		if err != nil {
			panic(err)
			return "", err
		}

		dirName := "zwave/command-class/" + cc.GetPackageName()
		filename := dirName + "/" + cc.GetPackageName() + ".go"
		os.Mkdir(dirName, 0775)
		fp, err := os.Create(filename)
		if err != nil {
			panic(err)
		}

		formatted, err := format.Source(buf.Bytes())
		if err != nil {
			fmt.Println(string(buf.Bytes()))
			fmt.Println(cc.Name)
			panic(err)
		}

		imported, err := imports.Process(filename, formatted, nil)
		if err != nil {
			fmt.Println(cc.Name)
			panic(err)
		}

		fp.Write(imported)
		fp.Close()
	}

	return string(buf.Bytes()), nil
}

func (g *Generator) initTemplates() error {
	funcs := template.FuncMap{
		"ToGoName":    toGoName,
		"NotZeroByte": notZeroByte,
		"Trim":        strings.TrimSpace,
	}

	tpl, err := template.New("").Funcs(funcs).ParseGlob("ccgen/templates/*.tpl")
	if err != nil {
		return err
	}

	g.tpl = tpl

	return nil
}
<commit_msg>Skip generation of ZWAVE_CMD_CLASS<commit_after>package ccgen

import (
	"bytes"
	"encoding/xml"
	"fmt"
	"go/format"
	"os"
	"strings"
	"text/template"

	"golang.org/x/tools/imports"
)

type Generator struct {
	zwClasses *ZwClasses
	tpl       *template.Template
}

func NewGenerator() (*Generator, error) {
	gen := &Generator{}

	if err := gen.initTemplates(); err != nil {
		return nil, err
	}

	fp, err := os.Open("ccgen/zwave-defs.xml")
	if err != nil {
		return nil, err
	}

	decoder := xml.NewDecoder(fp)

	zw := ZwClasses{}
	err = decoder.Decode(&zw)
	if err != nil {
		return nil, err
	}

	gen.zwClasses = &zw

	return gen, nil
}

func (g *Generator) GenDevices() (string, error) {
	buf := bytes.NewBuffer([]byte{})
	err := g.tpl.ExecuteTemplate(buf, "devices.tpl", g.zwClasses)
	if err != nil {
		return "", err
	}

	return string(buf.Bytes()), nil
}

func (g *Generator) GenCommandClasses() (string, error) {
	buf := bytes.NewBuffer([]byte{})

	for _, cc := range g.zwClasses.CommandClasses {
		if cc.Name == "ZWAVE_CMD_CLASS" {
			continue
		}

		// fmt.Println(cc.Name)
		buf := bytes.NewBuffer([]byte{})
		err := g.tpl.ExecuteTemplate(buf, "commandClass.tpl", cc)
		if err != nil {
			panic(err)
			return "", err
		}

		dirName := "zwave/command-class/" + cc.GetPackageName()
		filename := dirName + "/" + cc.GetPackageName() + ".go"
		os.Mkdir(dirName, 0775)
		fp, err := os.Create(filename)
		if err != nil {
			panic(err)
		}

		formatted, err := format.Source(buf.Bytes())
		if err != nil {
			fmt.Println(string(buf.Bytes()))
			fmt.Println(cc.Name)
			panic(err)
		}

		imported, err := imports.Process(filename, formatted, nil)
		if err != nil {
			fmt.Println(cc.Name)
			panic(err)
		}

		fp.Write(imported)
		fp.Close()
	}

	return string(buf.Bytes()), nil
}

func (g *Generator) initTemplates() error {
	funcs := template.FuncMap{
		"ToGoName":    toGoName,
		"NotZeroByte": notZeroByte,
		"Trim":        strings.TrimSpace,
	}

	tpl, err := template.New("").Funcs(funcs).ParseGlob("ccgen/templates/*.tpl")
	if err != nil {
		return err
	}

	g.tpl = tpl

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2011 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 sync

import (
	"sync/atomic"
	"unsafe"
)

// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for.  Then each of the goroutines
// runs and calls Done when finished.  At the same time,
// Wait can be used to block until all goroutines have finished.
type WaitGroup struct {
	m       Mutex
	counter int32
	waiters int32
	sema    *uint32
}

// WaitGroup creates a new semaphore each time the old semaphore
// is released. This is to avoid the following race:
//
// G1: Add(1)
// G1: go G2()
// G1: Wait() // Context switch after Unlock() and before Semacquire().
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
// G3: Add(1) // Makes counter == 1, waiters == 0.
// G3: go G4()
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.

// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait are released.
// If the counter goes negative, Add panics.
//
// Note that calls with positive delta must happen before the call to Wait,
// or else Wait may wait for too small a group. Typically this means the calls
// to Add should execute before the statement creating the goroutine or
// other event to be waited for. See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {
	if raceenabled {
		_ = wg.m.state // trigger nil deref early
		if delta < 0 {
			// Synchronize decrements with Wait.
			raceReleaseMerge(unsafe.Pointer(wg))
		}
		raceDisable()
		defer raceEnable()
	}
	v := atomic.AddInt32(&wg.counter, int32(delta))
	if raceenabled {
		if delta > 0 && v == int32(delta) {
			// The first increment must be synchronized with Wait.
			// Need to model this as a read, because there can be
			// several concurrent wg.counter transitions from 0.
			raceRead(unsafe.Pointer(&wg.sema))
		}
	}
	if v < 0 {
		panic("sync: negative WaitGroup counter")
	}
	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
		return
	}
	wg.m.Lock()
	for i := int32(0); i < wg.waiters; i++ {
		runtime_Semrelease(wg.sema)
	}
	wg.waiters = 0
	wg.sema = nil
	wg.m.Unlock()
}

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
	wg.Add(-1)
}

// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
	if raceenabled {
		_ = wg.m.state // trigger nil deref early
		raceDisable()
	}
	if atomic.LoadInt32(&wg.counter) == 0 {
		if raceenabled {
			raceEnable()
			raceAcquire(unsafe.Pointer(wg))
		}
		return
	}
	wg.m.Lock()
	w := atomic.AddInt32(&wg.waiters, 1)
	if raceenabled && w == 1 {
		// Wait's must be synchronized with the first Add.
		// Need to model this is as a write to race with the read in Add.
		// As the consequence, can do the write only for the first waiter,
		// otherwise concurrent Wait's will race with each other.
		raceWrite(unsafe.Pointer(&wg.sema))
	}
	// This code is racing with the unlocked path in Add above.
	// The code above modifies counter and then reads waiters.
	// We must modify waiters and then read counter (the opposite order)
	// to avoid missing an Add.
	if atomic.LoadInt32(&wg.counter) == 0 {
		atomic.AddInt32(&wg.waiters, -1)
		if raceenabled {
			raceEnable()
			raceAcquire(unsafe.Pointer(wg))
			raceDisable()
		}
		wg.m.Unlock()
		if raceenabled {
			raceEnable()
		}
		return
	}
	if wg.sema == nil {
		wg.sema = new(uint32)
	}
	s := wg.sema
	wg.m.Unlock()
	runtime_Semacquire(s)
	if raceenabled {
		raceEnable()
		raceAcquire(unsafe.Pointer(wg))
	}
}
<commit_msg>sync: fix race instrumentation of WaitGroup Currently more than 1 gorutine can execute raceWrite() in Wait() in the following scenario: 1. goroutine 1 executes first check of wg.counter, sees that it's == 0 2. goroutine 2 executes first check of wg.counter, sees that it's == 0 3. goroutine 2 locks the mutex, sees that he is the first waiter and executes raceWrite() 4. goroutine 2 block on the semaphore 5. goroutine 3 executes Done() and unblocks goroutine 2 6. goroutine 1 lock the mutex, sees that he is the first waiter and executes raceWrite()<commit_after>// Copyright 2011 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 sync

import (
	"sync/atomic"
	"unsafe"
)

// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
// goroutines to wait for.  Then each of the goroutines
// runs and calls Done when finished.  At the same time,
// Wait can be used to block until all goroutines have finished.
type WaitGroup struct {
	m       Mutex
	counter int32
	waiters int32
	sema    *uint32
}

// WaitGroup creates a new semaphore each time the old semaphore
// is released. This is to avoid the following race:
//
// G1: Add(1)
// G1: go G2()
// G1: Wait() // Context switch after Unlock() and before Semacquire().
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
// G3: Add(1) // Makes counter == 1, waiters == 0.
// G3: go G4()
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.

// Add adds delta, which may be negative, to the WaitGroup counter.
// If the counter becomes zero, all goroutines blocked on Wait are released.
// If the counter goes negative, Add panics.
//
// Note that calls with positive delta must happen before the call to Wait,
// or else Wait may wait for too small a group. Typically this means the calls
// to Add should execute before the statement creating the goroutine or
// other event to be waited for. See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {
	if raceenabled {
		_ = wg.m.state // trigger nil deref early
		if delta < 0 {
			// Synchronize decrements with Wait.
			raceReleaseMerge(unsafe.Pointer(wg))
		}
		raceDisable()
		defer raceEnable()
	}
	v := atomic.AddInt32(&wg.counter, int32(delta))
	if raceenabled {
		if delta > 0 && v == int32(delta) {
			// The first increment must be synchronized with Wait.
			// Need to model this as a read, because there can be
			// several concurrent wg.counter transitions from 0.
			raceRead(unsafe.Pointer(&wg.sema))
		}
	}
	if v < 0 {
		panic("sync: negative WaitGroup counter")
	}
	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
		return
	}
	wg.m.Lock()
	for i := int32(0); i < wg.waiters; i++ {
		runtime_Semrelease(wg.sema)
	}
	wg.waiters = 0
	wg.sema = nil
	wg.m.Unlock()
}

// Done decrements the WaitGroup counter.
func (wg *WaitGroup) Done() {
	wg.Add(-1)
}

// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
	if raceenabled {
		_ = wg.m.state // trigger nil deref early
		raceDisable()
	}
	if atomic.LoadInt32(&wg.counter) == 0 {
		if raceenabled {
			raceEnable()
			raceAcquire(unsafe.Pointer(wg))
		}
		return
	}
	wg.m.Lock()
	w := atomic.AddInt32(&wg.waiters, 1)
	// This code is racing with the unlocked path in Add above.
	// The code above modifies counter and then reads waiters.
	// We must modify waiters and then read counter (the opposite order)
	// to avoid missing an Add.
	if atomic.LoadInt32(&wg.counter) == 0 {
		atomic.AddInt32(&wg.waiters, -1)
		if raceenabled {
			raceEnable()
			raceAcquire(unsafe.Pointer(wg))
			raceDisable()
		}
		wg.m.Unlock()
		if raceenabled {
			raceEnable()
		}
		return
	}
	if raceenabled && w == 1 {
		// Wait must be synchronized with the first Add.
		// Need to model this is as a write to race with the read in Add.
		// As a consequence, can do the write only for the first waiter,
		// otherwise concurrent Waits will race with each other.
		raceWrite(unsafe.Pointer(&wg.sema))
	}
	if wg.sema == nil {
		wg.sema = new(uint32)
	}
	s := wg.sema
	wg.m.Unlock()
	runtime_Semacquire(s)
	if raceenabled {
		raceEnable()
		raceAcquire(unsafe.Pointer(wg))
	}
}
<|endoftext|>


<commit_before>package gat

import (
	"fmt"
	"testing"
	"time"

	libgit "github.com/libgit2/git2go"
	. "github.com/smartystreets/goconvey/convey"

	"polydawn.net/danggit/lib/testutil"
)

func TestFetch(t *testing.T) {
	Convey("Given a local git repo", t, testutil.WithTmpdir(func() {
		repo, err := libgit.InitRepository("repo", true)
		maybePanic(err)

		Convey("and given some commits and branches", func() {
			// shove in file content
			blobOid, err := repo.CreateBlobFromBuffer([]byte("hello, world!\n"))
			maybePanic(err)

			// assemble tree
			treeBuilder, err := repo.TreeBuilder()
			maybePanic(err)
			defer treeBuilder.Free()
			treeBuilder.Insert("thefile", blobOid, libgit.FilemodeBlob)
			treeOid, err := treeBuilder.Write()
			maybePanic(err)
			// immediately look it up again because silly api
			tree, err := repo.LookupTree(treeOid)
			maybePanic(err)

			// assemble commit
			author := &libgit.Signature{
				Name:  "author",
				Email: "email@domain.wow",
				When:  time.Date(2009, 10, 14, 12, 0, 0, 0, time.UTC),
			}
			commitOid, err := repo.CreateCommit(
				"",
				author,
				author,
				"log message",
				tree,
			)
			maybePanic(err)
			// immediately look it up again because silly api
			commit, err := repo.LookupCommit(commitOid)
			maybePanic(err)

			// create branch
			branchName := "test-branch"
			branch, err := repo.CreateBranch(branchName, commit, false)
			maybePanic(err)
			branch.Free()

			remote, err := repo.Remotes.CreateAnonymous(repo.Path())
			maybePanic(err)

			remoteName := "test-remote"
			refspec := fmt.Sprintf("+refs/heads/*:refs/remotes/%s/*", remoteName)
			err = remote.Fetch([]string{refspec}, nil, "")
			maybePanic(err)

			// ref, err := repo.References.Lookup("remotes/test/master")
			expectedBranch := fmt.Sprintf("%s/%s", remoteName, branchName)
			remoteBranch, err := repo.LookupBranch(expectedBranch, libgit.BranchRemote)
			maybePanic(err)
			Convey("remote branch commit should be remote commit", func() {
				// So(ref.Target(), ShouldEqual, commitOid)
				So(remoteBranch.Reference.Target(), ShouldResemble, commitOid)
			})

			Convey("execgit believe our work", func() {
				So(
					execgit.Bake("ls-remote", "repo").Output(),
					ShouldResemble,
					fmt.Sprintf("%s\trefs/heads/%s\n%s\trefs/remotes/%s\n", commitOid, branchName, commitOid, expectedBranch),
				)
			})
		})
	}))
}
<commit_msg>remove commented code<commit_after>package gat

import (
	"fmt"
	"testing"
	"time"

	libgit "github.com/libgit2/git2go"
	. "github.com/smartystreets/goconvey/convey"

	"polydawn.net/danggit/lib/testutil"
)

func TestFetch(t *testing.T) {
	Convey("Given a local git repo", t, testutil.WithTmpdir(func() {
		repo, err := libgit.InitRepository("repo", true)
		maybePanic(err)

		Convey("and given some commits and branches", func() {
			// shove in file content
			blobOid, err := repo.CreateBlobFromBuffer([]byte("hello, world!\n"))
			maybePanic(err)

			// assemble tree
			treeBuilder, err := repo.TreeBuilder()
			maybePanic(err)
			defer treeBuilder.Free()
			treeBuilder.Insert("thefile", blobOid, libgit.FilemodeBlob)
			treeOid, err := treeBuilder.Write()
			maybePanic(err)
			// immediately look it up again because silly api
			tree, err := repo.LookupTree(treeOid)
			maybePanic(err)

			// assemble commit
			author := &libgit.Signature{
				Name:  "author",
				Email: "email@domain.wow",
				When:  time.Date(2009, 10, 14, 12, 0, 0, 0, time.UTC),
			}
			commitOid, err := repo.CreateCommit(
				"",
				author,
				author,
				"log message",
				tree,
			)
			maybePanic(err)
			// immediately look it up again because silly api
			commit, err := repo.LookupCommit(commitOid)
			maybePanic(err)

			// create branch
			branchName := "test-branch"
			branch, err := repo.CreateBranch(branchName, commit, false)
			maybePanic(err)
			branch.Free()

			remote, err := repo.Remotes.CreateAnonymous(repo.Path())
			maybePanic(err)

			remoteName := "test-remote"
			refspec := fmt.Sprintf("+refs/heads/*:refs/remotes/%s/*", remoteName)
			err = remote.Fetch([]string{refspec}, nil, "")
			maybePanic(err)

			expectedBranch := fmt.Sprintf("%s/%s", remoteName, branchName)
			remoteBranch, err := repo.LookupBranch(expectedBranch, libgit.BranchRemote)
			maybePanic(err)
			Convey("remote branch commit should be remote commit", func() {
				So(remoteBranch.Reference.Target(), ShouldResemble, commitOid)
			})

			Convey("execgit believe our work", func() {
				So(
					execgit.Bake("ls-remote", "repo").Output(),
					ShouldResemble,
					fmt.Sprintf("%s\trefs/heads/%s\n%s\trefs/remotes/%s\n", commitOid, branchName, commitOid, expectedBranch),
				)
			})
		})
	}))
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcs

import (
	"errors"
	"fmt"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"
	"time"

	"golang.org/x/net/context"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestRetry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func contentsAre(s string) Matcher {
	pred := func(c interface{}) (err error) {
		// Convert.
		req, ok := c.(*CreateObjectRequest)
		if !ok {
			err = fmt.Errorf("which has type %T", c)
			return
		}

		// Read.
		contents, err := ioutil.ReadAll(req.Contents)
		if err != nil {
			err = fmt.Errorf("whose contents cannot be read: %v", err)
			return
		}

		// Compare.
		if string(contents) != s {
			err = errors.New("whose contents don't match")
			return
		}

		return
	}

	return NewMatcher(pred, "has the specified contents")
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type retryBucketTest struct {
	ctx     context.Context
	wrapped MockBucket
	bucket  Bucket
}

func (t *retryBucketTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.wrapped = NewMockBucket(ti.MockController, "wrapped")
	t.bucket = newRetryBucket(time.Second, t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type RetryBucket_CreateObjectTest struct {
	retryBucketTest

	req CreateObjectRequest
	obj *Object
}

func init() { RegisterTestSuite(&RetryBucket_CreateObjectTest{}) }

func (t *RetryBucket_CreateObjectTest) call() (err error) {
	t.obj, err = t.bucket.CreateObject(t.ctx, &t.req)
	return
}

func (t *RetryBucket_CreateObjectTest) ErrorReading() {
	var err error

	// Pass in a reader that will return an error.
	t.req.Contents = ioutil.NopCloser(
		iotest.OneByteReader(
			iotest.TimeoutReader(
				strings.NewReader("foobar"))))

	// Call
	err = t.call()

	ExpectThat(err, Error(HasSubstr("ReadAll")))
	ExpectThat(err, Error(HasSubstr("timeout")))
}

func (t *RetryBucket_CreateObjectTest) CallsWrapped() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) Successful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := &Object{}
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}

func (t *RetryBucket_CreateObjectTest) ShouldNotRetry() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := errors.New("taco")
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, expected))

	// Call
	err = t.call()

	ExpectEq(expected, err)
}

func (t *RetryBucket_CreateObjectTest) CallsWrappedForRetry() {
	AssertTrue(false, "TODO")
}

func (t *RetryBucket_CreateObjectTest) RetrySuccessful() {
	AssertTrue(false, "TODO")
}
<commit_msg>RetryBucket_CreateObjectTest.CallsWrappedForRetry<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gcs

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strings"
	"testing"
	"testing/iotest"
	"time"

	"golang.org/x/net/context"

	. "github.com/jacobsa/oglematchers"
	. "github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
)

func TestRetry(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

func contentsAre(s string) Matcher {
	pred := func(c interface{}) (err error) {
		// Convert.
		req, ok := c.(*CreateObjectRequest)
		if !ok {
			err = fmt.Errorf("which has type %T", c)
			return
		}

		// Read.
		contents, err := ioutil.ReadAll(req.Contents)
		if err != nil {
			err = fmt.Errorf("whose contents cannot be read: %v", err)
			return
		}

		// Compare.
		if string(contents) != s {
			err = errors.New("whose contents don't match")
			return
		}

		return
	}

	return NewMatcher(pred, "has the specified contents")
}

////////////////////////////////////////////////////////////////////////
// Boilerplate
////////////////////////////////////////////////////////////////////////

type retryBucketTest struct {
	ctx     context.Context
	wrapped MockBucket
	bucket  Bucket
}

func (t *retryBucketTest) SetUp(ti *TestInfo) {
	t.ctx = ti.Ctx
	t.wrapped = NewMockBucket(ti.MockController, "wrapped")
	t.bucket = newRetryBucket(time.Second, t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// CreateObject
////////////////////////////////////////////////////////////////////////

type RetryBucket_CreateObjectTest struct {
	retryBucketTest

	req CreateObjectRequest
	obj *Object
}

func init() { RegisterTestSuite(&RetryBucket_CreateObjectTest{}) }

func (t *RetryBucket_CreateObjectTest) call() (err error) {
	t.obj, err = t.bucket.CreateObject(t.ctx, &t.req)
	return
}

func (t *RetryBucket_CreateObjectTest) ErrorReading() {
	var err error

	// Pass in a reader that will return an error.
	t.req.Contents = ioutil.NopCloser(
		iotest.OneByteReader(
			iotest.TimeoutReader(
				strings.NewReader("foobar"))))

	// Call
	err = t.call()

	ExpectThat(err, Error(HasSubstr("ReadAll")))
	ExpectThat(err, Error(HasSubstr("timeout")))
}

func (t *RetryBucket_CreateObjectTest) CallsWrapped() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) Successful() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := &Object{}
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(expected, nil))

	// Call
	err = t.call()

	AssertEq(nil, err)
	ExpectEq(expected, t.obj)
}

func (t *RetryBucket_CreateObjectTest) ShouldNotRetry() {
	var err error

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(""))

	// Wrapped
	expected := errors.New("taco")
	ExpectCall(t.wrapped, "CreateObject")(Any(), Any()).
		WillOnce(Return(nil, expected))

	// Call
	err = t.call()

	ExpectEq(expected, err)
}

func (t *RetryBucket_CreateObjectTest) CallsWrappedForRetry() {
	const expected = "taco"

	// Request
	t.req.Contents = ioutil.NopCloser(strings.NewReader(expected))

	// Wrapped
	retryable := io.ErrUnexpectedEOF

	ExpectCall(t.wrapped, "CreateObject")(Any(), contentsAre(expected)).
		WillOnce(Return(nil, retryable)).
		WillOnce(Return(nil, errors.New("")))

	// Call
	t.call()
}

func (t *RetryBucket_CreateObjectTest) RetrySuccessful() {
	AssertTrue(false, "TODO")
}
<|endoftext|>