master alpha
兔子 1 year ago
commit 03e58778dd

@ -0,0 +1,21 @@
module icbcwifi
go 1.19
require (
b612.me/starlog v1.3.0
b612.me/starnet v0.1.5
b612.me/staros v1.1.4
)
require (
b612.me/notify v1.2.0 // indirect
b612.me/starcrypto v0.0.1 // indirect
b612.me/stario v0.0.7 // indirect
b612.me/starmap v1.2.0 // indirect
b612.me/win32api v0.0.1 // indirect
b612.me/wincmd v0.0.1 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
)

@ -0,0 +1,36 @@
b612.me/notify v1.2.0 h1:RedXNMLqY+TozalmdIUM27EFvZp06pzeqHn/F9G1eEs=
b612.me/notify v1.2.0/go.mod h1:EPctpKCVnoZO1hUJTRYpOw3huTemua+SGNIuUCsnzOc=
b612.me/starcrypto v0.0.1 h1:xGngzXPUrVbqtWzNw2e+0eWsdG7GG1/X+ONDGIzdriI=
b612.me/starcrypto v0.0.1/go.mod h1:hz0xRnfWNpYOlVrIPoGrQOWPibq4YiUZ7qN5tsQbzPo=
b612.me/stario v0.0.5/go.mod h1:or4ssWcxQSjMeu+hRKEgtp0X517b3zdlEOAms8Qscvw=
b612.me/stario v0.0.7 h1:QbQcsHCVLE6vRgVrPN4+9DGiSaC6IWdtm4ClL2tpMUg=
b612.me/stario v0.0.7/go.mod h1:or4ssWcxQSjMeu+hRKEgtp0X517b3zdlEOAms8Qscvw=
b612.me/starlog v1.3.0 h1:GV/qhZ1MssUWedT5YHDltGbq+ZUoB58ysNY/yI7QuDw=
b612.me/starlog v1.3.0/go.mod h1:qydvFLzkSg+2TrgNvc+bbx5qC6GaH+dtJUjgQjRL0ro=
b612.me/starmap v1.2.0 h1:sRUeMRUqOyb3pAQln5U6V07kIYp0714Z3gJ/g2nCJXc=
b612.me/starmap v1.2.0/go.mod h1:InIJXA3qVeMkvkUhCV/XPchCiNcJcVYdYV8EAOGbGZY=
b612.me/starnet v0.1.3/go.mod h1:j/dd6BKwQK80O4gfbGYg2aYtPH76gSdgpuKboK/DwN4=
b612.me/starnet v0.1.5 h1:HdhUMRxTkQietBZvg9azXdFugbIcBI4e7/EjbFctyeo=
b612.me/starnet v0.1.5/go.mod h1:j/dd6BKwQK80O4gfbGYg2aYtPH76gSdgpuKboK/DwN4=
b612.me/staros v1.1.2/go.mod h1:9kNWVJWNJfs2MiWEt7X3SO+ixYKPGqus1ShTy8hpfU0=
b612.me/staros v1.1.4 h1:Ikh74tYMqXkDHXJHArVf1/yhLMORfwZ+q8clAKvYjrM=
b612.me/staros v1.1.4/go.mod h1://P/Ivz7hb/lrI+FwMh5G/T27iJ8WlWZZr3wOoPfVsU=
b612.me/win32api v0.0.1 h1:vLFB1xhO6pd9+zB2EyaapKB459Urv3v+C1YwgwOFEWo=
b612.me/win32api v0.0.1/go.mod h1:MHu0JBQjzxQ2yxpZPUBbn5un45o67eF5iWKa4Q9e0yE=
b612.me/wincmd v0.0.1 h1:4+RCFKHuD/JqAYsdtO6sTNKJs1nQVMQo87h6KhTJjkM=
b612.me/wincmd v0.0.1/go.mod h1:32xTM7qWAI7jx6qwTrig05rxejSYbSp7CX5WD7qsMxY=
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5 h1:saXMvIOKvRFwbOMicHXr0B1uwoxq9dGmLe5ExMES6c4=
golang.org/x/sys v0.0.0-20220318055525-2edf467146b5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

@ -0,0 +1,118 @@
package main
import (
"b612.me/starlog"
"b612.me/starnet"
"b612.me/staros"
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
)
func main() {
myDir := filepath.Dir(os.Args[0])
baseName := filepath.Base(os.Args[0])
procs, err := staros.FindProcessByName(baseName)
if err != nil {
starlog.Errorln(err)
os.Exit(2)
}
for _, v := range procs {
if int(v.Pid) == os.Getpid() {
continue
}
if len(v.Args) > 1 {
starlog.Errorf("another process already run:%+v\n", v)
os.Exit(3)
}
}
if len(os.Args) < 2 {
pid, err := staros.Daemon(os.Args[0], "-f")
if err != nil {
fmt.Println(err)
os.Exit(1)
}
fmt.Println("pid :", pid)
return
}
starlog.SetLogFile(filepath.Join(myDir, "icbcauth.log"), starlog.Std, true)
defer starlog.Close(starlog.Std)
//sig := make(chan os.Signal)
//signal.Notify(sig, os.Kill, os.Interrupt)
//for {
data, err := CheckNeedAuth(starlog.Std)
if err != nil {
return
}
if data != nil {
err = Auth(starlog.Std, data)
if err != nil {
return
}
}
// return
// select {
// case <-sig:
// starlog.Infoln("Stopped By Signal")
// return
// case <-time.After(time.Second * 300):
// }
// }
}
func CheckNeedAuth(log *starlog.StarLogger) (*url.URL, error) {
log.Noticeln("Checking If Need Auth")
res, err := starnet.Curl(starnet.NewRequests("http://139.199.163.65/", nil, "GET",
starnet.WithDisableRedirect(true)))
if err != nil {
log.Errorln("Checking Failed:", err)
return nil, err
}
if res.Location != nil {
log.Warningln("Checking Finished:Need Auth,Auth Url:", res.Location.String())
return res.Location, nil
}
log.Infoln("Checking Finished,No Need Auth")
return nil, nil
}
func Auth(log *starlog.StarLogger, authUrl *url.URL) error {
log.Noticeln("Trying to Auth...")
strUrl := "http://" + authUrl.Host + "/portallogin?" + authUrl.RawQuery
log.Noticeln("Auth Url is:", strUrl)
res, err := starnet.Curl(starnet.NewRequests(strUrl, nil, "GET",
starnet.WithDisableRedirect(true)))
if err != nil {
log.Errorln("Auth Failed:", err)
return err
}
if res.Location == nil {
starlog.Errorln("Cannot Got Redirect Url")
return errors.New("Cannot Got Redirect Url")
}
starlog.Infoln("Redirect Url is:", res.Location.String())
starlog.Noticeln("Getting Cookie...")
cok, err := starnet.Curl(starnet.NewRequests(res.Location.String(), nil, "GET"))
if err != nil {
log.Errorln("Auth Failed:", err)
return err
}
if len(cok.RespCookies) == 0 {
log.Errorln("Cannot Got Cookies")
return errors.New("Get Cookie Failed")
}
starlog.Infoln("Got Cookie:", cok.RespCookies)
starlog.Noticeln("Trying to Using Auth Url:", `http://content.icbc.com.cn/cmp/AuthSkipController.do?method=authSkip&ajaxRequest=true`)
res, err = starnet.Curl(starnet.NewRequests(`http://content.icbc.com.cn/cmp/AuthSkipController.do?method=authSkip&ajaxRequest=true`,
nil, "GET", starnet.WithDisableRedirect(true),
starnet.WithHeader("Referer", res.Location.String()),
starnet.WithCookies(cok.RespCookies)))
if err != nil {
log.Errorln("Auth Failed:", err)
return err
}
log.Infoln("Auth Result:", res.RespHttpCode, string(res.RecvData))
return nil
}

593
vendor/b612.me/notify/client.go generated vendored

@ -0,0 +1,593 @@
package notify
import (
"b612.me/starcrypto"
"b612.me/stario"
"b612.me/starnet"
"context"
"errors"
"fmt"
"math/rand"
"net"
"os"
"sync"
"sync/atomic"
"time"
)
//var nowd int64
type ClientCommon struct {
alive atomic.Value
status Status
byeFromServer bool
conn net.Conn
mu sync.Mutex
msgID uint64
queue *starnet.StarQueue
stopFn context.CancelFunc
stopCtx context.Context
parallelNum int
maxReadTimeout time.Duration
maxWriteTimeout time.Duration
keyExchangeFn func(c Client) error
linkFns map[string]func(message *Message)
defaultFns func(message *Message)
msgEn func([]byte, []byte) []byte
msgDe func([]byte, []byte) []byte
noFinSyncMsgPool sync.Map
handshakeRsaPubKey []byte
SecretKey []byte
noFinSyncMsgMaxKeepSeconds int
lastHeartbeat int64
heartbeatPeriod time.Duration
wg stario.WaitGroup
netType NetType
showError bool
skipKeyExchange bool
useHeartBeat bool
sequenceDe func([]byte) (interface{}, error)
sequenceEn func(interface{}) ([]byte, error)
}
func (c *ClientCommon) Connect(network string, addr string) error {
if c.alive.Load().(bool) {
return errors.New("client already run")
}
c.stopCtx, c.stopFn = context.WithCancel(context.Background())
c.queue = starnet.NewQueueCtx(c.stopCtx, 4)
conn, err := net.Dial(network, addr)
if err != nil {
return err
}
c.alive.Store(true)
c.status.Alive = true
c.conn = conn
if c.useHeartBeat {
go c.Heartbeat()
}
return c.clientPostInit()
}
func (c *ClientCommon) ConnectTimeout(network string, addr string, timeout time.Duration) error {
if c.alive.Load().(bool) {
return errors.New("client already run")
}
c.stopCtx, c.stopFn = context.WithCancel(context.Background())
c.queue = starnet.NewQueueCtx(c.stopCtx, 4)
conn, err := net.DialTimeout(network, addr, timeout)
if err != nil {
return err
}
c.alive.Store(true)
c.status.Alive = true
c.conn = conn
if c.useHeartBeat {
go c.Heartbeat()
}
return c.clientPostInit()
}
func (c *ClientCommon) monitorPool() {
for {
select {
case <-c.stopCtx.Done():
c.noFinSyncMsgPool.Range(func(k, v interface{}) bool {
data := v.(WaitMsg)
close(data.Reply)
c.noFinSyncMsgPool.Delete(k)
return true
})
return
case <-time.After(time.Second * 30):
}
now := time.Now()
if c.noFinSyncMsgMaxKeepSeconds > 0 {
c.noFinSyncMsgPool.Range(func(k, v interface{}) bool {
data := v.(WaitMsg)
if data.Time.Add(time.Duration(c.noFinSyncMsgMaxKeepSeconds) * time.Second).Before(now) {
close(data.Reply)
c.noFinSyncMsgPool.Delete(k)
}
return true
})
}
}
}
func (c *ClientCommon) SkipExchangeKey() bool {
return c.skipKeyExchange
}
func (c *ClientCommon) SetSkipExchangeKey(val bool) {
c.skipKeyExchange = val
}
func (c *ClientCommon) clientPostInit() error {
go c.readMessage()
go c.loadMessage()
if !c.skipKeyExchange {
err := c.keyExchangeFn(c)
if err != nil {
c.alive.Store(false)
c.mu.Lock()
c.status = Status{
Alive: false,
Reason: "key exchange failed",
Err: err,
}
c.mu.Unlock()
c.stopFn()
return err
}
}
return nil
}
func NewClient() Client {
var client = ClientCommon{
maxReadTimeout: 0,
maxWriteTimeout: 0,
sequenceEn: encode,
sequenceDe: Decode,
keyExchangeFn: aesRsaHello,
SecretKey: defaultAesKey,
handshakeRsaPubKey: defaultRsaPubKey,
msgEn: defaultMsgEn,
msgDe: defaultMsgDe,
}
client.alive.Store(false)
//heartbeat should not controlable for user
client.useHeartBeat = true
client.heartbeatPeriod = time.Second * 20
client.linkFns = make(map[string]func(*Message))
client.defaultFns = func(message *Message) {
return
}
client.wg = stario.NewWaitGroup(0)
client.stopCtx, client.stopFn = context.WithCancel(context.Background())
return &client
}
func (c *ClientCommon) Heartbeat() {
failedCount := 0
for {
select {
case <-c.stopCtx.Done():
return
case <-time.After(c.heartbeatPeriod):
}
_, err := c.sendWait(TransferMsg{
ID: 10000,
Key: "heartbeat",
Value: nil,
Type: MSG_SYS_WAIT,
}, time.Second*5)
if err == nil {
c.lastHeartbeat = time.Now().Unix()
failedCount = 0
}
failedCount++
if failedCount >= 3 {
//fmt.Println("heatbeat failed,stop client")
c.alive.Store(false)
c.mu.Lock()
c.status = Status{
Alive: false,
Reason: "heartbeat failed more than 3 times",
Err: errors.New("heartbeat failed more than 3 times"),
}
c.mu.Unlock()
c.stopFn()
return
}
}
}
func (c *ClientCommon) ShowError(std bool) {
c.mu.Lock()
c.showError = std
c.mu.Unlock()
}
func (c *ClientCommon) readMessage() {
for {
select {
case <-c.stopCtx.Done():
c.conn.Close()
return
default:
}
data := make([]byte, 8192)
if c.maxReadTimeout.Seconds() != 0 {
c.conn.SetReadDeadline(time.Now().Add(c.maxReadTimeout))
}
readNum, err := c.conn.Read(data)
if err == os.ErrDeadlineExceeded {
if readNum != 0 {
c.queue.ParseMessage(data[:readNum], "b612")
}
continue
}
if err != nil {
if c.showError {
fmt.Println("client read error", err)
}
c.alive.Store(false)
c.mu.Lock()
c.status = Status{
Alive: false,
Reason: "client read error",
Err: err,
}
c.mu.Unlock()
c.stopFn()
continue
}
c.queue.ParseMessage(data[:readNum], "b612")
}
}
func (c *ClientCommon) sayGoodBye() error {
_, err := c.sendWait(TransferMsg{
ID: 10010,
Key: "bye",
Value: nil,
Type: MSG_SYS_WAIT,
}, time.Second*3)
return err
}
func (c *ClientCommon) loadMessage() {
for {
select {
case <-c.stopCtx.Done():
//say goodbye
if !c.byeFromServer {
c.sayGoodBye()
}
c.conn.Close()
return
case data, ok := <-c.queue.RestoreChan():
if !ok {
continue
}
c.wg.Add(1)
go func(data starnet.MsgQueue) {
defer c.wg.Done()
//fmt.Println("c received:", float64(time.Now().UnixNano()-nowd)/1000000)
now := time.Now()
//transfer to Msg
msg, err := c.sequenceDe(c.msgDe(c.SecretKey, data.Msg))
if err != nil {
if c.showError {
fmt.Println("client decode data error", err)
}
return
}
message := Message{
ServerConn: c,
TransferMsg: msg.(TransferMsg),
NetType: NET_CLIENT,
}
message.Time = now
c.dispatchMsg(message)
}(data)
}
}
}
func (c *ClientCommon) dispatchMsg(message Message) {
switch message.TransferMsg.Type {
case MSG_SYS_WAIT:
fallthrough
case MSG_SYS:
c.sysMsg(message)
return
case MSG_KEY_CHANGE:
fallthrough
case MSG_SYS_REPLY:
fallthrough
case MSG_SYNC_REPLY:
data, ok := c.noFinSyncMsgPool.Load(message.ID)
if ok {
wait := data.(WaitMsg)
wait.Reply <- message
c.noFinSyncMsgPool.Delete(message.ID)
return
}
return
//fallthrough
default:
}
callFn := func(fn func(*Message)) {
fn(&message)
}
fn, ok := c.linkFns[message.Key]
if ok {
callFn(fn)
}
if c.defaultFns != nil {
callFn(c.defaultFns)
}
}
func (c *ClientCommon) sysMsg(message Message) {
switch message.Key {
case "bye":
if message.TransferMsg.Type == MSG_SYS_WAIT {
//fmt.Println("recv stop signal from server")
c.byeFromServer = true
message.Reply(nil)
}
c.alive.Store(false)
c.mu.Lock()
c.status = Status{
Alive: false,
Reason: "recv stop signal from server",
Err: nil,
}
c.mu.Unlock()
c.stopFn()
}
}
func (c *ClientCommon) SetDefaultLink(fn func(message *Message)) {
c.defaultFns = fn
}
func (c *ClientCommon) SetLink(key string, fn func(*Message)) {
c.mu.Lock()
defer c.mu.Unlock()
c.linkFns[key] = fn
}
func (c *ClientCommon) send(msg TransferMsg) (WaitMsg, error) {
var wait WaitMsg
if msg.Type != MSG_SYNC_REPLY && msg.Type != MSG_KEY_CHANGE && msg.Type != MSG_SYS_REPLY || msg.ID == 0 {
msg.ID = atomic.AddUint64(&c.msgID, 1)
}
data, err := c.sequenceEn(msg)
if err != nil {
return WaitMsg{}, err
}
data = c.msgEn(c.SecretKey, data)
data = c.queue.BuildMessage(data)
if c.maxWriteTimeout.Seconds() != 0 {
c.conn.SetWriteDeadline(time.Now().Add(c.maxWriteTimeout))
}
_, err = c.conn.Write(data)
if err == nil && (msg.Type == MSG_SYNC_ASK || msg.Type == MSG_KEY_CHANGE || msg.Type == MSG_SYS_WAIT) {
wait.Time = time.Now()
wait.TransferMsg = msg
wait.Reply = make(chan Message, 1)
c.noFinSyncMsgPool.Store(msg.ID, wait)
}
return wait, err
}
func (c *ClientCommon) Send(key string, value MsgVal) error {
_, err := c.send(TransferMsg{
Key: key,
Value: value,
Type: MSG_ASYNC,
})
return err
}
func (c *ClientCommon) sendWait(msg TransferMsg, timeout time.Duration) (Message, error) {
data, err := c.send(msg)
if err != nil {
return Message{}, err
}
if timeout.Seconds() == 0 {
msg, ok := <-data.Reply
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
select {
case <-time.After(timeout):
close(data.Reply)
c.noFinSyncMsgPool.Delete(data.TransferMsg.ID)
return Message{}, os.ErrDeadlineExceeded
case <-c.stopCtx.Done():
return Message{}, errors.New("Service shutdown")
case msg, ok := <-data.Reply:
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
}
func (c *ClientCommon) sendCtx(msg TransferMsg, ctx context.Context) (Message, error) {
data, err := c.send(msg)
if err != nil {
return Message{}, err
}
if ctx == nil {
ctx = context.Background()
}
select {
case <-ctx.Done():
close(data.Reply)
c.noFinSyncMsgPool.Delete(data.TransferMsg.ID)
return Message{}, os.ErrDeadlineExceeded
case <-c.stopCtx.Done():
return Message{}, errors.New("Service shutdown")
case msg, ok := <-data.Reply:
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
}
func (c *ClientCommon) SendObjCtx(ctx context.Context, key string, val interface{}) (Message, error) {
data, err := c.sequenceEn(val)
if err != nil {
return Message{}, err
}
return c.sendCtx(TransferMsg{
Key: key,
Value: data,
Type: MSG_SYNC_ASK,
}, ctx)
}
func (c *ClientCommon) SendObj(key string, val interface{}) error {
data, err := encode(val)
if err != nil {
return err
}
_, err = c.send(TransferMsg{
Key: key,
Value: data,
Type: MSG_ASYNC,
})
return err
}
func (c *ClientCommon) SendCtx(ctx context.Context, key string, value MsgVal) (Message, error) {
return c.sendCtx(TransferMsg{
Key: key,
Value: value,
Type: MSG_SYNC_ASK,
}, ctx)
}
func (c *ClientCommon) SendWait(key string, value MsgVal, timeout time.Duration) (Message, error) {
return c.sendWait(TransferMsg{
Key: key,
Value: value,
Type: MSG_SYNC_ASK,
}, timeout)
}
func (c *ClientCommon) SendWaitObj(key string, value interface{}, timeout time.Duration) (Message, error) {
data, err := c.sequenceEn(value)
if err != nil {
return Message{}, err
}
return c.SendWait(key, data, timeout)
}
func (c *ClientCommon) Reply(m Message, value MsgVal) error {
return m.Reply(value)
}
func (c *ClientCommon) ExchangeKey(newKey []byte) error {
newSendKey, err := starcrypto.RSAEncrypt(newKey, c.handshakeRsaPubKey)
if err != nil {
return err
}
data, err := c.sendWait(TransferMsg{
ID: 19961127,
Key: "sirius",
Value: newSendKey,
Type: MSG_KEY_CHANGE,
}, time.Second*10)
if err != nil {
return err
}
if string(data.Value) != "success" {
return errors.New("cannot exchange new aes-key")
}
c.SecretKey = newKey
time.Sleep(time.Millisecond * 100)
return nil
}
func aesRsaHello(c Client) error {
newAesKey := []byte(fmt.Sprintf("%d%d%d%s", time.Now().UnixNano(), rand.Int63(), rand.Int63(), "b612.me"))
newAesKey = []byte(starcrypto.Md5Str(newAesKey))
return c.ExchangeKey(newAesKey)
}
func (c *ClientCommon) GetMsgEn() func([]byte, []byte) []byte {
return c.msgEn
}
func (c *ClientCommon) SetMsgEn(fn func([]byte, []byte) []byte) {
c.msgEn = fn
}
func (c *ClientCommon) GetMsgDe() func([]byte, []byte) []byte {
return c.msgDe
}
func (c *ClientCommon) SetMsgDe(fn func([]byte, []byte) []byte) {
c.msgDe = fn
}
func (c *ClientCommon) HeartbeatPeroid() time.Duration {
return c.heartbeatPeriod
}
func (c *ClientCommon) SetHeartbeatPeroid(duration time.Duration) {
c.heartbeatPeriod = duration
}
func (c *ClientCommon) GetSecretKey() []byte {
return c.SecretKey
}
func (c *ClientCommon) SetSecretKey(key []byte) {
c.SecretKey = key
}
func (c *ClientCommon) RsaPubKey() []byte {
return c.handshakeRsaPubKey
}
func (c *ClientCommon) SetRsaPubKey(key []byte) {
c.handshakeRsaPubKey = key
}
func (c *ClientCommon) Stop() error {
if !c.alive.Load().(bool) {
return nil
}
c.alive.Store(false)
c.mu.Lock()
c.status = Status{
Alive: false,
Reason: "recv stop signal from user",
Err: nil,
}
c.mu.Unlock()
c.stopFn()
return nil
}
func (c *ClientCommon) StopMonitorChan() <-chan struct{} {
return c.stopCtx.Done()
}
func (c *ClientCommon) Status() Status {
return c.status
}
func (c *ClientCommon) GetSequenceEn() func(interface{}) ([]byte, error) {
return c.sequenceEn
}
func (c *ClientCommon) SetSequenceEn(fn func(interface{}) ([]byte, error)) {
c.sequenceEn = fn
}
func (c *ClientCommon) GetSequenceDe() func([]byte) (interface{}, error) {
return c.sequenceDe
}
func (c *ClientCommon) SetSequenceDe(fn func([]byte) (interface{}, error)) {
c.sequenceDe = fn
}

@ -0,0 +1,49 @@
package notify
import (
"context"
"time"
)
type Client interface {
SetDefaultLink(func(message *Message))
SetLink(string, func(*Message))
send(msg TransferMsg) (WaitMsg, error)
sendWait(msg TransferMsg, timeout time.Duration) (Message, error)
Send(key string, value MsgVal) error
SendWait(key string, value MsgVal, timeout time.Duration) (Message, error)
SendWaitObj(key string, value interface{}, timeout time.Duration) (Message, error)
SendCtx(ctx context.Context, key string, value MsgVal) (Message, error)
Reply(m Message, value MsgVal) error
ExchangeKey(newKey []byte) error
Connect(network string, addr string) error
ConnectTimeout(network string, addr string, timeout time.Duration) error
SkipExchangeKey() bool
SetSkipExchangeKey(bool)
GetMsgEn() func([]byte, []byte) []byte
SetMsgEn(func([]byte, []byte) []byte)
GetMsgDe() func([]byte, []byte) []byte
SetMsgDe(func([]byte, []byte) []byte)
Heartbeat()
HeartbeatPeroid() time.Duration
SetHeartbeatPeroid(duration time.Duration)
GetSecretKey() []byte
SetSecretKey(key []byte)
RsaPubKey() []byte
SetRsaPubKey([]byte)
Stop() error
StopMonitorChan() <-chan struct{}
Status() Status
ShowError(bool)
GetSequenceEn() func(interface{}) ([]byte, error)
SetSequenceEn(func(interface{}) ([]byte, error))
GetSequenceDe() func([]byte) (interface{}, error)
SetSequenceDe(func([]byte) (interface{}, error))
SendObjCtx(ctx context.Context, key string, val interface{}) (Message, error)
SendObj(key string, val interface{}) error
}

86
vendor/b612.me/notify/default.go generated vendored

@ -0,0 +1,86 @@
package notify
import (
"b612.me/starcrypto"
)
var defaultRsaKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAxmeMqr9yfJFKZn26oe/HvC7bZXNLC9Nk55AuTkb4XuIoqXDb
AJD2Y/p167oJLKIqL3edcj7h+oTfn6s79vxT0ZCEf37ILU0G+scRzVwYHiLMwOUC
bS2o4Xor3zqUi9f1piJBvoBNh8RKKtsmJW6VQZdiUGJHbgX4MdOdtf/6TvxZMwSX
U+PRSCAjy04A31Zi7DEWUWJPyqmHeu++PxXU5lvoMdCGDqpcF2j2uO7oJJUww01M
3F5FtTElMrK4/P9gD4kP7NiPhOfVPEfBsYT/DSSjvqNZJZuWnxu+cDxE7J/sBvdp
eNRLhqzdmMYagZFuUmVrz8QmsD6jKHgydW+r7irllvb8WJPK/RIMif+4Rg7rDKFb
j8+ZQ3HZ/gKELoRSyb3zL6RC2qlGLjC1tdeN7TNTinCv092y39T8jIARJ7tpfePh
NBxsBdxfXbCAzHYZIHufI9Zlsc+felQwanlDhq+q8YLcnKHvNKYVyCf/upExpAiA
rr88y/KbeKes0KorKkwMBnGUMTothWM25wHozcurixNvP4UMWX7LWD7vOZZuNDQN
utZYeTwdsniI3mTO9vlPWEK8JTfxBU7x9SePUMJNDyjfDUJM8C2DOlyhGNPkgazO
GdliH87tHkEy/7jJnGclgKmciiVPgwHfFx9GGoBHEfvmAoGGrk4qNbjm7JECAwEA
AQKCAgBYzHe05ELFZfG6tYMWf08R9pbTbSqlfFOpIGrZNgJr1SUF0TDzq+3bCXpF
qtn4VAw1en/JZkOV8Gp1+Bm6jWymWtwyg/fr7pG1I+vf0dwpgMHLg7P2UX1IjXmd
S4a4oEuds69hJ+OLZFsdm0ATeM7ssGicOaBmqd1Pz7rCfnL1bxQtNVzVex1r/paG
o77YNr3HoKCwhCPaPM4aQ7sOWSMUhwYBZabaYX0eLShf1O2pkexlPO+tobPpSLmx
WzRYZ6QC0AGEq9hwT6KsfCFA5pmQtFllNY7suhpL1AsECLWAgoMNCyb1oW68NBpq
CiBK5WBPGH2MW+pE74Pu1P0gen6kLGnApKQjprE1aGuR+xkZe3uEnXwSryU9TXki
wINTEMsX8dkmofFqaJhUwSubrb+t7gvv9E9ZZe0X6UgKzAVVqvh4z1pP8VT+xHpu
pW7SR8n9cFddaEPUijSb1rSpJrNzfJJ+G7yrB7Cw2kBgQ07vzD3z/3kA9cwFevLS
mv3l3OQuB6y9c+AG3cX5WGAt/BVOLjimj9qJt+YglG0SwG31U0PUnnx6QVz/UtJm
CbJQ2TpJd+mk0HyuMU+eycp7BWF3PMN+SE4QgKCKWnhsLeAd3gcvifsbLOYE1OPg
wv1tqyJy0VsJiSn6Ub6Qq0kPLwCLlQTnLWk5mIhnRpHYufTSwQKCAQEA4gS4FKPU
tAcQ82dEYW4OjGfhNWrjFpF+A8K5zufleQWcgzQ3fQho13zH0vZobukfkEVlVxla
OIVk7ZgNA4mCSFrATjIx3RMqzrAUvTte0O4wkjYgCwVvTdS1W8nvRLKgugLygyoo
r+MLW5IT3eNMK/2fZbftNlAkbc7NCo3c2tS6MXFgjx5JUuzChOY73Kp4p5KS38L5
wRRiI8KTIKjBjMZ5q/l8VLKX89bKOCaWibmItoXY6QMbIjargb7YLp3X6uGEyGIu
VhPbQ80/+OC2ZqIvDecp4PYnJNZFeqfjyfhJCNqDjBKYwIscBLMU/Wf9OY258OR4
snQaerN1M0h9lQKCAQEA4LkZIRLLw+8bIVM+7VXxFwOAGy+MH35tvuNIToItAoUh
zjL5LG34PjID8J0DPyP8VRVanak1EcxF0aTEkvnt2f2RAVsW89ytcn8Lybb12Ae8
ia2ZWuIM+J40nuKOGPs3lJ9HqdPWmZYWsWKxFJmYBBnwD6CADYqhqambQn0HeaYl
/WUD7blLYg+4Kk1mt9/hIw93jTWP/86O2H0ia+AhYPTqyvVXfIXKhat6NlOYksGf
Hdv+aCC8Ukg6FyEgiNc/rFn0MWPnEX+cM1AwubviHIBhV8QWILLBTjupwsEBZVah
60ftH+HRUCmEeOpI7jyzIlfEUNLoBHfswKMhMPtcDQKCAQEA0JFkQX+xn/PJW6PX
AUWrXTvbIg0hw8i9DcFa76klJBnehWDhN5tUDE5Uo8PJOVgdTWgMjWSS0geezHX8
xF/XfudoAIDnbMfsP9FTQhCQfaLf5XzW8vSv8pWwSiS9jJp+IUjo+8siwrR03aqe
dKr0tr+ToS0qVG1+QGqO4gdpX/LgYxHp9ggPx9s94aAIa6hQMOrcaGqnSNqDedZr
KL8x5LOewek3J32rJVP3Rfut/SfeFfjL4rKADoF+oPs4yUPVZSV4/+VCNyKZuyaj
uwm6qFlPrLe9+J+OHbsxYG+fj9hzpRzoOZFLrppwX5HWc8XLcpnrlXVwP9VOPh5u
r8VcRQKCAQAJFHGHfJLvH8Ig3pQ0UryjCWkrsAghXaJhjB1nzqqy514uTrDysp7N
JIg0OKPg8TtI1MwMgsG6Ll7D0bx/k8mgfTZWr6+FuuznK2r2g4X7bJSZm4IOwgN0
KDBIGy9SoxPj1Wu32O9a1U2lbS9qfao+wC2K9Bk4ctmFWW0Eiri6mZP/YQ1/lXUO
SURPsUDtPQaDvCRAeGGRHG95H9U8NpoiqMKz4KXgSiecrwkJGOeZRml/c1wcKPZy
/KgcNyJxZQEVnazYMgksE9Pj3uGZH5ZLQISuXyXlvFNDLfX2AIZl6dIxB371QtKK
QqMvn4fC2IEEajdsbJkjVRUj03OL3xwhAoIBAAfMhDSvBbDkGTaXnNMjPPSbswqK
qcSRhSG27mjs1dDNBKuFbz6TkIOp4nxjuS9Zp19fErXlAE9mF5yXSmuiAkZmWfhs
HKpWIdjFJK1EqSfcINe2YuoyUIulz9oG7ObRHD4D8jSPjA8Ete+XsBHGyOtUl09u
X4u9uClhqjK+r1Tno2vw5yF6ZxfQtdWuL4W0UL1S8E+VO7vjTjNOYvgjAIpAM/gW
sqjA2Qw52UZqhhLXoTfRvtJilxlXXhIRJSsnUoGiYVCQ/upjqJCClEvJfIWdGY/U
I2CbFrwJcNvOG1lUsSM55JUmbrSWVPfo7yq2k9GCuFxOy2n/SVlvlQUcNkA=
-----END RSA PRIVATE KEY-----`)
var defaultRsaPubKey = []byte(`-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxmeMqr9yfJFKZn26oe/H
vC7bZXNLC9Nk55AuTkb4XuIoqXDbAJD2Y/p167oJLKIqL3edcj7h+oTfn6s79vxT
0ZCEf37ILU0G+scRzVwYHiLMwOUCbS2o4Xor3zqUi9f1piJBvoBNh8RKKtsmJW6V
QZdiUGJHbgX4MdOdtf/6TvxZMwSXU+PRSCAjy04A31Zi7DEWUWJPyqmHeu++PxXU
5lvoMdCGDqpcF2j2uO7oJJUww01M3F5FtTElMrK4/P9gD4kP7NiPhOfVPEfBsYT/
DSSjvqNZJZuWnxu+cDxE7J/sBvdpeNRLhqzdmMYagZFuUmVrz8QmsD6jKHgydW+r
7irllvb8WJPK/RIMif+4Rg7rDKFbj8+ZQ3HZ/gKELoRSyb3zL6RC2qlGLjC1tdeN
7TNTinCv092y39T8jIARJ7tpfePhNBxsBdxfXbCAzHYZIHufI9Zlsc+felQwanlD
hq+q8YLcnKHvNKYVyCf/upExpAiArr88y/KbeKes0KorKkwMBnGUMTothWM25wHo
zcurixNvP4UMWX7LWD7vOZZuNDQNutZYeTwdsniI3mTO9vlPWEK8JTfxBU7x9SeP
UMJNDyjfDUJM8C2DOlyhGNPkgazOGdliH87tHkEy/7jJnGclgKmciiVPgwHfFx9G
GoBHEfvmAoGGrk4qNbjm7JECAwEAAQ==
-----END PUBLIC KEY-----`)
var defaultAesKey = []byte{0x19, 0x96, 0x11, 0x27, 228, 187, 187, 231, 142, 137, 230, 179, 189, 229, 184, 133}
func defaultMsgEn(key []byte, d []byte) []byte {
return starcrypto.AesEncryptCFB(d, key)
}
func defaultMsgDe(key []byte, d []byte) []byte {
return starcrypto.AesDecryptCFB(d, key)
}
func init() {
Register(TransferMsg{})
}

472
vendor/b612.me/notify/msg.go generated vendored

@ -0,0 +1,472 @@
package notify
import (
"b612.me/starcrypto"
"context"
"errors"
"fmt"
"net"
"os"
"sync"
"sync/atomic"
"time"
)
const (
MSG_SYS MessageType = iota
MSG_SYS_WAIT
MSG_SYS_REPLY
MSG_KEY_CHANGE
MSG_ASYNC
MSG_SYNC_ASK
MSG_SYNC_REPLY
)
type MessageType uint8
type NetType uint8
const (
NET_SERVER NetType = iota
NET_CLIENT
)
type MsgVal []byte
type TransferMsg struct {
ID uint64
Key string
Value MsgVal
Type MessageType
}
type Message struct {
NetType
ClientConn *ClientConn
ServerConn Client
TransferMsg
Time time.Time
sync.Mutex
}
type WaitMsg struct {
TransferMsg
Time time.Time
Reply chan Message
//Ctx context.Context
}
func (m *Message) Reply(value MsgVal) (err error) {
reply := TransferMsg{
ID: m.ID,
Key: m.Key,
Value: value,
Type: m.Type,
}
if reply.Type == MSG_SYNC_ASK {
reply.Type = MSG_SYNC_REPLY
}
if reply.Type == MSG_SYS_WAIT {
reply.Type = MSG_SYS_REPLY
}
if m.NetType == NET_SERVER {
_, err = m.ClientConn.server.send(m.ClientConn, reply)
}
if m.NetType == NET_CLIENT {
_, err = m.ServerConn.send(reply)
}
return
}
func (m *Message) ReplyObj(value interface{}) (err error) {
data, err := encode(value)
if err != nil {
return err
}
return m.Reply(data)
}
type ClientConn struct {
alive atomic.Value
status Status
ClientID string
ClientAddr net.Addr
tuConn net.Conn
server Server
stopFn context.CancelFunc
stopCtx context.Context
maxReadTimeout time.Duration
maxWriteTimeout time.Duration
msgEn func([]byte, []byte) []byte
msgDe func([]byte, []byte) []byte
handshakeRsaKey []byte
SecretKey []byte
lastHeartBeat int64
}
type Status struct {
Alive bool
Reason string
Err error
}
func (c *ClientConn) readTUMessage() {
for {
select {
case <-c.stopCtx.Done():
c.tuConn.Close()
c.server.removeClient(c)
return
default:
}
if c.maxReadTimeout.Seconds() > 0 {
c.tuConn.SetReadDeadline(time.Now().Add(c.maxReadTimeout))
}
data := make([]byte, 8192)
num, err := c.tuConn.Read(data)
if err == os.ErrDeadlineExceeded {
if num != 0 {
c.server.pushMessage(data[:num], c.ClientID)
}
continue
}
if err != nil {
//conn is broke
c.alive.Store(false)
c.status = Status{
Alive: false,
Reason: "read error",
Err: err,
}
c.stopFn()
continue
}
c.server.pushMessage(data[:num], c.ClientID)
//fmt.Println("finished:", float64(time.Now().UnixNano()-nowd)/1000000)
}
}
func (c *ClientConn) rsaDecode(message Message) {
unknownKey := message.Value
data, err := starcrypto.RSADecrypt(unknownKey, c.handshakeRsaKey, "")
if err != nil {
fmt.Println(err)
message.Reply([]byte("failed"))
return
}
//fmt.Println("aes-key changed to", string(data))
message.Reply([]byte("success"))
c.SecretKey = data
}
func (c *ClientConn) sayGoodByeForTU() error {
_, err := c.server.sendWait(c, TransferMsg{
ID: 10010,
Key: "bye",
Value: nil,
Type: MSG_SYS_WAIT,
}, time.Second*3)
return err
}
func (c *ClientConn) GetSecretKey() []byte {
return c.SecretKey
}
func (c *ClientConn) SetSecretKey(key []byte) {
c.SecretKey = key
}
func (c *ClientConn) GetMsgEn() func([]byte, []byte) []byte {
return c.msgEn
}
func (c *ClientConn) SetMsgEn(fn func([]byte, []byte) []byte) {
c.msgEn = fn
}
func (c *ClientConn) GetMsgDe() func([]byte, []byte) []byte {
return c.msgDe
}
func (c *ClientConn) SetMsgDe(fn func([]byte, []byte) []byte) {
c.msgDe = fn
}
func (c *ClientConn) StopMonitorChan() <-chan struct{} {
return c.stopCtx.Done()
}
func (c *ClientConn) Status() Status {
return c.status
}
func (c *ClientConn) Server() Server {
return c.server
}
func (c *ClientConn) GetRemoteAddr() net.Addr {
return c.ClientAddr
}
func (m MsgVal) ToClearString() string {
return string(m)
}
func (m MsgVal) ToInterface() (interface{}, error) {
return Decode(m)
}
func (m MsgVal) MustToInterface() interface{} {
inf, err := m.ToInterface()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToString() (string, error) {
inf, err := m.ToInterface()
if err != nil {
return "", err
}
if data, ok := inf.(string); !ok {
return "", errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToString() string {
inf, err := m.ToString()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToInt32() (int32, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(int32); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToInt32() int32 {
inf, err := m.ToInt32()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToInt() (int, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(int); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToInt() int {
inf, err := m.ToInt()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToUint64() (uint64, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(uint64); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToUint64() uint64 {
inf, err := m.ToUint64()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToUint32() (uint32, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(uint32); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToUint32() uint32 {
inf, err := m.ToUint32()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToUint() (uint, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(uint); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToUint() uint {
inf, err := m.ToUint()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToBool() (bool, error) {
inf, err := m.ToInterface()
if err != nil {
return false, err
}
if data, ok := inf.(bool); !ok {
return false, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToBool() bool {
inf, err := m.ToBool()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToFloat64() (float64, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(float64); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToFloat64() float64 {
inf, err := m.ToFloat64()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToFloat32() (float32, error) {
inf, err := m.ToInterface()
if err != nil {
return 0, err
}
if data, ok := inf.(float32); !ok {
return 0, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToFloat32() float32 {
inf, err := m.ToFloat32()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToSliceString() ([]string, error) {
inf, err := m.ToInterface()
if err != nil {
return []string{}, err
}
if data, ok := inf.([]string); !ok {
return []string{}, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToSliceString() []string {
inf, err := m.ToSliceString()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToSliceInt64() ([]int64, error) {
inf, err := m.ToInterface()
if err != nil {
return []int64{}, err
}
if data, ok := inf.([]int64); !ok {
return []int64{}, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToSliceInt64() []int64 {
inf, err := m.ToSliceInt64()
if err != nil {
panic(err)
}
return inf
}
func (m MsgVal) ToSliceFloat64() ([]float64, error) {
inf, err := m.ToInterface()
if err != nil {
return []float64{}, err
}
if data, ok := inf.([]float64); !ok {
return []float64{}, errors.New("source data not match target type")
} else {
return data, nil
}
}
func (m MsgVal) MustToSliceFloat64() []float64 {
inf, err := m.ToSliceFloat64()
if err != nil {
panic(err)
}
return inf
}
func ToMsgVal(val interface{}) (MsgVal, error) {
return Encode(val)
}
func MustToMsgVal(val interface{}) MsgVal {
d, err := ToMsgVal(val)
if err != nil {
panic(err)
}
return d
}

@ -0,0 +1,33 @@
package notify
import (
"bytes"
"encoding/gob"
)
func Register(data interface{}) {
gob.Register(data)
}
func RegisterAll(data []interface{}) {
for _, v := range data {
gob.Register(v)
}
}
func encode(src interface{}) ([]byte, error) {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
err := enc.Encode(&src)
return buf.Bytes(), err
}
func Encode(src interface{}) ([]byte, error) {
return encode(src)
}
func Decode(src []byte) (interface{}, error) {
dec := gob.NewDecoder(bytes.NewReader(src))
var dst interface{}
err := dec.Decode(&dst)
return dst, err
}

665
vendor/b612.me/notify/server.go generated vendored

@ -0,0 +1,665 @@
package notify
import (
"b612.me/stario"
"b612.me/starnet"
"context"
"errors"
"fmt"
"math/rand"
"net"
"os"
"strings"
"sync"
"sync/atomic"
"time"
)
type ServerCommon struct {
msgID uint64
alive atomic.Value
status Status
listener net.Listener
udpListener *net.UDPConn
queue *starnet.StarQueue
stopFn context.CancelFunc
stopCtx context.Context
maxReadTimeout time.Duration
maxWriteTimeout time.Duration
parallelNum int
wg stario.WaitGroup
clientPool map[string]*ClientConn
mu sync.RWMutex
handshakeRsaKey []byte
SecretKey []byte
defaultMsgEn func([]byte, []byte) []byte
defaultMsgDe func([]byte, []byte) []byte
linkFns map[string]func(message *Message)
defaultFns func(message *Message)
noFinSyncMsgPool sync.Map
noFinSyncMsgMaxKeepSeconds int64
maxHeartbeatLostSeconds int64
sequenceDe func([]byte) (interface{}, error)
sequenceEn func(interface{}) ([]byte, error)
showError bool
}
func NewServer() Server {
var server ServerCommon
server.wg = stario.NewWaitGroup(0)
server.parallelNum = 0
server.noFinSyncMsgMaxKeepSeconds = 0
server.maxHeartbeatLostSeconds = 300
server.stopCtx, server.stopFn = context.WithCancel(context.Background())
server.SecretKey = defaultAesKey
server.handshakeRsaKey = defaultRsaKey
server.clientPool = make(map[string]*ClientConn)
server.defaultMsgEn = defaultMsgEn
server.defaultMsgDe = defaultMsgDe
server.sequenceEn = encode
server.sequenceDe = Decode
server.alive.Store(false)
server.linkFns = make(map[string]func(*Message))
server.defaultFns = func(message *Message) {
return
}
return &server
}
func (s *ServerCommon) ShowError(std bool) {
s.mu.Lock()
s.showError = std
s.mu.Unlock()
}
func (s *ServerCommon) Stop() error {
if !s.alive.Load().(bool) {
return nil
}
s.alive.Store(false)
s.mu.Lock()
s.status = Status{
Alive: false,
Reason: "recv stop signal from user",
Err: nil,
}
s.mu.Unlock()
s.stopFn()
return nil
}
func (s *ServerCommon) Listen(network string, addr string) error {
if s.alive.Load().(bool) {
return errors.New("server already run")
}
s.stopCtx, s.stopFn = context.WithCancel(context.Background())
s.queue = starnet.NewQueueCtx(s.stopCtx, 128)
if strings.Contains(strings.ToLower(network), "udp") {
return s.ListenUDP(network, addr)
}
return s.ListenTU(network, addr)
}
func (s *ServerCommon) ListenTU(network string, addr string) error {
listener, err := net.Listen(network, addr)
if err != nil {
return err
}
s.alive.Store(true)
s.status.Alive = true
s.listener = listener
go s.accept()
go s.monitorPool()
go s.loadMessage()
return nil
}
func (s *ServerCommon) monitorPool() {
for {
select {
case <-s.stopCtx.Done():
s.noFinSyncMsgPool.Range(func(k, v interface{}) bool {
data := v.(WaitMsg)
close(data.Reply)
s.noFinSyncMsgPool.Delete(k)
return true
})
return
case <-time.After(time.Second * 30):
}
now := time.Now()
if s.noFinSyncMsgMaxKeepSeconds > 0 {
s.noFinSyncMsgPool.Range(func(k, v interface{}) bool {
data := v.(WaitMsg)
if data.Time.Add(time.Duration(s.noFinSyncMsgMaxKeepSeconds) * time.Second).Before(now) {
close(data.Reply)
s.noFinSyncMsgPool.Delete(k)
}
return true
})
}
if s.maxHeartbeatLostSeconds != 0 {
for _, v := range s.clientPool {
if now.Unix()-v.lastHeartBeat > s.maxHeartbeatLostSeconds {
v.stopFn()
s.removeClient(v)
}
}
}
}
}
func (s *ServerCommon) SetDefaultCommEncode(fn func([]byte, []byte) []byte) {
s.defaultMsgEn = fn
}
func (s *ServerCommon) SetDefaultCommDecode(fn func([]byte, []byte) []byte) {
s.defaultMsgDe = fn
}
func (s *ServerCommon) SetDefaultLink(fn func(message *Message)) {
s.defaultFns = fn
}
func (s *ServerCommon) SetLink(key string, fn func(*Message)) {
s.mu.Lock()
defer s.mu.Unlock()
s.linkFns[key] = fn
}
func (s *ServerCommon) pushMessage(data []byte, source string) {
s.queue.ParseMessage(data, source)
}
func (s *ServerCommon) removeClient(client *ClientConn) {
s.mu.Lock()
defer s.mu.Unlock()
delete(s.clientPool, client.ClientID)
}
func (s *ServerCommon) accept() {
if s.udpListener != nil {
s.acceptUDP()
}
s.acceptTU()
}
func (s *ServerCommon) acceptTU() {
for {
select {
case <-s.stopCtx.Done():
return
default:
}
conn, err := s.listener.Accept()
if err != nil {
if s.showError {
fmt.Println("error accept:", err)
}
continue
}
var id string
for {
id = fmt.Sprintf("%s%d%d", conn.RemoteAddr().String(), time.Now().UnixNano(), rand.Int63())
s.mu.RLock()
if _, ok := s.clientPool[id]; ok {
s.mu.RUnlock()
continue
}
s.mu.RUnlock()
break
}
client := ClientConn{
ClientID: id,
ClientAddr: conn.RemoteAddr(),
tuConn: conn,
server: s,
maxReadTimeout: s.maxReadTimeout,
maxWriteTimeout: s.maxWriteTimeout,
SecretKey: s.SecretKey,
handshakeRsaKey: s.handshakeRsaKey,
msgEn: s.defaultMsgEn,
msgDe: s.defaultMsgDe,
lastHeartBeat: time.Now().Unix(),
}
client.alive.Store(true)
client.status = Status{
Alive: true,
Reason: "",
Err: nil,
}
client.stopCtx, client.stopFn = context.WithCancel(context.Background())
s.mu.Lock()
s.clientPool[id] = &client
s.mu.Unlock()
go client.readTUMessage()
}
}
func (s *ServerCommon) loadMessage() {
for {
select {
case <-s.stopCtx.Done():
var wg sync.WaitGroup
s.mu.RLock()
for _, v := range s.clientPool {
wg.Add(1)
go func() {
defer wg.Done()
v.sayGoodByeForTU()
v.alive.Store(false)
v.status = Status{
Alive: false,
Reason: "recv stop signal from server",
Err: nil,
}
v.stopFn()
s.removeClient(v)
}()
}
s.mu.RUnlock()
select {
case <-time.After(time.Second * 8):
case <-stario.WaitUntilFinished(func() error {
wg.Wait()
return nil
}):
}
if s.listener != nil {
s.listener.Close()
}
s.wg.Wait()
return
case data, ok := <-s.queue.RestoreChan():
if !ok {
continue
}
s.wg.Add(1)
go func(data starnet.MsgQueue) {
s.mu.RLock()
cc, ok := s.clientPool[data.Conn.(string)]
s.mu.RUnlock()
if !ok {
return
}
//fmt.Println("received:", float64(time.Now().UnixNano()-nowd)/1000000)
msg, err := s.sequenceDe(cc.msgDe(cc.SecretKey, data.Msg))
if err != nil {
if s.showError {
fmt.Println("server decode data error", err)
}
return
}
//fmt.Println("decoded:", float64(time.Now().UnixNano()-nowd)/1000000)
message := Message{
NetType: NET_SERVER,
ClientConn: cc,
TransferMsg: msg.(TransferMsg),
}
message.Time = time.Now()
//fmt.Println("dispatch:", float64(time.Now().UnixNano()-nowd)/1000000)
s.dispatchMsg(message)
}(data)
}
}
}
func (s *ServerCommon) sysMsg(message Message) {
switch message.Key {
case "bye":
//fmt.Println("recv stop signal from client", message.ClientConn.ClientID)
if message.TransferMsg.Type == MSG_SYS_WAIT {
message.Reply(nil)
}
message.ClientConn.alive.Store(false)
message.ClientConn.status = Status{
Alive: false,
Reason: "recv stop signal from client",
Err: nil,
}
message.ClientConn.stopFn()
case "heartbeat":
message.ClientConn.lastHeartBeat = time.Now().Unix()
message.Reply(nil)
}
}
func (s *ServerCommon) dispatchMsg(message Message) {
defer s.wg.Done()
switch message.TransferMsg.Type {
case MSG_SYS_WAIT:
fallthrough
case MSG_SYS:
s.sysMsg(message)
return
case MSG_KEY_CHANGE:
message.ClientConn.rsaDecode(message)
return
case MSG_SYS_REPLY:
fallthrough
case MSG_SYNC_REPLY:
data, ok := s.noFinSyncMsgPool.Load(message.TransferMsg.ID)
if ok {
wait := data.(WaitMsg)
wait.Reply <- message
s.noFinSyncMsgPool.Delete(message.TransferMsg.ID)
return
}
//just throw
return
//fallthrough
default:
}
callFn := func(fn func(*Message)) {
fn(&message)
}
fn, ok := s.linkFns[message.TransferMsg.Key]
if ok {
callFn(fn)
}
if s.defaultFns != nil {
callFn(s.defaultFns)
}
}
func (s *ServerCommon) send(c *ClientConn, msg TransferMsg) (WaitMsg, error) {
if s.udpListener != nil {
return s.sendUDP(c, msg)
}
return s.sendTU(c, msg)
}
func (s *ServerCommon) sendTU(c *ClientConn, msg TransferMsg) (WaitMsg, error) {
var wait WaitMsg
if msg.Type != MSG_SYNC_REPLY && msg.Type != MSG_KEY_CHANGE && msg.Type != MSG_SYS_REPLY || msg.ID == 0 {
msg.ID = atomic.AddUint64(&s.msgID, 1)
}
data, err := s.sequenceEn(msg)
if err != nil {
return WaitMsg{}, err
}
data = c.msgEn(c.SecretKey, data)
data = s.queue.BuildMessage(data)
if c.maxWriteTimeout.Seconds() != 0 {
c.tuConn.SetWriteDeadline(time.Now().Add(c.maxWriteTimeout))
}
_, err = c.tuConn.Write(data)
//fmt.Println("resend:", float64(time.Now().UnixNano()-nowd)/1000000)
if err == nil && (msg.Type == MSG_SYNC_ASK || msg.Type == MSG_SYS_WAIT) {
wait.Time = time.Now()
wait.TransferMsg = msg
wait.Reply = make(chan Message, 1)
s.noFinSyncMsgPool.Store(msg.ID, wait)
}
return wait, err
}
func (s *ServerCommon) Send(c *ClientConn, key string, value MsgVal) error {
_, err := s.send(c, TransferMsg{
Key: key,
Value: value,
Type: MSG_ASYNC,
})
return err
}
func (s *ServerCommon) sendWait(c *ClientConn, msg TransferMsg, timeout time.Duration) (Message, error) {
data, err := s.send(c, msg)
if err != nil {
return Message{}, err
}
if timeout.Seconds() == 0 {
msg, ok := <-data.Reply
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
select {
case <-time.After(timeout):
close(data.Reply)
s.noFinSyncMsgPool.Delete(data.TransferMsg.ID)
return Message{}, os.ErrDeadlineExceeded
case <-s.stopCtx.Done():
return Message{}, errors.New("Service shutdown")
case msg, ok := <-data.Reply:
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
}
func (s *ServerCommon) SendCtx(ctx context.Context, c *ClientConn, key string, value MsgVal) (Message, error) {
return s.sendCtx(c, TransferMsg{
Key: key,
Value: value,
Type: MSG_SYNC_ASK,
}, ctx)
}
func (s *ServerCommon) sendCtx(c *ClientConn, msg TransferMsg, ctx context.Context) (Message, error) {
data, err := s.send(c, msg)
if err != nil {
return Message{}, err
}
if ctx == nil {
ctx = context.Background()
}
select {
case <-ctx.Done():
close(data.Reply)
s.noFinSyncMsgPool.Delete(data.TransferMsg.ID)
return Message{}, os.ErrClosed
case <-s.stopCtx.Done():
return Message{}, errors.New("Service shutdown")
case msg, ok := <-data.Reply:
if !ok {
return msg, os.ErrInvalid
}
return msg, nil
}
}
func (s *ServerCommon) SendWait(c *ClientConn, key string, value MsgVal, timeout time.Duration) (Message, error) {
return s.sendWait(c, TransferMsg{
Key: key,
Value: value,
Type: MSG_SYNC_ASK,
}, timeout)
}
func (s *ServerCommon) SendWaitObj(c *ClientConn, key string, value interface{}, timeout time.Duration) (Message, error) {
data, err := s.sequenceEn(value)
if err != nil {
return Message{}, err
}
return s.SendWait(c, key, data, timeout)
}
func (s *ServerCommon) SendObjCtx(ctx context.Context, c *ClientConn, key string, val interface{}) (Message, error) {
data, err := s.sequenceEn(val)
if err != nil {
return Message{}, err
}
return s.sendCtx(c, TransferMsg{
Key: key,
Value: data,
Type: MSG_SYNC_ASK,
}, ctx)
}
func (s *ServerCommon) SendObj(c *ClientConn, key string, val interface{}) error {
data, err := encode(val)
if err != nil {
return err
}
_, err = s.send(c, TransferMsg{
Key: key,
Value: data,
Type: MSG_ASYNC,
})
return err
}
func (s *ServerCommon) Reply(m Message, value MsgVal) error {
return m.Reply(value)
}
//for udp below
func (s *ServerCommon) ListenUDP(network string, addr string) error {
udpAddr, err := net.ResolveUDPAddr(network, addr)
if err != nil {
return err
}
listener, err := net.ListenUDP(network, udpAddr)
if err != nil {
return err
}
s.alive.Store(true)
s.status.Alive = true
s.udpListener = listener
go s.accept()
go s.monitorPool()
go s.loadMessage()
return nil
}
func (s *ServerCommon) acceptUDP() {
for {
select {
case <-s.stopCtx.Done():
return
default:
}
if s.maxReadTimeout.Seconds() > 0 {
s.udpListener.SetReadDeadline(time.Now().Add(s.maxReadTimeout))
}
data := make([]byte, 4096)
num, addr, err := s.udpListener.ReadFromUDP(data)
id := addr.String()
//fmt.Println("s recv udp:", float64(time.Now().UnixNano()-nowd)/1000000)
s.mu.RLock()
if _, ok := s.clientPool[id]; !ok {
s.mu.RUnlock()
client := ClientConn{
ClientID: id,
ClientAddr: addr,
server: s,
maxReadTimeout: s.maxReadTimeout,
maxWriteTimeout: s.maxWriteTimeout,
SecretKey: s.SecretKey,
handshakeRsaKey: s.handshakeRsaKey,
msgEn: s.defaultMsgEn,
msgDe: s.defaultMsgDe,
lastHeartBeat: time.Now().Unix(),
}
client.stopCtx, client.stopFn = context.WithCancel(context.Background())
s.mu.Lock()
s.clientPool[id] = &client
s.mu.Unlock()
} else {
s.mu.RUnlock()
}
if err == os.ErrDeadlineExceeded {
if num != 0 {
s.pushMessage(data[:num], id)
}
continue
}
if err != nil {
continue
}
s.pushMessage(data[:num], id)
}
}
func (s *ServerCommon) sendUDP(c *ClientConn, msg TransferMsg) (WaitMsg, error) {
var wait WaitMsg
if msg.Type != MSG_SYNC_REPLY && msg.Type != MSG_KEY_CHANGE && msg.Type != MSG_SYS_REPLY || msg.ID == 0 {
msg.ID = uint64(time.Now().UnixNano()) + rand.Uint64() + rand.Uint64()
}
data, err := s.sequenceEn(msg)
if err != nil {
return WaitMsg{}, err
}
data = c.msgEn(c.SecretKey, data)
data = s.queue.BuildMessage(data)
if c.maxWriteTimeout.Seconds() != 0 {
s.udpListener.SetWriteDeadline(time.Now().Add(c.maxWriteTimeout))
}
_, err = s.udpListener.WriteTo(data, c.ClientAddr)
if err == nil && (msg.Type == MSG_SYNC_ASK || msg.Type == MSG_SYS_WAIT) {
wait.Time = time.Now()
wait.TransferMsg = msg
wait.Reply = make(chan Message, 1)
s.noFinSyncMsgPool.Store(msg.ID, wait)
}
return wait, err
}
func (s *ServerCommon) StopMonitorChan() <-chan struct{} {
return s.stopCtx.Done()
}
func (s *ServerCommon) Status() Status {
return s.status
}
func (s *ServerCommon) GetSecretKey() []byte {
return s.SecretKey
}
func (s *ServerCommon) SetSecretKey(key []byte) {
s.SecretKey = key
}
func (s *ServerCommon) RsaPrivKey() []byte {
return s.handshakeRsaKey
}
func (s *ServerCommon) SetRsaPrivKey(key []byte) {
s.handshakeRsaKey = key
}
func (s *ServerCommon) GetClient(id string) *ClientConn {
s.mu.RLock()
defer s.mu.RUnlock()
c, ok := s.clientPool[id]
if !ok {
return nil
}
return c
}
func (s *ServerCommon) GetClientLists() []*ClientConn {
s.mu.RLock()
defer s.mu.RUnlock()
var list []*ClientConn = make([]*ClientConn, 0, len(s.clientPool))
for _, v := range s.clientPool {
list = append(list, v)
}
return list
}
func (s *ServerCommon) GetClientAddrs() []net.Addr {
s.mu.RLock()
defer s.mu.RUnlock()
var list = make([]net.Addr, 0, len(s.clientPool))
for _, v := range s.clientPool {
list = append(list, v.ClientAddr)
}
return list
}
func (s *ServerCommon) GetSequenceEn() func(interface{}) ([]byte, error) {
return s.sequenceEn
}
func (s *ServerCommon) SetSequenceEn(fn func(interface{}) ([]byte, error)) {
s.sequenceEn = fn
}
func (s *ServerCommon) GetSequenceDe() func([]byte) (interface{}, error) {
return s.sequenceDe
}
func (s *ServerCommon) SetSequenceDe(fn func([]byte) (interface{}, error)) {
s.sequenceDe = fn
}
func (s *ServerCommon) HeartbeatTimeoutSec() int64 {
return s.maxHeartbeatLostSeconds
}
func (s *ServerCommon) SetHeartbeatTimeoutSec(sec int64) {
s.maxHeartbeatLostSeconds = sec
}

@ -0,0 +1,47 @@
package notify
import (
"context"
"net"
"time"
)
type Server interface {
SetDefaultCommEncode(func([]byte, []byte) []byte)
SetDefaultCommDecode(func([]byte, []byte) []byte)
SetDefaultLink(func(message *Message))
SetLink(string, func(*Message))
send(c *ClientConn, msg TransferMsg) (WaitMsg, error)
sendWait(c *ClientConn, msg TransferMsg, timeout time.Duration) (Message, error)
SendObjCtx(ctx context.Context, c *ClientConn, key string, val interface{}) (Message, error)
SendObj(c *ClientConn, key string, val interface{}) error
Send(c *ClientConn, key string, value MsgVal) error
SendWait(c *ClientConn, key string, value MsgVal, timeout time.Duration) (Message, error)
SendWaitObj(c *ClientConn, key string, value interface{}, timeout time.Duration) (Message, error)
SendCtx(ctx context.Context, c *ClientConn, key string, value MsgVal) (Message, error)
Reply(m Message, value MsgVal) error
pushMessage([]byte, string)
removeClient(client *ClientConn)
Listen(network string, addr string) error
Stop() error
StopMonitorChan() <-chan struct{}
Status() Status
GetSecretKey() []byte
SetSecretKey(key []byte)
RsaPrivKey() []byte
SetRsaPrivKey([]byte)
GetClient(id string) *ClientConn
GetClientLists() []*ClientConn
GetClientAddrs() []net.Addr
GetSequenceEn() func(interface{}) ([]byte, error)
SetSequenceEn(func(interface{}) ([]byte, error))
GetSequenceDe() func([]byte) (interface{}, error)
SetSequenceDe(func([]byte) (interface{}, error))
ShowError(bool)
HeartbeatTimeoutSec() int64
SetHeartbeatTimeoutSec(int64)
}

103
vendor/b612.me/starcrypto/crc32a.go generated vendored

@ -0,0 +1,103 @@
package starcrypto
import (
"encoding/binary"
"encoding/hex"
)
// CheckCRC32A calculates CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum.
// This function will produce the same results as following PHP code:
// hexdec(hash('crc32', $data))
func CheckCRC32A(data []byte) uint32 {
b := digest(data)
return binary.BigEndian.Uint32(b)
}
func Crc32A(data []byte) []byte {
return digest(data)
}
// Crc32AStr is a convenience function that outputs CRC32A (ITU I.363.5 algorithm, popularized by BZIP2) checksum as a hex string.
// This function will produce the same results as following PHP code:
// hash('crc32', $data)
func Crc32AStr(data []byte) string {
b := digest(data)
return hex.EncodeToString(b)
}
// digest performs checksum calculation for each byte of provided data and returns digest in form of byte array.
func digest(data []byte) []byte {
var crc uint32
var digest = make([]byte, 4)
crc = ^crc
for i := 0; i < len(data); i++ {
crc = (crc << 8) ^ table[(crc>>24)^(uint32(data[i])&0xff)]
}
crc = ^crc
digest[3] = byte((crc >> 24) & 0xff)
digest[2] = byte((crc >> 16) & 0xff)
digest[1] = byte((crc >> 8) & 0xff)
digest[0] = byte(crc & 0xff)
return digest
}
// table is the pre-generated 0x04C11DB7 polynominal used for CRC32A.
var table = [256]uint32{
0x0,
0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4,
}

1250
vendor/b612.me/starcrypto/crypto.go generated vendored

File diff suppressed because it is too large Load Diff

149
vendor/b612.me/stario/circle.go generated vendored

@ -0,0 +1,149 @@
package stario
import (
"errors"
"fmt"
"io"
"os"
"runtime"
"sync"
"sync/atomic"
"time"
)
type StarBuffer struct {
io.Reader
io.Writer
io.Closer
datas []byte
pStart uint64
pEnd uint64
cap uint64
isClose atomic.Value
isEnd atomic.Value
rmu sync.Mutex
wmu sync.Mutex
}
func NewStarBuffer(cap uint64) *StarBuffer {
rtnBuffer := new(StarBuffer)
rtnBuffer.cap = cap
rtnBuffer.datas = make([]byte, cap)
rtnBuffer.isClose.Store(false)
rtnBuffer.isEnd.Store(false)
return rtnBuffer
}
func (star *StarBuffer) Free() uint64 {
return star.cap - star.Len()
}
func (star *StarBuffer) Cap() uint64 {
return star.cap
}
func (star *StarBuffer) Len() uint64 {
if star.pEnd >= star.pStart {
return star.pEnd - star.pStart
}
return star.pEnd - star.pStart + star.cap
}
func (star *StarBuffer) getByte() (byte, error) {
if star.isClose.Load().(bool) || (star.Len() == 0 && star.isEnd.Load().(bool)) {
return 0, io.EOF
}
if star.Len() == 0 {
return 0, os.ErrNotExist
}
nowPtr := star.pStart
nextPtr := star.pStart + 1
if nextPtr >= star.cap {
nextPtr = 0
}
data := star.datas[nowPtr]
ok := atomic.CompareAndSwapUint64(&star.pStart, nowPtr, nextPtr)
if !ok {
return 0, os.ErrInvalid
}
return data, nil
}
func (star *StarBuffer) putByte(data byte) error {
if star.isClose.Load().(bool) {
return io.EOF
}
nowPtr := star.pEnd
kariEnd := nowPtr + 1
if kariEnd == star.cap {
kariEnd = 0
}
if kariEnd == atomic.LoadUint64(&star.pStart) {
for {
time.Sleep(time.Microsecond)
runtime.Gosched()
if kariEnd != atomic.LoadUint64(&star.pStart) {
break
}
}
}
star.datas[nowPtr] = data
if ok := atomic.CompareAndSwapUint64(&star.pEnd, nowPtr, kariEnd); !ok {
return os.ErrInvalid
}
return nil
}
func (star *StarBuffer) Close() error {
star.isClose.Store(true)
return nil
}
func (star *StarBuffer) Read(buf []byte) (int, error) {
if star.isClose.Load().(bool) || (star.Len() == 0 && star.isEnd.Load().(bool)) {
return 0, io.EOF
}
if buf == nil {
return 0, errors.New("buffer is nil")
}
star.rmu.Lock()
defer star.rmu.Unlock()
var sum int = 0
for i := 0; i < len(buf); i++ {
data, err := star.getByte()
if err != nil {
if err == io.EOF {
return sum, err
}
if err == os.ErrNotExist {
i--
continue
}
return sum, nil
}
buf[i] = data
sum++
}
return sum, nil
}
func (star *StarBuffer) Write(bts []byte) (int, error) {
if bts == nil && !star.isEnd.Load().(bool) {
star.isEnd.Store(true)
return 0, nil
}
if bts == nil || star.isClose.Load().(bool) {
return 0, io.EOF
}
star.wmu.Lock()
defer star.wmu.Unlock()
var sum = 0
for i := 0; i < len(bts); i++ {
err := star.putByte(bts[i])
if err != nil {
fmt.Println("Write bts err:", err)
return sum, err
}
sum++
}
return sum, nil
}

55
vendor/b612.me/stario/fn.go generated vendored

@ -0,0 +1,55 @@
package stario
import (
"errors"
"time"
)
var ERR_TIMEOUT = errors.New("TIME OUT")
func WaitUntilTimeout(tm time.Duration, fn func(chan struct{}) error) error {
var err error
finished := make(chan struct{})
imout := make(chan struct{})
go func() {
err = fn(imout)
finished <- struct{}{}
}()
select {
case <-finished:
return err
case <-time.After(tm):
close(imout)
return ERR_TIMEOUT
}
}
func WaitUntilFinished(fn func() error) <-chan error {
finished := make(chan error)
go func() {
err := fn()
finished <- err
}()
return finished
}
func WaitUntilTimeoutFinished(tm time.Duration, fn func(chan struct{}) error) <-chan error {
var err error
finished := make(chan struct{})
result := make(chan error)
imout := make(chan struct{})
go func() {
err = fn(imout)
finished <- struct{}{}
}()
go func() {
select {
case <-finished:
result <- err
case <-time.After(tm):
close(imout)
result <- ERR_TIMEOUT
}
}()
return result
}

411
vendor/b612.me/stario/io.go generated vendored

@ -0,0 +1,411 @@
package stario
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"golang.org/x/crypto/ssh/terminal"
)
type InputMsg struct {
msg string
err error
skipSliceSigErr bool
}
func Passwd(hint string, defaultVal string) InputMsg {
return passwd(hint, defaultVal, "")
}
func PasswdWithMask(hint string, defaultVal string, mask string) InputMsg {
return passwd(hint, defaultVal, mask)
}
func MessageBoxRaw(hint string, defaultVal string) InputMsg {
return messageBox(hint, defaultVal)
}
func messageBox(hint string, defaultVal string) InputMsg {
var ioBuf []rune
if hint != "" {
fmt.Print(hint)
}
if strings.Index(hint, "\n") >= 0 {
hint = strings.TrimSpace(hint[strings.LastIndex(hint, "\n"):])
}
fd := int(os.Stdin.Fd())
state, err := terminal.MakeRaw(fd)
if err != nil {
return InputMsg{msg: "", err: err}
}
defer fmt.Println()
defer terminal.Restore(fd, state)
inputReader := bufio.NewReader(os.Stdin)
for {
b, _, err := inputReader.ReadRune()
if err != nil {
return InputMsg{msg: "", err: err}
}
if b == 0x0d {
strValue := strings.TrimSpace(string(ioBuf))
if len(strValue) == 0 {
strValue = defaultVal
}
return InputMsg{msg: strValue, err: err}
}
if b == 0x08 || b == 0x7F {
if len(ioBuf) > 0 {
ioBuf = ioBuf[:len(ioBuf)-1]
}
fmt.Print("\r")
for i := 0; i < len(ioBuf)+2+len(hint); i++ {
fmt.Print(" ")
}
} else {
ioBuf = append(ioBuf, b)
}
fmt.Print("\r")
if hint != "" {
fmt.Print(hint)
}
fmt.Print(string(ioBuf))
}
}
func passwd(hint string, defaultVal string, mask string) InputMsg {
var ioBuf []rune
if hint != "" {
fmt.Print(hint)
}
if strings.Index(hint, "\n") >= 0 {
hint = strings.TrimSpace(hint[strings.LastIndex(hint, "\n"):])
}
fd := int(os.Stdin.Fd())
state, err := terminal.MakeRaw(fd)
if err != nil {
return InputMsg{msg: "", err: err}
}
defer fmt.Println()
defer terminal.Restore(fd, state)
inputReader := bufio.NewReader(os.Stdin)
for {
b, _, err := inputReader.ReadRune()
if err != nil {
return InputMsg{msg: "", err: err}
}
if b == 0x0d {
strValue := strings.TrimSpace(string(ioBuf))
if len(strValue) == 0 {
strValue = defaultVal
}
return InputMsg{msg: strValue, err: err}
}
if b == 0x08 || b == 0x7F {
if len(ioBuf) > 0 {
ioBuf = ioBuf[:len(ioBuf)-1]
}
fmt.Print("\r")
for i := 0; i < len(ioBuf)+2+len(hint); i++ {
fmt.Print(" ")
}
} else {
ioBuf = append(ioBuf, b)
}
fmt.Print("\r")
if hint != "" {
fmt.Print(hint)
}
for i := 0; i < len(ioBuf); i++ {
fmt.Print(mask)
}
}
}
func MessageBox(hint string, defaultVal string) InputMsg {
if hint != "" {
fmt.Print(hint)
}
inputReader := bufio.NewReader(os.Stdin)
str, err := inputReader.ReadString('\n')
if err != nil {
return InputMsg{msg: str, err: err}
}
str = strings.TrimSpace(str)
if len(str) == 0 {
str = defaultVal
}
return InputMsg{msg: str, err: err}
}
func (im InputMsg) IgnoreSliceParseError(i bool) InputMsg {
im.skipSliceSigErr = i
return im
}
func (im InputMsg) String() (string, error) {
if im.err != nil {
return "", im.err
}
return im.msg, nil
}
func (im InputMsg) MustString() string {
res, _ := im.String()
return res
}
func (im InputMsg) SliceString(sep string) ([]string, error) {
if im.err != nil {
return nil, im.err
}
return strings.Split(im.msg, sep), nil
}
func (im InputMsg) MustSliceString(sep string) []string {
res, _ := im.SliceString(sep)
return res
}
func (im InputMsg) sliceFn(sep string, fn func(string) (interface{}, error)) ([]interface{}, error) {
var res []interface{}
data, err := im.SliceString(sep)
if err != nil {
return res, err
}
for _, v := range data {
code, err := fn(v)
if err != nil && !im.skipSliceSigErr {
return nil, err
} else if err == nil {
res = append(res, code)
}
}
return res, nil
}
func (im InputMsg) Int() (int, error) {
if im.err != nil {
return 0, im.err
}
return strconv.Atoi(im.msg)
}
func (im InputMsg) SliceInt(sep string) ([]int, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.Atoi(v)
})
var res []int
for _, v := range data {
res = append(res, v.(int))
}
return res, err
}
func (im InputMsg) MustSliceInt(sep string) []int {
res, _ := im.SliceInt(sep)
return res
}
func (im InputMsg) MustInt() int {
res, _ := im.Int()
return res
}
func (im InputMsg) Int64() (int64, error) {
if im.err != nil {
return 0, im.err
}
return strconv.ParseInt(im.msg, 10, 64)
}
func (im InputMsg) MustInt64() int64 {
res, _ := im.Int64()
return res
}
func (im InputMsg) SliceInt64(sep string) ([]int64, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.ParseInt(v, 10, 64)
})
var res []int64
for _, v := range data {
res = append(res, v.(int64))
}
return res, err
}
func (im InputMsg) MustSliceInt64(sep string) []int64 {
res, _ := im.SliceInt64(sep)
return res
}
func (im InputMsg) Uint64() (uint64, error) {
if im.err != nil {
return 0, im.err
}
return strconv.ParseUint(im.msg, 10, 64)
}
func (im InputMsg) MustUint64() uint64 {
res, _ := im.Uint64()
return res
}
func (im InputMsg) SliceUint64(sep string) ([]uint64, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.ParseUint(v, 10, 64)
})
var res []uint64
for _, v := range data {
res = append(res, v.(uint64))
}
return res, err
}
func (im InputMsg) MustSliceUint64(sep string) []uint64 {
res, _ := im.SliceUint64(sep)
return res
}
func (im InputMsg) Bool() (bool, error) {
if im.err != nil {
return false, im.err
}
return strconv.ParseBool(im.msg)
}
func (im InputMsg) MustBool() bool {
res, _ := im.Bool()
return res
}
func (im InputMsg) SliceBool(sep string) ([]bool, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.ParseBool(v)
})
var res []bool
for _, v := range data {
res = append(res, v.(bool))
}
return res, err
}
func (im InputMsg) MustSliceBool(sep string) []bool {
res, _ := im.SliceBool(sep)
return res
}
func (im InputMsg) Float64() (float64, error) {
if im.err != nil {
return 0, im.err
}
return strconv.ParseFloat(im.msg, 64)
}
func (im InputMsg) MustFloat64() float64 {
res, _ := im.Float64()
return res
}
func (im InputMsg) SliceFloat64(sep string) ([]float64, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.ParseFloat(v, 64)
})
var res []float64
for _, v := range data {
res = append(res, v.(float64))
}
return res, err
}
func (im InputMsg) MustSliceFloat64(sep string) []float64 {
res, _ := im.SliceFloat64(sep)
return res
}
func (im InputMsg) Float32() (float32, error) {
if im.err != nil {
return 0, im.err
}
res, err := strconv.ParseFloat(im.msg, 32)
return float32(res), err
}
func (im InputMsg) MustFloat32() float32 {
res, _ := im.Float32()
return res
}
func (im InputMsg) SliceFloat32(sep string) ([]float32, error) {
data, err := im.sliceFn(sep, func(v string) (interface{}, error) {
return strconv.ParseFloat(v, 32)
})
var res []float32
for _, v := range data {
res = append(res, v.(float32))
}
return res, err
}
func (im InputMsg) MustSliceFloat32(sep string) []float32 {
res, _ := im.SliceFloat32(sep)
return res
}
func YesNo(hint string, defaults bool) bool {
for {
res := strings.ToUpper(MessageBox(hint, "").MustString())
if res == "" {
return defaults
}
res = res[0:1]
if res == "Y" {
return true
} else if res == "N" {
return false
}
}
}
func StopUntil(hint string, trigger string, repeat bool) error {
pressLen := len([]rune(trigger))
if trigger == "" {
pressLen = 1
}
fd := int(os.Stdin.Fd())
if hint != "" {
fmt.Print(hint)
}
state, err := terminal.MakeRaw(fd)
if err != nil {
return err
}
defer terminal.Restore(fd, state)
inputReader := bufio.NewReader(os.Stdin)
//ioBuf := make([]byte, pressLen)
i := 0
for {
b, _, err := inputReader.ReadRune()
if err != nil {
return err
}
if trigger == "" {
break
}
if b == []rune(trigger)[i] {
i++
if i == pressLen {
break
}
continue
}
i = 0
if hint != "" && repeat {
fmt.Print("\r\n")
fmt.Print(hint)
}
}
return nil
}

55
vendor/b612.me/stario/sync.go generated vendored

@ -0,0 +1,55 @@
package stario
import (
"sync"
"sync/atomic"
"time"
)
type WaitGroup struct {
wg *sync.WaitGroup
maxCount uint32
allCount uint32
}
func NewWaitGroup(maxCount int) WaitGroup {
return WaitGroup{wg: &sync.WaitGroup{}, maxCount: uint32(maxCount)}
}
func (swg *WaitGroup) Add(delta int) {
var Udelta uint32
if delta < 0 {
Udelta = uint32(-delta - 1)
} else {
Udelta = uint32(delta)
}
for {
allC := atomic.LoadUint32(&swg.allCount)
if atomic.LoadUint32(&swg.maxCount) == 0 || atomic.LoadUint32(&swg.maxCount) >= allC+uint32(delta) {
if delta < 0 {
atomic.AddUint32(&swg.allCount, ^uint32(Udelta))
} else {
atomic.AddUint32(&swg.allCount, uint32(Udelta))
}
break
}
time.Sleep(time.Microsecond)
}
swg.wg.Add(delta)
}
func (swg *WaitGroup) Done() {
swg.Add(-1)
}
func (swg *WaitGroup) Wait() {
swg.wg.Wait()
}
func (swg *WaitGroup) GetMaxWaitNum() int {
return int(atomic.LoadUint32(&swg.maxCount))
}
func (swg *WaitGroup) SetMaxWaitNum(num int) {
atomic.AddUint32(&swg.maxCount, uint32(num))
}

284
vendor/b612.me/starlog/archive.go generated vendored

@ -0,0 +1,284 @@
package starlog
import (
"errors"
"os"
"path/filepath"
"time"
"b612.me/staros"
"b612.me/starmap"
)
var archMap starmap.StarMapKV
func init() {
archMap = starmap.NewStarMap()
}
type Archive interface {
ShouldArchiveNow(string, os.FileInfo) bool
NextLogFilePath(string, os.FileInfo) string
Interval() int64
HookBeforArchive() func(string, os.FileInfo) error
HookAfterArchive() func(string, string, os.FileInfo) error
}
type logfileinfo struct {
fullpath string
pointer *os.File
}
func SetLogFile(path string, logger *StarLogger, appendMode bool) error {
var fileMode int
if appendMode {
fileMode = os.O_APPEND | os.O_CREATE | os.O_WRONLY
} else {
fileMode = os.O_CREATE | os.O_WRONLY | os.O_TRUNC
}
fullpath, err := filepath.Abs(path)
if err != nil {
return err
}
if !appendMode && staros.Exists(fullpath) {
os.Remove(fullpath)
}
fp, err := os.OpenFile(fullpath, fileMode, 0644)
if err != nil {
return err
}
if archMap.MustGet(logger.logcore.id) != nil {
logger.SetSwitching(true)
err := archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Close()
if err != nil {
logger.logcore.output = nil
logger.SetSwitching(false)
return err
}
err = archMap.Delete(logger.logcore.id)
if err != nil {
logger.logcore.output = nil
logger.SetSwitching(false)
return err
}
}
err = archMap.Store(logger.logcore.id, logfileinfo{
fullpath: fullpath,
pointer: fp,
})
if err != nil {
fp.Close()
logger.logcore.output = nil
logger.SetSwitching(false)
return err
}
logger.SetSwitching(true)
logger.logcore.output = fp
logger.SetSwitching(false)
return nil
}
func CloseWithSwitching(logger *StarLogger) error {
if archMap.MustGet(logger.logcore.id) != nil {
logger.SetSwitching(true)
err := archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Close()
if err != nil {
logger.logcore.output = nil
return err
}
err = archMap.Delete(logger.logcore.id)
if err != nil {
return err
}
}
return nil
}
func Close(logger *StarLogger) error {
defer logger.SetSwitching(false)
return CloseWithSwitching(logger)
}
func GetLogFileInfo(logger *StarLogger) (os.FileInfo, error) {
if archMap.MustGet(logger.logcore.id) != nil {
return archMap.MustGet(logger.logcore.id).(logfileinfo).pointer.Stat()
}
return nil, errors.New("logger don't have a register logfile")
}
func StartArchive(logger *StarLogger, arch Archive) error {
if archMap.MustGet("arch"+logger.logcore.id) != nil {
return errors.New("already running")
}
stopChan := make(chan int)
archMap.Store("arch"+logger.logcore.id, stopChan)
go func(stopChan chan int, arch Archive, logger *StarLogger) {
for {
select {
case <-stopChan:
return
case <-time.After(time.Second * time.Duration(arch.Interval())):
}
fileinfo, err := GetLogFileInfo(logger)
if err != nil {
logger.Errorf("cannot get log file info,reason is %v\n", err)
continue
}
if archMap.MustGet(logger.logcore.id) == nil {
logger.Errorf("cannot get log core info from the map:no such keys\n")
continue
}
fullpath := archMap.MustGet(logger.logcore.id).(logfileinfo).fullpath
if !arch.ShouldArchiveNow(fullpath, fileinfo) {
continue
}
newLogPath := arch.NextLogFilePath(fullpath, fileinfo)
if arch.HookBeforArchive() != nil {
if err := arch.HookBeforArchive()(fullpath, fileinfo); err != nil {
logger.Errorf("error occur while executing hook before archive,detail is %v\n", err)
continue
}
}
if err := SetLogFile(newLogPath, logger, false); err != nil {
logger.Errorf("error occur while executing coverting new log file,detail is %v\n", err)
continue
} else {
logger.Debugln("Set Log Success")
}
fileinfo, err = GetLogFileInfo(logger)
if err != nil {
logger.Errorf("cannot get new log core info from the map:no such keys\n")
continue
}
if arch.HookAfterArchive() != nil {
if err := arch.HookAfterArchive()(fullpath, newLogPath, fileinfo); err != nil {
logger.Errorf("error occur while executing hook after archive,detail is %v\n", err)
continue
}
}
}
}(stopChan, arch, logger)
return nil
}
func IsArchiveRun(logger *StarLogger) bool {
if archMap.MustGet("arch"+logger.logcore.id) == nil {
return false
}
return true
}
func StopArchive(logger *StarLogger) {
if archMap.MustGet("arch"+logger.logcore.id) == nil {
return
}
archMap.MustGet("arch" + logger.logcore.id).(chan int) <- 1
}
type ArchiveByDate struct {
interval int64
checkInterval int64
newFileNameStyle string
hookBefor func(string, os.FileInfo) error
hookAfter func(string, string, os.FileInfo) error
}
func (abd *ArchiveByDate) ShouldArchiveNow(fullpath string, info os.FileInfo) bool {
if time.Now().Unix()-staros.GetFileCreationTime(info).Unix() > abd.interval {
return true
}
return false
}
func (abd *ArchiveByDate) NextLogFilePath(oldpath string, info os.FileInfo) string {
dir := filepath.Dir(oldpath)
newName := time.Now().Format(abd.newFileNameStyle)
return filepath.Join(dir, newName)
}
func (abd *ArchiveByDate) Interval() int64 {
return abd.checkInterval
}
func (abd *ArchiveByDate) HookBeforArchive() func(string, os.FileInfo) error {
return abd.hookBefor
}
func (abd *ArchiveByDate) HookAfterArchive() func(string, string, os.FileInfo) error {
return abd.hookAfter
}
func (abd *ArchiveByDate) SetHookBeforArchive(f func(string, os.FileInfo) error) {
abd.hookBefor = f
}
func (abd *ArchiveByDate) SetHookAfterArchive(f func(string, string, os.FileInfo) error) {
abd.hookAfter = f
}
func NewArchiveByDate(archInterval int64, checkInterval int64, fileStyle string, hookbefor func(string, os.FileInfo) error, hookafter func(string, string, os.FileInfo) error) *ArchiveByDate {
return &ArchiveByDate{
interval: archInterval,
checkInterval: checkInterval,
newFileNameStyle: fileStyle,
hookBefor: hookbefor,
hookAfter: hookafter,
}
}
type ArchiveBySize struct {
size int64
checkInterval int64
newFileNameStyle string
hookBefor func(string, os.FileInfo) error
hookAfter func(string, string, os.FileInfo) error
}
func (abd *ArchiveBySize) ShouldArchiveNow(fullpath string, info os.FileInfo) bool {
if info.Size() > abd.size {
return true
}
return false
}
func (abd *ArchiveBySize) NextLogFilePath(oldpath string, info os.FileInfo) string {
dir := filepath.Dir(oldpath)
newName := time.Now().Format(abd.newFileNameStyle)
return filepath.Join(dir, newName)
}
func (abd *ArchiveBySize) Interval() int64 {
return abd.checkInterval
}
func (abd *ArchiveBySize) HookBeforArchive() func(string, os.FileInfo) error {
return abd.hookBefor
}
func (abd *ArchiveBySize) HookAfterArchive() func(string, string, os.FileInfo) error {
return abd.hookAfter
}
func (abd *ArchiveBySize) SetHookBeforArchive(f func(string, os.FileInfo) error) {
abd.hookBefor = f
}
func (abd *ArchiveBySize) SetHookAfterArchive(f func(string, string, os.FileInfo) error) {
abd.hookAfter = f
}
func NewArchiveBySize(size int64, checkInterval int64, fileStyle string, hookbefor func(string, os.FileInfo) error, hookafter func(string, string, os.FileInfo) error) *ArchiveBySize {
return &ArchiveBySize{
size: size,
checkInterval: checkInterval,
newFileNameStyle: fileStyle,
hookBefor: hookbefor,
hookAfter: hookafter,
}
}

603
vendor/b612.me/starlog/color.go generated vendored

@ -0,0 +1,603 @@
package starlog
import (
"fmt"
"io"
"os"
"strconv"
"strings"
"sync"
"b612.me/starlog/colorable"
"b612.me/starlog/isatty"
)
var (
// NoColor defines if the output is colorized or not. It's dynamically set to
// false or true based on the stdout's file descriptor referring to a terminal
// or not. This is a global option and affects all colors. For more control
// over each color block use the methods DisableColor() individually.
NoColor = os.Getenv("TERM") == "dumb" ||
(!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
// Output defines the standard output of the print functions. By default
// os.Stdout is used.
Output = colorable.NewColorableStdout()
// Error defines a color supporting writer for os.Stderr.
Errors = colorable.NewColorableStderr()
// colorsCache is used to reduce the count of created Color objects and
// allows to reuse already created objects with required Attr.
colorsCache = make(map[Attr]*Color)
colorsCacheMu sync.Mutex // protects colorsCache
)
// Color defines a custom color object which is defined by SGR parameters.
type Color struct {
params []Attr
noColor *bool
}
// Attr defines a single SGR Code
type Attr int
const escape = "\x1b"
// Base attributes
const (
Reset Attr = iota
Bold
Faint
Italic
Underline
BlinkSlow
BlinkRapid
ReverseVideo
Concealed
CrossedOut
)
// Foreground text colors
const (
FgBlack Attr = iota + 30
FgRed
FgGreen
FgYellow
FgBlue
FgMagenta
FgCyan
FgWhite
)
// Foreground Hi-Intensity text colors
const (
FgHiBlack Attr = iota + 90
FgHiRed
FgHiGreen
FgHiYellow
FgHiBlue
FgHiMagenta
FgHiCyan
FgHiWhite
)
// Background text colors
const (
BgBlack Attr = iota + 40
BgRed
BgGreen
BgYellow
BgBlue
BgMagenta
BgCyan
BgWhite
)
// Background Hi-Intensity text colors
const (
BgHiBlack Attr = iota + 100
BgHiRed
BgHiGreen
BgHiYellow
BgHiBlue
BgHiMagenta
BgHiCyan
BgHiWhite
)
// New returns a newly created color object.
func NewColor(value ...Attr) *Color {
c := &Color{params: make([]Attr, 0)}
c.Add(value...)
return c
}
// Set sets the given parameters immediately. It will change the color of
// output with the given SGR parameters until color.Unset() is called.
func Set(p ...Attr) *Color {
c := NewColor(p...)
c.Set()
return c
}
// Unset resets all escape attributes and clears the output. Usually should
// be called after Set().
func Unset() {
if NoColor {
return
}
fmt.Fprintf(Output, "%s[%dm", escape, Reset)
}
// Set sets the SGR sequence.
func (c *Color) Set() *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(Output, c.format())
return c
}
func (c *Color) unset() {
if c.isNoColorSet() {
return
}
Unset()
}
func (c *Color) setWriter(w io.Writer) *Color {
if c.isNoColorSet() {
return c
}
fmt.Fprintf(w, c.format())
return c
}
func (c *Color) unsetWriter(w io.Writer) {
if c.isNoColorSet() {
return
}
if NoColor {
return
}
fmt.Fprintf(w, "%s[%dm", escape, Reset)
}
// Add is used to chain SGR parameters. Use as many as parameters to combine
// and create custom color objects. Example: Add(color.FgRed, color.Underline).
func (c *Color) Add(value ...Attr) *Color {
c.params = append(c.params, value...)
return c
}
func (c *Color) prepend(value Attr) {
c.params = append(c.params, 0)
copy(c.params[1:], c.params[0:])
c.params[0] = value
}
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprint(w, a...)
}
// Print formats using the default formats for its operands and writes to
// standard output. Spaces are added between operands when neither is a
// string. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Print(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprint(Output, a...)
}
// Fprintf formats according to a format specifier and writes to w.
// It returns the number of bytes written and any write error encountered.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintf(w, format, a...)
}
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
// This is the standard fmt.Printf() method wrapped with the given color.
func (c *Color) Printf(format string, a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintf(Output, format, a...)
}
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// On Windows, users should wrap w with colorable.NewColorable() if w is of
// type *os.File.
func (c *Color) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
c.setWriter(w)
defer c.unsetWriter(w)
return fmt.Fprintln(w, a...)
}
// Println formats using the default formats for its operands and writes to
// standard output. Spaces are always added between operands and a newline is
// appended. It returns the number of bytes written and any write error
// encountered. This is the standard fmt.Print() method wrapped with the given
// color.
func (c *Color) Println(a ...interface{}) (n int, err error) {
c.Set()
defer c.unset()
return fmt.Fprintln(Output, a...)
}
// Sprint is just like Print, but returns a string instead of printing it.
func (c *Color) Sprint(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
// Sprintln is just like Println, but returns a string instead of printing it.
func (c *Color) Sprintln(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
// Sprintf is just like Printf, but returns a string instead of printing it.
func (c *Color) Sprintf(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
// FprintFunc returns a new function that prints the passed arguments as
// colorized with color.Fprint().
func (c *Color) FprintFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprint(w, a...)
}
}
// PrintFunc returns a new function that prints the passed arguments as
// colorized with color.Print().
func (c *Color) PrintFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Print(a...)
}
}
// FprintfFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintf().
func (c *Color) FprintfFunc() func(w io.Writer, format string, a ...interface{}) {
return func(w io.Writer, format string, a ...interface{}) {
c.Fprintf(w, format, a...)
}
}
// PrintfFunc returns a new function that prints the passed arguments as
// colorized with color.Printf().
func (c *Color) PrintfFunc() func(format string, a ...interface{}) {
return func(format string, a ...interface{}) {
c.Printf(format, a...)
}
}
// FprintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Fprintln().
func (c *Color) FprintlnFunc() func(w io.Writer, a ...interface{}) {
return func(w io.Writer, a ...interface{}) {
c.Fprintln(w, a...)
}
}
// PrintlnFunc returns a new function that prints the passed arguments as
// colorized with color.Println().
func (c *Color) PrintlnFunc() func(a ...interface{}) {
return func(a ...interface{}) {
c.Println(a...)
}
}
// SprintFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprint(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output, example:
//
// put := New(FgYellow).SprintFunc()
// fmt.Fprintf(color.Output, "This is a %s", put("warning"))
func (c *Color) SprintFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprint(a...))
}
}
// SprintfFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintf(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintfFunc() func(format string, a ...interface{}) string {
return func(format string, a ...interface{}) string {
return c.wrap(fmt.Sprintf(format, a...))
}
}
// SprintlnFunc returns a new function that returns colorized strings for the
// given arguments with fmt.Sprintln(). Useful to put into or mix into other
// string. Windows users should use this in conjunction with color.Output.
func (c *Color) SprintlnFunc() func(a ...interface{}) string {
return func(a ...interface{}) string {
return c.wrap(fmt.Sprintln(a...))
}
}
// sequence returns a formatted SGR sequence to be plugged into a "\x1b[...m"
// an example output might be: "1;36" -> bold cyan
func (c *Color) sequence() string {
format := make([]string, len(c.params))
for i, v := range c.params {
format[i] = strconv.Itoa(int(v))
}
return strings.Join(format, ";")
}
// wrap wraps the s string with the colors attributes. The string is ready to
// be printed.
func (c *Color) wrap(s string) string {
if c.isNoColorSet() {
return s
}
return c.format() + s + c.unformat()
}
func (c *Color) format() string {
return fmt.Sprintf("%s[%sm", escape, c.sequence())
}
func (c *Color) unformat() string {
return fmt.Sprintf("%s[%dm", escape, Reset)
}
// DisableColor disables the color output. Useful to not change any existing
// code and still being able to output. Can be used for flags like
// "--no-color". To enable back use EnableColor() method.
func (c *Color) DisableColor() {
c.noColor = boolPtr(true)
}
// EnableColor enables the color output. Use it in conjunction with
// DisableColor(). Otherwise this method has no side effects.
func (c *Color) EnableColor() {
c.noColor = boolPtr(false)
}
func (c *Color) isNoColorSet() bool {
// check first if we have user setted action
if c.noColor != nil {
return *c.noColor
}
// if not return the global option, which is disabled by default
return NoColor
}
// Equals returns a boolean value indicating whether two colors are equal.
func (c *Color) Equals(c2 *Color) bool {
if len(c.params) != len(c2.params) {
return false
}
for _, attr := range c.params {
if !c2.attrExists(attr) {
return false
}
}
return true
}
func (c *Color) attrExists(a Attr) bool {
for _, attr := range c.params {
if attr == a {
return true
}
}
return false
}
func boolPtr(v bool) *bool {
return &v
}
func getCachedColor(p Attr) *Color {
colorsCacheMu.Lock()
defer colorsCacheMu.Unlock()
c, ok := colorsCache[p]
if !ok {
c = NewColor(p)
colorsCache[p] = c
}
return c
}
func colorPrint(format string, p Attr, a ...interface{}) {
c := getCachedColor(p)
if !strings.HasSuffix(format, "\n") {
format += "\n"
}
if len(a) == 0 {
c.Print(format)
} else {
c.Printf(format, a...)
}
}
func colorString(format string, p Attr, a ...interface{}) string {
c := getCachedColor(p)
if len(a) == 0 {
return c.SprintFunc()(format)
}
return c.SprintfFunc()(format, a...)
}
// Black is a convenient helper function to print with black foreground. A
// newline is appended to format by default.
func Black(format string, a ...interface{}) { colorPrint(format, FgBlack, a...) }
// Red is a convenient helper function to print with red foreground. A
// newline is appended to format by default.
func Red(format string, a ...interface{}) { colorPrint(format, FgRed, a...) }
// Green is a convenient helper function to print with green foreground. A
// newline is appended to format by default.
func Green(format string, a ...interface{}) { colorPrint(format, FgGreen, a...) }
// Yellow is a convenient helper function to print with yellow foreground.
// A newline is appended to format by default.
func Yellow(format string, a ...interface{}) { colorPrint(format, FgYellow, a...) }
// Blue is a convenient helper function to print with blue foreground. A
// newline is appended to format by default.
func Blue(format string, a ...interface{}) { colorPrint(format, FgBlue, a...) }
// Magenta is a convenient helper function to print with magenta foreground.
// A newline is appended to format by default.
func Magenta(format string, a ...interface{}) { colorPrint(format, FgMagenta, a...) }
// Cyan is a convenient helper function to print with cyan foreground. A
// newline is appended to format by default.
func Cyan(format string, a ...interface{}) { colorPrint(format, FgCyan, a...) }
// White is a convenient helper function to print with white foreground. A
// newline is appended to format by default.
func White(format string, a ...interface{}) { colorPrint(format, FgWhite, a...) }
// BlackString is a convenient helper function to return a string with black
// foreground.
func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
// RedString is a convenient helper function to return a string with red
// foreground.
func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
// GreenString is a convenient helper function to return a string with green
// foreground.
func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
// YellowString is a convenient helper function to return a string with yellow
// foreground.
func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
// BlueString is a convenient helper function to return a string with blue
// foreground.
func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
// MagentaString is a convenient helper function to return a string with magenta
// foreground.
func MagentaString(format string, a ...interface{}) string {
return colorString(format, FgMagenta, a...)
}
// CyanString is a convenient helper function to return a string with cyan
// foreground.
func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
// WhiteString is a convenient helper function to return a string with white
// foreground.
func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
// HiBlack is a convenient helper function to print with hi-intensity black foreground. A
// newline is appended to format by default.
func HiBlack(format string, a ...interface{}) { colorPrint(format, FgHiBlack, a...) }
// HiRed is a convenient helper function to print with hi-intensity red foreground. A
// newline is appended to format by default.
func HiRed(format string, a ...interface{}) { colorPrint(format, FgHiRed, a...) }
// HiGreen is a convenient helper function to print with hi-intensity green foreground. A
// newline is appended to format by default.
func HiGreen(format string, a ...interface{}) { colorPrint(format, FgHiGreen, a...) }
// HiYellow is a convenient helper function to print with hi-intensity yellow foreground.
// A newline is appended to format by default.
func HiYellow(format string, a ...interface{}) { colorPrint(format, FgHiYellow, a...) }
// HiBlue is a convenient helper function to print with hi-intensity blue foreground. A
// newline is appended to format by default.
func HiBlue(format string, a ...interface{}) { colorPrint(format, FgHiBlue, a...) }
// HiMagenta is a convenient helper function to print with hi-intensity magenta foreground.
// A newline is appended to format by default.
func HiMagenta(format string, a ...interface{}) { colorPrint(format, FgHiMagenta, a...) }
// HiCyan is a convenient helper function to print with hi-intensity cyan foreground. A
// newline is appended to format by default.
func HiCyan(format string, a ...interface{}) { colorPrint(format, FgHiCyan, a...) }
// HiWhite is a convenient helper function to print with hi-intensity white foreground. A
// newline is appended to format by default.
func HiWhite(format string, a ...interface{}) { colorPrint(format, FgHiWhite, a...) }
// HiBlackString is a convenient helper function to return a string with hi-intensity black
// foreground.
func HiBlackString(format string, a ...interface{}) string {
return colorString(format, FgHiBlack, a...)
}
// HiRedString is a convenient helper function to return a string with hi-intensity red
// foreground.
func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
// HiGreenString is a convenient helper function to return a string with hi-intensity green
// foreground.
func HiGreenString(format string, a ...interface{}) string {
return colorString(format, FgHiGreen, a...)
}
// HiYellowString is a convenient helper function to return a string with hi-intensity yellow
// foreground.
func HiYellowString(format string, a ...interface{}) string {
return colorString(format, FgHiYellow, a...)
}
// HiBlueString is a convenient helper function to return a string with hi-intensity blue
// foreground.
func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
// HiMagentaString is a convenient helper function to return a string with hi-intensity magenta
// foreground.
func HiMagentaString(format string, a ...interface{}) string {
return colorString(format, FgHiMagenta, a...)
}
// HiCyanString is a convenient helper function to return a string with hi-intensity cyan
// foreground.
func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
// HiWhiteString is a convenient helper function to return a string with hi-intensity white
// foreground.
func HiWhiteString(format string, a ...interface{}) string {
return colorString(format, FgHiWhite, a...)
}

@ -0,0 +1,37 @@
// +build appengine
package colorable
import (
"io"
"os"
_ "b612.me/starlog/isatty"
)
// NewColorable returns new instance of Writer which handles escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
if enabled != nil {
*enabled = true
}
return func() {}
}

@ -0,0 +1,38 @@
// +build !windows
// +build !appengine
package colorable
import (
"io"
"os"
_ "b612.me/starlog/isatty"
)
// NewColorable returns new instance of Writer which handles escape sequence.
func NewColorable(file *os.File) io.Writer {
if file == nil {
panic("nil passed instead of *os.File to NewColorable()")
}
return file
}
// NewColorableStdout returns new instance of Writer which handles escape sequence for stdout.
func NewColorableStdout() io.Writer {
return os.Stdout
}
// NewColorableStderr returns new instance of Writer which handles escape sequence for stderr.
func NewColorableStderr() io.Writer {
return os.Stderr
}
// EnableColorsStdout enable colors if possible.
func EnableColorsStdout(enabled *bool) func() {
if enabled != nil {
*enabled = true
}
return func() {}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,55 @@
package colorable
import (
"bytes"
"io"
)
// NonColorable holds writer but removes escape sequence.
type NonColorable struct {
out io.Writer
}
// NewNonColorable returns new instance of Writer which removes escape sequence from Writer.
func NewNonColorable(w io.Writer) io.Writer {
return &NonColorable{out: w}
}
// Write writes data on console
func (w *NonColorable) Write(data []byte) (n int, err error) {
er := bytes.NewReader(data)
var bw [1]byte
loop:
for {
c1, err := er.ReadByte()
if err != nil {
break loop
}
if c1 != 0x1b {
bw[0] = c1
w.out.Write(bw[:])
continue
}
c2, err := er.ReadByte()
if err != nil {
break loop
}
if c2 != 0x5b {
continue
}
var buf bytes.Buffer
for {
c, err := er.ReadByte()
if err != nil {
break loop
}
if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' {
break
}
buf.Write([]byte(string(c)))
}
}
return len(data), nil
}

296
vendor/b612.me/starlog/core.go generated vendored

@ -0,0 +1,296 @@
package starlog
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"time"
)
func generateCoreLogStr(skip int, logstr string) string {
var line int = 0
var funcname, fileName string
now := time.Now()
pc, fName, codeln, ok := runtime.Caller(skip)
if !ok {
return ""
}
line = codeln
funcname = runtime.FuncForPC(pc).Name()
funcname = filepath.Ext(funcname)
funcname = strings.TrimPrefix(funcname, ".")
fileName = filepath.Base(fName)
y, m, d := now.Date()
h, i, s := now.Clock()
micro := now.Nanosecond() / 1e3
logStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", y, m, d, h, i, s, micro)
logStr += " " + fileName + ":" + strconv.Itoa(line)
logStr += " <" + funcname + ">"
logStr += " " + logstr
return logStr
}
func (logger *starlog) build(thread string, isStd bool, isShow bool, handler func([]Attr, string), level int, logDetail string) {
logger.mu.Lock()
defer logger.mu.Unlock()
var skip, line int = 3, 0
var funcname, fileName string
now := time.Now()
if isStd {
skip++
}
if logger.showDeatilFile || logger.showFuncName {
pc, fName, codeln, ok := runtime.Caller(skip)
if !ok {
return
}
line = codeln
funcname = runtime.FuncForPC(pc).Name()
funcname = filepath.Ext(funcname)
funcname = strings.TrimPrefix(funcname, ".")
fileName = filepath.Base(fName)
}
y, m, d := now.Date()
h, i, s := now.Clock()
micro := now.Nanosecond() / 1e3
logStr := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", y, m, d, h, i, s, micro)
var cenStr string
if logger.showDeatilFile {
cenStr += " " + fileName + ":" + strconv.Itoa(line)
}
if logger.showFuncName {
cenStr += " <" + funcname + ">"
}
if logger.showThread {
cenStr += " |" + thread + "|"
}
if logger.showLevel {
cenStr += " " + `[` + levels[level] + `]`
}
if !logger.showColor || !logger.onlyColorLevel {
logStr += cenStr + " " + logDetail
} else {
logStr += logger.colorMe[level].Sprint(cenStr) + " " + logDetail
}
if isShow {
if !logger.showColor {
fmt.Print(logStr)
} else if !logger.onlyColorLevel {
//logcolor := NewColor(logger.colorList[level]...)
logger.colorMe[level].Fprint(stdScreen, logStr)
} else {
fmt.Fprint(stdScreen, logStr)
}
}
if handler != nil {
stacks.Push(logTransfer{
handlerFunc: handler,
colors: logger.colorList[level],
logStr: logStr,
})
}
if !logger.stopWriter {
logger.write(logStr)
}
}
func (logger *starlog) write(logStr string) {
if logger.output == nil || logger.stopWriter {
return
}
var count int = 0
for logger.switching {
time.Sleep(time.Millisecond * 100)
count++
if count > 50 {
return
}
}
if logger.output == nil {
return
}
logger.output.Write([]byte(logStr))
}
func (logger *starlog) print(str ...interface{}) string {
return fmt.Sprint(str...)
}
func (logger *starlog) printf(format string, str ...interface{}) string {
return fmt.Sprintf(format, str...)
}
func (logger *starlog) println(str ...interface{}) string {
return fmt.Sprintln(str...)
}
func (logger *starlog) Debug(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs)
}
func (logger *starlog) Debugf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs)
}
func (logger *starlog) Debugln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvDebug, strs)
}
func (logger *starlog) Info(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs)
}
func (logger *starlog) Infof(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs)
}
func (logger *starlog) Infoln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvInfo, strs)
}
func (logger *starlog) Notice(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs)
}
func (logger *starlog) Noticef(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs)
}
func (logger *starlog) Noticeln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvNotice, strs)
}
func (logger *starlog) Warning(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs)
}
func (logger *starlog) Warningf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs)
}
func (logger *starlog) Warningln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvWarning, strs)
}
func (logger *starlog) Error(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs)
}
func (logger *starlog) Errorf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs)
}
func (logger *starlog) Errorln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvError, strs)
}
func (logger *starlog) Critical(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs)
}
func (logger *starlog) Criticalf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs)
}
func (logger *starlog) Criticalln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvCritical, strs)
}
func (logger *starlog) Fatal(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs)
os.Exit(9)
}
func (logger *starlog) Fatalf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs)
os.Exit(9)
}
func (logger *starlog) Fatalln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvFatal, strs)
os.Exit(9)
}
func (logger *starlog) Panic(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs)
panic(str)
}
func (logger *starlog) Panicf(thread string, isStd bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs)
panic(fmt.Sprintf(format, str...))
}
func (logger *starlog) Panicln(thread string, isStd bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, logger.showStd, handler, LvPanic, strs)
panic(fmt.Sprintln(str...))
}
func (logger *starlog) Print(thread string, isStd bool, isShow bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Printf(thread string, isStd bool, isShow bool, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Println(thread string, isStd bool, isShow bool, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
if isShow {
fmt.Print(strs)
}
logger.write(strs)
}
func (logger *starlog) Log(thread string, isStd bool, isShow bool, level int, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprint(str...)
logger.build(thread, isStd, isShow, handler, level, strs)
}
func (logger *starlog) Logf(thread string, isStd bool, isShow bool, level int, handler func([]Attr, string), format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
logger.build(thread, isStd, isShow, handler, level, strs)
}
func (logger *starlog) Logln(thread string, isStd bool, isShow bool, level int, handler func([]Attr, string), str ...interface{}) {
strs := fmt.Sprintln(str...)
logger.build(thread, isStd, isShow, handler, level, strs)
}

@ -0,0 +1,2 @@
// Package isatty implements interface to isatty
package isatty

@ -0,0 +1,18 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
package isatty
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
_, err := unix.IoctlGetTermios(int(fd), unix.TIOCGETA)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

@ -0,0 +1,15 @@
// +build appengine js nacl wasm
package isatty
// IsTerminal returns true if the file descriptor is terminal which
// is always false on js and appengine classic which is a sandboxed PaaS.
func IsTerminal(fd uintptr) bool {
return false
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

@ -0,0 +1,22 @@
// +build plan9
package isatty
import (
"syscall"
)
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
path, err := syscall.Fd2path(int(fd))
if err != nil {
return false
}
return path == "/dev/cons" || path == "/mnt/term/dev/cons"
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

@ -0,0 +1,22 @@
// +build solaris
// +build !appengine
package isatty
import (
"golang.org/x/sys/unix"
)
// IsTerminal returns true if the given file descriptor is a terminal.
// see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
func IsTerminal(fd uintptr) bool {
var termio unix.Termio
err := unix.IoctlSetTermio(int(fd), unix.TCGETA, &termio)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

@ -0,0 +1,18 @@
// +build linux aix
// +build !appengine
package isatty
import "golang.org/x/sys/unix"
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
_, err := unix.IoctlGetTermios(int(fd), unix.TCGETS)
return err == nil
}
// IsCygwinTerminal return true if the file descriptor is a cygwin or msys2
// terminal. This is also always false on this environment.
func IsCygwinTerminal(fd uintptr) bool {
return false
}

@ -0,0 +1,125 @@
// +build windows
// +build !appengine
package isatty
import (
"errors"
"strings"
"syscall"
"unicode/utf16"
"unsafe"
)
const (
objectNameInfo uintptr = 1
fileNameInfo = 2
fileTypePipe = 3
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
ntdll = syscall.NewLazyDLL("ntdll.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procGetFileInformationByHandleEx = kernel32.NewProc("GetFileInformationByHandleEx")
procGetFileType = kernel32.NewProc("GetFileType")
procNtQueryObject = ntdll.NewProc("NtQueryObject")
)
func init() {
// Check if GetFileInformationByHandleEx is available.
if procGetFileInformationByHandleEx.Find() != nil {
procGetFileInformationByHandleEx = nil
}
}
// IsTerminal return true if the file descriptor is terminal.
func IsTerminal(fd uintptr) bool {
var st uint32
r, _, e := syscall.Syscall(procGetConsoleMode.Addr(), 2, fd, uintptr(unsafe.Pointer(&st)), 0)
return r != 0 && e == 0
}
// Check pipe name is used for cygwin/msys2 pty.
// Cygwin/MSYS2 PTY has a name like:
// \{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master
func isCygwinPipeName(name string) bool {
token := strings.Split(name, "-")
if len(token) < 5 {
return false
}
if token[0] != `\msys` &&
token[0] != `\cygwin` &&
token[0] != `\Device\NamedPipe\msys` &&
token[0] != `\Device\NamedPipe\cygwin` {
return false
}
if token[1] == "" {
return false
}
if !strings.HasPrefix(token[2], "pty") {
return false
}
if token[3] != `from` && token[3] != `to` {
return false
}
if token[4] != "master" {
return false
}
return true
}
// getFileNameByHandle use the undocomented ntdll NtQueryObject to get file full name from file handler
// since GetFileInformationByHandleEx is not avilable under windows Vista and still some old fashion
// guys are using Windows XP, this is a workaround for those guys, it will also work on system from
// Windows vista to 10
// see https://stackoverflow.com/a/18792477 for details
func getFileNameByHandle(fd uintptr) (string, error) {
if procNtQueryObject == nil {
return "", errors.New("ntdll.dll: NtQueryObject not supported")
}
var buf [4 + syscall.MAX_PATH]uint16
var result int
r, _, e := syscall.Syscall6(procNtQueryObject.Addr(), 5,
fd, objectNameInfo, uintptr(unsafe.Pointer(&buf)), uintptr(2*len(buf)), uintptr(unsafe.Pointer(&result)), 0)
if r != 0 {
return "", e
}
return string(utf16.Decode(buf[4 : 4+buf[0]/2])), nil
}
// IsCygwinTerminal() return true if the file descriptor is a cygwin or msys2
// terminal.
func IsCygwinTerminal(fd uintptr) bool {
if procGetFileInformationByHandleEx == nil {
name, err := getFileNameByHandle(fd)
if err != nil {
return false
}
return isCygwinPipeName(name)
}
// Cygwin/msys's pty is a pipe.
ft, _, e := syscall.Syscall(procGetFileType.Addr(), 1, fd, 0, 0)
if ft != fileTypePipe || e != 0 {
return false
}
var buf [2 + syscall.MAX_PATH]uint16
r, _, e := syscall.Syscall6(procGetFileInformationByHandleEx.Addr(),
4, fd, fileNameInfo, uintptr(unsafe.Pointer(&buf)),
uintptr(len(buf)*2), 0, 0)
if r == 0 || e != 0 {
return false
}
l := *(*uint32)(unsafe.Pointer(&buf))
return isCygwinPipeName(string(utf16.Decode(buf[2 : 2+l/2])))
}

325
vendor/b612.me/starlog/standed.go generated vendored

@ -0,0 +1,325 @@
package starlog
import (
"b612.me/starmap"
"fmt"
"io"
"math/rand"
"sync"
"time"
)
var Std *StarLogger
var stdmu sync.Mutex
func init() {
stacks = starmap.NewStarStack(1024)
rand.Seed(time.Now().UnixNano())
stackStopChan = make(chan int)
StartStacks()
Std = NewStarlog(nil)
}
func SetShowColor(val bool) {
Std.SetShowColor(val)
}
func GetShowColor() bool {
return Std.GetShowColor()
}
func SetLevelColor(level int, color []Attr) {
Std.SetLevelColor(level, color)
}
func GetLevelColor(level int) []Attr {
return Std.GetLevelColor(level)
}
func Debug(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Debug(str...)
Std.isStd = false
}
func Debugf(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Debugf(format, str...)
Std.isStd = false
}
func Debugln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Debugln(str...)
Std.isStd = false
}
func Info(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Info(str...)
Std.isStd = false
}
func Infof(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Infof(format, str...)
Std.isStd = false
}
func Infoln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Infoln(str...)
Std.isStd = false
}
func Notice(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Notice(str...)
Std.isStd = false
}
func Noticef(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Noticef(format, str...)
Std.isStd = false
}
func Noticeln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Noticeln(str...)
Std.isStd = false
}
func Warning(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Warning(str...)
Std.isStd = false
}
func Warningf(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Warningf(format, str...)
Std.isStd = false
}
func Warningln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Warningln(str...)
Std.isStd = false
}
func Error(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Error(str...)
Std.isStd = false
}
func Errorf(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Errorf(format, str...)
Std.isStd = false
}
func Errorln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Errorln(str...)
Std.isStd = false
}
func Critical(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Critical(str...)
Std.isStd = false
}
func Criticalf(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Criticalf(format, str...)
Std.isStd = false
}
func Criticalln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Criticalln(str...)
Std.isStd = false
}
func Fatal(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Fatal(str...)
Std.isStd = false
}
func Fatalf(format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Fatalf(format, str...)
Std.isStd = false
}
func Panicln(str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Fatalln(str...)
Std.isStd = false
}
func Print(str ...interface{}) {
Std.Print(str...)
}
func Printf(format string, str ...interface{}) {
Std.Printf(format, str...)
}
func Println(str ...interface{}) {
Std.Println(str...)
}
func Log(isShow bool, level int, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Log(isShow, level, str...)
Std.isStd = false
}
func Logf(isShow bool, level int, format string, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Logf(isShow, level, format, str...)
Std.isStd = false
}
func Logln(isShow bool, level int, str ...interface{}) {
stdmu.Lock()
defer stdmu.Unlock()
Std.isStd = true
Std.Logln(isShow, level, str...)
Std.isStd = false
}
func StdPrint(attr []Attr, str ...interface{}) {
strs := fmt.Sprint(str...)
NewColor(attr...).Fprint(stdScreen, strs)
}
func StdPrintf(attr []Attr, format string, str ...interface{}) {
strs := fmt.Sprintf(format, str...)
NewColor(attr...).Fprint(stdScreen, strs)
}
func StdPrintln(attr []Attr, str ...interface{}) {
strs := fmt.Sprintln(str...)
NewColor(attr...).Fprint(stdScreen, strs)
}
func SetWriter(wr io.Writer) {
Std.SetWriter(wr)
}
func GetWriter() io.Writer {
return Std.GetWriter()
}
func SetHandler(f func([]Attr, string)) {
Std.SetHandler(f)
}
func GetHandler() func([]Attr, string) {
return Std.GetHandler()
}
func SetSwitching(sw bool) {
Std.SetSwitching(sw)
}
func SetShowOriginFile(val bool) {
Std.SetShowOriginFile(val)
}
func GetShowOriginFile() bool {
return Std.GetShowOriginFile()
}
func SetShowFuncName(val bool) {
Std.logcore.showFuncName = val
}
func GetShowFuncName() bool {
return Std.logcore.showFuncName
}
func SetShowLevel(val bool) {
Std.SetShowLevel(val)
}
func GetShowLevel() bool {
return Std.GetShowLevel()
}
func SetShowFlag(val bool) {
Std.SetShowFlag(val)
}
func GetShowFlag() bool {
return Std.GetShowFlag()
}
func SetShowStd(val bool) {
Std.SetShowStd(val)
}
func GetShowStd() bool {
return Std.GetShowStd()
}
func StopWrite() {
Std.StopWrite()
}
func EnbaleWrite() {
Std.EnbaleWrite()
}
func IsWriteStoed() bool {
return Std.IsWriteStoed()
}

206
vendor/b612.me/starlog/starlog.go generated vendored

@ -0,0 +1,206 @@
package starlog
import (
"io"
)
func (logger *StarLogger) SetShowColor(val bool) {
logger.logcore.showColor = val
}
func (logger *StarLogger) GetShowColor() bool {
return logger.logcore.showColor
}
func (logger *StarLogger) SetLevelColor(level int, color []Attr) {
logger.logcore.colorList[level] = color
logger.logcore.colorMe[level] = NewColor(color...)
}
func (logger *StarLogger) GetLevelColor(level int) []Attr {
return logger.logcore.colorList[level]
}
func (logger *StarLogger) SetWriter(wr io.Writer) {
logger.logcore.output = wr
}
func (logger *StarLogger) GetWriter() io.Writer {
return logger.logcore.output
}
func (logger *StarLogger) SetHandler(f func([]Attr, string)) {
logger.handlerFunc = f
}
func (logger *StarLogger) GetHandler() func([]Attr, string) {
return logger.handlerFunc
}
func (logger *StarLogger) SetSwitching(sw bool) {
logger.logcore.switching = sw
}
func (logger *StarLogger) SetOnlyColorLevel(ocl bool) {
logger.logcore.onlyColorLevel = ocl
}
func (logger *StarLogger) GetOnlyColorLevel() bool {
return logger.logcore.onlyColorLevel
}
func (logger *StarLogger) SetShowOriginFile(val bool) {
logger.logcore.showDeatilFile = val
}
func (logger *StarLogger) GetShowOriginFile() bool {
return logger.logcore.showDeatilFile
}
func (logger *StarLogger) SetShowFuncName(val bool) {
logger.logcore.showFuncName = val
}
func (logger *StarLogger) GetShowFuncName() bool {
return logger.logcore.showFuncName
}
func (logger *StarLogger) SetShowLevel(val bool) {
logger.logcore.showLevel = val
}
func (logger *StarLogger) GetShowLevel() bool {
return logger.logcore.showLevel
}
func (logger *StarLogger) SetShowFlag(val bool) {
logger.logcore.showThread = val
}
func (logger *StarLogger) GetShowFlag() bool {
return logger.logcore.showThread
}
func (logger *StarLogger) SetShowStd(val bool) {
logger.logcore.showStd = val
}
func (logger *StarLogger) GetShowStd() bool {
return logger.logcore.showStd
}
func (logger *StarLogger) StopWrite() {
logger.logcore.stopWriter = true
}
func (logger *StarLogger) EnbaleWrite() {
logger.logcore.stopWriter = false
}
func (logger *StarLogger) IsWriteStoed() bool {
return logger.logcore.stopWriter
}
func (logger *StarLogger) Debug(str ...interface{}) {
logger.logcore.Debug(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Debugf(format string, str ...interface{}) {
logger.logcore.Debugf(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Debugln(str ...interface{}) {
logger.logcore.Debugln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Info(str ...interface{}) {
logger.logcore.Info(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Infof(format string, str ...interface{}) {
logger.logcore.Infof(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Infoln(str ...interface{}) {
logger.logcore.Infoln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Notice(str ...interface{}) {
logger.logcore.Notice(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Noticef(format string, str ...interface{}) {
logger.logcore.Noticef(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Noticeln(str ...interface{}) {
logger.logcore.Noticeln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Warning(str ...interface{}) {
logger.logcore.Warning(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Warningf(format string, str ...interface{}) {
logger.logcore.Warningf(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Warningln(str ...interface{}) {
logger.logcore.Warningln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Error(str ...interface{}) {
logger.logcore.Error(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Errorf(format string, str ...interface{}) {
logger.logcore.Errorf(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Errorln(str ...interface{}) {
logger.logcore.Errorln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Critical(str ...interface{}) {
logger.logcore.Critical(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Criticalf(format string, str ...interface{}) {
logger.logcore.Criticalf(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Criticalln(str ...interface{}) {
logger.logcore.Criticalln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Fatal(str ...interface{}) {
logger.logcore.Fatal(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Fatalf(format string, str ...interface{}) {
logger.logcore.Fatalf(logger.thread, logger.isStd, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Fatalln(str ...interface{}) {
logger.logcore.Fatalln(logger.thread, logger.isStd, logger.handlerFunc, str...)
}
func (logger *StarLogger) Print(str ...interface{}) {
logger.logcore.Print(logger.thread, logger.isStd, logger.GetShowStd(), logger.handlerFunc, str...)
}
func (logger *StarLogger) Printf(format string, str ...interface{}) {
logger.logcore.Printf(logger.thread, logger.isStd, logger.GetShowStd(), logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Println(str ...interface{}) {
logger.logcore.Println(logger.thread, logger.isStd, logger.GetShowStd(), logger.handlerFunc, str...)
}
func (logger *StarLogger) Log(showLog bool, level int, str ...interface{}) {
logger.logcore.Log(logger.thread, logger.isStd, showLog, level, logger.handlerFunc, str...)
}
func (logger *StarLogger) Logf(showLog bool, level int, format string, str ...interface{}) {
logger.logcore.Logf(logger.thread, logger.isStd, showLog, level, logger.handlerFunc, format, str...)
}
func (logger *StarLogger) Logln(showLog bool, level int, str ...interface{}) {
logger.logcore.Logln(logger.thread, logger.isStd, showLog, level, logger.handlerFunc, str...)
}

188
vendor/b612.me/starlog/typed.go generated vendored

@ -0,0 +1,188 @@
package starlog
import (
"fmt"
"io"
"math/rand"
"sync"
"time"
"b612.me/starlog/colorable"
"b612.me/starmap"
)
const (
LvDebug = iota
LvInfo
LvNotice
LvWarning
LvError
LvCritical
LvPanic
LvFatal
)
var (
levels = map[int]string{
LvDebug: "DEBUG",
LvInfo: "INFO",
LvNotice: "NOTICE",
LvWarning: "WARNING",
LvError: "ERROR",
LvCritical: "CRITICAL",
LvPanic: "PANIC",
LvFatal: "FATAL",
}
stacks *starmap.StarStack
stackStarted bool = false
stackStopChan chan int
stackMu sync.Mutex
stdScreen io.Writer = colorable.NewColorableStdout()
)
type starlog struct {
mu *sync.Mutex
output io.Writer
showFuncName bool
showThread bool
showLevel bool
showDeatilFile bool
showColor bool
switching bool
showStd bool
onlyColorLevel bool
stopWriter bool
id string
colorList map[int][]Attr
colorMe map[int]*Color
}
type StarLogger struct {
thread string
handlerFunc func([]Attr, string)
logcore *starlog
isStd bool
}
type logTransfer struct {
handlerFunc func([]Attr, string)
colors []Attr
logStr string
}
func newLogCore(out io.Writer) *starlog {
return &starlog{
mu: &sync.Mutex{},
output: out,
showFuncName: true,
showThread: true,
showLevel: true,
showStd: true,
showDeatilFile: true,
switching: false,
stopWriter: false,
showColor: true,
id: generateId(),
colorList: map[int][]Attr{
LvDebug: []Attr{FgWhite},
LvInfo: []Attr{FgGreen},
LvNotice: []Attr{FgBlue},
LvWarning: []Attr{FgYellow},
LvError: []Attr{FgMagenta},
LvCritical: []Attr{FgRed, Bold},
LvPanic: []Attr{FgRed, Bold},
LvFatal: []Attr{FgRed},
},
colorMe: map[int]*Color{
LvDebug: NewColor([]Attr{FgWhite}...),
LvInfo: NewColor([]Attr{FgGreen}...),
LvNotice: NewColor([]Attr{FgBlue}...),
LvWarning: NewColor([]Attr{FgYellow}...),
LvError: NewColor([]Attr{FgMagenta}...),
LvCritical: NewColor([]Attr{FgRed, Bold}...),
LvPanic: NewColor([]Attr{FgRed, Bold}...),
LvFatal: NewColor([]Attr{FgRed}...),
},
}
}
func NewStarlog(out io.Writer) *StarLogger {
return &StarLogger{
handlerFunc: nil,
thread: "MAN",
logcore: newLogCore(out),
isStd: false,
}
}
func (logger *StarLogger) NewFlag() *StarLogger {
return &StarLogger{
thread: getRandomFlag(false),
handlerFunc: logger.handlerFunc,
logcore: logger.logcore,
isStd: false,
}
}
func (logger *StarLogger) SetNewRandomFlag() {
logger.thread = getRandomFlag(false)
}
func getRandomFlag(isMain bool) string {
rand.Seed(time.Now().UnixNano())
if isMain {
return "MAN"
}
flag := "MAN"
for flag == "MAN" {
flag = string([]byte{uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65), uint8(rand.Intn(26) + 65)})
}
return flag
}
func generateId() string {
rand.Seed(time.Now().UnixNano())
return fmt.Sprintf("%dstar%db612%d", time.Now().UnixNano(), rand.Intn(1000000), rand.Intn(1000000))
}
func StartStacks() {
stackMu.Lock()
if stackStarted {
stackMu.Unlock()
return
}
go func() {
stackStarted = true
stackMu.Unlock()
defer func() {
stackStarted = false
}()
for {
select {
case <-stackStopChan:
return
default:
}
poped := stacks.MustPop()
if poped == nil {
time.Sleep(time.Microsecond * 500)
continue
}
val := poped.(logTransfer)
if val.handlerFunc != nil {
val.handlerFunc(val.colors, val.logStr)
}
}
}()
}
func StopStacks() {
if !stackStarted {
return
}
stackStopChan <- 1
}
func Stop() {
StopStacks()
}

102
vendor/b612.me/starmap/basicrw.go generated vendored

@ -0,0 +1,102 @@
package starmap
import (
"errors"
"os"
)
func (stack *StarStackMem) Count() int {
stack.kvPushmu.Lock()
defer stack.kvPushmu.Unlock()
return len(stack.kvStack)
}
func (stack *StarStackMem) Push(val interface{}) error {
stack.kvPushmu.Lock()
defer stack.kvPushmu.Unlock()
stack.kvStack = append(stack.kvStack, val)
return nil
}
func (stack *StarStackMem) Pop() (interface{}, error) {
stack.kvPushmu.Lock()
defer stack.kvPushmu.Unlock()
if len(stack.kvStack) == 0 {
return nil, errors.New("Empty Stacks")
}
val := stack.kvStack[0]
stack.kvStack = stack.kvStack[1:]
return val, nil
}
func (stack *StarStackMem) MustPop() interface{} {
val, _ := stack.Pop()
return val
}
func Get(key interface{}) (interface{}, error) {
return globalMap.Get(key)
}
func (m *StarMapKV) Get(key interface{}) (interface{}, error) {
var err error
m.mu.RLock()
defer m.mu.RUnlock()
data, ok := m.kvMap[key]
if !ok {
err = os.ErrNotExist
}
return data, err
}
func (m *StarMapKV) MustGet(key interface{}) interface{} {
result, _ := m.Get(key)
return result
}
func MustGet(key interface{}) interface{} {
return globalMap.MustGet(key)
}
func Store(key interface{}, value interface{}) error {
return globalMap.Store(key, value)
}
func (m *StarMapKV) Store(key interface{}, value interface{}) error {
m.mu.Lock()
defer m.mu.Unlock()
m.kvMap[key] = value
return nil
}
func Exists(key interface{}) bool {
return globalMap.Exists(key)
}
func (m *StarMapKV) Exists(key interface{}) bool {
m.mu.RLock()
defer m.mu.RUnlock()
_, ok := m.kvMap[key]
return ok
}
func Delete(key interface{}) error {
return globalMap.Delete(key)
}
func (m *StarMapKV) Delete(key interface{}) error {
m.mu.Lock()
defer m.mu.Unlock()
delete(m.kvMap, key)
return nil
}
func Range(run func(k interface{}, v interface{}) bool) error {
return globalMap.Range(run)
}
func (m *StarMapKV) Range(run func(k interface{}, v interface{}) bool) error {
for k, v := range m.kvMap {
if !run(k, v) {
break
}
}
return nil
}

@ -0,0 +1,96 @@
package starmap
import (
"b612.me/notify"
)
func (kv *RemoteKv) clientOnline() error {
return kv.reconnect()
}
func (kv *RemoteKv) MustGet(key string) interface{} {
result, _ := kv.Get(key)
return result
}
func (kv *RemoteKv) Get(key interface{}) (interface{}, error) {
if err := kv.clientOnline(); err != nil {
return nil, err
}
keyCode, err := notify.ToMsgVal(key)
if err != nil {
return nil, err
}
data, err := kv.client.SendWait("get", keyCode, kv.readTimeout)
if err != nil {
return nil, err
}
rp, err := data.Value.ToInterface()
if err != nil {
return nil, err
}
reply := rp.(kvMsg)
return reply.Value, reply.Err
}
func (kv *RemoteKv) Store(key interface{}, value interface{}) error {
if err := kv.clientOnline(); err != nil {
return err
}
encodeData, err := notify.ToMsgVal(kvMsg{
Key: key,
Value: value,
Err: nil,
})
if err != nil {
return err
}
data, err := kv.client.SendWait("store", encodeData, kv.readTimeout)
if err != nil {
return err
}
rp, err := data.Value.ToInterface()
if err != nil {
return err
}
return rp.(kvMsg).Err
}
func (kv *RemoteKv) Delete(key interface{}) error {
if err := kv.clientOnline(); err != nil {
return err
}
keyCode, err := notify.ToMsgVal(key)
if err != nil {
return err
}
data, err := kv.client.SendWait("delete", keyCode, kv.readTimeout)
if err != nil {
return err
}
rp, err := data.Value.ToInterface()
if err != nil {
return err
}
return rp.(kvMsg).Err
}
func (kv *RemoteKv) Exists(key interface{}) bool {
if err := kv.clientOnline(); err != nil {
return false
}
keyCode, err := notify.ToMsgVal(key)
if err != nil {
return false
}
data, err := kv.client.SendWait("exists", keyCode, kv.readTimeout)
if err != nil {
return false
}
rp, err := data.Value.ToInterface()
if err != nil {
return false
}
reply := rp.(kvMsg)
return reply.Value.(bool)
}

@ -0,0 +1,102 @@
package starmap
import (
"encoding/gob"
"os"
"time"
"b612.me/notify"
)
func init() {
notify.Register(kvMsg{})
notify.Register(starMapErr{})
}
type starMapErr struct {
Err string
}
func (s starMapErr) Error() string {
return s.Err
}
func newStarMapErr(err error) error {
if err == nil {
return nil
}
return starMapErr{Err: err.Error()}
}
type kvMsg struct {
Key interface{}
Value interface{}
Err error
}
type RemoteKv struct {
server notify.Server
client notify.Client
kvmap StarMapKV
addr string
network string
readTimeout time.Duration
timeout time.Duration
}
func NewServer(network, addr string) (*RemoteKv, error) {
var err error
kv := RemoteKv{
server: notify.NewServer(),
kvmap: NewStarMap(),
addr: addr,
network: network,
}
err = kv.server.Listen(network, addr)
if err == nil {
kv.bind()
}
return &kv, err
}
func NewClient(network, addr string, dialTimeout time.Duration) (*RemoteKv, error) {
var err error
kv := RemoteKv{
client: notify.NewClient(),
kvmap: NewStarMap(),
addr: addr,
network: network,
timeout: dialTimeout,
readTimeout: time.Second * 5,
}
err = kv.client.ConnectTimeout(network, addr, dialTimeout)
return &kv, err
}
func (kv *RemoteKv) Register(data interface{}) {
gob.Register(data)
}
func (kv *RemoteKv) RegisterAll(data []interface{}) {
for _, v := range data {
gob.Register(v)
}
}
func (kv *RemoteKv) bind() {
//for server
kv.server.SetDefaultLink(kv.dispatch)
//for client
}
func (kv *RemoteKv) reconnect() error {
if kv.server != nil {
return nil
}
if kv.client != nil {
if kv.client.Status().Alive {
return nil
}
return kv.client.ConnectTimeout(kv.network, kv.addr, kv.timeout)
}
return os.ErrInvalid
}

@ -0,0 +1,39 @@
package starmap
import (
"b612.me/notify"
)
func (r *RemoteKv) dispatch(msg *notify.Message) {
switch msg.Key {
case "get":
data, err := r.kvmap.Get(msg.Value.MustToInterface())
msg.ReplyObj(kvMsg{
Key: msg.Value.MustToInterface(),
Value: data,
Err: newStarMapErr(err),
})
case "delete":
err := r.kvmap.Delete(msg.Value.MustToInterface())
msg.ReplyObj(kvMsg{
Key: msg.Value.MustToInterface(),
Value: nil,
Err: newStarMapErr(err),
})
case "exists":
ext := r.kvmap.Exists(msg.Value.MustToInterface())
msg.ReplyObj(kvMsg{
Key: msg.Value.MustToInterface(),
Value: ext,
Err: newStarMapErr(nil),
})
case "store":
ext := msg.Value.MustToInterface().(kvMsg)
err := r.kvmap.Store(ext.Key, ext.Value)
msg.ReplyObj(kvMsg{
Key: msg.Value.MustToInterface(),
Value: nil,
Err: newStarMapErr(err),
})
}
}

199
vendor/b612.me/starmap/stack.go generated vendored

@ -0,0 +1,199 @@
package starmap
import (
"errors"
"fmt"
"io"
"os"
"runtime"
"sync"
"sync/atomic"
"time"
)
type StarStack struct {
datas []interface{}
pStart uint64
pEnd uint64
cap uint64
isClose atomic.Value
rmu sync.Mutex
wmu sync.Mutex
}
func NewStarStack(cap uint64) *StarStack {
rtnBuffer := new(StarStack)
rtnBuffer.cap = cap
rtnBuffer.datas = make([]interface{}, cap)
rtnBuffer.isClose.Store(false)
return rtnBuffer
}
func (star *StarStack) init() {
star.cap = 1024
star.datas = make([]interface{}, star.cap)
star.isClose.Store(false)
}
func (star *StarStack) Free() uint64 {
return star.cap - star.Len()
}
func (star *StarStack) Cap() uint64 {
return star.cap
}
func (star *StarStack) Len() uint64 {
if star.pEnd >= star.pStart {
return star.pEnd - star.pStart
}
return star.pEnd - star.pStart + star.cap
}
func (star *StarStack) PopNoWait() (interface{}, error) {
if star.isClose.Load() == nil {
star.init()
}
if star.isClose.Load().(bool) {
return 0, io.EOF
}
if star.Len() == 0 {
return 0, os.ErrNotExist
}
nowPtr := star.pStart
nextPtr := star.pStart + 1
if nextPtr >= star.cap {
nextPtr = 0
}
data := star.datas[nowPtr]
ok := atomic.CompareAndSwapUint64(&star.pStart, nowPtr, nextPtr)
if !ok {
return 0, os.ErrInvalid
}
return data, nil
}
func (star *StarStack) MustPop() interface{} {
if star.isClose.Load() == nil {
star.init()
}
data, err := star.Pop()
if err != nil {
return nil
}
return data
}
func (star *StarStack) Pop() (interface{}, error) {
if star.isClose.Load() == nil {
star.init()
}
for {
if star.isClose.Load().(bool) {
return 0, io.EOF
}
if star.Len() == 0 {
return 0, os.ErrNotExist
}
nowPtr := star.pStart
nextPtr := star.pStart + 1
if nextPtr >= star.cap {
nextPtr = 0
}
data := star.datas[nowPtr]
ok := atomic.CompareAndSwapUint64(&star.pStart, nowPtr, nextPtr)
if !ok {
time.Sleep(time.Microsecond)
runtime.Gosched()
continue
}
return data, nil
}
}
func (star *StarStack) Push(data interface{}) error {
if star.isClose.Load() == nil {
star.init()
}
if star.isClose.Load().(bool) {
return io.EOF
}
nowPtr := star.pEnd
kariEnd := nowPtr + 1
if kariEnd == star.cap {
kariEnd = 0
}
if kariEnd == atomic.LoadUint64(&star.pStart) {
for {
time.Sleep(time.Microsecond)
runtime.Gosched()
if kariEnd != atomic.LoadUint64(&star.pStart) {
break
}
}
}
star.datas[nowPtr] = data
if ok := atomic.CompareAndSwapUint64(&star.pEnd, nowPtr, kariEnd); !ok {
return os.ErrInvalid
}
return nil
}
func (star *StarStack) Close() error {
if star.isClose.Load() == nil {
star.init()
}
star.isClose.Store(true)
return nil
}
func (star *StarStack) Read(buf []interface{}) (int, error) {
if star.isClose.Load() == nil {
star.init()
}
if star.isClose.Load().(bool) {
return 0, io.EOF
}
if buf == nil {
return 0, errors.New("buffer is nil")
}
star.rmu.Lock()
defer star.rmu.Unlock()
var sum int = 0
for i := 0; i < len(buf); i++ {
data, err := star.PopNoWait()
if err != nil {
if err == io.EOF {
return sum, err
}
if err == os.ErrNotExist {
i--
continue
}
return sum, nil
}
buf[i] = data
sum++
}
return sum, nil
}
func (star *StarStack) Write(bts []byte) (int, error) {
if star.isClose.Load() == nil {
star.init()
}
if bts == nil || star.isClose.Load().(bool) {
return 0, io.EOF
}
star.wmu.Lock()
defer star.wmu.Unlock()
var sum = 0
for i := 0; i < len(bts); i++ {
err := star.Push(bts[i])
if err != nil {
fmt.Println("Write bts err:", err)
return sum, err
}
sum++
}
return sum, nil
}

25
vendor/b612.me/starmap/starmap.go generated vendored

@ -0,0 +1,25 @@
package starmap
import "sync"
var globalMap StarMapKV
type StarMapKV struct {
kvMap map[interface{}]interface{}
mu sync.RWMutex
}
type StarStackMem struct {
kvPushmu sync.RWMutex
kvStack []interface{}
}
func init() {
globalMap = NewStarMap()
}
func NewStarMap() StarMapKV {
var mp StarMapKV
mp.kvMap = make(map[interface{}]interface{})
return mp
}

55
vendor/b612.me/starmap/sync.go generated vendored

@ -0,0 +1,55 @@
package starmap
import (
"sync"
"sync/atomic"
"time"
)
type WaitGroup struct {
wg *sync.WaitGroup
maxCount uint32
allCount uint32
}
func NewWaitGroup(maxCount int) WaitGroup {
return WaitGroup{wg: &sync.WaitGroup{}, maxCount: uint32(maxCount)}
}
func (swg *WaitGroup) Add(delta int) {
var Udelta uint32
if delta < 0 {
Udelta = uint32(-delta - 1)
} else {
Udelta = uint32(delta)
}
for {
allC := atomic.LoadUint32(&swg.allCount)
if atomic.LoadUint32(&swg.maxCount) == 0 || atomic.LoadUint32(&swg.maxCount) >= allC+uint32(delta) {
if delta < 0 {
atomic.AddUint32(&swg.allCount, ^uint32(Udelta))
} else {
atomic.AddUint32(&swg.allCount, uint32(Udelta))
}
break
}
time.Sleep(time.Microsecond)
}
swg.wg.Add(delta)
}
func (swg *WaitGroup) Done() {
swg.Add(-1)
}
func (swg *WaitGroup) Wait() {
swg.wg.Wait()
}
func (swg *WaitGroup) GetMaxWaitNum() int {
return int(atomic.LoadUint32(&swg.maxCount))
}
func (swg *WaitGroup) SetMaxWaitNum(num int) {
atomic.AddUint32(&swg.maxCount, uint32(num))
}

435
vendor/b612.me/starnet/curl.go generated vendored

@ -0,0 +1,435 @@
package starnet
import (
"bytes"
"context"
"crypto/rand"
"crypto/tls"
"errors"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"strings"
"time"
"b612.me/stario"
)
const (
HEADER_FORM_URLENCODE = `application/x-www-form-urlencoded`
HEADER_FORM_DATA = `multipart/form-data`
HEADER_JSON = `application/json`
)
type RequestFile struct {
UploadFile string
UploadForm map[string]string
UploadName string
}
type Request struct {
Url string
Method string
RecvData []byte
RecvContentLength int64
RecvIo io.Writer
RespHeader http.Header
RespCookies []*http.Cookie
RespHttpCode int
Location *url.URL
CircleBuffer *stario.StarBuffer
respReader io.ReadCloser
RequestOpts
}
type RequestOpts struct {
RequestFile
PostBuffer io.Reader
Process func(float64)
Proxy string
Timeout time.Duration
DialTimeout time.Duration
ReqHeader http.Header
ReqCookies []*http.Cookie
WriteRecvData bool
SkipTLSVerify bool
CustomTransport *http.Transport
Queries map[string]string
DisableRedirect bool
}
type RequestOpt func(opt *RequestOpts)
func WithDialTimeout(timeout time.Duration) RequestOpt {
return func(opt *RequestOpts) {
opt.DialTimeout = timeout
}
}
func WithTimeout(timeout time.Duration) RequestOpt {
return func(opt *RequestOpts) {
opt.Timeout = timeout
}
}
func WithHeader(key, val string) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqHeader.Set(key, val)
}
}
func WithHeaderMap(header map[string]string) RequestOpt {
return func(opt *RequestOpts) {
for key, val := range header {
opt.ReqHeader.Set(key, val)
}
}
}
func WithHeaderAdd(key, val string) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqHeader.Add(key, val)
}
}
func WithReader(r io.Reader) RequestOpt {
return func(opt *RequestOpts) {
opt.PostBuffer = r
}
}
func WithFetchRespBody(fetch bool) RequestOpt {
return func(opt *RequestOpts) {
opt.WriteRecvData = fetch
}
}
func WithCookies(ck []*http.Cookie) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqCookies = ck
}
}
func WithCookie(key, val, path string) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqCookies = append(opt.ReqCookies, &http.Cookie{Name: key, Value: val, Path: path})
}
}
func WithCookieMap(header map[string]string, path string) RequestOpt {
return func(opt *RequestOpts) {
for key, val := range header {
opt.ReqCookies = append(opt.ReqCookies, &http.Cookie{Name: key, Value: val, Path: path})
}
}
}
func WithQueries(queries map[string]string) RequestOpt {
return func(opt *RequestOpts) {
opt.Queries = queries
}
}
func WithProxy(proxy string) RequestOpt {
return func(opt *RequestOpts) {
opt.Proxy = proxy
}
}
func WithProcess(fn func(float64)) RequestOpt {
return func(opt *RequestOpts) {
opt.Process = fn
}
}
func WithContentType(ct string) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqHeader.Set("Content-Type", ct)
}
}
func WithUserAgent(ua string) RequestOpt {
return func(opt *RequestOpts) {
opt.ReqHeader.Set("User-Agent", ua)
}
}
func WithCustomTransport(hs *http.Transport) RequestOpt {
return func(opt *RequestOpts) {
opt.CustomTransport = hs
}
}
func WithSkipTLSVerify(skip bool) RequestOpt {
return func(opt *RequestOpts) {
opt.SkipTLSVerify = skip
}
}
func WithDisableRedirect(disable bool) RequestOpt {
return func(opt *RequestOpts) {
opt.DisableRedirect = disable
}
}
func NewRequests(url string, rawdata []byte, method string, opts ...RequestOpt) Request {
req := Request{
RequestOpts: RequestOpts{
Timeout: 30 * time.Second,
DialTimeout: 15 * time.Second,
WriteRecvData: true,
},
Url: url,
Method: method,
}
if rawdata != nil {
req.PostBuffer = bytes.NewBuffer(rawdata)
}
req.ReqHeader = make(http.Header)
if strings.ToUpper(method) == "POST" {
req.ReqHeader.Set("Content-Type", HEADER_FORM_URLENCODE)
}
req.ReqHeader.Set("User-Agent", "B612 / 1.1.0")
for _, v := range opts {
v(&req.RequestOpts)
}
if req.CustomTransport == nil {
req.CustomTransport = &http.Transport{}
}
if req.SkipTLSVerify {
if req.CustomTransport.TLSClientConfig == nil {
req.CustomTransport.TLSClientConfig = &tls.Config{}
}
req.CustomTransport.TLSClientConfig.InsecureSkipVerify = true
}
req.CustomTransport.DialContext = func(ctx context.Context, netw, addr string) (net.Conn, error) {
c, err := net.DialTimeout(netw, addr, req.DialTimeout)
if err != nil {
return nil, err
}
if req.Timeout != 0 {
c.SetDeadline(time.Now().Add(req.Timeout))
}
return c, nil
}
return req
}
func (curl *Request) ResetReqHeader() {
curl.ReqHeader = make(http.Header)
}
func (curl *Request) ResetReqCookies() {
curl.ReqCookies = []*http.Cookie{}
}
func (curl *Request) AddSimpleCookie(key, value string) {
curl.ReqCookies = append(curl.ReqCookies, &http.Cookie{Name: key, Value: value, Path: "/"})
}
func (curl *Request) AddCookie(key, value, path string) {
curl.ReqCookies = append(curl.ReqCookies, &http.Cookie{Name: key, Value: value, Path: path})
}
func randomBoundary() string {
var buf [30]byte
_, err := io.ReadFull(rand.Reader, buf[:])
if err != nil {
panic(err)
}
return fmt.Sprintf("%x", buf[:])
}
func Curl(curl Request) (resps Request, err error) {
var fpsrc *os.File
if curl.RequestFile.UploadFile != "" {
fpsrc, err = os.Open(curl.UploadFile)
if err != nil {
return
}
defer fpsrc.Close()
boundary := randomBoundary()
boundarybytes := []byte("\r\n--" + boundary + "\r\n")
endbytes := []byte("\r\n--" + boundary + "--\r\n")
fpstat, _ := fpsrc.Stat()
filebig := float64(fpstat.Size())
sum, n := 0, 0
fpdst := stario.NewStarBuffer(1048576)
if curl.UploadForm != nil {
for k, v := range curl.UploadForm {
header := fmt.Sprintf("Content-Disposition: form-data; name=\"%s\";\r\nContent-Type: x-www-form-urlencoded \r\n\r\n", k)
fpdst.Write(boundarybytes)
fpdst.Write([]byte(header))
fpdst.Write([]byte(v))
}
}
header := fmt.Sprintf("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\nContent-Type: application/octet-stream\r\n\r\n", curl.UploadName, fpstat.Name())
fpdst.Write(boundarybytes)
fpdst.Write([]byte(header))
go func() {
for {
bufs := make([]byte, 393213)
n, err = fpsrc.Read(bufs)
if err != nil {
if err == io.EOF {
if n != 0 {
fpdst.Write(bufs[0:n])
if curl.Process != nil {
go curl.Process(float64(sum+n) / filebig * 100)
}
}
break
}
return
}
sum += n
if curl.Process != nil {
go curl.Process(float64(sum+n) / filebig * 100)
}
fpdst.Write(bufs[0:n])
}
fpdst.Write(endbytes)
fpdst.Write(nil)
}()
curl.CircleBuffer = fpdst
curl.ReqHeader.Set("Content-Type", "multipart/form-data;boundary="+boundary)
}
resp, err := netcurl(curl)
if err != nil {
return Request{}, err
}
curl.Location, _ = resp.Location()
curl.RespHttpCode = resp.StatusCode
curl.RespHeader = resp.Header
curl.RespCookies = resp.Cookies()
curl.RecvContentLength = resp.ContentLength
readFunc := func(reader io.ReadCloser, writer io.Writer) error {
lengthall := resp.ContentLength
defer reader.Close()
var lengthsum int
buf := make([]byte, 65535)
for {
n, err := reader.Read(buf)
if n != 0 {
_, err := writer.Write(buf[:n])
lengthsum += n
if curl.Process != nil {
go curl.Process(float64(lengthsum) / float64(lengthall) * 100.00)
}
if err != nil {
return err
}
}
if err != nil && err != io.EOF {
return err
} else if err == io.EOF {
return nil
}
}
}
if curl.WriteRecvData {
buf := bytes.NewBuffer([]byte{})
err = readFunc(resp.Body, buf)
if err != nil {
return
}
curl.RecvData = buf.Bytes()
} else {
curl.respReader = resp.Body
}
if curl.RecvIo != nil {
if curl.WriteRecvData {
_, err = curl.RecvIo.Write(curl.RecvData)
} else {
err = readFunc(resp.Body, curl.RecvIo)
if err != nil {
return
}
}
}
return curl, err
}
// RespBodyReader Only works when WriteRecvData set to false
func (curl *Request) RespBodyReader() io.ReadCloser {
return curl.respReader
}
func netcurl(curl Request) (*http.Response, error) {
var req *http.Request
var err error
if curl.Method == "" {
return nil, errors.New("Error Method Not Entered")
}
if curl.PostBuffer != nil {
req, err = http.NewRequest(curl.Method, curl.Url, curl.PostBuffer)
} else if curl.CircleBuffer != nil && curl.CircleBuffer.Len() > 0 {
req, err = http.NewRequest(curl.Method, curl.Url, curl.CircleBuffer)
} else {
req, err = http.NewRequest(curl.Method, curl.Url, nil)
}
if curl.Queries != nil {
sid := req.URL.Query()
for k, v := range curl.Queries {
sid.Add(k, v)
}
req.URL.RawQuery = sid.Encode()
}
if err != nil {
return nil, err
}
req.Header = curl.ReqHeader
if len(curl.ReqCookies) != 0 {
for _, v := range curl.ReqCookies {
req.AddCookie(v)
}
}
if curl.Proxy != "" {
purl, err := url.Parse(curl.Proxy)
if err != nil {
return nil, err
}
curl.CustomTransport.Proxy = http.ProxyURL(purl)
}
client := &http.Client{
Transport: curl.CustomTransport,
}
if curl.DisableRedirect {
client.CheckRedirect = func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
}
}
resp, err := client.Do(req)
return resp, err
}
func UrlEncodeRaw(str string) string {
strs := strings.Replace(url.QueryEscape(str), "+", "%20", -1)
return strs
}
func UrlEncode(str string) string {
return url.QueryEscape(str)
}
func UrlDecode(str string) (string, error) {
return url.QueryUnescape(str)
}
func BuildQuery(queryData map[string]string) string {
query := url.Values{}
for k, v := range queryData {
query.Add(k, v)
}
return query.Encode()
}
func BuildPostForm(queryMap map[string]string) []byte {
query := url.Values{}
for k, v := range queryMap {
query.Add(k, v)
}
return []byte(query.Encode())
}

97
vendor/b612.me/starnet/ping.go generated vendored

@ -0,0 +1,97 @@
package starnet
import (
"bytes"
"encoding/binary"
"net"
"time"
)
type ICMP struct {
Type uint8
Code uint8
CheckSum uint16
Identifier uint16
SequenceNum uint16
}
func getICMP(seq uint16) ICMP {
icmp := ICMP{
Type: 8,
Code: 0,
CheckSum: 0,
Identifier: 0,
SequenceNum: seq,
}
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, icmp)
icmp.CheckSum = checkSum(buffer.Bytes())
buffer.Reset()
return icmp
}
func sendICMPRequest(icmp ICMP, destAddr *net.IPAddr, timeout time.Duration) (PingResult, error) {
var res PingResult
conn, err := net.DialIP("ip:icmp", nil, destAddr)
if err != nil {
return res, err
}
defer conn.Close()
var buffer bytes.Buffer
binary.Write(&buffer, binary.BigEndian, icmp)
if _, err := conn.Write(buffer.Bytes()); err != nil {
return res, err
}
tStart := time.Now()
conn.SetReadDeadline((time.Now().Add(timeout)))
recv := make([]byte, 1024)
res.RecvCount, err = conn.Read(recv)
if err != nil {
return res, err
}
tEnd := time.Now()
res.Duration = tEnd.Sub(tStart)
return res, err
}
func checkSum(data []byte) uint16 {
var (
sum uint32
length int = len(data)
index int
)
for length > 1 {
sum += uint32(data[index])<<8 + uint32(data[index+1])
index += 2
length -= 2
}
if length > 0 {
sum += uint32(data[index])
}
sum += (sum >> 16)
return uint16(^sum)
}
type PingResult struct {
Duration time.Duration
RecvCount int
}
func Ping(ip string, seq int, timeout time.Duration) (PingResult, error) {
var res PingResult
ipAddr, err := net.ResolveIPAddr("ip", ip)
if err != nil {
return res, err
}
icmp := getICMP(uint16(seq))
return sendICMPRequest(icmp, ipAddr, timeout)
}

317
vendor/b612.me/starnet/que.go generated vendored

@ -0,0 +1,317 @@
package starnet
import (
"bytes"
"context"
"encoding/binary"
"errors"
"os"
"sync"
"time"
)
// 识别头
var header = []byte{11, 27, 19, 96, 12, 25, 02, 20}
// MsgQueue 为基本的信息单位
type MsgQueue struct {
ID uint16
Msg []byte
Conn interface{}
}
// StarQueue 为流数据中的消息队列分发
type StarQueue struct {
count int64
Encode bool
Reserve uint16
Msgid uint16
MsgPool chan MsgQueue
UnFinMsg sync.Map
LastID int //= -1
ctx context.Context
cancel context.CancelFunc
duration time.Duration
EncodeFunc func([]byte) []byte
DecodeFunc func([]byte) []byte
//restoreMu sync.Mutex
}
func NewQueueCtx(ctx context.Context, count int64) *StarQueue {
var que StarQueue
que.Encode = false
que.count = count
que.MsgPool = make(chan MsgQueue, count)
if ctx == nil {
que.ctx, que.cancel = context.WithCancel(context.Background())
} else {
que.ctx, que.cancel = context.WithCancel(ctx)
}
que.duration = 0
return &que
}
func NewQueueWithCount(count int64) *StarQueue {
return NewQueueCtx(nil, count)
}
// NewQueue 建立一个新消息队列
func NewQueue() *StarQueue {
return NewQueueWithCount(32)
}
// Uint32ToByte 4位uint32转byte
func Uint32ToByte(src uint32) []byte {
res := make([]byte, 4)
res[3] = uint8(src)
res[2] = uint8(src >> 8)
res[1] = uint8(src >> 16)
res[0] = uint8(src >> 24)
return res
}
// ByteToUint32 byte转4位uint32
func ByteToUint32(src []byte) uint32 {
var res uint32
buffer := bytes.NewBuffer(src)
binary.Read(buffer, binary.BigEndian, &res)
return res
}
// Uint16ToByte 2位uint16转byte
func Uint16ToByte(src uint16) []byte {
res := make([]byte, 2)
res[1] = uint8(src)
res[0] = uint8(src >> 8)
return res
}
// ByteToUint16 用于byte转uint16
func ByteToUint16(src []byte) uint16 {
var res uint16
buffer := bytes.NewBuffer(src)
binary.Read(buffer, binary.BigEndian, &res)
return res
}
// BuildMessage 生成编码后的信息用于发送
func (que *StarQueue) BuildMessage(src []byte) []byte {
var buff bytes.Buffer
que.Msgid++
if que.Encode {
src = que.EncodeFunc(src)
}
length := uint32(len(src))
buff.Write(header)
buff.Write(Uint32ToByte(length))
buff.Write(Uint16ToByte(que.Msgid))
buff.Write(src)
return buff.Bytes()
}
// BuildHeader 生成编码后的Header用于发送
func (que *StarQueue) BuildHeader(length uint32) []byte {
var buff bytes.Buffer
que.Msgid++
buff.Write(header)
buff.Write(Uint32ToByte(length))
buff.Write(Uint16ToByte(que.Msgid))
return buff.Bytes()
}
type unFinMsg struct {
ID uint16
LengthRecv uint32
// HeaderMsg 信息头应当为14位8位识别码+4位长度码+2位id
HeaderMsg []byte
RecvMsg []byte
}
func (que *StarQueue) push2list(msg MsgQueue) {
que.MsgPool <- msg
}
// ParseMessage 用于解析收到的msg信息
func (que *StarQueue) ParseMessage(msg []byte, conn interface{}) error {
return que.parseMessage(msg, conn)
}
// parseMessage 用于解析收到的msg信息
func (que *StarQueue) parseMessage(msg []byte, conn interface{}) error {
tmp, ok := que.UnFinMsg.Load(conn)
if ok { //存在未完成的信息
lastMsg := tmp.(*unFinMsg)
headerLen := len(lastMsg.HeaderMsg)
if headerLen < 14 { //未完成头标题
//传输的数据不能填充header头
if len(msg) < 14-headerLen {
//加入header头并退出
lastMsg.HeaderMsg = bytesMerge(lastMsg.HeaderMsg, msg)
que.UnFinMsg.Store(conn, lastMsg)
return nil
}
//获取14字节完整的header
header := msg[0 : 14-headerLen]
lastMsg.HeaderMsg = bytesMerge(lastMsg.HeaderMsg, header)
//检查收到的header是否为认证header
//若不是,丢弃并重新来过
if !checkHeader(lastMsg.HeaderMsg[0:8]) {
que.UnFinMsg.Delete(conn)
if len(msg) == 0 {
return nil
}
return que.parseMessage(msg, conn)
}
//获得本数据包长度
lastMsg.LengthRecv = ByteToUint32(lastMsg.HeaderMsg[8:12])
//获得本数据包ID
lastMsg.ID = ByteToUint16(lastMsg.HeaderMsg[12:14])
//存入列表
que.UnFinMsg.Store(conn, lastMsg)
msg = msg[14-headerLen:]
if uint32(len(msg)) < lastMsg.LengthRecv {
lastMsg.RecvMsg = msg
que.UnFinMsg.Store(conn, lastMsg)
return nil
}
if uint32(len(msg)) >= lastMsg.LengthRecv {
lastMsg.RecvMsg = msg[0:lastMsg.LengthRecv]
if que.Encode {
lastMsg.RecvMsg = que.DecodeFunc(lastMsg.RecvMsg)
}
msg = msg[lastMsg.LengthRecv:]
storeMsg := MsgQueue{
ID: lastMsg.ID,
Msg: lastMsg.RecvMsg,
Conn: conn,
}
//que.restoreMu.Lock()
que.push2list(storeMsg)
//que.restoreMu.Unlock()
que.UnFinMsg.Delete(conn)
return que.parseMessage(msg, conn)
}
} else {
lastID := int(lastMsg.LengthRecv) - len(lastMsg.RecvMsg)
if lastID < 0 {
que.UnFinMsg.Delete(conn)
return que.parseMessage(msg, conn)
}
if len(msg) >= lastID {
lastMsg.RecvMsg = bytesMerge(lastMsg.RecvMsg, msg[0:lastID])
if que.Encode {
lastMsg.RecvMsg = que.DecodeFunc(lastMsg.RecvMsg)
}
storeMsg := MsgQueue{
ID: lastMsg.ID,
Msg: lastMsg.RecvMsg,
Conn: conn,
}
que.push2list(storeMsg)
que.UnFinMsg.Delete(conn)
if len(msg) == lastID {
return nil
}
msg = msg[lastID:]
return que.parseMessage(msg, conn)
}
lastMsg.RecvMsg = bytesMerge(lastMsg.RecvMsg, msg)
que.UnFinMsg.Store(conn, lastMsg)
return nil
}
}
if len(msg) == 0 {
return nil
}
var start int
if start = searchHeader(msg); start == -1 {
return errors.New("data format error")
}
msg = msg[start:]
lastMsg := unFinMsg{}
que.UnFinMsg.Store(conn, &lastMsg)
return que.parseMessage(msg, conn)
}
func checkHeader(msg []byte) bool {
if len(msg) != 8 {
return false
}
for k, v := range msg {
if v != header[k] {
return false
}
}
return true
}
func searchHeader(msg []byte) int {
if len(msg) < 8 {
return 0
}
for k, v := range msg {
find := 0
if v == header[0] {
for k2, v2 := range header {
if msg[k+k2] == v2 {
find++
} else {
break
}
}
if find == 8 {
return k
}
}
}
return -1
}
func bytesMerge(src ...[]byte) []byte {
var buff bytes.Buffer
for _, v := range src {
buff.Write(v)
}
return buff.Bytes()
}
// Restore 获取收到的信息
func (que *StarQueue) Restore() (MsgQueue, error) {
if que.duration.Seconds() == 0 {
que.duration = 86400 * time.Second
}
for {
select {
case <-que.ctx.Done():
return MsgQueue{}, errors.New("Stoped By External Function Call")
case <-time.After(que.duration):
if que.duration != 0 {
return MsgQueue{}, os.ErrDeadlineExceeded
}
case data, ok := <-que.MsgPool:
if !ok {
return MsgQueue{}, os.ErrClosed
}
return data, nil
}
}
}
// RestoreOne 获取收到的一个信息
//兼容性修改
func (que *StarQueue) RestoreOne() (MsgQueue, error) {
return que.Restore()
}
// Stop 立即停止Restore
func (que *StarQueue) Stop() {
que.cancel()
}
// RestoreDuration Restore最大超时时间
func (que *StarQueue) RestoreDuration(tm time.Duration) {
que.duration = tm
}
func (que *StarQueue) RestoreChan() <-chan MsgQueue {
return que.MsgPool
}

@ -0,0 +1,28 @@
// +build darwin
package staros
import (
"os"
"os/exec"
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 0.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 0
)
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
func Beep(freq float64, duration int) error {
osa, err := exec.LookPath("osascript")
if err != nil {
// Output the only beep we can
_, err = os.Stdout.Write([]byte{7})
return err
}
cmd := exec.Command(osa, "-e", `beep`)
return cmd.Run()
}

138
vendor/b612.me/staros/beep_linux.go generated vendored

@ -0,0 +1,138 @@
// +build linux
package staros
import (
"errors"
"os"
"syscall"
"time"
"unsafe"
)
// Constants
const (
// This number represents the fixed frequency of the original PC XT's timer chip, which is approximately 1.193 MHz. This number
// is divided with the desired frequency to obtain a counter value, that is subsequently fed into the timer chip, tied to the PC speaker.
clockTickRate = 1193180
// linux/kd.h, start sound generation (0 for off)
kiocsound = 0x4B2F
// linux/input-event-codes.h
evSnd = 0x12 // Event type
sndTone = 0x02 // Sound
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 440.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 200
)
// inputEvent represents linux/input.h event structure.
type inputEvent struct {
Time syscall.Timeval // time in seconds since epoch at which event occurred
Type uint16 // event type
Code uint16 // event code related to the event type
Value int32 // event value related to the event type
}
// ioctl system call manipulates the underlying device parameters of special files.
func ioctl(fd, name, data uintptr) error {
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, name, data)
if e != 0 {
return e
}
return nil
}
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
//
// On Linux it needs permission to access `/dev/tty0` or `/dev/input/by-path/platform-pcspkr-event-spkr` files for writing,
// and `pcspkr` module must be loaded. User must be in correct groups, usually `input` and/or `tty`.
//
// If it can not open device files, it will fallback to sending Bell character (https://en.wikipedia.org/wiki/Bell_character).
// For bell character in X11 terminals you can enable bell with `xset b on`. For console check `setterm` and `--blength` or `--bfreq` options.
//
// On macOS this just sends bell character. Enable `Audible bell` in Terminal --> Preferences --> Settings --> Advanced.
//
// On Windows it uses Beep function via syscall.
//
// On Web it plays hard coded beep sound.
func Beep(freq float64, duration int) error {
if freq == 0 {
freq = DefaultFreq
} else if freq > 20000 {
freq = 20000
} else if freq < 0 {
freq = DefaultFreq
}
if duration == 0 {
duration = DefaultDuration
}
period := int(float64(clockTickRate) / freq)
var evdev bool
f, err := os.OpenFile("/dev/tty0", os.O_WRONLY, 0644)
if err != nil {
e := err
f, err = os.OpenFile("/dev/input/by-path/platform-pcspkr-event-spkr", os.O_WRONLY, 0644)
if err != nil {
e = errors.New("beeep: " + e.Error() + "; " + err.Error())
// Output the only beep we can
_, err = os.Stdout.Write([]byte{7})
if err != nil {
return errors.New(e.Error() + "; " + err.Error())
}
return nil
}
evdev = true
}
defer f.Close()
if evdev { // Use Linux evdev API
ev := inputEvent{}
ev.Type = evSnd
ev.Code = sndTone
ev.Value = int32(freq)
d := *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
// Start beep
f.Write(d[:])
time.Sleep(time.Duration(duration) * time.Millisecond)
ev.Value = 0
d = *(*[unsafe.Sizeof(ev)]byte)(unsafe.Pointer(&ev))
// Stop beep
f.Write(d[:])
} else { // Use ioctl
// Start beep
err = ioctl(f.Fd(), kiocsound, uintptr(period))
if err != nil {
return err
}
time.Sleep(time.Duration(duration) * time.Millisecond)
// Stop beep
err = ioctl(f.Fd(), kiocsound, uintptr(0))
if err != nil {
return err
}
}
return nil
}

@ -0,0 +1,41 @@
// +build windows
package staros
import (
"syscall"
)
var (
// DefaultFreq - frequency, in Hz, middle A
DefaultFreq = 587.0
// DefaultDuration - duration in milliseconds
DefaultDuration = 500
)
// Beep beeps the PC speaker (https://en.wikipedia.org/wiki/PC_speaker).
func Beep(freq float64, duration int) error {
if freq == 0 {
freq = DefaultFreq
} else if freq > 32767 {
freq = 32767
} else if freq < 37 {
freq = DefaultFreq
}
if duration == 0 {
duration = DefaultDuration
}
kernel32, _ := syscall.LoadLibrary("kernel32.dll")
beep32, _ := syscall.GetProcAddress(kernel32, "Beep")
defer syscall.FreeLibrary(kernel32)
_, _, e := syscall.Syscall(uintptr(beep32), uintptr(2), uintptr(int(freq)), uintptr(duration), 0)
if e != 0 {
return e
}
return nil
}

44
vendor/b612.me/staros/files.go generated vendored

@ -0,0 +1,44 @@
package staros
import (
"errors"
"os"
)
var ERR_ALREADY_LOCKED = errors.New("ALREADY LOCKED")
var ERR_TIMEOUT = errors.New("TIME OUT")
func NewFileLock(filepath string) FileLock {
return FileLock{
filepath: filepath,
}
}
// 检测文件/文件夹是否存在
func Exists(path string) bool {
_, err := os.Stat(path)
if err != nil && os.IsNotExist(err) {
return false
}
return true
}
// IsFile 返回给定文件地址是否是一个文件,
//True为是一个文件,False为不是文件或路径无效
func IsFile(fpath string) bool {
s, err := os.Stat(fpath)
if err != nil {
return false
}
return !s.IsDir()
}
// IsFolder 返回给定文件地址是否是一个文件夹,
//True为是一个文件夹,False为不是文件夹或路径无效
func IsFolder(fpath string) bool {
s, err := os.Stat(fpath)
if err != nil {
return false
}
return s.IsDir()
}

@ -0,0 +1,91 @@
//+build darwin
package staros
import (
"b612.me/stario"
"os"
"syscall"
"time"
)
type FileLock struct {
fd int
filepath string
}
func (f *FileLock) openFileForLock() error {
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
if err != nil {
return err
}
f.filepath = f.filepath
f.fd = fd
return nil
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
return syscall.Flock(f.fd, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
if err != nil {
syscall.Close(f.fd)
if err == syscall.EWOULDBLOCK {
return ERR_ALREADY_LOCKED
}
}
return err
}
func (f *FileLock) Unlock() error {
err := syscall.Flock(f.fd, syscall.LOCK_UN)
if err != nil {
return err
}
return syscall.Close(f.fd)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
err := f.Lock(Exclusive)
select {
case <-tmout:
f.Unlock()
return nil
default:
}
return err
})
}
func timespecToTime(ts syscall.Timespec) time.Time {
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctimespec)
}
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atimespec)
}

@ -0,0 +1,91 @@
//+build linux
package staros
import (
"b612.me/stario"
"os"
"syscall"
"time"
)
type FileLock struct {
fd int
filepath string
}
func timespecToTime(ts syscall.Timespec) time.Time {
return time.Unix(int64(ts.Sec), int64(ts.Nsec))
}
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Ctim)
}
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
return timespecToTime(fileinfo.Sys().(*syscall.Stat_t).Atim)
}
func (f *FileLock) openFileForLock() error {
fd, err := syscall.Open(f.filepath, syscall.O_CREAT|syscall.O_RDONLY, 0600)
if err != nil {
return err
}
f.filepath = f.filepath
f.fd = fd
return nil
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
return syscall.Flock(f.fd, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType int
if Exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}
if err := f.openFileForLock(); err != nil {
return err
}
err := syscall.Flock(f.fd, lockType|syscall.LOCK_NB)
if err != nil {
syscall.Close(f.fd)
if err == syscall.EWOULDBLOCK {
return ERR_ALREADY_LOCKED
}
}
return err
}
func (f *FileLock) Unlock() error {
err := syscall.Flock(f.fd, syscall.LOCK_UN)
if err != nil {
return err
}
return syscall.Close(f.fd)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
return stario.WaitUntilTimeout(tm, func(tmout chan struct{}) error {
err := f.Lock(Exclusive)
select {
case <-tmout:
f.Unlock()
return nil
default:
}
return err
})
}

@ -0,0 +1,123 @@
// +build windows
package staros
import (
"b612.me/win32api"
"os"
"syscall"
"time"
)
type FileLock struct {
filepath string
handle win32api.HANDLE
}
func GetFileCreationTime(fileinfo os.FileInfo) time.Time {
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
return time.Unix(0, d.CreationTime.Nanoseconds())
}
func GetFileAccessTime(fileinfo os.FileInfo) time.Time {
d := fileinfo.Sys().(*syscall.Win32FileAttributeData)
return time.Unix(0, d.LastAccessTime.Nanoseconds())
}
func SetFileTimes(file *os.File, info os.FileInfo) {
}
func SetFileTimesbyTime(file *os.File) {
}
func (f *FileLock) openFileForLock() error {
name, err := syscall.UTF16PtrFromString(f.filepath)
if err != nil {
return err
}
handle, err := syscall.CreateFile(
name,
syscall.GENERIC_READ,
syscall.FILE_SHARE_READ,
nil,
syscall.OPEN_ALWAYS,
syscall.FILE_FLAG_OVERLAPPED|0x00000080,
0)
if err != nil {
return err
}
f.handle = win32api.HANDLE(handle)
return nil
}
func (f *FileLock) lockForTimeout(timeout time.Duration, lockType win32api.DWORD) error {
var err error
if err = f.openFileForLock(); err != nil {
return err
}
event, err := win32api.CreateEventW(nil, true, false, nil)
if err != nil {
return err
}
myEvent := &syscall.Overlapped{HEvent: syscall.Handle(event)}
defer syscall.CloseHandle(myEvent.HEvent)
_, err = win32api.LockFileEx(f.handle, lockType, 0, 1, 0, myEvent)
if err == nil {
return nil
}
if err != syscall.ERROR_IO_PENDING {
return err
}
millis := uint32(syscall.INFINITE)
if timeout >= 0 {
millis = uint32(timeout.Nanoseconds() / 1000000)
}
s, err := syscall.WaitForSingleObject(myEvent.HEvent, millis)
switch s {
case syscall.WAIT_OBJECT_0:
// success!
return nil
case syscall.WAIT_TIMEOUT:
f.Unlock()
return ERR_TIMEOUT
default:
f.Unlock()
return err
}
}
func (f *FileLock) Lock(Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(0, lockType)
}
func (f *FileLock) LockWithTimeout(tm time.Duration, Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(tm, lockType)
}
func (f *FileLock) LockNoBlocking(Exclusive bool) error {
var lockType win32api.DWORD
if Exclusive {
lockType = win32api.LOCKFILE_EXCLUSIVE_LOCK
} else {
lockType = 0
}
return f.lockForTimeout(0, lockType|win32api.LOCKFILE_FAIL_IMMEDIATELY)
}
func (f *FileLock) Unlock() error {
return syscall.Close(syscall.Handle(f.handle))
}

305
vendor/b612.me/staros/math.go generated vendored

@ -0,0 +1,305 @@
package staros
import (
"errors"
"fmt"
"math"
"strconv"
"strings"
)
func Calc(math string) (float64, error) {
math = strings.Replace(math, " ", "", -1)
math = strings.ToLower(math)
if err := check(math); err != nil {
return 0, err
}
result,err:=calc(math)
if err!=nil {
return 0,err
}
return floatRound(result,15),nil
}
func floatRound(f float64, n int) float64 {
format := "%." + strconv.Itoa(n) + "f"
res, _ := strconv.ParseFloat(fmt.Sprintf(format, f), 64)
return res
}
func check(math string) error {
math = strings.Replace(math, " ", "", -1)
math = strings.ToLower(math)
var bracketSum int
var signReady bool
for k, v := range math {
if string([]rune{v}) == "(" {
bracketSum++
}
if string([]rune{v}) == ")" {
bracketSum--
}
if bracketSum < 0 {
return fmt.Errorf("err at position %d.Reason is right bracket position not correct,except (", k)
}
if containSign(string([]rune{v})) {
if signReady {
if string([]rune{v}) != "+" && string([]rune{v}) != "-" {
return fmt.Errorf("err at position %d.Reason is sign %s not correct", k, string([]rune{v}))
}
} else {
signReady = true
continue
}
}
signReady = false
}
if bracketSum != 0 {
return fmt.Errorf("Error:right bracket is not equal as left bracket")
}
return nil
}
func calc(math string) (float64, error) {
var bracketLeft int
var bracketRight int
var DupStart int = -1
for pos, str := range math {
if string(str) == "(" {
bracketLeft = pos
}
if string(str) == ")" {
bracketRight = pos
break
}
}
if bracketRight == 0 && bracketLeft != 0 || (bracketLeft > bracketRight) {
return 0, fmt.Errorf("Error:bracket not correct at %d ,except )", bracketLeft)
}
if bracketRight == 0 && bracketLeft == 0 {
return calcLong(math)
}
line := math[bracketLeft+1 : bracketRight]
num, err := calcLong(line)
if err != nil {
return 0, err
}
for i := bracketLeft - 1; i >= 0; i-- {
if !containSign(math[i : i+1]) {
DupStart = i
continue
}
break
}
if DupStart != -1 {
sign := math[DupStart:bracketLeft]
num, err := calcDuaFloat(sign, num)
if err != nil {
return 0, err
}
math = math[:DupStart] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:]
DupStart = -1
} else {
math = math[:bracketLeft] + fmt.Sprintf("%.15f", num) + math[bracketRight+1:]
}
return calc(math)
}
func calcLong(str string) (float64, error) {
var sigReady bool = false
var sigApply bool = false
var numPool []float64
var operPool []string
var numStr string
var oper string
if str[0:1] == "+" || str[0:1] == "-" {
sigReady = true
}
for _, stp := range str {
if sigReady && containSign(string(stp)) {
sigReady = false
sigApply = true
oper = string(stp)
continue
}
if !containSign(string(stp)) {
sigReady = false
numStr = string(append([]rune(numStr), stp))
continue
}
if !sigReady {
sigReady = true
}
if sigApply {
num, err := calcDua(oper, numStr)
if err != nil {
return 0, err
}
sigApply = false
numPool = append(numPool, num)
} else {
num, err := parseNumbic(numStr)
if err != nil {
return 0, err
}
numPool = append(numPool, num)
}
numStr = ""
operPool = append(operPool, string(stp))
}
if sigApply {
num, err := calcDua(oper, numStr)
if err != nil {
return 0, err
}
numPool = append(numPool, num)
} else {
num, err := parseNumbic(numStr)
if err != nil {
return 0, err
}
numPool = append(numPool, num)
}
return calcPool(numPool, operPool)
}
func calcPool(numPool []float64, operPool []string) (float64, error) {
if len(numPool) == 1 && len(operPool) == 0 {
return numPool[0], nil
}
if len(numPool) < len(operPool) {
return 0, errors.New(("Operate Signal Is too much"))
}
calcFunc := func(k int, v string) (float64, error) {
num, err := calcSigFloat(numPool[k], v, numPool[k+1])
if err != nil {
return 0, err
}
tmp := append(numPool[:k], num)
numPool = append(tmp, numPool[k+2:]...)
operPool = append(operPool[:k], operPool[k+1:]...)
return calcPool(numPool, operPool)
}
for k, v := range operPool {
if v == "^" {
return calcFunc(k, v)
}
}
for k, v := range operPool {
if v == "*" || v == "/" {
return calcFunc(k, v)
}
}
for k, v := range operPool {
return calcFunc(k, v)
}
return 0, nil
}
func calcSigFloat(floatA float64, b string, floatC float64) (float64, error) {
switch b {
case "+":
return floatRound(floatA + floatC,15), nil
case "-":
return floatRound(floatA - floatC,15), nil
case "*":
return floatRound(floatA * floatC,15), nil
case "/":
if floatC == 0 {
return 0, errors.New("Divisor cannot be 0")
}
return floatRound(floatA / floatC,15), nil
case "^":
return math.Pow(floatA, floatC), nil
}
return 0, fmt.Errorf("unexpect method:%s", b)
}
func calcSig(a, b, c string) (float64, error) {
floatA, err := parseNumbic(a)
if err != nil {
return 0, err
}
floatC, err := parseNumbic(c)
if err != nil {
return 0, err
}
return calcSigFloat(floatA, b, floatC)
}
func calcDuaFloat(a string, floatB float64) (float64, error) {
switch a {
case "sin":
return math.Sin(floatB), nil
case "cos":
return math.Cos(floatB), nil
case "tan":
return math.Tan(floatB), nil
case "abs":
return math.Abs(floatB), nil
case "arcsin":
return math.Asin(floatB), nil
case "arccos":
return math.Acos(floatB), nil
case "arctan":
return math.Atan(floatB), nil
case "sqrt":
return math.Sqrt(floatB), nil
case "loge":
return math.Log(floatB), nil
case "log10":
return math.Log10(floatB), nil
case "log2":
return math.Log2(floatB), nil
case "floor":
return math.Floor(floatB), nil
case "ceil":
return math.Ceil(floatB), nil
case "round":
return math.Round(floatB), nil
case "trunc":
return math.Trunc(floatB), nil
case "+":
return 0 + floatB, nil
case "-":
return 0 - floatB, nil
}
return 0, fmt.Errorf("unexpect method:%s", a)
}
func calcDua(a, b string) (float64, error) {
floatB, err := parseNumbic(b)
if err != nil {
return 0, err
}
return calcDuaFloat(a, floatB)
}
func parseNumbic(str string) (float64, error) {
switch str {
case "pi":
return float64(math.Pi), nil
case "e":
return float64(math.E), nil
default:
return strconv.ParseFloat(str, 64)
}
}
func containSign(str string) bool {
var sign []string = []string{"+", "-", "*", "/", "^"}
for _, v := range sign {
if str == v {
return true
}
}
return false
}
func contain(pool []string, str string) bool {
for _, v := range pool {
if v == str {
return true
}
}
return false
}

@ -0,0 +1,101 @@
//+build darwin
package staros
import (
"encoding/binary"
"fmt"
"golang.org/x/sys/unix"
"os/exec"
"strconv"
"strings"
"unsafe"
)
// Memory 系统内存信息
func Memory() (MemStatus,error) {
return darwinMemory()
}
type swapUsage struct {
Total uint64
Avail uint64
Used uint64
Pagesize int32
Encrypted bool
}
func darwinMemory() (MemStatus, error) {
var err error
var res MemStatus
vm_stat, err := exec.LookPath("vm_stat")
if err != nil {
return res, err
}
out, err := exec.Command(vm_stat).CombinedOutput()
if err != nil {
return res, err
}
totalString, err := unix.Sysctl("hw.memsize")
if err != nil {
return res, err
}
// unix.sysctl() helpfully assumes the result is a null-terminated string and
// removes the last byte of the result if it's 0 :/
totalString += "\x00"
res.All = uint64(binary.LittleEndian.Uint64([]byte(totalString)))
lines := strings.Split(string(out), "\n")
pagesize := uint64(unix.Getpagesize())
for _, line := range lines {
fields := strings.Split(line, ":")
if len(fields) < 2 {
continue
}
key := strings.TrimSpace(fields[0])
value := strings.Trim(fields[1], " .")
switch key {
case "Pages free":
free, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
res.Free = free * pagesize
case "Pages inactive":
inactive, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
res.Available = inactive * pagesize
case "Pages active":
active, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
_ = active * pagesize
case "Pages wired down":
wired, e := strconv.ParseUint(value, 10, 64)
if e != nil {
err = e
}
_ = wired * pagesize
}
}
res.Available += res.Free
res.Used = res.All - res.Available
//swap
value, err := unix.SysctlRaw("vm.swapusage")
if err != nil {
return res, err
}
if len(value) != 32 {
return res, fmt.Errorf("unexpected output of sysctl vm.swapusage: %v (len: %d)", value, len(value))
}
swap := (*swapUsage)(unsafe.Pointer(&value[0]))
res.SwapAll = swap.Total
res.SwapUsed = swap.Used
res.SwapFree = swap.Avail
return res, err
}

@ -0,0 +1,24 @@
//+build linux
package staros
import "syscall"
// Memory 系统内存信息
func Memory() (MemStatus, error) {
var mem MemStatus
ram := new(syscall.Sysinfo_t)
if err := syscall.Sysinfo(ram); err != nil {
return mem, err
}
mem.All = uint64(ram.Totalram)
mem.BuffCache = uint64(ram.Bufferram)
mem.Free = uint64(ram.Freeram)
mem.Shared = uint64(ram.Sharedram)
mem.Available = uint64(ram.Freeram + ram.Sharedram + ram.Bufferram)
mem.SwapAll = uint64(ram.Totalswap)
mem.SwapFree = uint64(ram.Freeswap)
mem.SwapUsed = uint64(mem.SwapAll - mem.SwapFree)
mem.Used = uint64(mem.All - mem.Free)
return mem, nil
}

@ -0,0 +1,26 @@
// +build windows
package staros
import "b612.me/win32api"
// Memory 系统内存信息
func Memory() (MemStatus, error) {
var mem MemStatus
ram := new(win32api.MEMORYSTATUSEX)
_, err := win32api.GlobalMemoryStatusEx(ram)
if err != nil {
return mem, err
}
mem.All = uint64(ram.UllTotalPhys)
mem.Free = uint64(ram.UllAvailPhys)
mem.Available = uint64(ram.UllAvailPhys)
mem.Used = uint64(mem.All - mem.Free)
mem.SwapAll = uint64(ram.UllTotalPageFile)
mem.SwapFree = uint64(ram.UllAvailPageFile)
mem.SwapUsed = mem.SwapAll - mem.SwapFree
mem.VirtualAll = uint64(mem.VirtualAll)
mem.VirtualAvail = uint64(mem.VirtualAvail)
mem.VirtualUsed = mem.VirtualAll - mem.VirtualUsed
return mem, nil
}

@ -0,0 +1,319 @@
// +build !windows
package staros
import (
"errors"
"io/ioutil"
"os"
"strconv"
"strings"
"time"
)
func NetUsage() ([]NetAdapter, error) {
data, err := ioutil.ReadFile("/proc/net/dev")
if err != nil {
return []NetAdapter{}, err
}
sps := strings.Split(strings.TrimSpace(string(data)), "\n")
if len(sps) < 3 {
return []NetAdapter{}, errors.New("No Adaptor")
}
var res []NetAdapter
netLists := sps[2:]
for _, v := range netLists {
v = strings.ReplaceAll(v, " ", " ")
for strings.Contains(v, " ") {
v = strings.ReplaceAll(v, " ", " ")
}
v = strings.TrimSpace(v)
card := strings.Split(v, " ")
name := strings.ReplaceAll(card[0], ":", "")
recvBytes, _ := strconv.Atoi(card[1])
sendBytes, _ := strconv.Atoi(card[9])
res = append(res, NetAdapter{name, uint64(recvBytes), uint64(sendBytes)})
}
return res, nil
}
func NetUsageByname(name string) (NetAdapter, error) {
ada, err := NetUsage()
if err != nil {
return NetAdapter{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetAdapter{}, errors.New("Not Found")
}
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
list1, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
time.Sleep(duration)
list2, err := NetUsage()
if err != nil {
return []NetSpeed{}, err
}
if len(list1) > len(list2) {
return []NetSpeed{}, errors.New("NetWork Adaptor Num Not ok")
}
var res []NetSpeed
for k, v := range list1 {
recv := float64(list2[k].RecvBytes-v.RecvBytes) / duration.Seconds()
send := float64(list2[k].SendBytes-v.SendBytes) / duration.Seconds()
res = append(res, NetSpeed{v.Name, recv, send})
}
return res, nil
}
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
ada, err := NetSpeeds(duration)
if err != nil {
return NetSpeed{}, err
}
for _, v := range ada {
if v.Name == name {
return v, nil
}
}
return NetSpeed{}, errors.New("Not Found")
}
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
func NetConnections(analysePid bool,types string) ([]NetConn, error) {
var result []NetConn
var inodeMap map[string]int64
var err error
var fileList []string
if types=="" || strings.Contains(strings.ToLower(types),"all") {
fileList = []string{
"/proc/net/tcp",
"/proc/net/tcp6",
"/proc/net/udp",
"/proc/net/udp6",
"/proc/net/unix",
}
}
if strings.Contains(strings.ToLower(types),"tcp") {
fileList =append(fileList,"/proc/net/tcp","/proc/net/tcp6")
}
if strings.Contains(strings.ToLower(types),"udp") {
fileList =append(fileList,"/proc/net/udp","/proc/net/udp6")
}
if strings.Contains(strings.ToLower(types),"unix") {
fileList =append(fileList,"/proc/net/unix")
}
if analysePid {
inodeMap, err = GetInodeMap()
if err != nil {
return result, err
}
}
for _, file := range fileList {
data, err := ioutil.ReadFile(file)
if err != nil {
return result, err
}
tmpRes, err := analyseNetFiles(data, inodeMap, file[strings.LastIndex(file, "/")+1:])
if err != nil {
return result, err
}
result = append(result, tmpRes...)
}
return result, nil
}
func GetInodeMap() (map[string]int64, error) {
res := make(map[string]int64)
paths, err := ioutil.ReadDir("/proc")
if err != nil {
return nil, err
}
for _, v := range paths {
if v.IsDir() && Exists("/proc/"+v.Name()+"/fd") {
fds, err := ioutil.ReadDir("/proc/" + v.Name() + "/fd")
if err != nil && Exists("/proc/"+v.Name()+"/fd") {
return nil, err
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + v.Name() + "/fd/" + fd.Name())
if err != nil {
continue
}
if !strings.Contains(socket, "socket") {
continue
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
pid, err := strconv.ParseInt(v.Name(), 10, 64)
if err != nil {
break
}
res[socket[start+1:len(socket)-1]] = pid
}
}
}
return res, err
}
func analyseNetFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
if typed == "unix" {
return analyseUnixFiles(data, inodeMap, typed)
}
var result []NetConn
strdata := strings.TrimSpace(string(data))
strdata = remainOne(strdata, " ", " ")
csvData := strings.Split(strdata, "\n")
pidMap := make(map[int64]*Process)
for line, lineData := range csvData {
if line == 0 {
continue
}
v := strings.Split(strings.TrimSpace(lineData), " ")
var res NetConn
ip, port, err := parseHexIpPort(v[1])
if err != nil {
return result, err
}
res.LocalAddr = ip
res.LocalPort = port
ip, port, err = parseHexIpPort(v[2])
if err != nil {
return result, err
}
res.RemoteAddr = ip
res.RemotePort = port
//connection state
if strings.Contains(typed, "tcp") {
state, err := strconv.ParseInt(strings.TrimSpace(v[3]), 16, 64)
if err != nil {
return result, err
}
res.Status = TCP_STATE[state]
}
txrx_queue := strings.Split(strings.TrimSpace(v[4]), ":")
if len(txrx_queue) != 2 {
return result, errors.New("not a valid net file")
}
tx_queue, err := strconv.ParseInt(txrx_queue[0], 16, 64)
if err != nil {
return result, err
}
res.TX_Queue = tx_queue
rx_queue, err := strconv.ParseInt(txrx_queue[1], 16, 64)
if err != nil {
return result, err
}
res.RX_Queue = rx_queue
timer := strings.Split(strings.TrimSpace(v[5]), ":")
if len(timer) != 2 {
return result, errors.New("not a valid net file")
}
switch timer[0] {
case "00":
res.TimerActive = "NO_TIMER"
case "01":
//重传定时器
res.TimerActive = "RETRANSMIT"
case "02":
//连接定时器、FIN_WAIT_2定时器或TCP保活定时器
res.TimerActive = "KEEPALIVE"
case "03":
//TIME_WAIT定时器
res.TimerActive = "TIME_WAIT"
case "04":
//持续定时器
res.TimerActive = "ZERO_WINDOW_PROBE"
default:
res.TimerActive = "UNKNOWN"
}
timerJif, err := strconv.ParseInt(timer[1], 16, 64)
if err != nil {
return result, err
}
res.TimerJiffies = timerJif
timerCnt, err := strconv.ParseInt(strings.TrimSpace(v[6]), 16, 64)
if err != nil {
return result, err
}
res.RtoTimer = timerCnt
res.Uid, err = strconv.ParseInt(v[7], 10, 64)
if err != nil {
return result, err
}
res.Inode = v[9]
if inodeMap != nil && len(inodeMap) > 0 {
var ok bool
res.Pid, ok = inodeMap[res.Inode]
if !ok {
res.Pid = -1
} else {
_, ok := pidMap[res.Pid]
if !ok {
tmp, err := FindProcessByPid(res.Pid)
if err != nil {
pidMap[res.Pid] = nil
} else {
pidMap[res.Pid] = &tmp
}
}
res.Process = pidMap[res.Pid]
}
}
res.Typed = typed
result = append(result, res)
}
return result, nil
}
func analyseUnixFiles(data []byte, inodeMap map[string]int64, typed string) ([]NetConn, error) {
var result []NetConn
strdata := strings.TrimSpace(string(data))
strdata = remainOne(strdata, " ", " ")
csvData := strings.Split(strdata, "\n")
pidMap := make(map[int64]*Process)
for line, lineData := range csvData {
if line == 0 {
continue
}
v := strings.Split(strings.TrimSpace(lineData), " ")
var res NetConn
res.Inode = v[6]
if len(v) == 8 {
res.Socket = v[7]
}
if inodeMap != nil && len(inodeMap) > 0 {
var ok bool
res.Pid, ok = inodeMap[res.Inode]
if !ok {
res.Pid = -1
} else {
_, ok := pidMap[res.Pid]
if !ok || pidMap[res.Pid] == nil {
tmp, err := FindProcessByPid(res.Pid)
if err != nil {
pidMap[res.Pid] = nil
} else {
pidMap[res.Pid] = &tmp
}
}
if pidMap[res.Pid] != nil {
res.Uid = int64(pidMap[res.Pid].RUID)
res.Process = pidMap[res.Pid]
}
}
}
res.Typed = typed
result = append(result, res)
}
return result, nil
}

@ -0,0 +1,33 @@
// +build windows
package staros
import (
"time"
)
func NetUsage() ([]NetAdapter, error) {
var res []NetAdapter
return res, nil
}
func NetUsageByname(name string) (NetAdapter, error) {
return NetAdapter{}, nil
}
func NetSpeeds(duration time.Duration) ([]NetSpeed, error) {
var res []NetSpeed
return res, nil
}
func NetSpeedsByName(duration time.Duration, name string) (NetSpeed, error) {
return NetSpeed{}, nil
}
// NetConnections return all TCP/UDP/UNIX DOMAIN SOCKET Connections
// if your uid != 0 ,and analysePid==true ,you should have CAP_SYS_PRTACE and CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH Caps
func NetConnections(analysePid bool) ([]NetConn, error) {
var result []NetConn
return result, nil
}

47
vendor/b612.me/staros/os.go generated vendored

@ -0,0 +1,47 @@
package staros
import (
"os/user"
"strconv"
)
// GetUidGid
func GetUidGid(uname string) (uint32, uint32, string, error) {
usr, err := user.Lookup(uname)
if err != nil {
return 0, 0, "", err
}
uidInt, _ := strconv.Atoi(usr.Uid)
gidInt, _ := strconv.Atoi(usr.Gid)
return uint32(uidInt), uint32(gidInt), usr.HomeDir, nil
}
// GetUid
func GetUid(uname string) (uint32, error) {
usr, err := user.Lookup(uname)
if err != nil {
return 0, err
}
uidInt, _ := strconv.Atoi(usr.Uid)
return uint32(uidInt), nil
}
// GetGid
func GetGid(uname string) (uint32, error) {
usr, err := user.LookupGroup(uname)
if err != nil {
return 0, err
}
gidInt, _ := strconv.Atoi(usr.Gid)
return uint32(gidInt), nil
}
// GetGidByName
func GetGidByName(uname string) (uint32, error) {
usr, err := user.Lookup(uname)
if err != nil {
return 0, err
}
uidInt, _ := strconv.Atoi(usr.Gid)
return uint32(uidInt), nil
}

152
vendor/b612.me/staros/os_unix.go generated vendored

@ -0,0 +1,152 @@
// +build linux darwin unix
package staros
import (
"bytes"
"fmt"
"io/ioutil"
"os/user"
"strconv"
"strings"
"syscall"
"time"
)
var clockTicks = 100 // default value
// StartTime 开机时间
func StartTime() time.Time {
tmp, _ := readAsString("/proc/stat")
data := splitBy(ReplaceByte9(tmp), " ")
btime, _ := strconv.ParseInt(strings.TrimSpace(data["btime"]), 10, 64)
return time.Unix(btime, 0)
}
// IsRoot 当前是否是管理员用户
func IsRoot() bool {
uid, _ := user.Current()
if uid.Uid == "0" {
return true
}
return false
}
func Whoami() (uid, gid int, uname, gname, home string, err error) {
var me *user.User
var gup *user.Group
me, err = user.Current()
if err != nil {
return
}
uid, _ = strconv.Atoi(me.Uid)
gid, _ = strconv.Atoi(me.Uid)
home = me.HomeDir
uname = me.Username
gup, err = user.LookupGroupId(me.Gid)
if err != nil {
return
}
gname = gup.Name
return
}
func getCPUSample() (idle, total uint64) {
contents, err := ioutil.ReadFile("/proc/stat")
if err != nil {
return
}
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
fields := strings.Fields(line)
if fields[0] == "cpu" {
numFields := len(fields)
for i := 1; i < numFields; i++ {
val, err := strconv.ParseUint(fields[i], 10, 64)
if err != nil {
fmt.Println("Error: ", i, fields[i], err)
}
total += val // tally up all the numbers to get total ticks
if i == 4 || i == 5 { // idle is the 5th field in the cpu line
idle += val
}
}
return
}
}
return
}
func splitProcStat(content []byte) []string {
nameStart := bytes.IndexByte(content, '(')
nameEnd := bytes.LastIndexByte(content, ')')
restFields := strings.Fields(string(content[nameEnd+2:])) // +2 skip ') '
name := content[nameStart+1 : nameEnd]
pid := strings.TrimSpace(string(content[:nameStart]))
fields := make([]string, 3, len(restFields)+3)
fields[1] = string(pid)
fields[2] = string(name)
fields = append(fields, restFields...)
return fields
}
func getCPUSampleByPid(pid int) float64 {
contents, err := ioutil.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
if err != nil {
return 0
}
fields := splitProcStat(contents)
utime, err := strconv.ParseFloat(fields[14], 64)
if err != nil {
return 0
}
stime, err := strconv.ParseFloat(fields[15], 64)
if err != nil {
return 0
}
// There is no such thing as iotime in stat file. As an approximation, we
// will use delayacct_blkio_ticks (aggregated block I/O delays, as per Linux
// docs). Note: I am assuming at least Linux 2.6.18
var iotime float64
if len(fields) > 42 {
iotime, err = strconv.ParseFloat(fields[42], 64)
if err != nil {
iotime = 0 // Ancient linux version, most likely
}
} else {
iotime = 0 // e.g. SmartOS containers
}
return utime/float64(clockTicks) + stime/float64(clockTicks) + iotime/float64(clockTicks)
}
func CpuUsageByPid(pid int, sleep time.Duration) float64 {
total1 := getCPUSampleByPid(pid)
time.Sleep(sleep)
total2 := getCPUSampleByPid(pid)
return (total2 - total1) / sleep.Seconds() * 100
}
// CpuUsage 获取CPU使用量
func CpuUsage(sleep time.Duration) float64 {
idle0, total0 := getCPUSample()
time.Sleep(sleep)
idle1, total1 := getCPUSample()
idleTicks := float64(idle1 - idle0)
totalTicks := float64(total1 - total0)
cpuUsage := 100 * (totalTicks - idleTicks) / totalTicks
return cpuUsage
//fmt.Printf("CPU usage is %f%% [busy: %f, total: %f]\n", cpuUsage, totalTicks-idleTicks, totalTicks)
}
func DiskUsage(path string) (disk DiskStatus) {
fs := syscall.Statfs_t{}
err := syscall.Statfs(path, &fs)
if err != nil {
return
}
disk.All = fs.Blocks * uint64(fs.Bsize)
disk.Free = fs.Bfree * uint64(fs.Bsize)
disk.Available = fs.Bavail * uint64(fs.Bsize)
disk.Used = disk.All - disk.Free
return
}

@ -0,0 +1,60 @@
// +build windows
package staros
import (
"log"
"syscall"
"time"
"unsafe"
"b612.me/wincmd"
"b612.me/win32api"
)
// StartTime 开机时间
func StartTime() time.Time {
data, _ := win32api.GetTickCount()
date := float64(time.Now().Unix())
unix := date - float64(data)/1000
max := (unix - float64(int64(unix))) * 1000000000
return time.Unix(int64(unix), int64(max))
}
// IsRoot 当前是否是管理员用户
func IsRoot() bool {
return wincmd.Isas()
}
func DiskUsage(path string) (disk DiskStatus) {
kernel32, err := syscall.LoadLibrary("Kernel32.dll")
if err != nil {
log.Panic(err)
}
defer syscall.FreeLibrary(kernel32)
GetDiskFreeSpaceEx, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetDiskFreeSpaceExW")
if err != nil {
log.Panic(err)
}
lpFreeBytesAvailable := int64(0)
lpTotalNumberOfBytes := int64(0)
lpTotalNumberOfFreeBytes := int64(0)
syscall.Syscall6(uintptr(GetDiskFreeSpaceEx), 4,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("C:"))),
uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)), 0, 0)
disk.Free = uint64(lpTotalNumberOfFreeBytes)
disk.Used = uint64(lpTotalNumberOfBytes - lpTotalNumberOfFreeBytes)
disk.All = uint64(lpTotalNumberOfBytes)
disk.Available = uint64(lpFreeBytesAvailable)
return
}
func CpuUsage(sleep time.Duration) float64 {
return 0
}

347
vendor/b612.me/staros/process.go generated vendored

@ -0,0 +1,347 @@
package staros
import (
"bytes"
"context"
"errors"
"io"
"os"
"os/exec"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
)
//StarCmd Is Here
type StarCmd struct {
CMD *exec.Cmd
outfile io.ReadCloser
infile io.WriteCloser
errfile io.ReadCloser
running int32
//Store AlL of the Standed Outputs
stdout []byte
//Store All of the Standed Errors
errout []byte
runerr error
exitcode int
stdoutBuf *bytes.Buffer
stderrBuf *bytes.Buffer
stdoutpoint int
stderrpoint int
lock sync.Mutex
prewrite []string
prewritetime time.Duration
stopctxfunc context.CancelFunc
stopctx context.Context
}
func Command(command string, args ...string) (*StarCmd, error) {
var err error
shell := new(StarCmd)
shell.running = 0
shell.prewritetime = time.Millisecond * 200
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
cmd := exec.Command(command, args...)
shell.CMD = cmd
shell.infile, err = shell.CMD.StdinPipe()
if err != nil {
return shell, err
}
shell.errfile, err = shell.CMD.StderrPipe()
if err != nil {
return shell, err
}
shell.outfile, err = shell.CMD.StdoutPipe()
if err != nil {
return shell, err
}
shell.runerr = nil
shell.exitcode = -999
return shell, nil
}
func CommandContext(ctx context.Context, command string, args ...string) (*StarCmd, error) {
var err error
shell := new(StarCmd)
shell.running = 0
shell.stdoutBuf = bytes.NewBuffer(make([]byte, 0))
shell.stderrBuf = bytes.NewBuffer(make([]byte, 0))
shell.prewritetime = time.Millisecond * 200
shell.stopctx, shell.stopctxfunc = context.WithCancel(context.Background())
cmd := exec.CommandContext(ctx, command, args...)
shell.CMD = cmd
shell.infile, err = shell.CMD.StdinPipe()
if err != nil {
return shell, err
}
shell.errfile, err = shell.CMD.StderrPipe()
if err != nil {
return shell, err
}
shell.outfile, err = shell.CMD.StdoutPipe()
if err != nil {
return shell, err
}
shell.runerr = nil
shell.exitcode = -999
return shell, nil
}
func (starcli *StarCmd) queryStdout(ctx context.Context) {
for starcli.IsRunning() && starcli.CMD != nil {
select {
case <-ctx.Done():
return
default:
}
out := make([]byte, 65535)
n, err := starcli.outfile.Read(out)
if n != 0 {
starcli.lock.Lock()
starcli.stdoutBuf.Write(out[:n])
starcli.lock.Unlock()
for _, v := range out[:n] {
starcli.stdout = append(starcli.stdout, v)
}
}
if err != nil {
if err == io.EOF {
break
} else {
if !strings.Contains(err.Error(), "file already closed") {
starcli.runerr = err
}
return
}
}
}
}
func (starcli *StarCmd) queryStderr(ctx context.Context) {
for starcli.IsRunning() && starcli.CMD != nil {
select {
case <-ctx.Done():
return
default:
}
out := make([]byte, 65535)
n, err := starcli.errfile.Read(out)
if n != 0 {
starcli.lock.Lock()
starcli.stderrBuf.Write(out[:n])
starcli.lock.Unlock()
for _, v := range out[:n] {
starcli.errout = append(starcli.errout, v)
}
}
if err != nil {
if err == io.EOF {
break
} else {
if !strings.Contains(err.Error(), "file already closed") {
starcli.runerr = err
}
return
}
}
}
return
}
func (starcli *StarCmd) NowLineOutput() (string, error) {
starcli.lock.Lock()
buf, _ := starcli.stdoutBuf.ReadBytes('\n')
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
starcli.lock.Unlock()
if len(buferr) != 0 {
return string(buf), errors.New(string(buferr))
}
return string(buf), nil
}
func (starcli *StarCmd) NowLineStdOut() string {
starcli.lock.Lock()
defer starcli.lock.Unlock()
buf, _ := starcli.stdoutBuf.ReadBytes('\n')
return string(buf)
}
func (starcli *StarCmd) NowLineStdErr() error {
starcli.lock.Lock()
defer starcli.lock.Unlock()
buferr, _ := starcli.stderrBuf.ReadBytes(byte('\n'))
if len(buferr) != 0 {
return errors.New(string(buferr))
}
return nil
}
func (starcli *StarCmd) NowAllOutput() (string, error) {
var outstr string
starcli.lock.Lock()
buf := make([]byte, starcli.stdoutBuf.Len())
n, _ := starcli.stdoutBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 {
outstr = string(buf[:n])
}
if starcli.runerr != nil {
return outstr, starcli.runerr
}
starcli.lock.Lock()
buf = make([]byte, starcli.stderrBuf.Len())
n, _ = starcli.stderrBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 {
return outstr, errors.New(string(buf[:n]))
}
return outstr, nil
}
func (starcli *StarCmd) NowStdOut() string {
var outstr string
starcli.lock.Lock()
buf := make([]byte, starcli.stdoutBuf.Len())
n, _ := starcli.stdoutBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 {
outstr = string(buf[:n])
}
return outstr
}
func (starcli *StarCmd) NowStdErr() error {
starcli.lock.Lock()
buf := make([]byte, starcli.stderrBuf.Len())
n, _ := starcli.stderrBuf.Read(buf)
starcli.lock.Unlock()
if n != 0 {
return errors.New(string(buf[:n]))
}
return nil
}
func (starcli *StarCmd) AllOutPut() (string, error) {
err := starcli.runerr
if err == nil && len(starcli.errout) != 0 {
err = errors.New(string(starcli.errout))
}
return string(starcli.stdout), err
}
func (starcli *StarCmd) AllStdOut() string {
return string(starcli.stdout)
}
func (starcli *StarCmd) AllStdErr() error {
err := starcli.runerr
if err == nil && len(starcli.errout) != 0 {
err = errors.New(string(starcli.errout))
}
return err
}
func (starcli *StarCmd) setRunning(alive bool) {
if alive {
val := atomic.LoadInt32(&starcli.running)
if val == 0 {
atomic.AddInt32(&starcli.running, 1)
} else {
atomic.AddInt32(&starcli.running, 1-val)
}
return
}
val := atomic.LoadInt32(&starcli.running)
if val == 1 {
atomic.AddInt32(&starcli.running, -1)
} else {
atomic.AddInt32(&starcli.running, -val)
}
}
func (starcli *StarCmd) Start() error {
if err := starcli.CMD.Start(); err != nil {
return err
}
starcli.setRunning(true)
go func() {
err := starcli.CMD.Wait()
if err != nil {
starcli.runerr = err
}
starcli.stopctxfunc()
starcli.setRunning(false)
if starcli.CMD.ProcessState != nil {
starcli.exitcode = starcli.CMD.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
}
}()
go starcli.queryStdout(starcli.stopctx)
go starcli.queryStderr(starcli.stopctx)
go func(ctx context.Context) {
if len(starcli.prewrite) != 0 {
for _, v := range starcli.prewrite {
select {
case <-ctx.Done():
return
default:
break
}
starcli.WriteCmd(v)
time.Sleep(starcli.prewritetime)
}
}
}(starcli.stopctx)
return nil
}
func (starcli *StarCmd) IsRunning() bool {
return 0 != atomic.LoadInt32(&starcli.running)
}
func (starcli *StarCmd) Stoped() <-chan struct{} {
return starcli.stopctx.Done()
}
func (starcli *StarCmd) Exec(cmd string, wait int) (string, error) {
starcli.infile.Write([]byte(cmd + "\n"))
time.Sleep(time.Millisecond * time.Duration(wait))
return starcli.NowAllOutput()
}
func (starcli *StarCmd) WriteCmd(cmdstr string) {
starcli.infile.Write([]byte(cmdstr + "\n"))
}
func (starcli *StarCmd) PreWrite(cmd ...string) {
for _, v := range cmd {
starcli.prewrite = append(starcli.prewrite, v)
}
}
func (starcli *StarCmd) PreWriteInterval(dt time.Duration) {
starcli.prewritetime = dt
}
func (starcli *StarCmd) ExitCode() int {
return starcli.exitcode
}
func (starcli *StarCmd) Kill() error {
err := starcli.CMD.Process.Kill()
if err != nil {
return err
}
starcli.setRunning(false)
return nil
}
func (starcli *StarCmd) GetPid() int {
return starcli.CMD.Process.Pid
}
func (starcli *StarCmd) Signal(sig os.Signal) error {
return starcli.CMD.Process.Signal(sig)
}

@ -0,0 +1,348 @@
// +build linux darwin
package staros
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"syscall"
"time"
)
//FindProcessByName 通过进程名来查询应用信息
func FindProcessByName(name string) (datas []Process, err error) {
return FindProcess(func(in Process) bool {
if name == in.Name {
return true
}
return false
})
}
// FindProcess 通过进程信息来查询应用信息
func FindProcess(compare func(Process) bool) (datas []Process, err error) {
var name, main string
var mainb []byte
var netErr error
var netInfo []NetConn
paths, err := ioutil.ReadDir("/proc")
if err != nil {
return
}
netInfo, netErr = NetConnections(false, "")
appendNetInfo := func(p *Process) {
if netErr != nil {
p.netErr = netErr
return
}
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
p.netErr = err
return
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
if err != nil {
p.netErr = err
return
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
sid := socket[start+1 : len(socket)-1]
for _, v := range netInfo {
if v.Inode == sid {
v.Pid = p.Pid
v.Process = p
p.netConn = append(p.netConn, v)
}
}
}
}
for _, v := range paths {
if v.IsDir() && Exists("/proc/"+v.Name()+"/comm") {
name, err = readAsString("/proc/" + v.Name() + "/comm")
if err != nil {
continue
}
var tmp Process
tmp.LocalPath, err = os.Readlink("/proc/" + v.Name() + "/exe")
tmp.Path = tmp.LocalPath
tmp.LocalPath = filepath.Dir(tmp.LocalPath)
tmp.ExecPath, err = os.Readlink("/proc/" + v.Name() + "/cwd")
tmp.Name = strings.TrimSpace(name)
main, err = readAsString("/proc/" + v.Name() + "/status")
if err != nil {
tmp.Err = err
if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp)
continue
}
} else {
data := splitBy(main, ":")
tmp.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
tmp.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
tmp.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
uids := splitBySpace(data["Uid"])
gids := splitBySpace(data["Gid"])
tmp.RUID, _ = strconv.Atoi(uids[0])
tmp.EUID, _ = strconv.Atoi(uids[1])
tmp.RGID, _ = strconv.Atoi(gids[0])
tmp.EGID, _ = strconv.Atoi(gids[1])
tmp.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
tmp.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
tmp.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
tmp.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
tmp.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
tmp.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
tmp.VmLck *= 1024
tmp.VmData *= 1024
tmp.VmPeak *= 1024
tmp.VmSize *= 1024
tmp.VmHWM *= 1024
tmp.VmRSS *= 1024
}
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/cmdline")
if err != nil {
tmp.Err = err
if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp)
continue
}
} else {
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
tmp.Args = append(tmp.Args, string(v))
}
}
mainb, err = ioutil.ReadFile("/proc/" + v.Name() + "/environ")
if err != nil {
tmp.Err = err
if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp)
continue
}
} else {
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
tmp.Env = append(tmp.Env, string(v))
}
}
main, err = readAsString("/proc/" + v.Name() + "/stat")
if err != nil {
tmp.Err = err
if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp)
continue
}
} else {
times := splitBySpace(main)
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
tmp.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
}
if compare(tmp) {
appendNetInfo(&tmp)
datas = append(datas, tmp)
}
}
}
return
}
// FindProcessByPid 通过Pid来查询应用信息
func FindProcessByPid(pid int64) (datas Process, err error) {
var name, main string
var mainb []byte
if !Exists("/proc/" + fmt.Sprint(pid) + "/comm") {
err = errors.New("Not Found")
return
}
netInfo, netErr := NetConnections(false, "")
appendNetInfo := func(p *Process) {
if netErr != nil {
p.netErr = netErr
return
}
fds, err := ioutil.ReadDir("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd")
if err != nil && Exists("/proc/"+strconv.Itoa(int(p.Pid))+"/fd") {
p.netErr = err
return
}
for _, fd := range fds {
socket, err := os.Readlink("/proc/" + strconv.Itoa(int(p.Pid)) + "/fd/" + fd.Name())
if err != nil {
p.netErr = err
return
}
start := strings.Index(socket, "[")
if start < 0 {
continue
}
sid := socket[start+1 : len(socket)-1]
for _, v := range netInfo {
if v.Inode == sid {
v.Pid = p.Pid
v.Process = p
p.netConn = append(p.netConn, v)
}
}
}
}
name, err = readAsString("/proc/" + fmt.Sprint(pid) + "/comm")
if err != nil {
return
}
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/status")
if err != nil {
return
}
data := splitBy(main, ":")
datas.Name = strings.TrimSpace(name)
datas.Pid, _ = strconv.ParseInt(data["Pid"], 10, 64)
datas.PPid, _ = strconv.ParseInt(data["PPid"], 10, 64)
datas.TPid, _ = strconv.ParseInt(data["TracerPid"], 10, 64)
uids := splitBySpace(data["Uid"])
gids := splitBySpace(data["Gid"])
datas.RUID, _ = strconv.Atoi(uids[0])
datas.EUID, _ = strconv.Atoi(uids[1])
datas.RGID, _ = strconv.Atoi(gids[0])
datas.EGID, _ = strconv.Atoi(gids[1])
datas.VmPeak, _ = strconv.ParseInt(splitBySpace(data["VmPeak"])[0], 10, 64)
datas.VmSize, _ = strconv.ParseInt(splitBySpace(data["VmSize"])[0], 10, 64)
datas.VmHWM, _ = strconv.ParseInt(splitBySpace(data["VmHWM"])[0], 10, 64)
datas.VmRSS, _ = strconv.ParseInt(splitBySpace(data["VmRSS"])[0], 10, 64)
datas.VmLck, _ = strconv.ParseInt(splitBySpace(data["VmLck"])[0], 10, 64)
datas.VmData, _ = strconv.ParseInt(splitBySpace(data["VmData"])[0], 10, 64)
datas.VmLck *= 1024
datas.VmData *= 1024
datas.VmPeak *= 1024
datas.VmSize *= 1024
datas.VmHWM *= 1024
datas.VmRSS *= 1024
appendNetInfo(&datas)
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/cmdline")
if err != nil {
datas.Err = err
err = nil
} else {
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
datas.Args = append(datas.Args, string(v))
}
}
mainb, err = ioutil.ReadFile("/proc/" + fmt.Sprint(pid) + "/environ")
if err != nil {
datas.Err = err
err = nil
} else {
args := bytes.Split(mainb, []byte{0})
for _, v := range args {
datas.Env = append(datas.Env, string(v))
}
}
datas.LocalPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/exe")
datas.Path = datas.LocalPath
datas.LocalPath = filepath.Dir(datas.LocalPath)
datas.ExecPath, err = os.Readlink("/proc/" + fmt.Sprint(pid) + "/cwd")
main, err = readAsString("/proc/" + fmt.Sprint(pid) + "/stat")
if err != nil {
return
}
times := splitBySpace(main)
uptime, _ := strconv.ParseInt(strings.TrimSpace(times[21]), 10, 64)
datas.Uptime = time.Unix(StartTime().Unix()+uptime/100, int64((float64(uptime)/100-float64(uptime/100))*1000000000))
return
}
func Daemon(path string, args ...string) (int, error) {
cmd := exec.Command(path, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
if err := cmd.Start(); err != nil {
return -1, err
}
pid := cmd.Process.Pid
err := cmd.Process.Release()
return pid, err
}
func DaemonWithUser(uid, gid uint32, groups []uint32, path string, args ...string) (int, error) {
cmd := exec.Command(path, args...)
cmd.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uid,
Gid: gid,
Groups: groups,
},
Setsid: true,
}
if err := cmd.Start(); err != nil {
return -1, err
}
pid := cmd.Process.Pid
err := cmd.Process.Release()
return pid, err
}
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
Credential: &syscall.Credential{
Uid: uid,
Gid: gid,
Groups: groups,
},
Setsid: true,
}
}
func (starcli *StarCmd) Release() error {
if starcli.CMD.SysProcAttr == nil {
starcli.CMD.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
}
} else {
if !starcli.CMD.SysProcAttr.Setsid {
starcli.CMD.SysProcAttr.Setsid = true
}
}
if !starcli.IsRunning() {
if err := starcli.CMD.Start(); err != nil {
return err
}
}
time.Sleep(time.Millisecond * 10)
return starcli.CMD.Process.Release()
}
func (starcli *StarCmd) SetKeepCaps() error {
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
if 0 != err {
return err
}
return nil
}
func SetKeepCaps() error {
_, _, err := syscall.RawSyscall(157 /*SYS PRCTL */, 0x8 /*PR SET KEEPCAPS*/, 1, 0)
if 0 != err {
return err
}
return nil
}

@ -0,0 +1,72 @@
// +build windows
package staros
import (
"errors"
"fmt"
"os/exec"
"strconv"
"b612.me/wincmd"
)
// FindProcessByName 通过进程名来查询应用信息
func FindProcessByName(pname string) (data []Process, err error) {
var lists []map[string]string
lists, err = wincmd.GetRunningProcess()
if err != nil {
return
}
for _, v := range lists {
if v["name"] == pname {
var tmp Process
tmp.Name = pname
tmp.Pid, _ = strconv.ParseInt(v["pid"], 10, 64)
tmp.PPid, _ = strconv.ParseInt(v["ppid"], 10, 64)
data = append(data, tmp)
}
}
return
}
// FindProcessByPid 通过pid来查询应用信息
func FindProcessByPid(pid int64) (data Process, err error) {
var lists []map[string]string
lists, err = wincmd.GetRunningProcess()
if err != nil {
return
}
for _, v := range lists {
if v["pid"] == fmt.Sprint(pid) {
data.Name = v["name"]
data.Pid = pid
data.PPid, _ = strconv.ParseInt(v["ppid"], 10, 64)
return
}
}
err = errors.New("Not Found")
return
}
func Daemon(path string, args ...string) (int, error) {
cmd := exec.Command(path, args...)
if err := cmd.Start(); err != nil {
return -1, err
}
pid := cmd.Process.Pid
cmd.Process.Release()
return pid, nil
}
func (starcli *StarCmd) SetRunUser(uid, gid uint32, groups []uint32) {
}
func (starcli *StarCmd) Release() error {
if err := starcli.CMD.Start(); err != nil {
return err
}
starcli.CMD.Process.Release()
return nil
}

1
vendor/b612.me/staros/staros.go generated vendored

@ -0,0 +1 @@
package staros

159
vendor/b612.me/staros/tools.go generated vendored

@ -0,0 +1,159 @@
package staros
import (
"bytes"
"errors"
"io/ioutil"
"strconv"
"strings"
)
func splitBy(data, sep string) map[string]string {
res := make(map[string]string)
lists := strings.Split(data, "\n")
for _, v := range lists {
list := strings.SplitN(v, sep, 2)
if len(list) != 2 {
continue
}
res[strings.TrimSpace(list[0])] = strings.TrimSpace(list[1])
}
return res
}
// 横向替换ASCII<9>
func ReplaceByte9(data string) string {
return string(bytes.ReplaceAll([]byte(data), []byte{9}, []byte(" ")))
}
func splitBySpace(data string) []string {
data = string(bytes.ReplaceAll([]byte(data), []byte{9}, []byte(" ")))
nomorespace := func(data string) string {
return strings.ReplaceAll(data, " ", " ")
}
for strings.Index(data, " ") >= 0 {
data = nomorespace(data)
}
return strings.Split(data, " ")
}
func readAsString(path string) (string, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return "", err
}
return string(data), nil
}
func remainOne(data, old, new string) string {
data = strings.TrimSpace(data)
if !strings.Contains(data, old) {
return data
}
data = strings.ReplaceAll(data, old, new)
return remainOne(data, old, new)
}
func parseHexIpPort(str string) (string, int, error) {
str = strings.TrimSpace(str)
if len(str) != 13 && len(str) != 37 {
return "", 0, errors.New("Not a valid ip:port addr:" + str)
}
ipPort := strings.Split(str, ":")
if len(ipPort) != 2 {
return "", 0, errors.New("Not a valid ip:port addr:" + str)
}
if len(ipPort[0]) == 8 {
ip, err := parseHexIPv4(ipPort[0])
if err != nil {
return "", 0, err
}
port, err := parseHexPort(ipPort[1])
return ip, port, err
}
if len(ipPort[0]) == 32 {
ip, err := parseHexIPv6(ipPort[0])
if err != nil {
return "", 0, err
}
port, err := parseHexPort(ipPort[1])
return ip, port, err
}
return "", 0, errors.New("Invalid ip address:" + str)
}
func parseHexPort(str string) (int, error) {
tmpUint32, err := strconv.ParseUint(str, 16, 32)
return int(tmpUint32), err
}
func parseHexIPv4(str string) (string, error) {
var result string
if len(str) != 8 {
return "", errors.New("Not a vaild ipv4:" + str)
}
tmpUint64, err := strconv.ParseUint(str, 16, 32)
if err != nil {
return "", err
}
numicIp := uint32(tmpUint64)
for i := 0; i < 4; i++ {
result += strconv.FormatUint(uint64(uint8(numicIp>>(8*uint8(i)))), 10) + "."
}
return result[0 : len(result)-1], nil
}
func parseHexIPv6(str string) (string, error) {
var result string
if len(str) != 32 {
return "", errors.New("Not a vaild ipv6:" + str)
}
for i := 0; i < 4; i++ {
part := str[i*8 : (i+1)*8]
tmpUint64, err := strconv.ParseUint(part, 16, 32)
if err != nil {
return "", err
}
tmpUint32 := uint32(tmpUint64)
//07C2022A
for i := 0; i < 4; i++ {
tmp := strconv.FormatUint(uint64(uint8(tmpUint32>>uint8(8*i))), 16)
if len(tmp) == 1 {
tmp = "0" + tmp
}
result += tmp
if (i+1)%2 == 0 {
result += ":"
}
}
}
ipv6 := result[0 : len(result)-1]
ipv6List := strings.Split(ipv6, ":")
prepareZero := false
alreadyZero := false
for k, v := range ipv6List {
if v == "0000" && !alreadyZero {
ipv6List[k] = ""
prepareZero = true
continue
}
if v != "0000" && prepareZero {
alreadyZero = true
}
var nonZero = 0
for i := 0; i < 4; i++ {
sig := v[i : i+1]
if sig != "0" {
nonZero = i
break
}
}
ipv6List[k] = v[nonZero:4]
}
ipv6 = strings.TrimSuffix(remainOne(strings.Join(ipv6List, ":"), ":::", "::"), "::")
if ipv6 == "" {
ipv6 = "::0"
}
return ipv6, nil
}

114
vendor/b612.me/staros/typed.go generated vendored

@ -0,0 +1,114 @@
package staros
import (
"time"
)
const (
KB = 1024
MB = KB << 10
GB = MB << 10
TB = GB << 10
PB = TB << 10
)
const (
TCP_UNKNOWN = iota
TCP_ESTABLISHED
TCP_SYN_SENT
TCP_SYN_RECV
TCP_FIN_WAIT1
TCP_FIN_WAIT2
TCP_TIME_WAIT
TCP_CLOSE
TCP_CLOSE_WAIT
TCP_LAST_ACL
TCP_LISTEN
TCP_CLOSING
)
var TCP_STATE = []string{"TCP_UNKNOWN", "TCP_ESTABLISHED", "TCP_SYN_SENT", "TCP_SYN_RECV", "TCP_FIN_WAIT1", "TCP_FIN_WAIT2", "TCP_TIME_WAIT", "TCP_CLOSE", "TCP_CLOSE_WAIT", "TCP_LAST_ACL", "TCP_LISTEN", "TCP_CLOSING"}
type NetAdapter struct {
Name string
RecvBytes uint64
SendBytes uint64
}
type NetSpeed struct {
Name string
RecvBytes float64
SendBytes float64
}
// Process 定义一个进程的信息
type Process struct {
PPid int64
Pid int64
Name string
ExecPath string
LocalPath string
Path string
Args []string
Env []string
RUID int
EUID int
RGID int
EGID int
TPid int64
Uptime time.Time
VmPeak int64
VmSize int64
VmLck int64
VmHWM int64
VmRSS int64
VmData int64
netConn []NetConn
netErr error
Err error
}
func (p Process) GetNetConns() ([]NetConn, error) {
return p.netConn, p.netErr
}
type MemStatus struct {
All uint64
Used uint64
Free uint64
Shared uint64
BuffCache uint64
Available uint64
SwapAll uint64
SwapUsed uint64
SwapFree uint64
VirtualAll uint64
VirtualUsed uint64
VirtualAvail uint64
AvailExtended uint64
}
type DiskStatus struct {
All uint64
Used uint64
Free uint64
Available uint64
}
type NetConn struct {
LocalAddr string
LocalPort int
Typed string
RemoteAddr string
RemotePort int
Socket string
Inode string
Status string
TX_Queue int64
RX_Queue int64
TimerActive string
TimerJiffies int64
RtoTimer int64
Pid int64
Uid int64
Process *Process
}

@ -0,0 +1,79 @@
package win32api
import (
"errors"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
func DuplicateTokenEx(hExistingToken HANDLE, dwDesiredAccess DWORD,
lpTokenAttributes uintptr, ImpersonationLevel int,
TokenType TOKEN_TYPE, phNewToken *TOKEN) error {
advapi32, err := syscall.LoadLibrary("advapi32.dll")
if err != nil {
return errors.New("Can't Load Advapi32 API")
}
defer syscall.FreeLibrary(advapi32)
Dup, err := syscall.GetProcAddress(syscall.Handle(advapi32), "DuplicateTokenEx")
if err != nil {
return errors.New("Can't Load WTSQueryUserToken API")
}
r, _, errno := syscall.Syscall6(uintptr(Dup), 6, uintptr(hExistingToken), uintptr(dwDesiredAccess), lpTokenAttributes, uintptr(ImpersonationLevel),
uintptr(TokenType), uintptr(unsafe.Pointer(phNewToken)))
if r == 0 {
return error(errno)
}
return nil
}
func CreateProcessAsUser(hToken TOKEN, lpApplicationName, lpCommandLine string,
lpProcessAttributes, lpThreadAttributes, bInheritHandles uintptr,
dwCreationFlags uint16, lpEnvironment HANDLE, lpCurrentDirectory string,
lpStartupInfo *StartupInfo, lpProcessInformation *ProcessInformation) error {
var (
commandLine uintptr = 0
workingDir uintptr = 0
)
advapi32, err := syscall.LoadLibrary("advapi32.dll")
if err != nil {
return errors.New("Can't Load Advapi32 API")
}
defer syscall.FreeLibrary(advapi32)
CPAU, err := syscall.GetProcAddress(syscall.Handle(advapi32), "CreateProcessAsUserW")
if err != nil {
return errors.New("Can't Load CreateProcessAsUserW API")
}
if len(lpCommandLine) > 0 {
commandLine = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCommandLine)))
}
if len(lpCurrentDirectory) > 0 {
workingDir = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpCurrentDirectory)))
}
r, _, errno := syscall.Syscall12(uintptr(CPAU), 11, uintptr(hToken), uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(lpApplicationName))),
commandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, uintptr(dwCreationFlags), uintptr(lpEnvironment),
workingDir, uintptr(unsafe.Pointer(lpStartupInfo)), uintptr(unsafe.Pointer(lpProcessInformation)), 0)
if r == 0 {
return error(errno)
}
return nil
}
func GetTokenInformation(TokenHandle HANDLE, TokenInformationClass, TokenInformation,
TokenInformationLength uintptr, ReturnLength *uintptr) error {
advapi32, err := syscall.LoadLibrary("advapi32.dll")
if err != nil {
return errors.New("Can't Load Advapi32 API")
}
defer syscall.FreeLibrary(advapi32)
GTI, err := syscall.GetProcAddress(syscall.Handle(advapi32), "GetTokenInformation")
if err != nil {
return errors.New("Can't Load GetTokenInformation API")
}
if r, _, errno := syscall.Syscall6(uintptr(GTI), 5, uintptr(TokenHandle), TokenInformationClass,
TokenInformation, TokenInformationLength, uintptr(unsafe.Pointer(ReturnLength)), 0); r == 0 {
return error(errno)
}
return nil
}

@ -0,0 +1,5 @@
package win32api
type TOKEN_LINKED_TOKEN struct {
LinkedToken TOKEN
}

284
vendor/b612.me/win32api/kernel32.go generated vendored

@ -0,0 +1,284 @@
package win32api
import (
"errors"
"syscall"
"unsafe"
)
func WTSGetActiveConsoleSessionId() (DWORD, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0, errors.New("Can't Load Kernel32 API")
}
defer syscall.FreeLibrary(kernel32)
WTGet, err := syscall.GetProcAddress(syscall.Handle(kernel32), "WTSGetActiveConsoleSessionId")
if err != nil {
return 0, errors.New("Can't Load WTSGetActiveConsoleSessionId API")
}
res, _, _ := syscall.Syscall(uintptr(WTGet), 0, 0, 0, 0)
return DWORD(res), nil
}
func CloseHandle(hObject HANDLE) error {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return errors.New("Can't Load Kernel32 API")
}
defer syscall.FreeLibrary(kernel32)
CH, err := syscall.GetProcAddress(syscall.Handle(kernel32), "CloseHandle")
if err != nil {
return errors.New("Can't Load CloseHandle API")
}
if r, _, errno := syscall.Syscall(uintptr(CH), 1, uintptr(hObject), 0, 0); r == 0 {
return error(errno)
}
return nil
}
func CreateToolhelp32Snapshot(dwFlags, th32ProcessID DWORD) (HANDLE, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0, errors.New("Can't Load Kernel32 API")
}
defer syscall.FreeLibrary(kernel32)
CTS, err := syscall.GetProcAddress(syscall.Handle(kernel32), "CreateToolhelp32Snapshot")
if err != nil {
return 0, errors.New("Can't Load CreateToolhelp32Snapshot API")
}
r, _, errno := syscall.Syscall(uintptr(CTS), 2, uintptr(dwFlags), uintptr(th32ProcessID), 0)
if int(r) == -1 {
return 0, error(errno)
}
return HANDLE(r), nil
}
func Process32Next(hSnapshot HANDLE, lppe *PROCESSENTRY32) error {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return errors.New("Can't Load Kernel32 API")
}
defer syscall.FreeLibrary(kernel32)
PN, err := syscall.GetProcAddress(syscall.Handle(kernel32), "Process32Next")
if err != nil {
return errors.New("Can't Load Process32Next API")
}
r, _, errno := syscall.Syscall(uintptr(PN), 2, uintptr(hSnapshot), uintptr(unsafe.Pointer(lppe)), 0)
if r == 0 {
if errno != 0 {
return error(errno)
}
return syscall.EINVAL
}
return nil
}
func GetProcessId(Process HANDLE) uint32 {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0
}
defer syscall.FreeLibrary(kernel32)
GPI, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetProcessId")
if err != nil {
return 0
}
r, _, _ := syscall.Syscall(uintptr(GPI), 1, uintptr(Process), 0, 0)
return uint32(r)
}
func GetTickCount() (uint32, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0, err
}
defer syscall.FreeLibrary(kernel32)
GTC, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetTickCount")
if err != nil {
return 0, err
}
r, _, _ := syscall.Syscall(uintptr(GTC), 0, 0, 0, 0)
return uint32(r), nil
}
func GlobalMemoryStatusEx(data *MEMORYSTATUSEX) (bool, error) {
(*data).DwLength = DWORD(unsafe.Sizeof(*data))
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return false, err
}
defer syscall.FreeLibrary(kernel32)
GMS, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GlobalMemoryStatusEx")
if err != nil {
return false, err
}
r, _, errno := syscall.Syscall(uintptr(GMS), 1, uintptr(unsafe.Pointer(data)), 0, 0)
if r == 0 {
if errno != 0 {
return false, error(errno)
}
return false, syscall.EINVAL
}
return true, nil
}
func LockFileEx(hFile HANDLE, dwFlags DWORD, dwReserved DWORD, nNumberOfBytesToLockLow DWORD,
nNumberOfBytesToLockHigh DWORD, lpOverlapped *syscall.Overlapped) (bool, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return false, err
}
defer syscall.FreeLibrary(kernel32)
Lck, err := syscall.GetProcAddress(syscall.Handle(kernel32), "LockFileEx")
if err != nil {
return false, err
}
r, _, errno := syscall.Syscall6(uintptr(Lck), 6, uintptr(hFile), uintptr(dwFlags), uintptr(dwReserved),
uintptr(nNumberOfBytesToLockLow), uintptr(nNumberOfBytesToLockHigh), uintptr(unsafe.Pointer(lpOverlapped)))
if r == 0 {
if errno != 0 {
return false, error(errno)
}
return false, syscall.EINVAL
}
return true, nil
}
func OpenFileById(hVolumeHint HANDLE, lpFileId *FILE_ID_DESCRIPTOR, dwDesiredAccess DWORD, dwShareMode DWORD,
lpSecurityAttributes *syscall.SecurityAttributes, dwFlagsAndAttributes DWORD) (HANDLE, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0, err
}
defer syscall.FreeLibrary(kernel32)
ofb, err := syscall.GetProcAddress(syscall.Handle(kernel32), "OpenFileById")
if err != nil {
return 0, err
}
r, _, errno := syscall.Syscall6(ofb, 6, uintptr(hVolumeHint),
uintptr(unsafe.Pointer(lpFileId)), uintptr(dwDesiredAccess), uintptr(dwShareMode),
uintptr(unsafe.Pointer(lpSecurityAttributes)), uintptr(dwFlagsAndAttributes))
if r == syscall.INVALID_FILE_ATTRIBUTES {
if errno != 0 {
return HANDLE(r), error(errno)
}
return HANDLE(r), syscall.EINVAL
}
return HANDLE(r), nil
}
func CreateEventW(lpEventAttributes *syscall.SecurityAttributes, bManualReset bool,
bInitialState bool, lpName LPCWSTR) (HANDLE, error) {
var intBManualReset, intBInitialState int
if bManualReset {
intBManualReset = 1
}
if bInitialState {
intBInitialState = 1
}
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return 0, err
}
defer syscall.FreeLibrary(kernel32)
Lck, err := syscall.GetProcAddress(syscall.Handle(kernel32), "CreateEventW")
if err != nil {
return 0, err
}
r, _, errno := syscall.Syscall6(uintptr(Lck), 4, uintptr(unsafe.Pointer(lpEventAttributes)),
uintptr(intBManualReset), uintptr(intBInitialState), uintptr(unsafe.Pointer(lpName)), 0, 0)
if HANDLE(r) == 0 {
if errno != 0 {
return HANDLE(r), error(errno)
}
return HANDLE(r), syscall.EINVAL
}
return HANDLE(r), nil
}
func GetLogicalDriveStringsW(nBufferLength DWORD, lpBuffer LPWSTR) error {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return err
}
defer syscall.FreeLibrary(kernel32)
glds, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetLogicalDriveStringsW")
if err != nil {
return err
}
_, _, errno := syscall.Syscall(uintptr(glds), 2, uintptr(nBufferLength), uintptr(unsafe.Pointer(lpBuffer)), 0)
if errno != 0 {
return error(errno)
}
return nil
}
func GetVolumeInformationW(lpRootPathName LPCWSTR, lpVolumeNameBuffer LPWSTR, nVolumeNameSize DWORD,
lpVolumeSerialNumber LPDWORD, lpMaximumComponentLength LPDWORD, lpFileSystemFlags LPDWORD,
lpFileSystemNameBuffer LPWSTR, nFileSystemNameSize DWORD) error {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return err
}
defer syscall.FreeLibrary(kernel32)
glds, err := syscall.GetProcAddress(syscall.Handle(kernel32), "GetVolumeInformationW")
if err != nil {
return err
}
_, _, errno := syscall.Syscall9(uintptr(glds), 8, uintptr(unsafe.Pointer(lpRootPathName)),
uintptr(unsafe.Pointer(lpVolumeNameBuffer)), uintptr(nVolumeNameSize), uintptr(unsafe.Pointer(lpVolumeSerialNumber)),
uintptr(unsafe.Pointer(lpMaximumComponentLength)), uintptr(unsafe.Pointer(lpFileSystemFlags)),
uintptr(unsafe.Pointer(lpFileSystemNameBuffer)), uintptr(nFileSystemNameSize), 0)
if errno != 0 {
return error(errno)
}
return nil
}
func DeviceIoControl(hDevice HANDLE, dwIoControlCode DWORD, lpInBuffer LPVOID, nInBufferSize DWORD, lpOutBuffer LPVOID,
nOutBufferSize DWORD, lpBytesReturned LPDWORD, lpOverlapped *syscall.Overlapped) (bool, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return false, err
}
defer syscall.FreeLibrary(kernel32)
dic, err := syscall.GetProcAddress(syscall.Handle(kernel32), "DeviceIoControl")
if err != nil {
return false, err
}
r, _, errno := syscall.Syscall9(uintptr(dic), 8, uintptr(hDevice), uintptr(dwIoControlCode),
uintptr(unsafe.Pointer(lpInBuffer)), uintptr(nInBufferSize), uintptr(unsafe.Pointer(lpOutBuffer)), uintptr(nOutBufferSize),
uintptr(unsafe.Pointer(lpBytesReturned)), uintptr(unsafe.Pointer(lpOverlapped)), 0)
if r == 0 {
if errno != 0 {
return false, error(errno)
} else {
return false, syscall.EINVAL
}
}
return true, nil
}
func DeviceIoControlPtr(hDevice HANDLE, dwIoControlCode DWORD, lpInBuffer uintptr, nInBufferSize DWORD, lpOutBuffer uintptr,
nOutBufferSize DWORD, lpBytesReturned LPDWORD, lpOverlapped *syscall.Overlapped) (bool, error) {
kernel32, err := syscall.LoadLibrary("kernel32.dll")
if err != nil {
return false, err
}
defer syscall.FreeLibrary(kernel32)
dic, err := syscall.GetProcAddress(syscall.Handle(kernel32), "DeviceIoControl")
if err != nil {
return false, err
}
r, _, errno := syscall.Syscall9(uintptr(dic), 8, uintptr(hDevice), uintptr(dwIoControlCode),
lpInBuffer, uintptr(nInBufferSize), lpOutBuffer, uintptr(nOutBufferSize),
uintptr(unsafe.Pointer(lpBytesReturned)), uintptr(unsafe.Pointer(lpOverlapped)), 0)
if r == 0 {
if errno != 0 {
return false, error(errno)
} else {
return false, syscall.EINVAL
}
}
return true, nil
}

@ -0,0 +1,115 @@
package win32api
import "syscall"
type Ulong int32
type Ulong_ptr uintptr
const (
LOCKFILE_EXCLUSIVE_LOCK DWORD = 0x00000002
LOCKFILE_FAIL_IMMEDIATELY DWORD = 0x00000001
)
type PROCESSENTRY32 struct {
DwSize Ulong
CntUsage Ulong
Th32ProcessID Ulong
Th32DefaultHeapID Ulong_ptr
Th32ModuleID Ulong
CntThreads Ulong
Th32ParentProcessID Ulong
PcPriClassBase Ulong
DwFlags Ulong
SzExeFile [260]byte
}
type MEMORYSTATUSEX struct {
DwLength DWORD
DwMemoryLoad DWORD
UllTotalPhys DWORDLONG
UllAvailPhys DWORDLONG
UllTotalPageFile DWORDLONG
UllAvailPageFile DWORDLONG
UllTotalVirtual DWORDLONG
UllAvailVirtual DWORDLONG
UllAvailExtendedVirtual DWORDLONG
}
type USN_JOURNAL_DATA struct {
UsnJournalID DWORDLONG
FirstUsn USN
NextUsn USN
LowestValidUsn USN
MaxUsn USN
MaximumSize DWORDLONG
AllocationDelta DWORDLONG
}
type READ_USN_JOURNAL_DATA struct {
StartUsn USN
ReasonMask DWORD
ReturnOnlyOnClose DWORD
Timeout DWORDLONG
BytesToWaitFor DWORDLONG
UsnJournalID DWORDLONG
}
type USN_RECORD struct {
RecordLength DWORD
MajorVersion WORD
MinorVersion WORD
FileReferenceNumber DWORDLONG
ParentFileReferenceNumber DWORDLONG
Usn USN
TimeStamp LARGE_INTEGER
Reason DWORD
SourceInfo DWORD
SecurityId DWORD
FileAttributes DWORD
FileNameLength WORD
FileNameOffset WORD
FileName [1]WCHAR
}
type MFT_ENUM_DATA struct {
StartFileReferenceNumber DWORDLONG
LowUsn USN
HighUsn USN
}
const (
FSCTL_ENUM_USN_DATA = 0x900B3
FSCTL_QUERY_USN_JOURNAL = 0x900F4
FSCTL_READ_USN_JOURNAL = 0x900BB
O_RDONLY = syscall.O_RDONLY
O_RDWR = syscall.O_RDWR
O_CREAT = syscall.O_CREAT
O_WRONLY = syscall.O_WRONLY
GENERIC_READ = syscall.GENERIC_READ
GENERIC_WRITE = syscall.GENERIC_WRITE
FILE_APPEND_DATA = syscall.FILE_APPEND_DATA
FILE_SHARE_READ = syscall.FILE_SHARE_READ
FILE_SHARE_WRITE = syscall.FILE_SHARE_WRITE
ERROR_FILE_NOT_FOUND = syscall.ERROR_FILE_NOT_FOUND
O_APPEND = syscall.O_APPEND
O_CLOEXEC = syscall.O_CLOEXEC
O_EXCL = syscall.O_EXCL
O_TRUNC = syscall.O_TRUNC
CREATE_ALWAYS = syscall.CREATE_ALWAYS
CREATE_NEW = syscall.CREATE_NEW
OPEN_ALWAYS = syscall.OPEN_ALWAYS
TRUNCATE_EXISTING = syscall.TRUNCATE_EXISTING
OPEN_EXISTING = syscall.OPEN_EXISTING
FILE_ATTRIBUTE_NORMAL = syscall.FILE_ATTRIBUTE_NORMAL
FILE_FLAG_BACKUP_SEMANTICS = syscall.FILE_FLAG_BACKUP_SEMANTICS
FILE_ATTRIBUTE_DIRECTORY = syscall.FILE_ATTRIBUTE_DIRECTORY
MAX_LONG_PATH = syscall.MAX_LONG_PATH
)
type FILE_ID_DESCRIPTOR struct {
DwSize DWORD
Type DWORD
FileId DWORDLONG
ObjectId DWORDLONG
ExtendedFileId DWORDLONG
}

@ -0,0 +1,88 @@
package win32api
import (
"errors"
"strconv"
"syscall"
"unsafe"
)
func ShellExecute(hwnd HWND, lpOperation, lpFile, lpParameters, lpDirectory string, nShowCmd int) error {
shell32, err := syscall.LoadLibrary("shell32.dll")
var op, param, directory uintptr
if err != nil {
return errors.New("Can't Load Shell32 API")
}
defer syscall.FreeLibrary(shell32)
ShellExecute, err := syscall.GetProcAddress(syscall.Handle(shell32), "ShellExecuteW")
if err != nil {
return errors.New("Can't Load ShellExecute API")
}
if len(lpOperation) != 0 {
op = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpOperation)))
}
if len(lpParameters) != 0 {
param = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpParameters)))
}
if len(lpDirectory) != 0 {
directory = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpDirectory)))
}
r, _, _ := syscall.Syscall6(uintptr(ShellExecute), 6,
uintptr(hwnd),
op,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(lpFile))),
param,
directory,
uintptr(nShowCmd))
if r < 32 {
return errors.New("ERROR:" + strconv.Itoa(int(r)))
}
return nil
}
/**
func ShellExecuteEX2(hwnd HWND, lpVerb, lpFile, lpParameters, lpDirectory string, nShow int) error {
var newcmd SHELLEXECUTEINFOW
newcmd.cbSize = DWORD(unsafe.Sizeof(newcmd))
newcmd.hwnd = hwnd
newcmd.lpVerb = lpVerb
newcmd.lpFile = lpFile
newcmd.lpParameters = lpParameters
newcmd.lpDirectory = lpDirectory
newcmd.nShow = nShow
shell32, err := syscall.LoadLibrary("shell32.dll")
if err != nil {
return errors.New("Can't Load Shell32 API")
}
defer syscall.FreeLibrary(shell32)
ShellExecuteEx, err := syscall.GetProcAddress(syscall.Handle(shell32), "ShellExecuteExW")
if err != nil {
return errors.New("Can't Load ShellExecuteEx API")
}
r, _, _ := syscall.Syscall6(ShellExecuteEx, 1, uintptr(unsafe.Pointer(&newcmd)), 0, 0, 0, 0, 0)
fmt.Println(strconv.Itoa(int(r)))
fmt.Println(strconv.Itoa(int(newcmd.hInstApp)))
if r != 0 {
return errors.New("Error Recured")
}
return nil
}
*/
func ShellExecuteEx(muzika *SHELLEXECUTEINFOW) error {
shell32, err := syscall.LoadLibrary("shell32.dll")
if err != nil {
return errors.New("Can't Load Shell32 API")
}
defer syscall.FreeLibrary(shell32)
ShellExecuteEx, err := syscall.GetProcAddress(syscall.Handle(shell32), "ShellExecuteExW")
if err != nil {
return errors.New("Can't Load ShellExecuteEx API")
}
r, _, errno := syscall.Syscall6(ShellExecuteEx, 1, uintptr(unsafe.Pointer(muzika)), 0, 0, 0, 0, 0)
if r == 0 {
return error(errno)
}
return nil
}

@ -0,0 +1,24 @@
package win32api
type SHELLEXECUTEINFOW struct {
CbSize DWORD
FMask ULONG
Hwnd HWND
LpVerb uintptr
LpFile uintptr
LpParameters uintptr
LpDirectory uintptr
NShow int
HInstApp HINSTANCE
LpIDList LPVOID
LpClass uintptr
HkeyClass HKEY
DwHotKey DWORD
UnionorHMonitor HANDLE
HProcess HANDLE
}
type UNION struct {
HIcon HANDLE
HMonitor HANDLE
}

49
vendor/b612.me/win32api/user32.go generated vendored

@ -0,0 +1,49 @@
package win32api
import (
"errors"
"syscall"
)
func Keybd_event(keyname string, keydown bool) error {
var key int
var down uintptr
if !keydown {
down = KEYEVENTF_KEYUP
}
switch keyname {
case "shift":
key = VK_SHIFT
case "lshift":
key = VK_LSHIFT
case "rshift":
key = VK_RSHIFT
case "a":
key = VK_A
}
user32, err := syscall.LoadLibrary("user32.dll")
if err != nil {
return errors.New("Can't Load User32 API")
}
defer syscall.FreeLibrary(user32)
keyevent, err := syscall.GetProcAddress(syscall.Handle(user32), "keybd_event")
if err != nil {
return errors.New("Can't Load Keybd_event API")
}
syscall.Syscall6(keyevent, 4, uintptr(key), uintptr(key), down, 0, 0, 0)
return nil
}
func Keybd_event_origin(key, keyenv, down, extra uintptr) error {
user32, err := syscall.LoadLibrary("user32.dll")
if err != nil {
return errors.New("Can't Load User32 API")
}
defer syscall.FreeLibrary(user32)
keyevent, err := syscall.GetProcAddress(syscall.Handle(user32), "keybd_event")
if err != nil {
return errors.New("Can't Load Keybd_event API")
}
syscall.Syscall6(keyevent, 4, key, keyenv, down, extra, 0, 0)
return nil
}

@ -0,0 +1,180 @@
package win32api
const (
VK_SHIFT = 0x10
VK_CTRL = 0x11
VK_ALT = 0x12
VK_LSHIFT = 0xA0
VK_RSHIFT = 0xA1
VK_LCONTROL = 0xA2
VK_RCONTROL = 0xA3
KEYEVENTF_KEYUP = 0x0002
)
const (
VK_LBUTTON = 0x01
VK_RBUTTON = 0x02
VK_CANCEL = 0x03
VK_MBUTTON = 0x04
VK_XBUTTON1 = 0x05
VK_XBUTTON2 = 0x06
VK_BACK = 0x08
VK_TAB = 0x09
VK_CLEAR = 0x0C
VK_ENTER = 0x0D
VK_PAUSE = 0x13
VK_CAPITAL = 0x14
VK_KANA = 0x15
VK_HANGUEL = 0x15
VK_HANGUL = 0x15
VK_JUNJA = 0x17
VK_FINAL = 0x18
VK_HANJA = 0x19
VK_KANJI = 0x19
VK_ESC = 0x1B
VK_CONVERT = 0x1C
VK_NONCONVERT = 0x1D
VK_ACCEPT = 0x1E
VK_MODECHANGE = 0x1F
VK_SPACE = 0x20
VK_PRIOR = 0x21
VK_NEXT = 0x22
VK_END = 0x23
VK_HOME = 0x24
VK_LEFT = 0x25
VK_UP = 0x26
VK_RIGHT = 0x27
VK_DOWN = 0x28
VK_SELECT = 0x29
VK_PRINT = 0x2A
VK_EXECUTE = 0x2B
VK_SNAPSHOT = 0x2C
VK_INSERT = 0x2D
VK_DELETE = 0x2E
VK_HELP = 0x2F
VK_0 = 0x30
VK_1 = 0x31
VK_2 = 0x32
VK_3 = 0x33
VK_4 = 0x34
VK_5 = 0x35
VK_6 = 0x36
VK_7 = 0x37
VK_8 = 0x38
VK_9 = 0x39
VK_A = 0x41
VK_B = 0x42
VK_C = 0x43
VK_D = 0x44
VK_E = 0x45
VK_F = 0x46
VK_G = 0x47
VK_H = 0x48
VK_I = 0x49
VK_J = 0x4A
VK_K = 0x4B
VK_L = 0x4C
VK_M = 0x4D
VK_N = 0x4E
VK_O = 0x4F
VK_P = 0x50
VK_Q = 0x51
VK_R = 0x52
VK_S = 0x53
VK_T = 0x54
VK_U = 0x55
VK_V = 0x56
VK_W = 0x57
VK_X = 0x58
VK_Y = 0x59
VK_Z = 0x5A
VK_LWIN = 0x5B
VK_RWIN = 0x5C
VK_APPS = 0x5D
VK_SLEEP = 0x5F
VK_NUMPAD0 = 0x60
VK_NUMPAD1 = 0x61
VK_NUMPAD2 = 0x62
VK_NUMPAD3 = 0x63
VK_NUMPAD4 = 0x64
VK_NUMPAD5 = 0x65
VK_NUMPAD6 = 0x66
VK_NUMPAD7 = 0x67
VK_NUMPAD8 = 0x68
VK_NUMPAD9 = 0x69
VK_MULTIPLY = 0x6A
VK_ADD = 0x6B
VK_SEPARATOR = 0x6C
VK_SUBTRACT = 0x6D
VK_DECIMAL = 0x6E
VK_DIVIDE = 0x6F
VK_F1 = 0x70
VK_F2 = 0x71
VK_F3 = 0x72
VK_F4 = 0x73
VK_F5 = 0x74
VK_F6 = 0x75
VK_F7 = 0x76
VK_F8 = 0x77
VK_F9 = 0x78
VK_F10 = 0x79
VK_F11 = 0x7A
VK_F12 = 0x7B
VK_F13 = 0x7C
VK_F14 = 0x7D
VK_F15 = 0x7E
VK_F16 = 0x7F
VK_F17 = 0x80
VK_F18 = 0x81
VK_F19 = 0x82
VK_F20 = 0x83
VK_F21 = 0x84
VK_F22 = 0x85
VK_F23 = 0x86
VK_F24 = 0x87
VK_NUMLOCK = 0x90
VK_SCROLL = 0x91
VK_LMENU = 0xA4
VK_RMENU = 0xA5
VK_BROWSER_BACK = 0xA6
VK_BROWSER_FORWARD = 0xA7
VK_BROWSER_REFRESH = 0xA8
VK_BROWSER_STOP = 0xA9
VK_BROWSER_SEARCH = 0xAA
VK_BROWSER_FAVORITES = 0xAB
VK_BROWSER_HOME = 0xAC
VK_VOLUME_MUTE = 0xAD
VK_VOLUME_DOWN = 0xAE
VK_VOLUME_UP = 0xAF
VK_MEDIA_NEXT_TRACK = 0xB0
VK_MEDIA_PREV_TRACK = 0xB1
VK_MEDIA_STOP = 0xB2
VK_MEDIA_PLAY_PAUSE = 0xB3
VK_LAUNCH_MAIL = 0xB4
VK_LAUNCH_MEDIA_SELECT = 0xB5
VK_LAUNCH_APP1 = 0xB6
VK_LAUNCH_APP2 = 0xB7
VK_OEM_1 = 0xBA
VK_OEM_PLUS = 0xBB
VK_OEM_COMMA = 0xBC
VK_OEM_MINUS = 0xBD
VK_OEM_PERIOD = 0xBE
VK_OEM_2 = 0xBF
VK_OEM_3 = 0xC0
VK_OEM_4 = 0xDB
VK_OEM_5 = 0xDC
VK_OEM_6 = 0xDD
VK_OEM_7 = 0xDE
VK_OEM_8 = 0xDF
VK_OEM_102 = 0xE2
VK_PROCESSKEY = 0xE5
VK_PACKET = 0xE7
VK_ATTN = 0xF6
VK_CRSEL = 0xF7
VK_EXSEL = 0xF8
VK_EREOF = 0xF9
VK_PLAY = 0xFA
VK_ZOOM = 0xFB
VK_NONAME = 0xFC
VK_PA1 = 0xFD
VK_OEM_CLEAR = 0xFE
)

@ -0,0 +1,32 @@
package win32api
import (
"errors"
"syscall"
"unsafe"
)
/*
BOOL CreateEnvironmentBlock(
LPVOID *lpEnvironment,
HANDLE hToken,
BOOL bInherit
);
*/
func CreateEnvironmentBlock(lpEnvironment *HANDLE, hToken TOKEN, bInherit uintptr) error {
userenv, err := syscall.LoadLibrary("userenv.dll")
if err != nil {
return errors.New("Can't Load Userenv API")
}
defer syscall.FreeLibrary(userenv)
Dup, err := syscall.GetProcAddress(syscall.Handle(userenv), "CreateEnvironmentBlock")
if err != nil {
return errors.New("Can't Load WTSQueryUserToken API")
}
r, _, errno := syscall.Syscall6(uintptr(Dup), 3, uintptr(unsafe.Pointer(lpEnvironment)), uintptr(hToken), bInherit, 0, 0, 0)
if r == 0 {
return error(errno)
}
return nil
}

146
vendor/b612.me/win32api/win32api.go generated vendored

@ -0,0 +1,146 @@
package win32api
import (
"unsafe"
)
type (
ATOM uint16
BOOL int32
COLORREF uint32
DWM_FRAME_COUNT uint64
DWORD uint32
LPDWORD *uint32
DWORDLONG uint64
HACCEL HANDLE
HANDLE uintptr
HBITMAP HANDLE
HBRUSH HANDLE
HCURSOR HANDLE
HDC HANDLE
HDROP HANDLE
HDWP HANDLE
HENHMETAFILE HANDLE
HFONT HANDLE
HGDIOBJ HANDLE
HGLOBAL HANDLE
HGLRC HANDLE
HHOOK HANDLE
HICON HANDLE
HIMAGELIST HANDLE
HINSTANCE HANDLE
HKEY HANDLE
HKL HANDLE
HMENU HANDLE
HMODULE HANDLE
HMONITOR HANDLE
HPEN HANDLE
HRESULT int32
HRGN HANDLE
HRSRC HANDLE
HTHUMBNAIL HANDLE
HWND HANDLE
LPARAM uintptr
LPCVOID unsafe.Pointer
LPVOID unsafe.Pointer
LRESULT uintptr
LPCWSTR *uint16
PVOID unsafe.Pointer
QPC_TIME uint64
ULONG uint32
ULONG_PTR uintptr
WPARAM uintptr
WTS_CONNECTSTATE_CLASS int
TRACEHANDLE uintptr
TOKEN HANDLE
LPWSTR *uint16
TOKEN_TYPE int
SW int
SECURITY_IMPERSONATION_LEVEL int
WCHAR uint16
WORD uint16
USN int64
LARGE_INTEGER LONGLONG
LONGLONG int64
)
type WTS_SESSION_INFO struct {
SessionID HANDLE
WinStationName *uint16
State WTS_CONNECTSTATE_CLASS
}
const (
WTS_CURRENT_SERVER_HANDLE uintptr = 0
)
const (
WTSActive WTS_CONNECTSTATE_CLASS = iota
WTSConnected
WTSConnectQuery
WTSShadow
WTSDisconnected
WTSIdle
WTSListen
WTSReset
WTSDown
WTSInit
)
const (
SecurityAnonymous SECURITY_IMPERSONATION_LEVEL = iota
SecurityIdentification
SecurityImpersonation
SecurityDelegation
)
const (
TokenPrimary TOKEN_TYPE = iota + 1
TokenImpersonazion
)
const (
SW_HIDE SW = 0
SW_SHOWNORMAL = 1
SW_NORMAL = 1
SW_SHOWMINIMIZED = 2
SW_SHOWMAXIMIZED = 3
SW_MAXIMIZE = 3
SW_SHOWNOACTIVATE = 4
SW_SHOW = 5
SW_MINIMIZE = 6
SW_SHOWMINNOACTIVE = 7
SW_SHOWNA = 8
SW_RESTORE = 9
SW_SHOWDEFAULT = 10
SW_MAX = 1
)
const (
CREATE_UNICODE_ENVIRONMENT uint16 = 0x00000400
CREATE_NO_WINDOW = 0x08000000
CREATE_NEW_CONSOLE = 0x00000010
)
type StartupInfo struct {
Cb uint32
_ *uint16
Desktop *uint16
Title *uint16
X uint32
Y uint32
XSize uint32
YSize uint32
XCountChars uint32
YCountChars uint32
FillAttribute uint32
Flags uint32
ShowWindow uint16
_ uint16
_ *byte
StdInput HANDLE
StdOutput HANDLE
StdErr HANDLE
}
type ProcessInformation struct {
Process HANDLE
Thread HANDLE
ProcessId uint32
ThreadId uint32
}

@ -0,0 +1,42 @@
package win32api
import (
"errors"
"syscall"
"unsafe"
)
func WTSQueryUserToken(SessionId HANDLE, phToken *HANDLE) error {
wtsapi32, err := syscall.LoadLibrary("wtsapi32.dll")
if err != nil {
return errors.New("Can't Load Wtsapi32 API")
}
defer syscall.FreeLibrary(wtsapi32)
WTGet, err := syscall.GetProcAddress(syscall.Handle(wtsapi32), "WTSQueryUserToken")
if err != nil {
return errors.New("Can't Load WTSQueryUserToken API")
}
r, _, errno := syscall.Syscall(uintptr(WTGet), 2, uintptr(SessionId), uintptr(unsafe.Pointer(phToken)), 0)
if r == 0 {
return error(errno)
} else {
return nil
}
}
func WTSEnumerateSessions(hServer HANDLE, Reserved, Version DWORD, ppSessionInfo *HANDLE, pCount *int) error {
wtsapi32, err := syscall.LoadLibrary("wtsapi32.dll")
if err != nil {
return errors.New("Can't Load Wtsapi32 API")
}
defer syscall.FreeLibrary(wtsapi32)
WT, err := syscall.GetProcAddress(syscall.Handle(wtsapi32), "WTSEnumerateSessionsW")
if err != nil {
return errors.New("Can't Load WTSQueryUserToken API")
}
r, _, errno := syscall.Syscall6(uintptr(WT), 5, uintptr(hServer), uintptr(Reserved), uintptr(Version), uintptr(unsafe.Pointer(ppSessionInfo)), uintptr(unsafe.Pointer(pCount)), 0)
if r == 0 {
return error(errno)
}
return nil
}

11
vendor/b612.me/wincmd/disk.go generated vendored

@ -0,0 +1,11 @@
package wincmd
import "b612.me/wincmd/ntfs/usn"
func ListDrivers() ([]string, error) {
return usn.ListDrivers()
}
func GetDiskInfo(disk string) (usn.DiskInfo, error) {
return usn.GetDiskInfo(disk)
}

@ -0,0 +1,256 @@
package usn
import (
"b612.me/win32api"
"golang.org/x/sys/windows"
"os"
"sync"
"syscall"
"time"
)
const DevNull = "NUL"
// A fileStat is the implementation of FileInfo returned by Stat and Lstat.
type FileStat struct {
name string
// from ByHandleFileInformation, Win32FileAttributeData and Win32finddata
FileAttributes uint32
CreationTime syscall.Filetime
LastAccessTime syscall.Filetime
LastWriteTime syscall.Filetime
FileSizeHigh uint32
FileSizeLow uint32
// from Win32finddata
Reserved0 uint32
// what syscall.GetFileType returns
filetype uint32
// used to implement SameFile
sync.Mutex
path string
vol uint32
idxhi uint32
idxlo uint32
appendNameToPath bool
}
// newFileStatFromWin32finddata copies all required information
// from syscall.Win32finddata d into the newly created fileStat.
func newFileStatFromInformation(d *syscall.ByHandleFileInformation, name string, path string) FileStat {
return FileStat{
name: name,
path: path,
FileAttributes: d.FileAttributes,
CreationTime: d.CreationTime,
LastAccessTime: d.LastAccessTime,
LastWriteTime: d.LastWriteTime,
FileSizeHigh: d.FileSizeHigh,
FileSizeLow: d.FileSizeLow,
}
}
func (fs *FileStat) Name() string {
return fs.name
}
func (fs *FileStat) IsDir() bool {
return fs.FileAttributes&win32api.FILE_ATTRIBUTE_DIRECTORY != 0
}
func (fs *FileStat) isSymlink() bool {
// Use instructions described at
// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
// to recognize whether it's a symlink.
if fs.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
return false
}
return fs.Reserved0 == syscall.IO_REPARSE_TAG_SYMLINK ||
fs.Reserved0 == windows.IO_REPARSE_TAG_MOUNT_POINT
}
func (fs *FileStat) Size() int64 {
return int64(fs.FileSizeHigh)<<32 + int64(fs.FileSizeLow)
}
func (fs *FileStat) Mode() (m os.FileMode) {
if fs == &devNullStat {
return os.ModeDevice | os.ModeCharDevice | 0666
}
if fs.FileAttributes&syscall.FILE_ATTRIBUTE_READONLY != 0 {
m |= 0444
} else {
m |= 0666
}
if fs.isSymlink() {
return m | os.ModeSymlink
}
if fs.FileAttributes&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
m |= os.ModeDir | 0111
}
switch fs.filetype {
case syscall.FILE_TYPE_PIPE:
m |= os.ModeNamedPipe
case syscall.FILE_TYPE_CHAR:
m |= os.ModeDevice | os.ModeCharDevice
}
return m
}
func (fs *FileStat) ModTime() time.Time {
return time.Unix(0, fs.LastWriteTime.Nanoseconds())
}
// Sys returns syscall.Win32FileAttributeData for file fs.
func (fs *FileStat) Sys() interface{} {
return &syscall.Win32FileAttributeData{
FileAttributes: fs.FileAttributes,
CreationTime: fs.CreationTime,
LastAccessTime: fs.LastAccessTime,
LastWriteTime: fs.LastWriteTime,
FileSizeHigh: fs.FileSizeHigh,
FileSizeLow: fs.FileSizeLow,
}
}
// saveInfoFromPath saves full path of the file to be used by os.SameFile later,
// and set name from path.
// devNullStat is fileStat structure describing DevNull file ("NUL").
var devNullStat = FileStat{
name: DevNull,
// hopefully this will work for SameFile
vol: 0,
idxhi: 0,
idxlo: 0,
}
func fixLongPath(path string) string {
// Do nothing (and don't allocate) if the path is "short".
// Empirically (at least on the Windows Server 2013 builder),
// the kernel is arbitrarily okay with < 248 bytes. That
// matches what the docs above say:
// "When using an API to create a directory, the specified
// path cannot be so long that you cannot append an 8.3 file
// name (that is, the directory name cannot exceed MAX_PATH
// minus 12)." Since MAX_PATH is 260, 260 - 12 = 248.
//
// The MSDN docs appear to say that a normal path that is 248 bytes long
// will work; empirically the path must be less then 248 bytes long.
if len(path) < 248 {
// Don't fix. (This is how Go 1.7 and earlier worked,
// not automatically generating the \\?\ form)
return path
}
// The extended form begins with \\?\, as in
// \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt.
// The extended form disables evaluation of . and .. path
// elements and disables the interpretation of / as equivalent
// to \. The conversion here rewrites / to \ and elides
// . elements as well as trailing or duplicate separators. For
// simplicity it avoids the conversion entirely for relative
// paths or paths containing .. elements. For now,
// \\server\share paths are not converted to
// \\?\UNC\server\share paths because the rules for doing so
// are less well-specified.
if len(path) >= 2 && path[:2] == `\\` {
// Don't canonicalize UNC paths.
return path
}
if !isAbs(path) {
// Relative path
return path
}
const prefix = `\\?`
pathbuf := make([]byte, len(prefix)+len(path)+len(`\`))
copy(pathbuf, prefix)
n := len(path)
r, w := 0, len(prefix)
for r < n {
switch {
case IsPathSeparator(path[r]):
// empty block
r++
case path[r] == '.' && (r+1 == n || IsPathSeparator(path[r+1])):
// /./
r++
case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || IsPathSeparator(path[r+2])):
// /../ is currently unhandled
return path
default:
pathbuf[w] = '\\'
w++
for ; r < n && !IsPathSeparator(path[r]); r++ {
pathbuf[w] = path[r]
w++
}
}
}
// A drive's root directory needs a trailing \
if w == len(`\\?\c:`) {
pathbuf[w] = '\\'
w++
}
return string(pathbuf[:w])
}
func IsPathSeparator(c uint8) bool {
// NOTE: Windows accept / as path separator.
return c == '\\' || c == '/'
}
func isAbs(path string) (b bool) {
v := volumeName(path)
if v == "" {
return false
}
path = path[len(v):]
if path == "" {
return false
}
return IsPathSeparator(path[0])
}
func volumeName(path string) (v string) {
if len(path) < 2 {
return ""
}
// with drive letter
c := path[0]
if path[1] == ':' &&
('0' <= c && c <= '9' || 'a' <= c && c <= 'z' ||
'A' <= c && c <= 'Z') {
return path[:2]
}
// is it UNC
if l := len(path); l >= 5 && IsPathSeparator(path[0]) && IsPathSeparator(path[1]) &&
!IsPathSeparator(path[2]) && path[2] != '.' {
// first, leading `\\` and next shouldn't be `\`. its server name.
for n := 3; n < l-1; n++ {
// second, next '\' shouldn't be repeated.
if IsPathSeparator(path[n]) {
n++
// third, following something characters. its share name.
if !IsPathSeparator(path[n]) {
if path[n] == '.' {
break
}
for ; n < l; n++ {
if IsPathSeparator(path[n]) {
break
}
}
return path[:n]
}
break
}
}
}
return ""
}

@ -0,0 +1,596 @@
package usn
import (
"b612.me/stario"
"b612.me/win32api"
"fmt"
"os"
"reflect"
"runtime"
"syscall"
"unsafe"
)
type DiskInfo struct {
Driver string
Name string
Format string
SerialNumber uint32
}
func ListDrivers() ([]string, error) {
drivers := make([]string, 0, 26)
buf := make([]uint16, 255)
err := win32api.GetLogicalDriveStringsW(win32api.DWORD(len(buf)), &buf[0])
if err != nil {
return drivers, err
}
var driver []rune
for _, v := range buf {
if v != 0 {
driver = append(driver, rune(uint8(v)))
if v == 92 {
drivers = append(drivers, string(driver))
driver = []rune{}
}
}
}
return drivers, nil
}
func GetDiskInfo(disk string) (DiskInfo, error) {
format := make([]rune, 0, 12)
name := make([]rune, 0, 128)
ptr, _ := syscall.UTF16PtrFromString(disk)
var lpVolumeNameBuffer = make([]uint16, syscall.MAX_PATH+1)
var nVolumeNameSize = win32api.DWORD(len(lpVolumeNameBuffer))
var lpVolumeSerialNumber uint32
var lpMaximumComponentLength uint32
var lpFileSystemFlags uint32
var lpFileSystemNameBuffer = make([]uint16, 255)
var nFileSystemNameSize uint32 = syscall.MAX_PATH + 1
err := win32api.GetVolumeInformationW(ptr, &lpVolumeNameBuffer[0], nVolumeNameSize, &lpVolumeSerialNumber, &lpMaximumComponentLength,
&lpFileSystemFlags, &lpFileSystemNameBuffer[0], win32api.DWORD(nFileSystemNameSize))
for _, v := range lpFileSystemNameBuffer {
if v != 0 {
format = append(format, rune(v))
}
}
for _, v := range lpVolumeNameBuffer {
if v != 0 {
name = append(name, rune(v))
}
}
return DiskInfo{
SerialNumber: lpVolumeSerialNumber,
Driver: disk,
Name: string(name),
Format: string(format),
}, err
}
func DeviceIoControl(handle syscall.Handle, controlCode uint32, in interface{}, out interface{}, done *uint32) (err error) {
inPtr, inSize := getPointer(in)
outPtr, outSize := getPointer(out)
//_,err = syscall.Syscall9(procDeviceIoControl.Addr(), 8, uintptr(handle), uintptr(controlCode), inPtr, uintptr(inSize), outPtr, uintptr(outSize), uintptr(unsafe.Pointer(done)), uintptr(0), 0)
_, err = win32api.DeviceIoControlPtr(win32api.HANDLE(handle), win32api.DWORD(controlCode), inPtr, win32api.DWORD(inSize), outPtr, win32api.DWORD(outSize), done, nil)
return
}
func getPointer(i interface{}) (pointer, size uintptr) {
v := reflect.ValueOf(i)
switch k := v.Kind(); k {
case reflect.Ptr:
t := v.Elem().Type()
size = t.Size()
pointer = v.Pointer()
case reflect.Slice:
size = uintptr(v.Cap())
pointer = v.Pointer()
default:
fmt.Println("error")
}
return
}
// Need a custom Open to work with backup_semantics
func CreateFile(path string, mode int, attrs uint32) (fd syscall.Handle, err error) {
if len(path) == 0 {
return syscall.InvalidHandle, win32api.ERROR_FILE_NOT_FOUND
}
pathp, err := syscall.UTF16PtrFromString(path)
if err != nil {
return syscall.InvalidHandle, err
}
var access uint32
switch mode & (win32api.O_RDONLY | win32api.O_WRONLY | win32api.O_RDWR) {
case win32api.O_RDONLY:
access = win32api.GENERIC_READ
case win32api.O_WRONLY:
access = win32api.GENERIC_WRITE
case win32api.O_RDWR:
access = win32api.GENERIC_READ | win32api.GENERIC_WRITE
}
if mode&win32api.O_CREAT != 0 {
access |= win32api.GENERIC_WRITE
}
if mode&win32api.O_APPEND != 0 {
access &^= win32api.GENERIC_WRITE
access |= win32api.FILE_APPEND_DATA
}
sharemode := uint32(win32api.FILE_SHARE_READ | win32api.FILE_SHARE_WRITE)
var sa *syscall.SecurityAttributes
if mode&win32api.O_CLOEXEC == 0 {
sa = makeInheritSa()
}
var createmode uint32
switch {
case mode&(win32api.O_CREAT|win32api.O_EXCL) == (win32api.O_CREAT | win32api.O_EXCL):
createmode = win32api.CREATE_NEW
case mode&(win32api.O_CREAT|win32api.O_TRUNC) == (win32api.O_CREAT | win32api.O_TRUNC):
createmode = win32api.CREATE_ALWAYS
case mode&win32api.O_CREAT == win32api.O_CREAT:
createmode = win32api.OPEN_ALWAYS
case mode&win32api.O_TRUNC == win32api.O_TRUNC:
createmode = win32api.TRUNCATE_EXISTING
default:
createmode = win32api.OPEN_EXISTING
}
h, e := syscall.CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
return h, e
}
func makeInheritSa() *syscall.SecurityAttributes {
var sa syscall.SecurityAttributes
sa.Length = uint32(unsafe.Sizeof(sa))
sa.InheritHandle = 1
return &sa
}
// Query usn journal data
func queryUsnJournal(fd syscall.Handle) (ujd win32api.USN_JOURNAL_DATA, done uint32, err error) {
err = DeviceIoControl(fd, win32api.FSCTL_QUERY_USN_JOURNAL, []byte{}, &ujd, &done)
return
}
func readUsnJournal(fd syscall.Handle, rujd *win32api.READ_USN_JOURNAL_DATA) (data []byte, done uint32, err error) {
data = make([]byte, 0x1000)
err = DeviceIoControl(fd, win32api.FSCTL_READ_USN_JOURNAL, rujd, data, &done)
return
}
func enumUsnData(fd syscall.Handle, med *win32api.MFT_ENUM_DATA) (data []byte, done uint32, err error) {
data = make([]byte, 0x10000)
err = DeviceIoControl(fd, win32api.FSCTL_ENUM_USN_DATA, med, data, &done)
return
}
type FileEntry struct {
Name string
Parent win32api.DWORDLONG
Type uint8
}
type FileMonitor struct {
Name string
Self win32api.DWORDLONG
Parent win32api.DWORDLONG
Type uint8
Reason string
}
func ListUsnFile(driver string) (map[win32api.DWORDLONG]FileEntry, error) {
fileMap := make(map[win32api.DWORDLONG]FileEntry)
pDriver := "\\\\.\\" + driver[:len(driver)-1]
fd, err := CreateFile(pDriver, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return fileMap, err
}
ujd, _, err := queryUsnJournal(fd)
if err != nil {
return fileMap, err
}
med := win32api.MFT_ENUM_DATA{0, 0, ujd.NextUsn}
for {
data, done, err := enumUsnData(fd, &med)
if err != nil && done != 0 {
return fileMap, err
}
if done == 0 {
return fileMap, nil
}
var usn win32api.USN = *(*win32api.USN)(unsafe.Pointer(&data[0]))
// fmt.Println("usn", usn)
var ur *win32api.USN_RECORD
for i := unsafe.Sizeof(usn); i < uintptr(done); i += uintptr(ur.RecordLength) {
ur = (*win32api.USN_RECORD)(unsafe.Pointer(&data[i]))
nameLength := uintptr(ur.FileNameLength) / unsafe.Sizeof(ur.FileName[0])
fnp := unsafe.Pointer(&data[i+uintptr(ur.FileNameOffset)])
fnUtf := (*[10000]uint16)(fnp)[:nameLength]
fn := syscall.UTF16ToString(fnUtf)
(*reflect.SliceHeader)(unsafe.Pointer(&fn)).Cap = int(nameLength)
typed := uint8(0)
if ur.FileAttributes&win32api.FILE_ATTRIBUTE_DIRECTORY != 0 {
typed = 1
}
// fmt.Println("len", ur.FileNameLength, ur.FileNameOffset, "fn", fn)
fileMap[ur.FileReferenceNumber] = FileEntry{Name: fn, Parent: ur.ParentFileReferenceNumber, Type: typed}
}
med.StartFileReferenceNumber = win32api.DWORDLONG(usn)
}
}
func ListUsnFileFn(driver string, searchFn func(string, bool) bool) (map[win32api.DWORDLONG]FileEntry, error) {
fileMap := make(map[win32api.DWORDLONG]FileEntry)
pDriver := "\\\\.\\" + driver[:len(driver)-1]
fd, err := CreateFile(pDriver, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return fileMap, err
}
ujd, _, err := queryUsnJournal(fd)
if err != nil {
return fileMap, err
}
med := win32api.MFT_ENUM_DATA{0, 0, ujd.NextUsn}
for {
data, done, err := enumUsnData(fd, &med)
if err != nil && done != 0 {
return fileMap, err
}
if done == 0 {
return fileMap, nil
}
var usn win32api.USN = *(*win32api.USN)(unsafe.Pointer(&data[0]))
// fmt.Println("usn", usn)
var ur *win32api.USN_RECORD
for i := unsafe.Sizeof(usn); i < uintptr(done); i += uintptr(ur.RecordLength) {
ur = (*win32api.USN_RECORD)(unsafe.Pointer(&data[i]))
nameLength := uintptr(ur.FileNameLength) / unsafe.Sizeof(ur.FileName[0])
fnp := unsafe.Pointer(&data[i+uintptr(ur.FileNameOffset)])
fnUtf := (*[10000]uint16)(fnp)[:nameLength]
fn := syscall.UTF16ToString(fnUtf)
(*reflect.SliceHeader)(unsafe.Pointer(&fn)).Cap = int(nameLength)
typed := uint8(0)
if ur.FileAttributes&win32api.FILE_ATTRIBUTE_DIRECTORY != 0 {
typed = 1
}
if typed == 1 || searchFn(fn, typed == 1) {
// fmt.Println("len", ur.FileNameLength, ur.FileNameOffset, "fn", fn)
fileMap[ur.FileReferenceNumber] = FileEntry{Name: fn, Parent: ur.ParentFileReferenceNumber, Type: typed}
}
}
med.StartFileReferenceNumber = win32api.DWORDLONG(usn)
}
}
func GetFullUsnPath(diskName string, fileMap map[win32api.DWORDLONG]FileEntry, id win32api.DWORDLONG) (name string) {
for id != 0 {
fe := fileMap[id]
if id == fe.Parent {
name = "\\" + name
break
}
if name == "" {
name = fe.Name
} else {
name = fe.Name + "\\" + name
}
id = fe.Parent
}
name = diskName[:len(diskName)-1] + name
return
}
func GetFullUsnPathEntry(diskName string, fileMap map[win32api.DWORDLONG]FileEntry, en FileMonitor) (name string) {
fileMap[en.Self] = FileEntry{
Name: en.Name,
Parent: en.Parent,
Type: en.Type,
}
id := en.Self
for id != 0 {
fe := fileMap[id]
if id == fe.Parent {
name = "\\" + name
break
}
if name == "" {
name = fe.Name
} else {
name = fe.Name + "\\" + name
}
id = fe.Parent
}
name = diskName[:len(diskName)-1] + name
return
}
const (
ALL_FILES = iota
ONLY_FOLDER
NO_FOLDER
)
func ListNTFSUsnDriverFilesFn(diskName string, searchFn func(string, bool) bool) ([]string, error) {
var result []string
data, err := ListUsnFileFn(diskName, searchFn)
if err != nil {
return result, err
}
return listNTFSUsnDriverFiles(diskName, searchFn, data)
}
func ListNTFSUsnDriverFiles(diskName string, folder uint8) ([]string, error) {
var result []string
data, err := ListUsnFile(diskName)
if err != nil {
return result, err
}
return listNTFSUsnDriverFiles(diskName, func(name string, tp bool) bool {
if !tp && folder == ONLY_FOLDER {
return false
}
if tp && folder == NO_FOLDER {
return false
}
return true
}, data)
}
func listNTFSUsnDriverFiles(diskName string, fn func(string, bool) bool, data map[win32api.DWORDLONG]FileEntry) ([]string, error) {
result := make([]string, len(data))
i := 0
for k, v := range data {
if !fn(v.Name, v.Type == 1) {
continue
}
name := GetFullUsnPath(diskName, data, k)
result[i] = name
i++
}
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = i
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Len = i
data = nil
data = make(map[win32api.DWORDLONG]FileEntry, 0)
runtime.GC()
return result, nil
}
func ListNTFSUsnDriverInfoFn(diskName string, searchFn func(string, bool) bool) ([]FileStat, error) {
data, err := ListUsnFileFn(diskName, searchFn)
if err != nil {
return nil, err
}
return listNTFSUsnDriverInfo(diskName, searchFn, data)
}
func ListNTFSUsnDriverInfo(diskName string, folder uint8) ([]FileStat, error) {
data, err := ListUsnFile(diskName)
if err != nil {
return nil, err
}
return listNTFSUsnDriverInfo(diskName, func(name string, tp bool) bool {
if !tp && folder == ONLY_FOLDER {
return false
}
if tp && folder == NO_FOLDER {
return false
}
return true
}, data)
}
func listNTFSUsnDriverInfo(diskName string, fn func(string, bool) bool, data map[win32api.DWORDLONG]FileEntry) ([]FileStat, error) {
//fmt.Println("finished 1")
pDriver := "\\\\.\\" + diskName[:len(diskName)-1]
fd, err := CreateFile(pDriver, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return nil, err
}
defer syscall.Close(fd)
result := make([]FileStat, len(data))
i := int(0)
wg := stario.NewWaitGroup(100)
for k, v := range data {
if !fn(v.Name, v.Type == 1) {
continue
}
wg.Add(1)
go func(k win32api.DWORDLONG, v FileEntry, i int) {
defer wg.Done()
//now := time.Now().UnixNano()
/*
fd2, err := OpenFileByIdWithfd(fd, k, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return
}
//fmt.Println("cost", float64((time.Now().UnixNano()-now)/1000000))
var info syscall.ByHandleFileInformation
err = syscall.GetFileInformationByHandle(fd2, &info)
syscall.Close(fd2)
//fmt.Println("cost", float64((time.Now().UnixNano()-now)/1000000))
if err != nil {
return
}
*/
path := GetFullUsnPath(diskName, data, k)
fileInfo, err := os.Stat(path)
if err != nil {
return
}
fs := fileInfo.Sys().(*syscall.Win32FileAttributeData)
stat := FileStat{
FileAttributes: fs.FileAttributes,
CreationTime: fs.CreationTime,
LastAccessTime: fs.LastAccessTime,
LastWriteTime: fs.LastWriteTime,
FileSizeHigh: fs.FileSizeHigh,
FileSizeLow: fs.FileSizeLow,
}
stat.name = v.Name
stat.path = path
return
result[i] = stat
//result[i] = newFileStatFromInformation(&info, v.Name, path)
}(k, v, i)
i++
}
wg.Wait()
//fmt.Println("finished 2")
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Cap = i
(*reflect.SliceHeader)(unsafe.Pointer(&result)).Len = i
data = nil
//data = make(map[win32api.DWORDLONG]FileEntry, 0)
runtime.GC()
return result, nil
}
func getUsnJournalReasonString(reason win32api.DWORD) (s string) {
var reasons = []string{
"DataOverwrite", // 0x00000001
"DataExtend", // 0x00000002
"DataTruncation", // 0x00000004
"0x00000008", // 0x00000008
"NamedDataOverwrite", // 0x00000010
"NamedDataExtend", // 0x00000020
"NamedDataTruncation", // 0x00000040
"0x00000080", // 0x00000080
"FileCreate", // 0x00000100
"FileDelete", // 0x00000200
"PropertyChange", // 0x00000400
"SecurityChange", // 0x00000800
"RenameOldName", // 0x00001000
"RenameNewName", // 0x00002000
"IndexableChange", // 0x00004000
"BasicInfoChange", // 0x00008000
"HardLinkChange", // 0x00010000
"CompressionChange", // 0x00020000
"EncryptionChange", // 0x00040000
"ObjectIdChange", // 0x00080000
"ReparsePointChange", // 0x00100000
"StreamChange", // 0x00200000
"0x00400000", // 0x00400000
"0x00800000", // 0x00800000
"0x01000000", // 0x01000000
"0x02000000", // 0x02000000
"0x04000000", // 0x04000000
"0x08000000", // 0x08000000
"0x10000000", // 0x10000000
"0x20000000", // 0x20000000
"0x40000000", // 0x40000000
"*Close*", // 0x80000000
}
for i := 0; reason != 0; {
if reason&1 == 1 {
s = s + ", " + reasons[i]
}
reason >>= 1
i++
}
return
}
func MonitorUsnChange(driver string, rec chan FileMonitor) error {
pDriver := "\\\\.\\" + driver[:len(driver)-1]
fd, err := CreateFile(pDriver, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return err
}
ujd, _, err := queryUsnJournal(fd)
if err != nil {
return err
}
rujd := win32api.READ_USN_JOURNAL_DATA{ujd.NextUsn, 0xFFFFFFFF, 0, 0, 1, ujd.UsnJournalID}
for {
var usn win32api.USN
data, done, err := readUsnJournal(fd, &rujd)
if err != nil || done <= uint32(unsafe.Sizeof(usn)) {
return err
}
usn = *(*win32api.USN)(unsafe.Pointer(&data[0]))
var ur *win32api.USN_RECORD
for i := unsafe.Sizeof(usn); i < uintptr(done); i += uintptr(ur.RecordLength) {
ur = (*win32api.USN_RECORD)(unsafe.Pointer(&data[i]))
nameLength := uintptr(ur.FileNameLength) / unsafe.Sizeof(ur.FileName[0])
fnp := unsafe.Pointer(&data[i+uintptr(ur.FileNameOffset)])
fn := syscall.UTF16ToString((*[10000]uint16)(fnp)[:nameLength])
(*reflect.SliceHeader)(unsafe.Pointer(&fn)).Cap = int(nameLength)
// fmt.Println("len", ur.FileNameLength, ur.FileNameOffset, "fn", getFullPath(folders, ur.ParentFileReferenceNumber), syscall.UTF16ToString(fn), getUsnJournalReasonString(ur.Reason))
typed := uint8(0)
if ur.FileAttributes&win32api.FILE_ATTRIBUTE_DIRECTORY != 0 {
typed = 1
}
// fmt.Println("len", ur.FileNameLength, ur.FileNameOffset, "fn", fn)
rec <- FileMonitor{Name: fn, Parent: ur.ParentFileReferenceNumber, Type: typed, Self: ur.FileReferenceNumber, Reason: getUsnJournalReasonString(ur.Reason)}
}
rujd.StartUsn = usn
if usn == 0 {
return nil
}
}
}
func GetUsnFileInfo(diskName string, fileMap map[win32api.DWORDLONG]FileEntry, id win32api.DWORDLONG) (FileStat, error) {
name := fileMap[id].Name
path := GetFullUsnPath(diskName, fileMap, id)
fd, err := OpenFileById(diskName, id, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return FileStat{}, err
}
var info syscall.ByHandleFileInformation
err = syscall.GetFileInformationByHandle(fd, &info)
return newFileStatFromInformation(&info, name, path), err
}
// Need a custom Open to work with backup_semantics
func OpenFileById(diskName string, id win32api.DWORDLONG, mode int, attrs uint32) (syscall.Handle, error) {
pDriver := "\\\\.\\" + diskName[:len(diskName)-1]
fd, err := CreateFile(pDriver, syscall.O_RDONLY, win32api.FILE_ATTRIBUTE_NORMAL)
if err != nil {
return syscall.InvalidHandle, err
}
defer syscall.Close(fd)
return OpenFileByIdWithfd(fd, id, mode, attrs)
}
func OpenFileByIdWithfd(fd syscall.Handle, id win32api.DWORDLONG, mode int, attrs uint32) (syscall.Handle, error) {
var access uint32
switch mode & (win32api.O_RDONLY | win32api.O_WRONLY | win32api.O_RDWR) {
case win32api.O_RDONLY:
access = win32api.GENERIC_READ
case win32api.O_WRONLY:
access = win32api.GENERIC_WRITE
case win32api.O_RDWR:
access = win32api.GENERIC_READ | win32api.GENERIC_WRITE
}
if mode&win32api.O_CREAT != 0 {
access |= win32api.GENERIC_WRITE
}
if mode&win32api.O_APPEND != 0 {
access &^= win32api.GENERIC_WRITE
access |= win32api.FILE_APPEND_DATA
}
sharemode := uint32(win32api.FILE_SHARE_READ | win32api.FILE_SHARE_WRITE)
var sa *syscall.SecurityAttributes
if mode&win32api.O_CLOEXEC == 0 {
sa = makeInheritSa()
}
fid := win32api.FILE_ID_DESCRIPTOR{
DwSize: 16,
Type: 0,
FileId: id,
}
fid.DwSize = win32api.DWORD(unsafe.Sizeof(fid))
h, e := win32api.OpenFileById(win32api.HANDLE(fd), &fid, win32api.DWORD(access),
win32api.DWORD(sharemode), sa, win32api.DWORD(attrs))
return syscall.Handle(h), e
}

262
vendor/b612.me/wincmd/permission.go generated vendored

@ -0,0 +1,262 @@
package wincmd
import (
"fmt"
"strconv"
"strings"
"unsafe"
"b612.me/win32api"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/registry"
)
func StartProcessWithSYS(appPath, cmdLine, workDir string, runas bool) error {
var (
sessionId win32api.HANDLE
userToken win32api.TOKEN = 0
envInfo win32api.HANDLE
impersonationToken win32api.HANDLE = 0
startupInfo win32api.StartupInfo
processInfo win32api.ProcessInformation
sessionInformation win32api.HANDLE = win32api.HANDLE(0)
sessionCount int = 0
sessionList []*win32api.WTS_SESSION_INFO = make([]*win32api.WTS_SESSION_INFO, 0)
err error
)
if err := win32api.WTSEnumerateSessions(0, 0, 1, &sessionInformation, &sessionCount); err != nil {
return err
}
structSize := unsafe.Sizeof(win32api.WTS_SESSION_INFO{})
current := uintptr(sessionInformation)
for i := 0; i < sessionCount; i++ {
sessionList = append(sessionList, (*win32api.WTS_SESSION_INFO)(unsafe.Pointer(current)))
current += structSize
}
if sessionId, err = func() (win32api.HANDLE, error) {
for i := range sessionList {
if sessionList[i].State == win32api.WTSActive {
return sessionList[i].SessionID, nil
}
}
if sessionId, err := win32api.WTSGetActiveConsoleSessionId(); sessionId == 0xFFFFFFFF {
return 0xFFFFFFFF, fmt.Errorf("get current user session token: call native WTSGetActiveConsoleSessionId: %s", err)
} else {
return win32api.HANDLE(sessionId), nil
}
}(); err != nil {
return err
}
if err := win32api.WTSQueryUserToken(sessionId, &impersonationToken); err != nil {
return err
}
if err := win32api.DuplicateTokenEx(impersonationToken, 0, 0, int(win32api.SecurityImpersonation), win32api.TokenPrimary, &userToken); err != nil {
return fmt.Errorf("call native DuplicateTokenEx: %s", err)
}
if runas {
var admin win32api.TOKEN_LINKED_TOKEN
var dt uintptr = 0
if err := win32api.GetTokenInformation(impersonationToken, 19, uintptr(unsafe.Pointer(&admin)), uintptr(unsafe.Sizeof(admin)), &dt); err == nil {
userToken = admin.LinkedToken
}
}
if err := win32api.CloseHandle(impersonationToken); err != nil {
return fmt.Errorf("close windows handle used for token duplication: %s", err)
}
if err := win32api.CreateEnvironmentBlock(&envInfo, userToken, 0); err != nil {
return fmt.Errorf("create environment details for process: %s", err)
}
creationFlags := win32api.CREATE_UNICODE_ENVIRONMENT | win32api.CREATE_NEW_CONSOLE
startupInfo.ShowWindow = win32api.SW_SHOW
startupInfo.Desktop = windows.StringToUTF16Ptr("winsta0\\default")
if err := win32api.CreateProcessAsUser(userToken, appPath, cmdLine, 0, 0, 0,
creationFlags, envInfo, workDir, &startupInfo, &processInfo); err != nil {
return fmt.Errorf("create process as user: %s", err)
}
return nil
}
func GetRunningProcess() ([]map[string]string, error) {
result := []map[string]string{}
pHandle, err := win32api.CreateToolhelp32Snapshot(0x2, 0x0)
if err != nil {
return result, err
}
for {
var proc win32api.PROCESSENTRY32
proc.DwSize = win32api.Ulong(unsafe.Sizeof(proc))
if err := win32api.Process32Next(pHandle, &proc); err == nil {
bytetmp := proc.SzExeFile[0:]
var sakura []byte
for _, v := range bytetmp {
if v == byte(0) {
break
}
sakura = append(sakura, v)
}
result = append(result, map[string]string{"name": string(sakura), "pid": strconv.Itoa(int(proc.Th32ProcessID)), "ppid": fmt.Sprint(int(proc.Th32ParentProcessID))})
} else {
break
}
}
win32api.CloseHandle(pHandle)
return result, nil
}
func IsProcessRunningByPID(pid int) bool {
pHandle, err := win32api.CreateToolhelp32Snapshot(0x2, 0x0)
if err != nil {
return false
}
for {
var proc win32api.PROCESSENTRY32
proc.DwSize = win32api.Ulong(unsafe.Sizeof(proc))
if err := win32api.Process32Next(pHandle, &proc); err == nil {
bytetmp := int(proc.Th32ProcessID)
if bytetmp == pid {
return true
}
} else {
break
}
}
win32api.CloseHandle(pHandle)
return false
}
func IsProcessRunning(name string) bool {
pHandle, err := win32api.CreateToolhelp32Snapshot(0x2, 0x0)
if err != nil {
return false
}
for {
var proc win32api.PROCESSENTRY32
proc.DwSize = win32api.Ulong(unsafe.Sizeof(proc))
if err := win32api.Process32Next(pHandle, &proc); err == nil {
bytetmp := proc.SzExeFile[0:]
var sakura []byte
for _, v := range bytetmp {
if v == byte(0) {
break
}
sakura = append(sakura, v)
}
if strings.ToLower(strings.TrimSpace(string(sakura))) == strings.ToLower(strings.TrimSpace(name)) {
return true
}
} else {
break
}
}
win32api.CloseHandle(pHandle)
return false
}
func GetProcessCount(name string) int {
var res int = 0
pHandle, err := win32api.CreateToolhelp32Snapshot(0x2, 0x0)
if err != nil {
return 0
}
for {
var proc win32api.PROCESSENTRY32
proc.DwSize = win32api.Ulong(unsafe.Sizeof(proc))
if err := win32api.Process32Next(pHandle, &proc); err == nil {
bytetmp := proc.SzExeFile[0:]
var sakura []byte
for _, v := range bytetmp {
if v == byte(0) {
break
}
sakura = append(sakura, v)
}
if strings.ToLower(strings.TrimSpace(string(sakura))) == strings.ToLower(strings.TrimSpace(name)) {
res++
}
} else {
break
}
}
win32api.CloseHandle(pHandle)
return res
}
func Isas() bool {
_, errs := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM`, registry.ALL_ACCESS)
if errs != nil {
return false
}
return true
}
func StartProcess(appPath, cmdLine, wordDir string, runas bool, ShowWindow int) bool {
var cst string
if runas {
cst = "runas"
} else {
cst = "open"
}
r := win32api.ShellExecute(0, cst, appPath, cmdLine, wordDir, ShowWindow)
if r != nil {
return false
}
return true
}
func StartProcessWithPID(appPath, cmdLine, workDir string, runas bool, ShowWindow int) int {
var sakura win32api.SHELLEXECUTEINFOW
sakura.Hwnd = 0
sakura.NShow = ShowWindow
sakura.FMask = 0x00000040
sakura.LpParameters = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(cmdLine)))
sakura.LpFile = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(appPath)))
sakura.LpDirectory = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(workDir)))
if runas {
sakura.LpVerb = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("runas")))
} else {
sakura.LpVerb = uintptr(unsafe.Pointer(windows.StringToUTF16Ptr("open")))
}
sakura.CbSize = win32api.DWORD(unsafe.Sizeof(sakura))
if err := win32api.ShellExecuteEx(&sakura); err != nil {
return 0
}
return int(win32api.GetProcessId(sakura.HProcess))
}
func AutoRun(key, path string) (bool, error) {
reg, errs := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.ALL_ACCESS)
if errs != nil {
return false, errs
}
if errs = reg.SetStringValue(key, path); errs != nil {
return false, errs
}
return true, nil
}
func DeleteAutoRun(key string) (bool, error) {
reg, errs := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.ALL_ACCESS)
if errs != nil {
return false, errs
}
if _, i, _ := reg.GetStringValue(key); i == 0 {
return true, nil
}
if errs = reg.DeleteValue(key); errs != nil {
return false, errs
}
return true, nil
}
func IsAutoRun(key, path string) bool {
reg, errs := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Windows\CurrentVersion\Run`, registry.ALL_ACCESS)
if errs != nil {
return false
}
if sa, _, _ := reg.GetStringValue(key); sa == path {
return true
}
return false
}

353
vendor/b612.me/wincmd/svc.go generated vendored

@ -0,0 +1,353 @@
package wincmd
import (
"errors"
"fmt"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
"golang.org/x/sys/windows/svc/eventlog"
"golang.org/x/sys/windows/svc/mgr"
"time"
)
type SvcStatus svc.State
const (
Stopped = SvcStatus(svc.Stopped)
StartPending = SvcStatus(svc.StartPending)
StopPending = SvcStatus(svc.StopPending)
Running = SvcStatus(svc.Running)
ContinuePending = SvcStatus(svc.ContinuePending)
PausePending = SvcStatus(svc.PausePending)
Paused = SvcStatus(svc.Paused)
StartManual = windows.SERVICE_DEMAND_START // the service must be started manually
StartAutomatic = windows.SERVICE_AUTO_START // the service will start by itself whenever the computer reboots
StartDisabled = windows.SERVICE_DISABLED // the service cannot be started
// The severity of the error, and action taken,
// if this service fails to start.
ErrorCritical = windows.SERVICE_ERROR_CRITICAL
ErrorIgnore = windows.SERVICE_ERROR_IGNORE
ErrorNormal = windows.SERVICE_ERROR_NORMAL
ErrorSevere = windows.SERVICE_ERROR_SEVERE
)
type WinSvcExecute struct {
Run func()
Stop func()
Interrupt func()
Pause func()
Continue func()
OtherMethod func(svc.Cmd)
Name string
Accepted []svc.Accepted
}
type WinSvcInput struct {
Name string
DisplayName string
ExecPath string
DelayedAutoStart bool
Description string
StartType uint32
Args []string
}
type WinSvc struct {
*mgr.Service
}
func IsServiceExists(name string) (bool, error) {
if !Isas() {
return false, errors.New("permission deny")
}
winmgr, err := mgr.Connect()
if err != nil {
return false, err
}
defer winmgr.Disconnect()
lists, err := winmgr.ListServices()
if err != nil {
return false, err
}
for _, v := range lists {
if name == v {
return true, nil
}
}
return false, nil
}
func CreateService(mysvc WinSvcInput) (*WinSvc, error) {
if !Isas() {
return nil, errors.New("permission deny")
}
if exists, err := IsServiceExists(mysvc.Name); err != nil {
return nil, err
} else if exists {
return nil, errors.New("service already exists")
}
winmgr, err := mgr.Connect()
if err != nil {
return nil, err
}
defer winmgr.Disconnect()
mycfg := mgr.Config{
DisplayName: mysvc.DisplayName,
StartType: mysvc.StartType,
DelayedAutoStart: mysvc.DelayedAutoStart,
Description: mysvc.Description,
}
gsvc, err := winmgr.CreateService(mysvc.Name, mysvc.ExecPath, mycfg, mysvc.Args...)
if err != nil {
return nil, err
}
err = eventlog.InstallAsEventCreate(mysvc.Name, eventlog.Error|eventlog.Warning|eventlog.Info)
if err != nil {
gsvc.Delete()
return nil, fmt.Errorf("winsvc.InstallService: InstallAsEventCreate failed, err = %v", err)
}
var result WinSvc
result.Service = gsvc
return &result, nil
}
func OpenService(name string) (*WinSvc, error) {
if !Isas() {
return nil, errors.New("permission deny")
}
if exists, err := IsServiceExists(name); err != nil {
return nil, err
} else if !exists {
return nil, errors.New("service not exists")
}
winmgr, err := mgr.Connect()
if err != nil {
return nil, err
}
defer winmgr.Disconnect()
gsvc, err := winmgr.OpenService(name)
if err != nil {
return nil, err
}
var result WinSvc
result.Service = gsvc
return &result, nil
}
func DeleteService(name string) error {
mysvc, err := OpenService(name)
if err != nil {
return err
}
err = mysvc.Service.Delete()
if err != nil {
mysvc.Close()
return err
}
mysvc.Close()
err = eventlog.Remove(name)
if err != nil {
return err
}
var count int
for {
if ok, err := IsServiceExists(name); err != nil {
return err
} else if !ok {
return nil
}
time.Sleep(time.Millisecond * 300)
count++
if count > 100 {
return errors.New("timeout")
}
}
}
func StopService(name string) error {
mysvc, err := OpenService(name)
if err != nil {
return err
}
defer mysvc.Close()
_, err = mysvc.Service.Control(svc.Stop)
if err != nil {
return err
}
var count int
for {
status, err := mysvc.Service.Query()
if err != nil {
return err
}
if status.State == svc.Stopped {
return nil
}
time.Sleep(time.Millisecond * 100)
count++
if count > 100 {
return errors.New("timeout")
}
}
}
func StartService(name string) error {
mysvc, err := OpenService(name)
if err != nil {
return err
}
defer mysvc.Close()
err = mysvc.Service.Start()
if err != nil {
return err
}
var count int
for {
status, err := mysvc.Service.Query()
if err != nil {
return err
}
if status.State == svc.Running {
return nil
}
time.Sleep(time.Millisecond * 100)
count++
if count > 100 {
return errors.New("timeout")
}
}
}
func ServiceStatus(name string) (SvcStatus, error) {
mysvc, err := OpenService(name)
if err != nil {
return Stopped, err
}
defer mysvc.Close()
status, err := mysvc.Service.Query()
return SvcStatus(status.State), err
}
func InService() (bool, error) {
if !Isas() {
return false, nil
}
return svc.IsWindowsService()
}
func (w *WinSvc) Stop() error {
return StopService(w.Name)
}
func (w *WinSvc) Delete() error {
if err := w.Close(); err != nil {
return err
}
return DeleteService(w.Name)
}
func (w *WinSvc) StartService() error {
err := w.Service.Start()
if err != nil {
return err
}
var count int
for {
sts, err := w.Query()
if err != nil {
return err
}
if SvcStatus(sts.State) == Running {
return nil
}
time.Sleep(time.Millisecond * 100)
count++
if count > 100 {
return errors.New("timeout")
}
}
}
func InServiceBool() bool {
ok, _ := svc.IsWindowsService()
return ok
}
func (w *WinSvcExecute) Execute(args []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) {
var sva svc.Accepted
alreadyStoped := make(chan int)
for _, v := range w.Accepted {
sva = sva | v
}
s <- svc.Status{State: svc.StartPending}
go func() {
s <- svc.Status{State: svc.Running, Accepts: sva}
w.Run()
alreadyStoped <- 1
}()
for {
select {
case <-alreadyStoped:
return
case c := <-r:
switch c.Cmd {
case svc.Interrogate:
s <- c.CurrentStatus
w.Interrupt()
s <- c.CurrentStatus
case svc.Stop, svc.Shutdown:
s <- svc.Status{State: svc.StopPending}
w.Stop()
s <- svc.Status{State: svc.Stopped}
return
case svc.Pause:
s <- svc.Status{State: svc.PausePending, Accepts: sva}
if w.Pause != nil {
w.Pause()
}
s <- svc.Status{State: svc.Paused, Accepts: sva}
case svc.Continue:
s <- svc.Status{State: svc.ContinuePending, Accepts: sva}
if w.Continue != nil {
w.Continue()
}
s <- svc.Status{State: svc.Running, Accepts: sva}
default:
if w.OtherMethod != nil {
w.OtherMethod(c.Cmd)
}
s <- svc.Status{State: svc.Running, Accepts: sva}
}
}
}
}
func NewWinSvcExecute(name string, run, stop func()) *WinSvcExecute {
var res WinSvcExecute
res.Run = run
res.Stop = stop
res.Interrupt = func() {
time.Sleep(time.Millisecond)
}
res.Accepted = []svc.Accepted{svc.AcceptStop, svc.AcceptShutdown, svc.AcceptPauseAndContinue}
return &res
}
func (w *WinSvcExecute) StartService() error {
return svc.Run(w.Name, w)
}
func (w *WinSvcExecute) InService() (bool, error) {
if !Isas() {
return false, nil
}
return svc.IsWindowsService()
}
func (w *WinSvcExecute) InServiceBool() bool {
ok, _ := svc.IsWindowsService()
return ok
}

@ -0,0 +1,159 @@
// 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 blowfish
// getNextWord returns the next big-endian uint32 value from the byte slice
// at the given position in a circular manner, updating the position.
func getNextWord(b []byte, pos *int) uint32 {
var w uint32
j := *pos
for i := 0; i < 4; i++ {
w = w<<8 | uint32(b[j])
j++
if j >= len(b) {
j = 0
}
}
*pos = j
return w
}
// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
// pi and substitution tables for calls to Encrypt. This is used, primarily,
// by the bcrypt package to reuse the Blowfish key schedule during its
// set up. It's unlikely that you need to use this directly.
func ExpandKey(key []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
// Using inlined getNextWord for performance.
var d uint32
for k := 0; k < 4; k++ {
d = d<<8 | uint32(key[j])
j++
if j >= len(key) {
j = 0
}
}
c.p[i] ^= d
}
var l, r uint32
for i := 0; i < 18; i += 2 {
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
// This is similar to ExpandKey, but folds the salt during the key
// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
// and specializing it here is useful.
func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
j := 0
for i := 0; i < 18; i++ {
c.p[i] ^= getNextWord(key, &j)
}
j = 0
var l, r uint32
for i := 0; i < 18; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.p[i], c.p[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s0[i], c.s0[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s1[i], c.s1[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s2[i], c.s2[i+1] = l, r
}
for i := 0; i < 256; i += 2 {
l ^= getNextWord(salt, &j)
r ^= getNextWord(salt, &j)
l, r = encryptBlock(l, r, c)
c.s3[i], c.s3[i+1] = l, r
}
}
func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[0]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
xr ^= c.p[17]
return xr, xl
}
func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
xl, xr := l, r
xl ^= c.p[17]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
xr ^= c.p[0]
return xr, xl
}

@ -0,0 +1,99 @@
// 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 blowfish implements Bruce Schneier's Blowfish encryption algorithm.
//
// Blowfish is a legacy cipher and its short block size makes it vulnerable to
// birthday bound attacks (see https://sweet32.info). It should only be used
// where compatibility with legacy systems, not security, is the goal.
//
// Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305).
package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html.
import "strconv"
// The Blowfish block size in bytes.
const BlockSize = 8
// A Cipher is an instance of Blowfish encryption using a particular key.
type Cipher struct {
p [18]uint32
s0, s1, s2, s3 [256]uint32
}
type KeySizeError int
func (k KeySizeError) Error() string {
return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
}
// NewCipher creates and returns a Cipher.
// The key argument should be the Blowfish key, from 1 to 56 bytes.
func NewCipher(key []byte) (*Cipher, error) {
var result Cipher
if k := len(key); k < 1 || k > 56 {
return nil, KeySizeError(k)
}
initCipher(&result)
ExpandKey(key, &result)
return &result, nil
}
// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
// sufficient and desirable. For bcrypt compatibility, the key can be over 56
// bytes.
func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
if len(salt) == 0 {
return NewCipher(key)
}
var result Cipher
if k := len(key); k < 1 {
return nil, KeySizeError(k)
}
initCipher(&result)
expandKeyWithSalt(key, salt, &result)
return &result, nil
}
// BlockSize returns the Blowfish block size, 8 bytes.
// It is necessary to satisfy the Block interface in the
// package "crypto/cipher".
func (c *Cipher) BlockSize() int { return BlockSize }
// Encrypt encrypts the 8-byte buffer src using the key k
// and stores the result in dst.
// Note that for amounts of data larger than a block,
// it is not safe to just call Encrypt on successive blocks;
// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
func (c *Cipher) Encrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = encryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
// Decrypt decrypts the 8-byte buffer src using the key k
// and stores the result in dst.
func (c *Cipher) Decrypt(dst, src []byte) {
l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
l, r = decryptBlock(l, r, c)
dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
}
func initCipher(c *Cipher) {
copy(c.p[0:], p[0:])
copy(c.s0[0:], s0[0:])
copy(c.s1[0:], s1[0:])
copy(c.s2[0:], s2[0:])
copy(c.s3[0:], s3[0:])
}

@ -0,0 +1,199 @@
// 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.
// The startup permutation array and substitution boxes.
// They are the hexadecimal digits of PI; see:
// https://www.schneier.com/code/constants.txt.
package blowfish
var s0 = [256]uint32{
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
}
var s1 = [256]uint32{
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
}
var s2 = [256]uint32{
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
}
var s3 = [256]uint32{
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
}
var p = [18]uint32{
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
}

@ -0,0 +1,17 @@
// Copyright 2018 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.
//go:build go1.11 && gc && !purego
// +build go1.11,gc,!purego
package chacha20
const bufSize = 256
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
}

@ -0,0 +1,398 @@
// Copyright 2016 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 chacha20 implements the ChaCha20 and XChaCha20 encryption algorithms
// as specified in RFC 8439 and draft-irtf-cfrg-xchacha-01.
package chacha20
import (
"crypto/cipher"
"encoding/binary"
"errors"
"math/bits"
"golang.org/x/crypto/internal/subtle"
)
const (
// KeySize is the size of the key used by this cipher, in bytes.
KeySize = 32
// NonceSize is the size of the nonce used with the standard variant of this
// cipher, in bytes.
//
// Note that this is too short to be safely generated at random if the same
// key is reused more than 2³² times.
NonceSize = 12
// NonceSizeX is the size of the nonce used with the XChaCha20 variant of
// this cipher, in bytes.
NonceSizeX = 24
)
// Cipher is a stateful instance of ChaCha20 or XChaCha20 using a particular key
// and nonce. A *Cipher implements the cipher.Stream interface.
type Cipher struct {
// The ChaCha20 state is 16 words: 4 constant, 8 of key, 1 of counter
// (incremented after each block), and 3 of nonce.
key [8]uint32
counter uint32
nonce [3]uint32
// The last len bytes of buf are leftover key stream bytes from the previous
// XORKeyStream invocation. The size of buf depends on how many blocks are
// computed at a time by xorKeyStreamBlocks.
buf [bufSize]byte
len int
// overflow is set when the counter overflowed, no more blocks can be
// generated, and the next XORKeyStream call should panic.
overflow bool
// The counter-independent results of the first round are cached after they
// are computed the first time.
precompDone bool
p1, p5, p9, p13 uint32
p2, p6, p10, p14 uint32
p3, p7, p11, p15 uint32
}
var _ cipher.Stream = (*Cipher)(nil)
// NewUnauthenticatedCipher creates a new ChaCha20 stream cipher with the given
// 32 bytes key and a 12 or 24 bytes nonce. If a nonce of 24 bytes is provided,
// the XChaCha20 construction will be used. It returns an error if key or nonce
// have any other length.
//
// Note that ChaCha20, like all stream ciphers, is not authenticated and allows
// attackers to silently tamper with the plaintext. For this reason, it is more
// appropriate as a building block than as a standalone encryption mechanism.
// Instead, consider using package golang.org/x/crypto/chacha20poly1305.
func NewUnauthenticatedCipher(key, nonce []byte) (*Cipher, error) {
// This function is split into a wrapper so that the Cipher allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
c := &Cipher{}
return newUnauthenticatedCipher(c, key, nonce)
}
func newUnauthenticatedCipher(c *Cipher, key, nonce []byte) (*Cipher, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong key size")
}
if len(nonce) == NonceSizeX {
// XChaCha20 uses the ChaCha20 core to mix 16 bytes of the nonce into a
// derived key, allowing it to operate on a nonce of 24 bytes. See
// draft-irtf-cfrg-xchacha-01, Section 2.3.
key, _ = HChaCha20(key, nonce[0:16])
cNonce := make([]byte, NonceSize)
copy(cNonce[4:12], nonce[16:24])
nonce = cNonce
} else if len(nonce) != NonceSize {
return nil, errors.New("chacha20: wrong nonce size")
}
key, nonce = key[:KeySize], nonce[:NonceSize] // bounds check elimination hint
c.key = [8]uint32{
binary.LittleEndian.Uint32(key[0:4]),
binary.LittleEndian.Uint32(key[4:8]),
binary.LittleEndian.Uint32(key[8:12]),
binary.LittleEndian.Uint32(key[12:16]),
binary.LittleEndian.Uint32(key[16:20]),
binary.LittleEndian.Uint32(key[20:24]),
binary.LittleEndian.Uint32(key[24:28]),
binary.LittleEndian.Uint32(key[28:32]),
}
c.nonce = [3]uint32{
binary.LittleEndian.Uint32(nonce[0:4]),
binary.LittleEndian.Uint32(nonce[4:8]),
binary.LittleEndian.Uint32(nonce[8:12]),
}
return c, nil
}
// The constant first 4 words of the ChaCha20 state.
const (
j0 uint32 = 0x61707865 // expa
j1 uint32 = 0x3320646e // nd 3
j2 uint32 = 0x79622d32 // 2-by
j3 uint32 = 0x6b206574 // te k
)
const blockSize = 64
// quarterRound is the core of ChaCha20. It shuffles the bits of 4 state words.
// It's executed 4 times for each of the 20 ChaCha20 rounds, operating on all 16
// words each round, in columnar or diagonal groups of 4 at a time.
func quarterRound(a, b, c, d uint32) (uint32, uint32, uint32, uint32) {
a += b
d ^= a
d = bits.RotateLeft32(d, 16)
c += d
b ^= c
b = bits.RotateLeft32(b, 12)
a += b
d ^= a
d = bits.RotateLeft32(d, 8)
c += d
b ^= c
b = bits.RotateLeft32(b, 7)
return a, b, c, d
}
// SetCounter sets the Cipher counter. The next invocation of XORKeyStream will
// behave as if (64 * counter) bytes had been encrypted so far.
//
// To prevent accidental counter reuse, SetCounter panics if counter is less
// than the current value.
//
// Note that the execution time of XORKeyStream is not independent of the
// counter value.
func (s *Cipher) SetCounter(counter uint32) {
// Internally, s may buffer multiple blocks, which complicates this
// implementation slightly. When checking whether the counter has rolled
// back, we must use both s.counter and s.len to determine how many blocks
// we have already output.
outputCounter := s.counter - uint32(s.len)/blockSize
if s.overflow || counter < outputCounter {
panic("chacha20: SetCounter attempted to rollback counter")
}
// In the general case, we set the new counter value and reset s.len to 0,
// causing the next call to XORKeyStream to refill the buffer. However, if
// we're advancing within the existing buffer, we can save work by simply
// setting s.len.
if counter < s.counter {
s.len = int(s.counter-counter) * blockSize
} else {
s.counter = counter
s.len = 0
}
}
// XORKeyStream XORs each byte in the given slice with a byte from the
// cipher's key stream. Dst and src must overlap entirely or not at all.
//
// If len(dst) < len(src), XORKeyStream will panic. It is acceptable
// to pass a dst bigger than src, and in that case, XORKeyStream will
// only update dst[:len(src)] and will not touch the rest of dst.
//
// Multiple calls to XORKeyStream behave as if the concatenation of
// the src buffers was passed in a single run. That is, Cipher
// maintains state and does not reset at each XORKeyStream call.
func (s *Cipher) XORKeyStream(dst, src []byte) {
if len(src) == 0 {
return
}
if len(dst) < len(src) {
panic("chacha20: output smaller than input")
}
dst = dst[:len(src)]
if subtle.InexactOverlap(dst, src) {
panic("chacha20: invalid buffer overlap")
}
// First, drain any remaining key stream from a previous XORKeyStream.
if s.len != 0 {
keyStream := s.buf[bufSize-s.len:]
if len(src) < len(keyStream) {
keyStream = keyStream[:len(src)]
}
_ = src[len(keyStream)-1] // bounds check elimination hint
for i, b := range keyStream {
dst[i] = src[i] ^ b
}
s.len -= len(keyStream)
dst, src = dst[len(keyStream):], src[len(keyStream):]
}
if len(src) == 0 {
return
}
// If we'd need to let the counter overflow and keep generating output,
// panic immediately. If instead we'd only reach the last block, remember
// not to generate any more output after the buffer is drained.
numBlocks := (uint64(len(src)) + blockSize - 1) / blockSize
if s.overflow || uint64(s.counter)+numBlocks > 1<<32 {
panic("chacha20: counter overflow")
} else if uint64(s.counter)+numBlocks == 1<<32 {
s.overflow = true
}
// xorKeyStreamBlocks implementations expect input lengths that are a
// multiple of bufSize. Platform-specific ones process multiple blocks at a
// time, so have bufSizes that are a multiple of blockSize.
full := len(src) - len(src)%bufSize
if full > 0 {
s.xorKeyStreamBlocks(dst[:full], src[:full])
}
dst, src = dst[full:], src[full:]
// If using a multi-block xorKeyStreamBlocks would overflow, use the generic
// one that does one block at a time.
const blocksPerBuf = bufSize / blockSize
if uint64(s.counter)+blocksPerBuf > 1<<32 {
s.buf = [bufSize]byte{}
numBlocks := (len(src) + blockSize - 1) / blockSize
buf := s.buf[bufSize-numBlocks*blockSize:]
copy(buf, src)
s.xorKeyStreamBlocksGeneric(buf, buf)
s.len = len(buf) - copy(dst, buf)
return
}
// If we have a partial (multi-)block, pad it for xorKeyStreamBlocks, and
// keep the leftover keystream for the next XORKeyStream invocation.
if len(src) > 0 {
s.buf = [bufSize]byte{}
copy(s.buf[:], src)
s.xorKeyStreamBlocks(s.buf[:], s.buf[:])
s.len = bufSize - copy(dst, s.buf[:])
}
}
func (s *Cipher) xorKeyStreamBlocksGeneric(dst, src []byte) {
if len(dst) != len(src) || len(dst)%blockSize != 0 {
panic("chacha20: internal error: wrong dst and/or src length")
}
// To generate each block of key stream, the initial cipher state
// (represented below) is passed through 20 rounds of shuffling,
// alternatively applying quarterRounds by columns (like 1, 5, 9, 13)
// or by diagonals (like 1, 6, 11, 12).
//
// 0:cccccccc 1:cccccccc 2:cccccccc 3:cccccccc
// 4:kkkkkkkk 5:kkkkkkkk 6:kkkkkkkk 7:kkkkkkkk
// 8:kkkkkkkk 9:kkkkkkkk 10:kkkkkkkk 11:kkkkkkkk
// 12:bbbbbbbb 13:nnnnnnnn 14:nnnnnnnn 15:nnnnnnnn
//
// c=constant k=key b=blockcount n=nonce
var (
c0, c1, c2, c3 = j0, j1, j2, j3
c4, c5, c6, c7 = s.key[0], s.key[1], s.key[2], s.key[3]
c8, c9, c10, c11 = s.key[4], s.key[5], s.key[6], s.key[7]
_, c13, c14, c15 = s.counter, s.nonce[0], s.nonce[1], s.nonce[2]
)
// Three quarters of the first round don't depend on the counter, so we can
// calculate them here, and reuse them for multiple blocks in the loop, and
// for future XORKeyStream invocations.
if !s.precompDone {
s.p1, s.p5, s.p9, s.p13 = quarterRound(c1, c5, c9, c13)
s.p2, s.p6, s.p10, s.p14 = quarterRound(c2, c6, c10, c14)
s.p3, s.p7, s.p11, s.p15 = quarterRound(c3, c7, c11, c15)
s.precompDone = true
}
// A condition of len(src) > 0 would be sufficient, but this also
// acts as a bounds check elimination hint.
for len(src) >= 64 && len(dst) >= 64 {
// The remainder of the first column round.
fcr0, fcr4, fcr8, fcr12 := quarterRound(c0, c4, c8, s.counter)
// The second diagonal round.
x0, x5, x10, x15 := quarterRound(fcr0, s.p5, s.p10, s.p15)
x1, x6, x11, x12 := quarterRound(s.p1, s.p6, s.p11, fcr12)
x2, x7, x8, x13 := quarterRound(s.p2, s.p7, fcr8, s.p13)
x3, x4, x9, x14 := quarterRound(s.p3, fcr4, s.p9, s.p14)
// The remaining 18 rounds.
for i := 0; i < 9; i++ {
// Column round.
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
// Diagonal round.
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
// Add back the initial state to generate the key stream, then
// XOR the key stream with the source and write out the result.
addXor(dst[0:4], src[0:4], x0, c0)
addXor(dst[4:8], src[4:8], x1, c1)
addXor(dst[8:12], src[8:12], x2, c2)
addXor(dst[12:16], src[12:16], x3, c3)
addXor(dst[16:20], src[16:20], x4, c4)
addXor(dst[20:24], src[20:24], x5, c5)
addXor(dst[24:28], src[24:28], x6, c6)
addXor(dst[28:32], src[28:32], x7, c7)
addXor(dst[32:36], src[32:36], x8, c8)
addXor(dst[36:40], src[36:40], x9, c9)
addXor(dst[40:44], src[40:44], x10, c10)
addXor(dst[44:48], src[44:48], x11, c11)
addXor(dst[48:52], src[48:52], x12, s.counter)
addXor(dst[52:56], src[52:56], x13, c13)
addXor(dst[56:60], src[56:60], x14, c14)
addXor(dst[60:64], src[60:64], x15, c15)
s.counter += 1
src, dst = src[blockSize:], dst[blockSize:]
}
}
// HChaCha20 uses the ChaCha20 core to generate a derived key from a 32 bytes
// key and a 16 bytes nonce. It returns an error if key or nonce have any other
// length. It is used as part of the XChaCha20 construction.
func HChaCha20(key, nonce []byte) ([]byte, error) {
// This function is split into a wrapper so that the slice allocation will
// be inlined, and depending on how the caller uses the return value, won't
// escape to the heap.
out := make([]byte, 32)
return hChaCha20(out, key, nonce)
}
func hChaCha20(out, key, nonce []byte) ([]byte, error) {
if len(key) != KeySize {
return nil, errors.New("chacha20: wrong HChaCha20 key size")
}
if len(nonce) != 16 {
return nil, errors.New("chacha20: wrong HChaCha20 nonce size")
}
x0, x1, x2, x3 := j0, j1, j2, j3
x4 := binary.LittleEndian.Uint32(key[0:4])
x5 := binary.LittleEndian.Uint32(key[4:8])
x6 := binary.LittleEndian.Uint32(key[8:12])
x7 := binary.LittleEndian.Uint32(key[12:16])
x8 := binary.LittleEndian.Uint32(key[16:20])
x9 := binary.LittleEndian.Uint32(key[20:24])
x10 := binary.LittleEndian.Uint32(key[24:28])
x11 := binary.LittleEndian.Uint32(key[28:32])
x12 := binary.LittleEndian.Uint32(nonce[0:4])
x13 := binary.LittleEndian.Uint32(nonce[4:8])
x14 := binary.LittleEndian.Uint32(nonce[8:12])
x15 := binary.LittleEndian.Uint32(nonce[12:16])
for i := 0; i < 10; i++ {
// Diagonal round.
x0, x4, x8, x12 = quarterRound(x0, x4, x8, x12)
x1, x5, x9, x13 = quarterRound(x1, x5, x9, x13)
x2, x6, x10, x14 = quarterRound(x2, x6, x10, x14)
x3, x7, x11, x15 = quarterRound(x3, x7, x11, x15)
// Column round.
x0, x5, x10, x15 = quarterRound(x0, x5, x10, x15)
x1, x6, x11, x12 = quarterRound(x1, x6, x11, x12)
x2, x7, x8, x13 = quarterRound(x2, x7, x8, x13)
x3, x4, x9, x14 = quarterRound(x3, x4, x9, x14)
}
_ = out[31] // bounds check elimination hint
binary.LittleEndian.PutUint32(out[0:4], x0)
binary.LittleEndian.PutUint32(out[4:8], x1)
binary.LittleEndian.PutUint32(out[8:12], x2)
binary.LittleEndian.PutUint32(out[12:16], x3)
binary.LittleEndian.PutUint32(out[16:20], x12)
binary.LittleEndian.PutUint32(out[20:24], x13)
binary.LittleEndian.PutUint32(out[24:28], x14)
binary.LittleEndian.PutUint32(out[28:32], x15)
return out, nil
}

@ -0,0 +1,14 @@
// Copyright 2018 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.
//go:build (!arm64 && !s390x && !ppc64le) || (arm64 && !go1.11) || !gc || purego
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 !gc purego
package chacha20
const bufSize = blockSize
func (s *Cipher) xorKeyStreamBlocks(dst, src []byte) {
s.xorKeyStreamBlocksGeneric(dst, src)
}

@ -0,0 +1,17 @@
// Copyright 2019 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.
//go:build gc && !purego
// +build gc,!purego
package chacha20
const bufSize = 256
//go:noescape
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
}

@ -0,0 +1,27 @@
// Copyright 2018 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.
//go:build gc && !purego
// +build gc,!purego
package chacha20
import "golang.org/x/sys/cpu"
var haveAsm = cpu.S390X.HasVX
const bufSize = 256
// xorKeyStreamVX is an assembly implementation of XORKeyStream. It must only
// be called when the vector facility is available. Implementation in asm_s390x.s.
//go:noescape
func xorKeyStreamVX(dst, src []byte, key *[8]uint32, nonce *[3]uint32, counter *uint32)
func (c *Cipher) xorKeyStreamBlocks(dst, src []byte) {
if cpu.S390X.HasVX {
xorKeyStreamVX(dst, src, &c.key, &c.nonce, &c.counter)
} else {
c.xorKeyStreamBlocksGeneric(dst, src)
}
}

@ -0,0 +1,42 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found src the LICENSE file.
package chacha20
import "runtime"
// Platforms that have fast unaligned 32-bit little endian accesses.
const unaligned = runtime.GOARCH == "386" ||
runtime.GOARCH == "amd64" ||
runtime.GOARCH == "arm64" ||
runtime.GOARCH == "ppc64le" ||
runtime.GOARCH == "s390x"
// addXor reads a little endian uint32 from src, XORs it with (a + b) and
// places the result in little endian byte order in dst.
func addXor(dst, src []byte, a, b uint32) {
_, _ = src[3], dst[3] // bounds check elimination hint
if unaligned {
// The compiler should optimize this code into
// 32-bit unaligned little endian loads and stores.
// TODO: delete once the compiler does a reliably
// good job with the generic code below.
// See issue #25111 for more details.
v := uint32(src[0])
v |= uint32(src[1]) << 8
v |= uint32(src[2]) << 16
v |= uint32(src[3]) << 24
v ^= a + b
dst[0] = byte(v)
dst[1] = byte(v >> 8)
dst[2] = byte(v >> 16)
dst[3] = byte(v >> 24)
} else {
a += b
dst[0] = src[0] ^ byte(a)
dst[1] = src[1] ^ byte(a>>8)
dst[2] = src[2] ^ byte(a>>16)
dst[3] = src[3] ^ byte(a>>24)
}
}

@ -0,0 +1,145 @@
// Copyright 2019 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 curve25519 provides an implementation of the X25519 function, which
// performs scalar multiplication on the elliptic curve known as Curve25519.
// See RFC 7748.
package curve25519 // import "golang.org/x/crypto/curve25519"
import (
"crypto/subtle"
"fmt"
"golang.org/x/crypto/curve25519/internal/field"
)
// ScalarMult sets dst to the product scalar * point.
//
// Deprecated: when provided a low-order point, ScalarMult will set dst to all
// zeroes, irrespective of the scalar. Instead, use the X25519 function, which
// will return an error.
func ScalarMult(dst, scalar, point *[32]byte) {
var e [32]byte
copy(e[:], scalar[:])
e[0] &= 248
e[31] &= 127
e[31] |= 64
var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
x1.SetBytes(point[:])
x2.One()
x3.Set(&x1)
z3.One()
swap := 0
for pos := 254; pos >= 0; pos-- {
b := e[pos/8] >> uint(pos&7)
b &= 1
swap ^= int(b)
x2.Swap(&x3, swap)
z2.Swap(&z3, swap)
swap = int(b)
tmp0.Subtract(&x3, &z3)
tmp1.Subtract(&x2, &z2)
x2.Add(&x2, &z2)
z2.Add(&x3, &z3)
z3.Multiply(&tmp0, &x2)
z2.Multiply(&z2, &tmp1)
tmp0.Square(&tmp1)
tmp1.Square(&x2)
x3.Add(&z3, &z2)
z2.Subtract(&z3, &z2)
x2.Multiply(&tmp1, &tmp0)
tmp1.Subtract(&tmp1, &tmp0)
z2.Square(&z2)
z3.Mult32(&tmp1, 121666)
x3.Square(&x3)
tmp0.Add(&tmp0, &z3)
z3.Multiply(&x1, &z2)
z2.Multiply(&tmp1, &tmp0)
}
x2.Swap(&x3, swap)
z2.Swap(&z3, swap)
z2.Invert(&z2)
x2.Multiply(&x2, &z2)
copy(dst[:], x2.Bytes())
}
// ScalarBaseMult sets dst to the product scalar * base where base is the
// standard generator.
//
// It is recommended to use the X25519 function with Basepoint instead, as
// copying into fixed size arrays can lead to unexpected bugs.
func ScalarBaseMult(dst, scalar *[32]byte) {
ScalarMult(dst, scalar, &basePoint)
}
const (
// ScalarSize is the size of the scalar input to X25519.
ScalarSize = 32
// PointSize is the size of the point input to X25519.
PointSize = 32
)
// Basepoint is the canonical Curve25519 generator.
var Basepoint []byte
var basePoint = [32]byte{9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
func init() { Basepoint = basePoint[:] }
func checkBasepoint() {
if subtle.ConstantTimeCompare(Basepoint, []byte{
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}) != 1 {
panic("curve25519: global Basepoint value was modified")
}
}
// X25519 returns the result of the scalar multiplication (scalar * point),
// according to RFC 7748, Section 5. scalar, point and the return value are
// slices of 32 bytes.
//
// scalar can be generated at random, for example with crypto/rand. point should
// be either Basepoint or the output of another X25519 call.
//
// If point is Basepoint (but not if it's a different slice with the same
// contents) a precomputed implementation might be used for performance.
func X25519(scalar, point []byte) ([]byte, error) {
// Outline the body of function, to let the allocation be inlined in the
// caller, and possibly avoid escaping to the heap.
var dst [32]byte
return x25519(&dst, scalar, point)
}
func x25519(dst *[32]byte, scalar, point []byte) ([]byte, error) {
var in [32]byte
if l := len(scalar); l != 32 {
return nil, fmt.Errorf("bad scalar length: %d, expected %d", l, 32)
}
if l := len(point); l != 32 {
return nil, fmt.Errorf("bad point length: %d, expected %d", l, 32)
}
copy(in[:], scalar)
if &point[0] == &Basepoint[0] {
checkBasepoint()
ScalarBaseMult(dst, &in)
} else {
var base, zero [32]byte
copy(base[:], point)
ScalarMult(dst, &in, &base)
if subtle.ConstantTimeCompare(dst[:], zero[:]) == 1 {
return nil, fmt.Errorf("bad input point: low order point")
}
}
return dst[:], nil
}

@ -0,0 +1,416 @@
// Copyright (c) 2017 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 field implements fast arithmetic modulo 2^255-19.
package field
import (
"crypto/subtle"
"encoding/binary"
"math/bits"
)
// Element represents an element of the field GF(2^255-19). Note that this
// is not a cryptographically secure group, and should only be used to interact
// with edwards25519.Point coordinates.
//
// This type works similarly to math/big.Int, and all arguments and receivers
// are allowed to alias.
//
// The zero value is a valid zero element.
type Element struct {
// An element t represents the integer
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
//
// Between operations, all limbs are expected to be lower than 2^52.
l0 uint64
l1 uint64
l2 uint64
l3 uint64
l4 uint64
}
const maskLow51Bits uint64 = (1 << 51) - 1
var feZero = &Element{0, 0, 0, 0, 0}
// Zero sets v = 0, and returns v.
func (v *Element) Zero() *Element {
*v = *feZero
return v
}
var feOne = &Element{1, 0, 0, 0, 0}
// One sets v = 1, and returns v.
func (v *Element) One() *Element {
*v = *feOne
return v
}
// reduce reduces v modulo 2^255 - 19 and returns it.
func (v *Element) reduce() *Element {
v.carryPropagate()
// After the light reduction we now have a field element representation
// v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v.l0 + 19) >> 51
c = (v.l1 + c) >> 51
c = (v.l2 + c) >> 51
c = (v.l3 + c) >> 51
c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
// effectively applying the reduction identity to the carry.
v.l0 += 19 * c
v.l1 += v.l0 >> 51
v.l0 = v.l0 & maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 = v.l1 & maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 = v.l2 & maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 = v.l3 & maskLow51Bits
// no additional carry
v.l4 = v.l4 & maskLow51Bits
return v
}
// Add sets v = a + b, and returns v.
func (v *Element) Add(a, b *Element) *Element {
v.l0 = a.l0 + b.l0
v.l1 = a.l1 + b.l1
v.l2 = a.l2 + b.l2
v.l3 = a.l3 + b.l3
v.l4 = a.l4 + b.l4
// Using the generic implementation here is actually faster than the
// assembly. Probably because the body of this function is so simple that
// the compiler can figure out better optimizations by inlining the carry
// propagation. TODO
return v.carryPropagateGeneric()
}
// Subtract sets v = a - b, and returns v.
func (v *Element) Subtract(a, b *Element) *Element {
// We first add 2 * p, to guarantee the subtraction won't underflow, and
// then subtract b (which can be up to 2^255 + 2^13 * 19).
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate()
}
// Negate sets v = -a, and returns v.
func (v *Element) Negate(a *Element) *Element {
return v.Subtract(feZero, a)
}
// Invert sets v = 1/z mod p, and returns v.
//
// If z == 0, Invert returns v = 0.
func (v *Element) Invert(z *Element) *Element {
// Inversion is implemented as exponentiation with exponent p 2. It uses the
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
z2.Square(z) // 2
t.Square(&z2) // 4
t.Square(&t) // 8
z9.Multiply(&t, z) // 9
z11.Multiply(&z9, &z2) // 11
t.Square(&z11) // 22
z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
t.Square(&z2_5_0) // 2^6 - 2^1
for i := 0; i < 4; i++ {
t.Square(&t) // 2^10 - 2^5
}
z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
t.Square(&z2_10_0) // 2^11 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^20 - 2^10
}
z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
t.Square(&z2_20_0) // 2^21 - 2^1
for i := 0; i < 19; i++ {
t.Square(&t) // 2^40 - 2^20
}
t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
t.Square(&t) // 2^41 - 2^1
for i := 0; i < 9; i++ {
t.Square(&t) // 2^50 - 2^10
}
z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
t.Square(&z2_50_0) // 2^51 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^100 - 2^50
}
z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
t.Square(&z2_100_0) // 2^101 - 2^1
for i := 0; i < 99; i++ {
t.Square(&t) // 2^200 - 2^100
}
t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
t.Square(&t) // 2^201 - 2^1
for i := 0; i < 49; i++ {
t.Square(&t) // 2^250 - 2^50
}
t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
t.Square(&t) // 2^251 - 2^1
t.Square(&t) // 2^252 - 2^2
t.Square(&t) // 2^253 - 2^3
t.Square(&t) // 2^254 - 2^4
t.Square(&t) // 2^255 - 2^5
return v.Multiply(&t, &z11) // 2^255 - 21
}
// Set sets v = a, and returns v.
func (v *Element) Set(a *Element) *Element {
*v = *a
return v
}
// SetBytes sets v to x, which must be a 32-byte little-endian encoding.
//
// Consistent with RFC 7748, the most significant bit (the high bit of the
// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
// are accepted. Note that this is laxer than specified by RFC 8032.
func (v *Element) SetBytes(x []byte) *Element {
if len(x) != 32 {
panic("edwards25519: invalid field element input size")
}
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
v.l0 = binary.LittleEndian.Uint64(x[0:8])
v.l0 &= maskLow51Bits
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
v.l1 &= maskLow51Bits
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v.l2 &= maskLow51Bits
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
v.l3 &= maskLow51Bits
// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
// Note: not bytes 25:33, shift 4, to avoid overread.
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
v.l4 &= maskLow51Bits
return v
}
// Bytes returns the canonical 32-byte little-endian encoding of v.
func (v *Element) Bytes() []byte {
// This function is outlined to make the allocations inline in the caller
// rather than happen on the heap.
var out [32]byte
return v.bytes(&out)
}
func (v *Element) bytes(out *[32]byte) []byte {
t := *v
t.reduce()
var buf [8]byte
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
bitsOffset := i * 51
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
for i, bb := range buf {
off := bitsOffset/8 + i
if off >= len(out) {
break
}
out[off] |= bb
}
}
return out[:]
}
// Equal returns 1 if v and u are equal, and 0 otherwise.
func (v *Element) Equal(u *Element) int {
sa, sv := u.Bytes(), v.Bytes()
return subtle.ConstantTimeCompare(sa, sv)
}
// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
// Select sets v to a if cond == 1, and to b if cond == 0.
func (v *Element) Select(a, b *Element, cond int) *Element {
m := mask64Bits(cond)
v.l0 = (m & a.l0) | (^m & b.l0)
v.l1 = (m & a.l1) | (^m & b.l1)
v.l2 = (m & a.l2) | (^m & b.l2)
v.l3 = (m & a.l3) | (^m & b.l3)
v.l4 = (m & a.l4) | (^m & b.l4)
return v
}
// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
func (v *Element) Swap(u *Element, cond int) {
m := mask64Bits(cond)
t := m & (v.l0 ^ u.l0)
v.l0 ^= t
u.l0 ^= t
t = m & (v.l1 ^ u.l1)
v.l1 ^= t
u.l1 ^= t
t = m & (v.l2 ^ u.l2)
v.l2 ^= t
u.l2 ^= t
t = m & (v.l3 ^ u.l3)
v.l3 ^= t
u.l3 ^= t
t = m & (v.l4 ^ u.l4)
v.l4 ^= t
u.l4 ^= t
}
// IsNegative returns 1 if v is negative, and 0 otherwise.
func (v *Element) IsNegative() int {
return int(v.Bytes()[0] & 1)
}
// Absolute sets v to |u|, and returns v.
func (v *Element) Absolute(u *Element) *Element {
return v.Select(new(Element).Negate(u), u, u.IsNegative())
}
// Multiply sets v = x * y, and returns v.
func (v *Element) Multiply(x, y *Element) *Element {
feMul(v, x, y)
return v
}
// Square sets v = x * x, and returns v.
func (v *Element) Square(x *Element) *Element {
feSquare(v, x)
return v
}
// Mult32 sets v = x * y, and returns v.
func (v *Element) Mult32(x *Element, y uint32) *Element {
x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x.l4, y)
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v.l1 = x1lo + x0hi
v.l2 = x2lo + x1hi
v.l3 = x3lo + x2hi
v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation.
return v
}
// mul51 returns lo + hi * 2⁵¹ = a * b.
func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
mh, ml := bits.Mul64(a, uint64(b))
lo = ml & maskLow51Bits
hi = (mh << 13) | (ml >> 51)
return
}
// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
func (v *Element) Pow22523(x *Element) *Element {
var t0, t1, t2 Element
t0.Square(x) // x^2
t1.Square(&t0) // x^4
t1.Square(&t1) // x^8
t1.Multiply(x, &t1) // x^9
t0.Multiply(&t0, &t1) // x^11
t0.Square(&t0) // x^22
t0.Multiply(&t1, &t0) // x^31
t1.Square(&t0) // x^62
for i := 1; i < 5; i++ { // x^992
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
t1.Square(&t0) // 2^11 - 2
for i := 1; i < 10; i++ { // 2^20 - 2^10
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^20 - 1
t2.Square(&t1) // 2^21 - 2
for i := 1; i < 20; i++ { // 2^40 - 2^20
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^40 - 1
t1.Square(&t1) // 2^41 - 2
for i := 1; i < 10; i++ { // 2^50 - 2^10
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^50 - 1
t1.Square(&t0) // 2^51 - 2
for i := 1; i < 50; i++ { // 2^100 - 2^50
t1.Square(&t1)
}
t1.Multiply(&t1, &t0) // 2^100 - 1
t2.Square(&t1) // 2^101 - 2
for i := 1; i < 100; i++ { // 2^200 - 2^100
t2.Square(&t2)
}
t1.Multiply(&t2, &t1) // 2^200 - 1
t1.Square(&t1) // 2^201 - 2
for i := 1; i < 50; i++ { // 2^250 - 2^50
t1.Square(&t1)
}
t0.Multiply(&t1, &t0) // 2^250 - 1
t0.Square(&t0) // 2^251 - 2
t0.Square(&t0) // 2^252 - 4
return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
}
// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
var sqrtM1 = &Element{1718705420411056, 234908883556509,
2233514472574048, 2117202627021982, 765476049583133}
// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
//
// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
// and returns r and 0.
func (r *Element) SqrtRatio(u, v *Element) (rr *Element, wasSquare int) {
var a, b Element
// r = (u * v3) * (u * v7)^((p-5)/8)
v2 := a.Square(v)
uv3 := b.Multiply(u, b.Multiply(v2, v))
uv7 := a.Multiply(uv3, a.Square(v2))
r.Multiply(uv3, r.Pow22523(uv7))
check := a.Multiply(v, a.Square(r)) // check = v * r^2
uNeg := b.Negate(u)
correctSignSqrt := check.Equal(u)
flippedSignSqrt := check.Equal(uNeg)
flippedSignSqrtI := check.Equal(uNeg.Multiply(uNeg, sqrtM1))
rPrime := b.Multiply(r, sqrtM1) // r_prime = SQRT_M1 * r
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
r.Absolute(r) // Choose the nonnegative square root.
return r, correctSignSqrt | flippedSignSqrt
}

@ -0,0 +1,13 @@
// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
// +build amd64,gc,!purego
package field
// feMul sets out = a * b. It works like feMulGeneric.
//go:noescape
func feMul(out *Element, a *Element, b *Element)
// feSquare sets out = a * a. It works like feSquareGeneric.
//go:noescape
func feSquare(out *Element, a *Element)

@ -0,0 +1,12 @@
// Copyright (c) 2019 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.
//go:build !amd64 || !gc || purego
// +build !amd64 !gc purego
package field
func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
func feSquare(v, x *Element) { feSquareGeneric(v, x) }

@ -0,0 +1,16 @@
// Copyright (c) 2020 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.
//go:build arm64 && gc && !purego
// +build arm64,gc,!purego
package field
//go:noescape
func carryPropagate(v *Element)
func (v *Element) carryPropagate() *Element {
carryPropagate(v)
return v
}

@ -0,0 +1,12 @@
// Copyright (c) 2021 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.
//go:build !arm64 || !gc || purego
// +build !arm64 !gc purego
package field
func (v *Element) carryPropagate() *Element {
return v.carryPropagateGeneric()
}

@ -0,0 +1,264 @@
// Copyright (c) 2017 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 field
import "math/bits"
// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
// bits.Mul64 and bits.Add64 intrinsics.
type uint128 struct {
lo, hi uint64
}
// mul64 returns a * b.
func mul64(a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
return uint128{lo, hi}
}
// addMul64 returns v + a * b.
func addMul64(v uint128, a, b uint64) uint128 {
hi, lo := bits.Mul64(a, b)
lo, c := bits.Add64(lo, v.lo, 0)
hi, _ = bits.Add64(hi, v.hi, c)
return uint128{lo, hi}
}
// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
func shiftRightBy51(a uint128) uint64 {
return (a.hi << (64 - 51)) | (a.lo >> 51)
}
func feMulGeneric(v, a, b *Element) {
a0 := a.l0
a1 := a.l1
a2 := a.l2
a3 := a.l3
a4 := a.l4
b0 := b.l0
b1 := b.l1
b2 := b.l2
b3 := b.l3
b4 := b.l4
// Limb multiplication works like pen-and-paper columnar multiplication, but
// with 51-bit limbs instead of digits.
//
// a4 a3 a2 a1 a0 x
// b4 b3 b2 b1 b0 =
// ------------------------
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a4b1 a3b1 a2b1 a1b1 a0b1 +
// a4b2 a3b2 a2b2 a1b2 a0b2 +
// a4b3 a3b3 a2b3 a1b3 a0b3 +
// a4b4 a3b4 a2b4 a1b4 a0b4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
// reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
// r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
//
// Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute r5: whenever the result of a multiplication
// belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
//
// a4b0 a3b0 a2b0 a1b0 a0b0 +
// a3b1 a2b1 a1b1 a0b1 19×a4b1 +
// a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
// a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
// a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// Finally we add up the columns into wide, overlapping limbs.
a1_19 := a1 * 19
a2_19 := a2 * 19
a3_19 := a3 * 19
a4_19 := a4 * 19
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
r0 := mul64(a0, b0)
r0 = addMul64(r0, a1_19, b4)
r0 = addMul64(r0, a2_19, b3)
r0 = addMul64(r0, a3_19, b2)
r0 = addMul64(r0, a4_19, b1)
// r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
r1 := mul64(a0, b1)
r1 = addMul64(r1, a1, b0)
r1 = addMul64(r1, a2_19, b4)
r1 = addMul64(r1, a3_19, b3)
r1 = addMul64(r1, a4_19, b2)
// r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
r2 := mul64(a0, b2)
r2 = addMul64(r2, a1, b1)
r2 = addMul64(r2, a2, b0)
r2 = addMul64(r2, a3_19, b4)
r2 = addMul64(r2, a4_19, b3)
// r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
r3 := mul64(a0, b3)
r3 = addMul64(r3, a1, b2)
r3 = addMul64(r3, a2, b1)
r3 = addMul64(r3, a3, b0)
r3 = addMul64(r3, a4_19, b4)
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
r4 := mul64(a0, b4)
r4 = addMul64(r4, a1, b3)
r4 = addMul64(r4, a2, b2)
r4 = addMul64(r4, a3, b1)
r4 = addMul64(r4, a4, b0)
// After the multiplication, we need to reduce (carry) the five coefficients
// to obtain a result with limbs that are at most slightly larger than 2⁵¹,
// to respect the Element invariant.
//
// Overall, the reduction works the same as carryPropagate, except with
// wider inputs: we take the carry for each coefficient by shifting it right
// by 51, and add it to the limb above it. The top carry is multiplied by 19
// according to the reduction identity and added to the lowest limb.
//
// The largest coefficient (r0) will be at most 111 bits, which guarantees
// that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
//
// r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
// r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
// r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
// r0 < 2⁷ × 2⁵² × 2⁵²
// r0 < 2¹¹¹
//
// Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
// 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
// allows us to easily apply the reduction identity.
//
// r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
// r4 < 5 × 2⁵² × 2⁵²
// r4 < 2¹⁰⁷
//
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
// Now all coefficients fit into 64-bit registers but are still too large to
// be passed around as a Element. We therefore do one last carry chain,
// where the carries will be small enough to fit in the wiggle room above 2⁵¹.
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
func feSquareGeneric(v, a *Element) {
l0 := a.l0
l1 := a.l1
l2 := a.l2
l3 := a.l3
l4 := a.l4
// Squaring works precisely like multiplication above, but thanks to its
// symmetry we get to group a few terms together.
//
// l4 l3 l2 l1 l0 x
// l4 l3 l2 l1 l0 =
// ------------------------
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l4l1 l3l1 l2l1 l1l1 l0l1 +
// l4l2 l3l2 l2l2 l1l2 l0l2 +
// l4l3 l3l3 l2l3 l1l3 l0l3 +
// l4l4 l3l4 l2l4 l1l4 l0l4 =
// ----------------------------------------------
// r8 r7 r6 r5 r4 r3 r2 r1 r0
//
// l4l0 l3l0 l2l0 l1l0 l0l0 +
// l3l1 l2l1 l1l1 l0l1 19×l4l1 +
// l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
// l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
// l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
// --------------------------------------
// r4 r3 r2 r1 r0
//
// With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
// only three Mul64 and four Add64, instead of five and eight.
l0_2 := l0 * 2
l1_2 := l1 * 2
l1_38 := l1 * 38
l2_38 := l2 * 38
l3_38 := l3 * 38
l3_19 := l3 * 19
l4_19 := l4 * 19
// r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
r0 := mul64(l0, l0)
r0 = addMul64(r0, l1_38, l4)
r0 = addMul64(r0, l2_38, l3)
// r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
r1 := mul64(l0_2, l1)
r1 = addMul64(r1, l2_38, l4)
r1 = addMul64(r1, l3_19, l3)
// r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
r2 := mul64(l0_2, l2)
r2 = addMul64(r2, l1, l1)
r2 = addMul64(r2, l3_38, l4)
// r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
r3 := mul64(l0_2, l3)
r3 = addMul64(r3, l1_2, l2)
r3 = addMul64(r3, l4_19, l4)
// r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
r4 := mul64(l0_2, l4)
r4 = addMul64(r4, l1_2, l3)
r4 = addMul64(r4, l2, l2)
c0 := shiftRightBy51(r0)
c1 := shiftRightBy51(r1)
c2 := shiftRightBy51(r2)
c3 := shiftRightBy51(r3)
c4 := shiftRightBy51(r4)
rr0 := r0.lo&maskLow51Bits + c4*19
rr1 := r1.lo&maskLow51Bits + c0
rr2 := r2.lo&maskLow51Bits + c1
rr3 := r3.lo&maskLow51Bits + c2
rr4 := r4.lo&maskLow51Bits + c3
*v = Element{rr0, rr1, rr2, rr3, rr4}
v.carryPropagate()
}
// carryPropagate brings the limbs below 52 bits by applying the reduction
// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry. TODO inline
func (v *Element) carryPropagateGeneric() *Element {
c0 := v.l0 >> 51
c1 := v.l1 >> 51
c2 := v.l2 >> 51
c3 := v.l3 >> 51
c4 := v.l4 >> 51
v.l0 = v.l0&maskLow51Bits + c4*19
v.l1 = v.l1&maskLow51Bits + c0
v.l2 = v.l2&maskLow51Bits + c1
v.l3 = v.l3&maskLow51Bits + c2
v.l4 = v.l4&maskLow51Bits + c3
return v
}

@ -0,0 +1,71 @@
// Copyright 2019 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 ed25519 implements the Ed25519 signature algorithm. See
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
//
// Beginning with Go 1.13, the functionality of this package was moved to the
// standard library as crypto/ed25519. This package only acts as a compatibility
// wrapper.
package ed25519
import (
"crypto/ed25519"
"io"
)
const (
// PublicKeySize is the size, in bytes, of public keys as used in this package.
PublicKeySize = 32
// PrivateKeySize is the size, in bytes, of private keys as used in this package.
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
//
// This type is an alias for crypto/ed25519's PublicKey type.
// See the crypto/ed25519 package for the methods on this type.
type PublicKey = ed25519.PublicKey
// PrivateKey is the type of Ed25519 private keys. It implements crypto.Signer.
//
// This type is an alias for crypto/ed25519's PrivateKey type.
// See the crypto/ed25519 package for the methods on this type.
type PrivateKey = ed25519.PrivateKey
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
return ed25519.GenerateKey(rand)
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
return ed25519.NewKeyFromSeed(seed)
}
// Sign signs the message with privateKey and returns a signature. It will
// panic if len(privateKey) is not PrivateKeySize.
func Sign(privateKey PrivateKey, message []byte) []byte {
return ed25519.Sign(privateKey, message)
}
// Verify reports whether sig is a valid signature of message by publicKey. It
// will panic if len(publicKey) is not PublicKeySize.
func Verify(publicKey PublicKey, message, sig []byte) bool {
return ed25519.Verify(publicKey, message, sig)
}

@ -0,0 +1,40 @@
// Copyright 2019 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.
//go:build !go1.13
// +build !go1.13
package poly1305
// Generic fallbacks for the math/bits intrinsics, copied from
// src/math/bits/bits.go. They were added in Go 1.12, but Add64 and Sum64 had
// variable time fallbacks until Go 1.13.
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
sum = x + y + carry
carryOut = ((x & y) | ((x | y) &^ sum)) >> 63
return
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
diff = x - y - borrow
borrowOut = ((^x & y) | (^(x ^ y) & diff)) >> 63
return
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
const mask32 = 1<<32 - 1
x0 := x & mask32
x1 := x >> 32
y0 := y & mask32
y1 := y >> 32
w0 := x0 * y0
t := x1*y0 + w0>>32
w1 := t & mask32
w2 := t >> 32
w1 += x0 * y1
hi = x1*y1 + w2 + w1>>32
lo = x * y
return
}

@ -0,0 +1,22 @@
// Copyright 2019 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.
//go:build go1.13
// +build go1.13
package poly1305
import "math/bits"
func bitsAdd64(x, y, carry uint64) (sum, carryOut uint64) {
return bits.Add64(x, y, carry)
}
func bitsSub64(x, y, borrow uint64) (diff, borrowOut uint64) {
return bits.Sub64(x, y, borrow)
}
func bitsMul64(x, y uint64) (hi, lo uint64) {
return bits.Mul64(x, y)
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save