1
0
Fork 0
forked from External/ergo

Compare commits

..

2 commits

Author SHA1 Message Date
Shivaram Lingamneni
ae704b7db4 update to goreleaser v2
* goreleaser version must be specified in .goreleaser.yml
* --skip-publish is replaced by --skip=publish
2024-06-09 04:25:23 -04:00
Shivaram Lingamneni
68d8383647 update goreleaser config:
* --rm-dist is replaced by --clean
* `replacements` is removed:
   https://goreleaser.com/deprecations/#archivesreplacements
2024-06-09 04:17:07 -04:00
160 changed files with 5145 additions and 11017 deletions

View file

@ -19,7 +19,7 @@ jobs:
- name: "setup go" - name: "setup go"
uses: "actions/setup-go@v3" uses: "actions/setup-go@v3"
with: with:
go-version: "1.23" go-version: "1.22"
- name: "install python3-pytest" - name: "install python3-pytest"
run: "sudo apt install -y python3-pytest" run: "sudo apt install -y python3-pytest"
- name: "make install" - name: "make install"

View file

@ -18,7 +18,6 @@ builds:
- amd64 - amd64
- arm - arm
- arm64 - arm64
- riscv64
goarm: goarm:
- 6 - 6
ignore: ignore:
@ -26,30 +25,20 @@ builds:
goarch: arm goarch: arm
- goos: windows - goos: windows
goarch: arm64 goarch: arm64
- goos: windows
goarch: riscv64
- goos: darwin - goos: darwin
goarch: arm goarch: arm
- goos: darwin
goarch: riscv64
- goos: freebsd - goos: freebsd
goarch: arm goarch: arm
- goos: freebsd - goos: freebsd
goarch: arm64 goarch: arm64
- goos: freebsd
goarch: riscv64
- goos: openbsd - goos: openbsd
goarch: arm goarch: arm
- goos: openbsd - goos: openbsd
goarch: arm64 goarch: arm64
- goos: openbsd
goarch: riscv64
- goos: plan9 - goos: plan9
goarch: arm goarch: arm
- goos: plan9 - goos: plan9
goarch: arm64 goarch: arm64
- goos: plan9
goarch: riscv64
flags: flags:
- -trimpath - -trimpath

View file

