Merge pull request #262 from OktopUSP/dev

CWMP methods + docs + initial wifi and USP bulk data + update go dependencies
This commit is contained in:
Leandro Antônio Farias Machado 2024-05-30 14:09:49 -03:00 committed by GitHub
commit 128090ad9e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
141 changed files with 10860 additions and 4474 deletions

View File

@ -20,36 +20,20 @@ This repository aims to promote the development of a multi-vendor management pla
<p>If you'd like to know how to donate above <a href="https://github.com/sponsors/leandrofars">Github Sponsors</a> values, start a partnership or somehow to contribute to the project, email <a href="">leandro@oktopus.app.br</a>, every contribution is welcome, and the resources will help the project to move on. Also, if your company uses this project and you'd like your logo to appear up here, contact us.
--------------------------------------------------------------------------------------------------------------------------------------------------------
<ul>
<li>
<h4>💼 Commercial Support:</h4>
<a href="https://oktopus.app.br/controller#offer"> Pricing Plans </a>
<p>
Our solution has an open-source software license, meaning you can modify/study the code and use it for free. You can perform all the configurations, allocate servers, and set it up on your network with the classic "do it yourself" approach, or save time and money: contact us for a quote and get commercial support.
</p>
<ul>
<li>
Software customization according to your needs and preferences
</li>
<li>
Full support to your team
</li>
<li>
Affordable prices for companies of all sizes
</li>
<li>
Trust and assistance from experts
</li>
<li>
Complete solution for production environments, from the server provisionning to devices connection
</li>
</ul>
<p>Contact <a href="">leandro@oktopus.app.br</a> via email and get a quote.</p>
</li>
</ul>
--------------------------------------------------------------------------------------------------------------------------------------------------------
<h1>Controller</h1>
That's Oktopus Core, I's responsable for the devices management. Made by different microservices that can be run indepently and work together to provide the best experience for the user and make available different options for device connetion. Below here you will find some helpfull information about how the software works, the parts of it, the architecture and infrastructure.
<ul><li><h4>Infrastructure:</h4></li></ul>
@ -76,6 +60,9 @@ user@user-laptop:~/oktopus/deploy/compose$ COMPOSE_PROFILES=nats,controller,cwmp
Oktopus deployment in <u><b>Kubernetes</b></u> still is in beta phase: <a href="https://github.com/OktopUSP/oktopus/blob/main/deploy/kubernetes/README.md"> Instructions for Kubernetes deployment</a><p></p>
UI will open at port 3000:
<img src="https://github.com/OktopUSP/oktopus/assets/83298718/65f7c5b9-c08d-479a-8a13-fdfc634b5ca2"/>
<h2>Agent</h2>
Agent is a piece of software taht runs on the CPE or IoT device and is responsable for connecting it to the Controller (Oktopus) through CWMP and/or USP.
</li>
<li>
@ -89,8 +76,6 @@ Oktopus deployment in <u><b>Kubernetes</b></u> still is in beta phase: <a href="
</li>
</ul>
--------------------------------------------------------------------------------------------------------------------------------------------------------
<ul>
<li>
<h4>Roadmap:</h4>
@ -178,8 +163,6 @@ Seeking to solve the challenges mentioned above, providers and manufacturers tog
</li>
</ul>
--------------------------------------------------------------------------------------------------------------------------------------------------------
<ul>
<li>
<h4>Topology:</h4>

View File

@ -20,6 +20,7 @@ func main() {
natsActions.Publish,
natsActions.Subscribe,
h,
&c.Acs,
)
b.StartBridge()

View File

@ -5,16 +5,15 @@ go 1.22.2
require (
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/nats-io/nats.go v1.34.1
github.com/nats-io/nats.go v1.35.0
github.com/oleiade/lane v1.0.1
golang.org/x/net v0.24.0
)
require (
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

View File

@ -4,8 +4,12 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4=
github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk=
github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@ -14,9 +18,13 @@ github.com/oleiade/lane v1.0.1 h1:hXofkn7GEOubzTwNpeL9MaNy8WxolCYb9cInAIeqShU=
github.com/oleiade/lane v1.0.1/go.mod h1:IyTkraa4maLfjq/GmHR+Dxb4kCMtEGeb+qmhlrQ5Mk4=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

View File

@ -5,9 +5,12 @@ import (
"crypto/rand"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
type myjar struct {
@ -22,51 +25,81 @@ func (p *myjar) Cookies(u *url.URL) []*http.Cookie {
return p.jar[u.Host]
}
func Auth(username string, password string, uri string) (bool, error) {
client := &http.Client{}
func Auth(username string, password string, url string) (bool, error) {
client := &http.Client{Timeout: time.Second * 1}
jar := &myjar{}
jar.jar = make(map[string][]*http.Cookie)
client.Jar = jar
var req *http.Request
var resp *http.Response
var err error
req, err = http.NewRequest("GET", uri, nil)
req, err = http.NewRequest("GET", url, nil)
if err != nil {
return false, err
}
req.Header.Set("Connection", "keep-alive")
req.Header.Del("Accept-Encoding")
resp, err = client.Do(req)
if err != nil {
return false, err
}
// if resp.StatusCode == 401 {
// var authorization map[string]string = DigestAuthParams(resp)
// realmHeader := authorization["realm"]
// qopHeader := authorization["qop"]
// nonceHeader := authorization["nonce"]
// opaqueHeader := authorization["opaque"]
// realm := realmHeader
// // A1
// h := md5.New()
// A1 := fmt.Sprintf("%s:%s:%s", username, realm, password)
// io.WriteString(h, A1)
// HA1 := fmt.Sprintf("%x", h.Sum(nil))
// // A2
// h = md5.New()
// A2 := fmt.Sprintf("GET:%s", "/auth")
// io.WriteString(h, A2)
// HA2 := fmt.Sprintf("%x", h.Sum(nil))
defer resp.Body.Close()
io.Copy(ioutil.Discard, resp.Body)
// // response
// cnonce := RandomKey()
// response := H(strings.Join([]string{HA1, nonceHeader, "00000001", cnonce, qopHeader, HA2}, ":"))
if resp.StatusCode == 401 {
var authorization map[string]string = DigestAuthParams(resp)
realmHeader := authorization["realm"]
qopHeader := authorization["qop"]
nonceHeader := authorization["nonce"]
opaqueHeader := authorization["opaque"]
realm := realmHeader
// // now make header
// AuthHeader := fmt.Sprintf(`Digest username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=00000001, qop=%s, response="%s", opaque="%s", algorithm=MD5`,
// username, realmHeader, nonceHeader, "/auth", cnonce, qopHeader, response, opaqueHeader)
// req.Header.Set("Authorization", AuthHeader)
// resp, err = client.Do(req)
// } else {
// return false, fmt.Errorf("response status code should have been 401, it was %v", resp.StatusCode)
// }
return resp.StatusCode == 200, err
uri := "/"
if surl := strings.Split(url, "/"); len(surl) == 4 {
uri = "/" + surl[3]
}
// A1
h := md5.New()
A1 := fmt.Sprintf("%s:%s:%s", username, realm, password)
io.WriteString(h, A1)
HA1 := fmt.Sprintf("%x", h.Sum(nil))
// A2
h = md5.New()
A2 := fmt.Sprintf("GET:%s", uri)
io.WriteString(h, A2)
HA2 := fmt.Sprintf("%x", h.Sum(nil))
// response
cnonce := RandomKey()
response := H(strings.Join([]string{HA1, nonceHeader, "00000001", cnonce, qopHeader, HA2}, ":"))
// now make header
AuthHeader := fmt.Sprintf(`Digest username="%s",realm="%s",nonce="%s",uri="%s",qop=%s,nc=00000001,cnonce="%s",response="%s",opaque="%s",algorithm=MD5`,
username, realmHeader, nonceHeader, uri, qopHeader, cnonce, response, opaqueHeader)
req.Header.Set("Authorization", AuthHeader)
resp, err = client.Do(req)
if err != nil {
return false, err
}
io.Copy(ioutil.Discard, resp.Body)
if resp.StatusCode == 401 {
return false, fmt.Errorf("Authentication error!")
}
return true, err
} else if resp.StatusCode == 200 {
return true, err
}
return false, fmt.Errorf("Response status code not expected")
}
/*
@ -90,6 +123,7 @@ func DigestAuthParams(r *http.Response) map[string]string {
}
return result
}
func RandomKey() string {
k := make([]byte, 12)
for bytes := 0; bytes < len(k); {

View File

@ -4,6 +4,7 @@ import (
"encoding/json"
"log"
"net/http"
"oktopUSP/backend/services/acs/internal/config"
"oktopUSP/backend/services/acs/internal/server/handler"
"strings"
"time"
@ -17,6 +18,7 @@ type Bridge struct {
sub func(string, func(*nats.Msg)) error
cpes map[string]handler.CPE
h *handler.Handler
conf *config.Acs
}
type msgAnswer struct {
@ -24,24 +26,25 @@ type msgAnswer struct {
Msg any
}
const DEVICE_ANSWER_TIMEOUT = 5 * time.Second
func NewBridge(
pub func(string, []byte) error,
sub func(string, func(*nats.Msg)) error,
h *handler.Handler,
c *config.Acs,
) *Bridge {
return &Bridge{
pub: pub,
sub: sub,
cpes: h.Cpes,
h: h,
conf: c,
}
}
func (b *Bridge) StartBridge() {
b.sub(handler.NATS_CWMP_ADAPTER_SUBJECT_PREFIX+"*.api", func(msg *nats.Msg) {
log.Printf("Received message: %s", string(msg.Data))
//log.Printf("Received message: %s", string(msg.Data))
log.Printf("Subject: %s", msg.Subject)
log.Printf("Reply: %s", msg.Reply)
@ -53,6 +56,8 @@ func (b *Bridge) StartBridge() {
return
}
if cpe.Queue.Size() > 0 {
log.Println("Queue size: ", cpe.Queue.Size())
log.Println("Queue data: ", cpe.Queue)
log.Printf("Device %s is busy", device)
respondMsg(msg.Respond, http.StatusConflict, "Device is busy")
return
@ -65,6 +70,7 @@ func (b *Bridge) StartBridge() {
Id: uuid.NewString(),
CwmpMsg: msg.Data,
Callback: deviceAnswer,
Time: time.Now(),
})
err := b.h.ConnectionRequest(cpe)
@ -78,14 +84,19 @@ func (b *Bridge) StartBridge() {
//req := cpe.Queue.Dequeue().(handler.Request)
//cpe.Waiting = &req
defer cpe.Queue.Dequeue()
select {
case response := <-deviceAnswer:
log.Println("Received response from device: ", string(response))
if b.conf.DebugMode {
log.Printf("Received response from cpe: %s payload: %s ", cpe.SerialNumber, string(response))
}
respondMsg(msg.Respond, http.StatusOK, response)
case <-time.After(DEVICE_ANSWER_TIMEOUT):
case <-time.After(b.conf.DeviceAnswerTimeout):
log.Println("Device response timed out")
respondMsg(msg.Respond, http.StatusRequestTimeout, "Request timeout")
}
})
}

View File

@ -30,6 +30,9 @@ type Acs struct {
Password string
Route string
DebugMode bool
ConnReqUsername string
ConnReqPassword string
DeviceAnswerTimeout time.Duration
}
type Config struct {
@ -47,8 +50,11 @@ func NewConfig() *Config {
natsVerifyCertificates := flag.Bool("nats_verify_certificates", lookupEnvOrBool("NATS_VERIFY_CERTIFICATES", false), "verify validity of certificates from nats server")
acsPort := flag.String("acs_port", lookupEnvOrString("ACS_PORT", ":9292"), "port for acs server")
acsRoute := flag.String("acs_route", lookupEnvOrString("ACS_ROUTE", "/acs"), "route for acs server")
connReqUser := flag.String("connrq_user", lookupEnvOrString("CONN_RQ_USER", ""), "Connection Request Username")
connReqPasswd := flag.String("connrq_passwd", lookupEnvOrString("CONN_RQ_PASSWD", ""), "Connection Request Password")
acsKeepAliveInterval := flag.Int("acs_keep_alive_interval", lookupEnvOrInt("KEEP_ALIVE_INTERVAL", 300), "keep alive interval in seconds for acs server")
cwmpDebugMode := flag.Bool("debug_mode", lookupEnvOrBool("CWMP_DEBUG", false), "enable or disable cwmp logs in debug mode")
deviceAnswerTimeout := flag.Int("device_answer_timeout", lookupEnvOrInt("DEVICE_ANSWER_TIMEOUT", 10), "device answer timeout in seconds")
flHelp := flag.Bool("help", false, "Help")
/*
@ -77,8 +83,11 @@ func NewConfig() *Config {
Acs: Acs{
Port: *acsPort,
Route: *acsRoute,
KeepAliveInterval: time.Duration(*acsKeepAliveInterval),
KeepAliveInterval: time.Duration(*acsKeepAliveInterval) * time.Second,
DebugMode: *cwmpDebugMode,
ConnReqUsername: *connReqUser,
ConnReqPassword: *connReqPasswd,
DeviceAnswerTimeout: time.Duration(*deviceAnswerTimeout) * time.Second,
},
}
}

View File

@ -63,6 +63,11 @@ type GetParameterNamesResponse struct {
ParameterList []ParameterInfoStruct `xml:"Body>GetParameterNamesResponse>ParameterList>ParameterInfoStruct"`
}
type Fault struct {
FaultCode uint
FaultString string
}
type CWMPInform struct {
DeviceId DeviceID `xml:"Body>Inform>DeviceId"`
Events []EventStruct `xml:"Body>Inform>Event>EventStruct"`

View File

@ -1,7 +1,6 @@
package handler
import (
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
@ -69,7 +68,7 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
log.Println("New device: " + sn)
h.Cpes[sn] = CPE{
SerialNumber: sn,
LastConnection: time.Now().UTC(),
LastConnection: time.Now(),
SoftwareVersion: Inform.GetSoftwareVersion(),
HardwareVersion: Inform.GetHardwareVersion(),
ExternalIPAddress: addr,
@ -78,12 +77,11 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
Queue: lane.NewQueue(),
DataModel: Inform.GetDataModelType(),
}
go h.handleCpeStatus(sn)
h.pub(NATS_CWMP_SUBJECT_PREFIX+sn+".info", tmp)
}
obj := h.Cpes[sn]
cpe := &obj
cpe.LastConnection = time.Now().UTC()
cpe.LastConnection = time.Now()
log.Printf("Received an Inform from device %s withEventCodes %s", addr, Inform.GetEvents())
@ -91,8 +89,9 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
cookie := http.Cookie{Name: "oktopus", Value: sn, Expires: expiration}
http.SetCookie(w, &cookie)
data, _ := xml.Marshal(cwmp.InformResponse(envelope.Header.Id))
w.Write(data)
//data, _ := xml.Marshal(cwmp.InformResponse(envelope.Header.Id))
fmt.Fprintf(w, cwmp.InformResponse(envelope.Header.Id))
} else if messageType == "TransferComplete" {
} else if messageType == "GetRPC" {
@ -104,34 +103,27 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
}
if cpe.Waiting != nil {
log.Println("CPE was waiting for a response, now received something")
var e cwmp.SoapEnvelope
xml.Unmarshal([]byte(body), &e)
log.Println("Kind of envelope: ", e.KindOf())
if e.KindOf() == "GetParameterNamesResponse" {
// var envelope cwmp.GetParameterNamesResponse
// xml.Unmarshal([]byte(body), &envelope)
// msg := new(NatsSendMessage)
// msg.MsgType = "GetParameterNamesResponse"
// msg.Data, _ = json.Marshal(envelope)
log.Println("Receive GetParameterNamesResponse from CPE:", cpe.SerialNumber)
cpe.Waiting.Callback <- tmp
msgAnswer(cpe.Waiting.Callback, cpe.Waiting.Time, h.acsConfig.DeviceAnswerTimeout, tmp)
} else if e.KindOf() == "GetParameterValuesResponse" {
var envelope cwmp.GetParameterValuesResponse
xml.Unmarshal([]byte(body), &envelope)
msg := new(NatsSendMessage)
msg.MsgType = "GetParameterValuesResponse"
msg.Data, _ = json.Marshal(envelope)
cpe.Waiting.Callback <- tmp
log.Println("Receive GetParameterValuesResponse from CPE:", cpe.SerialNumber)
msgAnswer(cpe.Waiting.Callback, cpe.Waiting.Time, h.acsConfig.DeviceAnswerTimeout, tmp)
} else if e.KindOf() == "Fault" {
log.Println("Receive FaultResponse from CPE:", cpe.SerialNumber)
msgAnswer(cpe.Waiting.Callback, cpe.Waiting.Time, h.acsConfig.DeviceAnswerTimeout, tmp)
log.Println(body)
} else {
log.Println("Unknown message type")
cpe.Waiting.Callback <- tmp
log.Println("Envelope:", e)
msgAnswer(cpe.Waiting.Callback, cpe.Waiting.Time, h.acsConfig.DeviceAnswerTimeout, tmp)
}
cpe.Waiting = nil
} else {
@ -152,6 +144,7 @@ func (h *Handler) CwmpHandler(w http.ResponseWriter, r *http.Request) {
}
}
h.Cpes[cpe.SerialNumber] = cpe
log.Println("---End of CWMP Handler---")
}
func (h *Handler) ConnectionRequest(cpe CPE) error {
@ -160,9 +153,24 @@ func (h *Handler) ConnectionRequest(cpe CPE) error {
// log.Println("ConnectionRequestUsername: ", cpe.Username)
// log.Println("ConnectionRequestPassword: ", cpe.Password)
ok, err := auth.Auth("", "", cpe.ConnectionRequestURL)
ok, err := auth.Auth(h.acsConfig.ConnReqUsername, h.acsConfig.ConnReqPassword, cpe.ConnectionRequestURL)
if !ok {
cpe.Queue.Dequeue()
log.Println("Error while authenticating to CPE: ", err)
}
log.Println("<-- Successfully authenticated to CPE", cpe.SerialNumber)
return err
}
func msgAnswer(
callback chan []byte,
timeMsgWasSent time.Time,
timeOut time.Duration,
msgAnswer []byte,
) {
if time.Since(timeMsgWasSent) > timeOut {
log.Println("CPE took too long to answer the request, the message will be discarded")
} else {
callback <- msgAnswer
}
}

View File

@ -16,6 +16,7 @@ type Request struct {
User string
Password string
CwmpMsg []byte
Time time.Time
Callback chan []byte
}

View File

@ -5,14 +5,21 @@ import (
"time"
)
func (h *Handler) handleCpeStatus(cpe string) {
func (h *Handler) HandleCpeStatus() {
for {
for cpe := range h.Cpes {
if cpe == "" {
continue
}
log.Println("Checking CPE " + cpe + " status")
if time.Since(h.Cpes[cpe].LastConnection) > h.acsConfig.KeepAliveInterval {
log.Printf("LastConnection: %s, KeepAliveInterval: %s", h.Cpes[cpe].LastConnection, h.acsConfig.KeepAliveInterval)
log.Println("CPE", cpe, "is offline")
h.pub("cwmp.v1."+cpe+".status", []byte("0"))
delete(h.Cpes, cpe)
break
}
time.Sleep(h.acsConfig.KeepAliveInterval)
}
log.Println("CPE", cpe, "is offline")
h.pub("cwmp.v1."+cpe+".status", []byte("0"))
time.Sleep(10 * time.Second)
}
}

View File

@ -12,6 +12,8 @@ import (
func Run(c config.Acs, natsActions nats.NatsActions, h *handler.Handler) {
http.HandleFunc(c.Route, h.CwmpHandler)
go h.HandleCpeStatus()
log.Printf("ACS running at %s%s", c.Port, c.Route)
err := http.ListenAndServe(c.Port, nil)

1
backend/services/bulkdata/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.env.local

View File

View File

@ -0,0 +1,8 @@
FROM golang:1.22@sha256:82e07063a1ac3ee59e6f38b1222e32ce88469e4431ff6496cc40fb9a0fc18229 as builder
WORKDIR /app
COPY ../ .
RUN CGO_ENABLED=0 GOOS=linux go build -o bulkdata cmd/bulkdata/main.go
FROM alpine:3.14@sha256:0f2d5c38dd7a4f4f733e688e3a6733cb5ab1ac6e3cb4603a5dd564e5bfb80eed
COPY --from=builder /app/bulkdata /
ENTRYPOINT ["/bulkdata"]

View File

@ -0,0 +1,61 @@
.PHONY: help build push start stop release remove delete run logs bash
DOCKER_USER ?= oktopusp
DOCKER_APP ?= bulkdata
DOCKER_TAG ?= $(shell git log --format="%h" -n 1)
CONTAINER_SHELL ?= /bin/sh
.DEFAULT_GOAL := help
help:
@echo "Makefile arguments:"
@echo ""
@echo "DOCKER_USER - docker user to build image"
@echo "DOCKER_APP - docker image name"
@echo "DOCKER_TAG - docker image tag"
@echo "CONTAINER_SHELL - container shell e.g:'/bin/bash'"
@echo ""
@echo "Makefile commands:"
@echo ""
@echo "build - docker image build"
@echo "push - push docker iamge to registry"
@echo "run - create and start docker container with the image"
@echo "start - start existent docker container with the image"
@echo "stop - stop docker container running the image"
@echo "remove - remove docker container running the image"
@echo "delete - delete docker image"
@echo "logs - show logs of docker container"
@echo "bash - access container shell"
@echo "release - tag image as latest and push to registry"
build:
@docker build -t ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG} -f Dockerfile ../
run:
@docker run -d --name ${DOCKER_USER}-${DOCKER_APP} ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
stop:
@docker stop ${DOCKER_USER}-${DOCKER_APP}
remove: stop
@docker rm ${DOCKER_USER}-${DOCKER_APP}
delete:
@docker rmi ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
start:
@docker start ${DOCKER_USER}-${DOCKER_APP}
push:
@docker push ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
logs:
@docker logs -f ${DOCKER_USER}-${DOCKER_APP}
bash:
@docker exec -it ${DOCKER_USER}-${DOCKER_APP} ${CONTAINER_SHELL}
release: build
@docker push ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG}
@docker tag ${DOCKER_USER}/${DOCKER_APP}:${DOCKER_TAG} ${DOCKER_USER}/${DOCKER_APP}:latest
@docker push ${DOCKER_USER}/${DOCKER_APP}:latest

View File

@ -0,0 +1,29 @@
package main
import (
"log"
"os"
"os/signal"
"syscall"
"github.com/oktopUSP/backend/services/bulkdata/internal/api"
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
"github.com/oktopUSP/backend/services/bulkdata/internal/nats"
)
func main() {
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGINT)
c := config.NewConfig()
js, nc, kv := nats.StartNatsClient(c.Nats)
server := api.NewApi(c.RestApi, js, nc, kv)
server.StartApi()
<-done
log.Println("bulk data collector is saying adios ...")
}

View File

@ -0,0 +1,19 @@
module github.com/oktopUSP/backend/services/bulkdata
go 1.22.3
require (
github.com/gorilla/mux v1.8.1
github.com/joho/godotenv v1.5.1
github.com/nats-io/nats.go v1.34.1
github.com/rs/cors v1.11.0
)
require (
github.com/klauspost/compress v1.17.2 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

View File

@ -0,0 +1,20 @@
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4=
github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po=
github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=

View File

@ -0,0 +1,58 @@
package api
import (
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/oktopUSP/backend/services/bulkdata/internal/api/cors"
"github.com/oktopUSP/backend/services/bulkdata/internal/api/handler"
"github.com/oktopUSP/backend/services/bulkdata/internal/api/middleware"
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
)
type Api struct {
port string
handler handler.Handler
}
const REQUEST_TIMEOUT = time.Second * 30
func NewApi(c config.RestApi, js jetstream.JetStream, nc *nats.Conn, kv jetstream.KeyValue) Api {
return Api{
port: c.Port,
handler: handler.NewHandler(js, nc, kv),
}
}
func (a *Api) StartApi() {
r := mux.NewRouter()
r.HandleFunc("/healthcheck", a.handler.Healthcheck).Methods("GET")
r.HandleFunc("/", a.handler.Data).Methods("POST")
/* ----- Middleware for requests which requires user to be authenticated ---- */
r.Use(func(handler http.Handler) http.Handler {
return middleware.Middleware(handler)
})
/* -------------------------------------------------------------------------- */
corsOpts := cors.GetCorsConfig()
srv := &http.Server{
Addr: "0.0.0.0:" + a.port,
WriteTimeout: time.Second * 60,
ReadTimeout: time.Second * 60,
IdleTimeout: time.Second * 60,
Handler: corsOpts.Handler(r),
}
go func() {
if err := srv.ListenAndServe(); err != nil {
log.Println(err)
}
}()
log.Println("Running Bulk Data Collector HTTP Server at port", a.port)
}

View File

@ -0,0 +1,39 @@
package cors
import (
"log"
"net/http"
"os"
"strings"
"github.com/rs/cors"
)
func GetCorsConfig() cors.Cors {
allowedOrigins := getCorsEnvConfig()
log.Println("API CORS - AllowedOrigins:", allowedOrigins)
return *cors.New(cors.Options{
AllowedOrigins: allowedOrigins,
AllowedMethods: []string{
http.MethodGet,
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
http.MethodHead,
},
AllowedHeaders: []string{
"*", //or you can your header key values which you are using in your application
},
})
}
func getCorsEnvConfig() []string {
val, _ := os.LookupEnv("REST_API_CORS")
if val == "" {
return []string{"*"}
}
return strings.Split(val, ",")
}

View File

@ -0,0 +1,31 @@
package handler
import (
"encoding/json"
"log"
"net/http"
)
func (h *Handler) Data(w http.ResponseWriter, r *http.Request) {
oui := r.URL.Query().Get("oui")
pc := r.URL.Query().Get("pc")
sn := r.URL.Query().Get("sn")
eid := r.URL.Query().Get("eid")
log.Println("oui: ", oui)
log.Println("pc: ", pc)
log.Println("sn: ", sn)
log.Println("eid: ", eid)
var body map[string]interface{}
err := json.NewDecoder(r.Body).Decode(&body)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Println("Body: ", body)
}

View File

@ -0,0 +1,23 @@
package handler
import (
"context"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
type Handler struct {
js jetstream.JetStream
nc *nats.Conn
kv jetstream.KeyValue
ctx context.Context
}
func NewHandler(js jetstream.JetStream, nc *nats.Conn, kv jetstream.KeyValue) Handler {
return Handler{
js: js,
nc: nc,
kv: kv,
}
}

View File

@ -0,0 +1,7 @@
package handler
import "net/http"
func (h *Handler) Healthcheck(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("I'm Alive"))
}

View File

@ -0,0 +1,26 @@
package middleware
import (
"net/http"
)
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
// tokenString := r.Header.Get("Authorization")
// if tokenString == "" {
// w.WriteHeader(http.StatusUnauthorized)
// return
// }
// email, err := auth.ValidateToken(tokenString)
// if err != nil {
// w.WriteHeader(http.StatusUnauthorized)
// return
// }
//ctx := context.WithValue(r.Context(), "email", email)
next.ServeHTTP(w, r.WithContext(r.Context()))
},
)
}