@ -1,13 +1,13 @@
# Changelog # Changelog
All notable changes to Ergo will be documented in this file. All notable changes to Ergo will be documented in this file.
## [2.14.0] - 2024-06-30 ## [2.14.0-rc1] - 2024-06-09
We're pleased to be publishing v2.14.0, a new stable release. This release contains primarily bug fixes, with the addition of some new authentication mechanisms for integrating with web clients. We're pleased to be publishing the release candidate for v2.14.0 (the official release should follow within two weeks or so). This release contains primarily bug fixes, with the addition of some new authentication mechanisms for integrating with web clients.
This release includes changes to the config file format, all of which are fully backwards-compatible and do not require updating the file before upgrading. It includes no changes to the database file format. This release includes changes to the config file format, all of which are fully backwards-compatible and do not require updating the file before upgrading. It includes no changes to the database file format.
Many thanks to [@al3xandros](https://github.com/al3xandros), donio, [@eeeeeta](https://github.com/eeeeeta), [@emersion](https://github.com/emersion), [@Eriner](https://github.com/Eriner), [@eskimo](https://github.com/eskimo), [@Herringway](https://github.com/Herringway), [@jwheare](https://github.com/jwheare), [@knolley](https://github.com/knolley), [@mengzhuo](https://github.com/mengzhuo), pathof, [@poVoq](https://github.com/poVoq), [@progval](https://github.com/progval), [@RNDpacman](https://github.com/RNDpacman), and [@xnaas](https://github.com/xnaas) for contributing patches, reporting issues, and helping test. Many thanks to [@al3xandros](https://github.com/al3xandros), donio, [@eeeeeta](https://github.com/eeeeeta), [@emersion](https://github.com/emersion), [@Eriner](https://github.com/Eriner), [@eskimo](https://github.com/eskimo), [@Herringway](https://github.com/Herringway), [@jwheare](https://github.com/jwheare), [@knolley](https://github.com/knolley), pathof, [@poVoq](https://github.com/poVoq), [@progval](https://github.com/progval), [@RNDpacman](https://github.com/RNDpacman), and [@xnaas](https://github.com/xnaas) for contributing patches, reporting issues, and helping test.
### Config changes ### Config changes
* Added `accounts.oauth2` and `accounts.jwt-auth` blocks for configuring OAuth2 and JWT authentication (#2004) * Added `accounts.oauth2` and `accounts.jwt-auth` blocks for configuring OAuth2 and JWT authentication (#2004)
@ -23,7 +23,6 @@ Many thanks to [@al3xandros](https://github.com/al3xandros), donio, [@eeeeeta](h
* The new `ergo defaultconfig` subcommand prints a copy of the default config file to standard output (#2157, #2160, thanks [@al3xandros](https://github.com/al3xandros)!) * The new `ergo defaultconfig` subcommand prints a copy of the default config file to standard output (#2157, #2160, thanks [@al3xandros](https://github.com/al3xandros)!)
### Fixed ### Fixed
* Even with `allow-truncation: false` (the recommended default), some oversized messages were being accepted and relayed with truncation. These messages will now be rejected with `417 ERR_INPUTTOOLONG` as expected (#2170)
* NICK and QUIT from invisible members of auditorium channels are no longer recorded in history (#2133, #2137, thanks [@knolley](https://github.com/knolley) and [@poVoq](https://github.com/poVoq)!) * NICK and QUIT from invisible members of auditorium channels are no longer recorded in history (#2133, #2137, thanks [@knolley](https://github.com/knolley) and [@poVoq](https://github.com/poVoq)!)
* If channel registration was disabled, registered channels could become inaccessible after rehash; this has been fixed (#2130, thanks [@eeeeeta](https://github.com/eeeeeta)!) * If channel registration was disabled, registered channels could become inaccessible after rehash; this has been fixed (#2130, thanks [@eeeeeta](https://github.com/eeeeeta)!)
* Attempts to use unrecognized SASL mechanisms no longer count against the login throttle, improving compatibility with Pidgin (#2156, thanks donio and pathof!) * Attempts to use unrecognized SASL mechanisms no longer count against the login throttle, improving compatibility with Pidgin (#2156, thanks donio and pathof!)
@ -41,7 +40,6 @@ Many thanks to [@al3xandros](https://github.com/al3xandros), donio, [@eeeeeta](h
### Internal ### Internal
* Official release builds use Go 1.22.4 * Official release builds use Go 1.22.4
* Added a linux/riscv64 release (#2172, #2173, thanks [@mengzhuo](https://github.com/mengzhuo)!)
## [2.13.1] - 2024-05-06 ## [2.13.1] - 2024-05-06

View file

@ -1,8 +1,7 @@
## build ergo binary ## build ergo binary
FROM docker.io/golang:1.23-alpine AS build-env FROM docker.io/golang:1.22-alpine AS build-env
RUN apk upgrade -U --force-refresh --no-cache RUN apk upgrade -U --force-refresh --no-cache && apk add --no-cache --purge --clean-protected -l -u make git
RUN apk add --no-cache --purge --clean-protected -l -u make git
# copy ergo source # copy ergo source
WORKDIR /go/src/github.com/ergochat/ergo WORKDIR /go/src/github.com/ergochat/ergo
@ -19,6 +18,13 @@ RUN make install
## build ergo container ## build ergo container
FROM docker.io/alpine:3.19 FROM docker.io/alpine:3.19
# metadata
LABEL maintainer="Daniel Oaks <daniel@danieloaks.net>,Daniel Thamdrup <dallemon@protonmail.com>" \
description="Ergo is a modern, experimental IRC server written in Go"
# standard ports listened on
EXPOSE 6667/tcp 6697/tcp
# ergo itself # ergo itself
COPY --from=build-env /go/bin/ergo \ COPY --from=build-env /go/bin/ergo \
/go/src/github.com/ergochat/ergo/default.yaml \ /go/src/github.com/ergochat/ergo/default.yaml \
@ -33,4 +39,10 @@ WORKDIR /ircd
# default motd # default motd
COPY --from=build-env /go/src/github.com/ergochat/ergo/ergo.motd /ircd/ergo.motd COPY --from=build-env /go/src/github.com/ergochat/ergo/ergo.motd /ircd/ergo.motd
# launch
ENTRYPOINT ["/ircd-bin/run.sh"] ENTRYPOINT ["/ircd-bin/run.sh"]
# # uncomment to debug
# RUN apk add --no-cache bash
# RUN apk add --no-cache vim
# CMD /bin/bash

View file

@ -12,10 +12,10 @@ capdef_file = ./irc/caps/defs.go
all: build all: build
install: install:
go install -mod=mod -v -ldflags "-X main.commit=$(GIT_COMMIT) -X main.version=$(GIT_TAG)" go install -v -ldflags "-X main.commit=$(GIT_COMMIT) -X main.version=$(GIT_TAG)"
build: build:
go build -mod=mod -v -ldflags "-X main.commit=$(GIT_COMMIT) -X main.version=$(GIT_TAG)" go build -v -ldflags "-X main.commit=$(GIT_COMMIT) -X main.version=$(GIT_TAG)"
release: release:
goreleaser --skip=publish --clean goreleaser --skip=publish --clean

View file

@ -369,7 +369,7 @@ server:
# in a "closed-loop" system where you control the server and all the clients, # in a "closed-loop" system where you control the server and all the clients,
# you may want to increase the maximum (non-tag) length of an IRC line from # you may want to increase the maximum (non-tag) length of an IRC line from
# the default value of 512. DO NOT change this on a public server: # the default value of 512. DO NOT change this on a public server:
max-line-len: 2048 #max-line-len: 512
# send all 0's as the LUSERS (user counts) output to non-operators; potentially useful # send all 0's as the LUSERS (user counts) output to non-operators; potentially useful
# if you don't want to publicize how popular the server is # if you don't want to publicize how popular the server is
@ -820,7 +820,7 @@ lock-file: "ircd.lock"
# datastore configuration # datastore configuration
datastore: datastore:
# path to the database file (used to store account and channel registrations): # path to the datastore
path: ircd.db path: ircd.db
# if the database schema requires an upgrade, `autoupgrade` will attempt to # if the database schema requires an upgrade, `autoupgrade` will attempt to
@ -1067,9 +1067,3 @@ history:
# whether to allow customization of the config at runtime using environment variables, # whether to allow customization of the config at runtime using environment variables,
# e.g., ERGO__SERVER__MAX_SENDQ=128k. see the manual for more details. # e.g., ERGO__SERVER__MAX_SENDQ=128k. see the manual for more details.
allow-environment-overrides: true allow-environment-overrides: true
cef:
imagor:
url: "https://example.com/embed/"
secret: "secretgoeshere"
redis: "redis://user:password@localhost:6379/0?protocol=3"

View file

@ -219,12 +219,6 @@ CAPDEFS = [
url="https://github.com/ircv3/ircv3-specifications/pull/527", url="https://github.com/ircv3/ircv3-specifications/pull/527",
standard="proposed IRCv3", standard="proposed IRCv3",
), ),
CapDef(
identifier="ExtendedISupport",
name="draft/extended-isupport",
url="https://github.com/ircv3/ircv3-specifications/pull/543",
standard="proposed IRCv3",
),
] ]
def validate_defs(): def validate_defs():

23
go.mod
View file

@ -1,6 +1,6 @@
module github.com/ergochat/ergo module github.com/ergochat/ergo
go 1.23 go 1.22
require ( require (
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48
@ -8,7 +8,7 @@ require (
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881 github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881
github.com/ergochat/irc-go v0.5.0-rc2 github.com/ergochat/irc-go v0.5.0-rc1
github.com/go-sql-driver/mysql v1.7.0 github.com/go-sql-driver/mysql v1.7.0
github.com/go-test/deep v1.0.6 // indirect github.com/go-test/deep v1.0.6 // indirect
github.com/gofrs/flock v0.8.1 github.com/gofrs/flock v0.8.1
@ -16,24 +16,19 @@ require (
github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd github.com/okzk/sdnotify v0.0.0-20180710141335-d9becc38acbd
github.com/onsi/ginkgo v1.12.0 // indirect github.com/onsi/ginkgo v1.12.0 // indirect
github.com/onsi/gomega v1.9.0 // indirect github.com/onsi/gomega v1.9.0 // indirect
github.com/tidwall/buntdb v1.3.1 github.com/stretchr/testify v1.4.0 // indirect
github.com/tidwall/buntdb v1.2.10
github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208 github.com/toorop/go-dkim v0.0.0-20201103131630-e1cd1a0a5208
github.com/xdg-go/scram v1.0.2 github.com/xdg-go/scram v1.0.2
golang.org/x/crypto v0.25.0 golang.org/x/crypto v0.17.0
golang.org/x/term v0.22.0 golang.org/x/term v0.15.0
golang.org/x/text v0.16.0 golang.org/x/text v0.14.0
gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v2 v2.4.0
) )
require ( require github.com/golang-jwt/jwt/v5 v5.2.0
github.com/cshum/imagor v1.4.13
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/redis/go-redis/v9 v9.6.1
)
require ( require (
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/tidwall/btree v1.4.2 // indirect github.com/tidwall/btree v1.4.2 // indirect
github.com/tidwall/gjson v1.14.3 // indirect github.com/tidwall/gjson v1.14.3 // indirect
github.com/tidwall/grect v0.1.4 // indirect github.com/tidwall/grect v0.1.4 // indirect
@ -42,7 +37,7 @@ require (
github.com/tidwall/rtred v0.1.2 // indirect github.com/tidwall/rtred v0.1.2 // indirect
github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/tidwall/tinyqueue v0.1.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
golang.org/x/sys v0.22.0 // indirect golang.org/x/sys v0.15.0 // indirect
) )
replace github.com/gorilla/websocket => github.com/ergochat/websocket v1.4.2-oragono1 replace github.com/gorilla/websocket => github.com/ergochat/websocket v1.4.2-oragono1

56
go.sum
View file

@ -2,28 +2,18 @@ code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48 h1:/EMHruHCFXR9
code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc= code.cloudfoundry.org/bytefmt v0.0.0-20200131002437-cf55d5288a48/go.mod h1:wN/zk7mhREp/oviagqUXY3EwuHhWyOvAdsn5Y4CzOrc=
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962 h1:KeNholpO2xKjgaaSyd+DyQRrsQjhbSeS7qe4nEw8aQw=
github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo= github.com/GehirnInc/crypt v0.0.0-20200316065508-bb7000b8a962/go.mod h1:kC29dT1vFpj7py2OvG1khBdQpo3kInWP+6QipLbdngo=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cshum/imagor v1.4.13 h1:BFcSpsTUOJj+Wv5SzDeXa8bhsT/Ehw7EcrFD0UTdpmU=
github.com/cshum/imagor v1.4.13/go.mod h1:LHxXgks6Y06GzEHitnlO8vcD5gznxIHWPdvGsnlGpMo=
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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 h1:WLHTOodthVyv5NvYLIvWl112kSFv5IInKKrRN2qpons= github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1 h1:WLHTOodthVyv5NvYLIvWl112kSFv5IInKKrRN2qpons=
github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1/go.mod h1:mov+uh1DPWsltdQnOdzn08UO9GsJ3MEvhtu0Ci37fdk= github.com/ergochat/confusables v0.0.0-20201108231250-4ab98ab61fb1/go.mod h1:mov+uh1DPWsltdQnOdzn08UO9GsJ3MEvhtu0Ci37fdk=
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881 h1:+J5m88nvybxB5AnBVGzTXM/yHVytt48rXBGcJGzSbms= github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881 h1:+J5m88nvybxB5AnBVGzTXM/yHVytt48rXBGcJGzSbms=
github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881/go.mod h1:ASYJtQujNitna6cVHsNQTGrfWvMPJ5Sa2lZlmsH65uM= github.com/ergochat/go-ident v0.0.0-20230911071154-8c30606d6881/go.mod h1:ASYJtQujNitna6cVHsNQTGrfWvMPJ5Sa2lZlmsH65uM=
github.com/ergochat/irc-go v0.4.0 h1:0YibCKfAAtwxQdNjLQd9xpIEPisLcJ45f8FNsMHAuZc=
github.com/ergochat/irc-go v0.4.0/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
github.com/ergochat/irc-go v0.5.0-rc1 h1:kFoIHExoNFQ2CV+iShAVna/H4xrXQB4t4jK5Sep2j9k= github.com/ergochat/irc-go v0.5.0-rc1 h1:kFoIHExoNFQ2CV+iShAVna/H4xrXQB4t4jK5Sep2j9k=
github.com/ergochat/irc-go v0.5.0-rc1/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0= github.com/ergochat/irc-go v0.5.0-rc1/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
github.com/ergochat/irc-go v0.5.0-rc2 h1:VuSQJF5K4hWvYSzGa4b8vgL6kzw8HF6LSOejE+RWpAo=
github.com/ergochat/irc-go v0.5.0-rc2/go.mod h1:2vi7KNpIPWnReB5hmLpl92eMywQvuIeIIGdt/FQCph0=
github.com/ergochat/scram v1.0.2-ergo1 h1:2bYXiRFQH636pT0msOG39fmEYl4Eq+OuutcyDsCix/g= github.com/ergochat/scram v1.0.2-ergo1 h1:2bYXiRFQH636pT0msOG39fmEYl4Eq+OuutcyDsCix/g=
github.com/ergochat/scram v1.0.2-ergo1/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/ergochat/scram v1.0.2-ergo1/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM= github.com/ergochat/websocket v1.4.2-oragono1 h1:plMUunFBM6UoSCIYCKKclTdy/TkkHfUslhOfJQzfueM=
@ -35,8 +25,8 @@ github.com/go-test/deep v1.0.6 h1:UHSEyLZUwX9Qoi99vVwvewiMC8mM2bf7XEM2nqvzEn8=
github.com/go-test/deep v1.0.6/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/go-test/deep v1.0.6/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@ -50,16 +40,15 @@ github.com/onsi/gomega v1.9.0 h1:R1uwffexN6Pr340GtYRIdZmAiN4J+iw6WG4wog1DUXg=
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI= github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI=
github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8= github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8=
github.com/tidwall/btree v1.4.2 h1:PpkaieETJMUxYNADsjgtNRcERX7mGc/GP2zp/r5FM3g= github.com/tidwall/btree v1.4.2 h1:PpkaieETJMUxYNADsjgtNRcERX7mGc/GP2zp/r5FM3g=
github.com/tidwall/btree v1.4.2/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= github.com/tidwall/btree v1.4.2/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE=
github.com/tidwall/buntdb v1.3.1 h1:HKoDF01/aBhl9RjYtbaLnvX9/OuenwvQiC3OP1CcL4o= github.com/tidwall/buntdb v1.2.10 h1:U/ebfkmYPBnyiNZIirUiWFcxA/mgzjbKlyPynFsPtyM=
github.com/tidwall/buntdb v1.3.1/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= github.com/tidwall/buntdb v1.2.10/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU=
github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@ -81,22 +70,22 @@ github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc= github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.14.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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -106,8 +95,7 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
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

@ -64,11 +64,10 @@ const (
BotTagName = "bot" BotTagName = "bot"
// https://ircv3.net/specs/extensions/chathistory // https://ircv3.net/specs/extensions/chathistory
ChathistoryTargetsBatchType = "draft/chathistory-targets" ChathistoryTargetsBatchType = "draft/chathistory-targets"
ExtendedISupportBatchType = "draft/extended-isupport"
) )
func init() { func init() {
nameToCapability = make(map[string]Capability, numCapabs) nameToCapability = make(map[string]Capability)
for capab, name := range capabilityNames { for capab, name := range capabilityNames {
nameToCapability[name] = Capability(capab) nameToCapability[name] = Capability(capab)
} }

View file

@ -7,7 +7,7 @@ package caps
const ( const (
// number of recognized capabilities: // number of recognized capabilities:
numCapabs = 36 numCapabs = 34
// length of the uint32 array that represents the bitset: // length of the uint32 array that represents the bitset:
bitsetLen = 2 bitsetLen = 2
) )
@ -53,10 +53,6 @@ const (
// https://github.com/ircv3/ircv3-specifications/pull/362 // https://github.com/ircv3/ircv3-specifications/pull/362
EventPlayback Capability = iota EventPlayback Capability = iota
// ExtendedISupport is the proposed IRCv3 capability named "draft/extended-isupport":
// https://github.com/ircv3/ircv3-specifications/pull/543
ExtendedISupport Capability = iota
// Languages is the proposed IRCv3 capability named "draft/languages": // Languages is the proposed IRCv3 capability named "draft/languages":
// https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6 // https://gist.github.com/DanielOaks/8126122f74b26012a3de37db80e4e0c6
Languages Capability = iota Languages Capability = iota
@ -152,8 +148,6 @@ const (
// ZNCSelfMessage is the ZNC vendor capability named "znc.in/self-message": // ZNCSelfMessage is the ZNC vendor capability named "znc.in/self-message":
// https://wiki.znc.in/Query_buffers // https://wiki.znc.in/Query_buffers
ZNCSelfMessage Capability = iota ZNCSelfMessage Capability = iota
ExtendedNames Capability = iota
) )
// `capabilityNames[capab]` is the string name of the capability `capab` // `capabilityNames[capab]` is the string name of the capability `capab`
@ -169,7 +163,6 @@ var (
"draft/channel-rename", "draft/channel-rename",
"draft/chathistory", "draft/chathistory",
"draft/event-playback", "draft/event-playback",
"draft/extended-isupport",
"draft/languages", "draft/languages",
"draft/message-redaction", "draft/message-redaction",
"draft/multiline", "draft/multiline",
@ -194,6 +187,5 @@ var (
"userhost-in-names", "userhost-in-names",
"znc.in/playback", "znc.in/playback",
"znc.in/self-message", "znc.in/self-message",
"cef/extended-names",
} }
) )

View file

@ -1,194 +0,0 @@
package irc
import (
"context"
"crypto/sha256"
"encoding/json"
"fmt"
"github.com/cshum/imagor/imagorpath"
"github.com/ergochat/ergo/irc/caps"
"github.com/ergochat/irc-go/ircmsg"
"net/http"
"regexp"
"strings"
"time"
)
var ctx = context.Background()
func (channel *Channel) RedisBroadcast(message ...string) {
if channel.server.redis == nil {
return
}
err := channel.server.redis.Publish(ctx, "channel."+channel.NameCasefolded(), strings.Join(message, " ")).Err()
if err != nil {
fmt.Printf("Channel broadcast error: %v", err)
}
}
func (client *Client) RedisBroadcast(message ...string) {
err := client.server.redis.Publish(ctx, "user."+client.NickCasefolded(), strings.Join(message, " ")).Err()
if err != nil {
fmt.Printf("User broadcast error: %v", err)
}
}
func (channel *Channel) Broadcast(command string, params ...string) {
channel.BroadcastFrom(channel.server.name, command, params...)
}
func (channel *Channel) BroadcastFrom(prefix string, command string, params ...string) {
for _, member := range channel.Members() {
for _, session := range member.Sessions() {
session.Send(nil, prefix, command, params...)
}
}
}
// ChannelSub Actions and info centering around channels
func (server *Server) ChannelSub() {
pubsub := server.redis.PSubscribe(ctx, "channel.*")
defer pubsub.Close()
ch := pubsub.Channel()
for msg := range ch {
server.logger.Info("RedisMessage", msg.Channel, msg.Payload)
line := strings.Split(msg.Payload, " ")
channelName := strings.SplitN(msg.Channel, ".", 2)[1]
channel := server.channels.Get(channelName)
if len(line) == 0 {
println("Empty string dumped into ", msg.Channel, " channel")
}
if channel == nil {
server.logger.Warning("RedisMessage", "Unknown channel")
continue
}
switch line[0] {
case "VOICEPART":
channel.Broadcast("VOICEPART", channelName, line[1])
case "VOICESTATE":
channel.Broadcast("VOICESTATE", channelName, line[1], line[2], line[3])
case "BROADCASTTO":
for _, person := range channel.Members() {
person.Send(nil, server.name, line[1], line[2:]...)
}
}
}
}
// UserSub Handles things pertaining to users
func (server *Server) UserSub() {
pubsub := server.redis.PSubscribe(ctx, "user.*")
defer pubsub.Close()
ch := pubsub.Channel()
for msg := range ch {
server.logger.Info("RedisMessage", msg.Channel, msg.Payload)
line := strings.Split(msg.Payload, " ")
userName := strings.SplitN(msg.Channel, ".", 2)[1]
user := server.clients.Get(userName)
if len(line) == 0 {
println("Empty string dumped into ", msg.Channel, " channel")
}
switch line[0] {
case "FULLYREMOVE":
if user != nil {
user.destroy(nil)
err := server.accounts.Unregister(user.Account(), true)
if err != nil {
return
}
}
break
case "BROADCASTAS":
if user != nil {
// I'm not too sure what the capability bit is, I think it's just ones that match
for friend := range user.Friends(caps.ExtendedNames) {
friend.Send(nil, user.NickMaskString(), line[1], line[2:]...)
}
}
break
}
}
}
func startRedis(server *Server) {
go server.ChannelSub()
go server.UserSub()
}
func (server *Server) GenerateImagorSignaturesFromMessage(message *ircmsg.Message) string {
line, err := message.Line()
if err == nil {
return server.GenerateImagorSignatures(line)
}
return ""
}
func (server *Server) GetUrlMime(url string) string {
config := server.Config()
// hacky, should fix
if !strings.Contains(url, "?") {
url += "?"
}
params := imagorpath.Params{
Image: url,
Meta: true,
}
metaPath := imagorpath.Generate(params, imagorpath.NewHMACSigner(sha256.New, 0, config.Cef.Imagor.Secret))
client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Get(config.Cef.Imagor.Url + metaPath)
if err != nil {
println("Failed on the initial get")
println(err.Error())
return ""
}
defer resp.Body.Close()
var meta map[string]interface{}
err = json.NewDecoder(resp.Body).Decode(&meta)
if err != nil {
println("Failed on the JSON decode")
return ""
}
contentType, valid := meta["format"].(string)
if !valid {
println("No content type")
return ""
}
return contentType
}
var urlRegex = regexp.MustCompile("https?:\\/\\/[\\w-]+(\\.[\\w-]+)+([\\w.,@?^=%&amp;:/~+#-]*[\\w@?^=%&amp;/~+#-])?")
// Process a message to add Imagor signatures
func (server *Server) GenerateImagorSignatures(str string) string {
urls := urlRegex.FindAllString(str, -1)
var sigs []string
for _, url := range urls {
params := imagorpath.Params{
Image: url,
FitIn: true,
Width: 600,
Height: 600,
}
path := imagorpath.Generate(params, imagorpath.NewHMACSigner(sha256.New, 0, server.Config().Cef.Imagor.Secret))
signature := path[:strings.IndexByte(path, '/')]
contentType := server.GetUrlMime(url)
if contentType != "" {
sigs = append(sigs, signature+"|"+strings.ReplaceAll(contentType, "/", "_"))
} else {
sigs = append(sigs, signature)
}
}
if len(sigs) > 0 {
return strings.Join(sigs, ",")
}
return ""
}

View file

@ -477,12 +477,6 @@ func (channel *Channel) Names(client *Client, rb *ResponseBuffer) {
if respectAuditorium && memberData.modes.HighestChannelUserMode() == modes.Mode(0) { if respectAuditorium && memberData.modes.HighestChannelUserMode() == modes.Mode(0) {
continue continue
} }
if rb.session.capabilities.Has(caps.ExtendedNames) {
away, _ := target.Away()
if away {
nick = nick + "*"
}
}
tl.AddParts(memberData.modes.Prefixes(isMultiPrefix), nick) tl.AddParts(memberData.modes.Prefixes(isMultiPrefix), nick)
} }
} }
@ -727,9 +721,6 @@ func (channel *Channel) AddHistoryItem(item history.Item, account string) (err e
if !itemIsStorable(&item, channel.server.Config()) { if !itemIsStorable(&item, channel.server.Config()) {
return return
} }
if item.Target == "" {
item.Target = channel.nameCasefolded
}
status, target, _ := channel.historyStatus(channel.server.Config()) status, target, _ := channel.historyStatus(channel.server.Config())
if status == HistoryPersistent { if status == HistoryPersistent {
@ -804,8 +795,6 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
} }
client.server.logger.Debug("channels", fmt.Sprintf("%s joined channel %s", details.nick, chname)) client.server.logger.Debug("channels", fmt.Sprintf("%s joined channel %s", details.nick, chname))
// I think this is assured to always be a good join point
channel.RedisBroadcast("VOICEPOLL")
givenMode := func() (givenMode modes.Mode) { givenMode := func() (givenMode modes.Mode) {
channel.joinPartMutex.Lock() channel.joinPartMutex.Lock()
@ -839,12 +828,11 @@ func (channel *Channel) Join(client *Client, key string, isSajoin bool, rb *Resp
// no history item for fake persistent joins // no history item for fake persistent joins
if rb != nil && !respectAuditorium { if rb != nil && !respectAuditorium {
histItem := history.Item{ histItem := history.Item{
Type: history.Join, Type: history.Join,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.account, AccountName: details.accountName,
Message: message, Message: message,
Target: channel.NameCasefolded(), IsBot: isBot,
IsBot: isBot,
} }
histItem.Params[0] = details.realname histItem.Params[0] = details.realname
channel.AddHistoryItem(histItem, details.account) channel.AddHistoryItem(histItem, details.account)
@ -975,7 +963,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
} }
} }
if 0 < numItems { if 0 < numItems {
channel.replayHistoryItems(rb, items, false, "", "", numItems) channel.replayHistoryItems(rb, items, false)
rb.Flush(true) rb.Flush(true)
} }
} }
@ -1003,7 +991,6 @@ func (channel *Channel) playJoinForSession(session *Session) {
channel.Names(client, sessionRb) channel.Names(client, sessionRb)
} }
sessionRb.Send(false) sessionRb.Send(false)
channel.RedisBroadcast("VOICEPOLL")
} }
// Part parts the given client from this channel, with the given message. // Part parts the given client from this channel, with the given message.
@ -1055,19 +1042,18 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
if !respectAuditorium { if !respectAuditorium {
channel.AddHistoryItem(history.Item{ channel.AddHistoryItem(history.Item{
Type: history.Part, Type: history.Part,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.account, AccountName: details.accountName,
Message: splitMessage, Message: splitMessage,
Target: channel.NameCasefolded(), IsBot: isBot,
IsBot: isBot,
}, details.account) }, details.account)
} }
client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname)) client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
} }
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, chathistoryCommand bool, identifier string, preposition string, limit int) { func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, chathistoryCommand bool) {
// send an empty batch if necessary, as per the CHATHISTORY spec // send an empty batch if necessary, as per the CHATHISTORY spec
chname := channel.Name() chname := channel.Name()
client := rb.target client := rb.target
@ -1087,19 +1073,19 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
} }
} }
batchID := rb.StartNestedBatch("chathistory", chname, identifier, preposition, strconv.Itoa(limit)) batchID := rb.StartNestedBatch("chathistory", chname)
defer rb.EndNestedBatch(batchID) defer rb.EndNestedBatch(batchID)
for _, item := range items { for _, item := range items {
nick := NUHToNick(item.Nick) nick := NUHToNick(item.Nick)
switch item.Type { switch item.Type {
case history.Privmsg: case history.Privmsg:
rb.AddSplitMessageFromClientWithReactions(item.Nick, item.Account, item.IsBot, item.Tags, "PRIVMSG", chname, item.Message, item.Reactions) rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, item.Tags, "PRIVMSG", chname, item.Message)
case history.Notice: case history.Notice:
rb.AddSplitMessageFromClientWithReactions(item.Nick, item.Account, item.IsBot, item.Tags, "NOTICE", chname, item.Message, item.Reactions) rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, item.Tags, "NOTICE", chname, item.Message)
case history.Tagmsg: case history.Tagmsg:
if eventPlayback { if eventPlayback {
rb.AddSplitMessageFromClient(item.Nick, item.Account, item.IsBot, item.Tags, "TAGMSG", chname, item.Message) rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, item.Tags, "TAGMSG", chname, item.Message)
} else if chathistoryCommand { } else if chathistoryCommand {
// #1676, we have to send something here or else it breaks pagination // #1676, we have to send something here or else it breaks pagination
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, fmt.Sprintf(client.t("%s sent a TAGMSG"), nick)) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, fmt.Sprintf(client.t("%s sent a TAGMSG"), nick))
@ -1107,25 +1093,25 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
case history.Join: case history.Join:
if eventPlayback { if eventPlayback {
if extendedJoin { if extendedJoin {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "JOIN", chname, item.Account, item.Params[0]) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "JOIN", chname, item.AccountName, item.Params[0])
} else { } else {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "JOIN", chname) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "JOIN", chname)
} }
} else { } else {
if !playJoinsAsPrivmsg { if !playJoinsAsPrivmsg {
continue // #474 continue // #474
} }
var message string var message string
if item.Account == "*" { if item.AccountName == "*" {
message = fmt.Sprintf(client.t("%s joined the channel"), nick) message = fmt.Sprintf(client.t("%s joined the channel"), nick)
} else { } else {
message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.Account) message = fmt.Sprintf(client.t("%[1]s [account: %[2]s] joined the channel"), nick, item.AccountName)
} }
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message)
} }
case history.Part: case history.Part:
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "PART", chname, item.Message.Message) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "PART", chname, item.Message.Message)
} else { } else {
if !playJoinsAsPrivmsg { if !playJoinsAsPrivmsg {
continue // #474 continue // #474
@ -1135,14 +1121,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
} }
case history.Kick: case history.Kick:
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "KICK", chname, item.Params[0], item.Message.Message) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "KICK", chname, item.Params[0], item.Message.Message)
} else { } else {
message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Params[0], item.Message.Message) message := fmt.Sprintf(client.t("%[1]s kicked %[2]s (%[3]s)"), nick, item.Params[0], item.Message.Message)
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message)
} }
case history.Quit: case history.Quit:
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "QUIT", item.Message.Message) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "QUIT", item.Message.Message)
} else { } else {
if !playJoinsAsPrivmsg { if !playJoinsAsPrivmsg {
continue // #474 continue // #474
@ -1152,14 +1138,14 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
} }
case history.Nick: case history.Nick:
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "NICK", item.Params[0]) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "NICK", item.Params[0])
} else { } else {
message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0]) message := fmt.Sprintf(client.t("%[1]s changed nick to %[2]s"), nick, item.Params[0])
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message)
} }
case history.Topic: case history.Topic:
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "TOPIC", chname, item.Message.Message) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "TOPIC", chname, item.Message.Message)
} else { } else {
message := fmt.Sprintf(client.t("%[1]s set the channel topic to: %[2]s"), nick, item.Message.Message) message := fmt.Sprintf(client.t("%[1]s set the channel topic to: %[2]s"), nick, item.Message.Message)
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message)
@ -1171,7 +1157,7 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
params[i+1] = pair.Message params[i+1] = pair.Message
} }
if eventPlayback { if eventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "MODE", params...) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "MODE", params...)
} else { } else {
message := fmt.Sprintf(client.t("%[1]s set channel modes: %[2]s"), nick, strings.Join(params[1:], " ")) message := fmt.Sprintf(client.t("%[1]s set channel modes: %[2]s"), nick, strings.Join(params[1:], " "))
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, message)
@ -1241,12 +1227,11 @@ func (channel *Channel) SetTopic(client *Client, topic string, rb *ResponseBuffe
} }
channel.AddHistoryItem(history.Item{ channel.AddHistoryItem(history.Item{
Type: history.Topic, Type: history.Topic,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.account, AccountName: details.accountName,
Message: message, Message: message,
IsBot: isBot, IsBot: isBot,
Target: channel.NameCasefolded(),
}, details.account) }, details.account)
channel.MarkDirty(IncludeTopic) channel.MarkDirty(IncludeTopic)
@ -1335,11 +1320,6 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
isBot := client.HasMode(modes.Bot) isBot := client.HasMode(modes.Bot)
chname := channel.Name() chname := channel.Name()
// STATUSMSG targets are prefixed with the supplied min-prefix, e.g., @#channel
if minPrefixMode != modes.Mode(0) {
chname = fmt.Sprintf("%s%s", modes.ChannelModePrefixes[minPrefixMode], chname)
}
if !client.server.Config().Server.Compatibility.allowTruncation { if !client.server.Config().Server.Compatibility.allowTruncation {
if !validateSplitMessageLen(histType, details.nickMask, chname, message) { if !validateSplitMessageLen(histType, details.nickMask, chname, message) {
rb.Add(nil, client.server.name, ERR_INPUTTOOLONG, details.nick, client.t("Line too long to be relayed without truncation")) rb.Add(nil, client.server.name, ERR_INPUTTOOLONG, details.nick, client.t("Line too long to be relayed without truncation"))
@ -1347,6 +1327,11 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
} }
} }
// STATUSMSG targets are prefixed with the supplied min-prefix, e.g., @#channel
if minPrefixMode != modes.Mode(0) {
chname = fmt.Sprintf("%s%s", modes.ChannelModePrefixes[minPrefixMode], chname)
}
if channel.flags.HasMode(modes.OpModerated) { if channel.flags.HasMode(modes.OpModerated) {
channel.stateMutex.RLock() channel.stateMutex.RLock()
cuData, ok := channel.members[client] cuData, ok := channel.members[client]
@ -1386,13 +1371,12 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
// #959: don't save STATUSMSG (or OpModerated) // #959: don't save STATUSMSG (or OpModerated)
if minPrefixMode == modes.Mode(0) { if minPrefixMode == modes.Mode(0) {
channel.AddHistoryItem(history.Item{ channel.AddHistoryItem(history.Item{
Type: histType, Type: histType,
Message: message, Message: message,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.accountName, AccountName: details.accountName,
Tags: clientOnlyTags, Tags: clientOnlyTags,
IsBot: isBot, IsBot: isBot,
Target: channel.NameCasefolded(),
}, details.account) }, details.account)
} }
} }
@ -1466,7 +1450,6 @@ func (channel *Channel) Quit(client *Client) {
client.server.channels.Cleanup(channel) client.server.channels.Cleanup(channel)
} }
client.removeChannel(channel) client.removeChannel(channel)
channel.Broadcast("KICK", client.NickCasefolded())
} }
func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer, hasPrivs bool) { func (channel *Channel) Kick(client *Client, target *Client, comment string, rb *ResponseBuffer, hasPrivs bool) {
@ -1499,12 +1482,11 @@ func (channel *Channel) Kick(client *Client, target *Client, comment string, rb
rb.AddFromClient(message.Time, message.Msgid, details.nickMask, details.accountName, isBot, nil, "KICK", chname, targetNick, comment) rb.AddFromClient(message.Time, message.Msgid, details.nickMask, details.accountName, isBot, nil, "KICK", chname, targetNick, comment)
histItem := history.Item{ histItem := history.Item{
Type: history.Kick, Type: history.Kick,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.account, AccountName: details.accountName,
Message: message, Message: message,
IsBot: isBot, IsBot: isBot,
Target: channel.NameCasefolded(),
} }
histItem.Params[0] = targetNick histItem.Params[0] = targetNick
channel.AddHistoryItem(histItem, details.account) channel.AddHistoryItem(histItem, details.account)
@ -1531,7 +1513,7 @@ func (channel *Channel) Purge(source string) {
now := time.Now().UTC() now := time.Now().UTC()
for _, member := range members { for _, member := range members {
tnick := member.Nick() tnick := member.Nick()
msgid := utils.GenerateMessageIdStr() msgid := utils.GenerateSecretToken()
for _, session := range member.Sessions() { for _, session := range member.Sessions() {
session.sendFromClientInternal(false, now, msgid, source, "*", false, nil, "KICK", chname, tnick, member.t("This channel has been purged by the server administrators and cannot be used")) session.sendFromClientInternal(false, now, msgid, source, "*", false, nil, "KICK", chname, tnick, member.t("This channel has been purged by the server administrators and cannot be used"))
} }
@ -1581,8 +1563,6 @@ func (channel *Channel) Invite(invitee *Client, inviter *Client, rb *ResponseBuf
item := history.Item{ item := history.Item{
Type: history.Invite, Type: history.Invite,
Message: message, Message: message,
Account: inviter.Account(),
Target: invitee.Account(),
} }
for _, member := range channel.Members() { for _, member := range channel.Members() {

View file

@ -753,7 +753,6 @@ func csListHandler(service *ircService, server *Server, client *Client, command
} }
func csInfoHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) { func csInfoHandler(service *ircService, server *Server, client *Client, command string, params []string, rb *ResponseBuffer) {
if len(params) == 0 { if len(params) == 0 {
// #765 // #765
listRegisteredChannels(service, client.Account(), rb) listRegisteredChannels(service, client.Account(), rb)
@ -766,41 +765,37 @@ func csInfoHandler(service *ircService, server *Server, client *Client, command
return return
} }
// purge status
if client.HasRoleCapabs("chanreg") {
purgeRecord, err := server.channels.LoadPurgeRecord(chname)
if err == nil {
service.Notice(rb, fmt.Sprintf(client.t("Channel %s was purged by the server operators and cannot be used"), chname))
service.Notice(rb, fmt.Sprintf(client.t("Purged by operator: %s"), purgeRecord.Oper))
service.Notice(rb, fmt.Sprintf(client.t("Purged at: %s"), purgeRecord.PurgedAt.Format(time.RFC1123)))
if purgeRecord.Reason != "" {
service.Notice(rb, fmt.Sprintf(client.t("Purge reason: %s"), purgeRecord.Reason))
}
}
} else {
if server.channels.IsPurged(chname) {
service.Notice(rb, fmt.Sprintf(client.t("Channel %s was purged by the server operators and cannot be used"), chname))
}
}
var chinfo RegisteredChannel var chinfo RegisteredChannel
channel := server.channels.Get(params[0]) channel := server.channels.Get(params[0])
if channel != nil { if channel != nil {
chinfo = channel.exportSummary() chinfo = channel.exportSummary()
} }
tags := map[string]string{
"target": chinfo.Name,
}
// purge status
if client.HasRoleCapabs("chanreg") {
purgeRecord, err := server.channels.LoadPurgeRecord(chname)
if err == nil {
service.TaggedNotice(rb, fmt.Sprintf(client.t("Channel %s was purged by the server operators and cannot be used"), chname), tags)
service.TaggedNotice(rb, fmt.Sprintf(client.t("Purged by operator: %s"), purgeRecord.Oper), tags)
service.TaggedNotice(rb, fmt.Sprintf(client.t("Purged at: %s"), purgeRecord.PurgedAt.Format(time.RFC1123)), tags)
if purgeRecord.Reason != "" {
service.TaggedNotice(rb, fmt.Sprintf(client.t("Purge reason: %s"), purgeRecord.Reason), tags)
}
}
} else {
if server.channels.IsPurged(chname) {
service.TaggedNotice(rb, fmt.Sprintf(client.t("Channel %s was purged by the server operators and cannot be used"), chname), tags)
}
}
// channel exists but is unregistered, or doesn't exist: // channel exists but is unregistered, or doesn't exist:
if chinfo.Founder == "" { if chinfo.Founder == "" {
service.TaggedNotice(rb, fmt.Sprintf(client.t("Channel %s is not registered"), chname), tags) service.Notice(rb, fmt.Sprintf(client.t("Channel %s is not registered"), chname))
return return
} }
service.TaggedNotice(rb, fmt.Sprintf(client.t("Channel %s is registered"), chinfo.Name), tags) service.Notice(rb, fmt.Sprintf(client.t("Channel %s is registered"), chinfo.Name))
service.TaggedNotice(rb, fmt.Sprintf(client.t("Founder: %s"), chinfo.Founder), tags) service.Notice(rb, fmt.Sprintf(client.t("Founder: %s"), chinfo.Founder))
service.TaggedNotice(rb, fmt.Sprintf(client.t("Registered at: %s"), chinfo.RegisteredAt.Format(time.RFC1123)), tags) service.Notice(rb, fmt.Sprintf(client.t("Registered at: %s"), chinfo.RegisteredAt.Format(time.RFC1123)))
} }
func displayChannelSetting(service *ircService, settingName string, settings ChannelSettings, client *Client, rb *ResponseBuffer) { func displayChannelSetting(service *ircService, settingName string, settings ChannelSettings, client *Client, rb *ResponseBuffer) {

View file

@ -35,8 +35,8 @@ import (
) )
const ( const (
// Set to 4096 because CEF doesn't care about compatibility // maximum IRC line length, not including tags
DefaultMaxLineLen = 4096 DefaultMaxLineLen = 512
// IdentTimeout is how long before our ident (username) check times out. // IdentTimeout is how long before our ident (username) check times out.
IdentTimeout = time.Second + 500*time.Millisecond IdentTimeout = time.Second + 500*time.Millisecond
@ -179,8 +179,6 @@ type Session struct {
batchCounter atomic.Uint32 batchCounter atomic.Uint32
isupportSentPrereg bool
quitMessage string quitMessage string
awayMessage string awayMessage string
@ -651,17 +649,6 @@ func (client *Client) run(session *Session) {
firstLine := !isReattach firstLine := !isReattach
correspondents, _ := client.server.historyDB.GetPMs(client.Account())
// For safety, let's keep this within the 4096 character barrier
var lineBuilder utils.TokenLineBuilder
lineBuilder.Initialize(MaxLineLen, ",")
for username, timestamp := range correspondents {
lineBuilder.Add(fmt.Sprintf("%s %d", client.server.getCurrentNick(username), timestamp))
}
for _, message := range lineBuilder.Lines() {
session.Send(nil, client.server.name, "PMS", message)
}
for { for {
var invalidUtf8 bool var invalidUtf8 bool
line, err := session.socket.Read() line, err := session.socket.Read()
@ -875,14 +862,14 @@ func (session *Session) Ping() {
session.Send(nil, "", "PING", session.client.Nick()) session.Send(nil, "", "PING", session.client.Nick())
} }
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, chathistoryCommand bool, identifier string, preposition string, limit int) { func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, chathistoryCommand bool) {
var batchID string var batchID string
details := client.Details() details := client.Details()
nick := details.nick nick := details.nick
if target == "" { if target == "" {
target = nick target = nick
} }
batchID = rb.StartNestedBatch("chathistory", target, identifier, preposition, strconv.Itoa(limit)) batchID = rb.StartNestedBatch("chathistory", target)
isSelfMessage := func(item *history.Item) bool { isSelfMessage := func(item *history.Item) bool {
// XXX: Params[0] is the message target. if the source of this message is an in-memory // XXX: Params[0] is the message target. if the source of this message is an in-memory
@ -903,7 +890,7 @@ func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.I
continue continue
} }
if hasEventPlayback { if hasEventPlayback {
rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.Account, item.IsBot, nil, "INVITE", nick, item.Message.Message) rb.AddFromClient(item.Message.Time, item.Message.Msgid, item.Nick, item.AccountName, item.IsBot, nil, "INVITE", nick, item.Message.Message)
} else { } else {
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", fmt.Sprintf(client.t("%[1]s invited you to channel %[2]s"), NUHToNick(item.Nick), item.Message.Message)) rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", fmt.Sprintf(client.t("%[1]s invited you to channel %[2]s"), NUHToNick(item.Nick), item.Message.Message))
} }
@ -931,11 +918,11 @@ func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.I
tags = item.Tags tags = item.Tags
} }
if !isSelfMessage(&item) { if !isSelfMessage(&item) {
rb.AddSplitMessageFromClientWithReactions(item.Nick, item.Account, item.IsBot, tags, command, nick, item.Message, item.Reactions) rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, tags, command, nick, item.Message)
} else { } else {
// this message was sent *from* the client to another nick; the target is item.Params[0] // this message was sent *from* the client to another nick; the target is item.Params[0]
// substitute client's current nickmask in case client changed nick // substitute client's current nickmask in case client changed nick
rb.AddSplitMessageFromClientWithReactions(details.nickMask, item.Account, item.IsBot, tags, command, item.Params[0], item.Message, item.Reactions) rb.AddSplitMessageFromClient(details.nickMask, item.AccountName, item.IsBot, tags, command, item.Params[0], item.Message)
} }
} }
@ -1365,11 +1352,11 @@ func (client *Client) destroy(session *Session) {
splitQuitMessage := utils.MakeMessage(quitMessage) splitQuitMessage := utils.MakeMessage(quitMessage)
isBot := client.HasMode(modes.Bot) isBot := client.HasMode(modes.Bot)
quitItem = history.Item{ quitItem = history.Item{
Type: history.Quit, Type: history.Quit,
Nick: details.nickMask, Nick: details.nickMask,
Account: details.accountName, AccountName: details.accountName,
Message: splitQuitMessage, Message: splitQuitMessage,
IsBot: isBot, IsBot: isBot,
} }
var cache MessageCache var cache MessageCache
cache.Initialize(client.server, splitQuitMessage.Time, splitQuitMessage.Msgid, details.nickMask, details.accountName, isBot, nil, "QUIT", quitMessage) cache.Initialize(client.server, splitQuitMessage.Time, splitQuitMessage.Msgid, details.nickMask, details.accountName, isBot, nil, "QUIT", quitMessage)
@ -1449,10 +1436,6 @@ func composeMultilineBatch(batchID, fromNickMask, fromAccount string, isBot bool
for _, msg := range message.Split { for _, msg := range message.Split {
message := ircmsg.MakeMessage(nil, fromNickMask, command, target, msg.Message) message := ircmsg.MakeMessage(nil, fromNickMask, command, target, msg.Message)
message.SetTag("batch", batchID) message.SetTag("batch", batchID)
for k, v := range msg.Tags {
message.SetTag(k, v)
}
if msg.Concat { if msg.Concat {
message.SetTag(caps.MultilineConcatTag, "") message.SetTag(caps.MultilineConcatTag, "")
} }
@ -1690,7 +1673,7 @@ func (client *Client) addHistoryItem(target *Client, item history.Item, details,
} }
item.Nick = details.nickMask item.Nick = details.nickMask
item.Account = details.account item.AccountName = details.accountName
targetedItem := item targetedItem := item
targetedItem.Params[0] = tDetails.nick targetedItem.Params[0] = tDetails.nick
@ -1698,15 +1681,15 @@ func (client *Client) addHistoryItem(target *Client, item history.Item, details,
tStatus, _ := target.historyStatus(config) tStatus, _ := target.historyStatus(config)
// add to ephemeral history // add to ephemeral history
if cStatus == HistoryEphemeral { if cStatus == HistoryEphemeral {
targetedItem.Target = tDetails.account targetedItem.CfCorrespondent = tDetails.nickCasefolded
client.history.Add(targetedItem) client.history.Add(targetedItem)
} }
if tStatus == HistoryEphemeral && client != target { if tStatus == HistoryEphemeral && client != target {
item.Target = target.Account() item.CfCorrespondent = details.nickCasefolded
target.history.Add(item) target.history.Add(item)
} }
if cStatus == HistoryPersistent || tStatus == HistoryPersistent { if cStatus == HistoryPersistent || tStatus == HistoryPersistent {
targetedItem.Target = target.account targetedItem.CfCorrespondent = ""
client.server.historyDB.AddDirectMessage(details.nickCasefolded, details.account, tDetails.nickCasefolded, tDetails.account, targetedItem) client.server.historyDB.AddDirectMessage(details.nickCasefolded, details.account, tDetails.nickCasefolded, tDetails.account, targetedItem)
} }
return nil return nil

View file

@ -152,10 +152,6 @@ func init() {
handler: isonHandler, handler: isonHandler,
minParams: 1, minParams: 1,
}, },
"ISUPPORT": {
handler: isupportHandler,
usablePreReg: true,
},
"JOIN": { "JOIN": {
handler: joinHandler, handler: joinHandler,
minParams: 1, minParams: 1,
@ -383,11 +379,6 @@ func init() {
handler: zncHandler, handler: zncHandler,
minParams: 1, minParams: 1,
}, },
// CEF custom commands
"REACT": {
handler: reactHandler,
minParams: 2,
},
} }
initializeServices() initializeServices()

View file

@ -709,14 +709,6 @@ type Config struct {
} }
Filename string Filename string
Cef struct {
Imagor struct {
Url string
Secret string
}
Redis string
}
} }
// OperClass defines an assembled operator class. // OperClass defines an assembled operator class.
@ -1664,7 +1656,6 @@ func (config *Config) generateISupport() (err error) {
isupport.Add("RPCHAN", "E") isupport.Add("RPCHAN", "E")
isupport.Add("RPUSER", "E") isupport.Add("RPUSER", "E")
} }
isupport.Add("SAFELIST", "")
isupport.Add("STATUSMSG", "~&@%+") isupport.Add("STATUSMSG", "~&@%+")
isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:%d", maxTargetsString, maxTargetsString, maxTargetsString, config.Limits.MonitorEntries)) isupport.Add("TARGMAX", fmt.Sprintf("NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:%s,TAGMSG:%s,NOTICE:%s,MONITOR:%d", maxTargetsString, maxTargetsString, maxTargetsString, config.Limits.MonitorEntries))
isupport.Add("TOPICLEN", strconv.Itoa(config.Limits.TopicLen)) isupport.Add("TOPICLEN", strconv.Itoa(config.Limits.TopicLen))

View file

@ -8,7 +8,7 @@ package irc
const ( const (
// maxLastArgLength is used to simply cap off the final argument when creating general messages where we need to select a limit. // maxLastArgLength is used to simply cap off the final argument when creating general messages where we need to select a limit.
// for instance, in MONITOR lists, RPL_ISUPPORT lists, etc. // for instance, in MONITOR lists, RPL_ISUPPORT lists, etc.
maxLastArgLength = 1024 maxLastArgLength = 400
// maxTargets is the maximum number of targets for PRIVMSG and NOTICE. // maxTargets is the maximum number of targets for PRIVMSG and NOTICE.
maxTargets = 4 maxTargets = 4
) )

View file

@ -275,6 +275,6 @@ func (dm *DLineManager) loadFromDatastore() {
}) })
} }
func (server *Server) loadDLines() { func (s *Server) loadDLines() {
server.dlines = NewDLineManager(server) s.dlines = NewDLineManager(s)
} }

View file

@ -1,4 +1,4 @@
//go:build !(plan9 || solaris) //go:build !plan9
package flock package flock

View file

@ -1,4 +1,4 @@
//go:build plan9 || solaris //go:build plan9
package flock package flock

View file

@ -410,11 +410,7 @@ func (client *Client) SetMode(mode modes.Mode, on bool) bool {
func (client *Client) SetRealname(realname string) { func (client *Client) SetRealname(realname string) {
client.stateMutex.Lock() client.stateMutex.Lock()
// TODO: make this configurable
client.realname = realname client.realname = realname
if len(realname) > 128 {
client.realname = client.realname[:128]
}
alwaysOn := client.registered && client.alwaysOn alwaysOn := client.registered && client.alwaysOn
client.stateMutex.Unlock() client.stateMutex.Unlock()
if alwaysOn { if alwaysOn {

View file

@ -570,16 +570,6 @@ func batchHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon
// XXX changing the label inside a handler is a bit dodgy, but it works here // XXX changing the label inside a handler is a bit dodgy, but it works here
// because there's no way we could have triggered a flush up to this point // because there's no way we could have triggered a flush up to this point
rb.Label = batch.responseLabel rb.Label = batch.responseLabel
for _, msg := range batch.message.Split {
signatures := server.GenerateImagorSignatures(msg.Message)
if len(signatures) > 0 {
if msg.Tags == nil {
msg.Tags = make(map[string]string)
}
msg.Tags["signatures"] = signatures
}
}
dispatchMessageToTarget(client, batch.tags, histType, batch.command, batch.target, batch.message, rb) dispatchMessageToTarget(client, batch.tags, histType, batch.command, batch.target, batch.message, rb)
} }
} }
@ -712,14 +702,6 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
var err error var err error
var listTargets bool var listTargets bool
var targets []history.TargetListing var targets []history.TargetListing
var _, batchIdentifier = msg.GetTag("identifier")
var assuredPreposition = "error"
var limit int
if len(batchIdentifier) == 0 {
batchIdentifier = "UNIDENTIFIED"
}
defer func() { defer func() {
// errors are sent either without a batch, or in a draft/labeled-response batch as usual // errors are sent either without a batch, or in a draft/labeled-response batch as usual
if err == utils.ErrInvalidParams { if err == utils.ErrInvalidParams {
@ -739,9 +721,9 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
target.Time.Format(IRCv3TimestampFormat)) target.Time.Format(IRCv3TimestampFormat))
} }
} else if channel != nil { } else if channel != nil {
channel.replayHistoryItems(rb, items, true, batchIdentifier, assuredPreposition, limit) channel.replayHistoryItems(rb, items, true)
} else { } else {
client.replayPrivmsgHistory(rb, items, target, true, batchIdentifier, assuredPreposition, limit) client.replayPrivmsgHistory(rb, items, target, true)
} }
} }
}() }()
@ -794,6 +776,7 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
paramPos := 2 paramPos := 2
var start, end history.Selector var start, end history.Selector
var limit int
switch preposition { switch preposition {
case "targets": case "targets":
// use the same selector parsing as BETWEEN, // use the same selector parsing as BETWEEN,
@ -848,7 +831,6 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
err = utils.ErrInvalidParams err = utils.ErrInvalidParams
return return
} }
assuredPreposition = preposition
if listTargets { if listTargets {
targets, err = client.listTargets(start, end, limit) targets, err = client.listTargets(start, end, limit)
@ -873,6 +855,7 @@ func debugHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respon
switch param { switch param {
case "GCSTATS": case "GCSTATS":
stats := debug.GCStats{ stats := debug.GCStats{
Pause: make([]time.Duration, 10),
PauseQuantiles: make([]time.Duration, 5), PauseQuantiles: make([]time.Duration, 5),
} }
debug.ReadGCStats(&stats) debug.ReadGCStats(&stats)
@ -1145,12 +1128,6 @@ func extjwtHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
} }
claims["channel"] = channel.Name() claims["channel"] = channel.Name()
var channelModeStrings []string
for _, mode := range channel.flags.AllModes() {
channelModeStrings = append(channelModeStrings, mode.String())
}
claims["chanModes"] = channelModeStrings
claims["joined"] = 0 claims["joined"] = 0
claims["cmodes"] = []string{} claims["cmodes"] = []string{}
if present, joinTimeSecs, cModes := channel.ClientStatus(client); present { if present, joinTimeSecs, cModes := channel.ClientStatus(client); present {
@ -1234,34 +1211,29 @@ Get an explanation of <argument>, or "index" for a list of help topics.`), rb)
// HISTORY alice 15 // HISTORY alice 15
// HISTORY #darwin 1h // HISTORY #darwin 1h
func historyHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool { func historyHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
rb.Notice(client.t("This command is currently disabled. Please use CHATHISTORY")) config := server.Config()
/* if !config.History.Enabled {
config := server.Config() rb.Notice(client.t("This command has been disabled by the server administrators"))
if !config.History.Enabled { return false
rb.Notice(client.t("This command has been disabled by the server administrators")) }
return false
items, channel, err := easySelectHistory(server, client, msg.Params)
if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false
} else if err != nil {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), msg.Command, client.t("Could not retrieve history"))
return false
}
if len(items) != 0 {
if channel != nil {
channel.replayHistoryItems(rb, items, true)
} else {
client.replayPrivmsgHistory(rb, items, "", true)
} }
}
items, channel, err := easySelectHistory(server, client, msg.Params)
if err == errNoSuchChannel {
rb.Add(nil, server.name, ERR_NOSUCHCHANNEL, client.Nick(), utils.SafeErrorParam(msg.Params[0]), client.t("No such channel"))
return false
} else if err != nil {
rb.Add(nil, server.name, ERR_UNKNOWNERROR, client.Nick(), msg.Command, client.t("Could not retrieve history"))
return false
}
var _, batchIdentifier = msg.GetTag("identifier")
if len(items) != 0 {
if channel != nil {
channel.replayHistoryItems(rb, items, true, batchIdentifier)
} else {
client.replayPrivmsgHistory(rb, items, "", true, batchIdentifier)
}
}
*/
return false return false
} }
@ -1349,15 +1321,6 @@ func isonHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respons
return false return false
} }
// ISUPPORT
func isupportHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
server.RplISupport(client, rb)
if !client.registered {
rb.session.isupportSentPrereg = true
}
return false
}
// JOIN <channel>{,<channel>} [<key>{,<key>}] // JOIN <channel>{,<channel>} [<key>{,<key>}]
func joinHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool { func joinHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
// #1417: allow `JOIN 0` with a confirmation code // #1417: allow `JOIN 0` with a confirmation code
@ -1926,12 +1889,11 @@ func announceCmodeChanges(channel *Channel, applied modes.ModeChanges, source, a
} }
} }
channel.AddHistoryItem(history.Item{ channel.AddHistoryItem(history.Item{
Type: history.Mode, Type: history.Mode,
Nick: source, Nick: source,
Account: accountName, AccountName: accountName,
Message: message, Message: message,
Target: channel.NameCasefolded(), IsBot: isBot,
IsBot: isBot,
}, account) }, account)
} }
} }
@ -2222,7 +2184,6 @@ func validateLineLen(msgType history.ItemType, source, target, payload string) (
default: default:
return true return true
} }
limit -= len(target)
limit -= len(payload) limit -= len(payload)
return limit >= 0 return limit >= 0
} }
@ -2272,7 +2233,7 @@ func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.Message, ba
if !isConcat && len(rb.session.batch.message.Split) != 0 { if !isConcat && len(rb.session.batch.message.Split) != 0 {
rb.session.batch.lenBytes++ // bill for the newline rb.session.batch.lenBytes++ // bill for the newline
} }
rb.session.batch.message.Append(msg.Params[1], isConcat, msg.ClientOnlyTags()) rb.session.batch.message.Append(msg.Params[1], isConcat)
rb.session.batch.lenBytes += len(msg.Params[1]) rb.session.batch.lenBytes += len(msg.Params[1])
config := server.Config() config := server.Config()
if config.Limits.Multiline.MaxBytes < rb.session.batch.lenBytes { if config.Limits.Multiline.MaxBytes < rb.session.batch.lenBytes {
@ -2350,53 +2311,11 @@ func messageHandler(server *Server, client *Client, msg ircmsg.Message, rb *Resp
// each target gets distinct msgids // each target gets distinct msgids
splitMsg := utils.MakeMessage(message) splitMsg := utils.MakeMessage(message)
signatures := server.GenerateImagorSignaturesFromMessage(&msg)
if len(signatures) > 0 {
if clientOnlyTags == nil {
clientOnlyTags = make(map[string]string)
}
clientOnlyTags["signatures"] = signatures
}
dispatchMessageToTarget(client, clientOnlyTags, histType, msg.Command, targetString, splitMsg, rb) dispatchMessageToTarget(client, clientOnlyTags, histType, msg.Command, targetString, splitMsg, rb)
} }
return false return false
} }
// Not really sure how to do this in Go
var endChars = map[int32]bool{
' ': true,
'@': true,
':': true,
'!': true,
'?': true,
}
func detectMentions(message string) (mentions []string) {
buf := ""
mentions = []string{}
working := false
for _, char := range message {
if char == '@' {
working = true
continue
}
if !working {
continue
}
if _, stop := endChars[char]; stop {
working = false
mentions = append(mentions, buf)
buf = ""
} else {
buf += string(char)
}
}
if len(buf) != 0 {
mentions = append(mentions, buf)
}
return
}
func dispatchMessageToTarget(client *Client, tags map[string]string, histType history.ItemType, command, target string, message utils.SplitMessage, rb *ResponseBuffer) { func dispatchMessageToTarget(client *Client, tags map[string]string, histType history.ItemType, command, target string, message utils.SplitMessage, rb *ResponseBuffer) {
server := client.server server := client.server
@ -2413,15 +2332,7 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi
} }
return return
} }
// This likely isn't that great for performance. Should figure out some way to deal with this at some point
mentions := detectMentions(message.Message)
channel.SendSplitMessage(command, lowestPrefix, tags, client, message, rb) channel.SendSplitMessage(command, lowestPrefix, tags, client, message, rb)
for _, mention := range mentions {
user := client.server.clients.Get(mention)
if user != nil {
user.RedisBroadcast("MENTION", channel.Name(), message.Msgid)
}
}
} else if target[0] == '$' && len(target) > 2 && client.Oper().HasRoleCapab("massmessage") { } else if target[0] == '$' && len(target) > 2 && client.Oper().HasRoleCapab("massmessage") {
details := client.Details() details := client.Details()
matcher, err := utils.CompileGlob(target[2:], false) matcher, err := utils.CompileGlob(target[2:], false)
@ -2444,7 +2355,6 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi
} }
} }
} else { } else {
// PMs
lowercaseTarget := strings.ToLower(target) lowercaseTarget := strings.ToLower(target)
service, isService := ErgoServices[lowercaseTarget] service, isService := ErgoServices[lowercaseTarget]
_, isZNC := zncHandlers[lowercaseTarget] _, isZNC := zncHandlers[lowercaseTarget]
@ -2544,13 +2454,8 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi
Type: histType, Type: histType,
Message: message, Message: message,
Tags: tags, Tags: tags,
Target: user.Account(),
Account: client.Account(),
} }
client.addHistoryItem(user, item, &details, &tDetails, config) client.addHistoryItem(user, item, &details, &tDetails, config)
user.RedisBroadcast("MENTION", user.NickCasefolded(), message.Msgid)
} }
} }
@ -2839,7 +2744,7 @@ func redactHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
var members []*Client // members of a channel, or both parties of a PM var members []*Client // members of a channel, or both parties of a PM
var canDelete CanDelete var canDelete CanDelete
msgid := utils.GenerateMessageIdStr() msgid := utils.GenerateSecretToken()
time := time.Now().UTC().Round(0) time := time.Now().UTC().Round(0)
details := client.Details() details := client.Details()
isBot := client.HasMode(modes.Bot) isBot := client.HasMode(modes.Bot)
@ -2866,16 +2771,16 @@ func redactHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
rb.Add(nil, server.name, "FAIL", "REDACT", "REDACT_FORBIDDEN", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("You are not authorized to delete messages")) rb.Add(nil, server.name, "FAIL", "REDACT", "REDACT_FORBIDDEN", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("You are not authorized to delete messages"))
return false return false
} }
account := "*" accountName := "*"
if canDelete == canDeleteSelf { if canDelete == canDeleteSelf {
account = client.account accountName = client.AccountName()
if account == "*" { if accountName == "*" {
rb.Add(nil, server.name, "FAIL", "REDACT", "REDACT_FORBIDDEN", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("You are not authorized to delete this message")) rb.Add(nil, server.name, "FAIL", "REDACT", "REDACT_FORBIDDEN", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("You are not authorized to delete this message"))
return false return false
} }
} }
err := server.DeleteMessage(target, targetmsgid, account) err := server.DeleteMessage(target, targetmsgid, accountName)
if err == errNoop { if err == errNoop {
rb.Add(nil, server.name, "FAIL", "REDACT", "UNKNOWN_MSGID", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("This message does not exist or is too old")) rb.Add(nil, server.name, "FAIL", "REDACT", "UNKNOWN_MSGID", utils.SafeErrorParam(target), utils.SafeErrorParam(targetmsgid), client.t("This message does not exist or is too old"))
return false return false
@ -2892,7 +2797,7 @@ func redactHandler(server *Server, client *Client, msg ircmsg.Message, rb *Respo
if target[0] != '#' { if target[0] != '#' {
// If this is a PM, we just removed the message from the buffer of the other party; // If this is a PM, we just removed the message from the buffer of the other party;
// now we have to remove it from the buffer of the client who sent the REDACT command // now we have to remove it from the buffer of the client who sent the REDACT command
err := server.DeleteMessage(client.Nick(), targetmsgid, account) err := server.DeleteMessage(client.Nick(), targetmsgid, accountName)
if err != nil { if err != nil {
client.server.logger.Error("internal", fmt.Sprintf("Private message %s is not deletable by %s from their own buffer's even though we just deleted it from %s's. This is a bug, please report it in details.", targetmsgid, client.Nick(), target), client.Nick()) client.server.logger.Error("internal", fmt.Sprintf("Private message %s is not deletable by %s from their own buffer's even though we just deleted it from %s's. This is a bug, please report it in details.", targetmsgid, client.Nick(), target), client.Nick())
@ -3218,8 +3123,6 @@ func relaymsgHandler(server *Server, client *Client, msg ircmsg.Message, rb *Res
Type: history.Privmsg, Type: history.Privmsg,
Message: message, Message: message,
Nick: nuh, Nick: nuh,
Target: channel.NameCasefolded(),
Account: "$RELAYMSG",
}, "") }, "")
// 3 possibilities for tags: // 3 possibilities for tags:
@ -4085,33 +3988,6 @@ func zncHandler(server *Server, client *Client, msg ircmsg.Message, rb *Response
return false return false
} }
// REACT <msgid> :<reaction>
func reactHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
// This directly uses SQL stuff, since it's targeted at CEF, which requires a DB.
_, _, target, sender, _, pm, err := server.historyDB.GetMessage(msg.Params[0])
if err != nil {
return false
}
var operation string
if server.historyDB.HasReactionFromUser(msg.Params[0], client.AccountName(), msg.Params[1]) {
server.historyDB.DeleteReaction(msg.Params[0], client.AccountName(), msg.Params[1])
operation = "DEL"
} else {
server.historyDB.AddReaction(msg.Params[0], client.AccountName(), msg.Params[1])
operation = "ADD"
}
if pm {
server.clients.Get(target).Send(nil, client.NickMaskString(), "REACT", operation, msg.Params[0], msg.Params[1])
server.clients.Get(sender).Send(nil, client.NickMaskString(), "REACT", operation, msg.Params[0], msg.Params[1])
} else {
server.channels.Get(target).BroadcastFrom(client.NickMaskString(), "REACT", operation, msg.Params[0], msg.Params[1])
}
return false
}
// fake handler for unknown commands // fake handler for unknown commands
func unknownCommandHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool { func unknownCommandHandler(server *Server, client *Client, msg ircmsg.Message, rb *ResponseBuffer) bool {
var message string var message string

View file

@ -259,11 +259,6 @@ appropriate channel privs.`,
text: `ISON <nickname>{ <nickname>} text: `ISON <nickname>{ <nickname>}
Returns whether the given nicks exist on the network.`, Returns whether the given nicks exist on the network.`,
},
"isupport": {
text: `ISUPPORT
Returns RPL_ISUPPORT lines describing the server's capabilities.`,
}, },
"join": { "join": {
text: `JOIN <channel>{,<channel>} [<key>{,<key>}] text: `JOIN <channel>{,<channel>} [<key>{,<key>}]
@ -634,12 +629,6 @@ for direct use by end users.`,
duplicate: true, duplicate: true,
}, },
"react": {
text: `REACT <msgid> <reaction>
Toggles a reaction to a message. CEF-specific`,
},
// Informational // Informational
"modes": { "modes": {
textGenerator: modesTextGenerator, textGenerator: modesTextGenerator,

View file

@ -32,20 +32,13 @@ const (
initialAutoSize = 32 initialAutoSize = 32
) )
type Reaction struct {
Name string
Total int
SampleUsers []string
}
// Item represents an event (e.g., a PRIVMSG or a JOIN) and its associated data // Item represents an event (e.g., a PRIVMSG or a JOIN) and its associated data
type Item struct { type Item struct {
Type ItemType Type ItemType
Nick string Nick string
// this is the uncasefolded account name, if there's no account it should be set to "*" // this is the uncasefolded account name, if there's no account it should be set to "*"
// in cef, this is always set, at least in theory. cant wait for bugs toc rop up AccountName string
Account string
// for non-privmsg items, we may stuff some other data in here // for non-privmsg items, we may stuff some other data in here
Message utils.SplitMessage Message utils.SplitMessage
Tags map[string]string Tags map[string]string
@ -53,10 +46,8 @@ type Item struct {
// for a DM, this is the casefolded nickname of the other party (whether this is // for a DM, this is the casefolded nickname of the other party (whether this is
// an incoming or outgoing message). this lets us emulate the "query buffer" functionality // an incoming or outgoing message). this lets us emulate the "query buffer" functionality
// required by CHATHISTORY: // required by CHATHISTORY:
Target string `json:"Target"` CfCorrespondent string `json:"CfCorrespondent,omitempty"`
IsBot bool `json:"IsBot,omitempty"` IsBot bool `json:"IsBot,omitempty"`
Reactions []Reaction
} }
// HasMsgid tests whether a message has the message id `msgid`. // HasMsgid tests whether a message has the message id `msgid`.
@ -222,10 +213,10 @@ func (list *Buffer) allCorrespondents() (results []TargetListing) {
stop := list.start stop := list.start
for { for {
if !seen.Has(list.buffer[pos].Target) { if !seen.Has(list.buffer[pos].CfCorrespondent) {
seen.Add(list.buffer[pos].Target) seen.Add(list.buffer[pos].CfCorrespondent)
results = append(results, TargetListing{ results = append(results, TargetListing{
CfName: list.buffer[pos].Target, CfName: list.buffer[pos].CfCorrespondent,
Time: list.buffer[pos].Message.Time, Time: list.buffer[pos].Message.Time,
}) })
} }
@ -290,7 +281,7 @@ func (list *Buffer) MakeSequence(correspondent string, cutoff time.Time) Sequenc
var pred Predicate var pred Predicate
if correspondent != "" { if correspondent != "" {
pred = func(item *Item) bool { pred = func(item *Item) bool {
return item.Target == correspondent return item.CfCorrespondent == correspondent
} }
} }
return &bufferSequence{ return &bufferSequence{

View file

@ -49,7 +49,7 @@ func (t *JwtServiceConfig) Enabled() bool {
func (t *JwtServiceConfig) Sign(claims MapClaims) (result string, err error) { func (t *JwtServiceConfig) Sign(claims MapClaims) (result string, err error) {
claims["exp"] = time.Now().Unix() + int64(t.Expiration/time.Second) claims["exp"] = time.Now().Unix() + int64(t.Expiration/time.Second)
claims["now"] = time.Now().Unix()
if t.rsaPrivateKey != nil { if t.rsaPrivateKey != nil {
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims(claims)) token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims(claims))
return token.SignedString(t.rsaPrivateKey) return token.SignedString(t.rsaPrivateKey)

View file

@ -253,6 +253,6 @@ func (km *KLineManager) loadFromDatastore() {
} }
func (server *Server) loadKLines() { func (s *Server) loadKLines() {
server.klines = NewKLineManager(server) s.klines = NewKLineManager(s)
} }

View file

@ -30,9 +30,17 @@ var (
const ( const (
// maximum length in bytes of any message target (nickname or channel name) in its // maximum length in bytes of any message target (nickname or channel name) in its
// canonicalized (i.e., casefolded) state: // canonicalized (i.e., casefolded) state:
MaxTargetLength = 64 MaxTargetLength = 64
cleanupRowLimit = 50
cleanupPauseTime = 10 * time.Minute // latest schema of the db
latestDbSchema = "2"
keySchemaVersion = "db.version"
// minor version indicates rollback-safe upgrades, i.e.,
// you can downgrade oragono and everything will work
latestDbMinorVersion = "2"
keySchemaMinorVersion = "db.minorversion"
cleanupRowLimit = 50
cleanupPauseTime = 10 * time.Minute
) )
type e struct{} type e struct{}
@ -42,16 +50,11 @@ type MySQL struct {
logger *logger.Manager logger *logger.Manager
insertHistory *sql.Stmt insertHistory *sql.Stmt
insertSequence *sql.Stmt
insertConversation *sql.Stmt insertConversation *sql.Stmt
insertCorrespondent *sql.Stmt
insertAccountMessage *sql.Stmt insertAccountMessage *sql.Stmt
getReactionsQuery *sql.Stmt
getSingleReaction *sql.Stmt
addReaction *sql.Stmt
deleteReaction *sql.Stmt
getMessageById *sql.Stmt
stateMutex sync.Mutex stateMutex sync.Mutex
config Config config Config
@ -86,55 +89,197 @@ func (mysql *MySQL) getExpireTime() (expireTime time.Duration) {
return return
} }
func (mysql *MySQL) Open() (err error) { func (m *MySQL) Open() (err error) {
var address string var address string
if mysql.config.SocketPath != "" { if m.config.SocketPath != "" {
address = fmt.Sprintf("unix(%s)", mysql.config.SocketPath) address = fmt.Sprintf("unix(%s)", m.config.SocketPath)
} else if mysql.config.Port != 0 { } else if m.config.Port != 0 {
address = fmt.Sprintf("tcp(%s:%d)", mysql.config.Host, mysql.config.Port) address = fmt.Sprintf("tcp(%s:%d)", m.config.Host, m.config.Port)
} }
mysql.db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s/%s", mysql.config.User, mysql.config.Password, address, mysql.config.HistoryDatabase)) m.db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s/%s", m.config.User, m.config.Password, address, m.config.HistoryDatabase))
if err != nil { if err != nil {
return err return err
} }
if mysql.config.MaxConns != 0 { if m.config.MaxConns != 0 {
mysql.db.SetMaxOpenConns(mysql.config.MaxConns) m.db.SetMaxOpenConns(m.config.MaxConns)
mysql.db.SetMaxIdleConns(mysql.config.MaxConns) m.db.SetMaxIdleConns(m.config.MaxConns)
} }
if mysql.config.ConnMaxLifetime != 0 { if m.config.ConnMaxLifetime != 0 {
mysql.db.SetConnMaxLifetime(mysql.config.ConnMaxLifetime) m.db.SetConnMaxLifetime(m.config.ConnMaxLifetime)
} }
err = mysql.fixSchemas() err = m.fixSchemas()
if err != nil { if err != nil {
return err return err
} }
err = mysql.prepareStatements() err = m.prepareStatements()
if err != nil { if err != nil {
return err return err
} }
go mysql.cleanupLoop() go m.cleanupLoop()
go mysql.forgetLoop() go m.forgetLoop()
return nil return nil
} }
func (mysql *MySQL) fixSchemas() (err error) { func (mysql *MySQL) fixSchemas() (err error) {
// 3M now handles this _, err = mysql.db.Exec(`CREATE TABLE IF NOT EXISTS metadata (
key_name VARCHAR(32) primary key,
value VARCHAR(32) NOT NULL
) CHARSET=ascii COLLATE=ascii_bin;`)
if err != nil {
return err
}
var schema string
err = mysql.db.QueryRow(`select value from metadata where key_name = ?;`, keySchemaVersion).Scan(&schema)
if err == sql.ErrNoRows {
err = mysql.createTables()
if err != nil {
return
}
_, err = mysql.db.Exec(`insert into metadata (key_name, value) values (?, ?);`, keySchemaVersion, latestDbSchema)
if err != nil {
return
}
_, err = mysql.db.Exec(`insert into metadata (key_name, value) values (?, ?);`, keySchemaMinorVersion, latestDbMinorVersion)
if err != nil {
return
}
return
} else if err == nil && schema != latestDbSchema {
// TODO figure out what to do about schema changes
return fmt.Errorf("incompatible schema: got %s, expected %s", schema, latestDbSchema)
} else if err != nil {
return err
}
var minorVersion string
err = mysql.db.QueryRow(`select value from metadata where key_name = ?;`, keySchemaMinorVersion).Scan(&minorVersion)
if err == sql.ErrNoRows {
// XXX for now, the only minor version upgrade is the account tracking tables
err = mysql.createComplianceTables()
if err != nil {
return
}
err = mysql.createCorrespondentsTable()
if err != nil {
return
}
_, err = mysql.db.Exec(`insert into metadata (key_name, value) values (?, ?);`, keySchemaMinorVersion, latestDbMinorVersion)
if err != nil {
return
}
} else if err == nil && minorVersion == "1" {
// upgrade from 2.1 to 2.2: create the correspondents table
err = mysql.createCorrespondentsTable()
if err != nil {
return
}
_, err = mysql.db.Exec(`update metadata set value = ? where key_name = ?;`, latestDbMinorVersion, keySchemaMinorVersion)
if err != nil {
return
}
} else if err == nil && minorVersion != latestDbMinorVersion {
// TODO: if minorVersion < latestDbMinorVersion, upgrade,
// if latestDbMinorVersion < minorVersion, ignore because backwards compatible
}
return return
} }
func (mysql *MySQL) createTables() (err error) { func (mysql *MySQL) createTables() (err error) {
// 3M now handles this _, err = mysql.db.Exec(`CREATE TABLE history (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
data BLOB NOT NULL,
msgid BINARY(16) NOT NULL,
KEY (msgid(4))
) CHARSET=ascii COLLATE=ascii_bin;`)
if err != nil {
return err
}
_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE sequence (
history_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
target VARBINARY(%[1]d) NOT NULL,
nanotime BIGINT UNSIGNED NOT NULL,
KEY (target, nanotime)
) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
if err != nil {
return err
}
/* XXX: this table used to be:
CREATE TABLE sequence (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
target VARBINARY(%[1]d) NOT NULL,
nanotime BIGINT UNSIGNED NOT NULL,
history_id BIGINT NOT NULL,
KEY (target, nanotime),
KEY (history_id)
) CHARSET=ascii COLLATE=ascii_bin;
Some users may still be using the old schema.
*/
_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE conversations (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
target VARBINARY(%[1]d) NOT NULL,
correspondent VARBINARY(%[1]d) NOT NULL,
nanotime BIGINT UNSIGNED NOT NULL,
history_id BIGINT NOT NULL,
KEY (target, correspondent, nanotime),
KEY (history_id)
) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
if err != nil {
return err
}
err = mysql.createCorrespondentsTable()
if err != nil {
return err
}
err = mysql.createComplianceTables()
if err != nil {
return err
}
return nil return nil
} }
func (mysql *MySQL) createCorrespondentsTable() (err error) {
_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE correspondents (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
target VARBINARY(%[1]d) NOT NULL,
correspondent VARBINARY(%[1]d) NOT NULL,
nanotime BIGINT UNSIGNED NOT NULL,
UNIQUE KEY (target, correspondent),
KEY (target, nanotime),
KEY (nanotime)
) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
return
}
func (mysql *MySQL) createComplianceTables() (err error) { func (mysql *MySQL) createComplianceTables() (err error) {
// 3M now handles this _, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE account_messages (
history_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
account VARBINARY(%[1]d) NOT NULL,
KEY (account, history_id)
) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
if err != nil {
return err
}
_, err = mysql.db.Exec(fmt.Sprintf(`CREATE TABLE forget (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
account VARBINARY(%[1]d) NOT NULL
) CHARSET=ascii COLLATE=ascii_bin;`, MaxTargetLength))
if err != nil {
return err
}
return nil return nil
} }
@ -182,6 +327,10 @@ func (mysql *MySQL) doCleanup(age time.Duration) (count int, err error) {
mysql.logger.Debug("mysql", fmt.Sprintf("deleting %d history rows, max age %s", len(ids), utils.NanoToTimestamp(maxNanotime))) mysql.logger.Debug("mysql", fmt.Sprintf("deleting %d history rows, max age %s", len(ids), utils.NanoToTimestamp(maxNanotime)))
if maxNanotime != 0 {
mysql.deleteCorrespondents(ctx, maxNanotime)
}
return len(ids), mysql.deleteHistoryIDs(ctx, ids) return len(ids), mysql.deleteHistoryIDs(ctx, ids)
} }
@ -198,14 +347,21 @@ func (mysql *MySQL) deleteHistoryIDs(ctx context.Context, ids []uint64) (err err
inBuf.WriteRune(')') inBuf.WriteRune(')')
inClause := inBuf.String() inClause := inBuf.String()
_, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM conversations WHERE history_id in %s;`, inClause))
if err != nil {
return
}
_, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM sequence WHERE history_id in %s;`, inClause))
if err != nil {
return
}
if mysql.isTrackingAccountMessages() { if mysql.isTrackingAccountMessages() {
_, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM account_messages WHERE history_id in %s;`, inClause)) _, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM account_messages WHERE history_id in %s;`, inClause))
if err != nil { if err != nil {
return return
} }
} }
fmt.Printf(`DELETE FROM history WHERE msgid in %s;`, inClause) _, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM history WHERE id in %s;`, inClause))
_, err = mysql.db.ExecContext(ctx, fmt.Sprintf(`DELETE FROM history WHERE msgid in %s;`, inClause))
if err != nil { if err != nil {
return return
} }
@ -214,35 +370,57 @@ func (mysql *MySQL) deleteHistoryIDs(ctx context.Context, ids []uint64) (err err
} }
func (mysql *MySQL) selectCleanupIDs(ctx context.Context, age time.Duration) (ids []uint64, maxNanotime int64, err error) { func (mysql *MySQL) selectCleanupIDs(ctx context.Context, age time.Duration) (ids []uint64, maxNanotime int64, err error) {
before := timestampSnowflake(time.Now().Add(-age))
maxNanotime = time.Now().Add(-age).Unix() * 1000000000
rows, err := mysql.db.QueryContext(ctx, ` rows, err := mysql.db.QueryContext(ctx, `
SELECT history.msgid SELECT history.id, sequence.nanotime, conversations.nanotime
FROM history FROM history
WHERE msgid < ? LEFT JOIN sequence ON history.id = sequence.history_id
ORDER BY history.msgid LIMIT ?;`, before, cleanupRowLimit) LEFT JOIN conversations on history.id = conversations.history_id
ORDER BY history.id LIMIT ?;`, cleanupRowLimit)
if err != nil { if err != nil {
return return
} }
defer rows.Close() defer rows.Close()
ids = make([]uint64, cleanupRowLimit) idset := make(map[uint64]struct{}, cleanupRowLimit)
threshold := time.Now().Add(-age).UnixNano()
i := 0
for rows.Next() { for rows.Next() {
var id uint64 var id uint64
err = rows.Scan(&id) var seqNano, convNano sql.NullInt64
err = rows.Scan(&id, &seqNano, &convNano)
if err != nil { if err != nil {
return return
} }
nanotime := extractNanotime(seqNano, convNano)
// returns 0 if not found; in that case the data is inconsistent
// and we should delete the entry
if nanotime < threshold {
idset[id] = struct{}{}
if nanotime > maxNanotime {
maxNanotime = nanotime
}
}
}
ids = make([]uint64, len(idset))
i := 0
for id := range idset {
ids[i] = id ids[i] = id
i++ i++
} }
ids = ids[0:i]
return return
} }
func (mysql *MySQL) deleteCorrespondents(ctx context.Context, threshold int64) {
result, err := mysql.db.ExecContext(ctx, `DELETE FROM correspondents WHERE nanotime <= (?);`, threshold)
if err != nil {
mysql.logError("error deleting correspondents", err)
} else {
count, err := result.RowsAffected()
if !mysql.logError("error deleting correspondents", err) {
mysql.logger.Debug(fmt.Sprintf("deleted %d correspondents entries", count))
}
}
}
// wait for forget queue items and process them one by one // wait for forget queue items and process them one by one
func (mysql *MySQL) forgetLoop() { func (mysql *MySQL) forgetLoop() {
defer func() { defer func() {
@ -348,7 +526,23 @@ func (mysql *MySQL) doForgetIteration(account string) (count int, err error) {
func (mysql *MySQL) prepareStatements() (err error) { func (mysql *MySQL) prepareStatements() (err error) {
mysql.insertHistory, err = mysql.db.Prepare(`INSERT INTO history mysql.insertHistory, err = mysql.db.Prepare(`INSERT INTO history
(data, msgid, target, sender, nanotime) VALUES (?, ?, ?, ?, ?);`) (data, msgid) VALUES (?, ?);`)
if err != nil {
return
}
mysql.insertSequence, err = mysql.db.Prepare(`INSERT INTO sequence
(target, nanotime, history_id) VALUES (?, ?, ?);`)
if err != nil {
return
}
mysql.insertConversation, err = mysql.db.Prepare(`INSERT INTO conversations
(target, correspondent, nanotime, history_id) VALUES (?, ?, ?, ?);`)
if err != nil {
return
}
mysql.insertCorrespondent, err = mysql.db.Prepare(`INSERT INTO correspondents
(target, correspondent, nanotime) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE nanotime = GREATEST(nanotime, ?);`)
if err != nil { if err != nil {
return return
} }
@ -358,38 +552,6 @@ func (mysql *MySQL) prepareStatements() (err error) {
return return
} }
mysql.getReactionsQuery, err = mysql.db.Prepare(`select react, count(*) as total, (select JSON_ARRAYAGG(user)
from reactions r
where r.msgid = main.msgid
and r.react = main.react
limit 3) as sample
from reactions as main
where main.msgid = ?
group by react, msgid;`)
if err != nil {
return
}
mysql.getSingleReaction, err = mysql.db.Prepare(`SELECT COUNT(*) FROM reactions WHERE msgid = ? AND user = ? AND react = ?`)
if err != nil {
return
}
mysql.deleteReaction, err = mysql.db.Prepare(`DELETE FROM reactions WHERE msgid = ? AND user = ? AND react = ?`)
if err != nil {
return
}
mysql.addReaction, err = mysql.db.Prepare(`INSERT INTO reactions(msgid, user, react) VALUES (?, ?, ?)`)
if err != nil {
return
}
mysql.getMessageById, err = mysql.db.Prepare(`SELECT msgid, data, target, sender, nanotime, pm FROM history WHERE msgid = ?`)
if err != nil {
return
}
return return
} }
@ -446,6 +608,11 @@ func (mysql *MySQL) AddChannelItem(target string, item history.Item, account str
return return
} }
err = mysql.insertSequenceEntry(ctx, target, item.Message.Time.UnixNano(), id)
if err != nil {
return
}
err = mysql.insertAccountMessageEntry(ctx, id, account) err = mysql.insertAccountMessageEntry(ctx, id, account)
if err != nil { if err != nil {
return return
@ -454,21 +621,39 @@ func (mysql *MySQL) AddChannelItem(target string, item history.Item, account str
return return
} }
func (mysql *MySQL) insertSequenceEntry(ctx context.Context, target string, messageTime int64, id int64) (err error) {
_, err = mysql.insertSequence.ExecContext(ctx, target, messageTime, id)
mysql.logError("could not insert sequence entry", err)
return
}
func (mysql *MySQL) insertConversationEntry(ctx context.Context, target, correspondent string, messageTime int64, id int64) (err error) {
_, err = mysql.insertConversation.ExecContext(ctx, target, correspondent, messageTime, id)
mysql.logError("could not insert conversations entry", err)
return
}
func (mysql *MySQL) insertCorrespondentsEntry(ctx context.Context, target, correspondent string, messageTime int64, historyId int64) (err error) {
_, err = mysql.insertCorrespondent.ExecContext(ctx, target, correspondent, messageTime, messageTime)
mysql.logError("could not insert conversations entry", err)
return
}
func (mysql *MySQL) insertBase(ctx context.Context, item history.Item) (id int64, err error) { func (mysql *MySQL) insertBase(ctx context.Context, item history.Item) (id int64, err error) {
var value []byte value, err := marshalItem(&item)
value, err = marshalItem(&item)
if mysql.logError("could not marshal item", err) { if mysql.logError("could not marshal item", err) {
return return
} }
var account = item.Account
if account == "" { msgidBytes, err := decodeMsgid(item.Message.Msgid)
account = "*" if mysql.logError("could not decode msgid", err) {
}
result, err := mysql.insertHistory.ExecContext(ctx, value, item.Message.Msgid, item.Target, account, item.Message.Time.UnixNano())
if mysql.logError("could not insert item", err) {
return return
} }
result, err := mysql.insertHistory.ExecContext(ctx, value, msgidBytes)
if mysql.logError("could not insert item", err) {
return
}
id, err = result.LastInsertId() id, err = result.LastInsertId()
if mysql.logError("could not insert item", err) { if mysql.logError("could not insert item", err) {
return return
@ -502,7 +687,36 @@ func (mysql *MySQL) AddDirectMessage(sender, senderAccount, recipient, recipient
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout()) ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel() defer cancel()
_, err = mysql.insertBase(ctx, item) id, err := mysql.insertBase(ctx, item)
if err != nil {
return
}
nanotime := item.Message.Time.UnixNano()
if senderAccount != "" {
err = mysql.insertConversationEntry(ctx, senderAccount, recipient, nanotime, id)
if err != nil {
return
}
err = mysql.insertCorrespondentsEntry(ctx, senderAccount, recipient, nanotime, id)
if err != nil {
return
}
}
if recipientAccount != "" && sender != recipient {
err = mysql.insertConversationEntry(ctx, recipientAccount, sender, nanotime, id)
if err != nil {
return
}
err = mysql.insertCorrespondentsEntry(ctx, recipientAccount, sender, nanotime, id)
if err != nil {
return
}
}
err = mysql.insertAccountMessageEntry(ctx, id, senderAccount)
if err != nil { if err != nil {
return return
} }
@ -511,7 +725,7 @@ func (mysql *MySQL) AddDirectMessage(sender, senderAccount, recipient, recipient
} }
// note that accountName is the unfolded name // note that accountName is the unfolded name
func (mysql *MySQL) DeleteMsgid(msgid, account string) (err error) { func (mysql *MySQL) DeleteMsgid(msgid, accountName string) (err error) {
if mysql.db == nil { if mysql.db == nil {
return nil return nil
} }
@ -524,11 +738,11 @@ func (mysql *MySQL) DeleteMsgid(msgid, account string) (err error) {
return return
} }
if account != "*" { if accountName != "*" {
var item history.Item var item history.Item
err = unmarshalItem(data, &item) err = unmarshalItem(data, &item)
// delete if the entry is corrupt // delete if the entry is corrupt
if err == nil && item.Account != account { if err == nil && item.AccountName != accountName {
return ErrDisallowed return ErrDisallowed
} }
} }
@ -539,10 +753,7 @@ func (mysql *MySQL) DeleteMsgid(msgid, account string) (err error) {
} }
func (mysql *MySQL) Export(account string, writer io.Writer) { func (mysql *MySQL) Export(account string, writer io.Writer) {
// no eu presence... if mysql.db == nil {
// maybe fix this when i know the new schema works
return
/*if mysql.db == nil {
return return
} }
@ -554,8 +765,10 @@ func (mysql *MySQL) Export(account string, writer io.Writer) {
defer cancel() defer cancel()
rows, rowsErr := mysql.db.QueryContext(ctx, ` rows, rowsErr := mysql.db.QueryContext(ctx, `
SELECT history.data, msgid, target FROM history SELECT account_messages.history_id, history.data, sequence.target FROM account_messages
WHERE sender = ? AND account_messages.history_id > ? INNER JOIN history ON history.id = account_messages.history_id
INNER JOIN sequence ON account_messages.history_id = sequence.history_id
WHERE account_messages.account = ? AND account_messages.history_id > ?
LIMIT ?`, account, lastSeen, cleanupRowLimit) LIMIT ?`, account, lastSeen, cleanupRowLimit)
if rowsErr != nil { if rowsErr != nil {
err = rowsErr err = rowsErr
@ -567,7 +780,7 @@ func (mysql *MySQL) Export(account string, writer io.Writer) {
var blob, jsonBlob []byte var blob, jsonBlob []byte
var target string var target string
var item history.Item var item history.Item
err = rows.Scan(&blob, &id, &target) err = rows.Scan(&id, &blob, &target)
if err != nil { if err != nil {
return return
} }
@ -575,7 +788,7 @@ func (mysql *MySQL) Export(account string, writer io.Writer) {
if err != nil { if err != nil {
return return
} }
item.Target = target item.CfCorrespondent = target
jsonBlob, err = json.Marshal(item) jsonBlob, err = json.Marshal(item)
if err != nil { if err != nil {
return return
@ -595,66 +808,28 @@ func (mysql *MySQL) Export(account string, writer io.Writer) {
} }
mysql.logError("could not export history", err) mysql.logError("could not export history", err)
return*/
}
// Kinda an intermediary function due to the CEF DB structure
func (mysql *MySQL) GetMessage(msgid string) (id uint64, item history.Item, target string, sender string, nanotime uint64, pm bool, err error) {
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
var data []byte
row := mysql.getMessageById.QueryRowContext(ctx, msgid)
err = row.Scan(&id, &data, &target, &sender, &nanotime, &pm)
if err != nil {
return
}
err = unmarshalItem(data, &item)
return
}
func (mysql *MySQL) HasReactionFromUser(msgid string, user string, reaction string) (exists bool) {
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
row := mysql.getSingleReaction.QueryRowContext(ctx, msgid, user, reaction)
var count int
row.Scan(&count)
return count > 0
}
func (mysql *MySQL) AddReaction(msgid string, user string, reaction string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
_, err = mysql.addReaction.ExecContext(ctx, msgid, user, reaction)
return
}
func (mysql *MySQL) DeleteReaction(msgid string, user string, reaction string) (err error) {
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
_, err = mysql.deleteReaction.ExecContext(ctx, msgid, user, reaction)
return return
} }
func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData bool) (result time.Time, id uint64, data []byte, err error) { func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData bool) (result time.Time, id uint64, data []byte, err error) {
decoded, err := decodeMsgid(msgid)
if err != nil { if err != nil {
return return
} }
cols := `history.nanotime` cols := `sequence.nanotime, conversations.nanotime`
if includeData { if includeData {
cols = `history.nanotime, history.id, history.data` cols = `sequence.nanotime, conversations.nanotime, history.id, history.data`
} }
// Since CEF uses snowflakes and vanilla ergo uses blobs, we cast as int to make it function.
// May have to adjust it some day
row := mysql.db.QueryRowContext(ctx, fmt.Sprintf(` row := mysql.db.QueryRowContext(ctx, fmt.Sprintf(`
SELECT %s FROM history SELECT %s FROM history
WHERE history.msgid = CAST(? AS UNSIGNED) LIMIT 1;`, cols), msgid) LEFT JOIN sequence ON history.id = sequence.history_id
var nanoSeq sql.NullInt64 LEFT JOIN conversations ON history.id = conversations.history_id
WHERE history.msgid = ? LIMIT 1;`, cols), decoded)
var nanoSeq, nanoConv sql.NullInt64
if !includeData { if !includeData {
err = row.Scan(&nanoSeq) err = row.Scan(&nanoSeq, &nanoConv)
} else { } else {
err = row.Scan(&nanoSeq, &id, &data) err = row.Scan(&nanoSeq, &nanoConv, &id, &data)
} }
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
mysql.logError("could not resolve msgid to time", err) mysql.logError("could not resolve msgid to time", err)
@ -662,7 +837,7 @@ func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData b
if err != nil { if err != nil {
return return
} }
nanotime := nanoSeq.Int64 nanotime := extractNanotime(nanoSeq, nanoConv)
if nanotime == 0 { if nanotime == 0 {
err = sql.ErrNoRows err = sql.ErrNoRows
return return
@ -671,6 +846,15 @@ func (mysql *MySQL) lookupMsgid(ctx context.Context, msgid string, includeData b
return return
} }
func extractNanotime(seq, conv sql.NullInt64) (result int64) {
if seq.Valid {
return seq.Int64
} else if conv.Valid {
return conv.Int64
}
return
}
func (mysql *MySQL) selectItems(ctx context.Context, query string, args ...interface{}) (results []history.Item, err error) { func (mysql *MySQL) selectItems(ctx context.Context, query string, args ...interface{}) (results []history.Item, err error) {
rows, err := mysql.db.QueryContext(ctx, query, args...) rows, err := mysql.db.QueryContext(ctx, query, args...)
if mysql.logError("could not select history items", err) { if mysql.logError("could not select history items", err) {
@ -681,10 +865,8 @@ func (mysql *MySQL) selectItems(ctx context.Context, query string, args ...inter
for rows.Next() { for rows.Next() {
var blob []byte var blob []byte
var msgid uint64
var item history.Item var item history.Item
err = rows.Scan(&blob)
err = rows.Scan(&blob, &msgid)
if mysql.logError("could not scan history item", err) { if mysql.logError("could not scan history item", err) {
return return
} }
@ -692,36 +874,17 @@ func (mysql *MySQL) selectItems(ctx context.Context, query string, args ...inter
if mysql.logError("could not unmarshal history item", err) { if mysql.logError("could not unmarshal history item", err) {
return return
} }
reactions, rErr := mysql.getReactionsQuery.Query(msgid)
if mysql.logError("could not get reactions", rErr) {
return
}
var react string
var total int
var sample string
for reactions.Next() {
reactions.Scan(&react, &total, &sample)
var sampleDecoded []string
json.Unmarshal([]byte(sample), &sampleDecoded)
item.Reactions = append(item.Reactions, history.Reaction{
Name: react,
Total: total,
SampleUsers: sampleDecoded,
})
}
results = append(results, item) results = append(results, item)
} }
return return
} }
func timestampSnowflake(t time.Time) uint64 {
var ts = t.Unix() & 0xffffffffffff
return uint64(ts << 16)
}
func (mysql *MySQL) betweenTimestamps(ctx context.Context, target, correspondent string, after, before, cutoff time.Time, limit int) (results []history.Item, err error) { func (mysql *MySQL) betweenTimestamps(ctx context.Context, target, correspondent string, after, before, cutoff time.Time, limit int) (results []history.Item, err error) {
useSequence := correspondent == ""
table := "sequence"
if !useSequence {
table = "conversations"
}
after, before, ascending := history.MinMaxAsc(after, before, cutoff) after, before, ascending := history.MinMaxAsc(after, before, cutoff)
direction := "ASC" direction := "ASC"
@ -730,25 +893,27 @@ func (mysql *MySQL) betweenTimestamps(ctx context.Context, target, correspondent
} }
var queryBuf strings.Builder var queryBuf strings.Builder
args := make([]interface{}, 0, 7)
if correspondent == "" { args := make([]interface{}, 0, 6)
fmt.Fprintf(&queryBuf, "SELECT data, msgid FROM history WHERE target = ? ") fmt.Fprintf(&queryBuf,
"SELECT history.data from history INNER JOIN %[1]s ON history.id = %[1]s.history_id WHERE", table)
if useSequence {
fmt.Fprintf(&queryBuf, " sequence.target = ?")
args = append(args, target) args = append(args, target)
} else { } else {
fmt.Fprintf(&queryBuf, "SELECT data, msgid FROM history WHERE (target = ? and sender = ?) OR (target = ? and sender = ?)") fmt.Fprintf(&queryBuf, " conversations.target = ? AND conversations.correspondent = ?")
args = append(args, target, correspondent, correspondent, target) args = append(args, target)
args = append(args, correspondent)
} }
if !after.IsZero() { if !after.IsZero() {
fmt.Fprintf(&queryBuf, " AND nanotime > ?") fmt.Fprintf(&queryBuf, " AND %s.nanotime > ?", table)
args = append(args, after.UnixNano()) args = append(args, after.UnixNano())
} }
if !before.IsZero() { if !before.IsZero() {
fmt.Fprintf(&queryBuf, " AND nanotime <= ?") fmt.Fprintf(&queryBuf, " AND %s.nanotime < ?", table)
args = append(args, before.UnixNano()) args = append(args, before.UnixNano())
} }
fmt.Fprintf(&queryBuf, " ORDER BY %[1]s.nanotime %[2]s LIMIT ?;", table, direction)
fmt.Fprintf(&queryBuf, " ORDER BY nanotime %[1]s LIMIT ?;", direction)
args = append(args, limit) args = append(args, limit)
results, err = mysql.selectItems(ctx, queryBuf.String(), args...) results, err = mysql.selectItems(ctx, queryBuf.String(), args...)
@ -766,19 +931,19 @@ func (mysql *MySQL) listCorrespondentsInternal(ctx context.Context, target strin
} }
var queryBuf strings.Builder var queryBuf strings.Builder
args := make([]interface{}, 0, 5) args := make([]interface{}, 0, 4)
queryBuf.WriteString(`SELECT target, sender, nanotime from history queryBuf.WriteString(`SELECT correspondents.correspondent, correspondents.nanotime from correspondents
WHERE target = ? OR (sender = ? and pm = true)`) WHERE target = ?`)
args = append(args, target, target) args = append(args, target)
if !after.IsZero() { if !after.IsZero() {
queryBuf.WriteString(" AND nanotime > ?") queryBuf.WriteString(" AND correspondents.nanotime > ?")
args = append(args, after.UnixNano()) args = append(args, after.UnixNano())
} }
if !before.IsZero() { if !before.IsZero() {
queryBuf.WriteString(" AND nanotime < ?") queryBuf.WriteString(" AND correspondents.nanotime < ?")
args = append(args, before.UnixNano()) args = append(args, before.UnixNano())
} }
fmt.Fprintf(&queryBuf, " ORDER BY nanotime %s LIMIT ?;", direction) fmt.Fprintf(&queryBuf, " ORDER BY correspondents.nanotime %s LIMIT ?;", direction)
args = append(args, limit) args = append(args, limit)
query := queryBuf.String() query := queryBuf.String()
@ -787,26 +952,17 @@ func (mysql *MySQL) listCorrespondentsInternal(ctx context.Context, target strin
return return
} }
defer rows.Close() defer rows.Close()
var msgTarget string var correspondent string
var msgSender string
var nanotime int64 var nanotime int64
for rows.Next() { for rows.Next() {
err = rows.Scan(&msgTarget, &msgSender, &nanotime) err = rows.Scan(&correspondent, &nanotime)
if err != nil { if err != nil {
return return
} }
if msgTarget == target { results = append(results, history.TargetListing{
results = append(results, history.TargetListing{ CfName: correspondent,
CfName: msgSender, Time: time.Unix(0, nanotime),
Time: time.Unix(0, nanotime), })
})
} else {
results = append(results, history.TargetListing{
CfName: msgTarget,
Time: time.Unix(0, nanotime),
})
}
} }
if !ascending { if !ascending {
@ -886,7 +1042,6 @@ func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (
defer cancel() defer cancel()
startTime := start.Time startTime := start.Time
if start.Msgid != "" { if start.Msgid != "" {
startTime, _, _, err = s.mysql.lookupMsgid(ctx, start.Msgid, false) startTime, _, _, err = s.mysql.lookupMsgid(ctx, start.Msgid, false)
if err != nil { if err != nil {
@ -900,7 +1055,6 @@ func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (
endTime := end.Time endTime := end.Time
if end.Msgid != "" { if end.Msgid != "" {
endTime, _, _, err = s.mysql.lookupMsgid(ctx, end.Msgid, false) endTime, _, _, err = s.mysql.lookupMsgid(ctx, end.Msgid, false)
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return nil, nil return nil, nil
@ -947,41 +1101,3 @@ func (mysql *MySQL) MakeSequence(target, correspondent string, cutoff time.Time)
cutoff: cutoff, cutoff: cutoff,
} }
} }
func (mysql *MySQL) GetPMs(casefoldedUser string) (results map[string]int64, err error) {
if mysql.db == nil {
return
}
results = make(map[string]int64)
ctx, cancel := context.WithTimeout(context.Background(), mysql.getTimeout())
defer cancel()
var queryBuf strings.Builder
args := make([]interface{}, 0)
queryBuf.WriteString(`SELECT max(nanotime), target, sender FROM history WHERE target = ? OR (sender = ? and pm = true) GROUP BY target, sender;`)
args = append(args, casefoldedUser, casefoldedUser)
rows, err := mysql.db.QueryContext(ctx, queryBuf.String(), args...)
if mysql.logError("could not get pms", err) {
return
}
defer rows.Close()
var last int64
var target, sender string
for rows.Next() {
err = rows.Scan(&last, &target, &sender)
if mysql.logError("could not get pms", err) {
return
}
// We really don't need nanosecond precision
if target != casefoldedUser {
results[target] = last / 1000000
} else {
results[sender] = last / 1000000
}
}
return
}

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"github.com/ergochat/ergo/irc/history" "github.com/ergochat/ergo/irc/history"
"github.com/ergochat/ergo/irc/utils"
) )
// 123 / '{' is the magic number that means JSON; // 123 / '{' is the magic number that means JSON;
@ -16,3 +17,7 @@ func marshalItem(item *history.Item) (result []byte, err error) {
func unmarshalItem(data []byte, result *history.Item) (err error) { func unmarshalItem(data []byte, result *history.Item) (err error) {
return json.Unmarshal(data, result) return json.Unmarshal(data, result)
} }
func decodeMsgid(msgid string) ([]byte, error) {
return utils.B32Encoder.DecodeString(msgid)
}

View file

@ -93,11 +93,11 @@ func performNickChange(server *Server, client *Client, target *Client, session *
isBot := !isSanick && client.HasMode(modes.Bot) isBot := !isSanick && client.HasMode(modes.Bot)
message := utils.MakeMessage("") message := utils.MakeMessage("")
histItem := history.Item{ histItem := history.Item{
Type: history.Nick, Type: history.Nick,
Nick: origNickMask, Nick: origNickMask,
Account: details.account, AccountName: details.accountName,
Message: message, Message: message,
IsBot: isBot, IsBot: isBot,
} }
histItem.Params[0] = assignedNickname histItem.Params[0] = assignedNickname
@ -123,8 +123,6 @@ func performNickChange(server *Server, client *Client, target *Client, session *
for _, channel := range target.Channels() { for _, channel := range target.Channels() {
if channel.memberIsVisible(client) { if channel.memberIsVisible(client) {
// I LOVE MUTATING STATE!
histItem.Target = channel.NameCasefolded()
channel.AddHistoryItem(histItem, details.account) channel.AddHistoryItem(histItem, details.account)
} }
} }

View file

@ -4,10 +4,7 @@
package irc package irc
import ( import (
"github.com/ergochat/ergo/irc/history"
"runtime/debug" "runtime/debug"
"strconv"
"strings"
"time" "time"
"github.com/ergochat/ergo/irc/caps" "github.com/ergochat/ergo/irc/caps"
@ -124,12 +121,8 @@ func (rb *ResponseBuffer) AddFromClient(time time.Time, msgid string, fromNickMa
rb.AddMessage(msg) rb.AddMessage(msg)
} }
func (rb *ResponseBuffer) AddSplitMessageFromClient(fromNickMask string, fromAccount string, isBot bool, tags map[string]string, command string, target string, message utils.SplitMessage) {
rb.AddSplitMessageFromClientWithReactions(fromNickMask, fromAccount, isBot, tags, command, target, message, nil)
}
// AddSplitMessageFromClient adds a new split message from a specific client to our queue. // AddSplitMessageFromClient adds a new split message from a specific client to our queue.
func (rb *ResponseBuffer) AddSplitMessageFromClientWithReactions(fromNickMask string, fromAccount string, isBot bool, tags map[string]string, command string, target string, message utils.SplitMessage, reactions []history.Reaction) { func (rb *ResponseBuffer) AddSplitMessageFromClient(fromNickMask string, fromAccount string, isBot bool, tags map[string]string, command string, target string, message utils.SplitMessage) {
if message.Is512() { if message.Is512() {
if message.Message == "" { if message.Message == "" {
// XXX this is a TAGMSG // XXX this is a TAGMSG
@ -149,25 +142,10 @@ func (rb *ResponseBuffer) AddSplitMessageFromClientWithReactions(fromNickMask st
if i == 0 { if i == 0 {
msgid = message.Msgid msgid = message.Msgid
} }
mergedTags := make(map[string]string) rb.AddFromClient(message.Time, msgid, fromNickMask, fromAccount, isBot, tags, command, target, messagePair.Message)
for k, v := range tags {
mergedTags[k] = v
}
for k, v := range messagePair.Tags {
mergedTags[k] = v
}
rb.AddFromClient(message.Time, msgid, fromNickMask, fromAccount, isBot, mergedTags, command, target, messagePair.Message)
} }
} }
} }
if reactions != nil && len(reactions) >= 1 {
var text string
for _, react := range reactions {
text = strings.Join([]string{message.Msgid, react.Name, strconv.Itoa(react.Total)}, " ")
text += " " + strings.Join(react.SampleUsers, " ")
rb.Add(nil, rb.target.server.name, "REACTIONS", text)
}
}
} }
func (rb *ResponseBuffer) addEchoMessage(tags map[string]string, nickMask, accountName, command, target string, message utils.SplitMessage) { func (rb *ResponseBuffer) addEchoMessage(tags map[string]string, nickMask, accountName, command, target string, message utils.SplitMessage) {

View file

@ -110,9 +110,6 @@ func sendRoleplayMessage(server *Server, client *Client, source string, targetSt
Type: history.Privmsg, Type: history.Privmsg,
Message: splitMessage, Message: splitMessage,
Nick: sourceMask, Nick: sourceMask,
Target: target,
// TODO: does this work?
Account: "$RP",
}, client.Account()) }, client.Account())
} else { } else {
target, err := CasefoldName(targetString) target, err := CasefoldName(targetString)

View file

@ -5,11 +5,8 @@ package irc
import ( import (
"bufio" "bufio"
"bytes"
"io" "io"
"net/http"
"os/exec" "os/exec"
"strings"
"syscall" "syscall"
"time" "time"
) )
@ -24,27 +21,7 @@ type scriptResponse struct {
err error err error
} }
func RunHttp(command string, args []string, input []byte, timeout time.Duration) (output []byte, err error) {
client := http.Client{
Timeout: timeout,
}
post, err := client.Post(command, "application/json", bytes.NewBuffer(input))
if err != nil {
return nil, err
}
defer post.Body.Close()
output, err = io.ReadAll(post.Body)
if err != nil {
return nil, err
}
return
}
func RunScript(command string, args []string, input []byte, timeout, killTimeout time.Duration) (output []byte, err error) { func RunScript(command string, args []string, input []byte, timeout, killTimeout time.Duration) (output []byte, err error) {
if strings.HasPrefix(command, "http") {
return RunHttp(command, args, input, timeout)
}
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
stdin, err := cmd.StdinPipe() stdin, err := cmd.StdinPipe()
if err != nil { if err != nil {

View file

@ -36,8 +36,6 @@ import (
"github.com/ergochat/ergo/irc/mysql" "github.com/ergochat/ergo/irc/mysql"
"github.com/ergochat/ergo/irc/sno" "github.com/ergochat/ergo/irc/sno"
"github.com/ergochat/ergo/irc/utils" "github.com/ergochat/ergo/irc/utils"
"github.com/redis/go-redis/v9"
) )
const ( const (
@ -98,9 +96,6 @@ type Server struct {
semaphores ServerSemaphores semaphores ServerSemaphores
flock flock.Flocker flock flock.Flocker
defcon atomic.Uint32 defcon atomic.Uint32
// CEF
redis *redis.Client
} }
// NewServer returns a new Oragono server. // NewServer returns a new Oragono server.
@ -168,13 +163,6 @@ func (server *Server) Shutdown() {
func (server *Server) Run() { func (server *Server) Run() {
defer server.Shutdown() defer server.Shutdown()
redisOpts, err := redis.ParseURL(server.Config().Cef.Redis)
if err != nil {
panic(err)
}
server.redis = redis.NewClient(redisOpts)
startRedis(server)
for { for {
select { select {
case <-server.exitSignals: case <-server.exitSignals:
@ -446,9 +434,7 @@ func (server *Server) playRegistrationBurst(session *Session) {
session.Send(nil, server.name, RPL_MYINFO, d.nick, server.name, Ver, rplMyInfo1, rplMyInfo2, rplMyInfo3) session.Send(nil, server.name, RPL_MYINFO, d.nick, server.name, Ver, rplMyInfo1, rplMyInfo2, rplMyInfo3)
rb := NewResponseBuffer(session) rb := NewResponseBuffer(session)
if !(rb.session.capabilities.Has(caps.ExtendedISupport) && rb.session.isupportSentPrereg) { server.RplISupport(c, rb)
server.RplISupport(c, rb)
}
if d.account != "" && session.capabilities.Has(caps.Persistence) { if d.account != "" && session.capabilities.Has(caps.Persistence) {
reportPersistenceStatus(c, rb, false) reportPersistenceStatus(c, rb, false)
} }
@ -470,17 +456,10 @@ func (server *Server) playRegistrationBurst(session *Session) {
// RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses. // RplISupport outputs our ISUPPORT lines to the client. This is used on connection and in VERSION responses.
func (server *Server) RplISupport(client *Client, rb *ResponseBuffer) { func (server *Server) RplISupport(client *Client, rb *ResponseBuffer) {
server.sendRplISupportLines(client, rb, server.Config().Server.isupport.CachedReply)
}
func (server *Server) sendRplISupportLines(client *Client, rb *ResponseBuffer, lines [][]string) {
if rb.session.capabilities.Has(caps.ExtendedISupport) {
batchID := rb.StartNestedBatch(caps.ExtendedISupportBatchType)
defer rb.EndNestedBatch(batchID)
}
translatedISupport := client.t("are supported by this server") translatedISupport := client.t("are supported by this server")
nick := client.Nick() nick := client.Nick()
for _, cachedTokenLine := range lines { config := server.Config()
for _, cachedTokenLine := range config.Server.isupport.CachedReply {
length := len(cachedTokenLine) + 2 length := len(cachedTokenLine) + 2
tokenline := make([]string, length) tokenline := make([]string, length)
tokenline[0] = nick tokenline[0] = nick
@ -815,19 +794,13 @@ func (server *Server) applyConfig(config *Config) (err error) {
} }
if !initial { if !initial {
// send 005 updates (somewhat rare) // push new info to all of our clients
if len(newISupportReplies) != 0 { for _, sClient := range server.clients.AllClients() {
for _, sClient := range server.clients.AllClients() { for _, tokenline := range newISupportReplies {
for _, session := range sClient.Sessions() { sClient.Send(nil, server.name, RPL_ISUPPORT, append([]string{sClient.nick}, tokenline...)...)
rb := NewResponseBuffer(session)
server.sendRplISupportLines(sClient, rb, newISupportReplies)
rb.Send(false)
}
} }
}
if sendRawOutputNotice { if sendRawOutputNotice {
for _, sClient := range server.clients.AllClients() {
sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect.")) sClient.Notice(sClient.t("This server is in debug mode and is logging all user I/O. If you do not wish for everything you send to be readable by the server owner(s), please disconnect."))
} }
} }
@ -1079,7 +1052,7 @@ func (server *Server) ForgetHistory(accountName string) {
return return
} }
predicate := func(item *history.Item) bool { return item.Account == accountName } predicate := func(item *history.Item) bool { return item.AccountName == accountName }
for _, channel := range server.channels.Channels() { for _, channel := range server.channels.Channels() {
channel.history.Delete(predicate) channel.history.Delete(predicate)
@ -1093,7 +1066,7 @@ func (server *Server) ForgetHistory(accountName string) {
// deletes a message. target is a hint about what buffer it's in (not required for // deletes a message. target is a hint about what buffer it's in (not required for
// persistent history, where all the msgids are indexed together). if accountName // persistent history, where all the msgids are indexed together). if accountName
// is anything other than "*", it must match the recorded AccountName of the message // is anything other than "*", it must match the recorded AccountName of the message
func (server *Server) DeleteMessage(target, msgid, account string) (err error) { func (server *Server) DeleteMessage(target, msgid, accountName string) (err error) {
config := server.Config() config := server.Config()
var hist *history.Buffer var hist *history.Buffer
@ -1116,10 +1089,10 @@ func (server *Server) DeleteMessage(target, msgid, account string) (err error) {
} }
if hist == nil { if hist == nil {
err = server.historyDB.DeleteMsgid(msgid, account) err = server.historyDB.DeleteMsgid(msgid, accountName)
} else { } else {
count := hist.Delete(func(item *history.Item) bool { count := hist.Delete(func(item *history.Item) bool {
return item.Message.Msgid == msgid && (account == "*" || item.Account == account) return item.Message.Msgid == msgid && (accountName == "*" || item.AccountName == accountName)
}) })
if count == 0 { if count == 0 {
err = errNoop err = errNoop

View file

@ -107,10 +107,6 @@ func (service *ircService) Notice(rb *ResponseBuffer, text string) {
rb.Add(nil, service.prefix, "NOTICE", rb.target.Nick(), text) rb.Add(nil, service.prefix, "NOTICE", rb.target.Nick(), text)
} }
func (service *ircService) TaggedNotice(rb *ResponseBuffer, text string, tags map[string]string) {
rb.Add(tags, service.prefix, "NOTICE", rb.target.Nick(), text)
}
// all service commands at the protocol level, by uppercase command name // all service commands at the protocol level, by uppercase command name
// e.g., NICKSERV, NS // e.g., NICKSERV, NS
var ergoServicesByCommandAlias map[string]*ircService var ergoServicesByCommandAlias map[string]*ircService

View file

@ -14,7 +14,6 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"net" "net"
"strconv"
"strings" "strings"
"time" "time"
) )
@ -32,26 +31,8 @@ var (
const ( const (
SecretTokenLength = 26 SecretTokenLength = 26
MachineId = 1 // Since there's no scaling Ergo, id is fixed at 1. Other things can have 2-127
) )
var inc uint64 = 0
// slingamn, if you ever see this, i'm sorry - I just didn't want to attach what i think is redundant data to every
// message.
func GenerateMessageId() uint64 {
inc++
var ts = time.Now().Unix() & 0xffffffffffff
var flake = uint64(ts << 16)
flake |= MachineId << 10
flake |= inc % 0x3ff
return flake
}
func GenerateMessageIdStr() string {
return strconv.FormatUint(GenerateMessageId(), 10)
}
// generate a secret token that cannot be brute-forced via online attacks // generate a secret token that cannot be brute-forced via online attacks
func GenerateSecretToken() string { func GenerateSecretToken() string {
// 128 bits of entropy are enough to resist any online attack: // 128 bits of entropy are enough to resist any online attack:

View file

@ -16,7 +16,6 @@ func IsRestrictedCTCPMessage(message string) bool {
type MessagePair struct { type MessagePair struct {
Message string Message string
Tags map[string]string
Concat bool // should be relayed with the multiline-concat tag Concat bool // should be relayed with the multiline-concat tag
} }
@ -38,20 +37,19 @@ type SplitMessage struct {
func MakeMessage(original string) (result SplitMessage) { func MakeMessage(original string) (result SplitMessage) {
result.Message = original result.Message = original
result.Msgid = GenerateMessageIdStr() result.Msgid = GenerateSecretToken()
result.SetTime() result.SetTime()
return return
} }
func (sm *SplitMessage) Append(message string, concat bool, tags map[string]string) { func (sm *SplitMessage) Append(message string, concat bool) {
if sm.Msgid == "" { if sm.Msgid == "" {
sm.Msgid = GenerateMessageIdStr() sm.Msgid = GenerateSecretToken()
} }
sm.Split = append(sm.Split, MessagePair{ sm.Split = append(sm.Split, MessagePair{
Message: message, Message: message,
Concat: concat, Concat: concat,
Tags: tags,
}) })
} }

View file

@ -7,7 +7,7 @@ import "fmt"
const ( const (
// SemVer is the semantic version of Ergo. // SemVer is the semantic version of Ergo.
SemVer = "2.15.0-unreleased" SemVer = "2.14.0-rc1"
) )
var ( var (

View file

@ -203,7 +203,7 @@ func zncPlayPrivmsgsFrom(client *Client, rb *ResponseBuffer, target string, star
zncMax := client.server.Config().History.ZNCMax zncMax := client.server.Config().History.ZNCMax
items, err := sequence.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax) items, err := sequence.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
if err == nil && len(items) != 0 { if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, target, false, "", "", 0) client.replayPrivmsgHistory(rb, items, target, false)
} }
} }
@ -211,7 +211,7 @@ func zncPlayPrivmsgsFromAll(client *Client, rb *ResponseBuffer, start, end time.
zncMax := client.server.Config().History.ZNCMax zncMax := client.server.Config().History.ZNCMax
items, err := client.privmsgsBetween(start, end, maxDMTargetsForAutoplay, zncMax) items, err := client.privmsgsBetween(start, end, maxDMTargetsForAutoplay, zncMax)
if err == nil && len(items) != 0 { if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, "", false, "", "", 0) client.replayPrivmsgHistory(rb, items, "", false)
} }
} }

@ -1 +1 @@
Subproject commit a1324407893b603fe6b55ce7c4ee385938291ae1 Subproject commit af980ed3b639b5e1b3749c74027872adb69922a7

View file

@ -791,7 +791,7 @@ lock-file: "ircd.lock"
# datastore configuration # datastore configuration
datastore: datastore:
# path to the database file (used to store account and channel registrations): # path to the datastore
path: ircd.db path: ircd.db
# if the database schema requires an upgrade, `autoupgrade` will attempt to # if the database schema requires an upgrade, `autoupgrade` will attempt to

View file

@ -196,15 +196,6 @@ func trimInitialSpaces(str string) string {
return str[i:] return str[i:]
} }
func isASCII(str string) bool {
for i := 0; i < len(str); i++ {
if str[i] > 127 {
return false
}
}
return true
}
func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Message, err error) { func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Message, err error) {
// remove either \n or \r\n from the end of the line: // remove either \n or \r\n from the end of the line:
line = strings.TrimSuffix(line, "\n") line = strings.TrimSuffix(line, "\n")
@ -274,16 +265,11 @@ func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Messa
commandEnd = len(line) commandEnd = len(line)
paramStart = len(line) paramStart = len(line)
} }
baseCommand := line[:commandEnd] // normalize command to uppercase:
if len(baseCommand) == 0 { ircmsg.Command = strings.ToUpper(line[:commandEnd])
if len(ircmsg.Command) == 0 {
return ircmsg, ErrorLineIsEmpty return ircmsg, ErrorLineIsEmpty
} }
// technically this must be either letters or a 3-digit numeric:
if !isASCII(baseCommand) {
return ircmsg, ErrorLineContainsBadChar
}
// normalize command to uppercase:
ircmsg.Command = strings.ToUpper(baseCommand)
line = line[paramStart:] line = line[paramStart:]
for { for {

View file

@ -3,6 +3,7 @@ package ircutils
import ( import (
"encoding/base64" "encoding/base64"
"errors" "errors"
"strings"
) )
var ( var (
@ -24,7 +25,6 @@ func EncodeSASLResponse(raw []byte) (result []string) {
} }
response := base64.StdEncoding.EncodeToString(raw) response := base64.StdEncoding.EncodeToString(raw)
result = make([]string, 0, (len(response)/400)+1)
lastLen := 0 lastLen := 0
for len(response) > 0 { for len(response) > 0 {
// TODO once we require go 1.21, this can be: lastLen = min(len(response), 400) // TODO once we require go 1.21, this can be: lastLen = min(len(response), 400)
@ -48,11 +48,11 @@ func EncodeSASLResponse(raw []byte) (result []string) {
// Do not copy a SASLBuffer after first use. // Do not copy a SASLBuffer after first use.
type SASLBuffer struct { type SASLBuffer struct {
maxLength int maxLength int
buf []byte buffer strings.Builder
} }
// NewSASLBuffer returns a new SASLBuffer. maxLength is the maximum amount of // NewSASLBuffer returns a new SASLBuffer. maxLength is the maximum amount of
// data to buffer (0 for no limit). // base64'ed data to buffer (0 for no limit).
func NewSASLBuffer(maxLength int) *SASLBuffer { func NewSASLBuffer(maxLength int) *SASLBuffer {
result := new(SASLBuffer) result := new(SASLBuffer)
result.Initialize(maxLength) result.Initialize(maxLength)
@ -69,43 +69,37 @@ func (b *SASLBuffer) Initialize(maxLength int) {
// response along with any decoding or protocol errors detected. // response along with any decoding or protocol errors detected.
func (b *SASLBuffer) Add(value string) (done bool, output []byte, err error) { func (b *SASLBuffer) Add(value string) (done bool, output []byte, err error) {
if value == "+" { if value == "+" {
// total size is a multiple of 400 (possibly 0) output, err = b.getAndReset()
output = b.buf return true, output, err
b.Clear()
return true, output, nil
} }
if len(value) > 400 { if len(value) > 400 {
b.Clear() b.buffer.Reset()
return true, nil, ErrSASLTooLong return true, nil, ErrSASLTooLong
} }
curLen := len(b.buf) if b.maxLength != 0 && (b.buffer.Len()+len(value)) > b.maxLength {
chunkDecodedLen := base64.StdEncoding.DecodedLen(len(value)) b.buffer.Reset()
if b.maxLength != 0 && (curLen+chunkDecodedLen) > b.maxLength {
b.Clear()
return true, nil, ErrSASLLimitExceeded return true, nil, ErrSASLLimitExceeded
} }
// "append-make pattern" as in the bytes.Buffer implementation: b.buffer.WriteString(value)
b.buf = append(b.buf, make([]byte, chunkDecodedLen)...)
n, err := base64.StdEncoding.Decode(b.buf[curLen:], []byte(value))
b.buf = b.buf[0 : curLen+n]
if err != nil {
b.Clear()
return true, nil, err
}
if len(value) < 400 { if len(value) < 400 {
output = b.buf output, err = b.getAndReset()
b.Clear() return true, output, err
return true, output, nil
} else { } else {
// 400 bytes, wait for continuation line or +
return false, nil, nil return false, nil, nil
} }
} }
// Clear resets the buffer state. // Clear resets the buffer state.
func (b *SASLBuffer) Clear() { func (b *SASLBuffer) Clear() {
// we can't reuse this buffer in general since we may have returned it b.buffer.Reset()
b.buf = nil }
func (b *SASLBuffer) getAndReset() (output []byte, err error) {
output, err = base64.StdEncoding.DecodeString(b.buffer.String())
b.buffer.Reset()
return
} }

View file

@ -62,7 +62,7 @@ func (m *SigningMethodECDSA) Verify(signingString string, sig []byte, key interf
case *ecdsa.PublicKey: case *ecdsa.PublicKey:
ecdsaKey = k ecdsaKey = k
default: default:
return newError("ECDSA verify expects *ecdsa.PublicKey", ErrInvalidKeyType) return newError("ECDSA verify expects *ecsda.PublicKey", ErrInvalidKeyType)
} }
if len(sig) != 2*m.KeySize { if len(sig) != 2*m.KeySize {
@ -96,7 +96,7 @@ func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) ([]byte
case *ecdsa.PrivateKey: case *ecdsa.PrivateKey:
ecdsaKey = k ecdsaKey = k
default: default:
return nil, newError("ECDSA sign expects *ecdsa.PrivateKey", ErrInvalidKeyType) return nil, newError("ECDSA sign expects *ecsda.PrivateKey", ErrInvalidKeyType)
} }
// Create the hasher // Create the hasher

View file

@ -91,7 +91,7 @@ func (m *SigningMethodHMAC) Verify(signingString string, sig []byte, key interfa
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) { func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte, error) {
if keyBytes, ok := key.([]byte); ok { if keyBytes, ok := key.([]byte); ok {
if !m.Hash.Available() { if !m.Hash.Available() {
return nil, ErrHashUnavailable return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType)
} }
hasher := hmac.New(m.Hash.New, keyBytes) hasher := hmac.New(m.Hash.New, keyBytes)
@ -100,5 +100,5 @@ func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) ([]byte,
return hasher.Sum(nil), nil return hasher.Sum(nil), nil
} }
return nil, newError("HMAC sign expects []byte", ErrInvalidKeyType) return nil, ErrInvalidKeyType
} }

View file

@ -61,8 +61,6 @@ var (
ErrTxIterating = errors.New("tx is iterating") ErrTxIterating = errors.New("tx is iterating")
) )
const useAbsEx = true
// DB represents a collection of key-value pairs that persist on disk. // DB represents a collection of key-value pairs that persist on disk.
// Transactions are used for all forms of data access to the DB. // Transactions are used for all forms of data access to the DB.
type DB struct { type DB struct {
@ -897,35 +895,24 @@ func (db *DB) readLoad(rd io.Reader, modTime time.Time) (n int64, err error) {
return totalSize, ErrInvalid return totalSize, ErrInvalid
} }
if len(parts) == 5 { if len(parts) == 5 {
arg := strings.ToLower(parts[3]) if strings.ToLower(parts[3]) != "ex" {
if arg != "ex" && arg != "ae" {
return totalSize, ErrInvalid return totalSize, ErrInvalid
} }
ex, err := strconv.ParseInt(parts[4], 10, 64) ex, err := strconv.ParseUint(parts[4], 10, 64)
if err != nil { if err != nil {
return totalSize, err return totalSize, err
} }
var exat time.Time
now := time.Now() now := time.Now()
if arg == "ex" { dur := (time.Duration(ex) * time.Second) - now.Sub(modTime)
dur := (time.Duration(ex) * time.Second) - now.Sub(modTime) if dur > 0 {
exat = now.Add(dur)
} else {
exat = time.Unix(ex, 0)
}
if exat.After(now) {
db.insertIntoDatabase(&dbItem{ db.insertIntoDatabase(&dbItem{
key: parts[1], key: parts[1],
val: parts[2], val: parts[2],
opts: &dbItemOpts{ opts: &dbItemOpts{
ex: true, ex: true,
exat: exat, exat: now.Add(dur),
}, },
}) })
} else {
db.deleteFromDatabase(&dbItem{
key: parts[1],
})
} }
} else { } else {
db.insertIntoDatabase(&dbItem{key: parts[1], val: parts[2]}) db.insertIntoDatabase(&dbItem{key: parts[1], val: parts[2]})
@ -1343,19 +1330,13 @@ func appendBulkString(buf []byte, s string) []byte {
// writeSetTo writes an item as a single SET record to the a bufio Writer. // writeSetTo writes an item as a single SET record to the a bufio Writer.
func (dbi *dbItem) writeSetTo(buf []byte, now time.Time) []byte { func (dbi *dbItem) writeSetTo(buf []byte, now time.Time) []byte {
if dbi.opts != nil && dbi.opts.ex { if dbi.opts != nil && dbi.opts.ex {
ex := dbi.opts.exat.Sub(now) / time.Second
buf = appendArray(buf, 5) buf = appendArray(buf, 5)
buf = appendBulkString(buf, "set") buf = appendBulkString(buf, "set")
buf = appendBulkString(buf, dbi.key) buf = appendBulkString(buf, dbi.key)
buf = appendBulkString(buf, dbi.val) buf = appendBulkString(buf, dbi.val)
if useAbsEx { buf = appendBulkString(buf, "ex")
ex := dbi.opts.exat.Unix() buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10))
buf = appendBulkString(buf, "ae")
buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10))
} else {
ex := dbi.opts.exat.Sub(now) / time.Second
buf = appendBulkString(buf, "ex")
buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10))
}
} else { } else {
buf = appendArray(buf, 3) buf = appendArray(buf, 3)
buf = appendBulkString(buf, "set") buf = appendBulkString(buf, "set")
@ -1641,9 +1622,6 @@ func (tx *Tx) scan(desc, gt, lt bool, index, start, stop string,
// wrap a btree specific iterator around the user-defined iterator. // wrap a btree specific iterator around the user-defined iterator.
iter := func(item interface{}) bool { iter := func(item interface{}) bool {
dbi := item.(*dbItem) dbi := item.(*dbItem)
if dbi.expired() {
return true
}
return iterator(dbi.key, dbi.val) return iterator(dbi.key, dbi.val)
} }
var tr *btree.BTree var tr *btree.BTree

View file

@ -4,7 +4,7 @@
// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing // Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf // algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
package bcrypt package bcrypt // import "golang.org/x/crypto/bcrypt"
// The code is a port of Provos and Mazières's C implementation. // The code is a port of Provos and Mazières's C implementation.
import ( import (

View file

@ -11,7 +11,7 @@
// Deprecated: any new system should use AES (from crypto/aes, if necessary in // Deprecated: any new system should use AES (from crypto/aes, if necessary in
// an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from // an AEAD mode like crypto/cipher.NewGCM) or XChaCha20-Poly1305 (from
// golang.org/x/crypto/chacha20poly1305). // golang.org/x/crypto/chacha20poly1305).
package blowfish package blowfish // import "golang.org/x/crypto/blowfish"
// The code is a port of Bruce Schneier's C implementation. // The code is a port of Bruce Schneier's C implementation.
// See https://www.schneier.com/blowfish.html. // See https://www.schneier.com/blowfish.html.

View file

@ -16,7 +16,7 @@ Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
choose, you can pass the `New` functions from the different SHA packages to choose, you can pass the `New` functions from the different SHA packages to
pbkdf2.Key. pbkdf2.Key.
*/ */
package pbkdf2 package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
import ( import (
"crypto/hmac" "crypto/hmac"

View file

@ -59,4 +59,4 @@
// They produce output of the same length, with the same security strengths // They produce output of the same length, with the same security strengths
// against all attacks. This means, in particular, that SHA3-256 only has // against all attacks. This means, in particular, that SHA3-256 only has
// 128-bit collision resistance, because its output length is 32 bytes. // 128-bit collision resistance, because its output length is 32 bytes.
package sha3 package sha3 // import "golang.org/x/crypto/sha3"

View file

@ -9,7 +9,6 @@ package sha3
// bytes. // bytes.
import ( import (
"crypto"
"hash" "hash"
) )
@ -17,50 +16,39 @@ import (
// Its generic security strength is 224 bits against preimage attacks, // Its generic security strength is 224 bits against preimage attacks,
// and 112 bits against collision attacks. // and 112 bits against collision attacks.
func New224() hash.Hash { func New224() hash.Hash {
return new224() if h := new224Asm(); h != nil {
return h
}
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
} }
// New256 creates a new SHA3-256 hash. // New256 creates a new SHA3-256 hash.
// Its generic security strength is 256 bits against preimage attacks, // Its generic security strength is 256 bits against preimage attacks,
// and 128 bits against collision attacks. // and 128 bits against collision attacks.
func New256() hash.Hash { func New256() hash.Hash {
return new256() if h := new256Asm(); h != nil {
return h
}
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
} }
// New384 creates a new SHA3-384 hash. // New384 creates a new SHA3-384 hash.
// Its generic security strength is 384 bits against preimage attacks, // Its generic security strength is 384 bits against preimage attacks,
// and 192 bits against collision attacks. // and 192 bits against collision attacks.
func New384() hash.Hash { func New384() hash.Hash {
return new384() if h := new384Asm(); h != nil {
return h
}
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
} }
// New512 creates a new SHA3-512 hash. // New512 creates a new SHA3-512 hash.
// Its generic security strength is 512 bits against preimage attacks, // Its generic security strength is 512 bits against preimage attacks,
// and 256 bits against collision attacks. // and 256 bits against collision attacks.
func New512() hash.Hash { func New512() hash.Hash {
return new512() if h := new512Asm(); h != nil {
} return h
}
func init() {
crypto.RegisterHash(crypto.SHA3_224, New224)
crypto.RegisterHash(crypto.SHA3_256, New256)
crypto.RegisterHash(crypto.SHA3_384, New384)
crypto.RegisterHash(crypto.SHA3_512, New512)
}
func new224Generic() *state {
return &state{rate: 144, outputLen: 28, dsbyte: 0x06}
}
func new256Generic() *state {
return &state{rate: 136, outputLen: 32, dsbyte: 0x06}
}
func new384Generic() *state {
return &state{rate: 104, outputLen: 48, dsbyte: 0x06}
}
func new512Generic() *state {
return &state{rate: 72, outputLen: 64, dsbyte: 0x06} return &state{rate: 72, outputLen: 64, dsbyte: 0x06}
} }

27
vendor/golang.org/x/crypto/sha3/hashes_generic.go generated vendored Normal file
View file

@ -0,0 +1,27 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
package sha3
import (
"hash"
)
// new224Asm returns an assembly implementation of SHA3-224 if available,
// otherwise it returns nil.
func new224Asm() hash.Hash { return nil }
// new256Asm returns an assembly implementation of SHA3-256 if available,
// otherwise it returns nil.
func new256Asm() hash.Hash { return nil }
// new384Asm returns an assembly implementation of SHA3-384 if available,
// otherwise it returns nil.
func new384Asm() hash.Hash { return nil }
// new512Asm returns an assembly implementation of SHA3-512 if available,
// otherwise it returns nil.
func new512Asm() hash.Hash { return nil }

View file

@ -1,23 +0,0 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
package sha3
func new224() *state {
return new224Generic()
}
func new256() *state {
return new256Generic()
}
func new384() *state {
return new384Generic()
}
func new512() *state {
return new512Generic()
}

18
vendor/golang.org/x/crypto/sha3/register.go generated vendored Normal file
View file

@ -0,0 +1,18 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.4
package sha3
import (
"crypto"
)
func init() {
crypto.RegisterHash(crypto.SHA3_224, New224)
crypto.RegisterHash(crypto.SHA3_256, New256)
crypto.RegisterHash(crypto.SHA3_384, New384)
crypto.RegisterHash(crypto.SHA3_512, New512)
}

View file

@ -23,6 +23,7 @@ const (
type state struct { type state struct {
// Generic sponge components. // Generic sponge components.
a [25]uint64 // main state of the hash a [25]uint64 // main state of the hash
buf []byte // points into storage
rate int // the number of bytes of state to use rate int // the number of bytes of state to use
// dsbyte contains the "domain separation" bits and the first bit of // dsbyte contains the "domain separation" bits and the first bit of
@ -39,8 +40,7 @@ type state struct {
// Extendable-Output Functions (May 2014)" // Extendable-Output Functions (May 2014)"
dsbyte byte dsbyte byte
i, n int // storage[i:n] is the buffer, i is only used while squeezing storage storageBuf
storage [maxRate]byte
// Specific to SHA-3 and SHAKE. // Specific to SHA-3 and SHAKE.
outputLen int // the default output size in bytes outputLen int // the default output size in bytes
@ -54,18 +54,24 @@ func (d *state) BlockSize() int { return d.rate }
func (d *state) Size() int { return d.outputLen } func (d *state) Size() int { return d.outputLen }
// Reset clears the internal state by zeroing the sponge state and // Reset clears the internal state by zeroing the sponge state and
// the buffer indexes, and setting Sponge.state to absorbing. // the byte buffer, and setting Sponge.state to absorbing.
func (d *state) Reset() { func (d *state) Reset() {
// Zero the permutation's state. // Zero the permutation's state.
for i := range d.a { for i := range d.a {
d.a[i] = 0 d.a[i] = 0
} }
d.state = spongeAbsorbing d.state = spongeAbsorbing
d.i, d.n = 0, 0 d.buf = d.storage.asBytes()[:0]
} }
func (d *state) clone() *state { func (d *state) clone() *state {
ret := *d ret := *d
if ret.state == spongeAbsorbing {
ret.buf = ret.storage.asBytes()[:len(ret.buf)]
} else {
ret.buf = ret.storage.asBytes()[d.rate-cap(d.buf) : d.rate]
}
return &ret return &ret
} }
@ -76,40 +82,43 @@ func (d *state) permute() {
case spongeAbsorbing: case spongeAbsorbing:
// If we're absorbing, we need to xor the input into the state // If we're absorbing, we need to xor the input into the state
// before applying the permutation. // before applying the permutation.
xorIn(d, d.storage[:d.rate]) xorIn(d, d.buf)
d.n = 0 d.buf = d.storage.asBytes()[:0]
keccakF1600(&d.a) keccakF1600(&d.a)
case spongeSqueezing: case spongeSqueezing:
// If we're squeezing, we need to apply the permutation before // If we're squeezing, we need to apply the permutation before
// copying more output. // copying more output.
keccakF1600(&d.a) keccakF1600(&d.a)
d.i = 0 d.buf = d.storage.asBytes()[:d.rate]
copyOut(d, d.storage[:d.rate]) copyOut(d, d.buf)
} }
} }
// pads appends the domain separation bits in dsbyte, applies // pads appends the domain separation bits in dsbyte, applies
// the multi-bitrate 10..1 padding rule, and permutes the state. // the multi-bitrate 10..1 padding rule, and permutes the state.
func (d *state) padAndPermute() { func (d *state) padAndPermute(dsbyte byte) {
if d.buf == nil {
d.buf = d.storage.asBytes()[:0]
}
// Pad with this instance's domain-separator bits. We know that there's // Pad with this instance's domain-separator bits. We know that there's
// at least one byte of space in d.buf because, if it were full, // at least one byte of space in d.buf because, if it were full,
// permute would have been called to empty it. dsbyte also contains the // permute would have been called to empty it. dsbyte also contains the
// first one bit for the padding. See the comment in the state struct. // first one bit for the padding. See the comment in the state struct.
d.storage[d.n] = d.dsbyte d.buf = append(d.buf, dsbyte)
d.n++ zerosStart := len(d.buf)
for d.n < d.rate { d.buf = d.storage.asBytes()[:d.rate]
d.storage[d.n] = 0 for i := zerosStart; i < d.rate; i++ {
d.n++ d.buf[i] = 0
} }
// This adds the final one bit for the padding. Because of the way that // This adds the final one bit for the padding. Because of the way that
// bits are numbered from the LSB upwards, the final bit is the MSB of // bits are numbered from the LSB upwards, the final bit is the MSB of
// the last byte. // the last byte.
d.storage[d.rate-1] ^= 0x80 d.buf[d.rate-1] ^= 0x80
// Apply the permutation // Apply the permutation
d.permute() d.permute()
d.state = spongeSqueezing d.state = spongeSqueezing
d.n = d.rate d.buf = d.storage.asBytes()[:d.rate]
copyOut(d, d.storage[:d.rate]) copyOut(d, d.buf)
} }
// Write absorbs more data into the hash's state. It panics if any // Write absorbs more data into the hash's state. It panics if any
@ -118,25 +127,28 @@ func (d *state) Write(p []byte) (written int, err error) {
if d.state != spongeAbsorbing { if d.state != spongeAbsorbing {
panic("sha3: Write after Read") panic("sha3: Write after Read")
} }
if d.buf == nil {
d.buf = d.storage.asBytes()[:0]
}
written = len(p) written = len(p)
for len(p) > 0 { for len(p) > 0 {
if d.n == 0 && len(p) >= d.rate { if len(d.buf) == 0 && len(p) >= d.rate {
// The fast path; absorb a full "rate" bytes of input and apply the permutation. // The fast path; absorb a full "rate" bytes of input and apply the permutation.
xorIn(d, p[:d.rate]) xorIn(d, p[:d.rate])
p = p[d.rate:] p = p[d.rate:]
keccakF1600(&d.a) keccakF1600(&d.a)
} else { } else {
// The slow path; buffer the input until we can fill the sponge, and then xor it in. // The slow path; buffer the input until we can fill the sponge, and then xor it in.
todo := d.rate - d.n todo := d.rate - len(d.buf)
if todo > len(p) { if todo > len(p) {
todo = len(p) todo = len(p)
} }
d.n += copy(d.storage[d.n:], p[:todo]) d.buf = append(d.buf, p[:todo]...)
p = p[todo:] p = p[todo:]
// If the sponge is full, apply the permutation. // If the sponge is full, apply the permutation.
if d.n == d.rate { if len(d.buf) == d.rate {
d.permute() d.permute()
} }
} }
@ -149,19 +161,19 @@ func (d *state) Write(p []byte) (written int, err error) {
func (d *state) Read(out []byte) (n int, err error) { func (d *state) Read(out []byte) (n int, err error) {
// If we're still absorbing, pad and apply the permutation. // If we're still absorbing, pad and apply the permutation.
if d.state == spongeAbsorbing { if d.state == spongeAbsorbing {
d.padAndPermute() d.padAndPermute(d.dsbyte)
} }
n = len(out) n = len(out)
// Now, do the squeezing. // Now, do the squeezing.
for len(out) > 0 { for len(out) > 0 {
n := copy(out, d.storage[d.i:d.n]) n := copy(out, d.buf)
d.i += n d.buf = d.buf[n:]
out = out[n:] out = out[n:]
// Apply the permutation if we've squeezed the sponge dry. // Apply the permutation if we've squeezed the sponge dry.
if d.i == d.rate { if len(d.buf) == 0 {
d.permute() d.permute()
} }
} }

View file

@ -143,12 +143,6 @@ func (s *asmState) Write(b []byte) (int, error) {
// Read squeezes an arbitrary number of bytes from the sponge. // Read squeezes an arbitrary number of bytes from the sponge.
func (s *asmState) Read(out []byte) (n int, err error) { func (s *asmState) Read(out []byte) (n int, err error) {
// The 'compute last message digest' instruction only stores the digest
// at the first operand (dst) for SHAKE functions.
if s.function != shake_128 && s.function != shake_256 {
panic("sha3: can only call Read for SHAKE functions")
}
n = len(out) n = len(out)
// need to pad if we were absorbing // need to pad if we were absorbing
@ -208,17 +202,8 @@ func (s *asmState) Sum(b []byte) []byte {
// Hash the buffer. Note that we don't clear it because we // Hash the buffer. Note that we don't clear it because we
// aren't updating the state. // aren't updating the state.
switch s.function { klmd(s.function, &a, nil, s.buf)
case sha3_224, sha3_256, sha3_384, sha3_512: return append(b, a[:s.outputLen]...)
klmd(s.function, &a, nil, s.buf)
return append(b, a[:s.outputLen]...)
case shake_128, shake_256:
d := make([]byte, s.outputLen, 64)
klmd(s.function, &a, d, s.buf)
return append(b, d[:s.outputLen]...)
default:
panic("sha3: unknown function")
}
} }
// Reset resets the Hash to its initial state. // Reset resets the Hash to its initial state.
@ -248,56 +233,56 @@ func (s *asmState) Clone() ShakeHash {
return s.clone() return s.clone()
} }
// new224 returns an assembly implementation of SHA3-224 if available, // new224Asm returns an assembly implementation of SHA3-224 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func new224() hash.Hash { func new224Asm() hash.Hash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(sha3_224) return newAsmState(sha3_224)
} }
return new224Generic() return nil
} }
// new256 returns an assembly implementation of SHA3-256 if available, // new256Asm returns an assembly implementation of SHA3-256 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func new256() hash.Hash { func new256Asm() hash.Hash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(sha3_256) return newAsmState(sha3_256)
} }
return new256Generic() return nil
} }
// new384 returns an assembly implementation of SHA3-384 if available, // new384Asm returns an assembly implementation of SHA3-384 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func new384() hash.Hash { func new384Asm() hash.Hash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(sha3_384) return newAsmState(sha3_384)
} }
return new384Generic() return nil
} }
// new512 returns an assembly implementation of SHA3-512 if available, // new512Asm returns an assembly implementation of SHA3-512 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func new512() hash.Hash { func new512Asm() hash.Hash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(sha3_512) return newAsmState(sha3_512)
} }
return new512Generic() return nil
} }
// newShake128 returns an assembly implementation of SHAKE-128 if available, // newShake128Asm returns an assembly implementation of SHAKE-128 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func newShake128() ShakeHash { func newShake128Asm() ShakeHash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(shake_128) return newAsmState(shake_128)
} }
return newShake128Generic() return nil
} }
// newShake256 returns an assembly implementation of SHAKE-256 if available, // newShake256Asm returns an assembly implementation of SHAKE-256 if available,
// otherwise it returns a generic implementation. // otherwise it returns nil.
func newShake256() ShakeHash { func newShake256Asm() ShakeHash {
if cpu.S390X.HasSHA3 { if cpu.S390X.HasSHA3 {
return newAsmState(shake_256) return newAsmState(shake_256)
} }
return newShake256Generic() return nil
} }

View file

@ -115,21 +115,19 @@ func (c *state) Clone() ShakeHash {
// Its generic security strength is 128 bits against all attacks if at // Its generic security strength is 128 bits against all attacks if at
// least 32 bytes of its output are used. // least 32 bytes of its output are used.
func NewShake128() ShakeHash { func NewShake128() ShakeHash {
return newShake128() if h := newShake128Asm(); h != nil {
return h
}
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
} }
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash. // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
// Its generic security strength is 256 bits against all attacks if // Its generic security strength is 256 bits against all attacks if
// at least 64 bytes of its output are used. // at least 64 bytes of its output are used.
func NewShake256() ShakeHash { func NewShake256() ShakeHash {
return newShake256() if h := newShake256Asm(); h != nil {
} return h
}
func newShake128Generic() *state {
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
}
func newShake256Generic() *state {
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake} return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
} }

19
vendor/golang.org/x/crypto/sha3/shake_generic.go generated vendored Normal file
View file

@ -0,0 +1,19 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
package sha3
// newShake128Asm returns an assembly implementation of SHAKE-128 if available,
// otherwise it returns nil.
func newShake128Asm() ShakeHash {
return nil
}
// newShake256Asm returns an assembly implementation of SHAKE-256 if available,
// otherwise it returns nil.
func newShake256Asm() ShakeHash {
return nil
}

View file

@ -1,15 +0,0 @@
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !gc || purego || !s390x
package sha3
func newShake128() *state {
return newShake128Generic()
}
func newShake256() *state {
return newShake256Generic()
}

View file

@ -2,39 +2,22 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build (!amd64 && !386 && !ppc64le) || purego
package sha3 package sha3
import ( // A storageBuf is an aligned array of maxRate bytes.
"crypto/subtle" type storageBuf [maxRate]byte
"encoding/binary"
"unsafe"
"golang.org/x/sys/cpu" func (b *storageBuf) asBytes() *[maxRate]byte {
return (*[maxRate]byte)(b)
}
var (
xorIn = xorInGeneric
copyOut = copyOutGeneric
xorInUnaligned = xorInGeneric
copyOutUnaligned = copyOutGeneric
) )
// xorIn xors the bytes in buf into the state. const xorImplementationUnaligned = "generic"
func xorIn(d *state, buf []byte) {
if cpu.IsBigEndian {
for i := 0; len(buf) >= 8; i++ {
a := binary.LittleEndian.Uint64(buf)
d.a[i] ^= a
buf = buf[8:]
}
} else {
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
subtle.XORBytes(ab[:], ab[:], buf)
}
}
// copyOut copies uint64s to a byte buffer.
func copyOut(d *state, b []byte) {
if cpu.IsBigEndian {
for i := 0; len(b) >= 8; i++ {
binary.LittleEndian.PutUint64(b, d.a[i])
b = b[8:]
}
} else {
ab := (*[25 * 64 / 8]byte)(unsafe.Pointer(&d.a))
copy(b, ab[:])
}
}

28
vendor/golang.org/x/crypto/sha3/xor_generic.go generated vendored Normal file
View file

@ -0,0 +1,28 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sha3
import "encoding/binary"
// xorInGeneric xors the bytes in buf into the state; it
// makes no non-portable assumptions about memory layout
// or alignment.
func xorInGeneric(d *state, buf []byte) {
n := len(buf) / 8
for i := 0; i < n; i++ {
a := binary.LittleEndian.Uint64(buf)
d.a[i] ^= a
buf = buf[8:]
}
}
// copyOutGeneric copies uint64s to a byte buffer.
func copyOutGeneric(d *state, b []byte) {
for i := 0; len(b) >= 8; i++ {
binary.LittleEndian.PutUint64(b, d.a[i])
b = b[8:]
}
}

66
vendor/golang.org/x/crypto/sha3/xor_unaligned.go generated vendored Normal file
View file

@ -0,0 +1,66 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (amd64 || 386 || ppc64le) && !purego
package sha3
import "unsafe"
// A storageBuf is an aligned array of maxRate bytes.
type storageBuf [maxRate / 8]uint64
func (b *storageBuf) asBytes() *[maxRate]byte {
return (*[maxRate]byte)(unsafe.Pointer(b))
}
// xorInUnaligned uses unaligned reads and writes to update d.a to contain d.a
// XOR buf.
func xorInUnaligned(d *state, buf []byte) {
n := len(buf)
bw := (*[maxRate / 8]uint64)(unsafe.Pointer(&buf[0]))[: n/8 : n/8]
if n >= 72 {
d.a[0] ^= bw[0]
d.a[1] ^= bw[1]
d.a[2] ^= bw[2]
d.a[3] ^= bw[3]
d.a[4] ^= bw[4]
d.a[5] ^= bw[5]
d.a[6] ^= bw[6]
d.a[7] ^= bw[7]
d.a[8] ^= bw[8]
}
if n >= 104 {
d.a[9] ^= bw[9]
d.a[10] ^= bw[10]
d.a[11] ^= bw[11]
d.a[12] ^= bw[12]
}
if n >= 136 {
d.a[13] ^= bw[13]
d.a[14] ^= bw[14]
d.a[15] ^= bw[15]
d.a[16] ^= bw[16]
}
if n >= 144 {
d.a[17] ^= bw[17]
}
if n >= 168 {
d.a[18] ^= bw[18]
d.a[19] ^= bw[19]
d.a[20] ^= bw[20]
}
}
func copyOutUnaligned(d *state, buf []byte) {
ab := (*[maxRate]uint8)(unsafe.Pointer(&d.a[0]))
copy(buf, ab[:])
}
var (
xorIn = xorInUnaligned
copyOut = copyOutUnaligned
)
const xorImplementationUnaligned = "unaligned"

1
vendor/golang.org/x/sys/cpu/cpu.go generated vendored
View file

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

View file

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

View file

@ -29,11 +29,3 @@ TEXT ·getpfr0(SB),NOSPLIT,$0-8
WORD $0xd5380400 WORD $0xd5380400
MOVD R0, ret+0(FP) MOVD R0, ret+0(FP)
RET 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,4 +9,3 @@ package cpu
func getisar0() uint64 func getisar0() uint64
func getisar1() uint64 func getisar1() uint64
func getpfr0() uint64 func getpfr0() uint64
func getzfr0() uint64

View file

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

View file

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

View file

@ -9,11 +9,9 @@
#define PSALAA 1208(R0) #define PSALAA 1208(R0)
#define GTAB64(x) 80(x) #define GTAB64(x) 80(x)
#define LCA64(x) 88(x) #define LCA64(x) 88(x)
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
#define CAA(x) 8(x) #define CAA(x) 8(x)
#define CEECAATHDID(x) 976(x) // in the CAA #define EDCHPXV(x) 1016(x) // in the CAA
#define EDCHPXV(x) 1016(x) // in the CAA #define SAVSTACK_ASYNC(x) 336(x) // in the LCA
#define GOCB(x) 1104(x) // in the CAA
// SS_*, where x=SAVSTACK_ASYNC // SS_*, where x=SAVSTACK_ASYNC
#define SS_LE(x) 0(x) #define SS_LE(x) 0(x)
@ -21,125 +19,394 @@
#define SS_ERRNO(x) 16(x) #define SS_ERRNO(x) 16(x)
#define SS_ERRNOJR(x) 20(x) #define SS_ERRNOJR(x) 20(x)
// Function Descriptor Offsets #define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6
#define __errno 0x156*16
#define __err2ad 0x16C*16
// Call Instructions TEXT ·clearErrno(SB),NOSPLIT,$0-0
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6 BL addrerrno<>(SB)
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD MOVD $0, 0(R3)
#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 RET
// Returns the address of errno in R3. // 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). // Get library control area (LCA).
MOVW PSALAA, R8 MOVW PSALAA, R8
MOVD LCA64(R8), R8 MOVD LCA64(R8), R8
// Get __errno FuncDesc. // Get __errno FuncDesc.
MOVD CAA(R8), R9 MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9 MOVD EDCHPXV(R9), R9
ADD $(__errno), R9 ADD $(0x156*16), R9
LMG 0(R9), R5, R6 LMG 0(R9), R5, R6
// Switch to saved LE stack. // Switch to saved LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4 MOVD 0(R9), R4
MOVD $0, 0(R9) MOVD $0, 0(R9)
// Call __errno function. // Call __errno function.
LE_CALL LE_CALL
NOPH NOPH
// Switch back to Go stack. // Switch back to Go stack.
XOR R0, R0 // Restore R0 to $0. XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer. 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 RET
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64) // 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 BL runtime·save_g(SB) // Save g and stack pointer
MOVW PSALAA, R8 MOVW PSALAA, R8
MOVD LCA64(R8), R8 MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9 MOVD SAVSTACK_ASYNC(R8), R9
MOVD R15, 0(R9) MOVD R15, 0(R9)
MOVD argv+8(FP), R1 // Move function arguments into registers MOVD argv+8(FP), R1 // Move function arguments into registers
MOVD dsa+16(FP), g MOVD dsa+16(FP), g
MOVD fnptr+0(FP), R15 MOVD fnptr+0(FP), R15
BYTE $0x0D // Branch to function BYTE $0x0D // Branch to function
BYTE $0xEF BYTE $0xEF
BL runtime·load_g(SB) // Restore g and stack pointer BL runtime·load_g(SB) // Restore g and stack pointer
MOVW PSALAA, R8 MOVW PSALAA, R8
MOVD LCA64(R8), R8 MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9 MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R15 MOVD 0(R9), R15
RET RET
// func svcLoad(name *byte) unsafe.Pointer // func svcLoad(name *byte) unsafe.Pointer
TEXT ·svcLoad(SB), NOSPLIT, $0 TEXT ·svcLoad(SB),NOSPLIT,$0
MOVD R15, R2 // Save go stack pointer MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers MOVD name+0(FP), R0 // Move SVC args into registers
MOVD $0x80000000, R1 MOVD $0x80000000, R1
MOVD $0, R15 MOVD $0, R15
SVC_LOAD BYTE $0x0A // SVC 08 LOAD
MOVW R15, R3 // Save return code from SVC BYTE $0x08
MOVD R2, R15 // Restore go stack pointer MOVW R15, R3 // Save return code from SVC
CMP R3, $0 // Check SVC return code MOVD R2, R15 // Restore go stack pointer
BNE error CMP R3, $0 // Check SVC return code
BNE error
MOVD $-2, R3 // Reset last bit of entry point to zero MOVD $-2, R3 // Reset last bit of entry point to zero
AND R0, R3 AND R0, R3
MOVD R3, ret+8(FP) // Return entry point returned by SVC MOVD R3, addr+8(FP) // Return entry point returned by SVC
CMP R0, R3 // Check if last bit of entry point was set CMP R0, R3 // Check if last bit of entry point was set
BNE done BNE done
MOVD R15, R2 // Save go stack pointer MOVD R15, R2 // Save go stack pointer
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08) MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
SVC_DELETE BYTE $0x0A // SVC 09 DELETE
MOVD R2, R15 // Restore go stack pointer BYTE $0x09
MOVD R2, R15 // Restore go stack pointer
error: error:
MOVD $0, ret+8(FP) // Return 0 on failure MOVD $0, addr+8(FP) // Return 0 on failure
done: done:
XOR R0, R0 // Reset r0 to 0 XOR R0, R0 // Reset r0 to 0
RET RET
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64 // 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 R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers MOVD name+0(FP), R0 // Move SVC args into registers
MOVD fnptr+8(FP), R15 MOVD addr+8(FP), R15
SVC_DELETE BYTE $0x0A // SVC 09
XOR R0, R0 // Reset r0 to 0 BYTE $0x09
MOVD R15, R1 // Save SVC return code XOR R0, R0 // Reset r0 to 0
MOVD R2, R15 // Restore go stack pointer MOVD R15, R1 // Save SVC return code
MOVD R1, ret+16(FP) // Return SVC return code MOVD R2, R15 // Restore go stack pointer
MOVD R1, rc+0(FP) // Return SVC return code
RET RET
// func gettid() uint64 // func gettid() uint64
@ -150,233 +417,7 @@ TEXT ·gettid(SB), NOSPLIT, $0
// Get CEECAATHDID // Get CEECAATHDID
MOVD CAA(R8), R9 MOVD CAA(R8), R9
MOVD CEECAATHDID(R9), R9 MOVD 0x3D0(R9), R9
MOVD R9, ret+0(FP) MOVD R9, ret+0(FP)
RET 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

@ -1,657 +0,0 @@
// 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

@ -1,192 +0,0 @@
// 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

220
vendor/golang.org/x/sys/unix/epoll_zos.go generated vendored Normal file
View file

@ -0,0 +1,220 @@
// 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)
}

163
vendor/golang.org/x/sys/unix/fstatfs_zos.go generated vendored Normal file
View file

@ -0,0 +1,163 @@
// 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

@ -248,7 +248,6 @@ struct ltchars {
#include <linux/module.h> #include <linux/module.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/net_namespace.h> #include <linux/net_namespace.h>
#include <linux/nfc.h> #include <linux/nfc.h>
@ -263,7 +262,6 @@ struct ltchars {
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/seccomp.h> #include <linux/seccomp.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/sock_diag.h>
#include <linux/sockios.h> #include <linux/sockios.h>
#include <linux/taskstats.h> #include <linux/taskstats.h>
#include <linux/tipc.h> #include <linux/tipc.h>
@ -285,6 +283,10 @@ struct ltchars {
#include <asm/termbits.h> #include <asm/termbits.h>
#endif #endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN 0x20000000
#endif
#ifndef PTRACE_GETREGS #ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc #define PTRACE_GETREGS 0xc
#endif #endif
@ -293,6 +295,14 @@ struct ltchars {
#define PTRACE_SETREGS 0xd #define PTRACE_SETREGS 0xd
#endif #endif
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#ifndef SOL_SMC
#define SOL_SMC 286
#endif
#ifdef SOL_BLUETOOTH #ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h // SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go // but it is already in bluetooth_linux.go
@ -309,23 +319,10 @@ struct ltchars {
#undef TIPC_WAIT_FOREVER #undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff #define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/netfilter/nf_nat.h // Copied from linux/l2tp.h
// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h // Including linux/l2tp.h here causes conflicts between linux/in.h
// and netinet/in.h. // and netinet/in.h included via net/route.h above.
#define NF_NAT_RANGE_MAP_IPS (1 << 0) #define IPPROTO_L2TP 115
#define NF_NAT_RANGE_PROTO_SPECIFIED (1 << 1)
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
NF_NAT_RANGE_NETMAP)
// Copied from linux/hid.h. // Copied from linux/hid.h.
// Keep in sync with the size of the referenced fields. // Keep in sync with the size of the referenced fields.
@ -550,7 +547,6 @@ ccflags="$@"
$2 !~ "NLA_TYPE_MASK" && $2 !~ "NLA_TYPE_MASK" &&
$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ && $2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ || $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
$2 ~ /^SOCK_|SK_DIAG_|SKNLGRP_$/ ||
$2 ~ /^FIORDCHK$/ || $2 ~ /^FIORDCHK$/ ||
$2 ~ /^SIOC/ || $2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ || $2 ~ /^TIOC/ ||
@ -586,7 +582,7 @@ ccflags="$@"
$2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ ||
$2 ~ /^KEYCTL_/ || $2 ~ /^KEYCTL_/ ||
$2 ~ /^PERF_/ || $2 ~ /^PERF_/ ||
$2 ~ /^SECCOMP_/ || $2 ~ /^SECCOMP_MODE_/ ||
$2 ~ /^SEEK_/ || $2 ~ /^SEEK_/ ||
$2 ~ /^SCHED_/ || $2 ~ /^SCHED_/ ||
$2 ~ /^SPLICE_/ || $2 ~ /^SPLICE_/ ||
@ -607,9 +603,6 @@ ccflags="$@"
$2 ~ /^FSOPT_/ || $2 ~ /^FSOPT_/ ||
$2 ~ /^WDIO[CFS]_/ || $2 ~ /^WDIO[CFS]_/ ||
$2 ~ /^NFN/ || $2 ~ /^NFN/ ||
$2 !~ /^NFT_META_IIFTYPE/ &&
$2 ~ /^NFT_/ ||
$2 ~ /^NF_NAT_/ ||
$2 ~ /^XDP_/ || $2 ~ /^XDP_/ ||
$2 ~ /^RWF_/ || $2 ~ /^RWF_/ ||
$2 ~ /^(HDIO|WIN|SMART)_/ || $2 ~ /^(HDIO|WIN|SMART)_/ ||

View file

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

View file

@ -50,8 +50,3 @@ func (m *mremapMmapper) Mremap(oldData []byte, newLength int, flags int) (data [
func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) { func Mremap(oldData []byte, newLength int, flags int) (data []byte, err error) {
return mapper.Mremap(oldData, newLength, flags) return mapper.Mremap(oldData, newLength, flags)
} }
func MremapPtr(oldAddr unsafe.Pointer, oldSize uintptr, newAddr unsafe.Pointer, newSize uintptr, flags int) (ret unsafe.Pointer, err error) {
xaddr, err := mapper.mremap(uintptr(oldAddr), oldSize, newSize, flags, uintptr(newAddr))
return unsafe.Pointer(xaddr), err
}

View file

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

View file

@ -1,58 +0,0 @@
// 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

@ -1,75 +0,0 @@
// 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

@ -542,18 +542,6 @@ func SysctlKinfoProcSlice(name string, args ...int) ([]KinfoProc, error) {
} }
} }
//sys pthread_chdir_np(path string) (err error)
func PthreadChdir(path string) (err error) {
return pthread_chdir_np(path)
}
//sys pthread_fchdir_np(fd int) (err error)
func PthreadFchdir(fd int) (err error) {
return pthread_fchdir_np(fd)
}
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error) //sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) //sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)

View file

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

View file

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

View file

@ -1849,105 +1849,6 @@ func Dup2(oldfd, newfd int) error {
//sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error) //sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error)
//sys Fsopen(fsName string, flags int) (fd 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 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 //sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
//sysnb Getpgid(pid int) (pgid int, err error) //sysnb Getpgid(pid int) (pgid int, err error)

View file

@ -154,15 +154,6 @@ func Munmap(b []byte) (err error) {
return mapper.Munmap(b) return mapper.Munmap(b)
} }
func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) {
xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset)
return unsafe.Pointer(xaddr), err
}
func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) {
return mapper.munmap(uintptr(addr), length)
}
func Read(fd int, p []byte) (n int, err error) { func Read(fd int, p []byte) (n int, err error) {
n, err = read(fd, p) n, err = read(fd, p)
if raceenabled { if raceenabled {

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

View file

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

View file

@ -491,7 +491,6 @@ const (
BPF_F_REPLACE = 0x4 BPF_F_REPLACE = 0x4
BPF_F_SLEEPABLE = 0x10 BPF_F_SLEEPABLE = 0x10
BPF_F_STRICT_ALIGNMENT = 0x1 BPF_F_STRICT_ALIGNMENT = 0x1
BPF_F_TEST_REG_INVARIANTS = 0x80
BPF_F_TEST_RND_HI32 = 0x4 BPF_F_TEST_RND_HI32 = 0x4
BPF_F_TEST_RUN_ON_CPU = 0x1 BPF_F_TEST_RUN_ON_CPU = 0x1
BPF_F_TEST_STATE_FREQ = 0x8 BPF_F_TEST_STATE_FREQ = 0x8
@ -502,7 +501,6 @@ const (
BPF_IMM = 0x0 BPF_IMM = 0x0
BPF_IND = 0x40 BPF_IND = 0x40
BPF_JA = 0x0 BPF_JA = 0x0
BPF_JCOND = 0xe0
BPF_JEQ = 0x10 BPF_JEQ = 0x10
BPF_JGE = 0x30 BPF_JGE = 0x30
BPF_JGT = 0x20 BPF_JGT = 0x20
@ -658,9 +656,6 @@ const (
CAN_NPROTO = 0x8 CAN_NPROTO = 0x8
CAN_RAW = 0x1 CAN_RAW = 0x1
CAN_RAW_FILTER_MAX = 0x200 CAN_RAW_FILTER_MAX = 0x200
CAN_RAW_XL_VCID_RX_FILTER = 0x4
CAN_RAW_XL_VCID_TX_PASS = 0x2
CAN_RAW_XL_VCID_TX_SET = 0x1
CAN_RTR_FLAG = 0x40000000 CAN_RTR_FLAG = 0x40000000
CAN_SFF_ID_BITS = 0xb CAN_SFF_ID_BITS = 0xb
CAN_SFF_MASK = 0x7ff CAN_SFF_MASK = 0x7ff
@ -1343,7 +1338,6 @@ const (
F_OFD_SETLK = 0x25 F_OFD_SETLK = 0x25
F_OFD_SETLKW = 0x26 F_OFD_SETLKW = 0x26
F_OK = 0x0 F_OK = 0x0
F_SEAL_EXEC = 0x20
F_SEAL_FUTURE_WRITE = 0x10 F_SEAL_FUTURE_WRITE = 0x10
F_SEAL_GROW = 0x4 F_SEAL_GROW = 0x4
F_SEAL_SEAL = 0x1 F_SEAL_SEAL = 0x1
@ -1632,7 +1626,6 @@ const (
IP_FREEBIND = 0xf IP_FREEBIND = 0xf
IP_HDRINCL = 0x3 IP_HDRINCL = 0x3
IP_IPSEC_POLICY = 0x10 IP_IPSEC_POLICY = 0x10
IP_LOCAL_PORT_RANGE = 0x33
IP_MAXPACKET = 0xffff IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14 IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000 IP_MF = 0x2000
@ -1659,7 +1652,6 @@ const (
IP_PMTUDISC_OMIT = 0x5 IP_PMTUDISC_OMIT = 0x5
IP_PMTUDISC_PROBE = 0x3 IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1 IP_PMTUDISC_WANT = 0x1
IP_PROTOCOL = 0x34
IP_RECVERR = 0xb IP_RECVERR = 0xb
IP_RECVERR_RFC4884 = 0x1a IP_RECVERR_RFC4884 = 0x1a
IP_RECVFRAGSIZE = 0x19 IP_RECVFRAGSIZE = 0x19
@ -1705,7 +1697,6 @@ const (
KEXEC_ARCH_S390 = 0x160000 KEXEC_ARCH_S390 = 0x160000
KEXEC_ARCH_SH = 0x2a0000 KEXEC_ARCH_SH = 0x2a0000
KEXEC_ARCH_X86_64 = 0x3e0000 KEXEC_ARCH_X86_64 = 0x3e0000
KEXEC_FILE_DEBUG = 0x8
KEXEC_FILE_NO_INITRAMFS = 0x4 KEXEC_FILE_NO_INITRAMFS = 0x4
KEXEC_FILE_ON_CRASH = 0x2 KEXEC_FILE_ON_CRASH = 0x2
KEXEC_FILE_UNLOAD = 0x1 KEXEC_FILE_UNLOAD = 0x1
@ -1794,8 +1785,6 @@ const (
LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20 LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20
LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000 LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000
LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2
LANDLOCK_ACCESS_NET_BIND_TCP = 0x1
LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2
LANDLOCK_CREATE_RULESET_VERSION = 0x1 LANDLOCK_CREATE_RULESET_VERSION = 0x1
LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_OFF = 0x0
LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef
@ -1907,7 +1896,6 @@ const (
MNT_DETACH = 0x2 MNT_DETACH = 0x2
MNT_EXPIRE = 0x4 MNT_EXPIRE = 0x4
MNT_FORCE = 0x1 MNT_FORCE = 0x1
MNT_ID_REQ_SIZE_VER0 = 0x18
MODULE_INIT_COMPRESSED_FILE = 0x4 MODULE_INIT_COMPRESSED_FILE = 0x4
MODULE_INIT_IGNORE_MODVERSIONS = 0x1 MODULE_INIT_IGNORE_MODVERSIONS = 0x1
MODULE_INIT_IGNORE_VERMAGIC = 0x2 MODULE_INIT_IGNORE_VERMAGIC = 0x2
@ -2139,60 +2127,6 @@ const (
NFNL_SUBSYS_QUEUE = 0x3 NFNL_SUBSYS_QUEUE = 0x3
NFNL_SUBSYS_ULOG = 0x4 NFNL_SUBSYS_ULOG = 0x4
NFS_SUPER_MAGIC = 0x6969 NFS_SUPER_MAGIC = 0x6969
NFT_CHAIN_FLAGS = 0x7
NFT_CHAIN_MAXNAMELEN = 0x100
NFT_CT_MAX = 0x17
NFT_DATA_RESERVED_MASK = 0xffffff00
NFT_DATA_VALUE_MAXLEN = 0x40
NFT_EXTHDR_OP_MAX = 0x4
NFT_FIB_RESULT_MAX = 0x3
NFT_INNER_MASK = 0xf
NFT_LOGLEVEL_MAX = 0x8
NFT_NAME_MAXLEN = 0x100
NFT_NG_MAX = 0x1
NFT_OBJECT_CONNLIMIT = 0x5
NFT_OBJECT_COUNTER = 0x1
NFT_OBJECT_CT_EXPECT = 0x9
NFT_OBJECT_CT_HELPER = 0x3
NFT_OBJECT_CT_TIMEOUT = 0x7
NFT_OBJECT_LIMIT = 0x4
NFT_OBJECT_MAX = 0xa
NFT_OBJECT_QUOTA = 0x2
NFT_OBJECT_SECMARK = 0x8
NFT_OBJECT_SYNPROXY = 0xa
NFT_OBJECT_TUNNEL = 0x6
NFT_OBJECT_UNSPEC = 0x0
NFT_OBJ_MAXNAMELEN = 0x100
NFT_OSF_MAXGENRELEN = 0x10
NFT_QUEUE_FLAG_BYPASS = 0x1
NFT_QUEUE_FLAG_CPU_FANOUT = 0x2
NFT_QUEUE_FLAG_MASK = 0x3
NFT_REG32_COUNT = 0x10
NFT_REG32_SIZE = 0x4
NFT_REG_MAX = 0x4
NFT_REG_SIZE = 0x10
NFT_REJECT_ICMPX_MAX = 0x3
NFT_RT_MAX = 0x4
NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x7
NFT_TABLE_MAXNAMELEN = 0x100
NFT_TRACETYPE_MAX = 0x3
NFT_TUNNEL_F_MASK = 0x7
NFT_TUNNEL_MAX = 0x1
NFT_TUNNEL_MODE_MAX = 0x2
NFT_USERDATA_MAXLEN = 0x100
NFT_XFRM_KEY_MAX = 0x6
NF_NAT_RANGE_MAP_IPS = 0x1
NF_NAT_RANGE_MASK = 0x7f
NF_NAT_RANGE_NETMAP = 0x40
NF_NAT_RANGE_PERSISTENT = 0x8
NF_NAT_RANGE_PROTO_OFFSET = 0x20
NF_NAT_RANGE_PROTO_RANDOM = 0x4
NF_NAT_RANGE_PROTO_RANDOM_ALL = 0x14
NF_NAT_RANGE_PROTO_RANDOM_FULLY = 0x10
NF_NAT_RANGE_PROTO_SPECIFIED = 0x2
NILFS_SUPER_MAGIC = 0x3434 NILFS_SUPER_MAGIC = 0x3434
NL0 = 0x0 NL0 = 0x0
NL1 = 0x100 NL1 = 0x100
@ -2312,7 +2246,6 @@ const (
PERF_AUX_FLAG_PARTIAL = 0x4 PERF_AUX_FLAG_PARTIAL = 0x4
PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK = 0xff00 PERF_AUX_FLAG_PMU_FORMAT_TYPE_MASK = 0xff00
PERF_AUX_FLAG_TRUNCATED = 0x1 PERF_AUX_FLAG_TRUNCATED = 0x1
PERF_BRANCH_ENTRY_INFO_BITS_MAX = 0x21
PERF_BR_ARM64_DEBUG_DATA = 0x7 PERF_BR_ARM64_DEBUG_DATA = 0x7
PERF_BR_ARM64_DEBUG_EXIT = 0x5 PERF_BR_ARM64_DEBUG_EXIT = 0x5
PERF_BR_ARM64_DEBUG_HALT = 0x4 PERF_BR_ARM64_DEBUG_HALT = 0x4
@ -2410,7 +2343,6 @@ const (
PERF_RECORD_MISC_USER = 0x2 PERF_RECORD_MISC_USER = 0x2
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7 PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000 PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
PID_FS_MAGIC = 0x50494446
PIPEFS_MAGIC = 0x50495045 PIPEFS_MAGIC = 0x50495045
PPPIOCGNPMODE = 0xc008744c PPPIOCGNPMODE = 0xc008744c
PPPIOCNEWUNIT = 0xc004743e PPPIOCNEWUNIT = 0xc004743e
@ -2479,7 +2411,6 @@ const (
PR_MCE_KILL_GET = 0x22 PR_MCE_KILL_GET = 0x22
PR_MCE_KILL_LATE = 0x0 PR_MCE_KILL_LATE = 0x0
PR_MCE_KILL_SET = 0x1 PR_MCE_KILL_SET = 0x1
PR_MDWE_NO_INHERIT = 0x2
PR_MDWE_REFUSE_EXEC_GAIN = 0x1 PR_MDWE_REFUSE_EXEC_GAIN = 0x1
PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_DISABLE_MANAGEMENT = 0x2c
PR_MPX_ENABLE_MANAGEMENT = 0x2b PR_MPX_ENABLE_MANAGEMENT = 0x2b
@ -2684,9 +2615,8 @@ const (
RTAX_FEATURES = 0xc RTAX_FEATURES = 0xc
RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ALLFRAG = 0x8
RTAX_FEATURE_ECN = 0x1 RTAX_FEATURE_ECN = 0x1
RTAX_FEATURE_MASK = 0x1f RTAX_FEATURE_MASK = 0xf
RTAX_FEATURE_SACK = 0x2 RTAX_FEATURE_SACK = 0x2
RTAX_FEATURE_TCP_USEC_TS = 0x10
RTAX_FEATURE_TIMESTAMP = 0x4 RTAX_FEATURE_TIMESTAMP = 0x4
RTAX_HOPLIMIT = 0xa RTAX_HOPLIMIT = 0xa
RTAX_INITCWND = 0xb RTAX_INITCWND = 0xb
@ -2904,9 +2834,8 @@ const (
RWF_APPEND = 0x10 RWF_APPEND = 0x10
RWF_DSYNC = 0x2 RWF_DSYNC = 0x2
RWF_HIPRI = 0x1 RWF_HIPRI = 0x1
RWF_NOAPPEND = 0x20
RWF_NOWAIT = 0x8 RWF_NOWAIT = 0x8
RWF_SUPPORTED = 0x3f RWF_SUPPORTED = 0x1f
RWF_SYNC = 0x4 RWF_SYNC = 0x4
RWF_WRITE_LIFE_NOT_SET = 0x0 RWF_WRITE_LIFE_NOT_SET = 0x0
SCHED_BATCH = 0x3 SCHED_BATCH = 0x3
@ -2927,43 +2856,12 @@ const (
SCHED_RESET_ON_FORK = 0x40000000 SCHED_RESET_ON_FORK = 0x40000000
SCHED_RR = 0x2 SCHED_RR = 0x2
SCM_CREDENTIALS = 0x2 SCM_CREDENTIALS = 0x2
SCM_PIDFD = 0x4
SCM_RIGHTS = 0x1 SCM_RIGHTS = 0x1
SCM_SECURITY = 0x3
SCM_TIMESTAMP = 0x1d SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000 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_DISABLED = 0x0
SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_FILTER = 0x2
SECCOMP_MODE_STRICT = 0x1 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 SECRETMEM_MAGIC = 0x5345434d
SECURITYFS_MAGIC = 0x73636673 SECURITYFS_MAGIC = 0x73636673
SEEK_CUR = 0x1 SEEK_CUR = 0x1
@ -3062,8 +2960,6 @@ const (
SIOCSMIIREG = 0x8949 SIOCSMIIREG = 0x8949
SIOCSRARP = 0x8962 SIOCSRARP = 0x8962
SIOCWANDEV = 0x894a SIOCWANDEV = 0x894a
SK_DIAG_BPF_STORAGE_MAX = 0x3
SK_DIAG_BPF_STORAGE_REQ_MAX = 0x1
SMACK_MAGIC = 0x43415d53 SMACK_MAGIC = 0x43415d53
SMART_AUTOSAVE = 0xd2 SMART_AUTOSAVE = 0xd2
SMART_AUTO_OFFLINE = 0xdb SMART_AUTO_OFFLINE = 0xdb
@ -3084,8 +2980,6 @@ const (
SOCKFS_MAGIC = 0x534f434b SOCKFS_MAGIC = 0x534f434b
SOCK_BUF_LOCK_MASK = 0x3 SOCK_BUF_LOCK_MASK = 0x3
SOCK_DCCP = 0x6 SOCK_DCCP = 0x6
SOCK_DESTROY = 0x15
SOCK_DIAG_BY_FAMILY = 0x14
SOCK_IOC_TYPE = 0x89 SOCK_IOC_TYPE = 0x89
SOCK_PACKET = 0xa SOCK_PACKET = 0xa
SOCK_RAW = 0x3 SOCK_RAW = 0x3
@ -3127,7 +3021,6 @@ const (
SOL_TIPC = 0x10f SOL_TIPC = 0x10f
SOL_TLS = 0x11a SOL_TLS = 0x11a
SOL_UDP = 0x11 SOL_UDP = 0x11
SOL_VSOCK = 0x11f
SOL_X25 = 0x106 SOL_X25 = 0x106
SOL_XDP = 0x11b SOL_XDP = 0x11b
SOMAXCONN = 0x1000 SOMAXCONN = 0x1000
@ -3187,7 +3080,6 @@ const (
STATX_GID = 0x10 STATX_GID = 0x10
STATX_INO = 0x100 STATX_INO = 0x100
STATX_MNT_ID = 0x1000 STATX_MNT_ID = 0x1000
STATX_MNT_ID_UNIQUE = 0x4000
STATX_MODE = 0x2 STATX_MODE = 0x2
STATX_MTIME = 0x40 STATX_MTIME = 0x40
STATX_NLINK = 0x4 STATX_NLINK = 0x4
@ -3275,7 +3167,6 @@ const (
TCP_MAX_WINSHIFT = 0xe TCP_MAX_WINSHIFT = 0xe
TCP_MD5SIG = 0xe TCP_MD5SIG = 0xe
TCP_MD5SIG_EXT = 0x20 TCP_MD5SIG_EXT = 0x20
TCP_MD5SIG_FLAG_IFINDEX = 0x2
TCP_MD5SIG_FLAG_PREFIX = 0x1 TCP_MD5SIG_FLAG_PREFIX = 0x1
TCP_MD5SIG_MAXKEYLEN = 0x50 TCP_MD5SIG_MAXKEYLEN = 0x50
TCP_MSS = 0x200 TCP_MSS = 0x200
@ -3583,16 +3474,12 @@ const (
XDP_RX_RING = 0x2 XDP_RX_RING = 0x2
XDP_SHARED_UMEM = 0x1 XDP_SHARED_UMEM = 0x1
XDP_STATISTICS = 0x7 XDP_STATISTICS = 0x7
XDP_TXMD_FLAGS_CHECKSUM = 0x2
XDP_TXMD_FLAGS_TIMESTAMP = 0x1
XDP_TX_METADATA = 0x2
XDP_TX_RING = 0x3 XDP_TX_RING = 0x3
XDP_UMEM_COMPLETION_RING = 0x6 XDP_UMEM_COMPLETION_RING = 0x6
XDP_UMEM_FILL_RING = 0x5 XDP_UMEM_FILL_RING = 0x5
XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000 XDP_UMEM_PGOFF_COMPLETION_RING = 0x180000000
XDP_UMEM_PGOFF_FILL_RING = 0x100000000 XDP_UMEM_PGOFF_FILL_RING = 0x100000000
XDP_UMEM_REG = 0x4 XDP_UMEM_REG = 0x4
XDP_UMEM_TX_SW_CSUM = 0x2
XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1 XDP_UMEM_UNALIGNED_CHUNK_FLAG = 0x1
XDP_USE_NEED_WAKEUP = 0x8 XDP_USE_NEED_WAKEUP = 0x8
XDP_USE_SG = 0x10 XDP_USE_SG = 0x10

View file

@ -118,7 +118,6 @@ const (
IXOFF = 0x1000 IXOFF = 0x1000
IXON = 0x400 IXON = 0x400
MAP_32BIT = 0x40 MAP_32BIT = 0x40
MAP_ABOVE4G = 0x80
MAP_ANON = 0x20 MAP_ANON = 0x20
MAP_ANONYMOUS = 0x20 MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800 MAP_DENYWRITE = 0x800
@ -282,9 +281,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -118,7 +118,6 @@ const (
IXOFF = 0x1000 IXOFF = 0x1000
IXON = 0x400 IXON = 0x400
MAP_32BIT = 0x40 MAP_32BIT = 0x40
MAP_ABOVE4G = 0x80
MAP_ANON = 0x20 MAP_ANON = 0x20
MAP_ANONYMOUS = 0x20 MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800 MAP_DENYWRITE = 0x800
@ -283,9 +282,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -288,9 +288,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -87,7 +87,6 @@ const (
FICLONE = 0x40049409 FICLONE = 0x40049409
FICLONERANGE = 0x4020940d FICLONERANGE = 0x4020940d
FLUSHO = 0x1000 FLUSHO = 0x1000
FPMR_MAGIC = 0x46504d52
FPSIMD_MAGIC = 0x46508001 FPSIMD_MAGIC = 0x46508001
FS_IOC_ENABLE_VERITY = 0x40806685 FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601 FS_IOC_GETFLAGS = 0x80086601
@ -279,9 +278,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -275,9 +275,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -281,9 +281,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View file

@ -281,9 +281,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View file

@ -281,9 +281,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View file

@ -281,9 +281,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x80 SFD_NONBLOCK = 0x80
SIOCATMARK = 0x40047307 SIOCATMARK = 0x40047307

View file

@ -336,9 +336,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

View file

@ -340,9 +340,6 @@ const (
SCM_TIMESTAMPNS = 0x23 SCM_TIMESTAMPNS = 0x23
SCM_TXTIME = 0x3d SCM_TXTIME = 0x3d
SCM_WIFI_STATUS = 0x29 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_CLOEXEC = 0x80000
SFD_NONBLOCK = 0x800 SFD_NONBLOCK = 0x800
SIOCATMARK = 0x8905 SIOCATMARK = 0x8905

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