View File

@ -0,0 +1,105 @@
package config
import (
"context"
"flag"
"log"
"os"
"strconv"
"github.com/joho/godotenv"
)
const LOCAL_ENV = ".env.local"
type Nats struct {
Url string
Name string
VerifyCertificates bool
Ctx context.Context
}
type RestApi struct {
Port string
Ctx context.Context
}
type Config struct {
RestApi RestApi
Nats Nats
}
func NewConfig() *Config {
loadEnvVariables()
log.SetFlags(log.LstdFlags | log.Lshortfile)
natsUrl := flag.String("nats_url", lookupEnvOrString("NATS_URL", "nats://localhost:4222"), "url for nats server")
natsName := flag.String("nats_name", lookupEnvOrString("NATS_NAME", "adapter"), "name for nats client")
natsVerifyCertificates := flag.Bool("nats_verify_certificates", lookupEnvOrBool("NATS_VERIFY_CERTIFICATES", false), "verify validity of certificates from nats server")
flApiPort := flag.String("api_port", lookupEnvOrString("REST_API_PORT", "4000"), "Rest api port")
flHelp := flag.Bool("help", false, "Help")
/*
App variables priority:
1º - Flag through command line.
2º - Env variables.
3º - Default flag value.
*/
flag.Parse()
if *flHelp {
flag.Usage()
os.Exit(0)
}
ctx := context.TODO()
return &Config{
RestApi: RestApi{
Port: *flApiPort,
Ctx: ctx,
},
Nats: Nats{
Url: *natsUrl,
Name: *natsName,
VerifyCertificates: *natsVerifyCertificates,
Ctx: ctx,
},
}
}
func loadEnvVariables() {
err := godotenv.Load()
if _, err := os.Stat(LOCAL_ENV); err == nil {
_ = godotenv.Overload(LOCAL_ENV)
log.Printf("Loaded variables from '%s'", LOCAL_ENV)
return
}
if err != nil {
log.Println("Error to load environment variables:", err)
} else {
log.Println("Loaded variables from '.env'")
}
}
func lookupEnvOrString(key string, defaultVal string) string {
if val, _ := os.LookupEnv(key); val != "" {
return val
}
return defaultVal
}
func lookupEnvOrBool(key string, defaultVal bool) bool {
if val, _ := os.LookupEnv(key); val != "" {
v, err := strconv.ParseBool(val)
if err != nil {
log.Fatalf("LookupEnvOrBool[%s]: %v", key, err)
}
return v
}
return defaultVal
}

View File

@ -0,0 +1,74 @@
package nats
import (
"log"
"time"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
"github.com/oktopUSP/backend/services/bulkdata/internal/config"
)
const (
BUCKET_NAME = "devices-auth"
BUCKET_DESCRIPTION = "Devices authentication"
)
func StartNatsClient(c config.Nats) (jetstream.JetStream, *nats.Conn, jetstream.KeyValue) {
var (
nc *nats.Conn
err error
)
opts := defineOptions(c)
log.Printf("Connecting to NATS server %s", c.Url)
for {
nc, err = nats.Connect(c.Url, opts...)
if err != nil {
time.Sleep(5 * time.Second)
continue
}
break
}
log.Printf("Successfully connected to NATS server %s", c.Url)
js, err := jetstream.New(nc)
if err != nil {
log.Fatalf("Failed to create JetStream client: %v", err)
}
kv, err := js.CreateOrUpdateKeyValue(c.Ctx, jetstream.KeyValueConfig{
Bucket: BUCKET_NAME,
Description: BUCKET_DESCRIPTION,
})
if err != nil {
log.Fatalf("Failed to create KeyValue store: %v", err)
}
return js, nc, kv
}
func defineOptions(c config.Nats) []nats.Option {
var opts []nats.Option
opts = append(opts, nats.Name(c.Name))
opts = append(opts, nats.MaxReconnects(-1))
opts = append(opts, nats.ReconnectWait(5*time.Second))
opts = append(opts, nats.DisconnectErrHandler(func(nc *nats.Conn, err error) {
log.Printf("Got disconnected! Reason: %q\n", err)
}))
opts = append(opts, nats.ReconnectHandler(func(nc *nats.Conn) {
log.Printf("Got reconnected to %v!\n", nc.ConnectedUrl())
}))
opts = append(opts, nats.ClosedHandler(func(nc *nats.Conn) {
log.Printf("Connection closed. Reason: %q\n", nc.LastError())
}))
if c.VerifyCertificates {
opts = append(opts, nats.RootCAs())
}
return opts
}

View File

@ -57,18 +57,22 @@ func (a *Api) StartApi() {
authentication.HandleFunc("/admin/exists", a.adminUserExists).Methods("GET")
iot := r.PathPrefix("/api/device").Subrouter()
iot.HandleFunc("/auth", a.deviceAuth).Methods("GET", "POST", "DELETE")
iot.HandleFunc("/cwmp/{sn}/getParameterNames", a.cwmpGetParameterNamesMsg).Methods("GET", "PUT", "DELETE")
iot.HandleFunc("/cwmp/{sn}/getParameterNames", a.cwmpGetParameterNamesMsg).Methods("PUT")
iot.HandleFunc("/cwmp/{sn}/getParameterValues", a.cwmpGetParameterValuesMsg).Methods("PUT")
iot.HandleFunc("/cwmp/{sn}/getParameterAttributes", a.cwmpGetParameterAttributesMsg).Methods("PUT")
iot.HandleFunc("/cwmp/{sn}/setParameterValues", a.cwmpSetParameterValuesMsg).Methods("PUT")
iot.HandleFunc("", a.retrieveDevices).Methods("GET")
iot.HandleFunc("/{id}", a.retrieveDevices).Methods("GET")
iot.HandleFunc("/{sn}/{mtp}/get", a.deviceGetMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/add", a.deviceCreateMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/del", a.deviceDeleteMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/set", a.deviceUpdateMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/notify", a.deviceNotifyMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/parameters", a.deviceGetSupportedParametersMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/instances", a.deviceGetParameterInstances).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/operate", a.deviceOperateMsg).Methods("PUT")
iot.HandleFunc("/{sn}/{mtp}/fw_update", a.deviceFwUpdate).Methods("PUT")
// iot.HandleFunc("/{sn}/{mtp}/wifi", a.deviceWifi).Methods("PUT", "GET")
iot.HandleFunc("/{sn}/wifi", a.deviceWifi).Methods("PUT", "GET")
// mtp := r.PathPrefix("/api/mtp").Subrouter()
// mtp.HandleFunc("", a.mtpInfo).Methods("GET")
dash := r.PathPrefix("/api/info").Subrouter()

View File

@ -8,8 +8,9 @@ import (
"github.com/leandrofars/oktopus/internal/bridge"
"github.com/leandrofars/oktopus/internal/cwmp"
"github.com/leandrofars/oktopus/internal/nats"
n "github.com/leandrofars/oktopus/internal/nats"
"github.com/leandrofars/oktopus/internal/utils"
"github.com/nats-io/nats.go"
)
func (a *Api) cwmpGetParameterNamesMsg(w http.ResponseWriter, r *http.Request) {
@ -22,27 +23,91 @@ func (a *Api) cwmpGetParameterNamesMsg(w http.ResponseWriter, r *http.Request) {
return
}
data, err := bridge.NatsCwmpInteraction(
nats.NATS_CWMP_ADAPTER_SUBJECT_PREFIX+sn+".api",
payload,
w,
a.nc,
)
data, _, err := cwmpInteraction[cwmp.GetParameterNamesResponse](sn, payload, w, a.nc)
if err != nil {
return
}
var response cwmp.GetParameterNamesResponse
w.Write(data)
}
func (a *Api) cwmpGetParameterAttributesMsg(w http.ResponseWriter, r *http.Request) {
sn := getSerialNumberFromRequest(r)
payload, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall(err.Error()))
return
}
data, _, err := cwmpInteraction[cwmp.GetParameterAttributesResponse](sn, payload, w, a.nc)
if err != nil {
return
}
w.Write(data)
}
func (a *Api) cwmpGetParameterValuesMsg(w http.ResponseWriter, r *http.Request) {
sn := getSerialNumberFromRequest(r)
payload, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall(err.Error()))
return
}
data, _, err := cwmpInteraction[cwmp.GetParameterValuesResponse](sn, payload, w, a.nc)
if err != nil {
return
}
w.Write(data)
}
func (a *Api) cwmpSetParameterValuesMsg(w http.ResponseWriter, r *http.Request) {
sn := getSerialNumberFromRequest(r)
payload, err := io.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall(err.Error()))
return
}
data, _, err := cwmpInteraction[cwmp.SetParameterValuesResponse](sn, payload, w, a.nc)
if err != nil {
return
}
w.Write(data)
}
func cwmpInteraction[T cwmp.SetParameterValuesResponse | cwmp.GetParameterAttributesResponse | cwmp.GetParameterNamesResponse | cwmp.GetParameterValuesResponse](
sn string, payload []byte, w http.ResponseWriter, nc *nats.Conn,
) ([]byte, T, error) {
var response T
data, err := bridge.NatsCwmpInteraction(
n.NATS_CWMP_ADAPTER_SUBJECT_PREFIX+sn+".api",
payload,
w,
nc,
)
if err != nil {
return data, response, err
}
err = xml.Unmarshal(data, &response)
if err != nil {
err = json.Unmarshal(data, &response)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall(err))
return
}
return
}
w.Write(data)
return data, response, err
}

View File

@ -1,8 +1,10 @@
package api
import (
"log"
"net/http"
"github.com/google/uuid"
"github.com/leandrofars/oktopus/internal/bridge"
local "github.com/leandrofars/oktopus/internal/nats"
"github.com/leandrofars/oktopus/internal/usp/usp_msg"
@ -165,6 +167,44 @@ func (a *Api) deviceOperateMsg(w http.ResponseWriter, r *http.Request) {
}
}
func (a *Api) deviceNotifyMsg(w http.ResponseWriter, r *http.Request) {
sn := getSerialNumberFromRequest(r)
mtp, err := getMtpFromRequest(r, w)
if err != nil {
return
}
if mtp == "" {
var ok bool
mtp, ok = deviceStateOK(w, a.nc, sn)
if !ok {
return
}
}
// var notify usp_msg.Notify
notify := usp_msg.Notify{
SubscriptionId: uuid.NewString(),
SendResp: true,
Notification: &usp_msg.Notify_Event_{
Event: &usp_msg.Notify_Event{
EventName: "Push!",
ObjPath: "Device.BulkData.Profile.1.",
},
},
}
log.Printf("Notify %s:", notify.String())
msg := usp_utils.NewNotifyMsg(notify)
err = sendUspMsg(msg, sn, w, a.nc, mtp)
if err != nil {
return
}
}
func (a *Api) deviceUpdateMsg(w http.ResponseWriter, r *http.Request) {
sn := getSerialNumberFromRequest(r)

View File

@ -1,5 +1,32 @@
package api
import (
"log"
"net/http"
"strings"
"github.com/gorilla/mux"
"github.com/leandrofars/oktopus/internal/cwmp"
"github.com/leandrofars/oktopus/internal/entity"
"github.com/leandrofars/oktopus/internal/utils"
)
type ParamData struct {
Writable bool `json:"writable"`
Value interface{} `json:"value"`
}
type WiFi struct {
Path string `json:"path"`
Name ParamData `json:"name"`
SSID ParamData `json:"ssid"`
Password ParamData `json:"password"`
Security ParamData `json:"security"`
//SecurityCapabilities []ParamData `json:"securityCapabilities"`
Enable ParamData `json:"enable"`
Status ParamData `json:"status"`
}
// import (
// "encoding/json"
// "log"
@ -169,3 +196,205 @@ package api
// }
// }
// }
func (a *Api) deviceWifi(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
sn := vars["sn"]
device, err := getDeviceInfo(w, sn, a.nc)
if err != nil {
return
}
if r.Method == http.MethodGet {
if device.Cwmp == entity.Online {
var (
NUMBER_OF_WIFI_PARAMS_TO_GET = 5
)
var wlans []WiFi
payload := cwmp.GetParameterNames("InternetGatewayDevice.LANDevice.", 1)
_, response, err := cwmpInteraction[cwmp.GetParameterNamesResponse](sn, []byte(payload), w, a.nc)
if err != nil {
return
}
parameters_to_get_values := []string{}
wlanConfigurationInstances := 0
// x = InternetGatewayDevice.LanDevice.*.
for _, x := range response.ParameterList {
payload = cwmp.GetParameterNames(x.Name+"WLANConfiguration.", 1)
_, response, err := cwmpInteraction[cwmp.GetParameterNamesResponse](sn, []byte(payload), w, a.nc)
if err != nil {
return
}
// y = InternetGatewayDevice.LanDevice.*.WLANConfiguration.*
for _, y := range response.ParameterList {
wlans = append(wlans, WiFi{})
payload = cwmp.GetParameterNames(y.Name, 1)
_, response, err := cwmpInteraction[cwmp.GetParameterNamesResponse](sn, []byte(payload), w, a.nc)
if err != nil {
return
}
// z = InternetGatewayDevice.LanDevice.*.WLANConfiguration.*.<Parameter>
for _, z := range response.ParameterList {
path := strings.Split(z.Name, ".")
parameter := path[len(path)-1]
switch parameter {
case "Enable":
wlans[wlanConfigurationInstances].Enable.Writable = cwmp.ParamTypeIsWritable(z.Writable)
case "Name":
wlans[wlanConfigurationInstances].Name.Writable = cwmp.ParamTypeIsWritable(z.Writable)
case "Status":
wlans[wlanConfigurationInstances].Status.Writable = cwmp.ParamTypeIsWritable(z.Writable)
case "SSID":
wlans[wlanConfigurationInstances].SSID.Writable = cwmp.ParamTypeIsWritable(z.Writable)
case "Standard":
wlans[wlanConfigurationInstances].Security.Writable = cwmp.ParamTypeIsWritable(z.Writable)
case "KeyPassphrase":
wlans[wlanConfigurationInstances].Password.Writable = cwmp.ParamTypeIsWritable(z.Writable)
}
}
parameters_to_get_values = append(
parameters_to_get_values,
y.Name+"Enable",
y.Name+"Name",
y.Name+"Status",
y.Name+"SSID",
y.Name+"Standard",
y.Name+"PreSharedKey.1.KeyPassphrase",
)
wlans[wlanConfigurationInstances].Path = y.Name
wlanConfigurationInstances = wlanConfigurationInstances + 1
}
}
payload = cwmp.GetParameterMultiValues(parameters_to_get_values)
_, parameterValuesResp, err := cwmpInteraction[cwmp.GetParameterValuesResponse](sn, []byte(payload), w, a.nc)
if err != nil {
return
}
i := 0
wlanIndex := 0
for _, a := range parameterValuesResp.ParameterList {
path := strings.Split(a.Name, ".")
parameter := path[len(path)-1]
switch parameter {
case "Enable":
wlans[wlanIndex].Enable.Value = a.Value
case "Name":
wlans[wlanIndex].Name.Value = a.Value
case "Status":
wlans[wlanIndex].Status.Value = a.Value
case "SSID":
wlans[wlanIndex].SSID.Value = a.Value
case "Standard":
wlans[wlanIndex].Security.Value = a.Value
case "KeyPassphrase":
wlans[wlanIndex].Password.Value = a.Value
}
i = i + 1
if i == (NUMBER_OF_WIFI_PARAMS_TO_GET + 1) {
wlanIndex = wlanIndex + 1
i = 0
}
}
utils.MarshallEncoder(wlans, w)
return
}
if device.Mqtt == entity.Online || device.Stomp == entity.Online || device.Websockets == entity.Online {
w.WriteHeader(http.StatusNotImplemented)
w.Write(utils.Marshall("This feature is only working with CWMP devices"))
return
}
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall("Device is Offline"))
}
if r.Method == http.MethodPut {
if device.Cwmp == entity.Online {
var body []WiFi
err := utils.MarshallDecoder(&body, r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write(utils.Marshall("Couldn't decode received payload, err: " + err.Error()))
return
}
fmtBody := map[string]string{}
for _, x := range body {
if x.Name.Value != nil {
fmtBody[x.Path+"Name"] = x.Name.Value.(string)
}
if x.SSID.Value != nil {
fmtBody[x.Path+"SSID"] = x.SSID.Value.(string)
}
if x.Enable.Value != nil {
fmtBody[x.Path+"Enable"] = x.Enable.Value.(string)
}
}
payload := cwmp.SetParameterMultiValues(fmtBody)
_, setParameterValuesResp, err := cwmpInteraction[cwmp.SetParameterValuesResponse](sn, []byte(payload), w, a.nc)
if err != nil {
return
}
if setParameterValuesResp.Status == cwmp.ALL_OK {
log.Printf("All parameters sent to the cpe %s were applied", device.SN)
w.Write(utils.Marshall(cwmp.ALL_OK))
return
}
if setParameterValuesResp.Status == cwmp.SOME_PENDING {
log.Printf("All parameters sent to the cpe %s were committed, but not all of them were applied, maybe you need to wait sometime or have a reboot", device.SN)
w.Write(utils.Marshall(cwmp.SOME_PENDING))
return
}
}
if device.Mqtt == entity.Online || device.Stomp == entity.Online || device.Websockets == entity.Online {
w.WriteHeader(http.StatusNotImplemented)
w.Write(utils.Marshall("This feature is only working with CWMP devices"))
return
}
w.WriteHeader(http.StatusBadRequest)
w.Write(utils.Marshall("Device is Offline"))
}
}

View File

@ -9,6 +9,27 @@ import (
"time"
)
/*
A successful response to SetParameterValues method returns an integer enumeration defined as follows:
0 = All Parameter changes have been validated and applied.
1 = All Parameter changes have been validated and committed, but some or all are not yet applied (for example, if a reboot is required before the new values are applied).
*/
type SetParameterValuesResponseStatus int
const (
ALL_OK = 0
SOME_PENDING = 1
)
/* -------------------------------------------------------------------------- */
const WRITABLE = "1"
func ParamTypeIsWritable(param string) bool {
return param == WRITABLE
}
type SoapEnvelope struct {
XMLName xml.Name
Header SoapHeader
@ -41,6 +62,12 @@ type ParameterInfoStruct struct {
Writable string
}
type ParameterAttributeStruct struct {
Name string
Notification int
AccessList []string
}
type SetParameterValues_ struct {
ParameterList []ParameterValueStruct `xml:"Body>SetParameterValues>ParameterList>ParameterValueStruct"`
ParameterKey string `xml:"Body>SetParameterValues>ParameterKey>string"`
@ -55,6 +82,10 @@ type GetParameterNames_ struct {
NextLevel string `xml:"Body>GetParameterNames>NextLevel"`
}
type GetParameterAttributes_ struct {
ParameterNames []string `xml:"Body>GetParameterAttributes>ParameterNames>string"`
}
type GetParameterValuesResponse struct {
ParameterList []ParameterValueStruct `xml:"Body>GetParameterValuesResponse>ParameterList>ParameterValueStruct"`
}
@ -63,6 +94,10 @@ type GetParameterNamesResponse struct {
ParameterList []ParameterInfoStruct `xml:"Body>GetParameterNamesResponse>ParameterList>ParameterInfoStruct"`
}
type GetParameterAttributesResponse struct {
ParameterList []ParameterAttributeStruct `xml:"Body>GetParameterAttributesResponse>ParameterList>ParameterAttributeStruct"`
}
type CWMPInform struct {
DeviceId DeviceID `xml:"Body>Inform>DeviceId"`
Events []EventStruct `xml:"Body>Inform>Event>EventStruct"`
@ -180,6 +215,10 @@ func GetParameterMultiValues(leaves []string) string {
return msg
}
type SetParameterValuesResponse struct {
Status int `xml:"Body>SetParameterValuesResponse>Status"`
}
func SetParameterValues(leaf string, value string) string {
return `<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:cwmp="urn:dslforum-org:cwmp-1-0" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:schemaLocation="urn:dslforum-org:cwmp-1-0 ..\schemas\wt121.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
@ -210,7 +249,7 @@ func SetParameterMultiValues(data map[string]string) string {
<soap:Header/>
<soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<cwmp:SetParameterValues>
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[` + string(len(data)) + `]">`
<ParameterList soapenc:arrayType="cwmp:ParameterValueStruct[` + fmt.Sprint(len(data)) + `]">`
for key, value := range data {
msg += `<ParameterValueStruct>

View File

@ -11,6 +11,7 @@ type Device struct {
Mqtt Status
Stomp Status
Websockets Status
Cwmp Status
}
type VendorsCount struct {

View File

@ -145,3 +145,21 @@ func NewOperateMsg(getStuff usp_msg.Operate) usp_msg.Msg {
},
}
}
func NewNotifyMsg(notify usp_msg.Notify) usp_msg.Msg {
return usp_msg.Msg{
Header: &usp_msg.Header{
MsgId: uuid.NewString(),
MsgType: usp_msg.Header_NOTIFY,
},
Body: &usp_msg.Body{
MsgBody: &usp_msg.Body_Request{
Request: &usp_msg.Request{
ReqType: &usp_msg.Request_Notify{
Notify: &notify,
},
},
},
},
}
}

View File

@ -5,23 +5,23 @@ go 1.22.0
require (
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/nats-io/nats.go v1.33.1
go.mongodb.org/mongo-driver v1.14.0
google.golang.org/protobuf v1.33.0
github.com/nats-io/nats.go v1.35.0
go.mongodb.org/mongo-driver v1.15.0
google.golang.org/protobuf v1.34.1
)
require (
github.com/golang/snappy v0.0.1 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/montanaflynn/stats v0.7.1 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

View File

@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@ -10,10 +12,16 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/nats-io/nats.go v1.33.1 h1:8TxLZZ/seeEfR97qV0/Bl939tpDnt2Z2fK3HkPypj70=
github.com/nats-io/nats.go v1.33.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk=
github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@ -26,13 +34,19 @@ github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76 h1:tBiBTKHnIjovYoLX/TPkcf+OjqqKGQrPtGT3Foz+Pgo=
github.com/youmark/pkcs8 v0.0.0-20240424034433-3c2c7870ae76/go.mod h1:SQliXeA7Dhkt//vS29v3zpbEwoa+zb2Cn5xj5uO4K5U=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80=
go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
go.mongodb.org/mongo-driver v1.15.0 h1:rJCKC8eEliewXjZGf0ddURtl7tTVy1TK3bfl0gkUSLc=
go.mongodb.org/mongo-driver v1.15.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -41,6 +55,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -48,6 +64,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -56,6 +74,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
@ -64,3 +84,5 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=

View File

@ -3,16 +3,19 @@ module github.com/OktopUSP/oktopus/backend/services/mqtt-adapter
go 1.22.0
require (
github.com/eclipse/paho.golang v0.21.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/eclipse/paho.golang v0.21.0
github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
github.com/nats-io/nats.go v1.35.0
golang.org/x/sys v0.20.0
)
require (
github.com/gorilla/websocket v1.5.1 // indirect
github.com/joho/godotenv v1.5.1 // indirect
github.com/klauspost/compress v1.17.7 // indirect
github.com/nats-io/nats.go v1.33.1 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.20.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

View File

@ -1,5 +1,9 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eclipse/paho.golang v0.21.0 h1:cxxEReu+iFbA5RrHfRGxJOh8tXZKDywuehneoeBeyn8=
github.com/eclipse/paho.golang v0.21.0/go.mod h1:GHF6vy7SvDbDHBguaUpfuBkEB5G6j0zKxMG4gbh6QRQ=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
@ -8,17 +12,37 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg=
github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/nats-io/nats.go v1.33.1 h1:8TxLZZ/seeEfR97qV0/Bl939tpDnt2Z2fK3HkPypj70=
github.com/nats-io/nats.go v1.33.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk=
github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg=
golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -283,6 +283,11 @@ func tcpInfo(conn *net.TCPConn) (*unix.TCPInfo, error) {
}
func (b *Bridge) setMqttPassword() {
entry, _ := b.kv.Get(b.Ctx, b.Mqtt.Username)
entry, err := b.kv.Get(b.Ctx, b.Mqtt.Username)
if err != nil {
log.Printf("Error getting key %s: %v", b.Mqtt.Username, err)
return
}
b.Mqtt.Password = string(entry.Value())
}

View File

@ -5,14 +5,14 @@ go 1.22.1
require (
github.com/go-stomp/stomp/v3 v3.1.0
github.com/joho/godotenv v1.5.1
github.com/nats-io/nats.go v1.34.0
golang.org/x/sys v0.16.0
github.com/nats-io/nats.go v1.35.0
golang.org/x/sys v0.20.0
)
require (
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/compress v1.17.8 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

View File

@ -6,6 +6,8 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -13,6 +15,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/nats-io/nats.go v1.34.0 h1:fnxnPCNiwIG5w08rlMcEKTUw4AV/nKyGCOJE8TdhSPk=
github.com/nats-io/nats.go v1.34.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk=
github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
@ -22,6 +26,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -35,11 +41,15 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=

View File

@ -212,7 +212,7 @@ func (d *compressor) writeBlockSkip(tok *tokens, index int, eof bool) error {
// Should only be used after a start/reset.
func (d *compressor) fillWindow(b []byte) {
// Do not fill window if we are in store-only or huffman mode.
if d.level <= 0 {
if d.level <= 0 && d.level > -MinCustomWindowSize {
return
}
if d.fast != nil {

View File

@ -31,7 +31,7 @@ When using or transitioning to Go modules support:
```bash
# Go client latest or explicit version
go get github.com/nats-io/nats.go/@latest
go get github.com/nats-io/nats.go/@v1.34.0
go get github.com/nats-io/nats.go/@v1.35.0
# For latest NATS Server, add /v2 at the end
go get github.com/nats-io/nats-server/v2
@ -474,6 +474,19 @@ resp := &response{}
err := c.RequestWithContext(ctx, "foo", req, resp)
```
## Backwards compatibility
In the development of nats.go, we are committed to maintaining backward compatibility and ensuring a stable and reliable experience for all users. In general, we follow the standard go compatibility guidelines.
However, it's important to clarify our stance on certain types of changes:
- **Expanding structures:**
Adding new fields to structs is not considered a breaking change.
- **Adding methods to exported interfaces:**
Extending public interfaces with new methods is also not viewed as a breaking change within the context of this project. It is important to note that no unexported methods will be added to interfaces allowing users to implement them.
Additionally, this library always supports at least 2 latest minor Go versions. For example, if the latest Go version is 1.22, the library will support Go 1.21 and 1.22.
## License
Unless otherwise noted, the NATS source files are distributed

View File

@ -113,13 +113,19 @@ func main() {
// Get 10 messages from the consumer
messageCounter := 0
msgs, _ := c.Fetch(10)
msgs, err := c.Fetch(10)
if err != nil {
// handle error
}
for msg := range msgs.Messages() {
msg.Ack()
fmt.Printf("Received a JetStream message via fetch: %s\n", string(msg.Data()))
messageCounter++
}
fmt.Printf("received %d messages\n", messageCounter)
if msgs.Error() != nil {
fmt.Println("Error during Fetch(): ", msgs.Error())
}
@ -391,19 +397,29 @@ of messages/bytes. By default, `Fetch()` will wait 30 seconds before timing out
```go
// receive up to 10 messages from the stream
msgs, _ := c.Fetch(10)
msgs, err := c.Fetch(10)
if err != nil {
// handle error
}
for msg := range msgs.Messages() {
fmt.Printf("Received a JetStream message: %s\n", string(msg.Data()))
}
if msgs.Error() != nil {
// handle error
}
// receive up to 1024 B of data
msgs, _ := c.FetchBytes(1024)
msgs, err := c.FetchBytes(1024)
if err != nil {
// handle error
}
for msg := range msgs.Messages() {
fmt.Printf("Received a JetStream message: %s\n", string(msg.Data()))
}
if msgs.Error() != nil {
// handle error
}
@ -414,10 +430,15 @@ stream available at the time of sending request:
```go
// FetchNoWait will not wait for new messages if the whole batch is not available at the time of sending request.
msgs, _ := c.FetchNoWait(10)
msgs, err := c.FetchNoWait(10)
if err != nil {
// handle error
}
for msg := range msgs.Messages() {
fmt.Printf("Received a JetStream message: %s\n", string(msg.Data()))
}
if msgs.Error() != nil {
// handle error
}

View File

@ -208,6 +208,9 @@ func upsertConsumer(ctx context.Context, js *jetStream, stream string, cfg Consu
var ccSubj string
if cfg.FilterSubject != "" && len(cfg.FilterSubjects) == 0 {
if err := validateSubject(cfg.FilterSubject); err != nil {
return nil, err
}
ccSubj = apiSubj(js.apiPrefix, fmt.Sprintf(apiConsumerCreateWithFilterSubjectT, stream, consumerName, cfg.FilterSubject))
} else {
ccSubj = apiSubj(js.apiPrefix, fmt.Sprintf(apiConsumerCreateT, stream, consumerName))
@ -318,8 +321,11 @@ func deleteConsumer(ctx context.Context, js *jetStream, stream, consumer string)
}
func validateConsumerName(dur string) error {
if strings.Contains(dur, ".") {
return fmt.Errorf("%w: %q", ErrInvalidConsumerName, dur)
if dur == "" {
return fmt.Errorf("%w: '%s'", ErrInvalidConsumerName, "name is required")
}
if strings.ContainsAny(dur, ">*. /\\") {
return fmt.Errorf("%w: '%s'", ErrInvalidConsumerName, dur)
}
return nil
}

View File

@ -71,6 +71,10 @@ var (
// ErrJetStreamNotEnabled is an error returned when JetStream is not
// enabled.
//
// Note: This error will not be returned in clustered mode, even if each
// server in the cluster does not have JetStream enabled. In clustered mode,
// requests will time out instead.
ErrJetStreamNotEnabled JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabled, Description: "jetstream not enabled", Code: 503}}
// ErrJetStreamNotEnabledForAccount is an error returned when JetStream is

View File

@ -773,7 +773,7 @@ func validateStreamName(stream string) error {
if stream == "" {
return ErrStreamNameRequired
}
if strings.Contains(stream, ".") {
if strings.ContainsAny(stream, ">*. /\\") {
return fmt.Errorf("%w: '%s'", ErrInvalidStreamName, stream)
}
return nil
@ -783,7 +783,7 @@ func validateSubject(subject string) error {
if subject == "" {
return fmt.Errorf("%w: %s", ErrInvalidSubject, "subject cannot be empty")
}
if !subjectRegexp.MatchString(subject) {
if subject[0] == '.' || subject[len(subject)-1] == '.' || !subjectRegexp.MatchString(subject) {
return fmt.Errorf("%w: %s", ErrInvalidSubject, subject)
}
return nil
@ -791,9 +791,11 @@ func validateSubject(subject string) error {
// AccountInfo fetches account information from the server, containing details
// about the account associated with this JetStream connection. If account is
// not enabled for JetStream, ErrJetStreamNotEnabledForAccount is returned. If
// the server does not have JetStream enabled, ErrJetStreamNotEnabled is
// returned.
// not enabled for JetStream, ErrJetStreamNotEnabledForAccount is returned.
//
// If the server does not have JetStream enabled, ErrJetStreamNotEnabled is
// returned (for a single server setup). For clustered topologies, AccountInfo
// will time out.
func (js *jetStream) AccountInfo(ctx context.Context) (*AccountInfo, error) {
ctx, cancel := wrapContextWithoutDeadline(ctx)
if cancel != nil {

View File

@ -17,6 +17,7 @@ import (
"context"
"errors"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
@ -196,52 +197,52 @@ type (
// Bucket is the name of the KeyValue store. Bucket name has to be
// unique and can only contain alphanumeric characters, dashes, and
// underscores.
Bucket string
Bucket string `json:"bucket"`
// Description is an optional description for the KeyValue store.
Description string
Description string `json:"description,omitempty"`
// MaxValueSize is the maximum size of a value in bytes. If not
// specified, the default is -1 (unlimited).
MaxValueSize int32
MaxValueSize int32 `json:"max_value_size,omitempty"`
// History is the number of historical values to keep per key. If not
// specified, the default is 1. Max is 64.
History uint8
History uint8 `json:"history,omitempty"`
// TTL is the expiry time for keys. By default, keys do not expire.
TTL time.Duration
TTL time.Duration `json:"ttl,omitempty"`
// MaxBytes is the maximum size in bytes of the KeyValue store. If not
// specified, the default is -1 (unlimited).
MaxBytes int64
MaxBytes int64 `json:"max_bytes,omitempty"`
// Storage is the type of storage to use for the KeyValue store. If not
// specified, the default is FileStorage.
Storage StorageType
Storage StorageType `json:"storage,omitempty"`
// Replicas is the number of replicas to keep for the KeyValue store in
// clustered jetstream. Defaults to 1, maximum is 5.
Replicas int
Replicas int `json:"num_replicas,omitempty"`
// Placement is used to declare where the stream should be placed via
// tags and/or an explicit cluster name.
Placement *Placement
Placement *Placement `json:"placement,omitempty"`
// RePublish allows immediate republishing a message to the configured
// subject after it's stored.
RePublish *RePublish
RePublish *RePublish `json:"republish,omitempty"`
// Mirror defines the consiguration for mirroring another KeyValue
// store.
Mirror *StreamSource
Mirror *StreamSource `json:"mirror,omitempty"`
// Sources defines the configuration for sources of a KeyValue store.
Sources []*StreamSource
Sources []*StreamSource `json:"sources,omitempty"`
// Compression sets the underlying stream compression.
// NOTE: Compression is supported for nats-server 2.10.0+
Compression bool
Compression bool `json:"compression,omitempty"`
}
// KeyLister is used to retrieve a list of key value store keys. It returns
@ -447,12 +448,13 @@ const (
// Regex for valid keys and buckets.
var (
validBucketRe = regexp.MustCompile(`\A[a-zA-Z0-9_-]+\z`)
validKeyRe = regexp.MustCompile(`\A[-/_=\.a-zA-Z0-9]+\z`)
validBucketRe = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
validKeyRe = regexp.MustCompile(`^[-/_=\.a-zA-Z0-9]+$`)
validSearchKeyRe = regexp.MustCompile(`^[-/_=\.a-zA-Z0-9*]*[>]?$`)
)
func (js *jetStream) KeyValue(ctx context.Context, bucket string) (KeyValue, error) {
if !validBucketRe.MatchString(bucket) {
if !bucketValid(bucket) {
return nil, ErrInvalidBucketName
}
streamName := fmt.Sprintf(kvBucketNameTmpl, bucket)
@ -488,9 +490,27 @@ func (js *jetStream) CreateKeyValue(ctx context.Context, cfg KeyValueConfig) (Ke
// errors are joined so that backwards compatibility is retained
// and previous checks for ErrStreamNameAlreadyInUse will still work.
err = errors.Join(fmt.Errorf("%w: %s", ErrBucketExists, cfg.Bucket), err)
// If we have a failure to add, it could be because we have
// a config change if the KV was created against before a bug fix
// that changed the value of discard policy.
// We will check if the stream exists and if the only difference
// is the discard policy, we will update the stream.
// The same logic applies for KVs created pre 2.9.x and
// the AllowDirect setting.
if stream, _ = js.Stream(ctx, scfg.Name); stream != nil {
cfg := stream.CachedInfo().Config
cfg.Discard = scfg.Discard
cfg.AllowDirect = scfg.AllowDirect
if reflect.DeepEqual(cfg, scfg) {
stream, err = js.UpdateStream(ctx, scfg)
}
}
}
if err != nil {
return nil, err
}
}
pushJS, err := js.legacyJetStream()
if err != nil {
return nil, err
@ -539,7 +559,7 @@ func (js *jetStream) CreateOrUpdateKeyValue(ctx context.Context, cfg KeyValueCon
}
func (js *jetStream) prepareKeyValueConfig(ctx context.Context, cfg KeyValueConfig) (StreamConfig, error) {
if !validBucketRe.MatchString(cfg.Bucket) {
if !bucketValid(cfg.Bucket) {
return StreamConfig{}, ErrInvalidBucketName
}
if _, err := js.AccountInfo(ctx); err != nil {
@ -601,6 +621,7 @@ func (js *jetStream) prepareKeyValueConfig(ctx context.Context, cfg KeyValueConf
AllowDirect: true,
RePublish: cfg.RePublish,
Compression: compression,
Discard: DiscardNew,
}
if cfg.Mirror != nil {
// Copy in case we need to make changes so we do not change caller's version.
@ -636,7 +657,7 @@ func (js *jetStream) prepareKeyValueConfig(ctx context.Context, cfg KeyValueConf
// DeleteKeyValue will delete this KeyValue store (JetStream stream).
func (js *jetStream) DeleteKeyValue(ctx context.Context, bucket string) error {
if !validBucketRe.MatchString(bucket) {
if !bucketValid(bucket) {
return ErrInvalidBucketName
}
stream := fmt.Sprintf(kvBucketNameTmpl, bucket)
@ -773,6 +794,13 @@ func (js *jetStream) legacyJetStream() (nats.JetStreamContext, error) {
return js.conn.JetStream(opts...)
}
func bucketValid(bucket string) bool {
if len(bucket) == 0 {
return false
}
return validBucketRe.MatchString(bucket)
}
func keyValid(key string) bool {
if len(key) == 0 || key[0] == '.' || key[len(key)-1] == '.' {
return false
@ -780,6 +808,13 @@ func keyValid(key string) bool {
return validKeyRe.MatchString(key)
}
func searchKeyValid(key string) bool {
if len(key) == 0 || key[0] == '.' || key[len(key)-1] == '.' {
return false
}
return validSearchKeyRe.MatchString(key)
}
func (kv *kvs) get(ctx context.Context, key string, revision uint64) (KeyValueEntry, error) {
if !keyValid(key) {
return nil, ErrInvalidKey
@ -1036,6 +1071,9 @@ func (w *watcher) Stop() error {
// Watch for any updates to keys that match the keys argument which could include wildcards.
// Watch will send a nil entry when it has received all initial values.
func (kv *kvs) Watch(ctx context.Context, keys string, opts ...WatchOpt) (KeyWatcher, error) {
if !searchKeyValid(keys) {
return nil, fmt.Errorf("%w: %s", ErrInvalidKey, "keys cannot be empty and must be a valid NATS subject")
}
var o watchOpts
for _, opt := range opts {
if opt != nil {

View File

@ -378,6 +378,7 @@ func (js *jetStream) handleAsyncReply(m *nats.Msg) {
cb := js.publisher.asyncPublisherOpts.aecb
js.publisher.Unlock()
if cb != nil {
paf.msg.Reply = ""
cb(js, paf.msg, err)
}
}
@ -388,6 +389,12 @@ func (js *jetStream) handleAsyncReply(m *nats.Msg) {
paf.retries++
paf.msg.Reply = m.Subject
time.AfterFunc(paf.retryWait, func() {
js.publisher.Lock()
paf := js.getPAF(id)
js.publisher.Unlock()
if paf == nil {
return
}
_, err := js.PublishMsgAsync(paf.msg, func(po *pubOpts) error {
po.pafRetry = paf
return nil
@ -453,10 +460,21 @@ func (js *jetStream) resetPendingAcksOnReconnect() {
return
}
js.publisher.Lock()
for _, paf := range js.publisher.acks {
errCb := js.publisher.asyncPublisherOpts.aecb
for id, paf := range js.publisher.acks {
paf.err = nats.ErrDisconnected
if paf.errCh != nil {
paf.errCh <- paf.err
}
if errCb != nil {
js.publisher.Unlock()
// clear reply subject so that new one is created on republish
paf.msg.Reply = ""
errCb(js, paf.msg, nats.ErrDisconnected)
js.publisher.Lock()
}
delete(js.publisher.acks, id)
}
js.publisher.acks = nil
if js.publisher.doneCh != nil {
close(js.publisher.doneCh)
js.publisher.doneCh = nil

View File

@ -712,10 +712,20 @@ func (js *js) resetPendingAcksOnReconnect() {
return
}
js.mu.Lock()
for _, paf := range js.pafs {
errCb := js.opts.aecb
for id, paf := range js.pafs {
paf.err = ErrDisconnected
if paf.errCh != nil {
paf.errCh <- paf.err
}
if errCb != nil {
// clear reply subject so that new one is created on republish
js.mu.Unlock()
errCb(js, paf.msg, ErrDisconnected)
js.mu.Lock()
}
delete(js.pafs, id)
}
js.pafs = nil
if js.dch != nil {
close(js.dch)
js.dch = nil
@ -2867,6 +2877,7 @@ func (sub *Subscription) Fetch(batch int, opts ...PullOpt) ([]*Msg, error) {
if subClosed {
err = errors.Join(ErrBadSubscription, ErrSubscriptionClosed)
}
hbLock := sync.Mutex{}
if err == nil && len(msgs) < batch && !subClosed {
// For batch real size of 1, it does not make sense to set no_wait in
// the request.
@ -2909,7 +2920,9 @@ func (sub *Subscription) Fetch(batch int, opts ...PullOpt) ([]*Msg, error) {
if o.hb > 0 {
if hbTimer == nil {
hbTimer = time.AfterFunc(2*o.hb, func() {
hbLock.Lock()
hbErr = ErrNoHeartbeat
hbLock.Unlock()
cancel()
})
} else {
@ -2951,6 +2964,8 @@ func (sub *Subscription) Fetch(batch int, opts ...PullOpt) ([]*Msg, error) {
}
// If there is at least a message added to msgs, then need to return OK and no error
if err != nil && len(msgs) == 0 {
hbLock.Lock()
defer hbLock.Unlock()
if hbErr != nil {
return nil, hbErr
}
@ -3181,9 +3196,12 @@ func (sub *Subscription) FetchBatch(batch int, opts ...PullOpt) (MessageBatch, e
}
var hbTimer *time.Timer
var hbErr error
hbLock := sync.Mutex{}
if o.hb > 0 {
hbTimer = time.AfterFunc(2*o.hb, func() {
hbLock.Lock()
hbErr = ErrNoHeartbeat
hbLock.Unlock()
cancel()
})
}
@ -3219,11 +3237,13 @@ func (sub *Subscription) FetchBatch(batch int, opts ...PullOpt) (MessageBatch, e
}
}
if err != nil {
hbLock.Lock()
if hbErr != nil {
result.err = hbErr
} else {
result.err = o.checkCtxErr(err)
}
hbLock.Unlock()
}
close(result.msgs)
result.done <- struct{}{}

View File

@ -22,6 +22,10 @@ var (
// API errors
// ErrJetStreamNotEnabled is an error returned when JetStream is not enabled for an account.
//
// Note: This error will not be returned in clustered mode, even if each
// server in the cluster does not have JetStream enabled. In clustered mode,
// requests will time out instead.
ErrJetStreamNotEnabled JetStreamError = &jsError{apiErr: &APIError{ErrorCode: JSErrCodeJetStreamNotEnabled, Description: "jetstream not enabled", Code: 503}}
// ErrJetStreamNotEnabledForAccount is an error returned when JetStream is not enabled for an account.
@ -120,6 +124,9 @@ var (
// ErrInvalidConsumerName is returned when the provided consumer name is invalid (contains '.' or ' ').
ErrInvalidConsumerName JetStreamError = &jsError{message: "invalid consumer name"}
// ErrInvalidFilterSubject is returned when the provided filter subject is invalid.
ErrInvalidFilterSubject JetStreamError = &jsError{message: "invalid filter subject"}
// ErrNoMatchingStream is returned when stream lookup by subject is unsuccessful.
ErrNoMatchingStream JetStreamError = &jsError{message: "no stream matches subject"}

View File

@ -106,51 +106,143 @@ type JetStreamManager interface {
// There are sensible defaults for most. If no subjects are
// given the name will be used as the only subject.
type StreamConfig struct {
// Name is the name of the stream. It is required and must be unique
// across the JetStream account.
//
// Name Names cannot contain whitespace, ., *, >, path separators
// (forward or backwards slash), and non-printable characters.
Name string `json:"name"`
// Description is an optional description of the stream.
Description string `json:"description,omitempty"`
// Subjects is a list of subjects that the stream is listening on.
// Wildcards are supported. Subjects cannot be set if the stream is
// created as a mirror.
Subjects []string `json:"subjects,omitempty"`
// Retention defines the message retention policy for the stream.
// Defaults to LimitsPolicy.
Retention RetentionPolicy `json:"retention"`
// MaxConsumers specifies the maximum number of consumers allowed for
// the stream.
MaxConsumers int `json:"max_consumers"`
// MaxMsgs is the maximum number of messages the stream will store.
// After reaching the limit, stream adheres to the discard policy.
// If not set, server default is -1 (unlimited).
MaxMsgs int64 `json:"max_msgs"`
// MaxBytes is the maximum total size of messages the stream will store.
// After reaching the limit, stream adheres to the discard policy.
// If not set, server default is -1 (unlimited).
MaxBytes int64 `json:"max_bytes"`
// Discard defines the policy for handling messages when the stream
// reaches its limits in terms of number of messages or total bytes.
Discard DiscardPolicy `json:"discard"`
// DiscardNewPerSubject is a flag to enable discarding new messages per
// subject when limits are reached. Requires DiscardPolicy to be
// DiscardNew and the MaxMsgsPerSubject to be set.
DiscardNewPerSubject bool `json:"discard_new_per_subject,omitempty"`
// MaxAge is the maximum age of messages that the stream will retain.
MaxAge time.Duration `json:"max_age"`
// MaxMsgsPerSubject is the maximum number of messages per subject that
// the stream will retain.
MaxMsgsPerSubject int64 `json:"max_msgs_per_subject"`
// MaxMsgSize is the maximum size of any single message in the stream.
MaxMsgSize int32 `json:"max_msg_size,omitempty"`
// Storage specifies the type of storage backend used for the stream
// (file or memory).
Storage StorageType `json:"storage"`
// Replicas is the number of stream replicas in clustered JetStream.
// Defaults to 1, maximum is 5.
Replicas int `json:"num_replicas"`
// NoAck is a flag to disable acknowledging messages received by this
// stream.
//
// If set to true, publish methods from the JetStream client will not
// work as expected, since they rely on acknowledgements. Core NATS
// publish methods should be used instead. Note that this will make
// message delivery less reliable.
NoAck bool `json:"no_ack,omitempty"`
Template string `json:"template_owner,omitempty"`
// Duplicates is the window within which to track duplicate messages.
// If not set, server default is 2 minutes.
Duplicates time.Duration `json:"duplicate_window,omitempty"`
// Placement is used to declare where the stream should be placed via
// tags and/or an explicit cluster name.
Placement *Placement `json:"placement,omitempty"`
// Mirror defines the configuration for mirroring another stream.
Mirror *StreamSource `json:"mirror,omitempty"`
// Sources is a list of other streams this stream sources messages from.
Sources []*StreamSource `json:"sources,omitempty"`
// Sealed streams do not allow messages to be published or deleted via limits or API,
// sealed streams can not be unsealed via configuration update. Can only
// be set on already created streams via the Update API.
Sealed bool `json:"sealed,omitempty"`
// DenyDelete restricts the ability to delete messages from a stream via
// the API. Defaults to false.
DenyDelete bool `json:"deny_delete,omitempty"`
// DenyPurge restricts the ability to purge messages from a stream via
// the API. Defaults to false.
DenyPurge bool `json:"deny_purge,omitempty"`
// AllowRollup allows the use of the Nats-Rollup header to replace all
// contents of a stream, or subject in a stream, with a single new
// message.
AllowRollup bool `json:"allow_rollup_hdrs,omitempty"`
// Compression specifies the message storage compression algorithm.
// Defaults to NoCompression.
Compression StoreCompression `json:"compression"`
// FirstSeq is the initial sequence number of the first message in the
// stream.
FirstSeq uint64 `json:"first_seq,omitempty"`
// Allow applying a subject transform to incoming messages before doing anything else.
// SubjectTransform allows applying a transformation to matching
// messages' subjects.
SubjectTransform *SubjectTransformConfig `json:"subject_transform,omitempty"`
// Allow republish of the message after being sequenced and stored.
// RePublish allows immediate republishing a message to the configured
// subject after it's stored.
RePublish *RePublish `json:"republish,omitempty"`
// Allow higher performance, direct access to get individual messages. E.g. KeyValue
// AllowDirect enables direct access to individual messages using direct
// get API. Defaults to false.
AllowDirect bool `json:"allow_direct"`
// Allow higher performance and unified direct access for mirrors as well.
// MirrorDirect enables direct access to individual messages from the
// origin stream using direct get API. Defaults to false.
MirrorDirect bool `json:"mirror_direct"`
// Limits for consumers on this stream.
// ConsumerLimits defines limits of certain values that consumers can
// set, defaults for those who don't set these settings
ConsumerLimits StreamConsumerLimits `json:"consumer_limits,omitempty"`
// Metadata is additional metadata for the Stream.
// Keys starting with `_nats` are reserved.
// NOTE: Metadata requires nats-server v2.10.0+
// Metadata is a set of application-defined key-value pairs for
// associating metadata on the stream. This feature requires nats-server
// v2.10.0 or later.
Metadata map[string]string `json:"metadata,omitempty"`
// Template identifies the template that manages the Stream. DEPRECATED:
// This feature is no longer supported.
Template string `json:"template_owner,omitempty"`
}
// SubjectTransformConfig is for applying a subject transform (to matching messages) before doing anything else when a new message is received.
@ -288,9 +380,13 @@ type accountInfoResponse struct {
AccountInfo
}
// AccountInfo retrieves info about the JetStream usage from the current account.
// If JetStream is not enabled, this will return ErrJetStreamNotEnabled
// Other errors can happen but are generally considered retryable
// AccountInfo fetches account information from the server, containing details
// about the account associated with this JetStream connection. If account is
// not enabled for JetStream, ErrJetStreamNotEnabledForAccount is returned.
//
// If the server does not have JetStream enabled, ErrJetStreamNotEnabled is
// returned (for a single server setup). For clustered topologies, AccountInfo
// will time out.
func (js *js) AccountInfo(opts ...JSOpt) (*AccountInfo, error) {
o, cancel, err := getJSContextOpts(js.opts, opts...)
if err != nil {
@ -410,6 +506,10 @@ func (js *js) upsertConsumer(stream, consumerName string, cfg *ConsumerConfig, o
// if filter subject is empty or ">", use the endpoint without filter subject
ccSubj = fmt.Sprintf(apiConsumerCreateT, stream, consumerName)
} else {
// safeguard against passing invalid filter subject in request subject
if cfg.FilterSubject[0] == '.' || cfg.FilterSubject[len(cfg.FilterSubject)-1] == '.' {
return nil, fmt.Errorf("%w: %q", ErrInvalidFilterSubject, cfg.FilterSubject)
}
// if filter subject is not empty, use the endpoint with filter subject
ccSubj = fmt.Sprintf(apiConsumerCreateWithFilterSubjectT, stream, consumerName, cfg.FilterSubject)
}

View File

@ -249,22 +249,22 @@ func purge() DeleteOpt {
// KeyValueConfig is for configuring a KeyValue store.
type KeyValueConfig struct {
Bucket string
Description string
MaxValueSize int32
History uint8
TTL time.Duration
MaxBytes int64
Storage StorageType
Replicas int
Placement *Placement
RePublish *RePublish
Mirror *StreamSource
Sources []*StreamSource
Bucket string `json:"bucket"`
Description string `json:"description,omitempty"`
MaxValueSize int32 `json:"max_value_size,omitempty"`
History uint8 `json:"history,omitempty"`
TTL time.Duration `json:"ttl,omitempty"`
MaxBytes int64 `json:"max_bytes,omitempty"`
Storage StorageType `json:"storage,omitempty"`
Replicas int `json:"num_replicas,omitempty"`
Placement *Placement `json:"placement,omitempty"`
RePublish *RePublish `json:"republish,omitempty"`
Mirror *StreamSource `json:"mirror,omitempty"`
Sources []*StreamSource `json:"sources,omitempty"`
// Enable underlying stream compression.
// NOTE: Compression is supported for nats-server 2.10.0+
Compression bool
Compression bool `json:"compression,omitempty"`
}
// Used to watch all keys.
@ -344,8 +344,9 @@ const (
// Regex for valid keys and buckets.
var (
validBucketRe = regexp.MustCompile(`\A[a-zA-Z0-9_-]+\z`)
validKeyRe = regexp.MustCompile(`\A[-/_=\.a-zA-Z0-9]+\z`)
validBucketRe = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`)
validKeyRe = regexp.MustCompile(`^[-/_=\.a-zA-Z0-9]+$`)
validSearchKeyRe = regexp.MustCompile(`^[-/_=\.a-zA-Z0-9*]*[>]?$`)
)
// KeyValue will lookup and bind to an existing KeyValue store.
@ -353,7 +354,7 @@ func (js *js) KeyValue(bucket string) (KeyValue, error) {
if !js.nc.serverMinVersion(2, 6, 2) {
return nil, errors.New("nats: key-value requires at least server version 2.6.2")
}
if !validBucketRe.MatchString(bucket) {
if !bucketValid(bucket) {
return nil, ErrInvalidBucketName
}
stream := fmt.Sprintf(kvBucketNameTmpl, bucket)
@ -381,7 +382,7 @@ func (js *js) CreateKeyValue(cfg *KeyValueConfig) (KeyValue, error) {
if cfg == nil {
return nil, ErrKeyValueConfigRequired
}
if !validBucketRe.MatchString(cfg.Bucket) {
if !bucketValid(cfg.Bucket) {
return nil, ErrInvalidBucketName
}
if _, err := js.AccountInfo(); err != nil {
@ -507,7 +508,7 @@ func (js *js) CreateKeyValue(cfg *KeyValueConfig) (KeyValue, error) {
// DeleteKeyValue will delete this KeyValue store (JetStream stream).
func (js *js) DeleteKeyValue(bucket string) error {
if !validBucketRe.MatchString(bucket) {
if !bucketValid(bucket) {
return ErrInvalidBucketName
}
stream := fmt.Sprintf(kvBucketNameTmpl, bucket)
@ -547,6 +548,13 @@ func (e *kve) Created() time.Time { return e.created }
func (e *kve) Delta() uint64 { return e.delta }
func (e *kve) Operation() KeyValueOp { return e.op }
func bucketValid(bucket string) bool {
if len(bucket) == 0 {
return false
}
return validBucketRe.MatchString(bucket)
}
func keyValid(key string) bool {
if len(key) == 0 || key[0] == '.' || key[len(key)-1] == '.' {
return false
@ -554,6 +562,13 @@ func keyValid(key string) bool {
return validKeyRe.MatchString(key)
}
func searchKeyValid(key string) bool {
if len(key) == 0 || key[0] == '.' || key[len(key)-1] == '.' {
return false
}
return validSearchKeyRe.MatchString(key)
}
// Get returns the latest value for the key.
func (kv *kvs) Get(key string) (KeyValueEntry, error) {
e, err := kv.get(key, kvLatestRevision)
@ -951,6 +966,9 @@ func (kv *kvs) WatchAll(opts ...WatchOpt) (KeyWatcher, error) {
// Watch will fire the callback when a key that matches the keys pattern is updated.
// keys needs to be a valid NATS subject.
func (kv *kvs) Watch(keys string, opts ...WatchOpt) (KeyWatcher, error) {
if !searchKeyValid(keys) {
return nil, fmt.Errorf("%w: %s", ErrInvalidKey, "keys cannot be empty and must be a valid NATS subject")
}
var o watchOpts
for _, opt := range opts {
if opt != nil {

View File

@ -47,7 +47,7 @@ import (
// Default Constants
const (
Version = "1.34.0"
Version = "1.35.0"
DefaultURL = "nats://127.0.0.1:4222"
DefaultPort = 4222
DefaultMaxReconnect = 60
@ -2161,6 +2161,47 @@ func (nc *Conn) waitForExits() {
nc.wg.Wait()
}
// ForceReconnect forces a reconnect attempt to the server.
// This is a non-blocking call and will start the reconnect
// process without waiting for it to complete.
//
// If the connection is already in the process of reconnecting,
// this call will force an immediate reconnect attempt (bypassing
// the current reconnect delay).
func (nc *Conn) ForceReconnect() error {
nc.mu.Lock()
defer nc.mu.Unlock()
if nc.isClosed() {
return ErrConnectionClosed
}
if nc.isReconnecting() {
// if we're already reconnecting, force a reconnect attempt
// even if we're in the middle of a backoff
if nc.rqch != nil {
close(nc.rqch)
}
return nil
}
// Clear any queued pongs
nc.clearPendingFlushCalls()
// Clear any queued and blocking requests.
nc.clearPendingRequestCalls()
// Stop ping timer if set.
nc.stopPingTimer()
// Go ahead and make sure we have flushed the outbound
nc.bw.flush()
nc.conn.Close()
nc.changeConnStatus(RECONNECTING)
go nc.doReconnect(nil, true)
return nil
}
// ConnectedUrl reports the connected server's URL
func (nc *Conn) ConnectedUrl() string {
if nc == nil {
@ -2420,7 +2461,7 @@ func (nc *Conn) connect() (bool, error) {
nc.setup()
nc.changeConnStatus(RECONNECTING)
nc.bw.switchToPending()
go nc.doReconnect(ErrNoServers)
go nc.doReconnect(ErrNoServers, false)
err = nil
} else {
nc.current = nil
@ -2720,7 +2761,7 @@ func (nc *Conn) stopPingTimer() {
// Try to reconnect using the option parameters.
// This function assumes we are allowed to reconnect.
func (nc *Conn) doReconnect(err error) {
func (nc *Conn) doReconnect(err error, forceReconnect bool) {
// We want to make sure we have the other watchers shutdown properly
// here before we proceed past this point.
nc.waitForExits()
@ -2776,7 +2817,8 @@ func (nc *Conn) doReconnect(err error) {
break
}
doSleep := i+1 >= len(nc.srvPool)
doSleep := i+1 >= len(nc.srvPool) && !forceReconnect
forceReconnect = false
nc.mu.Unlock()
if !doSleep {
@ -2803,6 +2845,12 @@ func (nc *Conn) doReconnect(err error) {
select {
case <-rqch:
rt.Stop()
// we need to reset the rqch channel to avoid
// closing a closed channel in the next iteration
nc.mu.Lock()
nc.rqch = make(chan struct{})
nc.mu.Unlock()
case <-rt.C:
}
}
@ -2872,18 +2920,19 @@ func (nc *Conn) doReconnect(err error) {
// Done with the pending buffer
nc.bw.doneWithPending()
// This is where we are truly connected.
nc.status = CONNECTED
// Queue up the correct callback. If we are in initial connect state
// (using retry on failed connect), we will call the ConnectedCB,
// otherwise the ReconnectedCB.
if nc.Opts.ReconnectedCB != nil && !nc.initc {
nc.ach.push(func() { nc.Opts.ReconnectedCB(nc) })
} else if nc.Opts.ConnectedCB != nil && nc.initc {
nc.ach.push(func() { nc.Opts.ConnectedCB(nc) })
}
// If we are here with a retry on failed connect, indicate that the
// initial connect is now complete.
nc.initc = false
// Queue up the reconnect callback.
if nc.Opts.ReconnectedCB != nil {
nc.ach.push(func() { nc.Opts.ReconnectedCB(nc) })
}
// Release lock here, we will return below.
nc.mu.Unlock()
@ -2926,7 +2975,7 @@ func (nc *Conn) processOpErr(err error) {
// Clear any queued pongs, e.g. pending flush calls.
nc.clearPendingFlushCalls()
go nc.doReconnect(err)
go nc.doReconnect(err, false)
nc.mu.Unlock()
return
}
@ -3753,7 +3802,7 @@ func readMIMEHeader(tp *textproto.Reader) (textproto.MIMEHeader, error) {
}
// Process key fetching original case.
i := bytes.IndexByte([]byte(kv), ':')
i := strings.IndexByte(kv, ':')
if i < 0 {
return nil, ErrBadHeaderMsg
}
@ -3766,8 +3815,7 @@ func readMIMEHeader(tp *textproto.Reader) (textproto.MIMEHeader, error) {
for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
i++
}
value := string(kv[i:])
m[key] = append(m[key], value)
m[key] = append(m[key], kv[i:])
if err != nil {
return m, err
}

View File

@ -19,15 +19,14 @@
#define POLY1305_MUL(h0, h1, h2, r0, r1, t0, t1, t2, t3, t4, t5) \
MULLD r0, h0, t0; \
MULLD r0, h1, t4; \
MULHDU r0, h0, t1; \
MULLD r0, h1, t4; \
MULHDU r0, h1, t5; \
ADDC t4, t1, t1; \
MULLD r0, h2, t2; \
ADDZE t5; \
MULHDU r1, h0, t4; \
MULLD r1, h0, h0; \
ADD t5, t2, t2; \
ADDE t5, t2, t2; \
ADDC h0, t1, t1; \
MULLD h2, r1, t3; \
ADDZE t4, h0; \
@ -37,13 +36,11 @@
ADDE t5, t3, t3; \
ADDC h0, t2, t2; \
MOVD $-4, t4; \
MOVD t0, h0; \
MOVD t1, h1; \
ADDZE t3; \
ANDCC $3, t2, h2; \
AND t2, t4, t0; \
RLDICL $0, t2, $62, h2; \
AND t2, t4, h0; \
ADDC t0, h0, h0; \
ADDE t3, h1, h1; \
ADDE t3, t1, h1; \
SLD $62, t3, t4; \
SRD $2, t2; \
ADDZE h2; \
@ -75,6 +72,7 @@ TEXT ·update(SB), $0-32
loop:
POLY1305_ADD(R4, R8, R9, R10, R20, R21, R22)
PCALIGN $16
multiply:
POLY1305_MUL(R8, R9, R10, R11, R12, R16, R17, R18, R14, R20, R21)
ADD $-16, R5

View File

@ -103,6 +103,7 @@ var ARM64 struct {
HasASIMDDP bool // Advanced SIMD double precision instruction set
HasSHA512 bool // SHA512 hardware implementation
HasSVE bool // Scalable Vector Extensions
HasSVE2 bool // Scalable Vector Extensions 2
HasASIMDFHM bool // Advanced SIMD multiplication FP16 to FP32
_ CacheLinePad
}

View File

@ -28,6 +28,7 @@ func initOptions() {
{Name: "sm3", Feature: &ARM64.HasSM3},
{Name: "sm4", Feature: &ARM64.HasSM4},
{Name: "sve", Feature: &ARM64.HasSVE},
{Name: "sve2", Feature: &ARM64.HasSVE2},
{Name: "crc32", Feature: &ARM64.HasCRC32},
{Name: "atomics", Feature: &ARM64.HasATOMICS},
{Name: "asimdhp", Feature: &ARM64.HasASIMDHP},
@ -164,6 +165,15 @@ func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) {
switch extractBits(pfr0, 32, 35) {
case 1:
ARM64.HasSVE = true
parseARM64SVERegister(getzfr0())
}
}
func parseARM64SVERegister(zfr0 uint64) {
switch extractBits(zfr0, 0, 3) {
case 1:
ARM64.HasSVE2 = true
}
}

View File

@ -29,3 +29,11 @@ TEXT ·getpfr0(SB),NOSPLIT,$0-8
WORD $0xd5380400
MOVD R0, ret+0(FP)
RET
// func getzfr0() uint64
TEXT ·getzfr0(SB),NOSPLIT,$0-8
// get SVE Feature Register 0 into x0
// mrs x0, ID_AA64ZFR0_EL1 = d5380480
WORD $0xd5380480
MOVD R0, ret+0(FP)
RET

View File

@ -9,3 +9,4 @@ package cpu
func getisar0() uint64
func getisar1() uint64
func getpfr0() uint64
func getzfr0() uint64

View File

@ -35,6 +35,8 @@ const (
hwcap_SHA512 = 1 << 21
hwcap_SVE = 1 << 22
hwcap_ASIMDFHM = 1 << 23
hwcap2_SVE2 = 1 << 1
)
// linuxKernelCanEmulateCPUID reports whether we're running
@ -104,6 +106,9 @@ func doinit() {
ARM64.HasSHA512 = isSet(hwCap, hwcap_SHA512)
ARM64.HasSVE = isSet(hwCap, hwcap_SVE)
ARM64.HasASIMDFHM = isSet(hwCap, hwcap_ASIMDFHM)
// HWCAP2 feature bits
ARM64.HasSVE2 = isSet(hwCap2, hwcap2_SVE2)
}
func isSet(hwc uint, value uint) bool {

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix

View File

@ -9,9 +9,11 @@
#define PSALAA 1208(R0)
#define GTAB64(x) 80(x)
#define LCA64(x) 88(x)
#define CAA(x) 8(x)
#define EDCHPXV(x) 1016(x) // in the CAA
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
#define CAA(x) 8(x)
#define CEECAATHDID(x) 976(x) // in the CAA
#define EDCHPXV(x) 1016(x) // in the CAA
#define GOCB(x) 1104(x) // in the CAA
// SS_*, where x=SAVSTACK_ASYNC
#define SS_LE(x) 0(x)
@ -19,15 +21,38 @@
#define SS_ERRNO(x) 16(x)
#define SS_ERRNOJR(x) 20(x)
#define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6
// Function Descriptor Offsets
#define __errno 0x156*16
#define __err2ad 0x16C*16
TEXT ·clearErrno(SB),NOSPLIT,$0-0
// Call Instructions
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
DATA zosLibVec<>(SB)/8, $0
GLOBL zosLibVec<>(SB), NOPTR, $8
TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R8
MOVD EDCHPXV(R8), R8
MOVD R8, zosLibVec<>(SB)
RET
TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVD zosLibVec<>(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·clearErrno(SB), NOSPLIT, $0-0
BL addrerrno<>(SB)
MOVD $0, 0(R3)
RET
// Returns the address of errno in R3.
TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0
TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
@ -35,7 +60,7 @@ TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0
// Get __errno FuncDesc.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
ADD $(0x156*16), R9
ADD $(__errno), R9
LMG 0(R9), R5, R6
// Switch to saved LE stack.
@ -52,298 +77,8 @@ TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0
MOVD R4, 0(R9) // Save stack pointer.
RET
TEXT ·syscall_syscall(SB),NOSPLIT,$0-56
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+32(FP)
MOVD R0, r2+40(FP)
MOVD R0, err+48(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall(SB),NOSPLIT,$0-56
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+32(FP)
MOVD R0, r2+40(FP)
MOVD R0, err+48(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
done:
RET
TEXT ·syscall_syscall6(SB),NOSPLIT,$0-80
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+56(FP)
MOVD R0, r2+64(FP)
MOVD R0, err+72(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+72(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall6(SB),NOSPLIT,$0-80
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+56(FP)
MOVD R0, r2+64(FP)
MOVD R0, err+72(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL ·rrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+72(FP)
done:
RET
TEXT ·syscall_syscall9(SB),NOSPLIT,$0
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
MOVD a7+56(FP), R12
MOVD R12, (2176+48)(R4)
MOVD a8+64(FP), R12
MOVD R12, (2176+56)(R4)
MOVD a9+72(FP), R12
MOVD R12, (2176+64)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+80(FP)
MOVD R0, r2+88(FP)
MOVD R0, err+96(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+96(FP)
done:
BL runtime·exitsyscall(SB)
RET
TEXT ·syscall_rawsyscall9(SB),NOSPLIT,$0
MOVD a1+8(FP), R1
MOVD a2+16(FP), R2
MOVD a3+24(FP), R3
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get function.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
MOVD trap+0(FP), R5
SLD $4, R5
ADD R5, R9
LMG 0(R9), R5, R6
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Fill in parameter list.
MOVD a4+32(FP), R12
MOVD R12, (2176+24)(R4)
MOVD a5+40(FP), R12
MOVD R12, (2176+32)(R4)
MOVD a6+48(FP), R12
MOVD R12, (2176+40)(R4)
MOVD a7+56(FP), R12
MOVD R12, (2176+48)(R4)
MOVD a8+64(FP), R12
MOVD R12, (2176+56)(R4)
MOVD a9+72(FP), R12
MOVD R12, (2176+64)(R4)
// Call function.
LE_CALL
NOPH
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
MOVD R3, r1+80(FP)
MOVD R0, r2+88(FP)
MOVD R0, err+96(FP)
MOVW R3, R4
CMP R4, $-1
BNE done
BL addrerrno<>(SB)
MOVWZ 0(R3), R3
MOVD R3, err+96(FP)
done:
RET
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
TEXT ·svcCall(SB),NOSPLIT,$0
TEXT ·svcCall(SB), NOSPLIT, $0
BL runtime·save_g(SB) // Save g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
@ -366,13 +101,12 @@ TEXT ·svcCall(SB),NOSPLIT,$0
RET
// func svcLoad(name *byte) unsafe.Pointer
TEXT ·svcLoad(SB),NOSPLIT,$0
TEXT ·svcLoad(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD $0x80000000, R1
MOVD $0, R15
BYTE $0x0A // SVC 08 LOAD
BYTE $0x08
SVC_LOAD
MOVW R15, R3 // Save return code from SVC
MOVD R2, R15 // Restore go stack pointer
CMP R3, $0 // Check SVC return code
@ -380,33 +114,32 @@ TEXT ·svcLoad(SB),NOSPLIT,$0
MOVD $-2, R3 // Reset last bit of entry point to zero
AND R0, R3
MOVD R3, addr+8(FP) // Return entry point returned by SVC
MOVD R3, ret+8(FP) // Return entry point returned by SVC
CMP R0, R3 // Check if last bit of entry point was set
BNE done
MOVD R15, R2 // Save go stack pointer
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
BYTE $0x0A // SVC 09 DELETE
BYTE $0x09
SVC_DELETE
MOVD R2, R15 // Restore go stack pointer
error:
MOVD $0, addr+8(FP) // Return 0 on failure
MOVD $0, ret+8(FP) // Return 0 on failure
done:
XOR R0, R0 // Reset r0 to 0
RET
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
TEXT ·svcUnload(SB),NOSPLIT,$0
TEXT ·svcUnload(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD addr+8(FP), R15
BYTE $0x0A // SVC 09
BYTE $0x09
MOVD fnptr+8(FP), R15
SVC_DELETE
XOR R0, R0 // Reset r0 to 0
MOVD R15, R1 // Save SVC return code
MOVD R2, R15 // Restore go stack pointer
MOVD R1, rc+0(FP) // Return SVC return code
MOVD R1, ret+16(FP) // Return SVC return code
RET
// func gettid() uint64
@ -417,7 +150,233 @@ TEXT ·gettid(SB), NOSPLIT, $0
// Get CEECAATHDID
MOVD CAA(R8), R9
MOVD 0x3D0(R9), R9
MOVD CEECAATHDID(R9), R9
MOVD R9, ret+0(FP)
RET
//
// Call LE function, if the return is -1
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $-1 // compare result to -1
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// Call LE function, if the return is 0
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $0 // compare result to 0
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
XOR R2, R2
MOVWZ R2, (R3) // clear errno2
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// function to test if a pointer can be safely dereferenced (content read)
// return 0 for succces
//
TEXT ·ptrtest(SB), NOSPLIT, $0-16
MOVD arg+0(FP), R10 // test pointer in R10
// set up R2 to point to CEECAADMC
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
// set up R5 to point to the "shunt" path which set 1 to R3 (failure)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
// if r3 is not zero (failed) then branch to finish
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
// stomic store shunt address in R5 into CEECAADMC
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
// now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
// finish here, restore 0 into CEECAADMC
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R3, ret+8(FP) // result in R3
RET
//
// function to test if a untptr can be loaded from a pointer
// return 1: the 8-byte content
// 2: 0 for success, 1 for failure
//
// func safeload(ptr uintptr) ( value uintptr, error uintptr)
TEXT ·safeload(SB), NOSPLIT, $0-24
MOVD ptr+0(FP), R10 // test pointer in R10
MOVD $0x0, R6
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R6, value+8(FP) // result in R6
MOVD R3, error+16(FP) // error in R3
RET

View File

@ -0,0 +1,657 @@
// Copyright 2024 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 zos
package unix
import (
"bytes"
"fmt"
"unsafe"
)
//go:noescape
func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
//go:noescape
func A2e([]byte)
//go:noescape
func E2a([]byte)
const (
BPX4STA = 192 // stat
BPX4FST = 104 // fstat
BPX4LST = 132 // lstat
BPX4OPN = 156 // open
BPX4CLO = 72 // close
BPX4CHR = 500 // chattr
BPX4FCR = 504 // fchattr
BPX4LCR = 1180 // lchattr
BPX4CTW = 492 // cond_timed_wait
BPX4GTH = 1056 // __getthent
BPX4PTQ = 412 // pthread_quiesc
BPX4PTR = 320 // ptrace
)
const (
//options
//byte1
BPX_OPNFHIGH = 0x80
//byte2
BPX_OPNFEXEC = 0x80
//byte3
BPX_O_NOLARGEFILE = 0x08
BPX_O_LARGEFILE = 0x04
BPX_O_ASYNCSIG = 0x02
BPX_O_SYNC = 0x01
//byte4
BPX_O_CREXCL = 0xc0
BPX_O_CREAT = 0x80
BPX_O_EXCL = 0x40
BPX_O_NOCTTY = 0x20
BPX_O_TRUNC = 0x10
BPX_O_APPEND = 0x08
BPX_O_NONBLOCK = 0x04
BPX_FNDELAY = 0x04
BPX_O_RDWR = 0x03
BPX_O_RDONLY = 0x02
BPX_O_WRONLY = 0x01
BPX_O_ACCMODE = 0x03
BPX_O_GETFL = 0x0f
//mode
// byte1 (file type)
BPX_FT_DIR = 1
BPX_FT_CHARSPEC = 2
BPX_FT_REGFILE = 3
BPX_FT_FIFO = 4
BPX_FT_SYMLINK = 5
BPX_FT_SOCKET = 6
//byte3
BPX_S_ISUID = 0x08
BPX_S_ISGID = 0x04
BPX_S_ISVTX = 0x02
BPX_S_IRWXU1 = 0x01
BPX_S_IRUSR = 0x01
//byte4
BPX_S_IRWXU2 = 0xc0
BPX_S_IWUSR = 0x80
BPX_S_IXUSR = 0x40
BPX_S_IRWXG = 0x38
BPX_S_IRGRP = 0x20
BPX_S_IWGRP = 0x10
BPX_S_IXGRP = 0x08
BPX_S_IRWXOX = 0x07
BPX_S_IROTH = 0x04
BPX_S_IWOTH = 0x02
BPX_S_IXOTH = 0x01
CW_INTRPT = 1
CW_CONDVAR = 32
CW_TIMEOUT = 64
PGTHA_NEXT = 2
PGTHA_CURRENT = 1
PGTHA_FIRST = 0
PGTHA_LAST = 3
PGTHA_PROCESS = 0x80
PGTHA_CONTTY = 0x40
PGTHA_PATH = 0x20
PGTHA_COMMAND = 0x10
PGTHA_FILEDATA = 0x08
PGTHA_THREAD = 0x04
PGTHA_PTAG = 0x02
PGTHA_COMMANDLONG = 0x01
PGTHA_THREADFAST = 0x80
PGTHA_FILEPATH = 0x40
PGTHA_THDSIGMASK = 0x20
// thread quiece mode
QUIESCE_TERM int32 = 1
QUIESCE_FORCE int32 = 2
QUIESCE_QUERY int32 = 3
QUIESCE_FREEZE int32 = 4
QUIESCE_UNFREEZE int32 = 5
FREEZE_THIS_THREAD int32 = 6
FREEZE_EXIT int32 = 8
QUIESCE_SRB int32 = 9
)
type Pgtha struct {
Pid uint32 // 0
Tid0 uint32 // 4
Tid1 uint32
Accesspid byte // C
Accesstid byte // D
Accessasid uint16 // E
Loginname [8]byte // 10
Flag1 byte // 18
Flag1b2 byte // 19
}
type Bpxystat_t struct { // DSECT BPXYSTAT
St_id [4]uint8 // 0
St_length uint16 // 0x4
St_version uint16 // 0x6
St_mode uint32 // 0x8
St_ino uint32 // 0xc
St_dev uint32 // 0x10
St_nlink uint32 // 0x14
St_uid uint32 // 0x18
St_gid uint32 // 0x1c
St_size uint64 // 0x20
St_atime uint32 // 0x28
St_mtime uint32 // 0x2c
St_ctime uint32 // 0x30
St_rdev uint32 // 0x34
St_auditoraudit uint32 // 0x38
St_useraudit uint32 // 0x3c
St_blksize uint32 // 0x40
St_createtime uint32 // 0x44
St_auditid [4]uint32 // 0x48
St_res01 uint32 // 0x58
Ft_ccsid uint16 // 0x5c
Ft_flags uint16 // 0x5e
St_res01a [2]uint32 // 0x60
St_res02 uint32 // 0x68
St_blocks uint32 // 0x6c
St_opaque [3]uint8 // 0x70
St_visible uint8 // 0x73
St_reftime uint32 // 0x74
St_fid uint64 // 0x78
St_filefmt uint8 // 0x80
St_fspflag2 uint8 // 0x81
St_res03 [2]uint8 // 0x82
St_ctimemsec uint32 // 0x84
St_seclabel [8]uint8 // 0x88
St_res04 [4]uint8 // 0x90
// end of version 1
_ uint32 // 0x94
St_atime64 uint64 // 0x98
St_mtime64 uint64 // 0xa0
St_ctime64 uint64 // 0xa8
St_createtime64 uint64 // 0xb0
St_reftime64 uint64 // 0xb8
_ uint64 // 0xc0
St_res05 [16]uint8 // 0xc8
// end of version 2
}
type BpxFilestatus struct {
Oflag1 byte
Oflag2 byte
Oflag3 byte
Oflag4 byte
}
type BpxMode struct {
Ftype byte
Mode1 byte
Mode2 byte
Mode3 byte
}
// Thr attribute structure for extended attributes
type Bpxyatt_t struct { // DSECT BPXYATT
Att_id [4]uint8
Att_version uint16
Att_res01 [2]uint8
Att_setflags1 uint8
Att_setflags2 uint8
Att_setflags3 uint8
Att_setflags4 uint8
Att_mode uint32
Att_uid uint32
Att_gid uint32
Att_opaquemask [3]uint8
Att_visblmaskres uint8
Att_opaque [3]uint8
Att_visibleres uint8
Att_size_h uint32
Att_size_l uint32
Att_atime uint32
Att_mtime uint32
Att_auditoraudit uint32
Att_useraudit uint32
Att_ctime uint32
Att_reftime uint32
// end of version 1
Att_filefmt uint8
Att_res02 [3]uint8
Att_filetag uint32
Att_res03 [8]uint8
// end of version 2
Att_atime64 uint64
Att_mtime64 uint64
Att_ctime64 uint64
Att_reftime64 uint64
Att_seclabel [8]uint8
Att_ver3res02 [8]uint8
// end of version 3
}
func BpxOpen(name string, options *BpxFilestatus, mode *BpxMode) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(options)
parms[3] = unsafe.Pointer(mode)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4OPN)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxClose(fd int32) (rv int32, rc int32, rn int32) {
var parms [4]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&rv)
parms[2] = unsafe.Pointer(&rc)
parms[3] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CLO)
return rv, rc, rn
}
func BpxFileFStat(fd int32, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [6]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&stat_sz)
parms[2] = unsafe.Pointer(st)
parms[3] = unsafe.Pointer(&rv)
parms[4] = unsafe.Pointer(&rc)
parms[5] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4FST)
return rv, rc, rn
}
func BpxFileStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&stat_sz)
parms[3] = unsafe.Pointer(st)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4STA)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxFileLStat(name string, st *Bpxystat_t) (rv int32, rc int32, rn int32) {
if len(name) < 1024 {
var namebuf [1024]byte
sz := int32(copy(namebuf[:], name))
A2e(namebuf[:sz])
st.St_id = [4]uint8{0xe2, 0xe3, 0xc1, 0xe3}
st.St_version = 2
stat_sz := uint32(unsafe.Sizeof(*st))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&stat_sz)
parms[3] = unsafe.Pointer(st)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4LST)
return rv, rc, rn
}
return -1, -1, -1
}
func BpxChattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
if len(path) >= 1024 {
return -1, -1, -1
}
var namebuf [1024]byte
sz := int32(copy(namebuf[:], path))
A2e(namebuf[:sz])
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&attr_sz)
parms[3] = unsafe.Pointer(attr)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CHR)
return rv, rc, rn
}
func BpxLchattr(path string, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
if len(path) >= 1024 {
return -1, -1, -1
}
var namebuf [1024]byte
sz := int32(copy(namebuf[:], path))
A2e(namebuf[:sz])
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [7]unsafe.Pointer
parms[0] = unsafe.Pointer(&sz)
parms[1] = unsafe.Pointer(&namebuf[0])
parms[2] = unsafe.Pointer(&attr_sz)
parms[3] = unsafe.Pointer(attr)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4LCR)
return rv, rc, rn
}
func BpxFchattr(fd int32, attr *Bpxyatt_t) (rv int32, rc int32, rn int32) {
attr_sz := uint32(unsafe.Sizeof(*attr))
var parms [6]unsafe.Pointer
parms[0] = unsafe.Pointer(&fd)
parms[1] = unsafe.Pointer(&attr_sz)
parms[2] = unsafe.Pointer(attr)
parms[3] = unsafe.Pointer(&rv)
parms[4] = unsafe.Pointer(&rc)
parms[5] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4FCR)
return rv, rc, rn
}
func BpxCondTimedWait(sec uint32, nsec uint32, events uint32, secrem *uint32, nsecrem *uint32) (rv int32, rc int32, rn int32) {
var parms [8]unsafe.Pointer
parms[0] = unsafe.Pointer(&sec)
parms[1] = unsafe.Pointer(&nsec)
parms[2] = unsafe.Pointer(&events)
parms[3] = unsafe.Pointer(secrem)
parms[4] = unsafe.Pointer(nsecrem)
parms[5] = unsafe.Pointer(&rv)
parms[6] = unsafe.Pointer(&rc)
parms[7] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4CTW)
return rv, rc, rn
}
func BpxGetthent(in *Pgtha, outlen *uint32, out unsafe.Pointer) (rv int32, rc int32, rn int32) {
var parms [7]unsafe.Pointer
inlen := uint32(26) // nothing else will work. Go says Pgtha is 28-byte because of alignment, but Pgtha is "packed" and must be 26-byte
parms[0] = unsafe.Pointer(&inlen)
parms[1] = unsafe.Pointer(&in)
parms[2] = unsafe.Pointer(outlen)
parms[3] = unsafe.Pointer(&out)
parms[4] = unsafe.Pointer(&rv)
parms[5] = unsafe.Pointer(&rc)
parms[6] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4GTH)
return rv, rc, rn
}
func ZosJobname() (jobname string, err error) {
var pgtha Pgtha
pgtha.Pid = uint32(Getpid())
pgtha.Accesspid = PGTHA_CURRENT
pgtha.Flag1 = PGTHA_PROCESS
var out [256]byte
var outlen uint32
outlen = 256
rv, rc, rn := BpxGetthent(&pgtha, &outlen, unsafe.Pointer(&out[0]))
if rv == 0 {
gthc := []byte{0x87, 0xa3, 0x88, 0x83} // 'gthc' in ebcdic
ix := bytes.Index(out[:], gthc)
if ix == -1 {
err = fmt.Errorf("BPX4GTH: gthc return data not found")
return
}
jn := out[ix+80 : ix+88] // we didn't declare Pgthc, but jobname is 8-byte at offset 80
E2a(jn)
jobname = string(bytes.TrimRight(jn, " "))
} else {
err = fmt.Errorf("BPX4GTH: rc=%d errno=%d reason=code=0x%x", rv, rc, rn)
}
return
}
func Bpx4ptq(code int32, data string) (rv int32, rc int32, rn int32) {
var userdata [8]byte
var parms [5]unsafe.Pointer
copy(userdata[:], data+" ")
A2e(userdata[:])
parms[0] = unsafe.Pointer(&code)
parms[1] = unsafe.Pointer(&userdata[0])
parms[2] = unsafe.Pointer(&rv)
parms[3] = unsafe.Pointer(&rc)
parms[4] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4PTQ)
return rv, rc, rn
}
const (
PT_TRACE_ME = 0 // Debug this process
PT_READ_I = 1 // Read a full word
PT_READ_D = 2 // Read a full word
PT_READ_U = 3 // Read control info
PT_WRITE_I = 4 //Write a full word
PT_WRITE_D = 5 //Write a full word
PT_CONTINUE = 7 //Continue the process
PT_KILL = 8 //Terminate the process
PT_READ_GPR = 11 // Read GPR, CR, PSW
PT_READ_FPR = 12 // Read FPR
PT_READ_VR = 13 // Read VR
PT_WRITE_GPR = 14 // Write GPR, CR, PSW
PT_WRITE_FPR = 15 // Write FPR
PT_WRITE_VR = 16 // Write VR
PT_READ_BLOCK = 17 // Read storage
PT_WRITE_BLOCK = 19 // Write storage
PT_READ_GPRH = 20 // Read GPRH
PT_WRITE_GPRH = 21 // Write GPRH
PT_REGHSET = 22 // Read all GPRHs
PT_ATTACH = 30 // Attach to a process
PT_DETACH = 31 // Detach from a process
PT_REGSET = 32 // Read all GPRs
PT_REATTACH = 33 // Reattach to a process
PT_LDINFO = 34 // Read loader info
PT_MULTI = 35 // Multi process mode
PT_LD64INFO = 36 // RMODE64 Info Area
PT_BLOCKREQ = 40 // Block request
PT_THREAD_INFO = 60 // Read thread info
PT_THREAD_MODIFY = 61
PT_THREAD_READ_FOCUS = 62
PT_THREAD_WRITE_FOCUS = 63
PT_THREAD_HOLD = 64
PT_THREAD_SIGNAL = 65
PT_EXPLAIN = 66
PT_EVENTS = 67
PT_THREAD_INFO_EXTENDED = 68
PT_REATTACH2 = 71
PT_CAPTURE = 72
PT_UNCAPTURE = 73
PT_GET_THREAD_TCB = 74
PT_GET_ALET = 75
PT_SWAPIN = 76
PT_EXTENDED_EVENT = 98
PT_RECOVER = 99 // Debug a program check
PT_GPR0 = 0 // General purpose register 0
PT_GPR1 = 1 // General purpose register 1
PT_GPR2 = 2 // General purpose register 2
PT_GPR3 = 3 // General purpose register 3
PT_GPR4 = 4 // General purpose register 4
PT_GPR5 = 5 // General purpose register 5
PT_GPR6 = 6 // General purpose register 6
PT_GPR7 = 7 // General purpose register 7
PT_GPR8 = 8 // General purpose register 8
PT_GPR9 = 9 // General purpose register 9
PT_GPR10 = 10 // General purpose register 10
PT_GPR11 = 11 // General purpose register 11
PT_GPR12 = 12 // General purpose register 12
PT_GPR13 = 13 // General purpose register 13
PT_GPR14 = 14 // General purpose register 14
PT_GPR15 = 15 // General purpose register 15
PT_FPR0 = 16 // Floating point register 0
PT_FPR1 = 17 // Floating point register 1
PT_FPR2 = 18 // Floating point register 2
PT_FPR3 = 19 // Floating point register 3
PT_FPR4 = 20 // Floating point register 4
PT_FPR5 = 21 // Floating point register 5
PT_FPR6 = 22 // Floating point register 6
PT_FPR7 = 23 // Floating point register 7
PT_FPR8 = 24 // Floating point register 8
PT_FPR9 = 25 // Floating point register 9
PT_FPR10 = 26 // Floating point register 10
PT_FPR11 = 27 // Floating point register 11
PT_FPR12 = 28 // Floating point register 12
PT_FPR13 = 29 // Floating point register 13
PT_FPR14 = 30 // Floating point register 14
PT_FPR15 = 31 // Floating point register 15
PT_FPC = 32 // Floating point control register
PT_PSW = 40 // PSW
PT_PSW0 = 40 // Left half of the PSW
PT_PSW1 = 41 // Right half of the PSW
PT_CR0 = 42 // Control register 0
PT_CR1 = 43 // Control register 1
PT_CR2 = 44 // Control register 2
PT_CR3 = 45 // Control register 3
PT_CR4 = 46 // Control register 4
PT_CR5 = 47 // Control register 5
PT_CR6 = 48 // Control register 6
PT_CR7 = 49 // Control register 7
PT_CR8 = 50 // Control register 8
PT_CR9 = 51 // Control register 9
PT_CR10 = 52 // Control register 10
PT_CR11 = 53 // Control register 11
PT_CR12 = 54 // Control register 12
PT_CR13 = 55 // Control register 13
PT_CR14 = 56 // Control register 14
PT_CR15 = 57 // Control register 15
PT_GPRH0 = 58 // GP High register 0
PT_GPRH1 = 59 // GP High register 1
PT_GPRH2 = 60 // GP High register 2
PT_GPRH3 = 61 // GP High register 3
PT_GPRH4 = 62 // GP High register 4
PT_GPRH5 = 63 // GP High register 5
PT_GPRH6 = 64 // GP High register 6
PT_GPRH7 = 65 // GP High register 7
PT_GPRH8 = 66 // GP High register 8
PT_GPRH9 = 67 // GP High register 9
PT_GPRH10 = 68 // GP High register 10
PT_GPRH11 = 69 // GP High register 11
PT_GPRH12 = 70 // GP High register 12
PT_GPRH13 = 71 // GP High register 13
PT_GPRH14 = 72 // GP High register 14
PT_GPRH15 = 73 // GP High register 15
PT_VR0 = 74 // Vector register 0
PT_VR1 = 75 // Vector register 1
PT_VR2 = 76 // Vector register 2
PT_VR3 = 77 // Vector register 3
PT_VR4 = 78 // Vector register 4
PT_VR5 = 79 // Vector register 5
PT_VR6 = 80 // Vector register 6
PT_VR7 = 81 // Vector register 7
PT_VR8 = 82 // Vector register 8
PT_VR9 = 83 // Vector register 9
PT_VR10 = 84 // Vector register 10
PT_VR11 = 85 // Vector register 11
PT_VR12 = 86 // Vector register 12
PT_VR13 = 87 // Vector register 13
PT_VR14 = 88 // Vector register 14
PT_VR15 = 89 // Vector register 15
PT_VR16 = 90 // Vector register 16
PT_VR17 = 91 // Vector register 17
PT_VR18 = 92 // Vector register 18
PT_VR19 = 93 // Vector register 19
PT_VR20 = 94 // Vector register 20
PT_VR21 = 95 // Vector register 21
PT_VR22 = 96 // Vector register 22
PT_VR23 = 97 // Vector register 23
PT_VR24 = 98 // Vector register 24
PT_VR25 = 99 // Vector register 25
PT_VR26 = 100 // Vector register 26
PT_VR27 = 101 // Vector register 27
PT_VR28 = 102 // Vector register 28
PT_VR29 = 103 // Vector register 29
PT_VR30 = 104 // Vector register 30
PT_VR31 = 105 // Vector register 31
PT_PSWG = 106 // PSWG
PT_PSWG0 = 106 // Bytes 0-3
PT_PSWG1 = 107 // Bytes 4-7
PT_PSWG2 = 108 // Bytes 8-11 (IA high word)
PT_PSWG3 = 109 // Bytes 12-15 (IA low word)
)
func Bpx4ptr(request int32, pid int32, addr unsafe.Pointer, data unsafe.Pointer, buffer unsafe.Pointer) (rv int32, rc int32, rn int32) {
var parms [8]unsafe.Pointer
parms[0] = unsafe.Pointer(&request)
parms[1] = unsafe.Pointer(&pid)
parms[2] = unsafe.Pointer(&addr)
parms[3] = unsafe.Pointer(&data)
parms[4] = unsafe.Pointer(&buffer)
parms[5] = unsafe.Pointer(&rv)
parms[6] = unsafe.Pointer(&rc)
parms[7] = unsafe.Pointer(&rn)
bpxcall(parms[:], BPX4PTR)
return rv, rc, rn
}
func copyU8(val uint8, dest []uint8) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU8Arr(src, dest []uint8) int {
if len(dest) < len(src) {
return 0
}
for i, v := range src {
dest[i] = v
}
return len(src)
}
func copyU16(val uint16, dest []uint16) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU32(val uint32, dest []uint32) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}
func copyU32Arr(src, dest []uint32) int {
if len(dest) < len(src) {
return 0
}
for i, v := range src {
dest[i] = v
}
return len(src)
}
func copyU64(val uint64, dest []uint64) int {
if len(dest) < 1 {
return 0
}
dest[0] = val
return 1
}

View File

@ -0,0 +1,192 @@
// Copyright 2024 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.
#include "go_asm.h"
#include "textflag.h"
// function to call USS assembly language services
//
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bit64env.htm
//
// arg1 unsafe.Pointer array that ressembles an OS PLIST
//
// arg2 function offset as in
// doc: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_3.1.0/com.ibm.zos.v3r1.bpxb100/bpx2cr_List_of_offsets.htm
//
// func bpxcall(plist []unsafe.Pointer, bpx_offset int64)
TEXT ·bpxcall(SB), NOSPLIT|NOFRAME, $0
MOVD plist_base+0(FP), R1 // r1 points to plist
MOVD bpx_offset+24(FP), R2 // r2 offset to BPX vector table
MOVD R14, R7 // save r14
MOVD R15, R8 // save r15
MOVWZ 16(R0), R9
MOVWZ 544(R9), R9
MOVWZ 24(R9), R9 // call vector in r9
ADD R2, R9 // add offset to vector table
MOVWZ (R9), R9 // r9 points to entry point
BYTE $0x0D // BL R14,R9 --> basr r14,r9
BYTE $0xE9 // clobbers 0,1,14,15
MOVD R8, R15 // restore 15
JMP R7 // return via saved return address
// func A2e(arr [] byte)
// code page conversion from 819 to 1047
TEXT ·A2e(SB), NOSPLIT|NOFRAME, $0
MOVD arg_base+0(FP), R2 // pointer to arry of characters
MOVD arg_len+8(FP), R3 // count
XOR R0, R0
XOR R1, R1
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
// ASCII -> EBCDIC conversion table:
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
BYTE $0x37; BYTE $0x2d; BYTE $0x2e; BYTE $0x2f
BYTE $0x16; BYTE $0x05; BYTE $0x15; BYTE $0x0b
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
BYTE $0x3c; BYTE $0x3d; BYTE $0x32; BYTE $0x26
BYTE $0x18; BYTE $0x19; BYTE $0x3f; BYTE $0x27
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
BYTE $0x40; BYTE $0x5a; BYTE $0x7f; BYTE $0x7b
BYTE $0x5b; BYTE $0x6c; BYTE $0x50; BYTE $0x7d
BYTE $0x4d; BYTE $0x5d; BYTE $0x5c; BYTE $0x4e
BYTE $0x6b; BYTE $0x60; BYTE $0x4b; BYTE $0x61
BYTE $0xf0; BYTE $0xf1; BYTE $0xf2; BYTE $0xf3
BYTE $0xf4; BYTE $0xf5; BYTE $0xf6; BYTE $0xf7
BYTE $0xf8; BYTE $0xf9; BYTE $0x7a; BYTE $0x5e
BYTE $0x4c; BYTE $0x7e; BYTE $0x6e; BYTE $0x6f
BYTE $0x7c; BYTE $0xc1; BYTE $0xc2; BYTE $0xc3
BYTE $0xc4; BYTE $0xc5; BYTE $0xc6; BYTE $0xc7
BYTE $0xc8; BYTE $0xc9; BYTE $0xd1; BYTE $0xd2
BYTE $0xd3; BYTE $0xd4; BYTE $0xd5; BYTE $0xd6
BYTE $0xd7; BYTE $0xd8; BYTE $0xd9; BYTE $0xe2
BYTE $0xe3; BYTE $0xe4; BYTE $0xe5; BYTE $0xe6
BYTE $0xe7; BYTE $0xe8; BYTE $0xe9; BYTE $0xad
BYTE $0xe0; BYTE $0xbd; BYTE $0x5f; BYTE $0x6d
BYTE $0x79; BYTE $0x81; BYTE $0x82; BYTE $0x83
BYTE $0x84; BYTE $0x85; BYTE $0x86; BYTE $0x87
BYTE $0x88; BYTE $0x89; BYTE $0x91; BYTE $0x92
BYTE $0x93; BYTE $0x94; BYTE $0x95; BYTE $0x96
BYTE $0x97; BYTE $0x98; BYTE $0x99; BYTE $0xa2
BYTE $0xa3; BYTE $0xa4; BYTE $0xa5; BYTE $0xa6
BYTE $0xa7; BYTE $0xa8; BYTE $0xa9; BYTE $0xc0
BYTE $0x4f; BYTE $0xd0; BYTE $0xa1; BYTE $0x07
BYTE $0x20; BYTE $0x21; BYTE $0x22; BYTE $0x23
BYTE $0x24; BYTE $0x25; BYTE $0x06; BYTE $0x17
BYTE $0x28; BYTE $0x29; BYTE $0x2a; BYTE $0x2b
BYTE $0x2c; BYTE $0x09; BYTE $0x0a; BYTE $0x1b
BYTE $0x30; BYTE $0x31; BYTE $0x1a; BYTE $0x33
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x08
BYTE $0x38; BYTE $0x39; BYTE $0x3a; BYTE $0x3b
BYTE $0x04; BYTE $0x14; BYTE $0x3e; BYTE $0xff
BYTE $0x41; BYTE $0xaa; BYTE $0x4a; BYTE $0xb1
BYTE $0x9f; BYTE $0xb2; BYTE $0x6a; BYTE $0xb5
BYTE $0xbb; BYTE $0xb4; BYTE $0x9a; BYTE $0x8a
BYTE $0xb0; BYTE $0xca; BYTE $0xaf; BYTE $0xbc
BYTE $0x90; BYTE $0x8f; BYTE $0xea; BYTE $0xfa
BYTE $0xbe; BYTE $0xa0; BYTE $0xb6; BYTE $0xb3
BYTE $0x9d; BYTE $0xda; BYTE $0x9b; BYTE $0x8b
BYTE $0xb7; BYTE $0xb8; BYTE $0xb9; BYTE $0xab
BYTE $0x64; BYTE $0x65; BYTE $0x62; BYTE $0x66
BYTE $0x63; BYTE $0x67; BYTE $0x9e; BYTE $0x68
BYTE $0x74; BYTE $0x71; BYTE $0x72; BYTE $0x73
BYTE $0x78; BYTE $0x75; BYTE $0x76; BYTE $0x77
BYTE $0xac; BYTE $0x69; BYTE $0xed; BYTE $0xee
BYTE $0xeb; BYTE $0xef; BYTE $0xec; BYTE $0xbf
BYTE $0x80; BYTE $0xfd; BYTE $0xfe; BYTE $0xfb
BYTE $0xfc; BYTE $0xba; BYTE $0xae; BYTE $0x59
BYTE $0x44; BYTE $0x45; BYTE $0x42; BYTE $0x46
BYTE $0x43; BYTE $0x47; BYTE $0x9c; BYTE $0x48
BYTE $0x54; BYTE $0x51; BYTE $0x52; BYTE $0x53
BYTE $0x58; BYTE $0x55; BYTE $0x56; BYTE $0x57
BYTE $0x8c; BYTE $0x49; BYTE $0xcd; BYTE $0xce
BYTE $0xcb; BYTE $0xcf; BYTE $0xcc; BYTE $0xe1
BYTE $0x70; BYTE $0xdd; BYTE $0xde; BYTE $0xdb
BYTE $0xdc; BYTE $0x8d; BYTE $0x8e; BYTE $0xdf
retry:
WORD $0xB9931022 // TROO 2,2,b'0001'
BVS retry
RET
// func e2a(arr [] byte)
// code page conversion from 1047 to 819
TEXT ·E2a(SB), NOSPLIT|NOFRAME, $0
MOVD arg_base+0(FP), R2 // pointer to arry of characters
MOVD arg_len+8(FP), R3 // count
XOR R0, R0
XOR R1, R1
BYTE $0xA7; BYTE $0x15; BYTE $0x00; BYTE $0x82 // BRAS 1,(2+(256/2))
// EBCDIC -> ASCII conversion table:
BYTE $0x00; BYTE $0x01; BYTE $0x02; BYTE $0x03
BYTE $0x9c; BYTE $0x09; BYTE $0x86; BYTE $0x7f
BYTE $0x97; BYTE $0x8d; BYTE $0x8e; BYTE $0x0b
BYTE $0x0c; BYTE $0x0d; BYTE $0x0e; BYTE $0x0f
BYTE $0x10; BYTE $0x11; BYTE $0x12; BYTE $0x13
BYTE $0x9d; BYTE $0x0a; BYTE $0x08; BYTE $0x87
BYTE $0x18; BYTE $0x19; BYTE $0x92; BYTE $0x8f
BYTE $0x1c; BYTE $0x1d; BYTE $0x1e; BYTE $0x1f
BYTE $0x80; BYTE $0x81; BYTE $0x82; BYTE $0x83
BYTE $0x84; BYTE $0x85; BYTE $0x17; BYTE $0x1b
BYTE $0x88; BYTE $0x89; BYTE $0x8a; BYTE $0x8b
BYTE $0x8c; BYTE $0x05; BYTE $0x06; BYTE $0x07
BYTE $0x90; BYTE $0x91; BYTE $0x16; BYTE $0x93
BYTE $0x94; BYTE $0x95; BYTE $0x96; BYTE $0x04
BYTE $0x98; BYTE $0x99; BYTE $0x9a; BYTE $0x9b
BYTE $0x14; BYTE $0x15; BYTE $0x9e; BYTE $0x1a
BYTE $0x20; BYTE $0xa0; BYTE $0xe2; BYTE $0xe4
BYTE $0xe0; BYTE $0xe1; BYTE $0xe3; BYTE $0xe5
BYTE $0xe7; BYTE $0xf1; BYTE $0xa2; BYTE $0x2e
BYTE $0x3c; BYTE $0x28; BYTE $0x2b; BYTE $0x7c
BYTE $0x26; BYTE $0xe9; BYTE $0xea; BYTE $0xeb
BYTE $0xe8; BYTE $0xed; BYTE $0xee; BYTE $0xef
BYTE $0xec; BYTE $0xdf; BYTE $0x21; BYTE $0x24
BYTE $0x2a; BYTE $0x29; BYTE $0x3b; BYTE $0x5e
BYTE $0x2d; BYTE $0x2f; BYTE $0xc2; BYTE $0xc4
BYTE $0xc0; BYTE $0xc1; BYTE $0xc3; BYTE $0xc5
BYTE $0xc7; BYTE $0xd1; BYTE $0xa6; BYTE $0x2c
BYTE $0x25; BYTE $0x5f; BYTE $0x3e; BYTE $0x3f
BYTE $0xf8; BYTE $0xc9; BYTE $0xca; BYTE $0xcb
BYTE $0xc8; BYTE $0xcd; BYTE $0xce; BYTE $0xcf
BYTE $0xcc; BYTE $0x60; BYTE $0x3a; BYTE $0x23
BYTE $0x40; BYTE $0x27; BYTE $0x3d; BYTE $0x22
BYTE $0xd8; BYTE $0x61; BYTE $0x62; BYTE $0x63
BYTE $0x64; BYTE $0x65; BYTE $0x66; BYTE $0x67
BYTE $0x68; BYTE $0x69; BYTE $0xab; BYTE $0xbb
BYTE $0xf0; BYTE $0xfd; BYTE $0xfe; BYTE $0xb1
BYTE $0xb0; BYTE $0x6a; BYTE $0x6b; BYTE $0x6c
BYTE $0x6d; BYTE $0x6e; BYTE $0x6f; BYTE $0x70
BYTE $0x71; BYTE $0x72; BYTE $0xaa; BYTE $0xba
BYTE $0xe6; BYTE $0xb8; BYTE $0xc6; BYTE $0xa4
BYTE $0xb5; BYTE $0x7e; BYTE $0x73; BYTE $0x74
BYTE $0x75; BYTE $0x76; BYTE $0x77; BYTE $0x78
BYTE $0x79; BYTE $0x7a; BYTE $0xa1; BYTE $0xbf
BYTE $0xd0; BYTE $0x5b; BYTE $0xde; BYTE $0xae
BYTE $0xac; BYTE $0xa3; BYTE $0xa5; BYTE $0xb7
BYTE $0xa9; BYTE $0xa7; BYTE $0xb6; BYTE $0xbc
BYTE $0xbd; BYTE $0xbe; BYTE $0xdd; BYTE $0xa8
BYTE $0xaf; BYTE $0x5d; BYTE $0xb4; BYTE $0xd7
BYTE $0x7b; BYTE $0x41; BYTE $0x42; BYTE $0x43
BYTE $0x44; BYTE $0x45; BYTE $0x46; BYTE $0x47
BYTE $0x48; BYTE $0x49; BYTE $0xad; BYTE $0xf4
BYTE $0xf6; BYTE $0xf2; BYTE $0xf3; BYTE $0xf5
BYTE $0x7d; BYTE $0x4a; BYTE $0x4b; BYTE $0x4c
BYTE $0x4d; BYTE $0x4e; BYTE $0x4f; BYTE $0x50
BYTE $0x51; BYTE $0x52; BYTE $0xb9; BYTE $0xfb
BYTE $0xfc; BYTE $0xf9; BYTE $0xfa; BYTE $0xff
BYTE $0x5c; BYTE $0xf7; BYTE $0x53; BYTE $0x54
BYTE $0x55; BYTE $0x56; BYTE $0x57; BYTE $0x58
BYTE $0x59; BYTE $0x5a; BYTE $0xb2; BYTE $0xd4
BYTE $0xd6; BYTE $0xd2; BYTE $0xd3; BYTE $0xd5
BYTE $0x30; BYTE $0x31; BYTE $0x32; BYTE $0x33
BYTE $0x34; BYTE $0x35; BYTE $0x36; BYTE $0x37
BYTE $0x38; BYTE $0x39; BYTE $0xb3; BYTE $0xdb
BYTE $0xdc; BYTE $0xd9; BYTE $0xda; BYTE $0x9f
retry:
WORD $0xB9931022 // TROO 2,2,b'0001'
BVS retry
RET

View File

@ -1,220 +0,0 @@
// Copyright 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 zos && s390x
package unix
import (
"sync"
)
// This file simulates epoll on z/OS using poll.
// Analogous to epoll_event on Linux.
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
type EpollEvent struct {
Events uint32
Fd int32
Pad int32
}
const (
EPOLLERR = 0x8
EPOLLHUP = 0x10
EPOLLIN = 0x1
EPOLLMSG = 0x400
EPOLLOUT = 0x4
EPOLLPRI = 0x2
EPOLLRDBAND = 0x80
EPOLLRDNORM = 0x40
EPOLLWRBAND = 0x200
EPOLLWRNORM = 0x100
EPOLL_CTL_ADD = 0x1
EPOLL_CTL_DEL = 0x2
EPOLL_CTL_MOD = 0x3
// The following constants are part of the epoll API, but represent
// currently unsupported functionality on z/OS.
// EPOLL_CLOEXEC = 0x80000
// EPOLLET = 0x80000000
// EPOLLONESHOT = 0x40000000
// EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis
// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
// EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
)
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
// epToPollEvt converts epoll event field to poll equivalent.
// In epoll, Events is a 32-bit field, while poll uses 16 bits.
func epToPollEvt(events uint32) int16 {
var ep2p = map[uint32]int16{
EPOLLIN: POLLIN,
EPOLLOUT: POLLOUT,
EPOLLHUP: POLLHUP,
EPOLLPRI: POLLPRI,
EPOLLERR: POLLERR,
}
var pollEvts int16 = 0
for epEvt, pEvt := range ep2p {
if (events & epEvt) != 0 {
pollEvts |= pEvt
}
}
return pollEvts
}
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
func pToEpollEvt(revents int16) uint32 {
var p2ep = map[int16]uint32{
POLLIN: EPOLLIN,
POLLOUT: EPOLLOUT,
POLLHUP: EPOLLHUP,
POLLPRI: EPOLLPRI,
POLLERR: EPOLLERR,
}
var epollEvts uint32 = 0
for pEvt, epEvt := range p2ep {
if (revents & pEvt) != 0 {
epollEvts |= epEvt
}
}
return epollEvts
}
// Per-process epoll implementation.
type epollImpl struct {
mu sync.Mutex
epfd2ep map[int]*eventPoll
nextEpfd int
}
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
// On Linux, this is an in-kernel data structure accessed through a fd.
type eventPoll struct {
mu sync.Mutex
fds map[int]*EpollEvent
}
// epoll impl for this process.
var impl epollImpl = epollImpl{
epfd2ep: make(map[int]*eventPoll),
nextEpfd: 0,
}
func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
e.mu.Lock()
defer e.mu.Unlock()
epfd = e.nextEpfd
e.nextEpfd++
e.epfd2ep[epfd] = &eventPoll{
fds: make(map[int]*EpollEvent),
}
return epfd, nil
}
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
return e.epollcreate(4)
}
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
e.mu.Lock()
defer e.mu.Unlock()
ep, ok := e.epfd2ep[epfd]
if !ok {
return EBADF
}
switch op {
case EPOLL_CTL_ADD:
// TODO(neeilan): When we make epfds and fds disjoint, detect epoll
// loops here (instances watching each other) and return ELOOP.
if _, ok := ep.fds[fd]; ok {
return EEXIST
}
ep.fds[fd] = event
case EPOLL_CTL_MOD:
if _, ok := ep.fds[fd]; !ok {
return ENOENT
}
ep.fds[fd] = event
case EPOLL_CTL_DEL:
if _, ok := ep.fds[fd]; !ok {
return ENOENT
}
delete(ep.fds, fd)
}
return nil
}
// Must be called while holding ep.mu
func (ep *eventPoll) getFds() []int {
fds := make([]int, len(ep.fds))
for fd := range ep.fds {
fds = append(fds, fd)
}
return fds
}
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
ep, ok := e.epfd2ep[epfd]
if !ok {
e.mu.Unlock()
return 0, EBADF
}
pollfds := make([]PollFd, 4)
for fd, epollevt := range ep.fds {
pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
}
e.mu.Unlock()
n, err = Poll(pollfds, msec)
if err != nil {
return n, err
}
i := 0
for _, pFd := range pollfds {
if pFd.Revents != 0 {
events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
i++
}
if i == n {
break
}
}
return n, nil
}
func EpollCreate(size int) (fd int, err error) {
return impl.epollcreate(size)
}
func EpollCreate1(flag int) (fd int, err error) {
return impl.epollcreate1(flag)
}
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
return impl.epollctl(epfd, op, fd, event)
}
// Because EpollWait mutates events, the caller is expected to coordinate
// concurrent access if calling with the same epfd from multiple goroutines.
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
return impl.epollwait(epfd, events, msec)
}

View File

@ -1,163 +0,0 @@
// Copyright 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 zos && s390x
package unix
import (
"unsafe"
)
// This file simulates fstatfs on z/OS using fstatvfs and w_getmntent.
func Fstatfs(fd int, stat *Statfs_t) (err error) {
var stat_v Statvfs_t
err = Fstatvfs(fd, &stat_v)
if err == nil {
// populate stat
stat.Type = 0
stat.Bsize = stat_v.Bsize
stat.Blocks = stat_v.Blocks
stat.Bfree = stat_v.Bfree
stat.Bavail = stat_v.Bavail
stat.Files = stat_v.Files
stat.Ffree = stat_v.Ffree
stat.Fsid = stat_v.Fsid
stat.Namelen = stat_v.Namemax
stat.Frsize = stat_v.Frsize
stat.Flags = stat_v.Flag
for passn := 0; passn < 5; passn++ {
switch passn {
case 0:
err = tryGetmntent64(stat)
break
case 1:
err = tryGetmntent128(stat)
break
case 2:
err = tryGetmntent256(stat)
break
case 3:
err = tryGetmntent512(stat)
break
case 4:
err = tryGetmntent1024(stat)
break
default:
break
}
//proceed to return if: err is nil (found), err is nonnil but not ERANGE (another error occurred)
if err == nil || err != nil && err != ERANGE {
break
}
}
}
return err
}
func tryGetmntent64(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [64]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent128(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [128]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent256(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [256]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent512(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [512]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}
func tryGetmntent1024(stat *Statfs_t) (err error) {
var mnt_ent_buffer struct {
header W_Mnth
filesys_info [1024]W_Mntent
}
var buffer_size int = int(unsafe.Sizeof(mnt_ent_buffer))
fs_count, err := W_Getmntent((*byte)(unsafe.Pointer(&mnt_ent_buffer)), buffer_size)
if err != nil {
return err
}
err = ERANGE //return ERANGE if no match is found in this batch
for i := 0; i < fs_count; i++ {
if stat.Fsid == uint64(mnt_ent_buffer.filesys_info[i].Dev) {
stat.Type = uint32(mnt_ent_buffer.filesys_info[i].Fstname[0])
err = nil
break
}
}
return err
}

View File

@ -584,7 +584,7 @@ ccflags="$@"
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ ||
$2 ~ /^SECCOMP_MODE_/ ||
$2 ~ /^SECCOMP_/ ||
$2 ~ /^SEEK_/ ||
$2 ~ /^SCHED_/ ||
$2 ~ /^SPLICE_/ ||

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris
//go:build aix || darwin || dragonfly || freebsd || openbsd || solaris || zos
package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// For Unix, get the pagesize from the runtime.

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin
//go:build darwin || zos
package unix

View File

@ -0,0 +1,58 @@
// Copyright 2024 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.
// Socket control messages
package unix
import "unsafe"
// UnixCredentials encodes credentials into a socket control message
// for sending to another process. This can be used for
// authentication.
func UnixCredentials(ucred *Ucred) []byte {
b := make([]byte, CmsgSpace(SizeofUcred))
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
h.Level = SOL_SOCKET
h.Type = SCM_CREDENTIALS
h.SetLen(CmsgLen(SizeofUcred))
*(*Ucred)(h.data(0)) = *ucred
return b
}
// ParseUnixCredentials decodes a socket control message that contains
// credentials in a Ucred structure. To receive such a message, the
// SO_PASSCRED option must be enabled on the socket.
func ParseUnixCredentials(m *SocketControlMessage) (*Ucred, error) {
if m.Header.Level != SOL_SOCKET {
return nil, EINVAL
}
if m.Header.Type != SCM_CREDENTIALS {
return nil, EINVAL
}
ucred := *(*Ucred)(unsafe.Pointer(&m.Data[0]))
return &ucred, nil
}
// PktInfo4 encodes Inet4Pktinfo into a socket control message of type IP_PKTINFO.
func PktInfo4(info *Inet4Pktinfo) []byte {
b := make([]byte, CmsgSpace(SizeofInet4Pktinfo))
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
h.Level = SOL_IP
h.Type = IP_PKTINFO
h.SetLen(CmsgLen(SizeofInet4Pktinfo))
*(*Inet4Pktinfo)(h.data(0)) = *info
return b
}
// PktInfo6 encodes Inet6Pktinfo into a socket control message of type IPV6_PKTINFO.
func PktInfo6(info *Inet6Pktinfo) []byte {
b := make([]byte, CmsgSpace(SizeofInet6Pktinfo))
h := (*Cmsghdr)(unsafe.Pointer(&b[0]))
h.Level = SOL_IPV6
h.Type = IPV6_PKTINFO
h.SetLen(CmsgLen(SizeofInet6Pktinfo))
*(*Inet6Pktinfo)(h.data(0)) = *info
return b
}

View File

@ -0,0 +1,75 @@
// Copyright 2024 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 zos && s390x && gc
#include "textflag.h"
// provide the address of function variable to be fixed up.
TEXT ·getPipe2Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Pipe2(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_FlockAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Flock(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_GetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Getxattr(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_NanosleepAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Nanosleep(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_SetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Setxattr(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_Wait4Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Wait4(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_MountAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Mount(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_UnmountAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Unmount(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_UtimesNanoAtAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·UtimesNanoAt(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_UtimesNanoAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·UtimesNano(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_MkfifoatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Mkfifoat(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_ChtagAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Chtag(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·get_ReadlinkatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Readlinkat(SB), R8
MOVD R8, ret+0(FP)
RET

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin && go1.12
//go:build darwin
package unix

View File

@ -13,6 +13,7 @@
package unix
import (
"errors"
"sync"
"unsafe"
)
@ -169,25 +170,26 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
func Uname(uname *Utsname) error {
mib := []_C_int{CTL_KERN, KERN_OSTYPE}
n := unsafe.Sizeof(uname.Sysname)
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil {
// Suppress ENOMEM errors to be compatible with the C library __xuname() implementation.
if err := sysctl(mib, &uname.Sysname[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
return err
}
mib = []_C_int{CTL_KERN, KERN_HOSTNAME}
n = unsafe.Sizeof(uname.Nodename)
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil {
if err := sysctl(mib, &uname.Nodename[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
return err
}
mib = []_C_int{CTL_KERN, KERN_OSRELEASE}
n = unsafe.Sizeof(uname.Release)
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil {
if err := sysctl(mib, &uname.Release[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
return err
}
mib = []_C_int{CTL_KERN, KERN_VERSION}
n = unsafe.Sizeof(uname.Version)
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil {
if err := sysctl(mib, &uname.Version[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
return err
}
@ -205,7 +207,7 @@ func Uname(uname *Utsname) error {
mib = []_C_int{CTL_HW, HW_MACHINE}
n = unsafe.Sizeof(uname.Machine)
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil {
if err := sysctl(mib, &uname.Machine[0], &n, nil, 0); err != nil && !errors.Is(err, ENOMEM) {
return err
}

View File

@ -1849,6 +1849,105 @@ func Dup2(oldfd, newfd int) error {
//sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error)
//sys Fsopen(fsName string, flags int) (fd int, err error)
//sys Fspick(dirfd int, pathName string, flags int) (fd int, err error)
//sys fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error)
func fsconfigCommon(fd int, cmd uint, key string, value *byte, aux int) (err error) {
var keyp *byte
if keyp, err = BytePtrFromString(key); err != nil {
return
}
return fsconfig(fd, cmd, keyp, value, aux)
}
// FsconfigSetFlag is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_FLAG.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
func FsconfigSetFlag(fd int, key string) (err error) {
return fsconfigCommon(fd, FSCONFIG_SET_FLAG, key, nil, 0)
}
// FsconfigSetString is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_STRING.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is the parameter value to set.
func FsconfigSetString(fd int, key string, value string) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(value); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_STRING, key, valuep, 0)
}
// FsconfigSetBinary is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_BINARY.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is the parameter value to set.
func FsconfigSetBinary(fd int, key string, value []byte) (err error) {
if len(value) == 0 {
return EINVAL
}
return fsconfigCommon(fd, FSCONFIG_SET_BINARY, key, &value[0], len(value))
}
// FsconfigSetPath is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_PATH.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// path is a non-empty path for specified key.
// atfd is a file descriptor at which to start lookup from or AT_FDCWD.
func FsconfigSetPath(fd int, key string, path string, atfd int) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(path); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_PATH, key, valuep, atfd)
}
// FsconfigSetPathEmpty is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_PATH_EMPTY. The same as
// FconfigSetPath but with AT_PATH_EMPTY implied.
func FsconfigSetPathEmpty(fd int, key string, path string, atfd int) (err error) {
var valuep *byte
if valuep, err = BytePtrFromString(path); err != nil {
return
}
return fsconfigCommon(fd, FSCONFIG_SET_PATH_EMPTY, key, valuep, atfd)
}
// FsconfigSetFd is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_SET_FD.
//
// fd is the filesystem context to act upon.
// key the parameter key to set.
// value is a file descriptor to be assigned to specified key.
func FsconfigSetFd(fd int, key string, value int) (err error) {
return fsconfigCommon(fd, FSCONFIG_SET_FD, key, nil, value)
}
// FsconfigCreate is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_CMD_CREATE.
//
// fd is the filesystem context to act upon.
func FsconfigCreate(fd int) (err error) {
return fsconfig(fd, FSCONFIG_CMD_CREATE, nil, nil, 0)
}
// FsconfigReconfigure is equivalent to fsconfig(2) called
// with cmd == FSCONFIG_CMD_RECONFIGURE.
//
// fd is the filesystem context to act upon.
func FsconfigReconfigure(fd int) (err error) {
return fsconfig(fd, FSCONFIG_CMD_RECONFIGURE, nil, nil, 0)
}
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
//sysnb Getpgid(pid int) (pgid int, err error)

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin && !ios) || linux
//go:build (darwin && !ios) || linux || zos
package unix

View File

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin && !ios
//go:build (darwin && !ios) || zos
package unix

View File

@ -491,6 +491,7 @@ const (
BPF_F_REPLACE = 0x4
BPF_F_SLEEPABLE = 0x10
BPF_F_STRICT_ALIGNMENT = 0x1
BPF_F_TEST_REG_INVARIANTS = 0x80
BPF_F_TEST_RND_HI32 = 0x4
BPF_F_TEST_RUN_ON_CPU = 0x1
BPF_F_TEST_STATE_FREQ = 0x8
@ -1697,6 +1698,7 @@ const (
KEXEC_ARCH_S390 = 0x160000
KEXEC_ARCH_SH = 0x2a0000
KEXEC_ARCH_X86_64 = 0x3e0000
KEXEC_FILE_DEBUG = 0x8
KEXEC_FILE_NO_INITRAMFS = 0x4
KEXEC_FILE_ON_CRASH = 0x2
KEXEC_FILE_UNLOAD = 0x1
@ -1785,6 +1787,8 @@ const (
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20
LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1
LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
@ -1896,6 +1900,7 @@ const (
MNT_DETACH = 0x2
MNT_EXPIRE = 0x4
MNT_FORCE = 0x1
MNT_ID_REQ_SIZE_VER0 = 0x18
MODULE_INIT_COMPRESSED_FILE = 0x4
MODULE_INIT_IGNORE_MODVERSIONS = 0x1
MODULE_INIT_IGNORE_VERMAGIC = 0x2
@ -2300,6 +2305,7 @@ const (
PERF_AUX_FLAG_PARTIAL = 0x4
PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK = 0xff00
PERF_AUX_FLAG_TRUNCATED = 0x1
PERF_BRANCH_ENTRY_INFO_BITS_MAX = 0x21
PERF_BR_ARM64_DEBUG_DATA = 0x7
PERF_BR_ARM64_DEBUG_EXIT = 0x5
PERF_BR_ARM64_DEBUG_HALT = 0x4
@ -2465,6 +2471,7 @@ const (
PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1
PR_MDWE_NO_INHERIT = 0x2
PR_MDWE_REFUSE_EXEC_GAIN = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b
@ -2669,8 +2676,9 @@ const (
RTAX_FEATURES = 0xc
RTAX_FEATURE_ALLFRAG = 0x8
RTAX_FEATURE_ECN = 0x1
RTAX_FEATURE_MASK = 0xf
RTAX_FEATURE_MASK = 0x1f
RTAX_FEATURE_SACK = 0x2
RTAX_FEATURE_TCP_USEC_TS = 0x10
RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb
@ -2913,9 +2921,38 @@ const (
SCM_RIGHTS = 0x1
SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000
SECCOMP_ADDFD_FLAG_SEND = 0x2
SECCOMP_ADDFD_FLAG_SETFD = 0x1
SECCOMP_FILTER_FLAG_LOG = 0x2
SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8
SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4
SECCOMP_FILTER_FLAG_TSYNC = 0x1
SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10
SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20
SECCOMP_GET_ACTION_AVAIL = 0x2
SECCOMP_GET_NOTIF_SIZES = 0x3
SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100
SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101
SECCOMP_IOC_MAGIC = '!'
SECCOMP_MODE_DISABLED = 0x0
SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1
SECCOMP_RET_ACTION = 0x7fff0000
SECCOMP_RET_ACTION_FULL = 0xffff0000
SECCOMP_RET_ALLOW = 0x7fff0000
SECCOMP_RET_DATA = 0xffff
SECCOMP_RET_ERRNO = 0x50000
SECCOMP_RET_KILL = 0x0
SECCOMP_RET_KILL_PROCESS = 0x80000000
SECCOMP_RET_KILL_THREAD = 0x0
SECCOMP_RET_LOG = 0x7ffc0000
SECCOMP_RET_TRACE = 0x7ff00000
SECCOMP_RET_TRAP = 0x30000
SECCOMP_RET_USER_NOTIF = 0x7fc00000
SECCOMP_SET_MODE_FILTER = 0x1
SECCOMP_SET_MODE_STRICT = 0x0
SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1
SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1
SECRETMEM_MAGIC = 0x5345434d
SECURITYFS_MAGIC = 0x73636673
SEEK_CUR = 0x1
@ -3075,6 +3112,7 @@ const (
SOL_TIPC = 0x10f
SOL_TLS = 0x11a
SOL_UDP = 0x11
SOL_VSOCK = 0x11f
SOL_X25 = 0x106
SOL_XDP = 0x11b
SOMAXCONN = 0x1000
@ -3134,6 +3172,7 @@ const (
STATX_GID = 0x10
STATX_INO = 0x100
STATX_MNT_ID = 0x1000
STATX_MNT_ID_UNIQUE = 0x4000
STATX_MODE = 0x2
STATX_MTIME = 0x40
STATX_NLINK = 0x4
@ -3528,12 +3567,16 @@ const (
XDP_RX_RING = 0x2
XDP_SHARED_UMEM = 0x1
XDP_STATISTICS = 0x7
XDP_TXMD_FLAGS_CHECKSUM = 0x2
XDP_TXMD_FLAGS_TIMESTAMP = 0x1
XDP_TX_METADATA = 0x2
XDP_TX_RING = 0x3
XDP_UMEM_COMPLETION_RING = 0x6
XDP_UMEM_FILL_RING = 0x5
XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000
XDP_UMEM_PGOFF_FILL_RING = 0x100000000
XDP_UMEM_REG = 0x4
XDP_UMEM_TX_SW_CSUM = 0x2
XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1
XDP_USE_NEED_WAKEUP = 0x8
XDP_USE_SG = 0x10

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -282,6 +282,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -288,6 +288,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -278,6 +278,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -275,6 +275,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307

View File

@ -281,6 +281,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307

View File

@ -336,6 +336,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -340,6 +340,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -272,6 +272,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -344,6 +344,9 @@ const (
SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29
SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104
SFD_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905

View File

@ -335,6 +335,9 @@ const (
SCM_TIMESTAMPNS = 0x21
SCM_TXTIME = 0x3f
SCM_WIFI_STATUS = 0x25
SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103
SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102
SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104
SFD_CLOEXEC = 0x400000
SFD_NONBLOCK = 0x4000
SF_FP = 0x38

View File

@ -11,16 +11,41 @@ package unix
const (
BRKINT = 0x0001
CLOCAL = 0x1
CLOCK_MONOTONIC = 0x1
CLOCK_PROCESS_CPUTIME_ID = 0x2
CLOCK_REALTIME = 0x0
CLOCK_THREAD_CPUTIME_ID = 0x3
CLONE_NEWIPC = 0x08000000
CLONE_NEWNET = 0x40000000
CLONE_NEWNS = 0x00020000
CLONE_NEWPID = 0x20000000
CLONE_NEWUTS = 0x04000000
CLONE_PARENT = 0x00008000
CS8 = 0x0030
CSIZE = 0x0030
ECHO = 0x00000008
ECHONL = 0x00000001
EFD_SEMAPHORE = 0x00002000
EFD_CLOEXEC = 0x00001000
EFD_NONBLOCK = 0x00000004
EPOLL_CLOEXEC = 0x00001000
EPOLL_CTL_ADD = 0
EPOLL_CTL_MOD = 1
EPOLL_CTL_DEL = 2
EPOLLRDNORM = 0x0001
EPOLLRDBAND = 0x0002
EPOLLIN = 0x0003
EPOLLOUT = 0x0004
EPOLLWRBAND = 0x0008
EPOLLPRI = 0x0010
EPOLLERR = 0x0020
EPOLLHUP = 0x0040
EPOLLEXCLUSIVE = 0x20000000
EPOLLONESHOT = 0x40000000
FD_CLOEXEC = 0x01
FD_CLOFORK = 0x02
FD_SETSIZE = 0x800
FNDELAY = 0x04
F_CLOSFD = 9
F_CONTROL_CVT = 13
@ -45,6 +70,39 @@ const (
FSTYPE_NFS = 0xd5 //"N"
FSTYPE_TFS = 0xe3 //"T"
FSTYPE_AUTOMOUNT = 0xc1 //"A"
GRND_NONBLOCK = 1
GRND_RANDOM = 2
HUPCL = 0x0100 // Hang up on last close
IN_CLOEXEC = 0x00001000
IN_NONBLOCK = 0x00000004
IN_ACCESS = 0x00000001
IN_MODIFY = 0x00000002
IN_ATTRIB = 0x00000004
IN_CLOSE_WRITE = 0x00000008
IN_CLOSE_NOWRITE = 0x00000010
IN_OPEN = 0x00000020
IN_MOVED_FROM = 0x00000040
IN_MOVED_TO = 0x00000080
IN_CREATE = 0x00000100
IN_DELETE = 0x00000200
IN_DELETE_SELF = 0x00000400
IN_MOVE_SELF = 0x00000800
IN_UNMOUNT = 0x00002000
IN_Q_OVERFLOW = 0x00004000
IN_IGNORED = 0x00008000
IN_CLOSE = (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
IN_MOVE = (IN_MOVED_FROM | IN_MOVED_TO)
IN_ALL_EVENTS = (IN_ACCESS | IN_MODIFY | IN_ATTRIB |
IN_CLOSE | IN_OPEN | IN_MOVE |
IN_CREATE | IN_DELETE | IN_DELETE_SELF |
IN_MOVE_SELF)
IN_ONLYDIR = 0x01000000
IN_DONT_FOLLOW = 0x02000000
IN_EXCL_UNLINK = 0x04000000
IN_MASK_CREATE = 0x10000000
IN_MASK_ADD = 0x20000000
IN_ISDIR = 0x40000000
IN_ONESHOT = 0x80000000
IP6F_MORE_FRAG = 0x0001
IP6F_OFF_MASK = 0xfff8
IP6F_RESERVED_MASK = 0x0006
@ -152,10 +210,18 @@ const (
IP_PKTINFO = 101
IP_RECVPKTINFO = 102
IP_TOS = 2
IP_TTL = 3
IP_TTL = 14
IP_UNBLOCK_SOURCE = 11
ICMP6_FILTER = 1
MCAST_INCLUDE = 0
MCAST_EXCLUDE = 1
MCAST_JOIN_GROUP = 40
MCAST_LEAVE_GROUP = 41
MCAST_JOIN_SOURCE_GROUP = 42
MCAST_LEAVE_SOURCE_GROUP = 43
MCAST_BLOCK_SOURCE = 44
MCAST_UNBLOCK_SOURCE = 46
ICANON = 0x0010
ICMP6_FILTER = 0x26
ICRNL = 0x0002
IEXTEN = 0x0020
IGNBRK = 0x0004
@ -165,10 +231,10 @@ const (
ISTRIP = 0x0080
IXON = 0x0200
IXOFF = 0x0100
LOCK_SH = 0x1 // Not exist on zOS
LOCK_EX = 0x2 // Not exist on zOS
LOCK_NB = 0x4 // Not exist on zOS
LOCK_UN = 0x8 // Not exist on zOS
LOCK_SH = 0x1
LOCK_EX = 0x2
LOCK_NB = 0x4
LOCK_UN = 0x8
POLLIN = 0x0003
POLLOUT = 0x0004
POLLPRI = 0x0010
@ -182,15 +248,29 @@ const (
MAP_PRIVATE = 0x1 // changes are private
MAP_SHARED = 0x2 // changes are shared
MAP_FIXED = 0x4 // place exactly
MCAST_JOIN_GROUP = 40
MCAST_LEAVE_GROUP = 41
MCAST_JOIN_SOURCE_GROUP = 42
MCAST_LEAVE_SOURCE_GROUP = 43
MCAST_BLOCK_SOURCE = 44
MCAST_UNBLOCK_SOURCE = 45
__MAP_MEGA = 0x8
__MAP_64 = 0x10
MAP_ANON = 0x20
MAP_ANONYMOUS = 0x20
MS_SYNC = 0x1 // msync - synchronous writes
MS_ASYNC = 0x2 // asynchronous writes
MS_INVALIDATE = 0x4 // invalidate mappings
MS_BIND = 0x00001000
MS_MOVE = 0x00002000
MS_NOSUID = 0x00000002
MS_PRIVATE = 0x00040000
MS_REC = 0x00004000
MS_REMOUNT = 0x00008000
MS_RDONLY = 0x00000001
MS_UNBINDABLE = 0x00020000
MNT_DETACH = 0x00000004
ZOSDSFS_SUPER_MAGIC = 0x44534653 // zOS DSFS
NFS_SUPER_MAGIC = 0x6969 // NFS
NSFS_MAGIC = 0x6e736673 // PROCNS
PROC_SUPER_MAGIC = 0x9fa0 // proc FS
ZOSTFS_SUPER_MAGIC = 0x544653 // zOS TFS
ZOSUFS_SUPER_MAGIC = 0x554653 // zOS UFS
ZOSZFS_SUPER_MAGIC = 0x5A4653 // zOS ZFS
MTM_RDONLY = 0x80000000
MTM_RDWR = 0x40000000
MTM_UMOUNT = 0x10000000
@ -205,13 +285,20 @@ const (
MTM_REMOUNT = 0x00000100
MTM_NOSECURITY = 0x00000080
NFDBITS = 0x20
ONLRET = 0x0020 // NL performs CR function
O_ACCMODE = 0x03
O_APPEND = 0x08
O_ASYNCSIG = 0x0200
O_CREAT = 0x80
O_DIRECT = 0x00002000
O_NOFOLLOW = 0x00004000
O_DIRECTORY = 0x00008000
O_PATH = 0x00080000
O_CLOEXEC = 0x00001000
O_EXCL = 0x40
O_GETFL = 0x0F
O_LARGEFILE = 0x0400
O_NDELAY = 0x4
O_NONBLOCK = 0x04
O_RDONLY = 0x02
O_RDWR = 0x03
@ -248,6 +335,7 @@ const (
AF_IUCV = 17
AF_LAT = 14
AF_LINK = 18
AF_LOCAL = AF_UNIX // AF_LOCAL is an alias for AF_UNIX
AF_MAX = 30
AF_NBS = 7
AF_NDD = 23
@ -285,15 +373,33 @@ const (
RLIMIT_AS = 5
RLIMIT_NOFILE = 6
RLIMIT_MEMLIMIT = 7
RLIMIT_MEMLOCK = 0x8
RLIM_INFINITY = 2147483647
SCHED_FIFO = 0x2
SCM_CREDENTIALS = 0x2
SCM_RIGHTS = 0x01
SF_CLOSE = 0x00000002
SF_REUSE = 0x00000001
SHM_RND = 0x2
SHM_RDONLY = 0x1
SHMLBA = 0x1000
IPC_STAT = 0x3
IPC_SET = 0x2
IPC_RMID = 0x1
IPC_PRIVATE = 0x0
IPC_CREAT = 0x1000000
__IPC_MEGA = 0x4000000
__IPC_SHAREAS = 0x20000000
__IPC_BELOWBAR = 0x10000000
IPC_EXCL = 0x2000000
__IPC_GIGA = 0x8000000
SHUT_RD = 0
SHUT_RDWR = 2
SHUT_WR = 1
SOCK_CLOEXEC = 0x00001000
SOCK_CONN_DGRAM = 6
SOCK_DGRAM = 2
SOCK_NONBLOCK = 0x800
SOCK_RAW = 3
SOCK_RDM = 4
SOCK_SEQPACKET = 5
@ -378,8 +484,6 @@ const (
S_IFMST = 0x00FF0000
TCP_KEEPALIVE = 0x8
TCP_NODELAY = 0x1
TCP_INFO = 0xb
TCP_USER_TIMEOUT = 0x1
TIOCGWINSZ = 0x4008a368
TIOCSWINSZ = 0x8008a367
TIOCSBRK = 0x2000a77b
@ -427,7 +531,10 @@ const (
VSUSP = 9
VTIME = 10
WCONTINUED = 0x4
WEXITED = 0x8
WNOHANG = 0x1
WNOWAIT = 0x20
WSTOPPED = 0x10
WUNTRACED = 0x2
_BPX_SWAP = 1
_BPX_NONSWAP = 2
@ -452,8 +559,28 @@ const (
MADV_FREE = 15 // for Linux compatibility -- no zos semantics
MADV_WIPEONFORK = 16 // for Linux compatibility -- no zos semantics
MADV_KEEPONFORK = 17 // for Linux compatibility -- no zos semantics
AT_SYMLINK_NOFOLLOW = 1 // for Unix compatibility -- no zos semantics
AT_FDCWD = 2 // for Unix compatibility -- no zos semantics
AT_SYMLINK_FOLLOW = 0x400
AT_SYMLINK_NOFOLLOW = 0x100
XATTR_CREATE = 0x1
XATTR_REPLACE = 0x2
P_PID = 0
P_PGID = 1
P_ALL = 2
PR_SET_NAME = 15
PR_GET_NAME = 16
PR_SET_NO_NEW_PRIVS = 38
PR_GET_NO_NEW_PRIVS = 39
PR_SET_DUMPABLE = 4
PR_GET_DUMPABLE = 3
PR_SET_PDEATHSIG = 1
PR_GET_PDEATHSIG = 2
PR_SET_CHILD_SUBREAPER = 36
PR_GET_CHILD_SUBREAPER = 37
AT_FDCWD = -100
AT_EACCESS = 0x200
AT_EMPTY_PATH = 0x1000
AT_REMOVEDIR = 0x200
RENAME_NOREPLACE = 1 << 0
)
const (
@ -476,6 +603,7 @@ const (
EMLINK = Errno(125)
ENAMETOOLONG = Errno(126)
ENFILE = Errno(127)
ENOATTR = Errno(265)
ENODEV = Errno(128)
ENOENT = Errno(129)
ENOEXEC = Errno(130)
@ -700,7 +828,7 @@ var errorList = [...]struct {
{145, "EDC5145I", "The parameter list is too long, or the message to receive was too large for the buffer."},
{146, "EDC5146I", "Too many levels of symbolic links."},
{147, "EDC5147I", "Illegal byte sequence."},
{148, "", ""},
{148, "EDC5148I", "The named attribute or data not available."},
{149, "EDC5149I", "Value Overflow Error."},
{150, "EDC5150I", "UNIX System Services is not active."},
{151, "EDC5151I", "Dynamic allocation error."},
@ -743,6 +871,7 @@ var errorList = [...]struct {
{259, "EDC5259I", "A CUN_RS_NO_CONVERSION error was issued by Unicode Services."},
{260, "EDC5260I", "A CUN_RS_TABLE_NOT_ALIGNED error was issued by Unicode Services."},
{262, "EDC5262I", "An iconv() function encountered an unexpected error while using Unicode Services."},
{265, "EDC5265I", "The named attribute not available."},
{1000, "EDC8000I", "A bad socket-call constant was found in the IUCV header."},
{1001, "EDC8001I", "An error was found in the IUCV header."},
{1002, "EDC8002I", "A socket descriptor is out of range."},

View File

@ -0,0 +1,364 @@
// go run mksyscall_zos_s390x.go -o_sysnum zsysnum_zos_s390x.go -o_syscall zsyscall_zos_s390x.go -i_syscall syscall_zos_s390x.go -o_asm zsymaddr_zos_s390x.s
// Code generated by the command above; see README.md. DO NOT EDIT.
//go:build zos && s390x
#include "textflag.h"
// provide the address of function variable to be fixed up.
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FlistxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Flistxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FremovexattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fremovexattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FgetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fgetxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FsetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fsetxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_accept4Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·accept4(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_RemovexattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Removexattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_Dup3Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Dup3(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_DirfdAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Dirfd(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EpollCreateAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·EpollCreate(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EpollCreate1Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·EpollCreate1(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EpollCtlAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·EpollCtl(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EpollPwaitAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·EpollPwait(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EpollWaitAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·EpollWait(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_EventfdAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Eventfd(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FaccessatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Faccessat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FchmodatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fchmodat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FchownatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fchownat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FdatasyncAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fdatasync(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_fstatatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·fstatat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LgetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Lgetxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LsetxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Lsetxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FstatfsAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Fstatfs(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FutimesAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Futimes(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_FutimesatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Futimesat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_GetrandomAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Getrandom(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_InotifyInitAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·InotifyInit(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_InotifyInit1Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·InotifyInit1(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_InotifyAddWatchAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·InotifyAddWatch(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_InotifyRmWatchAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·InotifyRmWatch(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_ListxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Listxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LlistxattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Llistxattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LremovexattrAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Lremovexattr(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LutimesAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Lutimes(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_StatfsAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Statfs(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_SyncfsAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Syncfs(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_UnshareAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Unshare(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_LinkatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Linkat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_MkdiratAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Mkdirat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_MknodatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Mknodat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_PivotRootAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·PivotRoot(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_PrctlAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Prctl(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_PrlimitAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Prlimit(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_RenameatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Renameat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_Renameat2Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Renameat2(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_SethostnameAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Sethostname(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_SetnsAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Setns(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_SymlinkatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Symlinkat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_UnlinkatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·Unlinkat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_openatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·openat(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_openat2Addr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·openat2(SB), R8
MOVD R8, ret+0(FP)
RET
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
TEXT ·get_utimensatAddr(SB), NOSPLIT|NOFRAME, $0-8
MOVD $·utimensat(SB), R8
MOVD R8, ret+0(FP)
RET

View File

@ -906,6 +906,16 @@ func Fspick(dirfd int, pathName string, flags int) (fd int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error) {
_, _, e1 := Syscall6(SYS_FSCONFIG, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(value)), uintptr(aux), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {

File diff suppressed because it is too large Load Diff

View File

@ -448,4 +448,13 @@ const (
SYS_SET_MEMPOLICY_HOME_NODE = 450
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
SYS_STATMOUNT = 457
SYS_LISTMOUNT = 458
SYS_LSM_GET_SELF_ATTR = 459
SYS_LSM_SET_SELF_ATTR = 460
SYS_LSM_LIST_MODULES = 461
)

View File

@ -371,4 +371,12 @@ const (
SYS_CACHESTAT = 451
SYS_FCHMODAT2 = 452
SYS_MAP_SHADOW_STACK = 453
SYS_FUTEX_WAKE = 454
SYS_FUTEX_WAIT = 455
SYS_FUTEX_REQUEUE = 456
SYS_STATMOUNT = 457
SYS_LISTMOUNT = 458
SYS_LSM_GET_SELF_ATTR = 459
SYS_LSM_SET_SELF_ATTR = 460
SYS_LSM_LIST_MODULES = 461
)

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