Repository: datarhei/gosrt Branch: main Commit: 6ab34b20337a Files: 722 Total size: 9.4 MB Directory structure: gitextract_58kqutjt/ ├── .dockerignore ├── .editorconfig ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── codeql-analysis.yml │ └── go-tests.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── circular/ │ ├── circular.go │ └── circular_test.go ├── config.go ├── config_test.go ├── congestion/ │ ├── congestion.go │ └── live/ │ ├── doc.go │ ├── fake.go │ ├── receive.go │ ├── receive_test.go │ ├── send.go │ └── send_test.go ├── conn_request.go ├── connection.go ├── connection_test.go ├── contrib/ │ ├── client/ │ │ ├── main.go │ │ ├── reader.go │ │ └── writer.go │ └── server/ │ └── main.go ├── crypto/ │ ├── crypto.go │ └── crypto_test.go ├── dial.go ├── dial_test.go ├── doc.go ├── go.mod ├── go.sum ├── listen.go ├── listen_test.go ├── log.go ├── log_test.go ├── net/ │ ├── ip.go │ ├── ip_test.go │ ├── syncookie.go │ └── syncookie_test.go ├── net.go ├── net_windows.go ├── packet/ │ ├── packet.go │ └── packet_test.go ├── packet_conn.go ├── pubsub.go ├── pubsub_test.go ├── rand/ │ ├── rand.go │ └── rand_test.go ├── server.go ├── server_test.go ├── statistics.go └── vendor/ ├── github.com/ │ ├── benburkert/ │ │ └── openpgp/ │ │ └── aes/ │ │ └── keywrap/ │ │ ├── doc.go │ │ └── keywrap.go │ ├── davecgh/ │ │ └── go-spew/ │ │ ├── LICENSE │ │ └── spew/ │ │ ├── bypass.go │ │ ├── bypasssafe.go │ │ ├── common.go │ │ ├── config.go │ │ ├── doc.go │ │ ├── dump.go │ │ ├── format.go │ │ └── spew.go │ ├── felixge/ │ │ └── fgprof/ │ │ ├── BenchmarkProfilerGoroutines.txt │ │ ├── LICENSE.txt │ │ ├── README.md │ │ ├── fgprof.go │ │ └── handler.go │ ├── google/ │ │ └── pprof/ │ │ ├── AUTHORS │ │ ├── CONTRIBUTORS │ │ ├── LICENSE │ │ └── profile/ │ │ ├── encode.go │ │ ├── filter.go │ │ ├── index.go │ │ ├── legacy_java_profile.go │ │ ├── legacy_profile.go │ │ ├── merge.go │ │ ├── profile.go │ │ ├── proto.go │ │ └── prune.go │ ├── pkg/ │ │ └── profile/ │ │ ├── .travis.yml │ │ ├── AUTHORS │ │ ├── LICENSE │ │ ├── README.md │ │ └── profile.go │ ├── pmezard/ │ │ └── go-difflib/ │ │ ├── LICENSE │ │ └── difflib/ │ │ └── difflib.go │ └── stretchr/ │ └── testify/ │ ├── LICENSE │ ├── assert/ │ │ ├── assertion_compare.go │ │ ├── assertion_format.go │ │ ├── assertion_format.go.tmpl │ │ ├── assertion_forward.go │ │ ├── assertion_forward.go.tmpl │ │ ├── assertion_order.go │ │ ├── assertions.go │ │ ├── doc.go │ │ ├── errors.go │ │ ├── forward_assertions.go │ │ ├── http_assertions.go │ │ └── yaml/ │ │ ├── yaml_custom.go │ │ ├── yaml_default.go │ │ └── yaml_fail.go │ └── require/ │ ├── doc.go │ ├── forward_requirements.go │ ├── require.go │ ├── require.go.tmpl │ ├── require_forward.go │ ├── require_forward.go.tmpl │ └── requirements.go ├── golang.org/ │ └── x/ │ ├── net/ │ │ ├── LICENSE │ │ ├── PATENTS │ │ ├── bpf/ │ │ │ ├── asm.go │ │ │ ├── constants.go │ │ │ ├── doc.go │ │ │ ├── instructions.go │ │ │ ├── setter.go │ │ │ ├── vm.go │ │ │ └── vm_instructions.go │ │ ├── internal/ │ │ │ ├── iana/ │ │ │ │ └── const.go │ │ │ └── socket/ │ │ │ ├── cmsghdr.go │ │ │ ├── cmsghdr_bsd.go │ │ │ ├── cmsghdr_linux_32bit.go │ │ │ ├── cmsghdr_linux_64bit.go │ │ │ ├── cmsghdr_solaris_64bit.go │ │ │ ├── cmsghdr_stub.go │ │ │ ├── cmsghdr_unix.go │ │ │ ├── cmsghdr_zos_s390x.go │ │ │ ├── complete_dontwait.go │ │ │ ├── complete_nodontwait.go │ │ │ ├── empty.s │ │ │ ├── error_unix.go │ │ │ ├── error_windows.go │ │ │ ├── iovec_32bit.go │ │ │ ├── iovec_64bit.go │ │ │ ├── iovec_solaris_64bit.go │ │ │ ├── iovec_stub.go │ │ │ ├── mmsghdr_stub.go │ │ │ ├── mmsghdr_unix.go │ │ │ ├── msghdr_bsd.go │ │ │ ├── msghdr_bsdvar.go │ │ │ ├── msghdr_linux.go │ │ │ ├── msghdr_linux_32bit.go │ │ │ ├── msghdr_linux_64bit.go │ │ │ ├── msghdr_openbsd.go │ │ │ ├── msghdr_solaris_64bit.go │ │ │ ├── msghdr_stub.go │ │ │ ├── msghdr_zos_s390x.go │ │ │ ├── norace.go │ │ │ ├── race.go │ │ │ ├── rawconn.go │ │ │ ├── rawconn_mmsg.go │ │ │ ├── rawconn_msg.go │ │ │ ├── rawconn_nommsg.go │ │ │ ├── rawconn_nomsg.go │ │ │ ├── socket.go │ │ │ ├── sys_bsd.go │ │ │ ├── sys_const_unix.go │ │ │ ├── sys_linux.go │ │ │ ├── sys_linux_386.go │ │ │ ├── sys_linux_386.s │ │ │ ├── sys_linux_amd64.go │ │ │ ├── sys_linux_arm.go │ │ │ ├── sys_linux_arm64.go │ │ │ ├── sys_linux_loong64.go │ │ │ ├── sys_linux_mips.go │ │ │ ├── sys_linux_mips64.go │ │ │ ├── sys_linux_mips64le.go │ │ │ ├── sys_linux_mipsle.go │ │ │ ├── sys_linux_ppc.go │ │ │ ├── sys_linux_ppc64.go │ │ │ ├── sys_linux_ppc64le.go │ │ │ ├── sys_linux_riscv64.go │ │ │ ├── sys_linux_s390x.go │ │ │ ├── sys_linux_s390x.s │ │ │ ├── sys_netbsd.go │ │ │ ├── sys_posix.go │ │ │ ├── sys_stub.go │ │ │ ├── sys_unix.go │ │ │ ├── sys_windows.go │ │ │ ├── sys_zos_s390x.go │ │ │ ├── sys_zos_s390x.s │ │ │ ├── zsys_aix_ppc64.go │ │ │ ├── zsys_darwin_amd64.go │ │ │ ├── zsys_darwin_arm64.go │ │ │ ├── zsys_dragonfly_amd64.go │ │ │ ├── zsys_freebsd_386.go │ │ │ ├── zsys_freebsd_amd64.go │ │ │ ├── zsys_freebsd_arm.go │ │ │ ├── zsys_freebsd_arm64.go │ │ │ ├── zsys_freebsd_riscv64.go │ │ │ ├── zsys_linux_386.go │ │ │ ├── zsys_linux_amd64.go │ │ │ ├── zsys_linux_arm.go │ │ │ ├── zsys_linux_arm64.go │ │ │ ├── zsys_linux_loong64.go │ │ │ ├── zsys_linux_mips.go │ │ │ ├── zsys_linux_mips64.go │ │ │ ├── zsys_linux_mips64le.go │ │ │ ├── zsys_linux_mipsle.go │ │ │ ├── zsys_linux_ppc.go │ │ │ ├── zsys_linux_ppc64.go │ │ │ ├── zsys_linux_ppc64le.go │ │ │ ├── zsys_linux_riscv64.go │ │ │ ├── zsys_linux_s390x.go │ │ │ ├── zsys_netbsd_386.go │ │ │ ├── zsys_netbsd_amd64.go │ │ │ ├── zsys_netbsd_arm.go │ │ │ ├── zsys_netbsd_arm64.go │ │ │ ├── zsys_openbsd_386.go │ │ │ ├── zsys_openbsd_amd64.go │ │ │ ├── zsys_openbsd_arm.go │ │ │ ├── zsys_openbsd_arm64.go │ │ │ ├── zsys_openbsd_mips64.go │ │ │ ├── zsys_openbsd_ppc64.go │ │ │ ├── zsys_openbsd_riscv64.go │ │ │ ├── zsys_solaris_amd64.go │ │ │ └── zsys_zos_s390x.go │ │ ├── ipv4/ │ │ │ ├── batch.go │ │ │ ├── control.go │ │ │ ├── control_bsd.go │ │ │ ├── control_pktinfo.go │ │ │ ├── control_stub.go │ │ │ ├── control_unix.go │ │ │ ├── control_windows.go │ │ │ ├── control_zos.go │ │ │ ├── dgramopt.go │ │ │ ├── doc.go │ │ │ ├── endpoint.go │ │ │ ├── genericopt.go │ │ │ ├── header.go │ │ │ ├── helper.go │ │ │ ├── iana.go │ │ │ ├── icmp.go │ │ │ ├── icmp_linux.go │ │ │ ├── icmp_stub.go │ │ │ ├── packet.go │ │ │ ├── payload.go │ │ │ ├── payload_cmsg.go │ │ │ ├── payload_nocmsg.go │ │ │ ├── sockopt.go │ │ │ ├── sockopt_posix.go │ │ │ ├── sockopt_stub.go │ │ │ ├── sys_aix.go │ │ │ ├── sys_asmreq.go │ │ │ ├── sys_asmreq_stub.go │ │ │ ├── sys_asmreqn.go │ │ │ ├── sys_asmreqn_stub.go │ │ │ ├── sys_bpf.go │ │ │ ├── sys_bpf_stub.go │ │ │ ├── sys_bsd.go │ │ │ ├── sys_darwin.go │ │ │ ├── sys_dragonfly.go │ │ │ ├── sys_freebsd.go │ │ │ ├── sys_linux.go │ │ │ ├── sys_solaris.go │ │ │ ├── sys_ssmreq.go │ │ │ ├── sys_ssmreq_stub.go │ │ │ ├── sys_stub.go │ │ │ ├── sys_windows.go │ │ │ ├── sys_zos.go │ │ │ ├── zsys_aix_ppc64.go │ │ │ ├── zsys_darwin.go │ │ │ ├── zsys_dragonfly.go │ │ │ ├── zsys_freebsd_386.go │ │ │ ├── zsys_freebsd_amd64.go │ │ │ ├── zsys_freebsd_arm.go │ │ │ ├── zsys_freebsd_arm64.go │ │ │ ├── zsys_freebsd_riscv64.go │ │ │ ├── zsys_linux_386.go │ │ │ ├── zsys_linux_amd64.go │ │ │ ├── zsys_linux_arm.go │ │ │ ├── zsys_linux_arm64.go │ │ │ ├── zsys_linux_loong64.go │ │ │ ├── zsys_linux_mips.go │ │ │ ├── zsys_linux_mips64.go │ │ │ ├── zsys_linux_mips64le.go │ │ │ ├── zsys_linux_mipsle.go │ │ │ ├── zsys_linux_ppc.go │ │ │ ├── zsys_linux_ppc64.go │ │ │ ├── zsys_linux_ppc64le.go │ │ │ ├── zsys_linux_riscv64.go │ │ │ ├── zsys_linux_s390x.go │ │ │ ├── zsys_netbsd.go │ │ │ ├── zsys_openbsd.go │ │ │ ├── zsys_solaris.go │ │ │ └── zsys_zos_s390x.go │ │ └── ipv6/ │ │ ├── batch.go │ │ ├── control.go │ │ ├── control_rfc2292_unix.go │ │ ├── control_rfc3542_unix.go │ │ ├── control_stub.go │ │ ├── control_unix.go │ │ ├── control_windows.go │ │ ├── dgramopt.go │ │ ├── doc.go │ │ ├── endpoint.go │ │ ├── genericopt.go │ │ ├── header.go │ │ ├── helper.go │ │ ├── iana.go │ │ ├── icmp.go │ │ ├── icmp_bsd.go │ │ ├── icmp_linux.go │ │ ├── icmp_solaris.go │ │ ├── icmp_stub.go │ │ ├── icmp_windows.go │ │ ├── icmp_zos.go │ │ ├── payload.go │ │ ├── payload_cmsg.go │ │ ├── payload_nocmsg.go │ │ ├── sockopt.go │ │ ├── sockopt_posix.go │ │ ├── sockopt_stub.go │ │ ├── sys_aix.go │ │ ├── sys_asmreq.go │ │ ├── sys_asmreq_stub.go │ │ ├── sys_bpf.go │ │ ├── sys_bpf_stub.go │ │ ├── sys_bsd.go │ │ ├── sys_darwin.go │ │ ├── sys_freebsd.go │ │ ├── sys_linux.go │ │ ├── sys_solaris.go │ │ ├── sys_ssmreq.go │ │ ├── sys_ssmreq_stub.go │ │ ├── sys_stub.go │ │ ├── sys_windows.go │ │ ├── sys_zos.go │ │ ├── zsys_aix_ppc64.go │ │ ├── zsys_darwin.go │ │ ├── zsys_dragonfly.go │ │ ├── zsys_freebsd_386.go │ │ ├── zsys_freebsd_amd64.go │ │ ├── zsys_freebsd_arm.go │ │ ├── zsys_freebsd_arm64.go │ │ ├── zsys_freebsd_riscv64.go │ │ ├── zsys_linux_386.go │ │ ├── zsys_linux_amd64.go │ │ ├── zsys_linux_arm.go │ │ ├── zsys_linux_arm64.go │ │ ├── zsys_linux_loong64.go │ │ ├── zsys_linux_mips.go │ │ ├── zsys_linux_mips64.go │ │ ├── zsys_linux_mips64le.go │ │ ├── zsys_linux_mipsle.go │ │ ├── zsys_linux_ppc.go │ │ ├── zsys_linux_ppc64.go │ │ ├── zsys_linux_ppc64le.go │ │ ├── zsys_linux_riscv64.go │ │ ├── zsys_linux_s390x.go │ │ ├── zsys_netbsd.go │ │ ├── zsys_openbsd.go │ │ ├── zsys_solaris.go │ │ └── zsys_zos_s390x.go │ └── sys/ │ ├── LICENSE │ ├── PATENTS │ ├── unix/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── affinity_linux.go │ │ ├── aliases.go │ │ ├── asm_aix_ppc64.s │ │ ├── asm_bsd_386.s │ │ ├── asm_bsd_amd64.s │ │ ├── asm_bsd_arm.s │ │ ├── asm_bsd_arm64.s │ │ ├── asm_bsd_ppc64.s │ │ ├── asm_bsd_riscv64.s │ │ ├── asm_linux_386.s │ │ ├── asm_linux_amd64.s │ │ ├── asm_linux_arm.s │ │ ├── asm_linux_arm64.s │ │ ├── asm_linux_loong64.s │ │ ├── asm_linux_mips64x.s │ │ ├── asm_linux_mipsx.s │ │ ├── asm_linux_ppc64x.s │ │ ├── asm_linux_riscv64.s │ │ ├── asm_linux_s390x.s │ │ ├── asm_openbsd_mips64.s │ │ ├── asm_solaris_amd64.s │ │ ├── asm_zos_s390x.s │ │ ├── auxv.go │ │ ├── auxv_unsupported.go │ │ ├── bluetooth_linux.go │ │ ├── bpxsvc_zos.go │ │ ├── bpxsvc_zos.s │ │ ├── cap_freebsd.go │ │ ├── constants.go │ │ ├── dev_aix_ppc.go │ │ ├── dev_aix_ppc64.go │ │ ├── dev_darwin.go │ │ ├── dev_dragonfly.go │ │ ├── dev_freebsd.go │ │ ├── dev_linux.go │ │ ├── dev_netbsd.go │ │ ├── dev_openbsd.go │ │ ├── dev_zos.go │ │ ├── dirent.go │ │ ├── endian_big.go │ │ ├── endian_little.go │ │ ├── env_unix.go │ │ ├── fcntl.go │ │ ├── fcntl_darwin.go │ │ ├── fcntl_linux_32bit.go │ │ ├── fdset.go │ │ ├── gccgo.go │ │ ├── gccgo_c.c │ │ ├── gccgo_linux_amd64.go │ │ ├── ifreq_linux.go │ │ ├── ioctl_linux.go │ │ ├── ioctl_signed.go │ │ ├── ioctl_unsigned.go │ │ ├── ioctl_zos.go │ │ ├── mkall.sh │ │ ├── mkerrors.sh │ │ ├── mmap_nomremap.go │ │ ├── mremap.go │ │ ├── pagesize_unix.go │ │ ├── pledge_openbsd.go │ │ ├── ptrace_darwin.go │ │ ├── ptrace_ios.go │ │ ├── race.go │ │ ├── race0.go │ │ ├── readdirent_getdents.go │ │ ├── readdirent_getdirentries.go │ │ ├── sockcmsg_dragonfly.go │ │ ├── sockcmsg_linux.go │ │ ├── sockcmsg_unix.go │ │ ├── sockcmsg_unix_other.go │ │ ├── sockcmsg_zos.go │ │ ├── symaddr_zos_s390x.s │ │ ├── syscall.go │ │ ├── syscall_aix.go │ │ ├── syscall_aix_ppc.go │ │ ├── syscall_aix_ppc64.go │ │ ├── syscall_bsd.go │ │ ├── syscall_darwin.go │ │ ├── syscall_darwin_amd64.go │ │ ├── syscall_darwin_arm64.go │ │ ├── syscall_darwin_libSystem.go │ │ ├── syscall_dragonfly.go │ │ ├── syscall_dragonfly_amd64.go │ │ ├── syscall_freebsd.go │ │ ├── syscall_freebsd_386.go │ │ ├── syscall_freebsd_amd64.go │ │ ├── syscall_freebsd_arm.go │ │ ├── syscall_freebsd_arm64.go │ │ ├── syscall_freebsd_riscv64.go │ │ ├── syscall_hurd.go │ │ ├── syscall_hurd_386.go │ │ ├── syscall_illumos.go │ │ ├── syscall_linux.go │ │ ├── syscall_linux_386.go │ │ ├── syscall_linux_alarm.go │ │ ├── syscall_linux_amd64.go │ │ ├── syscall_linux_amd64_gc.go │ │ ├── syscall_linux_arm.go │ │ ├── syscall_linux_arm64.go │ │ ├── syscall_linux_gc.go │ │ ├── syscall_linux_gc_386.go │ │ ├── syscall_linux_gc_arm.go │ │ ├── syscall_linux_gccgo_386.go │ │ ├── syscall_linux_gccgo_arm.go │ │ ├── syscall_linux_loong64.go │ │ ├── syscall_linux_mips64x.go │ │ ├── syscall_linux_mipsx.go │ │ ├── syscall_linux_ppc.go │ │ ├── syscall_linux_ppc64x.go │ │ ├── syscall_linux_riscv64.go │ │ ├── syscall_linux_s390x.go │ │ ├── syscall_linux_sparc64.go │ │ ├── syscall_netbsd.go │ │ ├── syscall_netbsd_386.go │ │ ├── syscall_netbsd_amd64.go │ │ ├── syscall_netbsd_arm.go │ │ ├── syscall_netbsd_arm64.go │ │ ├── syscall_openbsd.go │ │ ├── syscall_openbsd_386.go │ │ ├── syscall_openbsd_amd64.go │ │ ├── syscall_openbsd_arm.go │ │ ├── syscall_openbsd_arm64.go │ │ ├── syscall_openbsd_libc.go │ │ ├── syscall_openbsd_mips64.go │ │ ├── syscall_openbsd_ppc64.go │ │ ├── syscall_openbsd_riscv64.go │ │ ├── syscall_solaris.go │ │ ├── syscall_solaris_amd64.go │ │ ├── syscall_unix.go │ │ ├── syscall_unix_gc.go │ │ ├── syscall_unix_gc_ppc64x.go │ │ ├── syscall_zos_s390x.go │ │ ├── sysvshm_linux.go │ │ ├── sysvshm_unix.go │ │ ├── sysvshm_unix_other.go │ │ ├── timestruct.go │ │ ├── unveil_openbsd.go │ │ ├── vgetrandom_linux.go │ │ ├── vgetrandom_unsupported.go │ │ ├── xattr_bsd.go │ │ ├── zerrors_aix_ppc.go │ │ ├── zerrors_aix_ppc64.go │ │ ├── zerrors_darwin_amd64.go │ │ ├── zerrors_darwin_arm64.go │ │ ├── zerrors_dragonfly_amd64.go │ │ ├── zerrors_freebsd_386.go │ │ ├── zerrors_freebsd_amd64.go │ │ ├── zerrors_freebsd_arm.go │ │ ├── zerrors_freebsd_arm64.go │ │ ├── zerrors_freebsd_riscv64.go │ │ ├── zerrors_linux.go │ │ ├── zerrors_linux_386.go │ │ ├── zerrors_linux_amd64.go │ │ ├── zerrors_linux_arm.go │ │ ├── zerrors_linux_arm64.go │ │ ├── zerrors_linux_loong64.go │ │ ├── zerrors_linux_mips.go │ │ ├── zerrors_linux_mips64.go │ │ ├── zerrors_linux_mips64le.go │ │ ├── zerrors_linux_mipsle.go │ │ ├── zerrors_linux_ppc.go │ │ ├── zerrors_linux_ppc64.go │ │ ├── zerrors_linux_ppc64le.go │ │ ├── zerrors_linux_riscv64.go │ │ ├── zerrors_linux_s390x.go │ │ ├── zerrors_linux_sparc64.go │ │ ├── zerrors_netbsd_386.go │ │ ├── zerrors_netbsd_amd64.go │ │ ├── zerrors_netbsd_arm.go │ │ ├── zerrors_netbsd_arm64.go │ │ ├── zerrors_openbsd_386.go │ │ ├── zerrors_openbsd_amd64.go │ │ ├── zerrors_openbsd_arm.go │ │ ├── zerrors_openbsd_arm64.go │ │ ├── zerrors_openbsd_mips64.go │ │ ├── zerrors_openbsd_ppc64.go │ │ ├── zerrors_openbsd_riscv64.go │ │ ├── zerrors_solaris_amd64.go │ │ ├── zerrors_zos_s390x.go │ │ ├── zptrace_armnn_linux.go │ │ ├── zptrace_linux_arm64.go │ │ ├── zptrace_mipsnn_linux.go │ │ ├── zptrace_mipsnnle_linux.go │ │ ├── zptrace_x86_linux.go │ │ ├── zsymaddr_zos_s390x.s │ │ ├── zsyscall_aix_ppc.go │ │ ├── zsyscall_aix_ppc64.go │ │ ├── zsyscall_aix_ppc64_gc.go │ │ ├── zsyscall_aix_ppc64_gccgo.go │ │ ├── zsyscall_darwin_amd64.go │ │ ├── zsyscall_darwin_amd64.s │ │ ├── zsyscall_darwin_arm64.go │ │ ├── zsyscall_darwin_arm64.s │ │ ├── zsyscall_dragonfly_amd64.go │ │ ├── zsyscall_freebsd_386.go │ │ ├── zsyscall_freebsd_amd64.go │ │ ├── zsyscall_freebsd_arm.go │ │ ├── zsyscall_freebsd_arm64.go │ │ ├── zsyscall_freebsd_riscv64.go │ │ ├── zsyscall_illumos_amd64.go │ │ ├── zsyscall_linux.go │ │ ├── zsyscall_linux_386.go │ │ ├── zsyscall_linux_amd64.go │ │ ├── zsyscall_linux_arm.go │ │ ├── zsyscall_linux_arm64.go │ │ ├── zsyscall_linux_loong64.go │ │ ├── zsyscall_linux_mips.go │ │ ├── zsyscall_linux_mips64.go │ │ ├── zsyscall_linux_mips64le.go │ │ ├── zsyscall_linux_mipsle.go │ │ ├── zsyscall_linux_ppc.go │ │ ├── zsyscall_linux_ppc64.go │ │ ├── zsyscall_linux_ppc64le.go │ │ ├── zsyscall_linux_riscv64.go │ │ ├── zsyscall_linux_s390x.go │ │ ├── zsyscall_linux_sparc64.go │ │ ├── zsyscall_netbsd_386.go │ │ ├── zsyscall_netbsd_amd64.go │ │ ├── zsyscall_netbsd_arm.go │ │ ├── zsyscall_netbsd_arm64.go │ │ ├── zsyscall_openbsd_386.go │ │ ├── zsyscall_openbsd_386.s │ │ ├── zsyscall_openbsd_amd64.go │ │ ├── zsyscall_openbsd_amd64.s │ │ ├── zsyscall_openbsd_arm.go │ │ ├── zsyscall_openbsd_arm.s │ │ ├── zsyscall_openbsd_arm64.go │ │ ├── zsyscall_openbsd_arm64.s │ │ ├── zsyscall_openbsd_mips64.go │ │ ├── zsyscall_openbsd_mips64.s │ │ ├── zsyscall_openbsd_ppc64.go │ │ ├── zsyscall_openbsd_ppc64.s │ │ ├── zsyscall_openbsd_riscv64.go │ │ ├── zsyscall_openbsd_riscv64.s │ │ ├── zsyscall_solaris_amd64.go │ │ ├── zsyscall_zos_s390x.go │ │ ├── zsysctl_openbsd_386.go │ │ ├── zsysctl_openbsd_amd64.go │ │ ├── zsysctl_openbsd_arm.go │ │ ├── zsysctl_openbsd_arm64.go │ │ ├── zsysctl_openbsd_mips64.go │ │ ├── zsysctl_openbsd_ppc64.go │ │ ├── zsysctl_openbsd_riscv64.go │ │ ├── zsysnum_darwin_amd64.go │ │ ├── zsysnum_darwin_arm64.go │ │ ├── zsysnum_dragonfly_amd64.go │ │ ├── zsysnum_freebsd_386.go │ │ ├── zsysnum_freebsd_amd64.go │ │ ├── zsysnum_freebsd_arm.go │ │ ├── zsysnum_freebsd_arm64.go │ │ ├── zsysnum_freebsd_riscv64.go │ │ ├── zsysnum_linux_386.go │ │ ├── zsysnum_linux_amd64.go │ │ ├── zsysnum_linux_arm.go │ │ ├── zsysnum_linux_arm64.go │ │ ├── zsysnum_linux_loong64.go │ │ ├── zsysnum_linux_mips.go │ │ ├── zsysnum_linux_mips64.go │ │ ├── zsysnum_linux_mips64le.go │ │ ├── zsysnum_linux_mipsle.go │ │ ├── zsysnum_linux_ppc.go │ │ ├── zsysnum_linux_ppc64.go │ │ ├── zsysnum_linux_ppc64le.go │ │ ├── zsysnum_linux_riscv64.go │ │ ├── zsysnum_linux_s390x.go │ │ ├── zsysnum_linux_sparc64.go │ │ ├── zsysnum_netbsd_386.go │ │ ├── zsysnum_netbsd_amd64.go │ │ ├── zsysnum_netbsd_arm.go │ │ ├── zsysnum_netbsd_arm64.go │ │ ├── zsysnum_openbsd_386.go │ │ ├── zsysnum_openbsd_amd64.go │ │ ├── zsysnum_openbsd_arm.go │ │ ├── zsysnum_openbsd_arm64.go │ │ ├── zsysnum_openbsd_mips64.go │ │ ├── zsysnum_openbsd_ppc64.go │ │ ├── zsysnum_openbsd_riscv64.go │ │ ├── zsysnum_zos_s390x.go │ │ ├── ztypes_aix_ppc.go │ │ ├── ztypes_aix_ppc64.go │ │ ├── ztypes_darwin_amd64.go │ │ ├── ztypes_darwin_arm64.go │ │ ├── ztypes_dragonfly_amd64.go │ │ ├── ztypes_freebsd_386.go │ │ ├── ztypes_freebsd_amd64.go │ │ ├── ztypes_freebsd_arm.go │ │ ├── ztypes_freebsd_arm64.go │ │ ├── ztypes_freebsd_riscv64.go │ │ ├── ztypes_linux.go │ │ ├── ztypes_linux_386.go │ │ ├── ztypes_linux_amd64.go │ │ ├── ztypes_linux_arm.go │ │ ├── ztypes_linux_arm64.go │ │ ├── ztypes_linux_loong64.go │ │ ├── ztypes_linux_mips.go │ │ ├── ztypes_linux_mips64.go │ │ ├── ztypes_linux_mips64le.go │ │ ├── ztypes_linux_mipsle.go │ │ ├── ztypes_linux_ppc.go │ │ ├── ztypes_linux_ppc64.go │ │ ├── ztypes_linux_ppc64le.go │ │ ├── ztypes_linux_riscv64.go │ │ ├── ztypes_linux_s390x.go │ │ ├── ztypes_linux_sparc64.go │ │ ├── ztypes_netbsd_386.go │ │ ├── ztypes_netbsd_amd64.go │ │ ├── ztypes_netbsd_arm.go │ │ ├── ztypes_netbsd_arm64.go │ │ ├── ztypes_openbsd_386.go │ │ ├── ztypes_openbsd_amd64.go │ │ ├── ztypes_openbsd_arm.go │ │ ├── ztypes_openbsd_arm64.go │ │ ├── ztypes_openbsd_mips64.go │ │ ├── ztypes_openbsd_ppc64.go │ │ ├── ztypes_openbsd_riscv64.go │ │ ├── ztypes_solaris_amd64.go │ │ └── ztypes_zos_s390x.go │ └── windows/ │ ├── aliases.go │ ├── dll_windows.go │ ├── env_windows.go │ ├── eventlog.go │ ├── exec_windows.go │ ├── memory_windows.go │ ├── mkerrors.bash │ ├── mkknownfolderids.bash │ ├── mksyscall.go │ ├── race.go │ ├── race0.go │ ├── security_windows.go │ ├── service.go │ ├── setupapi_windows.go │ ├── str.go │ ├── syscall.go │ ├── syscall_windows.go │ ├── types_windows.go │ ├── types_windows_386.go │ ├── types_windows_amd64.go │ ├── types_windows_arm.go │ ├── types_windows_arm64.go │ ├── zerrors_windows.go │ ├── zknownfolderids_windows.go │ └── zsyscall_windows.go ├── gopkg.in/ │ └── yaml.v3/ │ ├── LICENSE │ ├── NOTICE │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── emitterc.go │ ├── encode.go │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go └── modules.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ Dockerfile /.git ================================================ FILE: .editorconfig ================================================ # For more information about the properties used in # this file, please see the EditorConfig documentation: # http://editorconfig.org/ root = true [*] charset = utf-8 end_of_line = lf indent_size = 4 indent_style = tab insert_final_newline = true trim_trailing_whitespace = true spaces_around_brackets = outside [*.md] trim_trailing_whitespace = false indent_style = space [*.patch] indent_style = space ================================================ FILE: .github/dependabot.yml ================================================ version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "daily" ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: ["main"] pull_request: # The branches below must be a subset of the branches above branches: ["main"] schedule: - cron: "32 23 * * 2" jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: ["go"] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v4 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # - run: | # echo "Run, Build Application using script" # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 ================================================ FILE: .github/workflows/go-tests.yml ================================================ name: tests on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 2 - uses: actions/setup-go@v6 with: go-version: "1.25" - name: Run coverage run: go test -coverprofile=coverage.out -covermode=atomic -race -v ./... - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage.out flags: unit-linux ================================================ FILE: .gitignore ================================================ /contrib/server/server* /contrib/client/client* *.prof *.out *.html *.ts *.mp4 ================================================ FILE: CODE_OF_CONDUCT.md ================================================ Contributor Code of Conduct =========================== As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. Examples of unacceptable behavior by participants include: - Sexual language or imagery. - Derogatory comments or personal attacks. - Trolling, public or private harassment. - Insults. - Other unprofessional conduct. Examples of unacceptable behavior by participants include sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct. In addition, project maintainers who do not follow the Code of Conduct may be removed from the project team. This code of conduct applies both within a project and in public spaces when an individual represents the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org/), version 1.1.0, available at [https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/) ================================================ FILE: Dockerfile ================================================ ARG BUILD_IMAGE=golang:1.25-alpine FROM $BUILD_IMAGE AS builder COPY . /build RUN cd /build/contrib/client && CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -o client . RUN cd /build/contrib/server && CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -o server . FROM scratch COPY --from=builder /build/contrib/client/client /bin/srt-client COPY --from=builder /build/contrib/server/server /bin/srt-server WORKDIR /srt ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020-2022 FOSS GmbH Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ COMMIT := $(shell if [ -d .git ]; then git rev-parse HEAD; else echo "unknown"; fi) SHORTCOMMIT := $(shell echo $(COMMIT) | head -c 7) all: build ## test: Run all tests test: go test -race -coverprofile=/dev/null -covermode=atomic -v ./... ## fuzz: Run fuzz tests fuzz: go test -fuzz=Fuzz -run=^Fuzz ./packet -fuzztime 30s ## vet: Analyze code for potential errors vet: go vet ./... ## fmt: Format code fmt: go fmt ./... ## update: Update dependencies update: go get -u -t @-$(MAKE) tidy @-$(MAKE) vendor ## tidy: Tidy up go.mod tidy: go mod tidy ## vendor: Update vendored packages vendor: go mod vendor ## lint: Static analysis with staticcheck lint: staticcheck ./... ## client: Build import binary client: cd contrib/client && CGO_ENABLED=0 go build -o client -ldflags="-s -w" -a ## server: Build import binary server: cd contrib/server && CGO_ENABLED=0 go build -o server -ldflags="-s -w" -a ## coverage: Generate code coverage analysis coverage: go test -race -coverprofile=cover.out -timeout 60s -v ./... go tool cover -html=cover.out -o cover.html ## commit: Prepare code for commit (vet, fmt, test) commit: vet fmt lint test @echo "No errors found. Ready for a commit." ## docker: Build standard Docker image docker: docker build -t gosrt:$(SHORTCOMMIT) . ## logtopics: Extract all logging topics logtopics: grep -ERho 'log\("([^"]+)' *.go | sed -E -e 's/log\("//' | sort -u .PHONY: help test fuzz vet fmt vendor commit coverage lint client server update logtopics ## help: Show all commands help: Makefile @echo @echo " Choose a command:" @echo @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' @echo ================================================ FILE: README.md ================================================ # GoSRT Implementation of the SRT protocol in pure Go with minimal dependencies.
[](https://opensource.org/licenses/MIT)  [](https://codecov.io/gh/datarhei/gosrt) [](https://goreportcard.com/report/github.com/datarhei/gosrt) [](https://pkg.go.dev/github.com/datarhei/gosrt) - [SRT reference implementation](https://github.com/Haivision/srt) - [SRT RFC](https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html) - [SRT Technical Overview](https://github.com/Haivision/srt/files/2489142/SRT_Protocol_TechnicalOverview_DRAFT_2018-10-17.pdf) ## Implementations This implementation of the SRT protocol has live streaming of video/audio in mind. Because of this, the buffer mode and File Transfer Congestion Control (FileCC) are not implemented. | | | | --- | ----------------------------------------- | | ✅ | Handshake v4 and v5 | | ✅ | Message mode | | ✅ | Caller-Listener Handshake | | ✅ | Timestamp-Based Packet Delivery (TSBPD) | | ✅ | Too-Late Packet Drop (TLPKTDROP) | | ✅ | Live Congestion Control (LiveCC) | | ✅ | NAK and Peridoc NAK | | ✅ | Encryption | | ❌ | Buffer mode | | ❌ | Rendezvous Handshake | | ❌ | File Transfer Congestion Control (FileCC) | | ❌ | Connection Bonding | The parts that are implemented are based on what has been published in the SRT RFC. ## Requirements A Go version of 1.20+ is required. ## Installation ```shell go get github.com/datarhei/gosrt ``` ## Caller example ```go import "github.com/datarhei/gosrt" conn, err := srt.Dial("srt", "golang.org:6000", srt.Config{ StreamId: "...", }) if err != nil { // handle error } buffer := make([]byte, 2048) for { n, err := conn.Read(buffer) if err != nil { // handle error } // handle received data } conn.Close() ``` In the `contrib/client` directory you'll find a complete example of a SRT client. ## Listener example ```go import "github.com/datarhei/gosrt" ln, err := srt.Listen("srt", ":6000", srt.Config{...}) if err != nil { // handle error } for { req, err := ln.Accept2() if err != nil { // handle error } go func(req ConnRequest) { // check connection request by inspecting the connection request // and either rejecting it ... if somethingIsWrong { req.Reject(srt.REJ_PEER) return } // ... or accepting it ... conn, err := req.Accept() if err != nil { return } // ... and decide whether it is a publishing or subscribing connection. if publish { handlePublish(conn) } else { handleSubscribe(conn) } }(req) } ``` In the `contrib/server` directory you'll find a complete example of a SRT server. For your convenience this module provides the `Server` type which is a light framework for creating your own SRT server. The example server is based on this type. ## Contributed client In the `contrib/client` directory you'll find an example implementation of a SRT client. Build the client application with ```shell cd contrib/client && go build ``` The application requires only two options: | Option | Description | | ------- | -------------------- | | `-from` | Address to read from | | `-to` | Address to write to | Both options accept an address. Valid addresses are: `-` for `stdin`, resp. `stdout`, a `srt://` address, or an `udp://` address. ### SRT URL A SRT URL is of the form `srt://[host]:[port]/?[options]` where options are in the form of a `HTTP` query string. These are the known options (similar to [srt-live-transmit](https://github.com/Haivision/srt/blob/master/docs/apps/srt-live-transmit.md)): | Option | Values | Description | | -------------------- | ---------------------- | ----------------------------------------------------------------------- | | `mode` | `listener` or `caller` | Enforce listener or caller mode. | | `congestion` | `live` | Congestion control. Currently only `live` is supported. | | `conntimeo` | `ms` | Connection timeout. | | `drifttracer` | `bool` | Enable drift tracer. Not implemented. | | `enforcedencryption` | `bool` | Accept connection only if both parties have encryption enabled. | | `fc` | `bytes` | Flow control window size. | | `inputbw` | `bytes` | Input bandwidth. Ignored. | | `iptos` | 0...255 | IP socket type of service. Broken. | | `ipttl` | 1...255 | Defines IP socket "time to live" option. Broken. | | `ipv6only` | `bool` | Use IPv6 only. Not implemented. | | `kmpreannounce` | `packets` | Duration of Stream Encryption key switchover. | | `kmrefreshrate` | `packets` | Stream encryption key refresh rate. | | `latency` | `ms` | Maximum accepted transmission latency. | | `lossmaxttl` | `ms` | Packet reorder tolerance. Not implemented. | | `maxbw` | `bytes` | Bandwidth limit. Ignored. | | `mininputbw` | `bytes` | Minimum allowed estimate of `inputbw`. | | `messageapi` | `bool` | Enable SRT message mode. Must be `false`. | | `mss` | 76... | MTU size. | | `nakreport` | `bool` | Enable periodic NAK reports. | | `oheadbw` | 10...100 | Limits bandwidth overhead. Percents. Ignored. | | `packetfilter` | `string` | Set up the packet filter. Not implemented. | | `passphrase` | `string` | Password for the encrypted transmission. | | `payloadsize` | `bytes` | Maximum payload size. | | `pbkeylen` | `16`, `24`, or `32` | Crypto key length in bytes. | | `peeridletimeo` | `ms` | Peer idle timeout. | | `peerlatency` | `ms` | Minimum receiver latency to be requested by sender. | | `rcvbuf` | `bytes` | Receiver buffer size. | | `rcvlatency` | `ms` | Receiver-side latency. | | `sndbuf` | `bytes` | Sender buffer size. | | `snddropdelay` | `ms` | Sender's delay before dropping packets. | | `streamid` | `string` | Stream ID (settable in caller mode only, visible on the listener peer). | | `tlpktdrop` | `bool` | Drop too late packets. | | `transtype` | `live` | Transmission type. Must be `live`. | | `tsbpdmode` | `bool` | Enable timestamp-based packet delivery mode. | ### Usage Reading from a SRT sender and play with `ffplay`: ```shell ./client -from "srt://127.0.0.1:6001/?mode=listener&streamid=..." -to - | ffplay -f mpegts -i - ``` Reading from UDP and sending to a SRT server: ```shell ./client -from udp://:6000 -to "srt://127.0.0.1:6001/?mode=caller&streamid=..." ``` Simulate point-to-point transfer on localhost. Open one console and start `ffmpeg` (you need at least version 4.3.2, built with SRT enabled) to send to an UDP address: ```shell ffmpeg \ -f lavfi \ -re \ -i testsrc2=rate=25:size=640x360 \ -codec:v libx264 \ -b:v 1024k \ -maxrate:v 1024k \ -bufsize:v 1024k \ -preset ultrafast \ -r 25 \ -g 50 \ -pix_fmt yuv420p \ -flags2 local_header \ -f mpegts \ "udp://127.0.0.1:6000?pkt_size=1316" ``` In another console read from the UDP and start a SRT listenr: ```shell ./client -from udp://:6000 -to "srt://127.0.0.1:6001/?mode=listener&streamid=foobar" ``` In the third console connect to that stream and play the video with `ffplay`: ```shell ./client -from "srt://127.0.0.1:6001/?mode=caller&streamid=foobar" -to - | ffplay -f mpegts -i - ``` ## Contributed server In the `contrib/server` directory you'll find an example implementation of a SRT server. This server allows you to publish a stream that can be read by many clients. Build the client application with ```shell cd contrib/server && go build ``` The application has these options: | Option | Default | Description | | ------------- | --------- | ------------------------------------------ | | `-addr` | required | Address to listen on | | `-app` | `/` | Path prefix for streamid | | `-token` | (not set) | Token query param for streamid | | `-passphrase` | (not set) | Passphrase for de- and enrcypting the data | | `-logtopics` | (not set) | Topics for the log output | | `-profile` | `false` | Enable profiling | This example server expects the streamID (without any prefix) to be an URL path with optional query parameter, e.g. `/live/stream`. If the `-app` option is used, then the path must start with that path, e.g. the value is `/live` then the streamID must start with that value. The `-token` option can be used to define a token for that stream as some kind of access control, e.g. with `-token foobar` the streamID might look like `/live/stream?token=foobar`. Use `-passphrase` in order to enable and enforce encryption. Use `-logtopics` in order to write debug output. The value are a comma separated list of topics you want to be written to `stderr`, e.g. `connection,listen`. Check the [Logging](#logging) section in order to find out more about the different topics. Use `-profile` in order to write a CPU profile. ### StreamID In SRT the StreamID is used to transport somewhat arbitrary information from the caller to the listener. The provided example server uses this machanism to decide who is the sender and who is the receiver. The server must know if the connecting client wants to publish a stream or if it wants to subscribe to a stream. The example server looks for the `publish:` prefix in the StreamID. If this prefix is present, the server assumes that it is the receiver and the client will send the data. The subcribing clients must use the same StreamID (withouth the `publish:` prefix) in order to be able to receive data. If you implement your own server you are free to interpret the streamID as you wish. ### Usage Running a server listening on port 6001 with defaults: ```shell ./server -addr ":6001" ``` Now you can use the contributed client to publish a stream: ```shell ./client -from ... -to "srt://127.0.0.1:6001/?mode=caller&streamid=publish:/live/stream" ``` or directly from `ffmpeg`: ```shell ffmpeg \ -f lavfi \ -re \ -i testsrc2=rate=25:size=640x360 \ -codec:v libx264 \ -b:v 1024k \ -maxrate:v 1024k \ -bufsize:v 1024k \ -preset ultrafast \ -r 25 \ -g 50 \ -pix_fmt yuv420p \ -flags2 local_header \ -f mpegts \ -transtype live \ "srt://127.0.0.1:6001?streamid=publish:/live/stream" ``` If the server is not on localhost, you might adjust the `peerlatency` in order to avoid packet loss: `-peerlatency 1000000`. Now you can play the stream: ```shell ffplay -f mpegts -transtype live -i "srt://127.0.0.1:6001?streamid=/live/stream" ``` You will most likely first see some error messages from `ffplay` because it tries to make sense of the received data until a keyframe arrives. If you get more errors during playback, you might increase the receive buffer by adding e.g. `-rcvlatency 1000000` to the command line. ### Encryption The stream can be encrypted with a passphrase. First start the server with a passphrase. If you are using `srt-live-transmit`, the passphrase has to be at least 10 characters long otherwise it will not be accepted. ```shell ./server -addr :6001 -passphrase foobarfoobar ``` Send an encrpyted stream to the server: ```shell ffmpeg \ -f lavfi \ -re \ -i testsrc2=rate=25:size=640x360 \ -codec:v libx264 \ -b:v 1024k \ -maxrate:v 1024k \ -bufsize:v 1024k \ -preset ultrafast \ -r 25 \ -g 50 \ -pix_fmt yuv420p \ -flags2 local_header \ -f mpegts \ -transtype live \ "srt://127.0.0.1:6001?streamid=publish:/live/stream&passphrase=foobarfoobar" ``` Receive an encrypted stream from the server: ```shell ffplay -f mpegts -transtype live -i "srt://127.0.0.1:6001?streamid=/live/stream&passphrase=foobarfoobar" ``` You will most likely first see some error messages from `ffplay` because it tries to make sense of the received data until a keyframe arrives. If you get more errors during playback, you might increase the receive buffer by adding e.g. `-rcvlatency 1000000` to the command line. ## Logging This SRT module has a built-in logging facility for debugging purposes. Check the `Logger` interface and the `NewLogger(topics []string)` function. Because logging everything would be too much output if you wonly want to debug something specific, you have the possibility to limit the logging to specific areas like everything regarding a connection or only the handshake. That's why there are various topics. In the contributed server you see an example of how logging is used. Here's the essence: ```go logger := srt.NewLogger([]string{"connection", "handshake"}) config := srt.DefaultConfig config.Logger = logger ln, err := srt.Listen("udp", ":6000", config) if err != nil { // handle error } go func() { for m := range logger.Listen() { fmt.Fprintf(os.Stderr, "%#08x %s (in %s:%d)\n%s \n", m.SocketId, m.Topic, m.File, m.Line, m.Message) } }() for { conn, mode, err := ln.Accept(acceptFn) ... } ``` Currently known topics are: ``` connection:close connection:error connection:filter connection:new connection:rtt connection:tsbpd control:recv:ACK:cif control:recv:ACK:dump control:recv:ACK:error control:recv:ACKACK:dump control:recv:ACKACK:error control:recv:KM:cif control:recv:KM:dump control:recv:KM:error control:recv:NAK:cif control:recv:NAK:dump control:recv:NAK:error control:recv:keepalive:dump control:recv:shutdown:dump control:send:ACK:cif control:send:ACK:dump control:send:ACKACK:dump control:send:KM:cif control:send:KM:dump control:send:KM:error control:send:NAK:cif control:send:NAK:dump control:send:keepalive:dump control:send:shutdown:cif control:send:shutdown:dump data:recv:dump data:send:dump dial handshake:recv:cif handshake:recv:dump handshake:recv:error handshake:send:cif handshake:send:dump listen packet:recv:dump packet:send:dump ``` You can run `make logtopics` in order to extract the list of topics. ## Docker The docker image you can build with `docker build -t srt .` provides the example SRT client and server as mentioned in the paragraph above. E.g. run the server with `docker run -it --rm -p 6001:6001/udp srt srt-server -addr :6001`. ================================================ FILE: SECURITY.md ================================================ # Security Policy ## Supported Versions All versions in the list receive security updates. | Version | Supported | | ------- | ------------------ | | 0.1.1 | :white_check_mark: | | - | :x: | ## Reporting a Vulnerability If you have found or just suspect a security problem somewhere in Restreamer or Core, report it on support@datarhei.com. We treat security issues with confidentiality until controlled and disclosed responsibly. ================================================ FILE: circular/circular.go ================================================ // Package circular implements "circular numbers". This is a number that can be // increased (or decreased) indefinitely while only using up a limited amount of // memory. This feature comes with the limitiation in how distant two such // numbers can be. Circular numbers have a maximum. The maximum distance is // half the maximum value. If a number that has the maximum value is // increased by 1, it becomes 0. If a number that has the value of 0 is // decreased by 1, it becomes the maximum value. By comparing two circular // numbers it is not possible to tell how often they wrapped. Therefore these // two numbers must come from the same domain in order to make sense of the // camparison. package circular // Number represents a "circular number". A Number is immutable. All modification // to a Number will result in a new instance of a Number. type Number struct { max uint32 threshold uint32 value uint32 } // New returns a new circular number with the value of x and the maximum of max. func New(x, max uint32) Number { c := Number{ value: 0, max: max, threshold: max / 2, } if x > max { return c.Add(x) } c.value = x return c } // Val returns the current value of the number. func (a Number) Val() uint32 { return a.value } // Equals returns whether two circular numbers have the same value. func (a Number) Equals(b Number) bool { return a.value == b.value } // Distance returns the distance of two circular numbers. func (a Number) Distance(b Number) uint32 { if a.Equals(b) { return 0 } d := uint32(0) if a.value > b.value { d = a.value - b.value } else { d = b.value - a.value } if d >= a.threshold { d = a.max - d + 1 } return d } // Lt returns whether the circular number is lower than the circular number b. func (a Number) Lt(b Number) bool { if a.Equals(b) { return false } d := uint32(0) altb := false if a.value > b.value { d = a.value - b.value } else { d = b.value - a.value altb = true } if d < a.threshold { return altb } return !altb } // Lte returns whether the circular number is lower than or equal to the circular number b. func (a Number) Lte(b Number) bool { if a.Equals(b) { return true } return a.Lt(b) } // Gt returns whether the circular number is greather than the circular number b. func (a Number) Gt(b Number) bool { if a.Equals(b) { return false } d := uint32(0) agtb := false if a.value > b.value { d = a.value - b.value agtb = true } else { d = b.value - a.value } if d < a.threshold { return agtb } return !agtb } // Gte returns whether the circular number is greather than or equal to the circular number b. func (a Number) Gte(b Number) bool { if a.Equals(b) { return true } return a.Gt(b) } // Inc returns a new circular number with a value that is increased by 1. func (a Number) Inc() Number { b := a if b.value == b.max { b.value = 0 } else { b.value++ } return b } // Add returns a new circular number with a value that is increased by b. func (a Number) Add(b uint32) Number { c := a x := c.max - c.value if b <= x { c.value += b } else { c.value = b - x - 1 } return c } // Dec returns a new circular number with a value that is decreased by 1. func (a Number) Dec() Number { b := a if b.value == 0 { b.value = b.max } else { b.value-- } return b } // Sub returns a new circular number with a value that is decreased by b. func (a Number) Sub(b uint32) Number { c := a if b <= c.value { c.value -= b } else { c.value = c.max - (b - c.value) + 1 } return c } ================================================ FILE: circular/circular_test.go ================================================ package circular import ( "fmt" "testing" "github.com/stretchr/testify/require" ) const max uint32 = 0b11111111_11111111_11111111_11111111 func ExampleNumber_Inc() { a := New(42, max) b := a.Inc() fmt.Println(b.Val()) // Output: 43 } func TestIncNoWrap(t *testing.T) { a := New(42, max) require.Equal(t, uint32(42), a.Val()) a = a.Inc() require.Equal(t, uint32(43), a.Val()) } func TestIncWrap(t *testing.T) { a := New(max-1, max) require.Equal(t, max-1, a.Val()) a = a.Inc() require.Equal(t, max, a.Val()) a = a.Inc() require.Equal(t, uint32(0), a.Val()) } func TestDecNoWrap(t *testing.T) { a := New(42, max) require.Equal(t, uint32(42), a.Val()) a = a.Dec() require.Equal(t, uint32(41), a.Val()) } func TestDecWrap(t *testing.T) { a := New(0, max) require.Equal(t, uint32(0), a.Val()) a = a.Dec() require.Equal(t, max, a.Val()) a = a.Dec() require.Equal(t, max-1, a.Val()) } func TestDistanceNoWrap(t *testing.T) { a := New(42, max) b := New(50, max) d := a.Distance(b) require.Equal(t, uint32(8), d) d = b.Distance(a) require.Equal(t, uint32(8), d) } func TestDistanceWrap(t *testing.T) { a := New(2, max) b := New(max-2, max) d := a.Distance(b) require.Equal(t, uint32(5), d) d = b.Distance(a) require.Equal(t, uint32(5), d) } func TestLt(t *testing.T) { a := New(42, max) b := New(50, max) c := New(max-10, max) x := a.Lt(b) require.Equal(t, true, x) x = b.Lt(a) require.Equal(t, false, x) x = a.Lt(c) require.Equal(t, false, x) x = c.Lt(a) require.Equal(t, true, x) } func TestGt(t *testing.T) { a := New(42, max) b := New(50, max) c := New(max-10, max) x := a.Gt(b) require.Equal(t, false, x) x = b.Gt(a) require.Equal(t, true, x) x = a.Gt(c) require.Equal(t, true, x) x = c.Gt(a) require.Equal(t, false, x) } func TestAdd(t *testing.T) { a := New(max-42, max) a = a.Add(42) require.Equal(t, max, a.Val()) a = a.Add(1) require.Equal(t, uint32(0), a.Val()) } func TestSub(t *testing.T) { a := New(42, max) a = a.Sub(42) require.Equal(t, uint32(0), a.Val()) a = a.Sub(1) require.Equal(t, max, a.Val()) } ================================================ FILE: config.go ================================================ package srt import ( "fmt" "net/url" "strconv" "time" ) const ( UDP_HEADER_SIZE = 28 SRT_HEADER_SIZE = 16 MIN_MSS_SIZE = 76 MAX_MSS_SIZE = 1500 MIN_PAYLOAD_SIZE = MIN_MSS_SIZE - UDP_HEADER_SIZE - SRT_HEADER_SIZE MAX_PAYLOAD_SIZE = MAX_MSS_SIZE - UDP_HEADER_SIZE - SRT_HEADER_SIZE MIN_PASSPHRASE_SIZE = 10 MAX_PASSPHRASE_SIZE = 80 MAX_STREAMID_SIZE = 512 SRT_VERSION = 0x010401 ) // Config is the configuration for a SRT connection type Config struct { // Type of congestion control. 'live' or 'file' // SRTO_CONGESTION Congestion string // Connection timeout. // SRTO_CONNTIMEO ConnectionTimeout time.Duration // Enable drift tracer. // SRTO_DRIFTTRACER DriftTracer bool // Reject connection if parties set different passphrase. // SRTO_ENFORCEDENCRYPTION EnforcedEncryption bool // Flow control window size. Packets. // SRTO_FC FC uint32 // Accept group connections. // SRTO_GROUPCONNECT GroupConnect bool // Group stability timeout. // SRTO_GROUPSTABTIMEO GroupStabilityTimeout time.Duration // Input bandwidth. Bytes. // SRTO_INPUTBW InputBW int64 // IP socket type of service // SRTO_IPTOS IPTOS int // Defines IP socket "time to live" option. // SRTO_IPTTL IPTTL int // Allow only IPv6. // SRTO_IPV6ONLY IPv6Only int // Duration of Stream Encryption key switchover. Packets. // SRTO_KMPREANNOUNCE KMPreAnnounce uint64 // Stream encryption key refresh rate. Packets. // SRTO_KMREFRESHRATE KMRefreshRate uint64 // Defines the maximum accepted transmission latency. // SRTO_LATENCY Latency time.Duration // Packet reorder tolerance. // SRTO_LOSSMAXTTL LossMaxTTL uint32 // Bandwidth limit in bytes/s. // SRTO_MAXBW MaxBW int64 // Enable SRT message mode. // SRTO_MESSAGEAPI MessageAPI bool // Minimum input bandwidth // This option is effective only if both SRTO_MAXBW and SRTO_INPUTBW are set to 0. It controls the minimum allowed value of the input bitrate estimate. // SRTO_MININPUTBW MinInputBW int64 // Minimum SRT library version of a peer. // SRTO_MINVERSION MinVersion uint32 // MTU size // SRTO_MSS MSS uint32 // Enable periodic NAK reports // SRTO_NAKREPORT NAKReport bool // Limit bandwidth overhead, percents // SRTO_OHEADBW OverheadBW int64 // Set up the packet filter. // SRTO_PACKETFILTER PacketFilter string // Password for the encrypted transmission. // SRTO_PASSPHRASE Passphrase string // Maximum payload size. Bytes. // SRTO_PAYLOADSIZE PayloadSize uint32 // Crypto key length in bytes. // SRTO_PBKEYLEN PBKeylen int // Peer idle timeout. // SRTO_PEERIDLETIMEO PeerIdleTimeout time.Duration // Minimum receiver latency to be requested by sender. // SRTO_PEERLATENCY PeerLatency time.Duration // Receiver buffer size. Bytes. // SRTO_RCVBUF ReceiverBufferSize uint32 // Receiver-side latency. // SRTO_RCVLATENCY ReceiverLatency time.Duration // Sender buffer size. Bytes. // SRTO_SNDBUF SendBufferSize uint32 // Sender's delay before dropping packets. // SRTO_SNDDROPDELAY SendDropDelay time.Duration // Stream ID (settable in caller mode only, visible on the listener peer) // SRTO_STREAMID StreamId string // Drop too late packets. // SRTO_TLPKTDROP TooLatePacketDrop bool // Transmission type. 'live' or 'file'. // SRTO_TRANSTYPE TransmissionType string // Timestamp-based packet delivery mode. // SRTO_TSBPDMODE TSBPDMode bool // An implementation of the Logger interface Logger Logger // if a new IP starts sending data on an existing socket id, allow it AllowPeerIpChange bool } // DefaultConfig is the default configuration for a SRT connection // if no individual configuration has been provided. var defaultConfig Config = Config{ Congestion: "live", ConnectionTimeout: 3 * time.Second, DriftTracer: true, EnforcedEncryption: true, FC: 25600, GroupConnect: false, GroupStabilityTimeout: 0, InputBW: 0, IPTOS: 0, IPTTL: 0, IPv6Only: -1, KMPreAnnounce: 1 << 12, KMRefreshRate: 1 << 24, Latency: -1, LossMaxTTL: 0, MaxBW: -1, MessageAPI: false, MinVersion: SRT_VERSION, MSS: MAX_MSS_SIZE, NAKReport: true, OverheadBW: 25, PacketFilter: "", Passphrase: "", PayloadSize: MAX_PAYLOAD_SIZE, PBKeylen: 16, PeerIdleTimeout: 5 * time.Second, PeerLatency: 120 * time.Millisecond, ReceiverBufferSize: 0, ReceiverLatency: 120 * time.Millisecond, SendBufferSize: 0, SendDropDelay: 1 * time.Second, StreamId: "", TooLatePacketDrop: true, TransmissionType: "live", TSBPDMode: true, AllowPeerIpChange: false, } // DefaultConfig returns the default configuration for Dial and Listen. func DefaultConfig() Config { return defaultConfig } // UnmarshalURL takes a SRT URL and parses out the configuration. A SRT URL is // srt://[host]:[port]?[key1]=[value1]&[key2]=[value2]... It returns the host:port // of the URL. func (c *Config) UnmarshalURL(srturl string) (string, error) { u, err := url.Parse(srturl) if err != nil { return "", err } if u.Scheme != "srt" { return "", fmt.Errorf("the URL doesn't seem to be an srt:// URL") } return u.Host, c.UnmarshalQuery(u.RawQuery) } // UnmarshalQuery parses a query string and interprets it as a configuration // for a SRT connection. The key in each key/value pair corresponds to the // respective field in the Config type, but with only lower case letters. Bool // values can be represented as "true"/"false", "on"/"off", "yes"/"no", or "0"/"1". func (c *Config) UnmarshalQuery(query string) error { v, err := url.ParseQuery(query) if err != nil { return err } // https://github.com/Haivision/srt/blob/master/docs/apps/srt-live-transmit.md if s := v.Get("congestion"); len(s) != 0 { c.Congestion = s } if s := v.Get("conntimeo"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.ConnectionTimeout = time.Duration(d) * time.Millisecond } } if s := v.Get("drifttracer"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.DriftTracer = true case "no", "off", "false", "0": c.DriftTracer = false } } if s := v.Get("enforcedencryption"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.EnforcedEncryption = true case "no", "off", "false", "0": c.EnforcedEncryption = false } } if s := v.Get("fc"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.FC = uint32(d) } } if s := v.Get("groupconnect"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.GroupConnect = true case "no", "off", "false", "0": c.GroupConnect = false } } if s := v.Get("groupstabtimeo"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.GroupStabilityTimeout = time.Duration(d) * time.Millisecond } } if s := v.Get("inputbw"); len(s) != 0 { if d, err := strconv.ParseInt(s, 10, 64); err == nil { c.InputBW = d } } if s := v.Get("iptos"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.IPTOS = d } } if s := v.Get("ipttl"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.IPTTL = d } } if s := v.Get("ipv6only"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.IPv6Only = d } } if s := v.Get("kmpreannounce"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 64); err == nil { c.KMPreAnnounce = d } } if s := v.Get("kmrefreshrate"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 64); err == nil { c.KMRefreshRate = d } } if s := v.Get("latency"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.Latency = time.Duration(d) * time.Millisecond } } if s := v.Get("lossmaxttl"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.LossMaxTTL = uint32(d) } } if s := v.Get("maxbw"); len(s) != 0 { if d, err := strconv.ParseInt(s, 10, 64); err == nil { c.MaxBW = d } } if s := v.Get("mininputbw"); len(s) != 0 { if d, err := strconv.ParseInt(s, 10, 64); err == nil { c.MinInputBW = d } } if s := v.Get("messageapi"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.MessageAPI = true case "no", "off", "false", "0": c.MessageAPI = false } } // minversion is ignored if s := v.Get("mss"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.MSS = uint32(d) } } if s := v.Get("nakreport"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.NAKReport = true case "no", "off", "false", "0": c.NAKReport = false } } if s := v.Get("oheadbw"); len(s) != 0 { if d, err := strconv.ParseInt(s, 10, 64); err == nil { c.OverheadBW = d } } if s := v.Get("packetfilter"); len(s) != 0 { c.PacketFilter = s } if s := v.Get("passphrase"); len(s) != 0 { c.Passphrase = s } if s := v.Get("payloadsize"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.PayloadSize = uint32(d) } } if s := v.Get("pbkeylen"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.PBKeylen = d } } if s := v.Get("peeridletimeo"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.PeerIdleTimeout = time.Duration(d) * time.Millisecond } } if s := v.Get("peerlatency"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.PeerLatency = time.Duration(d) * time.Millisecond } } if s := v.Get("rcvbuf"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.ReceiverBufferSize = uint32(d) } } if s := v.Get("rcvlatency"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.ReceiverLatency = time.Duration(d) * time.Millisecond } } // retransmitalgo not implemented (there's only one) if s := v.Get("sndbuf"); len(s) != 0 { if d, err := strconv.ParseUint(s, 10, 32); err == nil { c.SendBufferSize = uint32(d) } } if s := v.Get("snddropdelay"); len(s) != 0 { if d, err := strconv.Atoi(s); err == nil { c.SendDropDelay = time.Duration(d) * time.Millisecond } } if s := v.Get("streamid"); len(s) != 0 { c.StreamId = s } if s := v.Get("tlpktdrop"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.TooLatePacketDrop = true case "no", "off", "false", "0": c.TooLatePacketDrop = false } } if s := v.Get("transtype"); len(s) != 0 { c.TransmissionType = s } if s := v.Get("tsbpdmode"); len(s) != 0 { switch s { case "yes", "on", "true", "1": c.TSBPDMode = true case "no", "off", "false", "0": c.TSBPDMode = false } } return nil } // MarshalURL returns the SRT URL for this config and the given address (host:port). func (c *Config) MarshalURL(address string) string { return "srt://" + address + "?" + c.MarshalQuery() } // MarshalQuery returns the corresponding query string for a configuration. func (c *Config) MarshalQuery() string { q := url.Values{} if c.Congestion != defaultConfig.Congestion { q.Set("congestion", c.Congestion) } if c.ConnectionTimeout != defaultConfig.ConnectionTimeout { q.Set("conntimeo", strconv.FormatInt(c.ConnectionTimeout.Milliseconds(), 10)) } if c.DriftTracer != defaultConfig.DriftTracer { q.Set("drifttracer", strconv.FormatBool(c.DriftTracer)) } if c.EnforcedEncryption != defaultConfig.EnforcedEncryption { q.Set("enforcedencryption", strconv.FormatBool(c.EnforcedEncryption)) } if c.FC != defaultConfig.FC { q.Set("fc", strconv.FormatUint(uint64(c.FC), 10)) } if c.GroupConnect != defaultConfig.GroupConnect { q.Set("groupconnect", strconv.FormatBool(c.GroupConnect)) } if c.GroupStabilityTimeout != defaultConfig.GroupStabilityTimeout { q.Set("groupstabtimeo", strconv.FormatInt(c.GroupStabilityTimeout.Milliseconds(), 10)) } if c.InputBW != defaultConfig.InputBW { q.Set("inputbw", strconv.FormatInt(c.InputBW, 10)) } if c.IPTOS != defaultConfig.IPTOS { q.Set("iptos", strconv.FormatInt(int64(c.IPTOS), 10)) } if c.IPTTL != defaultConfig.IPTTL { q.Set("ipttl", strconv.FormatInt(int64(c.IPTTL), 10)) } if c.IPv6Only != defaultConfig.IPv6Only { q.Set("ipv6only", strconv.FormatInt(int64(c.IPv6Only), 10)) } if len(c.Passphrase) != 0 { if c.KMPreAnnounce != defaultConfig.KMPreAnnounce { q.Set("kmpreannounce", strconv.FormatUint(c.KMPreAnnounce, 10)) } if c.KMRefreshRate != defaultConfig.KMRefreshRate { q.Set("kmrefreshrate", strconv.FormatUint(c.KMRefreshRate, 10)) } } if c.Latency != defaultConfig.Latency { q.Set("latency", strconv.FormatInt(c.Latency.Milliseconds(), 10)) } if c.LossMaxTTL != defaultConfig.LossMaxTTL { q.Set("lossmaxttl", strconv.FormatInt(int64(c.LossMaxTTL), 10)) } if c.MaxBW != defaultConfig.MaxBW { q.Set("maxbw", strconv.FormatInt(c.MaxBW, 10)) } if c.MinInputBW != defaultConfig.InputBW { q.Set("mininputbw", strconv.FormatInt(c.MinInputBW, 10)) } if c.MessageAPI != defaultConfig.MessageAPI { q.Set("messageapi", strconv.FormatBool(c.MessageAPI)) } if c.MSS != defaultConfig.MSS { q.Set("mss", strconv.FormatUint(uint64(c.MSS), 10)) } if c.NAKReport != defaultConfig.NAKReport { q.Set("nakreport", strconv.FormatBool(c.NAKReport)) } if c.OverheadBW != defaultConfig.OverheadBW { q.Set("oheadbw", strconv.FormatInt(c.OverheadBW, 10)) } if c.PacketFilter != defaultConfig.PacketFilter { q.Set("packetfilter", c.PacketFilter) } if len(c.Passphrase) != 0 { q.Set("passphrase", c.Passphrase) } if c.PayloadSize != defaultConfig.PayloadSize { q.Set("payloadsize", strconv.FormatUint(uint64(c.PayloadSize), 10)) } if c.PBKeylen != defaultConfig.PBKeylen { q.Set("pbkeylen", strconv.FormatInt(int64(c.PBKeylen), 10)) } if c.PeerIdleTimeout != defaultConfig.PeerIdleTimeout { q.Set("peeridletimeo", strconv.FormatInt(c.PeerIdleTimeout.Milliseconds(), 10)) } if c.PeerLatency != defaultConfig.PeerLatency { q.Set("peerlatency", strconv.FormatInt(c.PeerLatency.Milliseconds(), 10)) } if c.ReceiverBufferSize != defaultConfig.ReceiverBufferSize { q.Set("rcvbuf", strconv.FormatInt(int64(c.ReceiverBufferSize), 10)) } if c.ReceiverLatency != defaultConfig.ReceiverLatency { q.Set("rcvlatency", strconv.FormatInt(c.ReceiverLatency.Milliseconds(), 10)) } if c.SendBufferSize != defaultConfig.SendBufferSize { q.Set("sndbuf", strconv.FormatInt(int64(c.SendBufferSize), 10)) } if c.SendDropDelay != defaultConfig.SendDropDelay { q.Set("snddropdelay", strconv.FormatInt(c.SendDropDelay.Milliseconds(), 10)) } if len(c.StreamId) != 0 { q.Set("streamid", c.StreamId) } if c.TooLatePacketDrop != defaultConfig.TooLatePacketDrop { q.Set("tlpktdrop", strconv.FormatBool(c.TooLatePacketDrop)) } if c.TransmissionType != defaultConfig.TransmissionType { q.Set("transtype", c.TransmissionType) } if c.TSBPDMode != defaultConfig.TSBPDMode { q.Set("tsbpdmode", strconv.FormatBool(c.TSBPDMode)) } return q.Encode() } // Validate validates a configuration, returns an error if a field // has an invalid value. func (c *Config) Validate() error { if c.TransmissionType != "live" { return fmt.Errorf("config: TransmissionType must be 'live'") } c.Congestion = "live" c.NAKReport = true c.TooLatePacketDrop = true c.TSBPDMode = true if c.Congestion != "live" { return fmt.Errorf("config: Congestion mode must be 'live'") } if c.ConnectionTimeout <= 0 { return fmt.Errorf("config: ConnectionTimeout must be greater than 0") } if c.GroupConnect { return fmt.Errorf("config: GroupConnect is not supported") } if c.IPTOS > 0 && c.IPTOS > 255 { return fmt.Errorf("config: IPTOS must be lower than 255") } if c.IPTTL > 0 && c.IPTTL > 255 { return fmt.Errorf("config: IPTTL must be between 1 and 255") } if c.IPv6Only > 0 { return fmt.Errorf("config: IPv6Only is not supported") } if c.KMRefreshRate != 0 { if c.KMPreAnnounce < 1 || c.KMPreAnnounce > c.KMRefreshRate/2 { return fmt.Errorf("config: KMPreAnnounce must be greater than 1 and smaller than KMRefreshRate/2") } } if c.Latency >= 0 { c.PeerLatency = c.Latency c.ReceiverLatency = c.Latency } if c.MinVersion != SRT_VERSION { return fmt.Errorf("config: MinVersion must be %#06x", SRT_VERSION) } if c.MSS < MIN_MSS_SIZE || c.MSS > MAX_MSS_SIZE { return fmt.Errorf("config: MSS must be between %d and %d (both inclusive)", MIN_MSS_SIZE, MAX_MSS_SIZE) } if !c.NAKReport { return fmt.Errorf("config: NAKReport must be enabled") } if c.OverheadBW < 10 || c.OverheadBW > 100 { return fmt.Errorf("config: OverheadBW must be between 10 and 100") } if len(c.PacketFilter) != 0 { return fmt.Errorf("config: PacketFilter are not supported") } if len(c.Passphrase) != 0 { if len(c.Passphrase) < MIN_PASSPHRASE_SIZE || len(c.Passphrase) > MAX_PASSPHRASE_SIZE { return fmt.Errorf("config: Passphrase must be between %d and %d bytes long", MIN_PASSPHRASE_SIZE, MAX_PASSPHRASE_SIZE) } } if c.PayloadSize < MIN_PAYLOAD_SIZE || c.PayloadSize > MAX_PAYLOAD_SIZE { return fmt.Errorf("config: PayloadSize must be between %d and %d (both inclusive)", MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE) } if c.PayloadSize > c.MSS-uint32(SRT_HEADER_SIZE+UDP_HEADER_SIZE) { return fmt.Errorf("config: PayloadSize must not be larger than %d (MSS - %d)", c.MSS-uint32(SRT_HEADER_SIZE+UDP_HEADER_SIZE), SRT_HEADER_SIZE-UDP_HEADER_SIZE) } if c.PBKeylen != 16 && c.PBKeylen != 24 && c.PBKeylen != 32 { return fmt.Errorf("config: PBKeylen must be 16, 24, or 32 bytes") } if c.PeerLatency < 0 { return fmt.Errorf("config: PeerLatency must be greater than 0") } if c.ReceiverLatency < 0 { return fmt.Errorf("config: ReceiverLatency must be greater than 0") } if c.SendDropDelay < 0 { return fmt.Errorf("config: SendDropDelay must be greater than 0") } if len(c.StreamId) > MAX_STREAMID_SIZE { return fmt.Errorf("config: StreamId must be shorter than or equal to %d bytes", MAX_STREAMID_SIZE) } if !c.TooLatePacketDrop { return fmt.Errorf("config: TooLatePacketDrop must be enabled") } if c.TransmissionType != "live" { return fmt.Errorf("config: TransmissionType must be 'live'") } if !c.TSBPDMode { return fmt.Errorf("config: TSBPDMode must be enabled") } return nil } ================================================ FILE: config_test.go ================================================ package srt import ( "testing" "time" "github.com/stretchr/testify/require" ) func TestDefaultConfig(t *testing.T) { config := DefaultConfig() err := config.Validate() if err != nil { require.NoError(t, err, "Failed to verify the default configuration: %s", err) } } func TestMarshalUnmarshal(t *testing.T) { wantConfig := Config{ Congestion: "xxx", ConnectionTimeout: 42 * time.Second, DriftTracer: false, EnforcedEncryption: false, FC: 42, GroupConnect: true, GroupStabilityTimeout: 42 * time.Second, InputBW: 42, IPTOS: 42, IPTTL: 42, IPv6Only: 42, KMPreAnnounce: 42, KMRefreshRate: 42, Latency: 42 * time.Second, LossMaxTTL: 42, MaxBW: 42, MessageAPI: true, MinInputBW: 42, MSS: 42, NAKReport: false, OverheadBW: 42, PacketFilter: "FEC", Passphrase: "foobar", PayloadSize: 42, PBKeylen: 42, PeerIdleTimeout: 42 * time.Second, PeerLatency: 42 * time.Second, ReceiverBufferSize: 42, ReceiverLatency: 42 * time.Second, SendBufferSize: 42, SendDropDelay: 42 * time.Second, StreamId: "foobaz", TooLatePacketDrop: false, TransmissionType: "yyy", TSBPDMode: false, Logger: nil, } url := wantConfig.MarshalURL("localhost:6000") config := Config{} config.UnmarshalURL(url) require.Equal(t, wantConfig, config) } ================================================ FILE: congestion/congestion.go ================================================ // Package congestions provides interfaces and types congestion control implementations for SRT package congestion import ( "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/packet" ) // Sender is the sending part of the congestion control type Sender interface { // Stats returns sender statistics. Stats() SendStats // Flush flushes all queued packages. Flush() // Push pushes a packet to be send on the sender queue. Push(p packet.Packet) // Tick gets called from a connection in order to proceed with the queued packets. The provided value for // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds // since the start of the connection. Tick(now uint64) // ACK gets called when a sequence number has been confirmed from a receiver. ACK(sequenceNumber circular.Number) // NAK get called when packets with the listed sequence number should be resend. NAK(sequenceNumbers []circular.Number) // SetDropThreshold sets the threshold in microseconds for when to drop too late packages from the queue. SetDropThreshold(threshold uint64) } // Receiver is the receiving part of the congestion control type Receiver interface { // Stats returns receiver statistics. Stats() ReceiveStats // PacketRate returns the current packets and bytes per second, and the capacity of the link. PacketRate() (pps, bps, capacity float64) // Flush flushes all queued packages. Flush() // Push pushed a recieved packet to the receiver queue. Push(pkt packet.Packet) // Tick gets called from a connection in order to proceed with queued packets. The provided value for // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds // since the start of the connection. Tick(now uint64) // SetNAKInterval sets the interval between two periodic NAK messages to the sender in microseconds. SetNAKInterval(nakInterval uint64) } // SendStats are collected statistics from a sender type SendStats struct { Pkt uint64 // Sent packets in total Byte uint64 // Sent bytes in total PktUnique uint64 ByteUnique uint64 PktLoss uint64 ByteLoss uint64 PktRetrans uint64 ByteRetrans uint64 UsSndDuration uint64 // microseconds PktDrop uint64 ByteDrop uint64 // instantaneous PktBuf uint64 ByteBuf uint64 MsBuf uint64 PktFlightSize uint64 UsPktSndPeriod float64 // microseconds BytePayload uint64 MbpsEstimatedInputBandwidth float64 MbpsEstimatedSentBandwidth float64 PktLossRate float64 } // ReceiveStats are collected statistics from a reciever type ReceiveStats struct { Pkt uint64 Byte uint64 PktUnique uint64 ByteUnique uint64 PktLoss uint64 ByteLoss uint64 PktRetrans uint64 ByteRetrans uint64 PktBelated uint64 ByteBelated uint64 PktDrop uint64 ByteDrop uint64 // instantaneous PktBuf uint64 ByteBuf uint64 MsBuf uint64 BytePayload uint64 MbpsEstimatedRecvBandwidth float64 MbpsEstimatedLinkCapacity float64 PktLossRate float64 } ================================================ FILE: congestion/live/doc.go ================================================ // Package live provides implementations of the Sender and Receiver interfaces for live congestion control package live ================================================ FILE: congestion/live/fake.go ================================================ package live import ( "sync" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/congestion" "github.com/datarhei/gosrt/packet" ) type fakeLiveReceive struct { maxSeenSequenceNumber circular.Number lastACKSequenceNumber circular.Number lastDeliveredSequenceNumber circular.Number nPackets uint periodicACKInterval uint64 // config periodicNAKInterval uint64 // config lastPeriodicACK uint64 avgPayloadSize float64 // bytes rate struct { last time.Time period time.Duration packets uint64 bytes uint64 pps float64 bps float64 } sendACK func(seq circular.Number, light bool) sendNAK func(list []circular.Number) deliver func(p packet.Packet) lock sync.RWMutex } func NewFakeLiveReceive(config ReceiveConfig) congestion.Receiver { r := &fakeLiveReceive{ maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), periodicACKInterval: config.PeriodicACKInterval, periodicNAKInterval: config.PeriodicNAKInterval, avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm sendACK: config.OnSendACK, sendNAK: config.OnSendNAK, deliver: config.OnDeliver, } if r.sendACK == nil { r.sendACK = func(seq circular.Number, light bool) {} } if r.sendNAK == nil { r.sendNAK = func(list []circular.Number) {} } if r.deliver == nil { r.deliver = func(p packet.Packet) {} } r.rate.last = time.Now() r.rate.period = time.Second return r } func (r *fakeLiveReceive) Stats() congestion.ReceiveStats { return congestion.ReceiveStats{} } func (r *fakeLiveReceive) PacketRate() (pps, bps, capacity float64) { r.lock.Lock() defer r.lock.Unlock() tdiff := time.Since(r.rate.last) if tdiff < r.rate.period { pps = r.rate.pps bps = r.rate.bps return } r.rate.pps = float64(r.rate.packets) / tdiff.Seconds() r.rate.bps = float64(r.rate.bytes) / tdiff.Seconds() r.rate.packets, r.rate.bytes = 0, 0 r.rate.last = time.Now() pps = r.rate.pps bps = r.rate.bps return } func (r *fakeLiveReceive) Flush() {} func (r *fakeLiveReceive) Push(pkt packet.Packet) { r.lock.Lock() defer r.lock.Unlock() if pkt == nil { return } r.nPackets++ pktLen := pkt.Len() r.rate.packets++ r.rate.bytes += pktLen // 5.1.2. SRT's Default LiveCC Algorithm r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered return } if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { // Already acknowledged, ignoring return } if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { return } r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber } func (r *fakeLiveReceive) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { r.lock.RLock() defer r.lock.RUnlock() // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) if now-r.lastPeriodicACK < r.periodicACKInterval { if r.nPackets >= 64 { lite = true // Send light ACK } else { return } } ok = true sequenceNumber = r.maxSeenSequenceNumber.Inc() r.lastACKSequenceNumber = r.maxSeenSequenceNumber r.lastPeriodicACK = now r.nPackets = 0 return } func (r *fakeLiveReceive) Tick(now uint64) { if ok, sequenceNumber, lite := r.periodicACK(now); ok { r.sendACK(sequenceNumber, lite) } // Deliver packets whose PktTsbpdTime is ripe r.lock.Lock() defer r.lock.Unlock() r.lastDeliveredSequenceNumber = r.lastACKSequenceNumber } func (r *fakeLiveReceive) SetNAKInterval(nakInterval uint64) { r.lock.Lock() defer r.lock.Unlock() r.periodicNAKInterval = nakInterval } ================================================ FILE: congestion/live/receive.go ================================================ package live import ( "container/list" "fmt" "strings" "sync" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/congestion" "github.com/datarhei/gosrt/packet" ) // ReceiveConfig is the configuration for the liveRecv congestion control type ReceiveConfig struct { InitialSequenceNumber circular.Number PeriodicACKInterval uint64 // microseconds PeriodicNAKInterval uint64 // microseconds OnSendACK func(seq circular.Number, light bool) OnSendNAK func(list []circular.Number) OnDeliver func(p packet.Packet) } // receiver implements the Receiver interface type receiver struct { maxSeenSequenceNumber circular.Number lastACKSequenceNumber circular.Number lastDeliveredSequenceNumber circular.Number packetList *list.List lock sync.RWMutex nPackets uint periodicACKInterval uint64 // config periodicNAKInterval uint64 // config lastPeriodicACK uint64 lastPeriodicNAK uint64 avgPayloadSize float64 // bytes avgLinkCapacity float64 // packets per second probeTime time.Time probeNextSeq circular.Number statistics congestion.ReceiveStats rate struct { last uint64 // microseconds period uint64 packets uint64 bytes uint64 bytesRetrans uint64 packetsPerSecond float64 bytesPerSecond float64 pktLossRate float64 } sendACK func(seq circular.Number, light bool) sendNAK func(list []circular.Number) deliver func(p packet.Packet) } // NewReceiver takes a ReceiveConfig and returns a new Receiver func NewReceiver(config ReceiveConfig) congestion.Receiver { r := &receiver{ maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), packetList: list.New(), periodicACKInterval: config.PeriodicACKInterval, periodicNAKInterval: config.PeriodicNAKInterval, avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm sendACK: config.OnSendACK, sendNAK: config.OnSendNAK, deliver: config.OnDeliver, } if r.sendACK == nil { r.sendACK = func(seq circular.Number, light bool) {} } if r.sendNAK == nil { r.sendNAK = func(list []circular.Number) {} } if r.deliver == nil { r.deliver = func(p packet.Packet) {} } r.rate.last = 0 r.rate.period = uint64(time.Second.Microseconds()) return r } func (r *receiver) Stats() congestion.ReceiveStats { r.lock.Lock() defer r.lock.Unlock() r.statistics.BytePayload = uint64(r.avgPayloadSize) r.statistics.MbpsEstimatedRecvBandwidth = r.rate.bytesPerSecond * 8 / 1024 / 1024 r.statistics.MbpsEstimatedLinkCapacity = r.avgLinkCapacity * packet.MAX_PAYLOAD_SIZE * 8 / 1024 / 1024 r.statistics.PktLossRate = r.rate.pktLossRate return r.statistics } func (r *receiver) PacketRate() (pps, bps, capacity float64) { r.lock.Lock() defer r.lock.Unlock() pps = r.rate.packetsPerSecond bps = r.rate.bytesPerSecond capacity = r.avgLinkCapacity return } func (r *receiver) Flush() { r.lock.Lock() defer r.lock.Unlock() r.packetList = r.packetList.Init() } func (r *receiver) Push(pkt packet.Packet) { r.lock.Lock() defer r.lock.Unlock() if pkt == nil { return } // This is not really well (not at all) described in the specs. See core.cpp and window.h // and search for PUMASK_SEQNO_PROBE (0xF). Every 16th and 17th packet are // sent in pairs. This is used as a probe for the theoretical capacity of the link. if !pkt.Header().RetransmittedPacketFlag { probe := pkt.Header().PacketSequenceNumber.Val() & 0xF if probe == 0 { r.probeTime = time.Now() r.probeNextSeq = pkt.Header().PacketSequenceNumber.Inc() } else if probe == 1 && pkt.Header().PacketSequenceNumber.Equals(r.probeNextSeq) && !r.probeTime.IsZero() && pkt.Len() != 0 { // The time between packets scaled to a fully loaded packet diff := float64(time.Since(r.probeTime).Microseconds()) * (packet.MAX_PAYLOAD_SIZE / float64(pkt.Len())) if diff != 0 { // Here we're doing an average of the measurements. r.avgLinkCapacity = 0.875*r.avgLinkCapacity + 0.125*1_000_000/diff } } else { r.probeTime = time.Time{} } } else { r.probeTime = time.Time{} } r.nPackets++ pktLen := pkt.Len() r.rate.packets++ r.rate.bytes += pktLen r.statistics.Pkt++ r.statistics.Byte += pktLen //pkt.PktTsbpdTime = pkt.Timestamp + r.delay if pkt.Header().RetransmittedPacketFlag { r.statistics.PktRetrans++ r.statistics.ByteRetrans += pktLen r.rate.bytesRetrans += pktLen } // 5.1.2. SRT's Default LiveCC Algorithm r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered r.statistics.PktBelated++ r.statistics.ByteBelated += pktLen r.statistics.PktDrop++ r.statistics.ByteDrop += pktLen return } if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { // Already acknowledged, ignoring r.statistics.PktDrop++ r.statistics.ByteDrop += pktLen return } if pkt.Header().PacketSequenceNumber.Equals(r.maxSeenSequenceNumber.Inc()) { // In order, the packet we expected r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber } else if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { // Out of order, is it a missing piece? put it in the correct position for e := r.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) if p.Header().PacketSequenceNumber == pkt.Header().PacketSequenceNumber { // Already received (has been sent more than once), ignoring r.statistics.PktDrop++ r.statistics.ByteDrop += pktLen break } else if p.Header().PacketSequenceNumber.Gt(pkt.Header().PacketSequenceNumber) { // Late arrival, this fills a gap r.statistics.PktBuf++ r.statistics.PktUnique++ r.statistics.ByteBuf += pktLen r.statistics.ByteUnique += pktLen r.packetList.InsertBefore(pkt, e) break } } return } else { // Too far ahead, there are some missing sequence numbers, immediate NAK report // here we can prevent a possibly unnecessary NAK with SRTO_LOXXMAXTTL r.sendNAK([]circular.Number{ r.maxSeenSequenceNumber.Inc(), pkt.Header().PacketSequenceNumber.Dec(), }) len := uint64(pkt.Header().PacketSequenceNumber.Distance(r.maxSeenSequenceNumber)) r.statistics.PktLoss += len r.statistics.ByteLoss += len * uint64(r.avgPayloadSize) r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber } r.statistics.PktBuf++ r.statistics.PktUnique++ r.statistics.ByteBuf += pktLen r.statistics.ByteUnique += pktLen r.packetList.PushBack(pkt) } func (r *receiver) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { r.lock.Lock() defer r.lock.Unlock() // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) if now-r.lastPeriodicACK < r.periodicACKInterval { if r.nPackets >= 64 { lite = true // Send light ACK } else { return } } minPktTsbpdTime, maxPktTsbpdTime := uint64(0), uint64(0) ackSequenceNumber := r.lastACKSequenceNumber e := r.packetList.Front() if e != nil { p := e.Value.(packet.Packet) minPktTsbpdTime = p.Header().PktTsbpdTime maxPktTsbpdTime = p.Header().PktTsbpdTime } // Find the sequence number up until we have all in a row. // Where the first gap is (or at the end of the list) is where we can ACK to. for e := r.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) // Skip packets that we already ACK'd. if p.Header().PacketSequenceNumber.Lte(ackSequenceNumber) { continue } // If there are packets that should have been delivered by now, move forward. if p.Header().PktTsbpdTime <= now { ackSequenceNumber = p.Header().PacketSequenceNumber continue } // Check if the packet is the next in the row. if p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { ackSequenceNumber = p.Header().PacketSequenceNumber maxPktTsbpdTime = p.Header().PktTsbpdTime continue } break } ok = true sequenceNumber = ackSequenceNumber.Inc() // Keep track of the last ACK's sequence number. With this we can faster ignore // packets that come in late that have a lower sequence number. r.lastACKSequenceNumber = ackSequenceNumber r.lastPeriodicACK = now r.nPackets = 0 r.statistics.MsBuf = (maxPktTsbpdTime - minPktTsbpdTime) / 1_000 return } func (r *receiver) periodicNAK(now uint64) []circular.Number { r.lock.RLock() defer r.lock.RUnlock() if now-r.lastPeriodicNAK < r.periodicNAKInterval { return nil } list := []circular.Number{} // Send a periodic NAK ackSequenceNumber := r.lastACKSequenceNumber // Send a NAK for all gaps. // Not all gaps might get announced because the size of the NAK packet is limited. for e := r.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) // Skip packets that we already ACK'd. if p.Header().PacketSequenceNumber.Lte(ackSequenceNumber) { continue } // If this packet is not in sequence, we stop here and report that gap. if !p.Header().PacketSequenceNumber.Equals(ackSequenceNumber.Inc()) { nackSequenceNumber := ackSequenceNumber.Inc() list = append(list, nackSequenceNumber) list = append(list, p.Header().PacketSequenceNumber.Dec()) } ackSequenceNumber = p.Header().PacketSequenceNumber } r.lastPeriodicNAK = now return list } func (r *receiver) Tick(now uint64) { if ok, sequenceNumber, lite := r.periodicACK(now); ok { r.sendACK(sequenceNumber, lite) } if list := r.periodicNAK(now); len(list) != 0 { r.sendNAK(list) } // Deliver packets whose PktTsbpdTime is ripe r.lock.Lock() removeList := make([]*list.Element, 0, r.packetList.Len()) for e := r.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) if p.Header().PacketSequenceNumber.Lte(r.lastACKSequenceNumber) && p.Header().PktTsbpdTime <= now { r.statistics.PktBuf-- r.statistics.ByteBuf -= p.Len() r.lastDeliveredSequenceNumber = p.Header().PacketSequenceNumber r.deliver(p) removeList = append(removeList, e) } else { break } } for _, e := range removeList { r.packetList.Remove(e) } r.lock.Unlock() r.lock.Lock() tdiff := now - r.rate.last // microseconds if tdiff > r.rate.period { r.rate.packetsPerSecond = float64(r.rate.packets) / (float64(tdiff) / 1000 / 1000) r.rate.bytesPerSecond = float64(r.rate.bytes) / (float64(tdiff) / 1000 / 1000) if r.rate.bytes != 0 { r.rate.pktLossRate = float64(r.rate.bytesRetrans) / float64(r.rate.bytes) * 100 } else { r.rate.bytes = 0 } r.rate.packets = 0 r.rate.bytes = 0 r.rate.bytesRetrans = 0 r.rate.last = now } r.lock.Unlock() } func (r *receiver) SetNAKInterval(nakInterval uint64) { r.lock.Lock() defer r.lock.Unlock() r.periodicNAKInterval = nakInterval } func (r *receiver) String(t uint64) string { var b strings.Builder b.WriteString(fmt.Sprintf("maxSeen=%d lastACK=%d lastDelivered=%d\n", r.maxSeenSequenceNumber.Val(), r.lastACKSequenceNumber.Val(), r.lastDeliveredSequenceNumber.Val())) r.lock.RLock() for e := r.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) b.WriteString(fmt.Sprintf(" %d @ %d (in %d)\n", p.Header().PacketSequenceNumber.Val(), p.Header().PktTsbpdTime, int64(p.Header().PktTsbpdTime)-int64(t))) } r.lock.RUnlock() return b.String() } ================================================ FILE: congestion/live/receive_test.go ================================================ package live import ( "net" "testing" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/require" ) func mockLiveRecv(onSendACK func(seq circular.Number, light bool), onSendNAK func(list []circular.Number), onDeliver func(p packet.Packet)) *receiver { recv := NewReceiver(ReceiveConfig{ InitialSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), PeriodicACKInterval: 10, PeriodicNAKInterval: 20, OnSendACK: onSendACK, OnSendNAK: onSendNAK, OnDeliver: onDeliver, }) return recv.(*receiver) } func TestRecvSequence(t *testing.T) { nACK := 0 nNAK := 0 numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { nACK++ }, func(list []circular.Number) { nNAK++ }, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } require.Equal(t, 0, nACK) require.Equal(t, 0, nNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) recv.Tick(1) require.Equal(t, 0, nACK) require.Equal(t, 0, nNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) recv.Tick(10) // ACK period require.Equal(t, 1, nACK) require.Equal(t, 0, nNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(9), recv.lastACKSequenceNumber.Val()) require.Exactly(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, numbers) } func TestRecvTSBPD(t *testing.T) { numbers := []uint32{} recv := mockLiveRecv( nil, nil, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 20 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) recv.Tick(10) // ACK period require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(19), recv.lastACKSequenceNumber.Val()) require.Exactly(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, numbers) } func TestRecvNAK(t *testing.T) { seqACK := uint32(0) seqNAK := []uint32{} numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { seqACK = seq.Val() }, func(list []circular.Number) { seqNAK = []uint32{} for _, sn := range list { seqNAK = append(seqNAK, sn.Val()) } }, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{}, seqNAK) require.Equal(t, uint32(4), recv.maxSeenSequenceNumber.Val()) for i := 7; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) recv.Tick(10) // ACK period require.Equal(t, uint32(10), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) } func TestRecvPeriodicNAK(t *testing.T) { seqACK := uint32(0) seqNAK := []uint32{} numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { seqACK = seq.Val() }, func(list []circular.Number) { seqNAK = []uint32{} for _, sn := range list { seqNAK = append(seqNAK, sn.Val()) } }, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(50 + i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{}, seqNAK) require.Equal(t, uint32(4), recv.maxSeenSequenceNumber.Val()) for i := 7; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(50 + i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) recv.Tick(10) // ACK period require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) recv.Tick(20) // ACK period, NAK period require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) } func TestRecvACK(t *testing.T) { seqACK := uint32(0) seqNAK := []uint32{} numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { seqACK = seq.Val() }, func(list []circular.Number) { seqNAK = []uint32{} for _, sn := range list { seqNAK = append(seqNAK, sn.Val()) } }, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(10 + i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{}, seqNAK) require.Equal(t, uint32(4), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(0), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{}, numbers) for i := 7; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(30 + i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{5, 6}, seqNAK) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(0), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{}, numbers) for i := 15; i < 20; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(30 + i + 1) recv.Push(p) } require.Equal(t, uint32(0), seqACK) require.Equal(t, []uint32{10, 14}, seqNAK) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(0), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(0), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{}, numbers) recv.Tick(10) require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{10, 14}, seqNAK) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(5), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(0), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{}, numbers) recv.Tick(20) require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{5, 6, 10, 14}, seqNAK) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(5), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(5), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{0, 1, 2, 3, 4}, numbers) recv.Tick(30) require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{5, 6, 10, 14}, seqNAK) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(5), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(5), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{0, 1, 2, 3, 4}, numbers) for i := 5; i < 7; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(30 + i + 1) recv.Push(p) } recv.Tick(40) require.Equal(t, uint32(10), seqACK) require.Equal(t, []uint32{10, 14}, seqNAK) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint32(10), recv.lastACKSequenceNumber.Inc().Val()) require.Equal(t, uint32(10), recv.lastDeliveredSequenceNumber.Inc().Val()) require.Exactly(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, numbers) } func TestRecvDropTooLate(t *testing.T) { recv := mockLiveRecv( nil, nil, nil, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } recv.Tick(10) // ACK period stats := recv.Stats() require.Equal(t, uint32(9), recv.lastACKSequenceNumber.Val()) require.Equal(t, uint32(9), recv.lastDeliveredSequenceNumber.Val()) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint64(0), stats.PktDrop) p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(3), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(4) recv.Push(p) stats = recv.Stats() require.Equal(t, uint64(1), stats.PktDrop) } func TestRecvDropAlreadyACK(t *testing.T) { recv := mockLiveRecv( nil, nil, nil, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } for i := 5; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(10 + i + 1) recv.Push(p) } recv.Tick(10) // ACK period stats := recv.Stats() require.Equal(t, uint32(9), recv.lastACKSequenceNumber.Val()) require.Equal(t, uint32(4), recv.lastDeliveredSequenceNumber.Val()) require.Equal(t, uint32(9), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint64(0), stats.PktDrop) p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(6), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(7) recv.Push(p) stats = recv.Stats() require.Equal(t, uint64(1), stats.PktDrop) } func TestRecvDropAlreadyRecvNoACK(t *testing.T) { recv := mockLiveRecv( nil, nil, nil, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } for i := 5; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(10 + i + 1) recv.Push(p) } recv.Tick(10) // ACK period for i := range 10 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(10+i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(20 + i + 1) recv.Push(p) } stats := recv.Stats() require.Equal(t, uint32(9), recv.lastACKSequenceNumber.Val()) require.Equal(t, uint32(4), recv.lastDeliveredSequenceNumber.Val()) require.Equal(t, uint32(19), recv.maxSeenSequenceNumber.Val()) require.Equal(t, uint64(0), stats.PktDrop) p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(15), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(20 + 6) recv.Push(p) stats = recv.Stats() require.Equal(t, uint64(1), stats.PktDrop) } func TestRecvFlush(t *testing.T) { recv := mockLiveRecv( nil, nil, nil, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } require.Equal(t, 10, recv.packetList.Len()) recv.Flush() require.Equal(t, 0, recv.packetList.Len()) } func TestRecvPeriodicACKLite(t *testing.T) { liteACK := false recv := mockLiveRecv( func(seq circular.Number, light bool) { liteACK = light }, nil, nil, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 100 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(10 + i + 1) recv.Push(p) } require.Equal(t, false, liteACK) recv.Tick(1) require.Equal(t, true, liteACK) } func TestSkipTooLate(t *testing.T) { seqACK := uint32(0) numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { seqACK = seq.Val() }, nil, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 5 { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(i + 1) recv.Push(p) } recv.Tick(10) require.Equal(t, uint32(5), seqACK) require.Equal(t, []uint32{0, 1, 2, 3, 4}, numbers) for i := 5; i < 10; i++ { p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(uint32(3+i), packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = uint64(13 + i + 1) recv.Push(p) } recv.Tick(20) require.Equal(t, uint32(13), seqACK) require.Equal(t, []uint32{0, 1, 2, 3, 4, 8, 9}, numbers) } func TestIssue67(t *testing.T) { ackNumbers := []uint32{} nakNumbers := [][2]uint32{} numbers := []uint32{} recv := mockLiveRecv( func(seq circular.Number, light bool) { ackNumbers = append(ackNumbers, seq.Val()) }, func(list []circular.Number) { nakNumbers = append(nakNumbers, [2]uint32{list[0].Val(), list[1].Val()}) }, func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }, ) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") p := packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(0, packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = 1 recv.Push(p) recv.Tick(10) recv.Tick(20) recv.Tick(30) recv.Tick(40) recv.Tick(50) recv.Tick(60) recv.Tick(70) recv.Tick(80) recv.Tick(90) require.Equal(t, []uint32{1, 1, 1, 1, 1, 1, 1, 1, 1}, ackNumbers) p = packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(12, packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = 121 recv.Push(p) require.Equal(t, [][2]uint32{ {1, 11}, }, nakNumbers) p = packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(1, packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = 11 recv.Push(p) p = packet.NewPacket(addr) p.Header().PacketSequenceNumber = circular.New(11, packet.MAX_SEQUENCENUMBER) p.Header().PktTsbpdTime = 111 recv.Push(p) recv.Tick(100) require.Equal(t, []uint32{1, 1, 1, 1, 1, 1, 1, 1, 1, 2}, ackNumbers) recv.Tick(110) require.Equal(t, []uint32{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2}, ackNumbers) recv.Tick(120) require.Equal(t, []uint32{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 13}, ackNumbers) recv.Tick(130) require.Equal(t, []uint32{1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 13, 13}, ackNumbers) } ================================================ FILE: congestion/live/send.go ================================================ package live import ( "container/list" "sync" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/congestion" "github.com/datarhei/gosrt/packet" ) // SendConfig is the configuration for the liveSend congestion control type SendConfig struct { InitialSequenceNumber circular.Number DropThreshold uint64 MaxBW int64 InputBW int64 MinInputBW int64 OverheadBW int64 OnDeliver func(p packet.Packet) } // sender implements the Sender interface type sender struct { nextSequenceNumber circular.Number dropThreshold uint64 packetList *list.List lossList *list.List lock sync.RWMutex avgPayloadSize float64 // bytes pktSndPeriod float64 // microseconds maxBW float64 // bytes/s inputBW float64 // bytes/s overheadBW float64 // percent statistics congestion.SendStats probeTime uint64 rate struct { period uint64 // microseconds last uint64 bytes uint64 bytesSent uint64 bytesRetrans uint64 estimatedInputBW float64 // bytes/s estimatedSentBW float64 // bytes/s pktLossRate float64 } deliver func(p packet.Packet) } // NewSender takes a SendConfig and returns a new Sender func NewSender(config SendConfig) congestion.Sender { s := &sender{ nextSequenceNumber: config.InitialSequenceNumber, dropThreshold: config.DropThreshold, packetList: list.New(), lossList: list.New(), avgPayloadSize: packet.MAX_PAYLOAD_SIZE, // 5.1.2. SRT's Default LiveCC Algorithm maxBW: float64(config.MaxBW), inputBW: float64(config.InputBW), overheadBW: float64(config.OverheadBW), deliver: config.OnDeliver, } if s.deliver == nil { s.deliver = func(p packet.Packet) {} } s.maxBW = 128 * 1024 * 1024 // 1 Gbit/s s.pktSndPeriod = (s.avgPayloadSize + 16) * 1_000_000 / s.maxBW s.rate.period = uint64(time.Second.Microseconds()) s.rate.last = 0 return s } func (s *sender) Stats() congestion.SendStats { s.lock.Lock() defer s.lock.Unlock() s.statistics.UsPktSndPeriod = s.pktSndPeriod s.statistics.BytePayload = uint64(s.avgPayloadSize) s.statistics.MsBuf = 0 max := s.lossList.Back() min := s.lossList.Front() if max != nil && min != nil { s.statistics.MsBuf = (max.Value.(packet.Packet).Header().PktTsbpdTime - min.Value.(packet.Packet).Header().PktTsbpdTime) / 1_000 } s.statistics.MbpsEstimatedInputBandwidth = s.rate.estimatedInputBW * 8 / 1024 / 1024 s.statistics.MbpsEstimatedSentBandwidth = s.rate.estimatedSentBW * 8 / 1024 / 1024 s.statistics.PktLossRate = s.rate.pktLossRate return s.statistics } func (s *sender) Flush() { s.lock.Lock() defer s.lock.Unlock() s.packetList = s.packetList.Init() s.lossList = s.lossList.Init() } func (s *sender) Push(p packet.Packet) { s.lock.Lock() defer s.lock.Unlock() if p == nil { return } // Give to the packet a sequence number p.Header().PacketSequenceNumber = s.nextSequenceNumber p.Header().PacketPositionFlag = packet.SinglePacket p.Header().OrderFlag = false p.Header().MessageNumber = 1 s.nextSequenceNumber = s.nextSequenceNumber.Inc() pktLen := p.Len() s.statistics.PktBuf++ s.statistics.ByteBuf += pktLen // Input bandwidth calculation s.rate.bytes += pktLen p.Header().Timestamp = uint32(p.Header().PktTsbpdTime & uint64(packet.MAX_TIMESTAMP)) // Every 16th and 17th packet should be sent at the same time in order // for the receiver to determine the link capacity. Not really well // documented in the specs. // PktTsbpdTime is used for the timing of sending the packets. Here we // can modify it because it has already been used to set the packet's // timestamp. probe := p.Header().PacketSequenceNumber.Val() & 0xF if probe == 0 { s.probeTime = p.Header().PktTsbpdTime } else if probe == 1 { p.Header().PktTsbpdTime = s.probeTime } s.packetList.PushBack(p) s.statistics.PktFlightSize = uint64(s.packetList.Len()) } func (s *sender) Tick(now uint64) { // Deliver packets whose PktTsbpdTime is ripe s.lock.Lock() removeList := make([]*list.Element, 0, s.packetList.Len()) for e := s.packetList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) if p.Header().PktTsbpdTime <= now { s.statistics.Pkt++ s.statistics.PktUnique++ pktLen := p.Len() s.statistics.Byte += pktLen s.statistics.ByteUnique += pktLen s.statistics.UsSndDuration += uint64(s.pktSndPeriod) // 5.1.2. SRT's Default LiveCC Algorithm s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(pktLen) s.rate.bytesSent += pktLen s.deliver(p) removeList = append(removeList, e) } else { break } } for _, e := range removeList { s.lossList.PushBack(e.Value) s.packetList.Remove(e) } s.lock.Unlock() s.lock.Lock() removeList = make([]*list.Element, 0, s.lossList.Len()) for e := s.lossList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) if p.Header().PktTsbpdTime+s.dropThreshold <= now { // Dropped packet because too old s.statistics.PktDrop++ s.statistics.PktLoss++ s.statistics.ByteDrop += p.Len() s.statistics.ByteLoss += p.Len() removeList = append(removeList, e) } } // These packets are not needed anymore (too late) for _, e := range removeList { p := e.Value.(packet.Packet) s.statistics.PktBuf-- s.statistics.ByteBuf -= p.Len() s.lossList.Remove(e) // This packet has been ACK'd and we don't need it anymore p.Decommission() } s.lock.Unlock() s.lock.Lock() tdiff := now - s.rate.last if tdiff > s.rate.period { s.rate.estimatedInputBW = float64(s.rate.bytes) / (float64(tdiff) / 1000 / 1000) s.rate.estimatedSentBW = float64(s.rate.bytesSent) / (float64(tdiff) / 1000 / 1000) if s.rate.bytesSent != 0 { s.rate.pktLossRate = float64(s.rate.bytesRetrans) / float64(s.rate.bytesSent) * 100 } else { s.rate.pktLossRate = 0 } s.rate.bytes = 0 s.rate.bytesSent = 0 s.rate.bytesRetrans = 0 s.rate.last = now } s.lock.Unlock() } func (s *sender) ACK(sequenceNumber circular.Number) { s.lock.Lock() defer s.lock.Unlock() removeList := make([]*list.Element, 0, s.lossList.Len()) for e := s.lossList.Front(); e != nil; e = e.Next() { p := e.Value.(packet.Packet) if p.Header().PacketSequenceNumber.Lt(sequenceNumber) { // Remove packet from buffer because it has been successfully transmitted removeList = append(removeList, e) } else { break } } // These packets are not needed anymore (ACK'd) for _, e := range removeList { p := e.Value.(packet.Packet) s.statistics.PktBuf-- s.statistics.ByteBuf -= p.Len() s.lossList.Remove(e) // This packet has been ACK'd and we don't need it anymore p.Decommission() } s.pktSndPeriod = (s.avgPayloadSize + 16) * 1000000 / s.maxBW } func (s *sender) NAK(sequenceNumbers []circular.Number) { if len(sequenceNumbers) == 0 { return } s.lock.Lock() defer s.lock.Unlock() for e := s.lossList.Back(); e != nil; e = e.Prev() { p := e.Value.(packet.Packet) for i := 0; i < len(sequenceNumbers); i += 2 { if p.Header().PacketSequenceNumber.Gte(sequenceNumbers[i]) && p.Header().PacketSequenceNumber.Lte(sequenceNumbers[i+1]) { s.statistics.PktRetrans++ s.statistics.Pkt++ s.statistics.PktLoss++ s.statistics.ByteRetrans += p.Len() s.statistics.Byte += p.Len() s.statistics.ByteLoss += p.Len() // 5.1.2. SRT's Default LiveCC Algorithm s.avgPayloadSize = 0.875*s.avgPayloadSize + 0.125*float64(p.Len()) s.rate.bytesSent += p.Len() s.rate.bytesRetrans += p.Len() p.Header().RetransmittedPacketFlag = true s.deliver(p) } } } } func (s *sender) SetDropThreshold(threshold uint64) { s.lock.Lock() defer s.lock.Unlock() s.dropThreshold = threshold } ================================================ FILE: congestion/live/send_test.go ================================================ package live import ( "net" "testing" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/require" ) func mockLiveSend(onDeliver func(p packet.Packet)) *sender { send := NewSender(SendConfig{ InitialSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), DropThreshold: 10, OnDeliver: onDeliver, }) return send.(*sender) } func TestSendSequence(t *testing.T) { numbers := []uint32{} send := mockLiveSend(func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) }) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PktTsbpdTime = uint64(i + 1) send.Push(p) } send.Tick(5) require.Exactly(t, []uint32{0, 1, 2, 3, 4}, numbers) send.Tick(10) require.Exactly(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, numbers) } func TestSendLossListACK(t *testing.T) { send := mockLiveSend(nil) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PktTsbpdTime = uint64(i + 1) send.Push(p) } send.Tick(10) require.Equal(t, 10, send.lossList.Len()) for i := range 10 { send.ACK(circular.New(uint32(i+1), packet.MAX_SEQUENCENUMBER)) require.Equal(t, 10-(i+1), send.lossList.Len()) } } func TestSendRetransmit(t *testing.T) { numbers := []uint32{} nRetransmit := 0 send := mockLiveSend(func(p packet.Packet) { numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) if p.Header().RetransmittedPacketFlag { nRetransmit++ } }) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PktTsbpdTime = uint64(i + 1) send.Push(p) } send.Tick(10) require.Equal(t, 0, nRetransmit) send.NAK([]circular.Number{ circular.New(2, packet.MAX_SEQUENCENUMBER), circular.New(2, packet.MAX_SEQUENCENUMBER), }) require.Equal(t, 1, nRetransmit) send.NAK([]circular.Number{ circular.New(5, packet.MAX_SEQUENCENUMBER), circular.New(7, packet.MAX_SEQUENCENUMBER), }) require.Equal(t, 4, nRetransmit) } func TestSendDrop(t *testing.T) { send := mockLiveSend(nil) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PktTsbpdTime = uint64(i + 1) send.Push(p) } send.Tick(10) require.Equal(t, 10, send.lossList.Len()) send.Tick(20) require.Equal(t, 0, send.lossList.Len()) } func TestSendFlush(t *testing.T) { send := mockLiveSend(nil) addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") for i := range 10 { p := packet.NewPacket(addr) p.Header().PktTsbpdTime = uint64(i + 1) send.Push(p) } require.Exactly(t, 10, send.packetList.Len()) require.Exactly(t, 0, send.lossList.Len()) send.Tick(5) require.Exactly(t, 5, send.packetList.Len()) require.Exactly(t, 5, send.lossList.Len()) send.Flush() require.Exactly(t, 0, send.packetList.Len()) require.Exactly(t, 0, send.lossList.Len()) } ================================================ FILE: conn_request.go ================================================ package srt import ( "fmt" "net" "time" "github.com/datarhei/gosrt/crypto" "github.com/datarhei/gosrt/packet" "github.com/datarhei/gosrt/rand" ) // ConnRequest is an incoming connection request type ConnRequest interface { // RemoteAddr returns the address of the peer. The returned net.Addr // is a copy and can be used at will. RemoteAddr() net.Addr // Version returns the handshake version of the incoming request. Currently // known versions are 4 and 5. With version 4 the StreamId will always be // empty and IsEncrypted will always return false. An incoming version 4 // connection will always be publishing. Version() uint32 // StreamId returns the streamid of the requesting connection. Use this // to decide what to do with the connection. StreamId() string // SocketId return the socketid of the connection. SocketId() uint32 // PeerSocketId returns the socketid of the peer of the connection. PeerSocketId() uint32 // IsEncrypted returns whether the connection is encrypted. If it is // encrypted, use SetPassphrase to set the passphrase for decrypting. IsEncrypted() bool // SetPassphrase sets the passphrase in order to decrypt the incoming // data. Returns an error if the passphrase did not work or the connection // is not encrypted. SetPassphrase(p string) error // SetRejectionReason sets the rejection reason for the connection. If // no set, REJ_PEER will be used. // // Deprecated: replaced by Reject(). SetRejectionReason(r RejectionReason) // Accept accepts the request and returns a connection. Accept() (Conn, error) // Reject rejects the request. Reject(r RejectionReason) } // connRequest implements the ConnRequest interface type connRequest struct { ln *listener addr net.Addr localAddr net.Addr start time.Time socketId uint32 peerSocketId uint32 timestamp uint32 config Config handshake *packet.CIFHandshake crypto crypto.Crypto passphrase string rejectionReason RejectionReason } func newConnRequest(ln *listener, p packet.Packet) *connRequest { cif := &packet.CIFHandshake{} err := p.UnmarshalCIF(cif) ln.log("handshake:recv:dump", func() string { return p.Dump() }) ln.log("handshake:recv:cif", func() string { return cif.String() }) if err != nil { ln.log("handshake:recv:error", func() string { return err.Error() }) return nil } // Assemble the response (4.3.1. Caller-Listener Handshake) p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(ln.start).Microseconds()) p.Header().DestinationSocketId = cif.SRTSocketId cif.PeerIP.FromNetAddr(ln.addr) // Create a copy of the configuration for the connection config := ln.config if cif.HandshakeType == packet.HSTYPE_INDUCTION { // cif cif.Version = 5 cif.EncryptionField = 0 // Don't advertise any specific encryption method cif.ExtensionField = 0x4A17 //cif.initialPacketSequenceNumber = newCircular(0, MAX_SEQUENCENUMBER) //cif.maxTransmissionUnitSize = 0 //cif.maxFlowWindowSize = 0 //cif.SRTSocketId = 0 cif.SynCookie = ln.syncookie.Get(p.Header().Addr.String()) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) } else if cif.HandshakeType == packet.HSTYPE_CONCLUSION { // Verify the SYN cookie if !ln.syncookie.Verify(cif.SynCookie, p.Header().Addr.String()) { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "invalid SYN cookie" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // Peer is advertising a too big MSS if cif.MaxTransmissionUnitSize > MAX_MSS_SIZE { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("MTU is too big (%d bytes)", cif.MaxTransmissionUnitSize) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // If the peer has a smaller MTU size, adjust to it if cif.MaxTransmissionUnitSize < config.MSS { config.MSS = cif.MaxTransmissionUnitSize config.PayloadSize = config.MSS - SRT_HEADER_SIZE - UDP_HEADER_SIZE if config.PayloadSize < MIN_PAYLOAD_SIZE { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("payload size is too small (%d bytes)", config.PayloadSize) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) } } // We only support HSv4 and HSv5 if cif.Version == 4 { // Check if the type (encryption field + extension field) has the value 2 if cif.EncryptionField != 0 || cif.ExtensionField != 2 { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "invalid type, expecting a value of 2 (UDT_DGRAM)" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } } else if cif.Version == 5 { if cif.SRTHS == nil { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "missing handshake extension" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // Check if the peer version is sufficient if cif.SRTHS.SRTVersion < config.MinVersion { cif.HandshakeType = packet.HandshakeType(REJ_VERSION) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("peer version insufficient (%#06x), expecting at least %#06x", cif.SRTHS.SRTVersion, config.MinVersion) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // Check the required SRT flags if !cif.SRTHS.SRTFlags.TSBPDSND || !cif.SRTHS.SRTFlags.TSBPDRCV || !cif.SRTHS.SRTFlags.TLPKTDROP || !cif.SRTHS.SRTFlags.PERIODICNAK || !cif.SRTHS.SRTFlags.REXMITFLG { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return "not all required flags are set" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // We only support live streaming if cif.SRTHS.SRTFlags.STREAM { cif.HandshakeType = packet.HandshakeType(REJ_MESSAGEAPI) ln.log("handshake:recv:error", func() string { return "only live streaming is supported" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } // We only support live congestion control if cif.HasCongestionCtl && cif.CongestionCtl != "live" { cif.HandshakeType = packet.HandshakeType(REJ_CONGESTION) ln.log("handshake:recv:error", func() string { return "only live congestion control is supported" }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } } else { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("only HSv4 and HSv5 are supported (got HSv%d)", cif.Version) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } req := &connRequest{ ln: ln, addr: p.Header().Addr, localAddr: p.Header().LocalAddr, start: time.Now(), peerSocketId: cif.SRTSocketId, timestamp: p.Header().Timestamp, config: config, handshake: cif, } if cif.SRTKM != nil { cr, err := crypto.New(int(cif.SRTKM.KLen)) if err != nil { cif.HandshakeType = packet.HandshakeType(REJ_ROGUE) ln.log("handshake:recv:error", func() string { return fmt.Sprintf("crypto: %s", err) }) p.MarshalCIF(cif) ln.log("handshake:send:dump", func() string { return p.Dump() }) ln.log("handshake:send:cif", func() string { return cif.String() }) ln.send(p) return nil } req.crypto = cr } ln.lock.Lock() // We received a duplicate request: reject silently _, exists := ln.connsByPeer[cif.SRTSocketId] if exists { ln.lock.Unlock() return nil } // Already fill connsByPeer for this connection ln.connsByPeer[cif.SRTSocketId] = nil // Already reserve a socketId for this connection socketId, err := req.generateSocketId() if err == nil { ln.conns[socketId] = nil req.socketId = socketId } ln.lock.Unlock() // We couldn't create a socketId: reject silently if err != nil { return nil } return req } else { if cif.HandshakeType.IsRejection() { ln.log("handshake:recv:error", func() string { return fmt.Sprintf("connection rejected: %s", cif.HandshakeType.String()) }) } else { ln.log("handshake:recv:error", func() string { return fmt.Sprintf("unsupported handshake: %s", cif.HandshakeType.String()) }) } } return nil } func (req *connRequest) RemoteAddr() net.Addr { addr, _ := net.ResolveUDPAddr("udp", req.addr.String()) return addr } func (req *connRequest) Version() uint32 { return req.handshake.Version } func (req *connRequest) StreamId() string { return req.handshake.StreamId } func (req *connRequest) SocketId() uint32 { return req.socketId } func (req *connRequest) PeerSocketId() uint32 { return req.peerSocketId } func (req *connRequest) IsEncrypted() bool { return req.crypto != nil } func (req *connRequest) SetPassphrase(passphrase string) error { if req.handshake.Version == 5 { if req.crypto == nil { return fmt.Errorf("listen: request without encryption") } if err := req.crypto.UnmarshalKM(req.handshake.SRTKM, passphrase); err != nil { return err } } req.passphrase = passphrase return nil } func (req *connRequest) SetRejectionReason(reason RejectionReason) { req.rejectionReason = reason } func (req *connRequest) Reject(reason RejectionReason) { req.ln.lock.Lock() defer req.ln.lock.Unlock() if cr, hasReq := req.ln.connsByPeer[req.peerSocketId]; !hasReq || cr != nil { return } p := packet.NewPacket(req.addr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(req.ln.start).Microseconds()) p.Header().DestinationSocketId = req.peerSocketId p.Header().LocalAddr = req.localAddr req.handshake.HandshakeType = packet.HandshakeType(reason) p.MarshalCIF(req.handshake) req.ln.log("handshake:send:dump", func() string { return p.Dump() }) req.ln.log("handshake:send:cif", func() string { return req.handshake.String() }) req.ln.send(p) delete(req.ln.conns, req.socketId) delete(req.ln.connsByPeer, req.peerSocketId) } // generateSocketId generates an SRT SocketID that can be used for this connection func (req *connRequest) generateSocketId() (uint32, error) { for range 10 { socketId, err := rand.Uint32() if err != nil { return 0, fmt.Errorf("could not generate random socket id") } // check that the socket id is not already in use if _, found := req.ln.conns[socketId]; !found { return socketId, nil } } return 0, fmt.Errorf("could not generate unused socketid") } func (req *connRequest) Accept() (Conn, error) { if req.crypto != nil && len(req.passphrase) == 0 { req.Reject(REJ_BADSECRET) return nil, fmt.Errorf("passphrase is missing") } req.ln.lock.Lock() defer req.ln.lock.Unlock() if cr, hasReq := req.ln.connsByPeer[req.peerSocketId]; !hasReq || cr != nil { return nil, fmt.Errorf("connection already accepted") } // Select the largest TSBPD delay advertised by the caller, but at least 120ms recvTsbpdDelay := uint16(req.config.ReceiverLatency.Milliseconds()) sendTsbpdDelay := uint16(req.config.PeerLatency.Milliseconds()) if req.handshake.Version == 5 { if req.handshake.SRTHS.SendTSBPDDelay > recvTsbpdDelay { recvTsbpdDelay = req.handshake.SRTHS.SendTSBPDDelay } if req.handshake.SRTHS.RecvTSBPDDelay > sendTsbpdDelay { sendTsbpdDelay = req.handshake.SRTHS.RecvTSBPDDelay } req.config.StreamId = req.handshake.StreamId } req.config.Passphrase = req.passphrase localAddr := req.localAddr if localAddr == nil { localAddr = req.ln.addr } // Create a new connection conn := newSRTConn(srtConnConfig{ version: req.handshake.Version, localAddr: localAddr, remoteAddr: req.addr, config: req.config, start: req.start, socketId: req.socketId, peerSocketId: req.peerSocketId, tsbpdTimeBase: uint64(req.timestamp), tsbpdDelay: uint64(recvTsbpdDelay) * 1000, peerTsbpdDelay: uint64(sendTsbpdDelay) * 1000, initialPacketSequenceNumber: req.handshake.InitialPacketSequenceNumber, crypto: req.crypto, keyBaseEncryption: packet.EvenKeyEncrypted, onSend: req.ln.send, onShutdown: req.ln.handleShutdown, logger: req.config.Logger, }) req.ln.log("connection:new", func() string { return fmt.Sprintf("%#08x (%s)", conn.SocketId(), conn.StreamId()) }) req.handshake.SRTSocketId = req.socketId req.handshake.SynCookie = 0 if req.handshake.Version == 5 { // 3.2.1.1.1. Handshake Extension Message Flags req.handshake.SRTHS.SRTVersion = SRT_VERSION req.handshake.SRTHS.SRTFlags.TSBPDSND = true req.handshake.SRTHS.SRTFlags.TSBPDRCV = true req.handshake.SRTHS.SRTFlags.CRYPT = true req.handshake.SRTHS.SRTFlags.TLPKTDROP = true req.handshake.SRTHS.SRTFlags.PERIODICNAK = true req.handshake.SRTHS.SRTFlags.REXMITFLG = true req.handshake.SRTHS.SRTFlags.STREAM = false req.handshake.SRTHS.SRTFlags.PACKET_FILTER = false req.handshake.SRTHS.RecvTSBPDDelay = recvTsbpdDelay req.handshake.SRTHS.SendTSBPDDelay = sendTsbpdDelay } p := packet.NewPacket(req.addr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(req.start).Microseconds()) p.Header().DestinationSocketId = req.peerSocketId p.Header().LocalAddr = req.localAddr p.MarshalCIF(req.handshake) req.ln.log("handshake:send:dump", func() string { return p.Dump() }) req.ln.log("handshake:send:cif", func() string { return req.handshake.String() }) req.ln.send(p) req.ln.conns[req.socketId] = conn req.ln.connsByPeer[req.peerSocketId] = conn return conn, nil } ================================================ FILE: connection.go ================================================ package srt import ( "bytes" "context" "fmt" "io" "math" "net" "strings" "sync" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/congestion" "github.com/datarhei/gosrt/congestion/live" "github.com/datarhei/gosrt/crypto" "github.com/datarhei/gosrt/packet" ) // Conn is a SRT network connection. type Conn interface { // Read reads data from the connection. // Read can be made to time out and return an error after a fixed // time limit; see SetDeadline and SetReadDeadline. Read(p []byte) (int, error) // ReadPacket reads a packet from the queue of received packets. It blocks // if the queue is empty. Only data packets are returned. Using ReadPacket // and Read at the same time may lead to data loss. ReadPacket() (packet.Packet, error) // Write writes data to the connection. // Write can be made to time out and return an error after a fixed // time limit; see SetDeadline and SetWriteDeadline. Write(p []byte) (int, error) // WritePacket writes a packet to the write queue. Packets on the write queue // will be sent to the peer of the connection. Only data packets will be sent. WritePacket(p packet.Packet) error // Close closes the connection. // Any blocked Read or Write operations will be unblocked and return errors. Close() error // LocalAddr returns the local network address. The returned net.Addr is not shared by other invocations of LocalAddr. LocalAddr() net.Addr // RemoteAddr returns the remote network address. The returned net.Addr is not shared by other invocations of RemoteAddr. RemoteAddr() net.Addr SetDeadline(t time.Time) error SetReadDeadline(t time.Time) error SetWriteDeadline(t time.Time) error // SocketId return the socketid of the connection. SocketId() uint32 // PeerSocketId returns the socketid of the peer of the connection. PeerSocketId() uint32 // StreamId returns the streamid use for the connection. StreamId() string // Stats returns accumulated and instantaneous statistics of the connection. Stats(s *Statistics) // Version returns the connection version, either 4 or 5. With version 4, the streamid is not available Version() uint32 } type rtt struct { rtt float64 // microseconds rttVar float64 // microseconds lock sync.RWMutex } func (r *rtt) Recalculate(rtt time.Duration) { // 4.10. Round-Trip Time Estimation lastRTT := float64(rtt.Microseconds()) r.lock.Lock() defer r.lock.Unlock() r.rtt = r.rtt*0.875 + lastRTT*0.125 r.rttVar = r.rttVar*0.75 + math.Abs(r.rtt-lastRTT)*0.25 } func (r *rtt) RTT() float64 { r.lock.RLock() defer r.lock.RUnlock() return r.rtt } func (r *rtt) RTTVar() float64 { r.lock.RLock() defer r.lock.RUnlock() return r.rttVar } func (r *rtt) NAKInterval() float64 { r.lock.RLock() defer r.lock.RUnlock() // 4.8.2. Packet Retransmission (NAKs) nakInterval := (r.rtt + 4*r.rttVar) / 2 if nakInterval < 20000 { nakInterval = 20000 // 20ms } return nakInterval } type connStats struct { headerSize uint64 pktSentACK uint64 pktRecvACK uint64 pktSentACKACK uint64 pktRecvACKACK uint64 pktSentNAK uint64 pktRecvNAK uint64 pktSentKM uint64 pktRecvKM uint64 pktRecvUndecrypt uint64 byteRecvUndecrypt uint64 pktRecvInvalid uint64 pktSentKeepalive uint64 pktRecvKeepalive uint64 pktSentShutdown uint64 pktRecvShutdown uint64 mbpsLinkCapacity float64 } // Check if we implement the net.Conn interface var _ net.Conn = &srtConn{} type srtConn struct { version uint32 isCaller bool // Only relevant if version == 4 localAddr net.Addr remoteAddr net.Addr start time.Time shutdownOnce sync.Once socketId uint32 peerSocketId uint32 config Config crypto crypto.Crypto keyBaseEncryption packet.PacketEncryption kmPreAnnounceCountdown uint64 kmRefreshCountdown uint64 kmConfirmed bool cryptoLock sync.Mutex peerIdleTimeout *time.Timer rtt rtt // microseconds ackLock sync.RWMutex ackNumbers map[uint32]time.Time nextACKNumber circular.Number initialPacketSequenceNumber circular.Number tsbpdTimeBase uint64 // microseconds tsbpdWrapPeriod bool tsbpdTimeBaseOffset uint64 // microseconds tsbpdDelay uint64 // microseconds tsbpdDrift uint64 // microseconds peerTsbpdDelay uint64 // microseconds dropThreshold uint64 // microseconds // Queue for packets that are coming from the network networkQueue chan packet.Packet // Queue for packets that are written with writePacket() and will be send to the network writeQueue chan packet.Packet writeBuffer bytes.Buffer writeData []byte // Queue for packets that will be read locally with ReadPacket() readQueue chan packet.Packet readBuffer bytes.Buffer onSend func(p packet.Packet) onShutdown func(*srtConn) tick time.Duration // Congestion control recv congestion.Receiver snd congestion.Sender // context of all channels and routines ctx context.Context cancelCtx context.CancelFunc statistics connStats statisticsLock sync.RWMutex logger Logger debug struct { expectedRcvPacketSequenceNumber circular.Number expectedReadPacketSequenceNumber circular.Number } // HSv4 stopHSRequests context.CancelFunc stopKMRequests context.CancelFunc } type srtConnConfig struct { version uint32 isCaller bool localAddr net.Addr remoteAddr net.Addr config Config start time.Time socketId uint32 peerSocketId uint32 tsbpdTimeBase uint64 // microseconds tsbpdDelay uint64 // microseconds peerTsbpdDelay uint64 // microseconds initialPacketSequenceNumber circular.Number crypto crypto.Crypto keyBaseEncryption packet.PacketEncryption onSend func(p packet.Packet) onShutdown func(*srtConn) logger Logger } func newSRTConn(config srtConnConfig) *srtConn { c := &srtConn{ version: config.version, isCaller: config.isCaller, localAddr: config.localAddr, remoteAddr: config.remoteAddr, config: config.config, start: config.start, socketId: config.socketId, peerSocketId: config.peerSocketId, tsbpdTimeBase: config.tsbpdTimeBase, tsbpdDelay: config.tsbpdDelay, peerTsbpdDelay: config.peerTsbpdDelay, initialPacketSequenceNumber: config.initialPacketSequenceNumber, crypto: config.crypto, keyBaseEncryption: config.keyBaseEncryption, onSend: config.onSend, onShutdown: config.onShutdown, logger: config.logger, } if c.onSend == nil { c.onSend = func(p packet.Packet) {} } if c.onShutdown == nil { c.onShutdown = func(*srtConn) {} } c.nextACKNumber = circular.New(1, packet.MAX_TIMESTAMP) c.ackNumbers = make(map[uint32]time.Time) c.kmPreAnnounceCountdown = c.config.KMRefreshRate - c.config.KMPreAnnounce c.kmRefreshCountdown = c.config.KMRefreshRate // 4.10. Round-Trip Time Estimation c.rtt = rtt{ rtt: float64((100 * time.Millisecond).Microseconds()), rttVar: float64((50 * time.Millisecond).Microseconds()), } c.networkQueue = make(chan packet.Packet, 1024) c.writeQueue = make(chan packet.Packet, 1024) if c.version == 4 { // libsrt-1.2.3 receiver doesn't like it when the payload is larger than 7*188 bytes. // Here we just take a multiple of a mpegts chunk size. c.writeData = make([]byte, int(c.config.PayloadSize/188*188)) } else { // For v5 we use the max. payload size: https://github.com/Haivision/srt/issues/876 c.writeData = make([]byte, int(c.config.PayloadSize)) } c.readQueue = make(chan packet.Packet, 1024) c.peerIdleTimeout = time.AfterFunc(c.config.PeerIdleTimeout, func() { c.log("connection:close", func() string { return fmt.Sprintf("no more data received from peer for %s. shutting down", c.config.PeerIdleTimeout) }) go c.close() }) c.tick = 10 * time.Millisecond // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) -> periodicACK = 10 milliseconds // 4.8.2. Packet Retransmission (NAKs) -> periodicNAK at least 20 milliseconds c.recv = live.NewReceiver(live.ReceiveConfig{ InitialSequenceNumber: c.initialPacketSequenceNumber, PeriodicACKInterval: 10_000, PeriodicNAKInterval: 20_000, OnSendACK: c.sendACK, OnSendNAK: c.sendNAK, OnDeliver: c.deliver, }) // 4.6. Too-Late Packet Drop -> 125% of SRT latency, at least 1 second // https://github.com/Haivision/srt/blob/master/docs/API/API-socket-options.md#SRTO_SNDDROPDELAY c.dropThreshold = max(uint64(float64(c.peerTsbpdDelay)*1.25)+uint64(c.config.SendDropDelay.Microseconds()), uint64(time.Second.Microseconds())) c.dropThreshold += 20_000 c.snd = live.NewSender(live.SendConfig{ InitialSequenceNumber: c.initialPacketSequenceNumber, DropThreshold: c.dropThreshold, MaxBW: c.config.MaxBW, InputBW: c.config.InputBW, MinInputBW: c.config.MinInputBW, OverheadBW: c.config.OverheadBW, OnDeliver: c.pop, }) c.ctx, c.cancelCtx = context.WithCancel(context.Background()) go c.networkQueueReader(c.ctx) go c.writeQueueReader(c.ctx) go c.ticker(c.ctx) c.debug.expectedRcvPacketSequenceNumber = c.initialPacketSequenceNumber c.debug.expectedReadPacketSequenceNumber = c.initialPacketSequenceNumber c.statistics.headerSize = 8 + 16 // 8 bytes UDP + 16 bytes SRT if strings.Count(c.localAddr.String(), ":") < 2 { c.statistics.headerSize += 20 // 20 bytes IPv4 header } else { c.statistics.headerSize += 40 // 40 bytes IPv6 header } if c.version == 4 && c.isCaller { var hsrequestsCtx context.Context hsrequestsCtx, c.stopHSRequests = context.WithCancel(context.Background()) go c.sendHSRequests(hsrequestsCtx) if c.crypto != nil { var kmrequestsCtx context.Context kmrequestsCtx, c.stopKMRequests = context.WithCancel(context.Background()) go c.sendKMRequests(kmrequestsCtx) } } return c } func (c *srtConn) LocalAddr() net.Addr { if c.localAddr == nil { return nil } addr, _ := net.ResolveUDPAddr("udp", c.localAddr.String()) return addr } func (c *srtConn) RemoteAddr() net.Addr { if c.remoteAddr == nil { return nil } addr, _ := net.ResolveUDPAddr("udp", c.remoteAddr.String()) return addr } func (c *srtConn) SocketId() uint32 { return c.socketId } func (c *srtConn) PeerSocketId() uint32 { return c.peerSocketId } func (c *srtConn) StreamId() string { return c.config.StreamId } func (c *srtConn) Version() uint32 { return c.version } // ticker invokes the congestion control in regular intervals with // the current connection time. func (c *srtConn) ticker(ctx context.Context) { ticker := time.NewTicker(c.tick) defer ticker.Stop() defer func() { c.log("connection:close", func() string { return "left ticker loop" }) }() for { select { case <-ctx.Done(): return case t := <-ticker.C: tickTime := uint64(t.Sub(c.start).Microseconds()) c.recv.Tick(c.tsbpdTimeBase + tickTime) c.snd.Tick(tickTime) } } } func (c *srtConn) ReadPacket() (packet.Packet, error) { var p packet.Packet select { case <-c.ctx.Done(): return nil, io.EOF case p = <-c.readQueue: } if p.Header().PacketSequenceNumber.Gt(c.debug.expectedReadPacketSequenceNumber) { c.log("connection:error", func() string { return fmt.Sprintf("lost packets. got: %d, expected: %d (%d)", p.Header().PacketSequenceNumber.Val(), c.debug.expectedReadPacketSequenceNumber.Val(), c.debug.expectedReadPacketSequenceNumber.Distance(p.Header().PacketSequenceNumber)) }) } else if p.Header().PacketSequenceNumber.Lt(c.debug.expectedReadPacketSequenceNumber) { c.log("connection:error", func() string { return fmt.Sprintf("packet out of order. got: %d, expected: %d (%d)", p.Header().PacketSequenceNumber.Val(), c.debug.expectedReadPacketSequenceNumber.Val(), c.debug.expectedReadPacketSequenceNumber.Distance(p.Header().PacketSequenceNumber)) }) return nil, io.EOF } c.debug.expectedReadPacketSequenceNumber = p.Header().PacketSequenceNumber.Inc() return p, nil } func (c *srtConn) Read(b []byte) (int, error) { if c.readBuffer.Len() != 0 { return c.readBuffer.Read(b) } c.readBuffer.Reset() p, err := c.ReadPacket() if err != nil { return 0, err } c.readBuffer.Write(p.Data()) // The packet is out of congestion control and written to the read buffer p.Decommission() return c.readBuffer.Read(b) } // WritePacket writes a packet to the write queue. Packets on the write queue // will be sent to the peer of the connection. Only data packets will be sent. func (c *srtConn) WritePacket(p packet.Packet) error { if p.Header().IsControlPacket { // Ignore control packets return nil } _, err := c.Write(p.Data()) if err != nil { return err } return nil } func (c *srtConn) Write(b []byte) (int, error) { c.writeBuffer.Write(b) for { n, err := c.writeBuffer.Read(c.writeData) if err != nil { return 0, err } p := packet.NewPacket(nil) p.SetData(c.writeData[:n]) p.Header().IsControlPacket = false // Give the packet a deliver timestamp p.Header().PktTsbpdTime = c.getTimestamp() // Non-blocking write to the write queue select { case <-c.ctx.Done(): return 0, io.EOF case c.writeQueue <- p: default: return 0, io.EOF } if c.writeBuffer.Len() == 0 { break } } c.writeBuffer.Reset() return len(b), nil } // push puts a packet on the network queue. This is where packets go that came in from the network. func (c *srtConn) push(p packet.Packet) { // Non-blocking write to the network queue select { case <-c.ctx.Done(): case c.networkQueue <- p: default: c.log("connection:error", func() string { return "network queue is full" }) } } // getTimestamp returns the elapsed time since the start of the connection in microseconds. func (c *srtConn) getTimestamp() uint64 { return uint64(time.Since(c.start).Microseconds()) } // getTimestampForPacket returns the elapsed time since the start of the connection in // microseconds clamped a 32bit value. func (c *srtConn) getTimestampForPacket() uint32 { return uint32(c.getTimestamp() & uint64(packet.MAX_TIMESTAMP)) } // pop adds the destination address and socketid to the packet and sends it out to the network. // The packet will be encrypted if required. func (c *srtConn) pop(p packet.Packet) { p.Header().Addr = c.remoteAddr p.Header().LocalAddr = c.localAddr p.Header().DestinationSocketId = c.peerSocketId if !p.Header().IsControlPacket { c.cryptoLock.Lock() if c.crypto != nil { p.Header().KeyBaseEncryptionFlag = c.keyBaseEncryption if !p.Header().RetransmittedPacketFlag { c.crypto.EncryptOrDecryptPayload(p.Data(), p.Header().KeyBaseEncryptionFlag, p.Header().PacketSequenceNumber.Val()) } c.kmPreAnnounceCountdown-- c.kmRefreshCountdown-- if c.kmPreAnnounceCountdown == 0 && !c.kmConfirmed { c.sendKMRequest(c.keyBaseEncryption.Opposite()) // Resend the request until we get a response c.kmPreAnnounceCountdown = c.config.KMPreAnnounce/10 + 1 } if c.kmRefreshCountdown == 0 { c.kmPreAnnounceCountdown = c.config.KMRefreshRate - c.config.KMPreAnnounce c.kmRefreshCountdown = c.config.KMRefreshRate // Switch the keys c.keyBaseEncryption = c.keyBaseEncryption.Opposite() c.kmConfirmed = false } if c.kmRefreshCountdown == c.config.KMRefreshRate-c.config.KMPreAnnounce { // Decommission the previous key, resp. create a new SEK that will // be used in the next switch. c.crypto.GenerateSEK(c.keyBaseEncryption.Opposite()) } } c.cryptoLock.Unlock() c.log("data:send:dump", func() string { return p.Dump() }) } // Send the packet on the wire c.onSend(p) } // networkQueueReader reads the packets from the network queue in order to process them. func (c *srtConn) networkQueueReader(ctx context.Context) { defer func() { c.log("connection:close", func() string { return "left network queue reader loop" }) }() for { select { case <-ctx.Done(): return case p := <-c.networkQueue: c.handlePacket(p) } } } // writeQueueReader reads the packets from the write queue and puts them into congestion // control for sending. func (c *srtConn) writeQueueReader(ctx context.Context) { defer func() { c.log("connection:close", func() string { return "left write queue reader loop" }) }() for { select { case <-ctx.Done(): return case p := <-c.writeQueue: // Put the packet into the send congestion control c.snd.Push(p) } } } // deliver writes the packets to the read queue in order to be consumed by the Read function. func (c *srtConn) deliver(p packet.Packet) { // Non-blocking write to the read queue select { case <-c.ctx.Done(): case c.readQueue <- p: default: c.log("connection:error", func() string { return "readQueue was blocking, dropping packet" }) } } // handlePacket checks the packet header. If it is a control packet it will forwarded to the // respective handler. If it is a data packet it will be put into congestion control for // receiving. The packet will be decrypted if required. func (c *srtConn) handlePacket(p packet.Packet) { if p == nil { return } c.peerIdleTimeout.Reset(c.config.PeerIdleTimeout) header := p.Header() if header.IsControlPacket { if header.ControlType == packet.CTRLTYPE_KEEPALIVE { c.handleKeepAlive(p) } else if header.ControlType == packet.CTRLTYPE_SHUTDOWN { c.handleShutdown(p) } else if header.ControlType == packet.CTRLTYPE_NAK { c.handleNAK(p) } else if header.ControlType == packet.CTRLTYPE_ACK { c.handleACK(p) } else if header.ControlType == packet.CTRLTYPE_ACKACK { c.handleACKACK(p) } else if header.ControlType == packet.CTRLTYPE_USER { c.log("connection:recv:ctrl:user", func() string { return fmt.Sprintf("got CTRLTYPE_USER packet, subType: %s", header.SubType) }) // HSv4 Extension if header.SubType == packet.EXTTYPE_HSREQ { c.handleHSRequest(p) } else if header.SubType == packet.EXTTYPE_HSRSP { c.handleHSResponse(p) } // 3.2.2. Key Material if header.SubType == packet.EXTTYPE_KMREQ { c.handleKMRequest(p) } else if header.SubType == packet.EXTTYPE_KMRSP { c.handleKMResponse(p) } } return } if header.PacketSequenceNumber.Gt(c.debug.expectedRcvPacketSequenceNumber) { c.log("connection:error", func() string { return fmt.Sprintf("recv lost packets. got: %d, expected: %d (%d)\n", header.PacketSequenceNumber.Val(), c.debug.expectedRcvPacketSequenceNumber.Val(), c.debug.expectedRcvPacketSequenceNumber.Distance(header.PacketSequenceNumber)) }) } c.debug.expectedRcvPacketSequenceNumber = header.PacketSequenceNumber.Inc() //fmt.Printf("%s\n", p.String()) // Ignore FEC filter control packets // https://github.com/Haivision/srt/blob/master/docs/features/packet-filtering-and-fec.md // "An FEC control packet is distinguished from a regular data packet by having // its message number equal to 0. This value isn't normally used in SRT (message // numbers start from 1, increment to a maximum, and then roll back to 1)." if header.MessageNumber == 0 { c.log("connection:filter", func() string { return "dropped FEC filter control packet" }) return } // 4.5.1.1. TSBPD Time Base Calculation if !c.tsbpdWrapPeriod { if header.Timestamp > packet.MAX_TIMESTAMP-(30*1000000) { c.tsbpdWrapPeriod = true c.log("connection:tsbpd", func() string { return "TSBPD wrapping period started" }) } } else { if header.Timestamp >= (30*1000000) && header.Timestamp <= (60*1000000) { c.tsbpdWrapPeriod = false c.tsbpdTimeBaseOffset += uint64(packet.MAX_TIMESTAMP) + 1 c.log("connection:tsbpd", func() string { return "TSBPD wrapping period finished" }) } } tsbpdTimeBaseOffset := c.tsbpdTimeBaseOffset if c.tsbpdWrapPeriod { if header.Timestamp < (30 * 1000000) { tsbpdTimeBaseOffset += uint64(packet.MAX_TIMESTAMP) + 1 } } header.PktTsbpdTime = c.tsbpdTimeBase + tsbpdTimeBaseOffset + uint64(header.Timestamp) + c.tsbpdDelay + c.tsbpdDrift c.log("data:recv:dump", func() string { return p.Dump() }) c.cryptoLock.Lock() if c.crypto != nil { if header.KeyBaseEncryptionFlag != 0 { if err := c.crypto.EncryptOrDecryptPayload(p.Data(), header.KeyBaseEncryptionFlag, header.PacketSequenceNumber.Val()); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvUndecrypt++ c.statistics.byteRecvUndecrypt += p.Len() c.statisticsLock.Unlock() } } else { c.statisticsLock.Lock() c.statistics.pktRecvUndecrypt++ c.statistics.byteRecvUndecrypt += p.Len() c.statisticsLock.Unlock() } } c.cryptoLock.Unlock() // Put the packet into receive congestion control c.recv.Push(p) } // handleKeepAlive resets the idle timeout and sends a keepalive to the peer. func (c *srtConn) handleKeepAlive(p packet.Packet) { c.log("control:recv:keepalive:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvKeepalive++ c.statistics.pktSentKeepalive++ c.statisticsLock.Unlock() c.peerIdleTimeout.Reset(c.config.PeerIdleTimeout) c.log("control:send:keepalive:dump", func() string { return p.Dump() }) c.pop(p) } // handleShutdown closes the connection func (c *srtConn) handleShutdown(p packet.Packet) { c.log("control:recv:shutdown:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvShutdown++ c.statisticsLock.Unlock() go c.close() } // handleACK forwards the acknowledge sequence number to the congestion control and // returns a ACKACK (on a full ACK). The RTT is also updated in case of a full ACK. func (c *srtConn) handleACK(p packet.Packet) { c.log("control:recv:ACK:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvACK++ c.statisticsLock.Unlock() cif := &packet.CIFACK{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:ACK:error", func() string { return fmt.Sprintf("invalid ACK: %s", err) }) return } c.log("control:recv:ACK:cif", func() string { return cif.String() }) c.snd.ACK(cif.LastACKPacketSequenceNumber) if !cif.IsLite && !cif.IsSmall { // 4.10. Round-Trip Time Estimation c.recalculateRTT(time.Duration(int64(cif.RTT)) * time.Microsecond) // Estimated Link Capacity (from packets/s to Mbps) c.statisticsLock.Lock() c.statistics.mbpsLinkCapacity = float64(cif.EstimatedLinkCapacity) * MAX_PAYLOAD_SIZE * 8 / 1024 / 1024 c.statisticsLock.Unlock() c.sendACKACK(p.Header().TypeSpecific) } } // handleNAK forwards the lost sequence number to the congestion control. func (c *srtConn) handleNAK(p packet.Packet) { c.log("control:recv:NAK:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvNAK++ c.statisticsLock.Unlock() cif := &packet.CIFNAK{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:NAK:error", func() string { return fmt.Sprintf("invalid NAK: %s", err) }) return } c.log("control:recv:NAK:cif", func() string { return cif.String() }) // Inform congestion control about lost packets c.snd.NAK(cif.LostPacketSequenceNumber) } // handleACKACK updates the RTT and NAK interval for the congestion control. func (c *srtConn) handleACKACK(p packet.Packet) { c.ackLock.Lock() c.statisticsLock.Lock() c.statistics.pktRecvACKACK++ c.statisticsLock.Unlock() c.log("control:recv:ACKACK:dump", func() string { return p.Dump() }) // p.typeSpecific is the ACKNumber if ts, ok := c.ackNumbers[p.Header().TypeSpecific]; ok { // 4.10. Round-Trip Time Estimation c.recalculateRTT(time.Since(ts)) delete(c.ackNumbers, p.Header().TypeSpecific) } else { c.log("control:recv:ACKACK:error", func() string { return fmt.Sprintf("got unknown ACKACK (%d)", p.Header().TypeSpecific) }) c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() } for i := range c.ackNumbers { if i < p.Header().TypeSpecific { delete(c.ackNumbers, i) } } c.ackLock.Unlock() c.recv.SetNAKInterval(uint64(c.rtt.NAKInterval())) } // recalculateRTT recalculates the RTT based on a full ACK exchange func (c *srtConn) recalculateRTT(rtt time.Duration) { c.rtt.Recalculate(rtt) c.log("connection:rtt", func() string { return fmt.Sprintf("RTT=%.0fus RTTVar=%.0fus NAKInterval=%.0fms", c.rtt.RTT(), c.rtt.RTTVar(), c.rtt.NAKInterval()/1000) }) } // handleHSRequest handles the HSv4 handshake extension request and sends the response func (c *srtConn) handleHSRequest(p packet.Packet) { c.log("control:recv:HSReq:dump", func() string { return p.Dump() }) cif := &packet.CIFHandshakeExtension{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:HSReq:error", func() string { return fmt.Sprintf("invalid HSReq: %s", err) }) return } c.log("control:recv:HSReq:cif", func() string { return cif.String() }) // Check for version if cif.SRTVersion < 0x010200 || cif.SRTVersion >= 0x010300 { c.log("control:recv:HSReq:error", func() string { return fmt.Sprintf("unsupported version: %#08x", cif.SRTVersion) }) c.close() return } // Check the required SRT flags if !cif.SRTFlags.TSBPDSND { c.log("control:recv:HSRes:error", func() string { return "TSBPDSND flag must be set" }) c.close() return } if !cif.SRTFlags.TLPKTDROP { c.log("control:recv:HSRes:error", func() string { return "TLPKTDROP flag must be set" }) c.close() return } if !cif.SRTFlags.CRYPT { c.log("control:recv:HSRes:error", func() string { return "CRYPT flag must be set" }) c.close() return } if !cif.SRTFlags.REXMITFLG { c.log("control:recv:HSRes:error", func() string { return "REXMITFLG flag must be set" }) c.close() return } // we as receiver don't need this cif.SRTFlags.TSBPDSND = false // we as receiver are supporting these cif.SRTFlags.TSBPDRCV = true cif.SRTFlags.PERIODICNAK = true // These flag was introduced in HSv5 and should not be set in HSv4 if cif.SRTFlags.STREAM { c.log("control:recv:HSReq:error", func() string { return "STREAM flag is set" }) c.close() return } if cif.SRTFlags.PACKET_FILTER { c.log("control:recv:HSReq:error", func() string { return "PACKET_FILTER flag is set" }) c.close() return } recvTsbpdDelay := max(cif.SendTSBPDDelay, uint16(c.config.ReceiverLatency.Milliseconds())) c.tsbpdDelay = uint64(recvTsbpdDelay) * 1000 cif.RecvTSBPDDelay = 0 cif.SendTSBPDDelay = recvTsbpdDelay p.MarshalCIF(cif) // Send HS Response p.Header().SubType = packet.EXTTYPE_HSRSP c.pop(p) } // handleHSResponse handles the HSv4 handshake extension response func (c *srtConn) handleHSResponse(p packet.Packet) { c.log("control:recv:HSRes:dump", func() string { return p.Dump() }) cif := &packet.CIFHandshakeExtension{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:HSRes:error", func() string { return fmt.Sprintf("invalid HSRes: %s", err) }) return } c.log("control:recv:HSRes:cif", func() string { return cif.String() }) if c.version == 4 { // Check for version if cif.SRTVersion < 0x010200 || cif.SRTVersion >= 0x010300 { c.log("control:recv:HSRes:error", func() string { return fmt.Sprintf("unsupported version: %#08x", cif.SRTVersion) }) c.close() return } // TSBPDSND is not relevant from the receiver // PERIODICNAK is the sender's decision, we don't care, but will handle them // Check the required SRT flags if !cif.SRTFlags.TSBPDRCV { c.log("control:recv:HSRes:error", func() string { return "TSBPDRCV flag must be set" }) c.close() return } if !cif.SRTFlags.TLPKTDROP { c.log("control:recv:HSRes:error", func() string { return "TLPKTDROP flag must be set" }) c.close() return } if !cif.SRTFlags.CRYPT { c.log("control:recv:HSRes:error", func() string { return "CRYPT flag must be set" }) c.close() return } if !cif.SRTFlags.REXMITFLG { c.log("control:recv:HSRes:error", func() string { return "REXMITFLG flag must be set" }) c.close() return } // These flag was introduced in HSv5 and should not be set in HSv4 if cif.SRTFlags.STREAM { c.log("control:recv:HSReq:error", func() string { return "STREAM flag is set" }) c.close() return } if cif.SRTFlags.PACKET_FILTER { c.log("control:recv:HSReq:error", func() string { return "PACKET_FILTER flag is set" }) c.close() return } sendTsbpdDelay := max(cif.SendTSBPDDelay, uint16(c.config.PeerLatency.Milliseconds())) c.dropThreshold = max(uint64(float64(sendTsbpdDelay)*1.25)+uint64(c.config.SendDropDelay.Microseconds()), uint64(time.Second.Microseconds())) c.dropThreshold += 20_000 c.snd.SetDropThreshold(c.dropThreshold) c.stopHSRequests() } } // handleKMRequest checks if the key material is valid and responds with a KM response. func (c *srtConn) handleKMRequest(p packet.Packet) { c.log("control:recv:KMReq:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvKM++ c.statisticsLock.Unlock() cif := &packet.CIFKeyMaterialExtension{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:KMReq:error", func() string { return fmt.Sprintf("invalid KMReq: %s", err) }) return } c.log("control:recv:KMReq:cif", func() string { return cif.String() }) c.cryptoLock.Lock() if c.version == 4 && c.crypto == nil { cr, err := crypto.New(int(cif.KLen)) if err != nil { c.log("control:recv:KMReq:error", func() string { return fmt.Sprintf("crypto: %s", err) }) c.cryptoLock.Unlock() c.close() return } c.keyBaseEncryption = cif.KeyBasedEncryption.Opposite() c.crypto = cr } if c.crypto == nil { c.log("control:recv:KMReq:error", func() string { return "connection is not encrypted" }) c.cryptoLock.Unlock() return } if cif.KeyBasedEncryption == c.keyBaseEncryption { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:KMReq:error", func() string { return "invalid KM request. wants to reset the key that is already in use" }) c.cryptoLock.Unlock() return } if err := c.crypto.UnmarshalKM(cif, c.config.Passphrase); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:KMReq:error", func() string { return fmt.Sprintf("invalid KMReq: %s", err) }) c.cryptoLock.Unlock() return } // Switch the keys c.keyBaseEncryption = c.keyBaseEncryption.Opposite() c.cryptoLock.Unlock() // Send KM Response p.Header().SubType = packet.EXTTYPE_KMRSP c.statisticsLock.Lock() c.statistics.pktSentKM++ c.statisticsLock.Unlock() c.pop(p) } // handleKMResponse confirms the change of encryption keys. func (c *srtConn) handleKMResponse(p packet.Packet) { c.log("control:recv:KMRes:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktRecvKM++ c.statisticsLock.Unlock() cif := &packet.CIFKeyMaterialExtension{} if err := p.UnmarshalCIF(cif); err != nil { c.statisticsLock.Lock() c.statistics.pktRecvInvalid++ c.statisticsLock.Unlock() c.log("control:recv:KMRes:error", func() string { return fmt.Sprintf("invalid KMRes: %s", err) }) return } c.cryptoLock.Lock() defer c.cryptoLock.Unlock() if c.crypto == nil { c.log("control:recv:KMRes:error", func() string { return "connection is not encrypted" }) return } if c.version == 4 { c.stopKMRequests() if cif.Error != 0 { if cif.Error == packet.KM_NOSECRET { c.log("control:recv:KMRes:error", func() string { return "peer didn't enabled encryption" }) } else if cif.Error == packet.KM_BADSECRET { c.log("control:recv:KMRes:error", func() string { return "peer has a different passphrase" }) } c.close() return } } c.log("control:recv:KMRes:cif", func() string { return cif.String() }) if c.kmPreAnnounceCountdown >= c.config.KMPreAnnounce { c.log("control:recv:KMRes:error", func() string { return "not in pre-announce period, ignored" }) // Ignore the response, we're not in the pre-announce period return } c.kmConfirmed = true } // sendShutdown sends a shutdown packet to the peer. func (c *srtConn) sendShutdown() { p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_SHUTDOWN p.Header().Timestamp = c.getTimestampForPacket() cif := packet.CIFShutdown{} p.MarshalCIF(&cif) c.log("control:send:shutdown:dump", func() string { return p.Dump() }) c.log("control:send:shutdown:cif", func() string { return cif.String() }) c.statisticsLock.Lock() c.statistics.pktSentShutdown++ c.statisticsLock.Unlock() c.pop(p) } // sendNAK sends a NAK to the peer with the given range of sequence numbers. func (c *srtConn) sendNAK(list []circular.Number) { p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_NAK p.Header().Timestamp = c.getTimestampForPacket() cif := packet.CIFNAK{} cif.LostPacketSequenceNumber = append(cif.LostPacketSequenceNumber, list...) p.MarshalCIF(&cif) c.log("control:send:NAK:dump", func() string { return p.Dump() }) c.log("control:send:NAK:cif", func() string { return cif.String() }) c.statisticsLock.Lock() c.statistics.pktSentNAK++ c.statisticsLock.Unlock() c.pop(p) } // sendACK sends an ACK to the peer with the given sequence number. func (c *srtConn) sendACK(seq circular.Number, lite bool) { p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_ACK p.Header().Timestamp = c.getTimestampForPacket() cif := packet.CIFACK{ LastACKPacketSequenceNumber: seq, } c.ackLock.Lock() defer c.ackLock.Unlock() if lite { cif.IsLite = true p.Header().TypeSpecific = 0 } else { pps, bps, capacity := c.recv.PacketRate() cif.RTT = uint32(c.rtt.RTT()) cif.RTTVar = uint32(c.rtt.RTTVar()) cif.AvailableBufferSize = c.config.FC // TODO: available buffer size (packets) cif.PacketsReceivingRate = uint32(pps) // packets receiving rate (packets/s) cif.EstimatedLinkCapacity = uint32(capacity) // estimated link capacity (packets/s), not relevant for live mode cif.ReceivingRate = uint32(bps) // receiving rate (bytes/s), not relevant for live mode p.Header().TypeSpecific = c.nextACKNumber.Val() c.ackNumbers[p.Header().TypeSpecific] = time.Now() c.nextACKNumber = c.nextACKNumber.Inc() if c.nextACKNumber.Val() == 0 { c.nextACKNumber = c.nextACKNumber.Inc() } } p.MarshalCIF(&cif) c.log("control:send:ACK:dump", func() string { return p.Dump() }) c.log("control:send:ACK:cif", func() string { return cif.String() }) c.statisticsLock.Lock() c.statistics.pktSentACK++ c.statisticsLock.Unlock() c.pop(p) } // sendACKACK sends an ACKACK to the peer with the given ACK sequence. func (c *srtConn) sendACKACK(ackSequence uint32) { p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_ACKACK p.Header().Timestamp = c.getTimestampForPacket() p.Header().TypeSpecific = ackSequence c.log("control:send:ACKACK:dump", func() string { return p.Dump() }) c.statisticsLock.Lock() c.statistics.pktSentACKACK++ c.statisticsLock.Unlock() c.pop(p) } func (c *srtConn) sendHSRequests(ctx context.Context) { ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() select { case <-ctx.Done(): return case <-ticker.C: c.sendHSRequest() } } func (c *srtConn) sendHSRequest() { cif := &packet.CIFHandshakeExtension{ SRTVersion: 0x00010203, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, // we send in TSBPD mode TSBPDRCV: false, // not relevant for us as sender CRYPT: true, // must be always set TLPKTDROP: true, // must be set in live mode PERIODICNAK: false, // not relevant for us as sender REXMITFLG: true, // must alwasy be set STREAM: false, // has been introducet in HSv5 PACKET_FILTER: false, // has been introducet in HSv5 }, RecvTSBPDDelay: 0, SendTSBPDDelay: uint16(c.config.ReceiverLatency.Milliseconds()), } p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_USER p.Header().SubType = packet.EXTTYPE_HSREQ p.Header().Timestamp = c.getTimestampForPacket() p.MarshalCIF(cif) c.log("control:send:HSReq:dump", func() string { return p.Dump() }) c.log("control:send:HSReq:cif", func() string { return cif.String() }) c.pop(p) } func (c *srtConn) sendKMRequests(ctx context.Context) { ticker := time.NewTicker(500 * time.Millisecond) defer ticker.Stop() select { case <-ctx.Done(): return case <-ticker.C: c.sendKMRequest(c.keyBaseEncryption) } } // sendKMRequest sends a KM request to the peer. func (c *srtConn) sendKMRequest(key packet.PacketEncryption) { if c.crypto == nil { c.log("control:send:KMReq:error", func() string { return "connection is not encrypted" }) return } cif := &packet.CIFKeyMaterialExtension{} c.crypto.MarshalKM(cif, c.config.Passphrase, key) p := packet.NewPacket(c.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_USER p.Header().SubType = packet.EXTTYPE_KMREQ p.Header().Timestamp = c.getTimestampForPacket() p.MarshalCIF(cif) c.log("control:send:KMReq:dump", func() string { return p.Dump() }) c.log("control:send:KMReq:cif", func() string { return cif.String() }) c.statisticsLock.Lock() c.statistics.pktSentKM++ c.statisticsLock.Unlock() c.pop(p) } // Close closes the connection. func (c *srtConn) Close() error { c.close() return nil } // close closes the connection. func (c *srtConn) close() { c.shutdownOnce.Do(func() { c.log("connection:close", func() string { return "stopping peer idle timeout" }) c.peerIdleTimeout.Stop() c.log("connection:close", func() string { return "sending shutdown message to peer" }) c.sendShutdown() c.log("connection:close", func() string { return "stopping all routines and channels" }) c.cancelCtx() c.log("connection:close", func() string { return "flushing congestion" }) c.snd.Flush() c.recv.Flush() c.log("connection:close", func() string { return "shutdown" }) go func() { c.onShutdown(c) }() }) } func (c *srtConn) log(topic string, message func() string) { c.logger.Print(topic, c.socketId, 2, message) } func (c *srtConn) SetDeadline(t time.Time) error { return nil } func (c *srtConn) SetReadDeadline(t time.Time) error { return nil } func (c *srtConn) SetWriteDeadline(t time.Time) error { return nil } func (c *srtConn) Stats(s *Statistics) { if s == nil { return } now := uint64(time.Since(c.start).Milliseconds()) send := c.snd.Stats() recv := c.recv.Stats() previous := s.Accumulated interval := now - s.MsTimeStamp c.statisticsLock.RLock() defer c.statisticsLock.RUnlock() // Accumulated s.Accumulated = StatisticsAccumulated{ PktSent: send.Pkt, PktRecv: recv.Pkt, PktSentUnique: send.PktUnique, PktRecvUnique: recv.PktUnique, PktSendLoss: send.PktLoss, PktRecvLoss: recv.PktLoss, PktRetrans: send.PktRetrans, PktRecvRetrans: recv.PktRetrans, PktSentACK: c.statistics.pktSentACK, PktRecvACK: c.statistics.pktRecvACK, PktSentNAK: c.statistics.pktSentNAK, PktRecvNAK: c.statistics.pktRecvNAK, PktSentKM: c.statistics.pktSentKM, PktRecvKM: c.statistics.pktRecvKM, UsSndDuration: send.UsSndDuration, PktSendDrop: send.PktDrop, PktRecvDrop: recv.PktDrop, PktRecvUndecrypt: c.statistics.pktRecvUndecrypt, ByteSent: send.Byte + (send.Pkt * c.statistics.headerSize), ByteRecv: recv.Byte + (recv.Pkt * c.statistics.headerSize), ByteSentUnique: send.ByteUnique + (send.PktUnique * c.statistics.headerSize), ByteRecvUnique: recv.ByteUnique + (recv.PktUnique * c.statistics.headerSize), ByteRecvLoss: recv.ByteLoss + (recv.PktLoss * c.statistics.headerSize), ByteRetrans: send.ByteRetrans + (send.PktRetrans * c.statistics.headerSize), ByteRecvRetrans: recv.ByteRetrans + (recv.PktRetrans * c.statistics.headerSize), ByteSendDrop: send.ByteDrop + (send.PktDrop * c.statistics.headerSize), ByteRecvDrop: recv.ByteDrop + (recv.PktDrop * c.statistics.headerSize), ByteRecvUndecrypt: c.statistics.byteRecvUndecrypt + (c.statistics.pktRecvUndecrypt * c.statistics.headerSize), } // Interval s.Interval = StatisticsInterval{ MsInterval: interval, PktSent: s.Accumulated.PktSent - previous.PktSent, PktRecv: s.Accumulated.PktRecv - previous.PktRecv, PktSentUnique: s.Accumulated.PktSentUnique - previous.PktSentUnique, PktRecvUnique: s.Accumulated.PktRecvUnique - previous.PktRecvUnique, PktSendLoss: s.Accumulated.PktSendLoss - previous.PktSendLoss, PktRecvLoss: s.Accumulated.PktRecvLoss - previous.PktRecvLoss, PktRetrans: s.Accumulated.PktRetrans - previous.PktRetrans, PktRecvRetrans: s.Accumulated.PktRecvRetrans - previous.PktRecvRetrans, PktSentACK: s.Accumulated.PktSentACK - previous.PktSentACK, PktRecvACK: s.Accumulated.PktRecvACK - previous.PktRecvACK, PktSentNAK: s.Accumulated.PktSentNAK - previous.PktSentNAK, PktRecvNAK: s.Accumulated.PktRecvNAK - previous.PktRecvNAK, MbpsSendRate: float64(s.Accumulated.ByteSent-previous.ByteSent) * 8 / 1024 / 1024 / (float64(interval) / 1000), MbpsRecvRate: float64(s.Accumulated.ByteRecv-previous.ByteRecv) * 8 / 1024 / 1024 / (float64(interval) / 1000), UsSndDuration: s.Accumulated.UsSndDuration - previous.UsSndDuration, PktReorderDistance: 0, PktRecvBelated: s.Accumulated.PktRecvBelated - previous.PktRecvBelated, PktSndDrop: s.Accumulated.PktSendDrop - previous.PktSendDrop, PktRecvDrop: s.Accumulated.PktRecvDrop - previous.PktRecvDrop, PktRecvUndecrypt: s.Accumulated.PktRecvUndecrypt - previous.PktRecvUndecrypt, ByteSent: s.Accumulated.ByteSent - previous.ByteSent, ByteRecv: s.Accumulated.ByteRecv - previous.ByteRecv, ByteSentUnique: s.Accumulated.ByteSentUnique - previous.ByteSentUnique, ByteRecvUnique: s.Accumulated.ByteRecvUnique - previous.ByteRecvUnique, ByteRecvLoss: s.Accumulated.ByteRecvLoss - previous.ByteRecvLoss, ByteRetrans: s.Accumulated.ByteRetrans - previous.ByteRetrans, ByteRecvRetrans: s.Accumulated.ByteRecvRetrans - previous.ByteRecvRetrans, ByteRecvBelated: s.Accumulated.ByteRecvBelated - previous.ByteRecvBelated, ByteSendDrop: s.Accumulated.ByteSendDrop - previous.ByteSendDrop, ByteRecvDrop: s.Accumulated.ByteRecvDrop - previous.ByteRecvDrop, ByteRecvUndecrypt: s.Accumulated.ByteRecvUndecrypt - previous.ByteRecvUndecrypt, } // Instantaneous s.Instantaneous = StatisticsInstantaneous{ UsPktSendPeriod: send.UsPktSndPeriod, PktFlowWindow: uint64(c.config.FC), PktFlightSize: send.PktFlightSize, MsRTT: c.rtt.RTT() / 1000, MbpsSentRate: send.MbpsEstimatedSentBandwidth, MbpsRecvRate: recv.MbpsEstimatedRecvBandwidth, MbpsLinkCapacity: recv.MbpsEstimatedLinkCapacity, ByteAvailSendBuf: 0, // unlimited ByteAvailRecvBuf: 0, // unlimited MbpsMaxBW: float64(c.config.MaxBW) / 1024 / 1024, ByteMSS: uint64(c.config.MSS), PktSendBuf: send.PktBuf, ByteSendBuf: send.ByteBuf, MsSendBuf: send.MsBuf, MsSendTsbPdDelay: c.peerTsbpdDelay / 1000, PktRecvBuf: recv.PktBuf, ByteRecvBuf: recv.ByteBuf, MsRecvBuf: recv.MsBuf, MsRecvTsbPdDelay: c.tsbpdDelay / 1000, PktReorderTolerance: uint64(c.config.LossMaxTTL), PktRecvAvgBelatedTime: 0, PktSendLossRate: send.PktLossRate, PktRecvLossRate: recv.PktLossRate, } // If we're only sending, the receiver congestion control value for the link capacity is zero, // use the value that we got from the receiver via the ACK packets. if s.Instantaneous.MbpsLinkCapacity == 0 { s.Instantaneous.MbpsLinkCapacity = c.statistics.mbpsLinkCapacity } if c.config.MaxBW < 0 { s.Instantaneous.MbpsMaxBW = -1 } s.MsTimeStamp = now } ================================================ FILE: connection_test.go ================================================ package srt import ( "bytes" "strings" "testing" "time" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEncryption(t *testing.T) { message := "Hello World!" passphrase := "foobarfoobar" channel := NewPubSub(PubSubConfig{}) config := DefaultConfig() config.EnforcedEncryption = true server := Server{ Addr: "127.0.0.1:6003", Config: &config, HandleConnect: func(req ConnRequest) ConnType { if req.IsEncrypted() { if err := req.SetPassphrase(passphrase); err != nil { return REJECT } } streamid := req.StreamId() if streamid == "publish" { return PUBLISH } else if streamid == "subscribe" { return SUBSCRIBE } return REJECT }, HandlePublish: func(conn Conn) { channel.Publish(conn) conn.Close() }, HandleSubscribe: func(conn Conn) { channel.Subscribe(conn) conn.Close() }, } err := server.Listen() require.NoError(t, err) defer server.Shutdown() go func() { err := server.Serve() if err == ErrServerClosed { return } require.NoError(t, err) }() { // Reject connection if wrong password is set config := DefaultConfig() config.StreamId = "subscribe" config.Passphrase = "barfoobarfoo" _, err := Dial("srt", "127.0.0.1:6003", config) require.Error(t, err) } // Test transmitting an encrypted message readerConnected := make(chan struct{}) readerDone := make(chan struct{}) dataReader1 := bytes.Buffer{} go func() { defer close(readerDone) config := DefaultConfig() config.StreamId = "subscribe" config.Passphrase = "foobarfoobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } close(readerConnected) buffer := make([]byte, 2048) for { n, err := conn.Read(buffer) if n != 0 { dataReader1.Write(buffer[:n]) } if err != nil { break } } err = conn.Close() require.NoError(t, err) }() <-readerConnected writerDone := make(chan struct{}) go func() { defer close(writerDone) config := DefaultConfig() config.StreamId = "publish" config.Passphrase = "foobarfoobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } n, err := conn.Write([]byte(message)) if !assert.NoError(t, err) { panic(err.Error()) } assert.Equal(t, 12, n) time.Sleep(3 * time.Second) err = conn.Close() assert.NoError(t, err) }() <-writerDone <-readerDone reader1 := dataReader1.String() require.Equal(t, message, reader1) } // Test for https://github.com/datarhei/gosrt/pull/94 func TestEncryptionRetransmit(t *testing.T) { message := "Hello World!" passphrase := "foobarfoobar" channel := NewPubSub(PubSubConfig{}) config := DefaultConfig() config.EnforcedEncryption = true server := Server{ Addr: "127.0.0.1:6003", Config: &config, HandleConnect: func(req ConnRequest) ConnType { if req.IsEncrypted() { if err := req.SetPassphrase(passphrase); err != nil { return REJECT } } streamid := req.StreamId() if streamid == "publish" { return PUBLISH } else if streamid == "subscribe" { return SUBSCRIBE } return REJECT }, HandlePublish: func(conn Conn) { channel.Publish(conn) conn.Close() }, HandleSubscribe: func(conn Conn) { channel.Subscribe(conn) conn.Close() }, } err := server.Listen() require.NoError(t, err) defer server.Shutdown() go func() { err := server.Serve() if err == ErrServerClosed { return } require.NoError(t, err) }() { // Reject connection if wrong password is set config := DefaultConfig() config.StreamId = "subscribe" config.Passphrase = "barfoobarfoo" _, err := Dial("srt", "127.0.0.1:6003", config) require.Error(t, err) } // Test transmitting an encrypted message readerConnected := make(chan struct{}) readerDone := make(chan struct{}) dataReader1 := bytes.Buffer{} go func() { defer close(readerDone) config := DefaultConfig() config.StreamId = "subscribe" config.Passphrase = "foobarfoobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } close(readerConnected) buffer := make([]byte, 2048) for { n, err := conn.Read(buffer) if n != 0 { dataReader1.Write(buffer[:n]) } if err != nil { break } } err = conn.Close() require.NoError(t, err) }() <-readerConnected writerDone := make(chan struct{}) go func() { defer close(writerDone) config := DefaultConfig() config.StreamId = "publish" config.Passphrase = "foobarfoobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } counter := 0 dialer, _ := conn.(*dialer) originalOnSend := dialer.conn.onSend dialer.conn.onSend = func(p packet.Packet) { if !p.Header().IsControlPacket { // Drop every 2nd original packet if !p.Header().RetransmittedPacketFlag { counter++ if counter%2 == 0 { return } } } originalOnSend(p) } for range 5 { n, err := conn.Write([]byte(message)) if !assert.NoError(t, err) { panic(err.Error()) } assert.Equal(t, 12, n) } time.Sleep(3 * time.Second) err = conn.Close() assert.NoError(t, err) }() <-writerDone <-readerDone reader1 := dataReader1.String() require.Equal(t, message+message+message+message+message, reader1) } func TestEncryptionKeySwap(t *testing.T) { message := "Hello World!" passphrase := "foobarfoobar" channel := NewPubSub(PubSubConfig{}) config := DefaultConfig() config.EnforcedEncryption = true server := Server{ Addr: "127.0.0.1:6003", Config: &config, HandleConnect: func(req ConnRequest) ConnType { if req.IsEncrypted() { if err := req.SetPassphrase(passphrase); err != nil { return REJECT } } streamid := req.StreamId() if streamid == "publish" { return PUBLISH } else if streamid == "subscribe" { return SUBSCRIBE } return REJECT }, HandlePublish: func(conn Conn) { channel.Publish(conn) conn.Close() }, HandleSubscribe: func(conn Conn) { channel.Subscribe(conn) conn.Close() }, } err := server.Listen() require.NoError(t, err) defer server.Shutdown() go func() { err := server.Serve() if err == ErrServerClosed { return } require.NoError(t, err) }() // Test transmitting encrypted messages with key swap in between dataReader1 := bytes.Buffer{} readerConnected := make(chan struct{}) readerDone := make(chan struct{}) go func() { defer close(readerDone) config := DefaultConfig() config.StreamId = "subscribe" config.Passphrase = "foobarfoobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } buffer := make([]byte, 2048) close(readerConnected) for { n, err := conn.Read(buffer) if n != 0 { dataReader1.Write(buffer[:n]) } if err != nil { break } } err = conn.Close() assert.NoError(t, err) }() <-readerConnected writerDone := make(chan struct{}) go func() { defer close(writerDone) config := DefaultConfig() config.StreamId = "publish" config.Passphrase = "foobarfoobar" // Swap encryption key after 50 sent messages config.KMPreAnnounce = 10 config.KMRefreshRate = 30 conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } // Send 150 messages for range 150 { n, err := conn.Write([]byte(message)) if !assert.NoError(t, err) { panic(err.Error()) } assert.Equal(t, 12, n) } time.Sleep(3 * time.Second) err = conn.Close() assert.NoError(t, err) }() <-writerDone <-readerDone reader1 := dataReader1.String() require.Equal(t, strings.Repeat(message, 150), reader1) } func TestStats(t *testing.T) { message := "Hello World!" channel := NewPubSub(PubSubConfig{}) config := DefaultConfig() server := Server{ Addr: "127.0.0.1:6003", Config: &config, HandleConnect: func(req ConnRequest) ConnType { streamid := req.StreamId() if streamid == "publish" { return PUBLISH } else if streamid == "subscribe" { return SUBSCRIBE } return REJECT }, HandlePublish: func(conn Conn) { channel.Publish(conn) conn.Close() }, HandleSubscribe: func(conn Conn) { channel.Subscribe(conn) conn.Close() }, } err := server.Listen() require.NoError(t, err) defer server.Shutdown() go func() { err := server.Serve() if err == ErrServerClosed { return } require.NoError(t, err) }() statsReader := Statistics{} statsWriter := Statistics{} readerConnected := make(chan struct{}) readerDone := make(chan struct{}) dataReader1 := bytes.Buffer{} go func() { defer close(readerDone) config := DefaultConfig() config.StreamId = "subscribe" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } close(readerConnected) buffer := make([]byte, 2048) for { n, err := conn.Read(buffer) if n != 0 { dataReader1.Write(buffer[:n]) } if err != nil { break } } conn.Stats(&statsReader) err = conn.Close() require.NoError(t, err) }() <-readerConnected writerDone := make(chan struct{}) go func() { defer close(writerDone) config := DefaultConfig() config.StreamId = "publish" conn, err := Dial("srt", "127.0.0.1:6003", config) if !assert.NoError(t, err) { panic(err.Error()) } n, err := conn.Write([]byte(message)) if !assert.NoError(t, err) { panic(err.Error()) } assert.Equal(t, 12, n) time.Sleep(3 * time.Second) conn.Stats(&statsWriter) err = conn.Close() assert.NoError(t, err) }() <-writerDone <-readerDone reader1 := dataReader1.String() require.Equal(t, message, reader1) require.Equal(t, uint64(len(message)+44), statsReader.Accumulated.ByteRecv) require.Equal(t, uint64(1), statsReader.Accumulated.PktRecv) require.Equal(t, uint64(len(message)+44), statsWriter.Accumulated.ByteSent) require.Equal(t, uint64(1), statsWriter.Accumulated.PktSent) } ================================================ FILE: contrib/client/main.go ================================================ package main import ( "encoding/json" "flag" "fmt" "io" "net" "net/url" "os" "os/signal" "strconv" "strings" "sync" "time" srt "github.com/datarhei/gosrt" ) type stats struct { bprev uint64 btotal uint64 prev uint64 total uint64 lock sync.Mutex period time.Duration last time.Time } func (s *stats) init(period time.Duration) { s.bprev = 0 s.btotal = 0 s.prev = 0 s.total = 0 s.period = period s.last = time.Now() go s.tick() } func (s *stats) tick() { ticker := time.NewTicker(s.period) defer ticker.Stop() for c := range ticker.C { s.lock.Lock() diff := c.Sub(s.last) bavg := float64(s.btotal-s.bprev) * 8 / (1000 * 1000 * diff.Seconds()) avg := float64(s.total-s.prev) / diff.Seconds() s.bprev = s.btotal s.prev = s.total s.last = c s.lock.Unlock() fmt.Fprintf(os.Stderr, "\r%-54s: %8.3f kpackets (%8.3f packets/s), %8.3f mbytes (%8.3f Mbps)", c, float64(s.total)/1024, avg, float64(s.btotal)/1024/1024, bavg) } } func (s *stats) update(n uint64) { s.lock.Lock() defer s.lock.Unlock() s.btotal += n s.total++ } func main() { var from string var to string var logtopics string flag.StringVar(&from, "from", "", "Address to read from, sources: srt://, udp://, - (stdin)") flag.StringVar(&to, "to", "", "Address to write to, targets: srt://, udp://, file://, - (stdout)") flag.StringVar(&logtopics, "logtopics", "", "topics for the log output") flag.Parse() var logger srt.Logger if len(logtopics) != 0 { logger = srt.NewLogger(strings.Split(logtopics, ",")) } go func() { if logger == nil { return } for m := range logger.Listen() { fmt.Fprintf(os.Stderr, "%#08x %s (in %s:%d)\n%s \n", m.SocketId, m.Topic, m.File, m.Line, m.Message) } }() r, err := openReader(from, logger) if err != nil { fmt.Fprintf(os.Stderr, "Error: from: %v\n", err) flag.PrintDefaults() os.Exit(1) } w, err := openWriter(to, logger) if err != nil { fmt.Fprintf(os.Stderr, "Error: to: %v\n", err) flag.PrintDefaults() os.Exit(1) } doneChan := make(chan error) go func() { buffer := make([]byte, 2048) s := stats{} s.init(200 * time.Millisecond) for { n, err := r.Read(buffer) if err != nil { doneChan <- fmt.Errorf("read: %w", err) return } s.update(uint64(n)) if _, err := w.Write(buffer[:n]); err != nil { doneChan <- fmt.Errorf("write: %w", err) return } } }() go func() { quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) <-quit doneChan <- nil }() if err := <-doneChan; err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) } else { fmt.Fprint(os.Stderr, "\n") } w.Close() if srtconn, ok := w.(srt.Conn); ok { stats := &srt.Statistics{} srtconn.Stats(stats) data, err := json.MarshalIndent(stats, "", " ") if err != nil { fmt.Fprintf(os.Stderr, "writer: %+v\n", stats) } else { fmt.Fprintf(os.Stderr, "writer: %s\n", string(data)) } } r.Close() if srtconn, ok := r.(srt.Conn); ok { stats := &srt.Statistics{} srtconn.Stats(stats) data, err := json.MarshalIndent(stats, "", " ") if err != nil { fmt.Fprintf(os.Stderr, "reader: %+v\n", stats) } else { fmt.Fprintf(os.Stderr, "reader: %s\n", string(data)) } } if logger != nil { logger.Close() } } func openReader(addr string, logger srt.Logger) (io.ReadCloser, error) { if len(addr) == 0 { return nil, fmt.Errorf("the address must not be empty") } if addr == "-" { if os.Stdin == nil { return nil, fmt.Errorf("stdin is not defined") } return os.Stdin, nil } if strings.HasPrefix(addr, "debug://") { readerOptions := DebugReaderOptions{} parts := strings.SplitN(strings.TrimPrefix(addr, "debug://"), "?", 2) if len(parts) > 1 { options, err := url.ParseQuery(parts[1]) if err != nil { return nil, err } if x, err := strconv.ParseUint(options.Get("bitrate"), 10, 64); err == nil { readerOptions.Bitrate = x } } r, err := NewDebugReader(readerOptions) return r, err } u, err := url.Parse(addr) if err != nil { return nil, err } if u.Scheme == "srt" { config := srt.DefaultConfig() if err := config.UnmarshalQuery(u.RawQuery); err != nil { return nil, err } config.Logger = logger mode := u.Query().Get("mode") if mode == "listener" { ln, err := srt.Listen("srt", u.Host, config) if err != nil { return nil, err } conn, _, err := ln.Accept(func(req srt.ConnRequest) srt.ConnType { if config.StreamId != req.StreamId() { return srt.REJECT } req.SetPassphrase(config.Passphrase) return srt.PUBLISH }) if err != nil { return nil, err } if conn == nil { return nil, fmt.Errorf("incoming connection rejected") } return conn, nil } else if mode == "caller" { conn, err := srt.Dial("srt", u.Host, config) if err != nil { return nil, err } return conn, nil } else { return nil, fmt.Errorf("unsupported mode") } } else if u.Scheme == "udp" { laddr, err := net.ResolveUDPAddr("udp", u.Host) if err != nil { return nil, err } conn, err := net.ListenUDP("udp", laddr) if err != nil { return nil, err } return conn, nil } return nil, fmt.Errorf("unsupported reader") } func openWriter(addr string, logger srt.Logger) (io.WriteCloser, error) { if len(addr) == 0 { return nil, fmt.Errorf("the address must not be empty") } if addr == "-" { if os.Stdout == nil { return nil, fmt.Errorf("stdout is not defined") } return NewNonblockingWriter(os.Stdout, 2048), nil } if after, ok := strings.CutPrefix(addr, "file://"); ok { path := after file, err := os.Create(path) if err != nil { return nil, err } return NewNonblockingWriter(file, 2048), nil } u, err := url.Parse(addr) if err != nil { return nil, err } if u.Scheme == "srt" { config := srt.DefaultConfig() if err := config.UnmarshalQuery(u.RawQuery); err != nil { return nil, err } config.Logger = logger mode := u.Query().Get("mode") if mode == "listener" { ln, err := srt.Listen("srt", u.Host, config) if err != nil { return nil, err } conn, _, err := ln.Accept(func(req srt.ConnRequest) srt.ConnType { if config.StreamId != req.StreamId() { return srt.REJECT } req.SetPassphrase(config.Passphrase) return srt.SUBSCRIBE }) if err != nil { return nil, err } if conn == nil { return nil, fmt.Errorf("incoming connection rejected") } return conn, nil } else if mode == "caller" { conn, err := srt.Dial("srt", u.Host, config) if err != nil { return nil, err } return conn, nil } else { return nil, fmt.Errorf("unsupported mode") } } else if u.Scheme == "udp" { raddr, err := net.ResolveUDPAddr("udp", u.Host) if err != nil { return nil, err } conn, err := net.DialUDP("udp", nil, raddr) if err != nil { return nil, err } return conn, nil } return nil, fmt.Errorf("unsupported writer") } ================================================ FILE: contrib/client/reader.go ================================================ package main import ( "context" "io" "time" ) type Reader interface { io.ReadCloser } type debugReader struct { bytesPerSec uint64 cancel context.CancelFunc data chan byte } type DebugReaderOptions struct { Bitrate uint64 } func NewDebugReader(options DebugReaderOptions) (Reader, error) { r := &debugReader{ bytesPerSec: options.Bitrate / 8, } if r.bytesPerSec == 0 { r.bytesPerSec = 262_144 // 2Mbit/s } r.data = make(chan byte, r.bytesPerSec) ctx, cancel := context.WithCancel(context.Background()) r.cancel = cancel go r.generator(ctx) return r, nil } func (r *debugReader) Read(p []byte) (int, error) { len := len(p) if len == 0 { return 0, nil } var i int = 0 for b := range r.data { p[i] = b i += 1 if i == len { break } } return i, nil } func (r *debugReader) Close() error { r.cancel() return nil } func (r *debugReader) generator(ctx context.Context) { t := time.NewTicker(100 * time.Millisecond) defer t.Stop() s := "abcdefghijklmnopqrstuvwxyz*" pivot := 0 defer func() { close(r.data) }() for { select { case <-ctx.Done(): return case <-t.C: for i := uint64(0); i < r.bytesPerSec/10; i += 1 { r.data <- s[pivot] pivot += 1 if pivot >= len(s) { pivot = 0 } } } } } ================================================ FILE: contrib/client/writer.go ================================================ package main import ( "bytes" "io" "sync" "time" ) // NonblockingWriter is a io.Writer and io.Closer that won't block // any writes. If the underlying writer is blocking the data will be // buffered until it's available again. type Writer interface { io.WriteCloser } // nonblockingWriter implements the NonblockingWriter interface type nonblockingWriter struct { dst io.WriteCloser buf *bytes.Buffer lock sync.RWMutex size int done bool } // NewNonblockingWriter return a new NonBlockingWriter with writer as the // underlying writer. The size is the number of bytes to write to the // underlying writer in one iteration. It written as fast as possible to // the underlying writer. If there's no more data available to write // a pause of 10 milliseconds will be done. There's currently no limit // for the amount of data to be buffered. A call of the Close function // will close this writer. The underlying writer will not be closed. In // case there's an error while writing to the underlying writer, this // will close itself. func NewNonblockingWriter(writer io.WriteCloser, size int) Writer { u := &nonblockingWriter{ dst: writer, buf: new(bytes.Buffer), size: size, done: false, } if u.size <= 0 { u.size = 2048 } go u.writer() return u } func (u *nonblockingWriter) Write(p []byte) (int, error) { if u.done { return 0, io.EOF } u.lock.Lock() defer u.lock.Unlock() return u.buf.Write(p) } func (u *nonblockingWriter) Close() error { u.done = true u.dst.Close() return nil } // writer writes to the underlying writer in chunks read from // the buffer. If the buffer is empty, a short pause will be made. func (u *nonblockingWriter) writer() { p := make([]byte, u.size) for { u.lock.RLock() n, err := u.buf.Read(p) u.lock.RUnlock() if n == 0 || err == io.EOF { if u.done { break } time.Sleep(10 * time.Millisecond) continue } if _, err := u.dst.Write(p[:n]); err != nil { break } } u.done = true } ================================================ FILE: contrib/server/main.go ================================================ package main import ( "flag" "fmt" "net" "net/url" "os" "os/signal" "strings" "sync" srt "github.com/datarhei/gosrt" "github.com/pkg/profile" ) // server is an implementation of the Server framework type server struct { // Configuration parameter taken from the Config addr string app string token string passphrase string logtopics string profile string server *srt.Server // Map of publishing channels and a lock to serialize // access to the map. channels map[string]srt.PubSub lock sync.RWMutex } func (s *server) ListenAndServe() error { if len(s.app) == 0 { s.app = "/" } return s.server.ListenAndServe() } func (s *server) Shutdown() { s.server.Shutdown() } func main() { s := server{ channels: make(map[string]srt.PubSub), } flag.StringVar(&s.addr, "addr", "", "address to listen on") flag.StringVar(&s.app, "app", "", "path prefix for streamid") flag.StringVar(&s.token, "token", "", "token query param for streamid") flag.StringVar(&s.passphrase, "passphrase", "", "passphrase for de- and enrcypting the data") flag.StringVar(&s.logtopics, "logtopics", "", "topics for the log output") flag.StringVar(&s.profile, "profile", "", "enable profiling (cpu, mem, allocs, heap, rate, mutex, block, thread, trace)") flag.Parse() if len(s.addr) == 0 { fmt.Fprintf(os.Stderr, "Provide a listen address with -addr\n") os.Exit(1) } var p func(*profile.Profile) switch s.profile { case "cpu": p = profile.CPUProfile case "mem": p = profile.MemProfile case "allocs": p = profile.MemProfileAllocs case "heap": p = profile.MemProfileHeap case "rate": p = profile.MemProfileRate(2048) case "mutex": p = profile.MutexProfile case "block": p = profile.BlockProfile case "thread": p = profile.ThreadcreationProfile case "trace": p = profile.TraceProfile default: } if p != nil { defer profile.Start(profile.ProfilePath("."), profile.NoShutdownHook, p).Stop() } config := srt.DefaultConfig() if len(s.logtopics) != 0 { config.Logger = srt.NewLogger(strings.Split(s.logtopics, ",")) } config.KMPreAnnounce = 200 config.KMRefreshRate = 10000 s.server = &srt.Server{ Addr: s.addr, HandleConnect: s.handleConnect, HandlePublish: s.handlePublish, HandleSubscribe: s.handleSubscribe, Config: &config, } fmt.Fprintf(os.Stderr, "Listening on %s\n", s.addr) go func() { if config.Logger == nil { return } for m := range config.Logger.Listen() { fmt.Fprintf(os.Stderr, "%#08x %s (in %s:%d)\n%s \n", m.SocketId, m.Topic, m.File, m.Line, m.Message) } }() go func() { if err := s.ListenAndServe(); err != nil && err != srt.ErrServerClosed { fmt.Fprintf(os.Stderr, "SRT Server: %s\n", err) os.Exit(2) } }() quit := make(chan os.Signal, 1) signal.Notify(quit, os.Interrupt) <-quit s.Shutdown() if config.Logger != nil { config.Logger.Close() } } func (s *server) log(who, action, path, message string, client net.Addr) { fmt.Fprintf(os.Stderr, "%-10s %10s %s (%s) %s\n", who, action, path, client, message) } func (s *server) handleConnect(req srt.ConnRequest) srt.ConnType { var mode srt.ConnType = srt.SUBSCRIBE client := req.RemoteAddr() channel := "" if req.Version() == 4 { mode = srt.PUBLISH channel = "/" + client.String() req.SetPassphrase(s.passphrase) } else if req.Version() == 5 { streamId := req.StreamId() path := streamId if strings.HasPrefix(streamId, "publish:") { mode = srt.PUBLISH path = strings.TrimPrefix(streamId, "publish:") } else if after, ok := strings.CutPrefix(streamId, "subscribe:"); ok { path = after } u, err := url.Parse(path) if err != nil { return srt.REJECT } if req.IsEncrypted() { if err := req.SetPassphrase(s.passphrase); err != nil { s.log("CONNECT", "FORBIDDEN", u.Path, err.Error(), client) return srt.REJECT } } // Check the token token := u.Query().Get("token") if len(s.token) != 0 && s.token != token { s.log("CONNECT", "FORBIDDEN", u.Path, "invalid token ("+token+")", client) return srt.REJECT } // Check the app patch if !strings.HasPrefix(u.Path, s.app) { s.log("CONNECT", "FORBIDDEN", u.Path, "invalid app", client) return srt.REJECT } if len(strings.TrimPrefix(u.Path, s.app)) == 0 { s.log("CONNECT", "INVALID", u.Path, "stream name not provided", client) return srt.REJECT } channel = u.Path } else { return srt.REJECT } s.lock.RLock() pubsub := s.channels[channel] s.lock.RUnlock() if mode == srt.PUBLISH && pubsub != nil { s.log("CONNECT", "CONFLICT", channel, "already publishing", client) return srt.REJECT } if mode == srt.SUBSCRIBE && pubsub == nil { s.log("CONNECT", "NOTFOUND", channel, "not publishing", client) return srt.REJECT } return mode } func (s *server) handlePublish(conn srt.Conn) { channel := "" client := conn.RemoteAddr() if client == nil { conn.Close() return } if conn.Version() == 4 { channel = "/" + client.String() } else if conn.Version() == 5 { streamId := conn.StreamId() path := strings.TrimPrefix(streamId, "publish:") channel = path } else { s.log("PUBLISH", "INVALID", channel, "unknown connection version", client) conn.Close() return } // Look for the stream s.lock.Lock() pubsub := s.channels[channel] if pubsub == nil { pubsub = srt.NewPubSub(srt.PubSubConfig{ Logger: s.server.Config.Logger, }) s.channels[channel] = pubsub } else { pubsub = nil } s.lock.Unlock() if pubsub == nil { s.log("PUBLISH", "CONFLICT", channel, "already publishing", client) conn.Close() return } s.log("PUBLISH", "START", channel, "publishing", client) pubsub.Publish(conn) s.lock.Lock() delete(s.channels, channel) s.lock.Unlock() s.log("PUBLISH", "STOP", channel, "", client) stats := &srt.Statistics{} conn.Stats(stats) fmt.Fprintf(os.Stderr, "%+v\n", stats) conn.Close() } func (s *server) handleSubscribe(conn srt.Conn) { channel := "" client := conn.RemoteAddr() if client == nil { conn.Close() return } if conn.Version() == 4 { channel = client.String() } else if conn.Version() == 5 { streamId := conn.StreamId() path := strings.TrimPrefix(streamId, "subscribe:") channel = path } else { s.log("SUBSCRIBE", "INVALID", channel, "unknown connection version", client) conn.Close() return } s.log("SUBSCRIBE", "START", channel, "", client) // Look for the stream s.lock.RLock() pubsub := s.channels[channel] s.lock.RUnlock() if pubsub == nil { s.log("SUBSCRIBE", "NOTFOUND", channel, "not publishing", client) conn.Close() return } pubsub.Subscribe(conn) s.log("SUBSCRIBE", "STOP", channel, "", client) stats := &srt.Statistics{} conn.Stats(stats) fmt.Fprintf(os.Stderr, "%+v\n", stats) conn.Close() } ================================================ FILE: crypto/crypto.go ================================================ // Package crypto provides SRT cryptography package crypto import ( "crypto/aes" "crypto/cipher" "crypto/pbkdf2" "crypto/sha1" "encoding/binary" "errors" "fmt" "github.com/datarhei/gosrt/packet" "github.com/datarhei/gosrt/rand" "github.com/benburkert/openpgp/aes/keywrap" ) // Crypto implements the SRT data encryption and decryption. type Crypto interface { // Generate generates an even or odd SEK. GenerateSEK(key packet.PacketEncryption) error // UnmarshalMK unwraps the key with the passphrase in a Key Material Extension Message. If the passphrase // is wrong an error is returned. UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string) error // MarshalKM wraps the key with the passphrase and the odd/even SEK for a Key Material Extension Message. MarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string, key packet.PacketEncryption) error // EncryptOrDecryptPayload encrypts or decrypts the data of a packet with an even or odd SEK and // the sequence number. EncryptOrDecryptPayload(data []byte, key packet.PacketEncryption, packetSequenceNumber uint32) error } // crypto implements the Crypto interface type crypto struct { salt []byte keyLength int evenSEK []byte oddSEK []byte } // New returns a new SRT data encryption and decryption for the keyLength. On failure // error is non-nil. func New(keyLength int) (Crypto, error) { // 3.2.2. Key Material switch keyLength { case 16: case 24: case 32: default: return nil, fmt.Errorf("crypto: invalid key size, must be either 16, 24, or 32") } c := &crypto{ keyLength: keyLength, } // 3.2.2. Key Material: "The only valid length of salt defined is 128 bits." c.salt = make([]byte, 16) if err := c.prng(c.salt); err != nil { return nil, fmt.Errorf("crypto: can't generate salt: %w", err) } sek, err := c.generateSEK(c.keyLength) if err != nil { return nil, err } c.evenSEK = sek sek, err = c.generateSEK(c.keyLength) if err != nil { return nil, err } c.oddSEK = sek return c, nil } func (c *crypto) GenerateSEK(key packet.PacketEncryption) error { if !key.IsValid() { return fmt.Errorf("crypto: unknown key type") } sek, err := c.generateSEK(c.keyLength) if err != nil { return err } switch key { case packet.EvenKeyEncrypted: c.evenSEK = sek case packet.OddKeyEncrypted: c.oddSEK = sek } return nil } func (c *crypto) generateSEK(keyLength int) ([]byte, error) { sek := make([]byte, keyLength) err := c.prng(sek) if err != nil { return nil, fmt.Errorf("crypto: can't generate SEK: %w", err) } return sek, nil } // ErrInvalidKey is returned when the packet encryption is invalid var ErrInvalidKey = errors.New("crypto: invalid key for encryption. Must be even, odd, or both") // ErrInvalidWrap is returned when the packet encryption indicates a different length of the wrapped key var ErrInvalidWrap = errors.New("crypto: the un/wrapped key has the wrong length") func (c *crypto) UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string) error { if km.KeyBasedEncryption == packet.UnencryptedPacket || !km.KeyBasedEncryption.IsValid() { return ErrInvalidKey } n := 1 if km.KeyBasedEncryption == packet.EvenAndOddKey { n = 2 } wrapLength := n * c.keyLength if len(km.Wrap)-8 != wrapLength { return ErrInvalidWrap } if len(km.Salt) != 0 { copy(c.salt, km.Salt) } kek, err := c.calculateKEK(passphrase, c.salt, c.keyLength) if err != nil { return err } unwrap, err := keywrap.Unwrap(kek, km.Wrap) if err != nil { return err } if len(unwrap) != wrapLength { return ErrInvalidWrap } switch km.KeyBasedEncryption { case packet.EvenKeyEncrypted: copy(c.evenSEK, unwrap) case packet.OddKeyEncrypted: copy(c.oddSEK, unwrap) default: copy(c.evenSEK, unwrap[:c.keyLength]) copy(c.oddSEK, unwrap[c.keyLength:]) } return nil } func (c *crypto) MarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string, key packet.PacketEncryption) error { if key == packet.UnencryptedPacket || !key.IsValid() { return ErrInvalidKey } km.S = 0 km.Version = 1 km.PacketType = 2 km.Sign = 0x2029 km.KeyBasedEncryption = key // even or odd key km.KeyEncryptionKeyIndex = 0 km.Cipher = 2 km.Authentication = 0 km.StreamEncapsulation = 2 km.SLen = 16 km.KLen = uint16(c.keyLength) if len(km.Salt) != 16 { km.Salt = make([]byte, 16) } copy(km.Salt, c.salt) n := 1 if key == packet.EvenAndOddKey { n = 2 } w := make([]byte, n*c.keyLength) switch key { case packet.EvenKeyEncrypted: copy(w, c.evenSEK) case packet.OddKeyEncrypted: copy(w, c.oddSEK) default: copy(w[:c.keyLength], c.evenSEK) copy(w[c.keyLength:], c.oddSEK) } kek, err := c.calculateKEK(passphrase, c.salt, c.keyLength) if err != nil { return err } wrap, err := keywrap.Wrap(kek, w) if err != nil { return err } if len(km.Wrap) != len(wrap) { km.Wrap = make([]byte, len(wrap)) } copy(km.Wrap, wrap) return nil } func (c *crypto) EncryptOrDecryptPayload(data []byte, key packet.PacketEncryption, packetSequenceNumber uint32) error { // 6.1.2. AES Counter // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // | 0s | psn | 0 0| // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // XOR // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // | MSB(112, Salt) | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ // // psn (32 bit): packet sequence number // ctr (16 bit): block counter, all zeros // nonce (112 bit): 14 most significant bytes of the salt // // CTR = (MSB(112, Salt) XOR psn) << 16 if len(c.salt) != 16 { return fmt.Errorf("crypto: invalid salt. Must be of length 16 bytes") } ctr := make([]byte, 16) binary.BigEndian.PutUint32(ctr[10:], packetSequenceNumber) for i := range ctr[:14] { ctr[i] ^= c.salt[i] } var sek []byte switch key { case packet.EvenKeyEncrypted: sek = c.evenSEK case packet.OddKeyEncrypted: sek = c.oddSEK default: return fmt.Errorf("crypto: invalid SEK selected. Must be either even or odd") } // 6.2.2. Encrypting the Payload // 6.3.2. Decrypting the Payload block, err := aes.NewCipher(sek) if err != nil { return err } stream := cipher.NewCTR(block, ctr) stream.XORKeyStream(data, data) return nil } // calculateKEK calculates a KEK based on the passphrase. func (c *crypto) calculateKEK(passphrase string, salt []byte, keyLength int) ([]byte, error) { // 6.1.4. Key Encrypting Key (KEK) return pbkdf2.Key(sha1.New, passphrase, salt[8:], 2048, keyLength) } // prng generates a random sequence of byte into the given slice p. func (c *crypto) prng(p []byte) error { _, err := rand.Read(p) return err } ================================================ FILE: crypto/crypto_test.go ================================================ package crypto import ( "bytes" "encoding/hex" "testing" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/require" ) func mustDecodeString(s string) []byte { b, err := hex.DecodeString(s) if err != nil { panic(err) } return b } func TestInvalidKeylength(t *testing.T) { _, err := New(42) require.Error(t, err, "succeeded to create crypto with invalid keylength") } func TestInvalidKM(t *testing.T) { c, err := New(16) require.NoError(t, err) km := &packet.CIFKeyMaterialExtension{} km.KeyBasedEncryption = packet.UnencryptedPacket km.Salt = mustDecodeString("6c438852715a4d26e0e810b3132ca61f") km.Wrap = mustDecodeString("699ab4eac6b7c66c3a9fa0d6836326c2b294a10764233356") err = c.UnmarshalKM(km, "foobarfoobar") require.ErrorIs(t, err, ErrInvalidKey) km = &packet.CIFKeyMaterialExtension{} km.KeyBasedEncryption = packet.EvenKeyEncrypted km.Salt = mustDecodeString("6c438852715a4d26e0e810b3132ca61f") km.Wrap = mustDecodeString("5b901889bd106609ca8a83264b12ed1bfab3f02812bad65784ac396b1f57eb16c53e1020d3a3250b") err = c.UnmarshalKM(km, "foobarfoobar") require.ErrorIs(t, err, ErrInvalidWrap) } func TestUnmarshal(t *testing.T) { tests := []struct { keylength int salt string passphrase string evenWrap string oddWrap string evenOddWrap string }{ { keylength: 16, salt: "6c438852715a4d26e0e810b3132ca61f", passphrase: "foobarfoobar", evenWrap: "699ab4eac6b7c66c3a9fa0d6836326c2b294a10764233356", oddWrap: "ca4decaaf8d7b5c38288e84c8796929c84b7c139f1f769d5", evenOddWrap: "5b901889bd106609ca8a83264b12ed1bfab3f02812bad65784ac396b1f57eb16c53e1020d3a3250b", }, { keylength: 24, salt: "e636259ccc41e73611b9363bb58586b1", passphrase: "foobarfoobar", evenWrap: "8c6502d6a83e0ab894a43cb5b37b71c2755afc64a682bed9d46912138b60f384", oddWrap: "1fe56a4475759636674a7c5e44f1cdfb365a9f11d8fe74536e8df6b97eecf1c9", evenOddWrap: "7360357d363ebec384885b10c8120528889d1be05624bfc381c5fa090f00f9ecef5d6427f7542a58be144f4aeb07452beca546874a68197d", }, { keylength: 32, salt: "3825bb4163f7d5cf2804ec0b31a7370f", passphrase: "foobarfoobar", evenWrap: "7d1578458e41680dd997d1a185c75753f3344c6711542b35833f881f7c480304cbe9bdbe76035914", oddWrap: "cc1af097af558fa25b925417c4e6e9e1adacd8b96916b4ac4fac8e6ecdc3b5c48c01134e92e9e5f6", evenOddWrap: "f7373def4e9f61f6cd6a22e78916aa07cac8e5f07669d556ec8a15b7631fa9c631e9d98a3f92dbe187f434569ec71b9e2a53171feafd909a5560233fe02ed0301e576d4992b10c86", }, } for _, test := range tests { c, err := New(test.keylength) require.NoError(t, err) km := &packet.CIFKeyMaterialExtension{} km.KeyBasedEncryption = packet.EvenKeyEncrypted km.Salt = mustDecodeString(test.salt) km.Wrap = mustDecodeString(test.evenWrap) err = c.UnmarshalKM(km, test.passphrase) require.NoError(t, err) km.KeyBasedEncryption = packet.OddKeyEncrypted km.Salt = mustDecodeString(test.salt) km.Wrap = mustDecodeString(test.oddWrap) err = c.UnmarshalKM(km, test.passphrase) require.NoError(t, err) km.KeyBasedEncryption = packet.EvenAndOddKey km.Salt = mustDecodeString(test.salt) km.Wrap = mustDecodeString(test.evenOddWrap) err = c.UnmarshalKM(km, test.passphrase) require.NoError(t, err) } } func TestMarshal(t *testing.T) { tests := []struct { keylength int salt string evenSEK string oddSEK string passphrase string evenWrap string oddWrap string evenOddWrap string }{ { keylength: 16, salt: "6c438852715a4d26e0e810b3132ca61f", evenSEK: "047dc22e7f000be55a25ba56ae2e9180", oddSEK: "240c8e76ccf3637641af473edaf15aaf", passphrase: "foobarfoobar", evenWrap: "699ab4eac6b7c66c3a9fa0d6836326c2b294a10764233356", oddWrap: "ca4decaaf8d7b5c38288e84c8796929c84b7c139f1f769d5", evenOddWrap: "5b901889bd106609ca8a83264b12ed1bfab3f02812bad65784ac396b1f57eb16c53e1020d3a3250b", }, { keylength: 24, salt: "e636259ccc41e73611b9363bb58586b1", evenSEK: "4dca0ad088da64fdc8e98002d141bc46fed4fa0167b931c8", oddSEK: "2b2bbb64ee3942cfa31bfe58efd1d2102c40b7bc028f8946", passphrase: "foobarfoobar", evenWrap: "8c6502d6a83e0ab894a43cb5b37b71c2755afc64a682bed9d46912138b60f384", oddWrap: "1fe56a4475759636674a7c5e44f1cdfb365a9f11d8fe74536e8df6b97eecf1c9", evenOddWrap: "7360357d363ebec384885b10c8120528889d1be05624bfc381c5fa090f00f9ecef5d6427f7542a58be144f4aeb07452beca546874a68197d", }, { keylength: 32, salt: "3825bb4163f7d5cf2804ec0b31a7370f", evenSEK: "53a088d93431181075f8a9bc4876359afe48967308120c93f97bbd823d8de62a", oddSEK: "7893e88b6296ffcc5a2eab5f53d48efd7adaeced8cb3a851d4f8e2dbda8db17a", passphrase: "foobarfoobar", evenWrap: "7d1578458e41680dd997d1a185c75753f3344c6711542b35833f881f7c480304cbe9bdbe76035914", oddWrap: "cc1af097af558fa25b925417c4e6e9e1adacd8b96916b4ac4fac8e6ecdc3b5c48c01134e92e9e5f6", evenOddWrap: "f7373def4e9f61f6cd6a22e78916aa07cac8e5f07669d556ec8a15b7631fa9c631e9d98a3f92dbe187f434569ec71b9e2a53171feafd909a5560233fe02ed0301e576d4992b10c86", }, } for _, test := range tests { c, err := New(test.keylength) require.NoError(t, err) cr := c.(*crypto) cr.salt = mustDecodeString(test.salt) cr.evenSEK = mustDecodeString(test.evenSEK) cr.oddSEK = mustDecodeString(test.oddSEK) km := &packet.CIFKeyMaterialExtension{} err = c.MarshalKM(km, test.passphrase, packet.EvenKeyEncrypted) require.NoError(t, err, "keylength: %d", test.keylength) wrap := mustDecodeString(test.evenWrap) x := bytes.Compare(km.Wrap, wrap) require.Equal(t, 0, x, "keylength: %d", test.keylength) km = &packet.CIFKeyMaterialExtension{} err = c.MarshalKM(km, test.passphrase, packet.OddKeyEncrypted) require.NoError(t, err, "keylength: %d", test.keylength) wrap = mustDecodeString(test.oddWrap) x = bytes.Compare(km.Wrap, wrap) require.Equal(t, 0, x, "keylength: %d", test.keylength) km = &packet.CIFKeyMaterialExtension{} err = c.MarshalKM(km, test.passphrase, packet.EvenAndOddKey) require.NoError(t, err, "keylength: %d", test.keylength) wrap = mustDecodeString(test.evenOddWrap) x = bytes.Compare(km.Wrap, wrap) require.Equal(t, 0, x, "keylength: %d", test.keylength) } } func TestDecode(t *testing.T) { packetSequenceNumber := uint32(0x79ee189e) data, _ := hex.DecodeString("47410011000001e00000808005211651aa410000000109f000000001419a2088dc6f8003fd0320993a9d4f33dd3a34628addfddfeffd03bf8f8677d149a74e8b1e56fd8208df79622c98c2edd137b6ff2331378c2c1299a2643d4048dd5e7062159a71fceacc10e61138f1d4e8788051c2f0f000fd1213d43ad36bd05682297ec6071bbfa83864a3436e813118a71e44797f3e12c22fc9f77e03455d5bc1405a001cae497adbff3f36004d122e5b77bfba7d391a6a830ef2235cf40747010012fe062c21e108d840187080300f6197be0c04ecb77bc455f686e23867fc2f802fe36677abf008cc43760db57d600afafd3fdad2f523ce844cf7ba3668f3e2ffff085b9c20baf084b810031e0400e7a094d9f114806e003ef32a9ef7684ddbef9b0007277e9524458b687c0801ae379e360c06f9c73130e90da9fff0201e3e81f7f5f0f35ff81016b8435c12e11d52f8342465d3a0de082f87381e0ccc83c1999040918a100908fc0e0428897c0e010e225e18060083010cc847010013cab57e091b4ff7f20697809cc00441b4ec99a00906ee73f795577dd2fef700111bbb5b8002f73beeb9d8a5debd5dd821020066420423209d2222ad5f8499e05ac0a6736b460c5d3c38312fb98cbcbc3e08023f0ffeabc09c285104a5cf89d002fe006c4dfa933a12aeabe60e0016689962dabb48ffefc3011e19c3f8200c7003b226030ae2036d41f4d00c23c8ad501344ee4ad41c4cd808210406da830301a7011c007977125ea5e4b3ef78783881e52841bfaf80065a6b47010014e72d60801017eb5c10020573e36020a4947bfd7c5d66fa85882e06ac5602bb987c92f0446c1c21883013b98ea1db881fa00bd7a5326b80b68c14c43856cafff000cebf7bc7ee3f000f38a4ccbb0ab620f78630085f575d4c85907f20276aa3df30835a0fc1673d74bba557609fabafdefe1f82dac64556e4155409b77275bfbff072105b9c100478679de1c82102070400c0bddf0400c382085eb5ae0084c88020e4915a80f4cc1c0026999a12652ab37e11863f00800e264701001546021dc486dab21021d062c81e8fff8c9461b27a997aa6d9a88187003e3aacd93a67bdeb5f249fc38a002d3607c66dd9b7d7c200132200133c811f612017e2004ce2004cf030001898220002010870e0104112c300192418a81f80885b482ed470a4907da0380108225f60a44452123200491a1b9486026ed55e484c42180bbb5e1983d25dfe03b5f7ffffff6830fbf17b3d9b33030f3f9fcef0cc200c3821020028e6c59b05e62e080180b91517eef77c210af0038ed823470100161881b6af0045260ce232b57f7104d0ca0007cd483569fe4cbc44b20992fff750c300186bebfb0677fb4fdfabffc37e0074a6606339e1b6a0972434060014f49331dcc8ee301df808bfd3e77fbbdeb9eb0f0c347f043cefe0c782085604e5a6825cfc0554d4cbe411286bb3f2cc06ab7fdfbf813ec7e45fe648fb8a216b6a26bfdf0e7f3f9de17820061c10030e1085f0042d20215acad5eef733834006419dd5def7e0032daeeb5deff867e0085a6085636b57e6418fdd354701001767fbafd3063f3a74cff7fb2c188406c5d5555545d45c998b8e32e3b1de39355fe10866eef5f849efbd00fc210d600a740661595abe01244c1800622d32398baa43c11fe769cf0843540c075b7dd0170089bebe7ff80073446b69b22df7f08433a0c07a4bba03ad7ef5f88ffe05d9a71348ce7dff9d73ac290400c3820060b5e0c017f03820416cb06009597c3189040f89003613152b3b7da0033850ab2322fb41c02f7353c002a9089cc4111f683c210ce008a6c188c5d6") tests := []struct { keylength int salt string evenSEK string oddSEK string passphrase string evenEncrypted string oddEncrypted string }{ { keylength: 16, salt: "6c438852715a4d26e0e810b3132ca61f", evenSEK: "047dc22e7f000be55a25ba56ae2e9180", oddSEK: "240c8e76ccf3637641af473edaf15aaf", passphrase: "foobarfoobar", evenEncrypted: "6053ce41905e451494d156b53c53fc6372c7e0eea81b10c4f21d4624915a93a368605cd958b14bf7274f1f75254ca606c464ea8a3f34e766fdee34dc6886512bf9b3916a3a24a3febe559cb9a07cfa5a0ec56ffee9b11605a97aa684736afcdad091fb467ca2a6ccce7356e8b2cd931f03f6c0ee4bccdd9fc6f635b080274f32f6b64a14b745efcfd7daaf05fc75369c1e37892d7f97dca5526eef2eba914cb729689b879c5a3f9a8fff061dda8f930eb20e92f241524c3743e12dd8e9b50937d73212307c2c47cb14834a5c2ab6fe1f68b46b2e1ca85cbecf00cf176a426d819ec9d41ed525f9ee7c2e7ee775cebc98357c55de1991ee23a979a4072672c4add4e215966ccef2bd04ad78f8822fcb3ed3a75d945a6c0d3dfa84b3f80c107cc94a0fb5b0b97ff71b8c8ab816ade945fb0ac70228f30e17565cd09b849a06746383193e55105904543b6079eecc53cf51d6d47690871f3f569501f0bcc790fc4c4ab344aedb53a5ef4ed19c8f5c43179f3c1de7065c32182e1ebe291809064c3cbc9ff69f92a61f3642e7ec5d711ef6a07556ea375550d6bf4221093a85b1b6bb8fd650ab3acd40f409497fdf08b88b718b408574ff9f6e003fe64803a34d5e4d86d361c5754741b60024ae24035f01f1a1e2f6dbb0aa93794fac2afa7fc824933260954b05845e856db7b7720ed0dd08504f50a4469d383b9d552e048bd674a98dfaa137bf15b740388ce0f8bcde80046d4ddc0e5987315183950477f069796201e97c990eb98370cd8f5f3bb99704d0806b59d31d02f5d0233875c27f9b132d6a7fdc3508a264b2d33a570f56aa4388e512a4181e9b0caeae8b368224d4b4ba499ef0cc7daf659d3bd38aa238577dde5d19ce1eb5257198096c00f90ab02a8c7320c6b1d10297fabf2e5f62af421a89cbaaa1e4a4e120d0e888354610c47d52a32e78f4ae21475d2201c74460d088e7686d00e7333a7c259a73944cd7981522205bec96b87157ae5fd5473e77d900f57c7edb170bc69d1e736760d63bf31c845f002259ab495c069cb39b074a066a9ddc718f3c6b94bde6fe0c82ace2d9c748f060435a1d4719651858a2f3c3ddf974035cbf1fe248fc3ee479ab37f064f019174df80f79b4bd7beb691f995358779fd124886158e669b118bbae7fac87a13558dc94f0f2dee89abe6e860082bca2fddd3822c193708b37cd53dfbeaab437a7654490bd55a29ca79e8de4f78f6c9c24aee40944d6c0e4f3cc4a5530683c087741b3ef36b464d11e207bc9b1e2ebddce33f3a706d7b7d83603b604a054d02ac0fac6d4194887b30c542e4f44a8df70d4ed53e47f019ab83dde4f251011b8fbe381ca6145547a6a9a340855d1020c078b8152a71f199653744c5c73e9910d601ee74ea6533393261b6a94ab356b3d028d05b47ce1a31cdf5acf3088d4a835285b42b7ea06cff52c98abc099fc0df611588a8941380e5ff65938aa9212ddc0d5a0b3f229615868a0654a1fc2bb0ac91f32ee802f2b316db20b758b6c7373f978f6efe7a6b8e1ffae4061e2a43f108965fdc7e60509d6896f299ad6bd3bfa5adc4a5c968878aecb8ce49ae278d613defcd5bc462c311f04093571af0f6f01484833c8977d3900e4b42085882b66d783edfeb3efd782cd6e44ef38bd1c1ce9dc427fa071caaa26924978530b3002d7e33722cbc87f1b2d670835960071763b712229740a7613da5236e10caa2466384306537d8253417a7f5bfee629129a8e52a52926a2b65f7c0c903c3762988350777a99abbeb34eeb49ebdb5a00c2bef02387651773e8f888b4f672c9f926aff5df12a899599fc40e5f95fc5394d615cafc8ef0831e21c7", oddEncrypted: "8f91686a120b4461f0e078ce80805cb51994b15d31f126ece327469f326c337f25d06e67fd9209308c933379aa796d6c3c7d3dee6410e413829ddb6d6327026c00bb4000992c54f185abf9d724c772d32b8a38ac094b39c948e46c1b06e4263fbf7c7318ef3667937e17a63579decfe667c8478284fab330c500f5f9266922a35a30f612cce0af0cb8f5ec1d3b393339955f7c6470380b9cf7e5ed29b83d296895f0308805e3e5acd0c5e8f54535223e61845692a7e52763a751e0b14633ebe73fe7ec215ffb3e45bcc777661d74efdb1631e5b8fa7ab3c7ec59f2c1f2399e90479b42557b73a14288792609eab84929152216c8969e3ff7f5a17c810ce31f0387448b9a3fc5901302f295d43c98efaceb2f3a0df2f0c6ccd328da26e6c836527ac19641dbe36f4a47a05f62ea0dd411a34f5f73a86cc9daf6e58eed9d630313687e5dd06d51a92668149cb0395a3e42bdd8174396f576ae88a574f933d7ccedd152a9981f1dbd2395be9647f9b0291de1a2a1dffbf3aa8739906dd47ddeaa4978ef50762bee7df61594da9c34109da985a611aa2c9a8a3e6d388a27d1378a85496b3ba54334b559477cecbc844319768c1ded16949dd4298a0b04e6ae478953bf1a18d98fb1db3128ca2997402b8d2f5110e4c238291fbed9e01babfcaa3117f1dbd0113ae5eaff9e0c75db87d2166cd3d67db5e4bb01badd69f3d6464df2029e51438882ca99dc038bf0f0811f3773490edf9ff75f63ac97dc41656035c19c943c094cf25c1c07a5db82de71f79f94075aab064bfb8dc1a4f434e0f8d24ae775f0c773098d5bef537dcc87f8e2a91e71b87ac6320c3619c612709ee7c8077d67a5f5768503445b08aa9feef79bf6318d7abab7feb9382ab0fcfc9835ea0f94ae3c554ba9aeb447b4c05028672a89fac1370b2ce1c438d2311474f91ee97f386d06369210b52eb10237b5ac692b944ff637920fb9aa258680ebfba9df52588f2edf086925403d9bcc3e92ea513131e42654dbe42a092825d5e5b96474080e24b9fb51624427a8d2fae30dba7f249520080b80ef8709aa50285c0d5cbf144df419d85018bc458c6a3f60d44c94503461db6e53de0723da92e2e89eb2e6c98dfac7b7d9f2e542f414bae4234683ce8ca33761d5e149380e417c779c63c157c98850d37ec4711bdb1e4e2a741c4195e4c5dd18274450d340755cde38a48d3004bcd12f9af936d916fa2ee855c4a4fc590d849460e690cd76bb0bc823dae428e831cd98b8cb405d9d2427951e37886855dc3dec94a9c5d32abb4517b56950af31f89b4e29f9e6edb7bb6f24a12af7bad41f012e79da1cec774dcc241dd110f810d6c9263e1bf5711eb4af1c5ab5f0bfb15fadc442124aa55db8d83454fab030f727bd4512bb0aa6d128637025442e0f0cec76fdf97c467f2b5072bbec7c44376becce9bf425725f433e13b4a335a549b1cbf05c51cb87907749b67f46be67339870ed1b3e5e5a356e4c1b36baf9bd28a58aa9bf1f66839947f1ffbe3331263b705798d7e3d1ad86f4a39169c874fe793af83680146cbef8d604e1f707ff16f90c2b707acc246d40bedce5b1a86023ed046258d3715104795edca4e1476d59bafd9e25e8b4dd087b2748dcbb0c4965b6a310e0639f6e7d3f1a0917fc4902bca1e908526c663dd259c3ea32f3abc3959746dd171179c931586a3725bfd0e4b814388afea817501113eab47555db0a470e724020cd57b158a49ba9ed340e6d8f1a0b67666dc4c31d02485b97354816a5c3c401a676005b603af3c632a2370b46b80b28ecebe3437e8dc57cdd299c702f7aff2b536eb920f402504590236d515fec68a17d02f6c3", }, { keylength: 24, salt: "e636259ccc41e73611b9363bb58586b1", evenSEK: "4dca0ad088da64fdc8e98002d141bc46fed4fa0167b931c8", oddSEK: "2b2bbb64ee3942cfa31bfe58efd1d2102c40b7bc028f8946", passphrase: "foobarfoobar", evenEncrypted: "97888ba6bd9d4015a6f62c4d3ad9c2674077218fb83ba213a634bef143186587debe76466eef8218f2b3aeae2cf00d5c46b28ffa0d325fb2ac4409fb97921e1f4c4a652d731ec6f608c92006a0ef8abe203dcf1c4f81795b126b2aff3a46d6c69a047a050a385417ecf9bea11530346607d8db1d821baf49b36b772160a1633257333b8c544fb0f4d25da28dcdb1e24a8611968053b4e636440756c7a8bf6fb7b9cb3bbc34a54e0b88c6651ac23192d18327d46e7aaf6c01a038346cb65f59d4f6be2d3a5f92c1bd043f236c0c9dbb1dad4994f426ee8ebd05a62c7558c384de5be20018ac50c73efd4ddc1255419c766f3cf53be6ad5fe35682208538e447abf0a68b1ba7d7030ace2a6b20d73bc71dd3ac7b026d60220f1eff05a66c5e06102e2801c8bd9d60091489f282eab072670f1e667bdbc2a067ddd62ffcdc82d9d78cd491277beed96f9fa87de05e6ddbbc7a79557fddd610a58c20187b71bf46f0e2017065b48689efd2862ed3bce11e0792ccfcf64494e34277be21fee874f15dd5377695b69ae1a1cf5413502ea182eea4cd4bbd8d29923aa357e05c7b974ab9df120dbaae26f282f2cc14bcb6a7075f678cf2ad3f39ce8cb01bd44bbeb60269ada55735c88d2355839267e7f9f7596e4baedd2f425d05cac9df2d3b8d6105fb9826a55c78438be8579c02664ec8bac3bde88513cb4019c2a57ad0044730d7f48568bb47ef15aae7949a8be5950421d4de73a6ad27397c0f19da4739acd7527648a8b643ecbf2451a2ac61d6e7666764f657f1003a981fa3f7ebd8db91f286b3b33a764b3542c99017f56b48db5e5f1061eb9327d137b5d6e8e86203de8501103b0fccb0cb97d0266778ea439e1432326b719a7f9396f1c773e6543b391c926920282faadf37983e2fa0dc368e2d384466981ec165df62df4386a618e5cd2a8bdd28d03a5688c38bcb00b2449c39e35f8113253c339e7e4b97048886a8046e686b97591e9b3507a9f10b9c6ca9b6b8546dbade8e42a5af607a35e99f31c06838099c6f5df0907b0f09a33216318118c03bb11374cf2a3cf2ff03978dd66b7b95dff36bfc0bf6c10e7de490e9ed6f9ec226275c59da836f405bb70f504e6b4d1140365d714b84b18a735a4f0de2b5ed7e4fc5ddaf8812d52dc6b49740b7673f408a2b64e4a05f05349706fdfea71914ae29f614fa58d7ad494f8e72de1f9ce579a0fa595a4cbe112effb769bb0e146c20f9aef08a72aff74f9a7d0404d802f9705428776bf660abce214ace695310ec32d5caa95d84e15c102032f40f7d51f409b285d272864e8e8f075e5e0d0034b0405a54c1b0946e1cbff5438fd7ed54544ab3b5e1382749b1949daac5921bee6cee31e377a331400dd6d8baefe84598d2d09159614b4a3e89de69d2b951470d8ab77534e152e04297b54418d73989e1c459c88c38c07bf881bf3e9421b1b22cf1572e969251f63613b3b696f391756ac48457748112ca41882fd6b21ec87bd0027d13a158ab224adab8e66375ba044239dec6dc6a67566a03da021fec02cf295f85eec4adec4b6583eb013b2a3505c37dfcf60de3d9376661760499b03ca718e150dc43825d93ed82c575ecc50c9d5353f66b5f37ea50b202777c7e3f8bbb7b776c98688f2505eceb735e1879d149982306c20ebb1fab4d81a1382f2d42277a7357a9a4bd4d6aaa60adb7fbbc6026710a6162f553938d4a42b2213d626f393c8b8cb7b0583e29d53b02d93f2ba47cdc1af9adc497c5b4285d73120965c44a05a1553cdaedeb615aa506e6d509aace22c2d285c0edb41c93e5041e55d65ee1b74fbcd735794fe0678c98e9d3b66ae92ef2768dee78b5", oddEncrypted: "232f7ccc827d309606b5d879ae55f3a7cce1bbb6a50d5d3fc4fdfc84a57687a2783ccf101ed666809707f57d611b8754af176edc336e4535047de6d22d97c094d126805d9ce17704cbebc84596047e86aaea51e0e268fddc76c2b78e2e3dc0cde4dd11ee383ae2d24fc8151de48b05360612d9f68c864bd4fe1933af1b979ed44b721cbe84f20f1e415219a88406e4110ed20a441feb045d72bf7684a4c7b91fdde8f39e9d92aec62c292f588de5b6e29162f0e9c916cd316f6ac1bb67d781eef73ff6c34e73325900558692b5a8fad10fc25b55835fa1f0a188d1b310f7ac146567abd8ec4ff34c9e421a1d8ca7202d5b086b9c6bc91401b018e25fa27b79810b91e41e923a8e34aac3a50bc79ec4f680284fcc7334a43225a187a44eab0795b09179d9acdb5a307b043d14b30fb2956bdb39d1a1acace0c9f6f1efbab1b3b6cb5eb5b6955daaae972aaddc69a23cbe0d427598319be0b2434fed8fc680e1f185ec953afe59c83c197d2637d1646e3b9ee81b262995e4a87fc901a0200cc109add2d0f9d3fdf2c28b0e08f2e7e1b777e9e65198726f0cc32d49d6505da3d2f520c24d6ae25238ae8f546cf36c60d2f531b501828b3b2472b922e3eb35e49862a5afb9ee16fdfa0c8f550ba843e9ffd459ec95f0773143db6124e7614ee92c52420fef4afeb38f1889a00f272d744d640f8299da75691353df80d902581cb4f5e8a6a49346fb5479a8591788b1e29b251b661a1581253aaa009874e61f4a90c332828c9698ce8b8b5a844464fb024236adeeedcf2495794fba71faaa91f8495d61f5d94bd4ea77f8449317d59684d738331c513b0c673db453ed6febc4c2b22ffaea1bbc605b9b18cd97bf8b13d23dbe0c1eac7b783d27f31c280ff6a4ed0abd365ffd9094b6b70d8664242b0a56980aa43b861611c7cdc53fd655d4ce7fd85d2b694b4ccbfadc20705bf647989772d13368cd6d8564d65e2efad39b2c3892ee1056c658dc1fba3cb25e9f3754bb19f9c62c84899ae222aa72d331a58c7099c0b962b4086979492b71079808e55b3a1428e363ef07657dfeb380000ef375090d68fa96eed42a2666d9d674b5e89bb1b46ae20f2f34f1f73a9498c862438159be04342eb965bf2320db95103857e23b34179f05802b831c61423763117feb7259bd79f462639e69b3d94d6c232989cb7c51c1a76d99f784505aef17ddbc15ab54dc18d263d978696d120e4c0cb316bfe351e9ea40c2124091d741bf143e05a8e1d2079ae17d17195ad59796e58fb2c7bf6ea38ff4d6b10611918e70be6fa813b2f0c6168efe9e978f0531c79339f8d1299af0406ea410c632209378ec7cb64f59df64ec59432d5804914c2e02f880ff7808f16dedd9e5f9ff65d0b82356ded08dff783fff05451830c9fcc9ed4d29bb31fe05bb7a26b13a2eaf844599434a7e5d66f4c937151d03c84cd948d73550988a3857365879d610322df76e60af66a82fc0edfd014d427dff1b07da87c1f95cbaf328c2d5bcfad68e9f21f39908c70276fb651efc8595891987219216ff56fc537c91dd6691b946efeba5c033ea240ef807c7ed3a004eb6eafd5c5fd6f3c4130a21d598eeb02347ca27d21491e9f8596b4dc1fd68cd7c4a299aaff22aefbc785fbbab7b5cfd31c3b3569cdd37a36f551e1ef5c200ed834342946f52a7c8dc9257369cc4eb6bfd834aa522658018cb72c220f9af613e6b176b71706c083c9159edae377db5419006ab6a74911e985b90a701cd076d6d3a61aff3c7ca97226c4449c14005b7ea0e935616269a92cc93a8ed25b89c3ee4cb995ff21a6ed8d193560cb25be2af1c9d36836cde6bf208ed7a903e672b0a", }, { keylength: 32, salt: "3825bb4163f7d5cf2804ec0b31a7370f", evenSEK: "53a088d93431181075f8a9bc4876359afe48967308120c93f97bbd823d8de62a", oddSEK: "7893e88b6296ffcc5a2eab5f53d48efd7adaeced8cb3a851d4f8e2dbda8db17a", passphrase: "foobarfoobar", evenEncrypted: "78614028a1a14bb323b5c618fc1bacdb7790af4ab63f271620841be94a272f2bce578a71ee17bc0be6bd0ce8ca8399ad70dbecedd034140a37ac208e6a4f662dac1bb1d9dbf621a7dd225520893376e846b7113dd6655c523f7a170b4628e555fc0f1a9da4db2fb6b43e1c27864573f5b3a4216891df7a44fc6afe4ea0b51e8c6661aadaccb5bb8646715bb186af78f25a15f4788926a7e2e3d3a02d44e6abf73c988399a81a715ccf9939584ac747871336583604e05c6ee40678656030081594fb1d5b875b10e7e9e23a4806087fa31119358e322387c4b68c3076c1f8798cb75aed16e9abe38d762a218834ef31d0224fdcbce0f3b5d1ab3de4a562051554425a9ed62467342cd97118ac51ebd968b17bd484bd91b2041040f27affb047a6a364f85784707d908846f44575aee763c00b4f252796a3893e38fb4cb0315b12f49f112b187b0a14eea5bc73c2855dd0925d79528fcacfa7fbf51d61c884dbf03dd3670ff25a7b8172f6008dcba7d5e0755cec03d537196e268c96a96eef051d8dc076af0b41b44cf016c8fa9c8a8bc8c05ba1baaf0ba5ef3707c055a3ed5dde97ae3a3fe01d80f5d86209b525b7cc427e9f5e7ccab993b8f96f5bde3831143249d0d87aff6f1098a0042d4d97ef363a4010c9a16c77aeb012656ee6dc14c955841a0d96bff509bd8ec4ba09b08d881681d25823666154791e0c6ea518fbd477bebc95e1540b45e2e5fa20fc5a55f44cb42e482f1681cf9f25b8b23e3763466e7599f2e9baac13d69df1fde7f20bda805c7b7a6b0eeb831638536a0d2b87722d93dd84bcb7c0416ec7f847d7043562f73e0cc61b8614fbfcf996d31f3c91e09515b81f8a940bd0d2c1df76d12bef9aca5ad3bbbc3184b117768c3c845e07b407fe38308c5186fbbec71b804243da8f3dc7d687eaab4614566426ac3471d0d8985d9e03dd49d69ad89d482e83c56dda25f3c993ff230343945064e98be1be142392ed8601141de324619e117fcecec781d64ccc6ad8a26c8220e118269b2e86a1965e289c3c7359a8de4496c3678211e6270ab5e351bf82516ca546c3725ff1f8be3d70a15d976405bda6af7ec6a9c2ace9651444df58bc3cf8f443af5e77e6e7d1a224129538f539c264718e835b19032d1e90d4a68a8ab86be5fb2cd8a411f23464afaa570e24b9b6a1e9293f868386f7fe62bee6505ed328a9648b5c7add16b2282d6d72b6ec744158039d135aa456b7e02d2143f7d7f6549e3a184bd6ba2205d98eacca8ce8b835473ae3049c742c6cd225f05f278a7c61923519984895671d5a852a8c0b1cea2c58b2e68076809da32cf2bbbd1efabab63b5b1744cc1d46c1bb9636e20c3ac9083fa150b8b7ccbb7c02acd945069e4b634cef0dd966895510e85bc77263dd759cc010e7b6c101ce9a7a174e86eae96bf170f326b74199fb80dd22ada008b94b65b8ff70df0c0ecb5cf6264467534e2fd284bdb5649325e8a8426ede70562ced020e7d01e8bff5ff5329c26ca316628bbb79cec4076b331c4fdc548420520e2fe659e32e15910c9b92194ab046af9016c10e4f3140f5d77cb3c3db495d1d2a2890ab5279f38c29b718adea946440c41f80ecb64c3aff989366321c4c4d036b35eff3ef0d32574d121abe1388bab5d2129ffe4742b8669f4657355c5d3be9aa4d83fa25c09d0c40ddff40d359f1d52450daceb1f2ab7555d52a1d4a95b96058e737b1e9ba46055eded6721b11cc23e68682a188e591c2f12334667433d189ebb43deb559bfaf3f0d942d815df2d61ebe7249b25b663fe8ba0d7457a49e6c351dc4ea83bbdd3b510dd4f0fcef25394773a2567369f15abbb654cb7123a", oddEncrypted: "1702c977482690c91205b502100c582fafe4d64445c157d405c12eca7c754137323e3262f1df2a493bbc801c81939daab7a0e5d8daaf2f16b57529253fbc867872c79dcc5693e5755a8b003b800366141e90260dd252c483117b109c1c98c6be916388c61cc50fd89d38a14ef9528d7b637dfb1bac7ea841854f3fb1ae08a0198c810bb0e71ccc8de9400876044517d0ace69a9fb7661757f70e15691ef5316174d750cde660952999ca884a39d013ef4d6742a39ac04c8186e950c70ef8c54ba9c95413951e623d4031727a5999fc4afbac5a431cff7af97deefe1726420cdf80f6fa466e15ddec9c5032e692a74235fd3c4daa39bba62a8fee67f7a274f59dd5df1f088422a3355dfdd039edeaa292cf73c3bfa9232f89bcf9152e9c8ab6765196f4d85c3c4953aa23c2b4112eecffa956180e7b656b9ef60a39c802bc53054464bcde89d75a39adc07517c0d953602d93a6faf94b898d59a28dae483dff6059dc6aa60dbc5df49296b9588b10b2aa5951838b76ad9e6f8acbc12821f7d325a56e4cbbe3fb28d247a3ec65dedd8eeae5e57acec2629f12c0d60bfa7313f857d1d651c98bd03e53566f55833eacd80a1fad586012882a3c72ab6b69153628d3daeb94d371a9f3057d3c12e4456740cf3739401383b0ffafb1066160949c0ba01ac361acec06b7f401a761c99d6a70612266ae93431f6818acdace7f53e7012f17bb8af6ee6bbf21ede564c87946311a496bb6946de81a542dee39e4eb3b5e0b20fcd03dd9e03ac4c7e2d991abf80510acfc0f9ff1754a1cb14c71dc06744114c557767653e6f224e64e45dbcd1d56c0fb02b09122eda9baff3f9a638e0ebc586383e8d4236f9f941db18e27f3c9ac50d3247002604dfecbe8a314ec491e9a27662bcecc60af269b768e1a3cae0b1df3c395b89dd193fb7551dfa5f2e3cf6b9f4d20f9c1388d7921981184fc2bad66aeebc64066398930f3d5a9b0131f2363ddae7620dd3fa5733c0cd1a4c10b1f362b868d24c0fe1b5af164560d99c268e9379389c7b4520f91d273f3746c616ce8cb204466167d9fb7a5a9053f9e3ce3f9db75edce1c711819439e639c4b34d1e8eca923521c6124d2b8d77f9f64df8b0cace079d0212c874245c38ab5d82406322d862094f3a63ac593928ce51a71a91c5ed6443c215528779a98c49702a6b589fc2862b03bf3da2ed6edc9a06980b2d3d19401c5c6f45ef429d658c3170a5427f935e5bdbbea4bed65b3a1a39c208a6cc3d0028f67c8e8a517b151579cf33b16bd1e2c62a1a5ef5fd25c17b3d19c0caa6d1e0ad41fdbcacc54721e0fb39fc1eaa5dbd8b7ba12ca5562e606376850eaf608f0a118f9d9c3179e3042852f108393a31ebbd6b7842119f991873c1a345eb0922fd3d0580512e880557e1748d3dbaafc17e1d520e29db951d7cd92427d050fb76141a50800b717f5d8e3aeac9489ffd40fd30d5b224d17d03be3d2c23779658cedf233003a85fbe06a34241d5cfa816e67bbf1c6b121a7e92af4bb693c4830b7b0b8c4d4b912209dce55a1d48e4d276e61f75b104b1052fbba25c2f2ab2bc2542337bd1e01e7c060ba4ff7cbc06f6531737de25f2869aebb91cdcd0177b04ce12271c65445ea59bb36bce7c8fc00139f753f972afc23576215bf8cb171c78d13025d0ed11ba9ca1c3062e1d02d5f01f05628d6d76c38a4235cc3cd05eea0e543b5ca5194197cc92eb903281d16ce58fb67116f9d12b6b976b5c6b1997f08ec15de40aeaaf80f87763ace3de08c5c9aae3b8e18d5c9bf799ea7b8a2219410f23fbe5c769c048d59f23dea27647a07952af3297c074aa6645c6d5c8358f1dbdbf09847f27b", }, } for _, test := range tests { c, err := New(test.keylength) require.NoError(t, err) cr := c.(*crypto) cr.salt = mustDecodeString(test.salt) cr.evenSEK = mustDecodeString(test.evenSEK) cr.oddSEK = mustDecodeString(test.oddSEK) encrypted := mustDecodeString(test.evenEncrypted) err = c.EncryptOrDecryptPayload(encrypted, packet.EvenKeyEncrypted, packetSequenceNumber) require.NoError(t, err, "keylength: %d", test.keylength) x := bytes.Compare(data, encrypted) require.Equal(t, 0, x, "keylength: %d", test.keylength) encrypted = mustDecodeString(test.oddEncrypted) err = c.EncryptOrDecryptPayload(encrypted, packet.OddKeyEncrypted, packetSequenceNumber) require.NoError(t, err, "keylength: %d", test.keylength) x = bytes.Compare(data, encrypted) require.Equal(t, 0, x, "keylength: %d", test.keylength) } } func TestEncode(t *testing.T) { packetSequenceNumber := uint32(0x79ee189e) originalData := "47410011000001e00000808005211651aa410000000109f000000001419a2088dc6f8003fd0320993a9d4f33dd3a34628addfddfeffd03bf8f8677d149a74e8b1e56fd8208df79622c98c2edd137b6ff2331378c2c1299a2643d4048dd5e7062159a71fceacc10e61138f1d4e8788051c2f0f000fd1213d43ad36bd05682297ec6071bbfa83864a3436e813118a71e44797f3e12c22fc9f77e03455d5bc1405a001cae497adbff3f36004d122e5b77bfba7d391a6a830ef2235cf40747010012fe062c21e108d840187080300f6197be0c04ecb77bc455f686e23867fc2f802fe36677abf008cc43760db57d600afafd3fdad2f523ce844cf7ba3668f3e2ffff085b9c20baf084b810031e0400e7a094d9f114806e003ef32a9ef7684ddbef9b0007277e9524458b687c0801ae379e360c06f9c73130e90da9fff0201e3e81f7f5f0f35ff81016b8435c12e11d52f8342465d3a0de082f87381e0ccc83c1999040918a100908fc0e0428897c0e010e225e18060083010cc847010013cab57e091b4ff7f20697809cc00441b4ec99a00906ee73f795577dd2fef700111bbb5b8002f73beeb9d8a5debd5dd821020066420423209d2222ad5f8499e05ac0a6736b460c5d3c38312fb98cbcbc3e08023f0ffeabc09c285104a5cf89d002fe006c4dfa933a12aeabe60e0016689962dabb48ffefc3011e19c3f8200c7003b226030ae2036d41f4d00c23c8ad501344ee4ad41c4cd808210406da830301a7011c007977125ea5e4b3ef78783881e52841bfaf80065a6b47010014e72d60801017eb5c10020573e36020a4947bfd7c5d66fa85882e06ac5602bb987c92f0446c1c21883013b98ea1db881fa00bd7a5326b80b68c14c43856cafff000cebf7bc7ee3f000f38a4ccbb0ab620f78630085f575d4c85907f20276aa3df30835a0fc1673d74bba557609fabafdefe1f82dac64556e4155409b77275bfbff072105b9c100478679de1c82102070400c0bddf0400c382085eb5ae0084c88020e4915a80f4cc1c0026999a12652ab37e11863f00800e264701001546021dc486dab21021d062c81e8fff8c9461b27a997aa6d9a88187003e3aacd93a67bdeb5f249fc38a002d3607c66dd9b7d7c200132200133c811f612017e2004ce2004cf030001898220002010870e0104112c300192418a81f80885b482ed470a4907da0380108225f60a44452123200491a1b9486026ed55e484c42180bbb5e1983d25dfe03b5f7ffffff6830fbf17b3d9b33030f3f9fcef0cc200c3821020028e6c59b05e62e080180b91517eef77c210af0038ed823470100161881b6af0045260ce232b57f7104d0ca0007cd483569fe4cbc44b20992fff750c300186bebfb0677fb4fdfabffc37e0074a6606339e1b6a0972434060014f49331dcc8ee301df808bfd3e77fbbdeb9eb0f0c347f043cefe0c782085604e5a6825cfc0554d4cbe411286bb3f2cc06ab7fdfbf813ec7e45fe648fb8a216b6a26bfdf0e7f3f9de17820061c10030e1085f0042d20215acad5eef733834006419dd5def7e0032daeeb5deff867e0085a6085636b57e6418fdd354701001767fbafd3063f3a74cff7fb2c188406c5d5555545d45c998b8e32e3b1de39355fe10866eef5f849efbd00fc210d600a740661595abe01244c1800622d32398baa43c11fe769cf0843540c075b7dd0170089bebe7ff80073446b69b22df7f08433a0c07a4bba03ad7ef5f88ffe05d9a71348ce7dff9d73ac290400c3820060b5e0c017f03820416cb06009597c3189040f89003613152b3b7da0033850ab2322fb41c02f7353c002a9089cc4111f683c210ce008a6c188c5d6" tests := []struct { keylength int salt string evenSEK string oddSEK string passphrase string evenEncrypted string oddEncrypted string }{ { keylength: 16, salt: "6c438852715a4d26e0e810b3132ca61f", evenSEK: "047dc22e7f000be55a25ba56ae2e9180", oddSEK: "240c8e76ccf3637641af473edaf15aaf", passphrase: "foobarfoobar", evenEncrypted: "6053ce41905e451494d156b53c53fc6372c7e0eea81b10c4f21d4624915a93a368605cd958b14bf7274f1f75254ca606c464ea8a3f34e766fdee34dc6886512bf9b3916a3a24a3febe559cb9a07cfa5a0ec56ffee9b11605a97aa684736afcdad091fb467ca2a6ccce7356e8b2cd931f03f6c0ee4bccdd9fc6f635b080274f32f6b64a14b745efcfd7daaf05fc75369c1e37892d7f97dca5526eef2eba914cb729689b879c5a3f9a8fff061dda8f930eb20e92f241524c3743e12dd8e9b50937d73212307c2c47cb14834a5c2ab6fe1f68b46b2e1ca85cbecf00cf176a426d819ec9d41ed525f9ee7c2e7ee775cebc98357c55de1991ee23a979a4072672c4add4e215966ccef2bd04ad78f8822fcb3ed3a75d945a6c0d3dfa84b3f80c107cc94a0fb5b0b97ff71b8c8ab816ade945fb0ac70228f30e17565cd09b849a06746383193e55105904543b6079eecc53cf51d6d47690871f3f569501f0bcc790fc4c4ab344aedb53a5ef4ed19c8f5c43179f3c1de7065c32182e1ebe291809064c3cbc9ff69f92a61f3642e7ec5d711ef6a07556ea375550d6bf4221093a85b1b6bb8fd650ab3acd40f409497fdf08b88b718b408574ff9f6e003fe64803a34d5e4d86d361c5754741b60024ae24035f01f1a1e2f6dbb0aa93794fac2afa7fc824933260954b05845e856db7b7720ed0dd08504f50a4469d383b9d552e048bd674a98dfaa137bf15b740388ce0f8bcde80046d4ddc0e5987315183950477f069796201e97c990eb98370cd8f5f3bb99704d0806b59d31d02f5d0233875c27f9b132d6a7fdc3508a264b2d33a570f56aa4388e512a4181e9b0caeae8b368224d4b4ba499ef0cc7daf659d3bd38aa238577dde5d19ce1eb5257198096c00f90ab02a8c7320c6b1d10297fabf2e5f62af421a89cbaaa1e4a4e120d0e888354610c47d52a32e78f4ae21475d2201c74460d088e7686d00e7333a7c259a73944cd7981522205bec96b87157ae5fd5473e77d900f57c7edb170bc69d1e736760d63bf31c845f002259ab495c069cb39b074a066a9ddc718f3c6b94bde6fe0c82ace2d9c748f060435a1d4719651858a2f3c3ddf974035cbf1fe248fc3ee479ab37f064f019174df80f79b4bd7beb691f995358779fd124886158e669b118bbae7fac87a13558dc94f0f2dee89abe6e860082bca2fddd3822c193708b37cd53dfbeaab437a7654490bd55a29ca79e8de4f78f6c9c24aee40944d6c0e4f3cc4a5530683c087741b3ef36b464d11e207bc9b1e2ebddce33f3a706d7b7d83603b604a054d02ac0fac6d4194887b30c542e4f44a8df70d4ed53e47f019ab83dde4f251011b8fbe381ca6145547a6a9a340855d1020c078b8152a71f199653744c5c73e9910d601ee74ea6533393261b6a94ab356b3d028d05b47ce1a31cdf5acf3088d4a835285b42b7ea06cff52c98abc099fc0df611588a8941380e5ff65938aa9212ddc0d5a0b3f229615868a0654a1fc2bb0ac91f32ee802f2b316db20b758b6c7373f978f6efe7a6b8e1ffae4061e2a43f108965fdc7e60509d6896f299ad6bd3bfa5adc4a5c968878aecb8ce49ae278d613defcd5bc462c311f04093571af0f6f01484833c8977d3900e4b42085882b66d783edfeb3efd782cd6e44ef38bd1c1ce9dc427fa071caaa26924978530b3002d7e33722cbc87f1b2d670835960071763b712229740a7613da5236e10caa2466384306537d8253417a7f5bfee629129a8e52a52926a2b65f7c0c903c3762988350777a99abbeb34eeb49ebdb5a00c2bef02387651773e8f888b4f672c9f926aff5df12a899599fc40e5f95fc5394d615cafc8ef0831e21c7", oddEncrypted: "8f91686a120b4461f0e078ce80805cb51994b15d31f126ece327469f326c337f25d06e67fd9209308c933379aa796d6c3c7d3dee6410e413829ddb6d6327026c00bb4000992c54f185abf9d724c772d32b8a38ac094b39c948e46c1b06e4263fbf7c7318ef3667937e17a63579decfe667c8478284fab330c500f5f9266922a35a30f612cce0af0cb8f5ec1d3b393339955f7c6470380b9cf7e5ed29b83d296895f0308805e3e5acd0c5e8f54535223e61845692a7e52763a751e0b14633ebe73fe7ec215ffb3e45bcc777661d74efdb1631e5b8fa7ab3c7ec59f2c1f2399e90479b42557b73a14288792609eab84929152216c8969e3ff7f5a17c810ce31f0387448b9a3fc5901302f295d43c98efaceb2f3a0df2f0c6ccd328da26e6c836527ac19641dbe36f4a47a05f62ea0dd411a34f5f73a86cc9daf6e58eed9d630313687e5dd06d51a92668149cb0395a3e42bdd8174396f576ae88a574f933d7ccedd152a9981f1dbd2395be9647f9b0291de1a2a1dffbf3aa8739906dd47ddeaa4978ef50762bee7df61594da9c34109da985a611aa2c9a8a3e6d388a27d1378a85496b3ba54334b559477cecbc844319768c1ded16949dd4298a0b04e6ae478953bf1a18d98fb1db3128ca2997402b8d2f5110e4c238291fbed9e01babfcaa3117f1dbd0113ae5eaff9e0c75db87d2166cd3d67db5e4bb01badd69f3d6464df2029e51438882ca99dc038bf0f0811f3773490edf9ff75f63ac97dc41656035c19c943c094cf25c1c07a5db82de71f79f94075aab064bfb8dc1a4f434e0f8d24ae775f0c773098d5bef537dcc87f8e2a91e71b87ac6320c3619c612709ee7c8077d67a5f5768503445b08aa9feef79bf6318d7abab7feb9382ab0fcfc9835ea0f94ae3c554ba9aeb447b4c05028672a89fac1370b2ce1c438d2311474f91ee97f386d06369210b52eb10237b5ac692b944ff637920fb9aa258680ebfba9df52588f2edf086925403d9bcc3e92ea513131e42654dbe42a092825d5e5b96474080e24b9fb51624427a8d2fae30dba7f249520080b80ef8709aa50285c0d5cbf144df419d85018bc458c6a3f60d44c94503461db6e53de0723da92e2e89eb2e6c98dfac7b7d9f2e542f414bae4234683ce8ca33761d5e149380e417c779c63c157c98850d37ec4711bdb1e4e2a741c4195e4c5dd18274450d340755cde38a48d3004bcd12f9af936d916fa2ee855c4a4fc590d849460e690cd76bb0bc823dae428e831cd98b8cb405d9d2427951e37886855dc3dec94a9c5d32abb4517b56950af31f89b4e29f9e6edb7bb6f24a12af7bad41f012e79da1cec774dcc241dd110f810d6c9263e1bf5711eb4af1c5ab5f0bfb15fadc442124aa55db8d83454fab030f727bd4512bb0aa6d128637025442e0f0cec76fdf97c467f2b5072bbec7c44376becce9bf425725f433e13b4a335a549b1cbf05c51cb87907749b67f46be67339870ed1b3e5e5a356e4c1b36baf9bd28a58aa9bf1f66839947f1ffbe3331263b705798d7e3d1ad86f4a39169c874fe793af83680146cbef8d604e1f707ff16f90c2b707acc246d40bedce5b1a86023ed046258d3715104795edca4e1476d59bafd9e25e8b4dd087b2748dcbb0c4965b6a310e0639f6e7d3f1a0917fc4902bca1e908526c663dd259c3ea32f3abc3959746dd171179c931586a3725bfd0e4b814388afea817501113eab47555db0a470e724020cd57b158a49ba9ed340e6d8f1a0b67666dc4c31d02485b97354816a5c3c401a676005b603af3c632a2370b46b80b28ecebe3437e8dc57cdd299c702f7aff2b536eb920f402504590236d515fec68a17d02f6c3", }, { keylength: 24, salt: "e636259ccc41e73611b9363bb58586b1", evenSEK: "4dca0ad088da64fdc8e98002d141bc46fed4fa0167b931c8", oddSEK: "2b2bbb64ee3942cfa31bfe58efd1d2102c40b7bc028f8946", passphrase: "foobarfoobar", evenEncrypted: "97888ba6bd9d4015a6f62c4d3ad9c2674077218fb83ba213a634bef143186587debe76466eef8218f2b3aeae2cf00d5c46b28ffa0d325fb2ac4409fb97921e1f4c4a652d731ec6f608c92006a0ef8abe203dcf1c4f81795b126b2aff3a46d6c69a047a050a385417ecf9bea11530346607d8db1d821baf49b36b772160a1633257333b8c544fb0f4d25da28dcdb1e24a8611968053b4e636440756c7a8bf6fb7b9cb3bbc34a54e0b88c6651ac23192d18327d46e7aaf6c01a038346cb65f59d4f6be2d3a5f92c1bd043f236c0c9dbb1dad4994f426ee8ebd05a62c7558c384de5be20018ac50c73efd4ddc1255419c766f3cf53be6ad5fe35682208538e447abf0a68b1ba7d7030ace2a6b20d73bc71dd3ac7b026d60220f1eff05a66c5e06102e2801c8bd9d60091489f282eab072670f1e667bdbc2a067ddd62ffcdc82d9d78cd491277beed96f9fa87de05e6ddbbc7a79557fddd610a58c20187b71bf46f0e2017065b48689efd2862ed3bce11e0792ccfcf64494e34277be21fee874f15dd5377695b69ae1a1cf5413502ea182eea4cd4bbd8d29923aa357e05c7b974ab9df120dbaae26f282f2cc14bcb6a7075f678cf2ad3f39ce8cb01bd44bbeb60269ada55735c88d2355839267e7f9f7596e4baedd2f425d05cac9df2d3b8d6105fb9826a55c78438be8579c02664ec8bac3bde88513cb4019c2a57ad0044730d7f48568bb47ef15aae7949a8be5950421d4de73a6ad27397c0f19da4739acd7527648a8b643ecbf2451a2ac61d6e7666764f657f1003a981fa3f7ebd8db91f286b3b33a764b3542c99017f56b48db5e5f1061eb9327d137b5d6e8e86203de8501103b0fccb0cb97d0266778ea439e1432326b719a7f9396f1c773e6543b391c926920282faadf37983e2fa0dc368e2d384466981ec165df62df4386a618e5cd2a8bdd28d03a5688c38bcb00b2449c39e35f8113253c339e7e4b97048886a8046e686b97591e9b3507a9f10b9c6ca9b6b8546dbade8e42a5af607a35e99f31c06838099c6f5df0907b0f09a33216318118c03bb11374cf2a3cf2ff03978dd66b7b95dff36bfc0bf6c10e7de490e9ed6f9ec226275c59da836f405bb70f504e6b4d1140365d714b84b18a735a4f0de2b5ed7e4fc5ddaf8812d52dc6b49740b7673f408a2b64e4a05f05349706fdfea71914ae29f614fa58d7ad494f8e72de1f9ce579a0fa595a4cbe112effb769bb0e146c20f9aef08a72aff74f9a7d0404d802f9705428776bf660abce214ace695310ec32d5caa95d84e15c102032f40f7d51f409b285d272864e8e8f075e5e0d0034b0405a54c1b0946e1cbff5438fd7ed54544ab3b5e1382749b1949daac5921bee6cee31e377a331400dd6d8baefe84598d2d09159614b4a3e89de69d2b951470d8ab77534e152e04297b54418d73989e1c459c88c38c07bf881bf3e9421b1b22cf1572e969251f63613b3b696f391756ac48457748112ca41882fd6b21ec87bd0027d13a158ab224adab8e66375ba044239dec6dc6a67566a03da021fec02cf295f85eec4adec4b6583eb013b2a3505c37dfcf60de3d9376661760499b03ca718e150dc43825d93ed82c575ecc50c9d5353f66b5f37ea50b202777c7e3f8bbb7b776c98688f2505eceb735e1879d149982306c20ebb1fab4d81a1382f2d42277a7357a9a4bd4d6aaa60adb7fbbc6026710a6162f553938d4a42b2213d626f393c8b8cb7b0583e29d53b02d93f2ba47cdc1af9adc497c5b4285d73120965c44a05a1553cdaedeb615aa506e6d509aace22c2d285c0edb41c93e5041e55d65ee1b74fbcd735794fe0678c98e9d3b66ae92ef2768dee78b5", oddEncrypted: "232f7ccc827d309606b5d879ae55f3a7cce1bbb6a50d5d3fc4fdfc84a57687a2783ccf101ed666809707f57d611b8754af176edc336e4535047de6d22d97c094d126805d9ce17704cbebc84596047e86aaea51e0e268fddc76c2b78e2e3dc0cde4dd11ee383ae2d24fc8151de48b05360612d9f68c864bd4fe1933af1b979ed44b721cbe84f20f1e415219a88406e4110ed20a441feb045d72bf7684a4c7b91fdde8f39e9d92aec62c292f588de5b6e29162f0e9c916cd316f6ac1bb67d781eef73ff6c34e73325900558692b5a8fad10fc25b55835fa1f0a188d1b310f7ac146567abd8ec4ff34c9e421a1d8ca7202d5b086b9c6bc91401b018e25fa27b79810b91e41e923a8e34aac3a50bc79ec4f680284fcc7334a43225a187a44eab0795b09179d9acdb5a307b043d14b30fb2956bdb39d1a1acace0c9f6f1efbab1b3b6cb5eb5b6955daaae972aaddc69a23cbe0d427598319be0b2434fed8fc680e1f185ec953afe59c83c197d2637d1646e3b9ee81b262995e4a87fc901a0200cc109add2d0f9d3fdf2c28b0e08f2e7e1b777e9e65198726f0cc32d49d6505da3d2f520c24d6ae25238ae8f546cf36c60d2f531b501828b3b2472b922e3eb35e49862a5afb9ee16fdfa0c8f550ba843e9ffd459ec95f0773143db6124e7614ee92c52420fef4afeb38f1889a00f272d744d640f8299da75691353df80d902581cb4f5e8a6a49346fb5479a8591788b1e29b251b661a1581253aaa009874e61f4a90c332828c9698ce8b8b5a844464fb024236adeeedcf2495794fba71faaa91f8495d61f5d94bd4ea77f8449317d59684d738331c513b0c673db453ed6febc4c2b22ffaea1bbc605b9b18cd97bf8b13d23dbe0c1eac7b783d27f31c280ff6a4ed0abd365ffd9094b6b70d8664242b0a56980aa43b861611c7cdc53fd655d4ce7fd85d2b694b4ccbfadc20705bf647989772d13368cd6d8564d65e2efad39b2c3892ee1056c658dc1fba3cb25e9f3754bb19f9c62c84899ae222aa72d331a58c7099c0b962b4086979492b71079808e55b3a1428e363ef07657dfeb380000ef375090d68fa96eed42a2666d9d674b5e89bb1b46ae20f2f34f1f73a9498c862438159be04342eb965bf2320db95103857e23b34179f05802b831c61423763117feb7259bd79f462639e69b3d94d6c232989cb7c51c1a76d99f784505aef17ddbc15ab54dc18d263d978696d120e4c0cb316bfe351e9ea40c2124091d741bf143e05a8e1d2079ae17d17195ad59796e58fb2c7bf6ea38ff4d6b10611918e70be6fa813b2f0c6168efe9e978f0531c79339f8d1299af0406ea410c632209378ec7cb64f59df64ec59432d5804914c2e02f880ff7808f16dedd9e5f9ff65d0b82356ded08dff783fff05451830c9fcc9ed4d29bb31fe05bb7a26b13a2eaf844599434a7e5d66f4c937151d03c84cd948d73550988a3857365879d610322df76e60af66a82fc0edfd014d427dff1b07da87c1f95cbaf328c2d5bcfad68e9f21f39908c70276fb651efc8595891987219216ff56fc537c91dd6691b946efeba5c033ea240ef807c7ed3a004eb6eafd5c5fd6f3c4130a21d598eeb02347ca27d21491e9f8596b4dc1fd68cd7c4a299aaff22aefbc785fbbab7b5cfd31c3b3569cdd37a36f551e1ef5c200ed834342946f52a7c8dc9257369cc4eb6bfd834aa522658018cb72c220f9af613e6b176b71706c083c9159edae377db5419006ab6a74911e985b90a701cd076d6d3a61aff3c7ca97226c4449c14005b7ea0e935616269a92cc93a8ed25b89c3ee4cb995ff21a6ed8d193560cb25be2af1c9d36836cde6bf208ed7a903e672b0a", }, { keylength: 32, salt: "3825bb4163f7d5cf2804ec0b31a7370f", evenSEK: "53a088d93431181075f8a9bc4876359afe48967308120c93f97bbd823d8de62a", oddSEK: "7893e88b6296ffcc5a2eab5f53d48efd7adaeced8cb3a851d4f8e2dbda8db17a", passphrase: "foobarfoobar", evenEncrypted: "78614028a1a14bb323b5c618fc1bacdb7790af4ab63f271620841be94a272f2bce578a71ee17bc0be6bd0ce8ca8399ad70dbecedd034140a37ac208e6a4f662dac1bb1d9dbf621a7dd225520893376e846b7113dd6655c523f7a170b4628e555fc0f1a9da4db2fb6b43e1c27864573f5b3a4216891df7a44fc6afe4ea0b51e8c6661aadaccb5bb8646715bb186af78f25a15f4788926a7e2e3d3a02d44e6abf73c988399a81a715ccf9939584ac747871336583604e05c6ee40678656030081594fb1d5b875b10e7e9e23a4806087fa31119358e322387c4b68c3076c1f8798cb75aed16e9abe38d762a218834ef31d0224fdcbce0f3b5d1ab3de4a562051554425a9ed62467342cd97118ac51ebd968b17bd484bd91b2041040f27affb047a6a364f85784707d908846f44575aee763c00b4f252796a3893e38fb4cb0315b12f49f112b187b0a14eea5bc73c2855dd0925d79528fcacfa7fbf51d61c884dbf03dd3670ff25a7b8172f6008dcba7d5e0755cec03d537196e268c96a96eef051d8dc076af0b41b44cf016c8fa9c8a8bc8c05ba1baaf0ba5ef3707c055a3ed5dde97ae3a3fe01d80f5d86209b525b7cc427e9f5e7ccab993b8f96f5bde3831143249d0d87aff6f1098a0042d4d97ef363a4010c9a16c77aeb012656ee6dc14c955841a0d96bff509bd8ec4ba09b08d881681d25823666154791e0c6ea518fbd477bebc95e1540b45e2e5fa20fc5a55f44cb42e482f1681cf9f25b8b23e3763466e7599f2e9baac13d69df1fde7f20bda805c7b7a6b0eeb831638536a0d2b87722d93dd84bcb7c0416ec7f847d7043562f73e0cc61b8614fbfcf996d31f3c91e09515b81f8a940bd0d2c1df76d12bef9aca5ad3bbbc3184b117768c3c845e07b407fe38308c5186fbbec71b804243da8f3dc7d687eaab4614566426ac3471d0d8985d9e03dd49d69ad89d482e83c56dda25f3c993ff230343945064e98be1be142392ed8601141de324619e117fcecec781d64ccc6ad8a26c8220e118269b2e86a1965e289c3c7359a8de4496c3678211e6270ab5e351bf82516ca546c3725ff1f8be3d70a15d976405bda6af7ec6a9c2ace9651444df58bc3cf8f443af5e77e6e7d1a224129538f539c264718e835b19032d1e90d4a68a8ab86be5fb2cd8a411f23464afaa570e24b9b6a1e9293f868386f7fe62bee6505ed328a9648b5c7add16b2282d6d72b6ec744158039d135aa456b7e02d2143f7d7f6549e3a184bd6ba2205d98eacca8ce8b835473ae3049c742c6cd225f05f278a7c61923519984895671d5a852a8c0b1cea2c58b2e68076809da32cf2bbbd1efabab63b5b1744cc1d46c1bb9636e20c3ac9083fa150b8b7ccbb7c02acd945069e4b634cef0dd966895510e85bc77263dd759cc010e7b6c101ce9a7a174e86eae96bf170f326b74199fb80dd22ada008b94b65b8ff70df0c0ecb5cf6264467534e2fd284bdb5649325e8a8426ede70562ced020e7d01e8bff5ff5329c26ca316628bbb79cec4076b331c4fdc548420520e2fe659e32e15910c9b92194ab046af9016c10e4f3140f5d77cb3c3db495d1d2a2890ab5279f38c29b718adea946440c41f80ecb64c3aff989366321c4c4d036b35eff3ef0d32574d121abe1388bab5d2129ffe4742b8669f4657355c5d3be9aa4d83fa25c09d0c40ddff40d359f1d52450daceb1f2ab7555d52a1d4a95b96058e737b1e9ba46055eded6721b11cc23e68682a188e591c2f12334667433d189ebb43deb559bfaf3f0d942d815df2d61ebe7249b25b663fe8ba0d7457a49e6c351dc4ea83bbdd3b510dd4f0fcef25394773a2567369f15abbb654cb7123a", oddEncrypted: "1702c977482690c91205b502100c582fafe4d64445c157d405c12eca7c754137323e3262f1df2a493bbc801c81939daab7a0e5d8daaf2f16b57529253fbc867872c79dcc5693e5755a8b003b800366141e90260dd252c483117b109c1c98c6be916388c61cc50fd89d38a14ef9528d7b637dfb1bac7ea841854f3fb1ae08a0198c810bb0e71ccc8de9400876044517d0ace69a9fb7661757f70e15691ef5316174d750cde660952999ca884a39d013ef4d6742a39ac04c8186e950c70ef8c54ba9c95413951e623d4031727a5999fc4afbac5a431cff7af97deefe1726420cdf80f6fa466e15ddec9c5032e692a74235fd3c4daa39bba62a8fee67f7a274f59dd5df1f088422a3355dfdd039edeaa292cf73c3bfa9232f89bcf9152e9c8ab6765196f4d85c3c4953aa23c2b4112eecffa956180e7b656b9ef60a39c802bc53054464bcde89d75a39adc07517c0d953602d93a6faf94b898d59a28dae483dff6059dc6aa60dbc5df49296b9588b10b2aa5951838b76ad9e6f8acbc12821f7d325a56e4cbbe3fb28d247a3ec65dedd8eeae5e57acec2629f12c0d60bfa7313f857d1d651c98bd03e53566f55833eacd80a1fad586012882a3c72ab6b69153628d3daeb94d371a9f3057d3c12e4456740cf3739401383b0ffafb1066160949c0ba01ac361acec06b7f401a761c99d6a70612266ae93431f6818acdace7f53e7012f17bb8af6ee6bbf21ede564c87946311a496bb6946de81a542dee39e4eb3b5e0b20fcd03dd9e03ac4c7e2d991abf80510acfc0f9ff1754a1cb14c71dc06744114c557767653e6f224e64e45dbcd1d56c0fb02b09122eda9baff3f9a638e0ebc586383e8d4236f9f941db18e27f3c9ac50d3247002604dfecbe8a314ec491e9a27662bcecc60af269b768e1a3cae0b1df3c395b89dd193fb7551dfa5f2e3cf6b9f4d20f9c1388d7921981184fc2bad66aeebc64066398930f3d5a9b0131f2363ddae7620dd3fa5733c0cd1a4c10b1f362b868d24c0fe1b5af164560d99c268e9379389c7b4520f91d273f3746c616ce8cb204466167d9fb7a5a9053f9e3ce3f9db75edce1c711819439e639c4b34d1e8eca923521c6124d2b8d77f9f64df8b0cace079d0212c874245c38ab5d82406322d862094f3a63ac593928ce51a71a91c5ed6443c215528779a98c49702a6b589fc2862b03bf3da2ed6edc9a06980b2d3d19401c5c6f45ef429d658c3170a5427f935e5bdbbea4bed65b3a1a39c208a6cc3d0028f67c8e8a517b151579cf33b16bd1e2c62a1a5ef5fd25c17b3d19c0caa6d1e0ad41fdbcacc54721e0fb39fc1eaa5dbd8b7ba12ca5562e606376850eaf608f0a118f9d9c3179e3042852f108393a31ebbd6b7842119f991873c1a345eb0922fd3d0580512e880557e1748d3dbaafc17e1d520e29db951d7cd92427d050fb76141a50800b717f5d8e3aeac9489ffd40fd30d5b224d17d03be3d2c23779658cedf233003a85fbe06a34241d5cfa816e67bbf1c6b121a7e92af4bb693c4830b7b0b8c4d4b912209dce55a1d48e4d276e61f75b104b1052fbba25c2f2ab2bc2542337bd1e01e7c060ba4ff7cbc06f6531737de25f2869aebb91cdcd0177b04ce12271c65445ea59bb36bce7c8fc00139f753f972afc23576215bf8cb171c78d13025d0ed11ba9ca1c3062e1d02d5f01f05628d6d76c38a4235cc3cd05eea0e543b5ca5194197cc92eb903281d16ce58fb67116f9d12b6b976b5c6b1997f08ec15de40aeaaf80f87763ace3de08c5c9aae3b8e18d5c9bf799ea7b8a2219410f23fbe5c769c048d59f23dea27647a07952af3297c074aa6645c6d5c8358f1dbdbf09847f27b", }, } for _, test := range tests { c, err := New(test.keylength) require.NoError(t, err) cr := c.(*crypto) cr.salt = mustDecodeString(test.salt) cr.evenSEK = mustDecodeString(test.evenSEK) cr.oddSEK = mustDecodeString(test.oddSEK) data, _ := hex.DecodeString(originalData) c.EncryptOrDecryptPayload(data, packet.EvenKeyEncrypted, packetSequenceNumber) encrypted := mustDecodeString(test.evenEncrypted) x := bytes.Compare(data, encrypted) require.Equal(t, 0, x, "keylength: %d", test.keylength) data = mustDecodeString(originalData) c.EncryptOrDecryptPayload(data, packet.OddKeyEncrypted, packetSequenceNumber) encrypted = mustDecodeString(test.oddEncrypted) x = bytes.Compare(data, encrypted) require.Equal(t, 0, x, "keylength: %d", test.keylength) } } ================================================ FILE: dial.go ================================================ package srt import ( "bytes" "context" "encoding/binary" "errors" "fmt" "net" "os" "sync" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/crypto" "github.com/datarhei/gosrt/packet" "github.com/datarhei/gosrt/rand" ) // ErrClientClosed is returned when the client connection has // been voluntarily closed. var ErrClientClosed = errors.New("srt: client closed") // dialer implements the Conn interface type dialer struct { version uint32 pc *net.UDPConn localAddr net.Addr remoteAddr net.Addr config Config socketId uint32 initialPacketSequenceNumber circular.Number crypto crypto.Crypto conn *srtConn connLock sync.RWMutex connChan chan connResponse start time.Time rcvQueue chan packet.Packet // for packets that come from the wire sndMutex sync.Mutex sndData bytes.Buffer // for packets that go to the wire shutdown bool shutdownLock sync.RWMutex shutdownOnce sync.Once stopReader context.CancelFunc doneChan chan error } type connResponse struct { conn *srtConn err error } // Dial connects to the address using the SRT protocol with the given config // and returns a Conn interface. // // The address is of the form "host:port". // // Example: // // Dial("srt", "127.0.0.1:3000", DefaultConfig()) // // In case of an error the returned Conn is nil and the error is non-nil. func Dial(network, address string, config Config) (Conn, error) { if network != "srt" { return nil, fmt.Errorf("the network must be 'srt'") } if err := config.Validate(); err != nil { return nil, fmt.Errorf("invalid config: %w", err) } if config.Logger == nil { config.Logger = NewLogger(nil) } dl := &dialer{ config: config, } netdialer := net.Dialer{ Control: DialControl(config), } conn, err := netdialer.Dial("udp", address) if err != nil { return nil, fmt.Errorf("failed dialing: %w", err) } pc, ok := conn.(*net.UDPConn) if !ok { conn.Close() return nil, fmt.Errorf("failed dialing: connection is not a UDP connection") } dl.pc = pc dl.localAddr = pc.LocalAddr() dl.remoteAddr = pc.RemoteAddr() dl.conn = nil dl.connChan = make(chan connResponse) dl.rcvQueue = make(chan packet.Packet, 2048) dl.doneChan = make(chan error) dl.start = time.Now() // create a new socket ID dl.socketId, err = rand.Uint32() if err != nil { dl.Close() return nil, err } seqNum, err := rand.Uint32() if err != nil { dl.Close() return nil, err } dl.initialPacketSequenceNumber = circular.New(seqNum&packet.MAX_SEQUENCENUMBER, packet.MAX_SEQUENCENUMBER) go func() { buffer := make([]byte, MAX_MSS_SIZE) // MTU size for { if dl.isShutdown() { dl.doneChan <- ErrClientClosed return } pc.SetReadDeadline(time.Now().Add(3 * time.Second)) n, _, err := pc.ReadFrom(buffer) if err != nil { if errors.Is(err, os.ErrDeadlineExceeded) { continue } if dl.isShutdown() { dl.doneChan <- ErrClientClosed return } dl.doneChan <- err return } p, err := packet.NewPacketFromData(dl.remoteAddr, buffer[:n]) if err != nil { continue } // non-blocking select { case dl.rcvQueue <- p: default: dl.log("dial", func() string { return "receive queue is full" }) } } }() var readerCtx context.Context readerCtx, dl.stopReader = context.WithCancel(context.Background()) go dl.reader(readerCtx) // Send the initial handshake request dl.sendInduction() dl.log("dial", func() string { return "waiting for response" }) timer := time.AfterFunc(dl.config.ConnectionTimeout, func() { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("connection timeout. server didn't respond"), } }) // Wait for handshake to conclude response := <-dl.connChan if response.err != nil { timer.Stop() dl.Close() return nil, response.err } timer.Stop() dl.connLock.Lock() dl.conn = response.conn dl.connLock.Unlock() return dl, nil } func (dl *dialer) checkConnection() error { select { case err := <-dl.doneChan: dl.Close() return err default: } return nil } // reader reads packets from the receive queue and pushes them into the connection func (dl *dialer) reader(ctx context.Context) { defer func() { dl.log("dial", func() string { return "left reader loop" }) }() dl.log("dial", func() string { return "reader loop started" }) for { select { case <-ctx.Done(): return case p := <-dl.rcvQueue: if dl.isShutdown() { break } dl.log("packet:recv:dump", func() string { return p.Dump() }) if p.Header().DestinationSocketId != dl.socketId { // libsrt <= 1.3.0 sends the CONCLUSION response with DestinationSocketId = 0 if !(p.Header().IsControlPacket && p.Header().ControlType == packet.CTRLTYPE_HANDSHAKE && p.Header().DestinationSocketId == 0) { break } } if p.Header().IsControlPacket && p.Header().ControlType == packet.CTRLTYPE_HANDSHAKE { dl.handleHandshake(p) break } dl.connLock.RLock() if dl.conn == nil { dl.connLock.RUnlock() break } dl.conn.push(p) dl.connLock.RUnlock() } } } // Send a packet to the wire. This function must be synchronous in order to allow to safely call Packet.Decommission() afterward. func (dl *dialer) send(p packet.Packet) { dl.sndMutex.Lock() defer dl.sndMutex.Unlock() dl.sndData.Reset() if err := p.Marshal(&dl.sndData); err != nil { p.Decommission() dl.log("packet:send:error", func() string { return "marshalling packet failed" }) return } buffer := dl.sndData.Bytes() dl.log("packet:send:dump", func() string { return p.Dump() }) // Write the packet's contents to the wire dl.pc.Write(buffer) if p.Header().IsControlPacket { // Control packets can be decommissioned because they will not be sent again (data packets might be retransferred) p.Decommission() } } func (dl *dialer) handleHandshake(p packet.Packet) { cif := &packet.CIFHandshake{} err := p.UnmarshalCIF(cif) dl.log("handshake:recv:dump", func() string { return p.Dump() }) dl.log("handshake:recv:cif", func() string { return cif.String() }) if err != nil { dl.log("handshake:recv:error", func() string { return err.Error() }) return } // assemble the response (4.3.1. Caller-Listener Handshake) p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(dl.start).Microseconds()) p.Header().DestinationSocketId = 0 // must be 0 for handshake if cif.HandshakeType == packet.HSTYPE_INDUCTION { if cif.Version < 4 || cif.Version > 5 { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer responded with unsupported handshake version (%d)", cif.Version), } return } cif.IsRequest = true cif.HandshakeType = packet.HSTYPE_CONCLUSION cif.InitialPacketSequenceNumber = dl.initialPacketSequenceNumber cif.MaxTransmissionUnitSize = dl.config.MSS // MTU size cif.MaxFlowWindowSize = dl.config.FC cif.SRTSocketId = dl.socketId cif.PeerIP.FromNetAddr(dl.localAddr) // Setup crypto context if len(dl.config.Passphrase) != 0 { keylen := dl.config.PBKeylen // If the server advertises a specific block cipher family and key size, // use this one, otherwise, use the configured one if cif.EncryptionField != 0 { switch cif.EncryptionField { case 2: keylen = 16 case 3: keylen = 24 case 4: keylen = 32 } } cr, err := crypto.New(keylen) if err != nil { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("failed creating crypto context: %w", err), } } dl.crypto = cr } // Verify version if cif.Version == 5 { dl.version = 5 // Verify magic number if cif.ExtensionField != 0x4A17 { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer sent the wrong magic number"), } return } cif.HasHS = true cif.SRTHS = &packet.CIFHandshakeExtension{ SRTVersion: SRT_VERSION, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, TSBPDRCV: true, CRYPT: true, // must always set to true TLPKTDROP: true, PERIODICNAK: true, REXMITFLG: true, STREAM: false, PACKET_FILTER: false, }, RecvTSBPDDelay: uint16(dl.config.ReceiverLatency.Milliseconds()), SendTSBPDDelay: uint16(dl.config.PeerLatency.Milliseconds()), } cif.HasSID = true cif.StreamId = dl.config.StreamId if dl.crypto != nil { cif.HasKM = true cif.SRTKM = &packet.CIFKeyMaterialExtension{} if err := dl.crypto.MarshalKM(cif.SRTKM, dl.config.Passphrase, packet.EvenKeyEncrypted); err != nil { dl.connChan <- connResponse{ conn: nil, err: err, } return } } } else { dl.version = 4 cif.EncryptionField = 0 cif.ExtensionField = 2 cif.HasHS = false cif.HasKM = false cif.HasSID = false } p.MarshalCIF(cif) dl.log("handshake:send:dump", func() string { return p.Dump() }) dl.log("handshake:send:cif", func() string { return cif.String() }) dl.send(p) } else if cif.HandshakeType == packet.HSTYPE_CONCLUSION { if cif.Version < 4 || cif.Version > 5 { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer responded with unsupported handshake version (%d)", cif.Version), } return } recvTsbpdDelay := uint16(dl.config.ReceiverLatency.Milliseconds()) sendTsbpdDelay := uint16(dl.config.PeerLatency.Milliseconds()) if cif.Version == 5 { if cif.SRTHS == nil { dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("missing handshake extension"), } return } // Check if the peer version is sufficient if cif.SRTHS.SRTVersion < dl.config.MinVersion { dl.sendShutdown(cif.SRTSocketId) dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer SRT version is not sufficient"), } return } // Check the required SRT flags if !cif.SRTHS.SRTFlags.TSBPDSND || !cif.SRTHS.SRTFlags.TSBPDRCV || !cif.SRTHS.SRTFlags.TLPKTDROP || !cif.SRTHS.SRTFlags.PERIODICNAK || !cif.SRTHS.SRTFlags.REXMITFLG { dl.sendShutdown(cif.SRTSocketId) dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer doesn't agree on SRT flags"), } return } // We only support live streaming if cif.SRTHS.SRTFlags.STREAM { dl.sendShutdown(cif.SRTSocketId) dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("peer doesn't support live streaming"), } return } // Select the largest TSBPD delay advertised by the listener, but at least 120ms if cif.SRTHS.SendTSBPDDelay > recvTsbpdDelay { recvTsbpdDelay = cif.SRTHS.SendTSBPDDelay } if cif.SRTHS.RecvTSBPDDelay > sendTsbpdDelay { sendTsbpdDelay = cif.SRTHS.RecvTSBPDDelay } } // If the peer has a smaller MTU size, adjust to it if cif.MaxTransmissionUnitSize < dl.config.MSS { dl.config.MSS = cif.MaxTransmissionUnitSize dl.config.PayloadSize = dl.config.MSS - SRT_HEADER_SIZE - UDP_HEADER_SIZE if dl.config.PayloadSize < MIN_PAYLOAD_SIZE { dl.sendShutdown(cif.SRTSocketId) dl.connChan <- connResponse{ conn: nil, err: fmt.Errorf("effective MSS too small (%d bytes) to fit the minimal payload size (%d bytes)", dl.config.MSS, MIN_PAYLOAD_SIZE), } return } } // Create a new connection conn := newSRTConn(srtConnConfig{ version: cif.Version, isCaller: true, localAddr: dl.localAddr, remoteAddr: dl.remoteAddr, config: dl.config, start: dl.start, socketId: dl.socketId, peerSocketId: cif.SRTSocketId, tsbpdTimeBase: uint64(time.Since(dl.start).Microseconds()), tsbpdDelay: uint64(recvTsbpdDelay) * 1000, peerTsbpdDelay: uint64(sendTsbpdDelay) * 1000, initialPacketSequenceNumber: cif.InitialPacketSequenceNumber, crypto: dl.crypto, keyBaseEncryption: packet.EvenKeyEncrypted, onSend: dl.send, onShutdown: func(*srtConn) { dl.Close() }, logger: dl.config.Logger, }) dl.log("connection:new", func() string { return fmt.Sprintf("%#08x (%s)", conn.SocketId(), conn.StreamId()) }) dl.connChan <- connResponse{ conn: conn, err: nil, } } else { var err error if cif.HandshakeType.IsRejection() { err = fmt.Errorf("connection rejected: %s", cif.HandshakeType.String()) } else { err = fmt.Errorf("unsupported handshake: %s", cif.HandshakeType.String()) } dl.connChan <- connResponse{ conn: nil, err: err, } } } func (dl *dialer) sendInduction() { p := packet.NewPacket(dl.remoteAddr) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(dl.start).Microseconds()) p.Header().DestinationSocketId = 0 cif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: dl.config.MSS, // MTU size MaxFlowWindowSize: dl.config.FC, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: dl.socketId, SynCookie: 0, } cif.PeerIP.FromNetAddr(dl.localAddr) p.MarshalCIF(cif) dl.log("handshake:send:dump", func() string { return p.Dump() }) dl.log("handshake:send:cif", func() string { return cif.String() }) dl.send(p) } func (dl *dialer) sendShutdown(peerSocketId uint32) { p := packet.NewPacket(dl.remoteAddr) data := [4]byte{} binary.BigEndian.PutUint32(data[0:], 0) p.SetData(data[0:4]) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_SHUTDOWN p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(dl.start).Microseconds()) p.Header().DestinationSocketId = peerSocketId dl.log("control:send:shutdown:dump", func() string { return p.Dump() }) dl.send(p) } func (dl *dialer) LocalAddr() net.Addr { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return nil } return dl.conn.LocalAddr() } func (dl *dialer) RemoteAddr() net.Addr { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return nil } return dl.conn.RemoteAddr() } func (dl *dialer) SocketId() uint32 { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return 0 } return dl.conn.SocketId() } func (dl *dialer) PeerSocketId() uint32 { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return 0 } return dl.conn.PeerSocketId() } func (dl *dialer) StreamId() string { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return "" } return dl.conn.StreamId() } func (dl *dialer) Version() uint32 { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return 0 } return dl.conn.Version() } func (dl *dialer) isShutdown() bool { dl.shutdownLock.RLock() defer dl.shutdownLock.RUnlock() return dl.shutdown } func (dl *dialer) Close() error { dl.shutdownOnce.Do(func() { dl.shutdownLock.Lock() dl.shutdown = true dl.shutdownLock.Unlock() dl.connLock.RLock() if dl.conn != nil { dl.conn.Close() } dl.connLock.RUnlock() dl.stopReader() dl.log("dial", func() string { return "closing socket" }) dl.pc.Close() select { case <-dl.doneChan: default: } }) return nil } func (dl *dialer) Read(p []byte) (n int, err error) { if err := dl.checkConnection(); err != nil { return 0, err } dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return 0, fmt.Errorf("no connection") } return dl.conn.Read(p) } func (dl *dialer) ReadPacket() (packet.Packet, error) { if err := dl.checkConnection(); err != nil { return nil, err } dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return nil, fmt.Errorf("no connection") } return dl.conn.ReadPacket() } func (dl *dialer) Write(p []byte) (n int, err error) { if err := dl.checkConnection(); err != nil { return 0, err } dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return 0, fmt.Errorf("no connection") } return dl.conn.Write(p) } func (dl *dialer) WritePacket(p packet.Packet) error { if err := dl.checkConnection(); err != nil { return err } dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return fmt.Errorf("no connection") } return dl.conn.WritePacket(p) } func (dl *dialer) SetDeadline(t time.Time) error { return dl.conn.SetDeadline(t) } func (dl *dialer) SetReadDeadline(t time.Time) error { return dl.conn.SetReadDeadline(t) } func (dl *dialer) SetWriteDeadline(t time.Time) error { return dl.conn.SetWriteDeadline(t) } func (dl *dialer) Stats(s *Statistics) { dl.connLock.RLock() defer dl.connLock.RUnlock() if dl.conn == nil { return } dl.conn.Stats(s) } func (dl *dialer) log(topic string, message func() string) { if dl.config.Logger == nil { return } dl.config.Logger.Print(topic, dl.socketId, 2, message) } ================================================ FILE: dial_test.go ================================================ package srt import ( "bytes" "net" "sync" "testing" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/require" ) func TestDialReject(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { return REJECT }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() conn, err := Dial("srt", "127.0.0.1:6003", DefaultConfig()) require.Error(t, err) require.Nil(t, conn) ln.Close() } func TestDialOK(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { return SUBSCRIBE }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() conn, err := Dial("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) err = conn.Close() require.NoError(t, err) ln.Close() } func TestDialV4(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { return SUBSCRIBE }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() start := time.Now() raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:6003") require.NoError(t, err) pc, err := net.DialUDP("udp", nil, raddr) require.NoError(t, err) packets := make(chan packet.Packet, 16) listenWg.Add(1) go func() { buffer := make([]byte, MAX_MSS_SIZE) listenWg.Done() for { n, _, err := pc.ReadFrom(buffer) if err != nil { return } p, err := packet.NewPacketFromData(pc.RemoteAddr(), buffer[:n]) require.NoError(t, err) packets <- p } }() p := packet.NewPacket(pc.RemoteAddr()) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = 0 sendcif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: 1500, // MTU size MaxFlowWindowSize: 25600, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 1234, SynCookie: 0, } sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) var data bytes.Buffer err = p.Marshal(&data) require.NoError(t, err) pc.Write(data.Bytes()) p = <-packets recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, false, recvcif.IsRequest) require.Equal(t, uint32(5), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(0x4A17), recvcif.ExtensionField) require.Equal(t, sendcif.InitialPacketSequenceNumber, recvcif.InitialPacketSequenceNumber) require.Equal(t, sendcif.MaxTransmissionUnitSize, recvcif.MaxTransmissionUnitSize) require.Equal(t, sendcif.MaxFlowWindowSize, recvcif.MaxFlowWindowSize) require.Equal(t, sendcif.HandshakeType, recvcif.HandshakeType) require.NotEmpty(t, recvcif.SynCookie) sendcif.HandshakeType = packet.HSTYPE_CONCLUSION sendcif.SynCookie = recvcif.SynCookie p.MarshalCIF(sendcif) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = 0 data.Reset() err = p.Marshal(&data) require.NoError(t, err) pc.Write(data.Bytes()) p = <-packets recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, false, recvcif.IsRequest) require.Equal(t, uint32(4), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(2), recvcif.ExtensionField) require.Equal(t, sendcif.InitialPacketSequenceNumber, recvcif.InitialPacketSequenceNumber) require.Equal(t, sendcif.MaxTransmissionUnitSize, recvcif.MaxTransmissionUnitSize) require.Equal(t, sendcif.MaxFlowWindowSize, recvcif.MaxFlowWindowSize) require.Equal(t, sendcif.HandshakeType, recvcif.HandshakeType) require.Empty(t, recvcif.SynCookie) require.False(t, recvcif.HasHS) require.False(t, recvcif.HasKM) require.False(t, recvcif.HasSID) pc.Close() ln.Close() } func TestDialV5(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { return SUBSCRIBE }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() start := time.Now() raddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:6003") require.NoError(t, err) pc, err := net.DialUDP("udp", nil, raddr) require.NoError(t, err) packets := make(chan packet.Packet, 16) listenWg.Add(1) go func() { buffer := make([]byte, MAX_MSS_SIZE) listenWg.Done() for { n, _, err := pc.ReadFrom(buffer) if err != nil { return } p, err := packet.NewPacketFromData(pc.RemoteAddr(), buffer[:n]) require.NoError(t, err) packets <- p } }() p := packet.NewPacket(pc.RemoteAddr()) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = 0 sendcif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: 1500, // MTU size MaxFlowWindowSize: 25600, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 1234, SynCookie: 0, } sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) var data bytes.Buffer err = p.Marshal(&data) require.NoError(t, err) pc.Write(data.Bytes()) p = <-packets recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, false, recvcif.IsRequest) require.Equal(t, uint32(5), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(0x4A17), recvcif.ExtensionField) require.Equal(t, sendcif.InitialPacketSequenceNumber, recvcif.InitialPacketSequenceNumber) require.Equal(t, sendcif.MaxTransmissionUnitSize, recvcif.MaxTransmissionUnitSize) require.Equal(t, sendcif.MaxFlowWindowSize, recvcif.MaxFlowWindowSize) require.Equal(t, sendcif.HandshakeType, recvcif.HandshakeType) require.NotEmpty(t, recvcif.SynCookie) sendcif.Version = 5 sendcif.ExtensionField = recvcif.ExtensionField sendcif.HandshakeType = packet.HSTYPE_CONCLUSION sendcif.SynCookie = recvcif.SynCookie sendcif.HasHS = true sendcif.SRTHS = &packet.CIFHandshakeExtension{ SRTVersion: SRT_VERSION, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, TSBPDRCV: true, CRYPT: true, // must always set to true TLPKTDROP: true, PERIODICNAK: true, REXMITFLG: true, STREAM: false, PACKET_FILTER: false, }, RecvTSBPDDelay: uint16(120), SendTSBPDDelay: uint16(120), } sendcif.HasSID = true sendcif.StreamId = "foobar" p.MarshalCIF(sendcif) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = 0 data.Reset() err = p.Marshal(&data) require.NoError(t, err) pc.Write(data.Bytes()) p = <-packets recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, false, recvcif.IsRequest) require.Equal(t, uint32(5), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(5), recvcif.ExtensionField) require.Equal(t, sendcif.InitialPacketSequenceNumber, recvcif.InitialPacketSequenceNumber) require.Equal(t, sendcif.MaxTransmissionUnitSize, recvcif.MaxTransmissionUnitSize) require.Equal(t, sendcif.MaxFlowWindowSize, recvcif.MaxFlowWindowSize) require.Equal(t, sendcif.HandshakeType, recvcif.HandshakeType) require.Empty(t, recvcif.SynCookie) require.True(t, recvcif.HasHS) require.Equal(t, recvcif.SRTHS, sendcif.SRTHS) require.False(t, recvcif.HasKM) require.True(t, recvcif.HasSID) require.Equal(t, recvcif.StreamId, sendcif.StreamId) pc.Close() ln.Close() } // test support for servers based on libsrt <= 1.3.0 // in which DestinationSocketId of the CONCLUSION response is always zero. func TestDialV5Pre130(t *testing.T) { ln, err := net.ListenPacket("udp", "127.0.0.1:6003") require.NoError(t, err) defer ln.Close() serverDone := make(chan error, 1) go func() { buf := make([]byte, MAX_MSS_SIZE) // Receive INDUCTION request. n, addr, err := ln.ReadFrom(buf) if err != nil { serverDone <- err return } p, err := packet.NewPacketFromData(addr, buf[:n]) if err != nil { serverDone <- err return } recvcif := &packet.CIFHandshake{} if err = p.UnmarshalCIF(recvcif); err != nil { serverDone <- err return } callerSocketId := recvcif.SRTSocketId p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = callerSocketId inductionResp := &packet.CIFHandshake{ IsRequest: false, Version: 5, EncryptionField: 0, ExtensionField: 0x4A17, InitialPacketSequenceNumber: recvcif.InitialPacketSequenceNumber, MaxTransmissionUnitSize: recvcif.MaxTransmissionUnitSize, MaxFlowWindowSize: recvcif.MaxFlowWindowSize, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 9876, SynCookie: 0xdeadbeef, } inductionResp.PeerIP.FromNetAddr(ln.LocalAddr()) p.MarshalCIF(inductionResp) var outbuf bytes.Buffer if err = p.Marshal(&outbuf); err != nil { serverDone <- err return } ln.WriteTo(outbuf.Bytes(), p.Header().Addr) // Receive CONCLUSION request. n, addr, err = ln.ReadFrom(buf) if err != nil { serverDone <- err return } p, err = packet.NewPacketFromData(addr, buf[:n]) if err != nil { serverDone <- err return } recvcif = &packet.CIFHandshake{} if err = p.UnmarshalCIF(recvcif); err != nil { serverDone <- err return } // Send CONCLUSION response with DestinationSocketId = 0 p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 conclusionResp := &packet.CIFHandshake{ IsRequest: false, Version: 5, EncryptionField: 0, ExtensionField: 1, InitialPacketSequenceNumber: recvcif.InitialPacketSequenceNumber, MaxTransmissionUnitSize: recvcif.MaxTransmissionUnitSize, MaxFlowWindowSize: recvcif.MaxFlowWindowSize, HandshakeType: packet.HSTYPE_CONCLUSION, SRTSocketId: 9876, SynCookie: 0, HasHS: true, SRTHS: &packet.CIFHandshakeExtension{ SRTVersion: SRT_VERSION, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, TSBPDRCV: true, CRYPT: true, TLPKTDROP: true, PERIODICNAK: true, REXMITFLG: true, }, RecvTSBPDDelay: uint16(DefaultConfig().ReceiverLatency.Milliseconds()), SendTSBPDDelay: uint16(DefaultConfig().PeerLatency.Milliseconds()), }, } conclusionResp.PeerIP.FromNetAddr(ln.LocalAddr()) p.MarshalCIF(conclusionResp) outbuf.Reset() if err = p.Marshal(&outbuf); err != nil { serverDone <- err return } ln.WriteTo(outbuf.Bytes(), p.Header().Addr) serverDone <- nil }() cfg := DefaultConfig() cfg.ConnectionTimeout = 3 * time.Second conn, err := Dial("srt", "127.0.0.1:6003", cfg) require.NoError(t, err) conn.Close() require.NoError(t, <-serverDone) } func TestDialV5MissingExtension(t *testing.T) { ln, err := net.ListenPacket("udp", "127.0.0.1:6003") require.NoError(t, err) defer ln.Close() go func() { // read induction request buf := make([]byte, MAX_MSS_SIZE) n, addr, err := ln.ReadFrom(buf) require.NoError(t, err) p, err := packet.NewPacketFromData(addr, buf[:n]) require.NoError(t, err) recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, packet.HSTYPE_INDUCTION, recvcif.HandshakeType) // write induction response p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif := &packet.CIFHandshake{ IsRequest: false, Version: 5, EncryptionField: 0, ExtensionField: 0x4A17, InitialPacketSequenceNumber: recvcif.InitialPacketSequenceNumber, MaxTransmissionUnitSize: recvcif.MaxTransmissionUnitSize, MaxFlowWindowSize: recvcif.MaxFlowWindowSize, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: recvcif.SRTSocketId, SynCookie: 1234, } sendcif.PeerIP.FromNetAddr(ln.LocalAddr()) p.MarshalCIF(sendcif) var outbuf bytes.Buffer err = p.Marshal(&outbuf) require.NoError(t, err) ln.WriteTo(outbuf.Bytes(), p.Header().Addr) // read conclusion request n, addr, err = ln.ReadFrom(buf) require.NoError(t, err) p, err = packet.NewPacketFromData(addr, buf[:n]) require.NoError(t, err) recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, packet.HSTYPE_CONCLUSION, recvcif.HandshakeType) // write invalid conclusion response p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif = recvcif sendcif.IsRequest = false sendcif.SRTSocketId = 9876 sendcif.SynCookie = 0 sendcif.PeerIP.FromNetAddr(ln.LocalAddr()) sendcif.HasHS = false p.MarshalCIF(sendcif) outbuf.Reset() err = p.Marshal(&outbuf) require.NoError(t, err) ln.WriteTo(outbuf.Bytes(), p.Header().Addr) }() _, err = Dial("srt", "127.0.0.1:6003", DefaultConfig()) require.EqualError(t, err, "missing handshake extension") } ================================================ FILE: doc.go ================================================ /* Package srt provides an interface for network I/O using the SRT protocol (https://github.com/Haivision/srt). The package gives access to the basic interface provided by the Dial, Listen, and Accept functions and the associated Conn and Listener interfaces. The Dial function connects to a server: conn, err := srt.Dial("srt", "golang.org:6000", srt.Config{ StreamId: "...", }) if err != nil { // handle error } buffer := make([]byte, 2048) for { n, err := conn.Read(buffer) if err != nil { // handle error } // handle received data } conn.Close() The Listen function creates servers: ln, err := srt.Listen("srt", ":6000", srt.Config{...}) if err != nil { // handle error } for { conn, mode, err := ln.Accept(handleConnect) if err != nil { // handle error } if mode == srt.REJECT { // rejected connection, ignore continue } if mode == srt.PUBLISH { go handlePublish(conn) } else { go handleSubscribe(conn) } } The ln.Accept function expects a function that takes a srt.ConnRequest and returns a srt.ConnType. The srt.ConnRequest lets you retrieve the streamid with on which you can decide what mode (srt.ConnType) to return. Check out the Server type that wraps the Listen and Accept into a convenient framework for your own SRT server. */ package srt ================================================ FILE: go.mod ================================================ module github.com/datarhei/gosrt go 1.25.0 require ( github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c github.com/pkg/profile v1.7.0 github.com/stretchr/testify v1.11.1 golang.org/x/net v0.54.0 golang.org/x/sys v0.44.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/fgprof v0.9.3 // indirect github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) ================================================ FILE: go.sum ================================================ github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYhJeJ2aZxADI2tGADS15AzIF8MQ8XAhT4= github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w= golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= ================================================ FILE: listen.go ================================================ package srt import ( "bytes" "context" "errors" "fmt" "net" "net/netip" "os" "sync" "time" srtnet "github.com/datarhei/gosrt/net" "github.com/datarhei/gosrt/packet" ) // ConnType represents the kind of connection as returned // from the AcceptFunc. It is one of REJECT, PUBLISH, or SUBSCRIBE. type ConnType int // String returns a string representation of the ConnType. func (c ConnType) String() string { switch c { case REJECT: return "REJECT" case PUBLISH: return "PUBLISH" case SUBSCRIBE: return "SUBSCRIBE" default: return "" } } const ( REJECT ConnType = ConnType(1 << iota) // Reject a connection PUBLISH // This connection is meant to write data to the server SUBSCRIBE // This connection is meant to read data from a PUBLISHed stream ) // RejectionReason are the rejection reasons that can be returned from the AcceptFunc in order to send // another reason than the default one (REJ_PEER) to the client. type RejectionReason uint32 // Table 7: Handshake Rejection Reason Codes const ( REJ_UNKNOWN RejectionReason = 1000 // unknown reason REJ_SYSTEM RejectionReason = 1001 // system function error REJ_PEER RejectionReason = 1002 // rejected by peer REJ_RESOURCE RejectionReason = 1003 // resource allocation problem REJ_ROGUE RejectionReason = 1004 // incorrect data in handshake REJ_BACKLOG RejectionReason = 1005 // listener's backlog exceeded REJ_IPE RejectionReason = 1006 // internal program error REJ_CLOSE RejectionReason = 1007 // socket is closing REJ_VERSION RejectionReason = 1008 // peer is older version than agent's min REJ_RDVCOOKIE RejectionReason = 1009 // rendezvous cookie collision REJ_BADSECRET RejectionReason = 1010 // wrong password REJ_UNSECURE RejectionReason = 1011 // password required or unexpected REJ_MESSAGEAPI RejectionReason = 1012 // stream flag collision REJ_CONGESTION RejectionReason = 1013 // incompatible congestion-controller type REJ_FILTER RejectionReason = 1014 // incompatible packet filter REJ_GROUP RejectionReason = 1015 // incompatible group ) // These are the extended rejection reasons that may be less well supported // Codes & their meanings taken from https://github.com/Haivision/srt/blob/f477af533562505abf5295f059cf2156b17be740/srtcore/access_control.h const ( REJX_BAD_REQUEST RejectionReason = 1400 // General syntax error in the SocketID specification (also a fallback code for undefined cases) REJX_UNAUTHORIZED RejectionReason = 1401 // Authentication failed, provided that the user was correctly identified and access to the required resource would be granted REJX_OVERLOAD RejectionReason = 1402 // The server is too heavily loaded, or you have exceeded credits for accessing the service and the resource. REJX_FORBIDDEN RejectionReason = 1403 // Access denied to the resource by any kind of reason. REJX_NOTFOUND RejectionReason = 1404 // Resource not found at this time. REJX_BAD_MODE RejectionReason = 1405 // The mode specified in `m` key in StreamID is not supported for this request. REJX_UNACCEPTABLE RejectionReason = 1406 // The requested parameters specified in SocketID cannot be satisfied for the requested resource. Also when m=publish and the data format is not acceptable. REJX_CONFLICT RejectionReason = 1407 // The resource being accessed is already locked for modification. This is in case of m=publish and the specified resource is currently read-only. REJX_NOTSUP_MEDIA RejectionReason = 1415 // The media type is not supported by the application. This is the `t` key that specifies the media type as stream, file and auth, possibly extended by the application. REJX_LOCKED RejectionReason = 1423 // The resource being accessed is locked for any access. REJX_FAILED_DEPEND RejectionReason = 1424 // The request failed because it specified a dependent session ID that has been disconnected. REJX_ISE RejectionReason = 1500 // Unexpected internal server error REJX_UNIMPLEMENTED RejectionReason = 1501 // The request was recognized, but the current version doesn't support it. REJX_GW RejectionReason = 1502 // The server acts as a gateway and the target endpoint rejected the connection. REJX_DOWN RejectionReason = 1503 // The service has been temporarily taken over by a stub reporting this error. The real service can be down for maintenance or crashed. REJX_VERSION RejectionReason = 1505 // SRT version not supported. This might be either unsupported backward compatibility, or an upper value of a version. REJX_NOROOM RejectionReason = 1507 // The data stream cannot be archived due to lacking storage space. This is in case when the request type was to send a file or the live stream to be archived. ) // ErrListenerClosed is returned when the listener is about to shutdown. var ErrListenerClosed = errors.New("srt: listener closed") // AcceptFunc receives a connection request and returns the type of connection // and is required by the Listener for each Accept of a new connection. type AcceptFunc func(req ConnRequest) ConnType // Listener waits for new connections type Listener interface { // Accept2 waits for new connections. // On closing the err will be ErrListenerClosed. Accept2() (ConnRequest, error) // Accept waits for new connections. For each new connection the AcceptFunc // gets called. Conn is a new connection if AcceptFunc is PUBLISH or SUBSCRIBE. // If AcceptFunc returns REJECT, Conn is nil. In case of failure error is not // nil, Conn is nil and ConnType is REJECT. On closing the listener err will // be ErrListenerClosed and ConnType is REJECT. // // Deprecated: replaced by Accept2(). Accept(AcceptFunc) (Conn, ConnType, error) // Close closes the listener. It will stop accepting new connections and // close all currently established connections. Close() // Addr returns the address of the listener. Addr() net.Addr } // listener implements the Listener interface. type listener struct { pc *packetConn addr net.Addr config Config backlog chan packet.Packet conns map[uint32]*srtConn connsByPeer map[uint32]*srtConn lock sync.RWMutex start time.Time rcvQueue chan packet.Packet sndMutex sync.Mutex sndData bytes.Buffer syncookie *srtnet.SYNCookie shutdown bool shutdownLock sync.RWMutex shutdownOnce sync.Once stopReader context.CancelFunc doneChan chan struct{} doneErr error doneOnce sync.Once } // Listen returns a new listener on the SRT protocol on the address with // the provided config. The network parameter needs to be "srt". // // The address has the form "host:port". // // Examples: // // Listen("srt", "127.0.0.1:3000", DefaultConfig()) // // In case of an error, the returned Listener is nil and the error is non-nil. func Listen(network, address string, config Config) (Listener, error) { if network != "srt" { return nil, fmt.Errorf("listen: the network must be 'srt'") } if err := config.Validate(); err != nil { return nil, fmt.Errorf("listen: invalid config: %w", err) } if config.Logger == nil { config.Logger = NewLogger(nil) } ln := &listener{ config: config, } lc := net.ListenConfig{ Control: ListenControl(config), } network = "udp" ip, _, err := net.SplitHostPort(address) if err != nil { return nil, fmt.Errorf("listen: invalid address: %w", err) } if len(ip) != 0 { addr, err := netip.ParseAddr(ip) if err != nil { return nil, fmt.Errorf("listen: invalid address: %w", err) } if addr.Is4() { network = "udp4" } else if addr.Is6() { network = "udp6" } } lp, err := lc.ListenPacket(context.Background(), network, address) if err != nil { return nil, fmt.Errorf("listen: %w", err) } pc := lp.(*net.UDPConn) ln.addr = pc.LocalAddr() if ln.addr == nil { return nil, fmt.Errorf("listen: no local address") } ln.pc = newPacketConn(pc) ln.conns = make(map[uint32]*srtConn) ln.connsByPeer = make(map[uint32]*srtConn) ln.backlog = make(chan packet.Packet, 128) ln.rcvQueue = make(chan packet.Packet, 2048) syncookie, err := srtnet.NewSYNCookie(ln.addr.String(), nil) if err != nil { ln.Close() return nil, err } ln.syncookie = syncookie ln.doneChan = make(chan struct{}) ln.start = time.Now() var readerCtx context.Context readerCtx, ln.stopReader = context.WithCancel(context.Background()) go ln.reader(readerCtx) go func() { buffer := make([]byte, config.MSS) // MTU size for { if ln.isShutdown() { ln.markDone(ErrListenerClosed) return } ln.pc.SetReadDeadline(time.Now().Add(3 * time.Second)) n, addr, localIP, err := ln.pc.readFromTo(buffer) if err != nil { if errors.Is(err, os.ErrDeadlineExceeded) { continue } if ln.isShutdown() { ln.markDone(ErrListenerClosed) return } ln.markDone(err) return } p, err := packet.NewPacketFromData(addr, buffer[:n]) if err != nil { continue } if localIP != nil { laddr := ln.addr.(*net.UDPAddr) p.Header().LocalAddr = &net.UDPAddr{IP: localIP, Port: laddr.Port} } // non-blocking select { case ln.rcvQueue <- p: default: ln.log("listen", func() string { return "receive queue is full" }) } } }() return ln, nil } func (ln *listener) Accept2() (ConnRequest, error) { if ln.isShutdown() { return nil, ErrListenerClosed } for { select { case <-ln.doneChan: return nil, ln.error() case p := <-ln.backlog: req := newConnRequest(ln, p) if req == nil { break } return req, nil } } } func (ln *listener) Accept(acceptFn AcceptFunc) (Conn, ConnType, error) { for { req, err := ln.Accept2() if err != nil { return nil, REJECT, err } if acceptFn == nil { req.Reject(REJ_PEER) continue } mode := acceptFn(req) if mode != PUBLISH && mode != SUBSCRIBE { // Figure out the reason reason := REJ_PEER if req.(*connRequest).rejectionReason > 0 { reason = req.(*connRequest).rejectionReason } req.Reject(reason) continue } conn, err := req.Accept() if err != nil { continue } return conn, mode, nil } } // markDone marks the listener as done by closing // the done channel & sets the error func (ln *listener) markDone(err error) { ln.doneOnce.Do(func() { ln.lock.Lock() defer ln.lock.Unlock() ln.doneErr = err close(ln.doneChan) }) } // error returns the error that caused the listener to be done // if it's nil then the listener is not done func (ln *listener) error() error { ln.lock.Lock() defer ln.lock.Unlock() return ln.doneErr } func (ln *listener) handleShutdown(c *srtConn) { ln.lock.Lock() delete(ln.conns, c.socketId) delete(ln.connsByPeer, c.peerSocketId) ln.lock.Unlock() } func (ln *listener) isShutdown() bool { ln.shutdownLock.RLock() defer ln.shutdownLock.RUnlock() return ln.shutdown } func (ln *listener) Close() { ln.shutdownOnce.Do(func() { ln.shutdownLock.Lock() ln.shutdown = true ln.shutdownLock.Unlock() ln.lock.RLock() for _, conn := range ln.conns { if conn == nil { continue } conn.close() } ln.lock.RUnlock() ln.stopReader() ln.log("listen", func() string { return "closing socket" }) ln.pc.Close() }) } func (ln *listener) Addr() net.Addr { addrString := "0.0.0.0:0" if ln.addr != nil { addrString = ln.addr.String() } addr, _ := net.ResolveUDPAddr("udp", addrString) return addr } func (ln *listener) reader(ctx context.Context) { defer func() { ln.log("listen", func() string { return "left reader loop" }) }() ln.log("listen", func() string { return "reader loop started" }) for { select { case <-ctx.Done(): return case p := <-ln.rcvQueue: if ln.isShutdown() { break } ln.log("packet:recv:dump", func() string { return p.Dump() }) if p.Header().DestinationSocketId == 0 { if p.Header().IsControlPacket && p.Header().ControlType == packet.CTRLTYPE_HANDSHAKE { select { case ln.backlog <- p: default: ln.log("handshake:recv:error", func() string { return "backlog is full" }) } } break } ln.lock.RLock() conn, ok := ln.conns[p.Header().DestinationSocketId] ln.lock.RUnlock() if !ok || conn == nil { // ignore the packet, we don't know the destination break } if !ln.config.AllowPeerIpChange { if p.Header().Addr.String() != conn.RemoteAddr().String() { // ignore the packet, it's not from the expected peer // https://haivision.github.io/srt-rfc/draft-sharabayko-srt.html#name-security-considerations break } } conn.push(p) } } } // Send a packet to the wire. This function must be synchronous in order to allow to safely call Packet.Decommission() afterward. func (ln *listener) send(p packet.Packet) { ln.sndMutex.Lock() defer ln.sndMutex.Unlock() ln.sndData.Reset() if err := p.Marshal(&ln.sndData); err != nil { p.Decommission() ln.log("packet:send:error", func() string { return "marshalling packet failed" }) return } buffer := ln.sndData.Bytes() ln.log("packet:send:dump", func() string { return p.Dump() }) // Write the packet's contents to the wire ln.pc.writeToFrom(buffer, p.Header().Addr, p.Header().LocalAddr) if p.Header().IsControlPacket { // Control packets can be decommissioned because they will not be sent again (data packets might be retransferred) p.Decommission() } } func (ln *listener) log(topic string, message func() string) { if ln.config.Logger == nil { return } ln.config.Logger.Print(topic, 0, 2, message) } ================================================ FILE: listen_test.go ================================================ package srt import ( "bytes" "context" "net" "strconv" "sync" "testing" "time" "github.com/datarhei/gosrt/circular" "github.com/datarhei/gosrt/packet" "github.com/stretchr/testify/require" ) func TestListenReuse(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) ln.Close() ln, err = Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) ln.Close() } func TestListen(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { require.Equal(t, "foobar", req.StreamId()) require.False(t, req.IsEncrypted()) return SUBSCRIBE }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() config := DefaultConfig() config.StreamId = "foobar" conn, err := Dial("srt", "127.0.0.1:6003", config) require.NoError(t, err) err = conn.Close() require.NoError(t, err) ln.Close() } func TestListenCrypt(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenWg := sync.WaitGroup{} listenWg.Add(1) go func(ln Listener) { listenWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { require.Equal(t, "foobar", req.StreamId()) require.True(t, req.IsEncrypted()) if req.SetPassphrase("zaboofzaboof") != nil { return REJECT } return SUBSCRIBE }) if err == ErrListenerClosed { return } require.NoError(t, err) } }(ln) listenWg.Wait() config := DefaultConfig() config.StreamId = "foobar" config.Passphrase = "zaboofzaboof" conn, err := Dial("srt", "127.0.0.1:6003", config) require.NoError(t, err) err = conn.Close() require.NoError(t, err) config.Passphrase = "raboofraboof" _, err = Dial("srt", "127.0.0.1:6003", config) require.Error(t, err) ln.Close() } func TestListenHSV4(t *testing.T) { start := time.Now() lc := net.ListenConfig{ Control: ListenControl(DefaultConfig()), } lp, err := lc.ListenPacket(context.Background(), "udp", "127.0.0.1:6003") require.NoError(t, err) pc := lp.(*net.UDPConn) listenWg := sync.WaitGroup{} packets := make(chan packet.Packet, 16) listenWg.Add(1) go func() { buffer := make([]byte, MAX_MSS_SIZE) listenWg.Done() for { n, addr, err := pc.ReadFrom(buffer) if err != nil { return } p, err := packet.NewPacketFromData(addr, buffer[:n]) require.NoError(t, err) if p.Header().ControlType != packet.CTRLTYPE_HANDSHAKE { continue } packets <- p } }() listenWg.Wait() go func() { conn, err := Dial("srt", "127.0.0.1:6003", DefaultConfig()) if err != nil { if err == ErrClientClosed { return } require.NoError(t, err) } require.NotNil(t, conn) conn.Close() }() p := <-packets recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, uint32(4), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(2), recvcif.ExtensionField) require.Equal(t, packet.HSTYPE_INDUCTION, recvcif.HandshakeType) require.Empty(t, recvcif.SynCookie) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif := &packet.CIFHandshake{ IsRequest: false, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: recvcif.InitialPacketSequenceNumber, MaxTransmissionUnitSize: recvcif.MaxTransmissionUnitSize, MaxFlowWindowSize: recvcif.MaxFlowWindowSize, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: recvcif.SRTSocketId, SynCookie: 1234, } sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) var data bytes.Buffer err = p.Marshal(&data) require.NoError(t, err) pc.WriteTo(data.Bytes(), p.Header().Addr) p = <-packets recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, uint32(4), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(2), recvcif.ExtensionField) require.Equal(t, packet.HSTYPE_CONCLUSION, recvcif.HandshakeType) require.Equal(t, sendcif.SynCookie, recvcif.SynCookie) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif = recvcif sendcif.IsRequest = false sendcif.SRTSocketId = 9876 sendcif.SynCookie = 0 sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) data.Reset() err = p.Marshal(&data) require.NoError(t, err) pc.WriteTo(data.Bytes(), p.Header().Addr) pc.Close() } func TestListenHSV5(t *testing.T) { start := time.Now() lc := net.ListenConfig{ Control: ListenControl(DefaultConfig()), } lp, err := lc.ListenPacket(context.Background(), "udp", "127.0.0.1:6003") require.NoError(t, err) pc := lp.(*net.UDPConn) listenWg := sync.WaitGroup{} packets := make(chan packet.Packet, 16) listenWg.Add(1) go func() { buffer := make([]byte, MAX_MSS_SIZE) listenWg.Done() for { n, addr, err := pc.ReadFrom(buffer) if err != nil { return } p, err := packet.NewPacketFromData(addr, buffer[:n]) require.NoError(t, err) if p.Header().ControlType != packet.CTRLTYPE_HANDSHAKE { continue } packets <- p } }() listenWg.Wait() go func() { config := DefaultConfig() config.StreamId = "foobar" conn, err := Dial("srt", "127.0.0.1:6003", config) if err != nil { if err == ErrClientClosed { return } require.NoError(t, err) } require.NotNil(t, conn) conn.Close() }() p := <-packets recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, uint32(4), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(2), recvcif.ExtensionField) require.Equal(t, packet.HSTYPE_INDUCTION, recvcif.HandshakeType) require.Empty(t, recvcif.SynCookie) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif := &packet.CIFHandshake{ IsRequest: false, Version: 5, EncryptionField: 0, ExtensionField: 0x4A17, InitialPacketSequenceNumber: recvcif.InitialPacketSequenceNumber, MaxTransmissionUnitSize: recvcif.MaxTransmissionUnitSize, MaxFlowWindowSize: recvcif.MaxFlowWindowSize, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: recvcif.SRTSocketId, SynCookie: 1234, } sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) var data bytes.Buffer err = p.Marshal(&data) require.NoError(t, err) pc.WriteTo(data.Bytes(), p.Header().Addr) p = <-packets recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, uint32(5), recvcif.Version) require.Equal(t, uint16(0), recvcif.EncryptionField) require.Equal(t, uint16(5), recvcif.ExtensionField) require.Equal(t, packet.HSTYPE_CONCLUSION, recvcif.HandshakeType) require.Equal(t, sendcif.SynCookie, recvcif.SynCookie) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = uint32(time.Since(start).Microseconds()) p.Header().DestinationSocketId = recvcif.SRTSocketId sendcif = recvcif sendcif.IsRequest = false sendcif.SRTSocketId = 9876 sendcif.SynCookie = 0 sendcif.PeerIP.FromNetAddr(pc.LocalAddr()) p.MarshalCIF(sendcif) data.Reset() err = p.Marshal(&data) require.NoError(t, err) pc.WriteTo(data.Bytes(), p.Header().Addr) pc.Close() } func TestListenAsync(t *testing.T) { const parallelCount = 2 ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) var ( // All streams are pending pendingWg sync.WaitGroup pendingSet sync.Map // Set of which streams are pending // All streams are connected connectedWg sync.WaitGroup // All listener goroutines are stopped listenerWg sync.WaitGroup ) listenerWg.Add(parallelCount) pendingWg.Add(parallelCount) connectedWg.Add(parallelCount) for i := range parallelCount { go func() { defer listenerWg.Done() for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { // Only call Done() if we're the first request for this stream if _, ok := pendingSet.Swap(req.StreamId(), struct{}{}); !ok { pendingWg.Done() } // Wait for all streams to be pending Before returning pendingWg.Wait() return PUBLISH }) if err == ErrListenerClosed { return } require.NoError(t, err) } }() go func(streamId string) { config := DefaultConfig() config.StreamId = streamId conn, err := Dial("srt", "127.0.0.1:6003", config) require.NoError(t, err) connectedWg.Done() conn.Close() }(strconv.Itoa(i)) } // Wait for all streams to be connected connectedWg.Wait() ln.Close() listenerWg.Wait() } func TestListenHSV5MissingExtension(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenDone := make(chan struct{}) defer func() { <-listenDone }() go func() { defer close(listenDone) for { _, _, err := ln.Accept(func(req ConnRequest) ConnType { return SUBSCRIBE }) if err != nil { break } } }() conn, err := net.Dial("udp", "127.0.0.1:6003") require.NoError(t, err) defer conn.Close() // send induction request p := packet.NewPacket(conn.RemoteAddr()) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 sendcif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(10000, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: MAX_MSS_SIZE, MaxFlowWindowSize: 25600, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 55555, SynCookie: 0, } sendcif.PeerIP.FromNetAddr(conn.LocalAddr()) p.MarshalCIF(sendcif) var buf bytes.Buffer err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // read induction response inbuf := make([]byte, MAX_MSS_SIZE) n, err := conn.Read(inbuf) require.NoError(t, err) p, err = packet.NewPacketFromData(conn.RemoteAddr(), inbuf[:n]) require.NoError(t, err) recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) // send conclusion p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 // recvcif.SRTSocketId sendcif.Version = 5 sendcif.ExtensionField = recvcif.ExtensionField sendcif.HandshakeType = packet.HSTYPE_CONCLUSION sendcif.SynCookie = recvcif.SynCookie sendcif.HasSID = true sendcif.StreamId = "foobar" p.MarshalCIF(sendcif) buf.Reset() err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // read error n, err = conn.Read(inbuf) require.NoError(t, err) p, err = packet.NewPacketFromData(conn.RemoteAddr(), inbuf[:n]) require.NoError(t, err) recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, recvcif.HandshakeType, packet.HandshakeType(REJ_ROGUE)) ln.Close() } func TestListenParallelRequests(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) listenDone := make(chan struct{}) defer func() { <-listenDone }() var reqReady sync.WaitGroup reqReady.Add(4) var serverSideConnReady sync.WaitGroup serverSideConnReady.Add(4) go func() { defer close(listenDone) for { req, err := ln.Accept2() if err != nil { break } reqReady.Done() go func() { defer serverSideConnReady.Done() // wait for all requests to be pending reqReady.Wait() conn, err := req.Accept() require.NoError(t, err) conn.Close() }() } }() var clientSideConnReady sync.WaitGroup for range 4 { clientSideConnReady.Go(func() { config := DefaultConfig() config.StreamId = "foobar" conn, err := Dial("srt", "127.0.0.1:6003", config) require.NoError(t, err) err = conn.Close() require.NoError(t, err) }) } serverSideConnReady.Wait() clientSideConnReady.Wait() ln.Close() } func TestListenDiscardRepeatedHandshakes(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) singleReqReceived := make(chan struct{}) listenDone := make(chan struct{}) defer func() { <-listenDone }() defer ln.Close() go func() { defer close(listenDone) for { req, err := ln.Accept2() if err != nil { break } close(singleReqReceived) defer req.Reject(REJ_CLOSE) } }() for range 4 { conn, err := net.Dial("udp", "127.0.0.1:6003") require.NoError(t, err) defer conn.Close() // send induction request p := packet.NewPacket(conn.RemoteAddr()) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 sendcif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(10000, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: MAX_MSS_SIZE, MaxFlowWindowSize: 25600, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 55555, SynCookie: 0, } sendcif.PeerIP.FromNetAddr(conn.LocalAddr()) p.MarshalCIF(sendcif) var buf bytes.Buffer err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // read induction response inbuf := make([]byte, 1024) n, err := conn.Read(inbuf) require.NoError(t, err) p, err = packet.NewPacketFromData(conn.RemoteAddr(), inbuf[:n]) require.NoError(t, err) recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) // send conclusion p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 // recvcif.SRTSocketId sendcif.Version = 5 sendcif.ExtensionField = recvcif.ExtensionField sendcif.HandshakeType = packet.HSTYPE_CONCLUSION sendcif.SynCookie = recvcif.SynCookie sendcif.HasHS = true sendcif.SRTHS = &packet.CIFHandshakeExtension{ SRTVersion: SRT_VERSION, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, TSBPDRCV: true, CRYPT: true, // must always set to true TLPKTDROP: true, PERIODICNAK: true, REXMITFLG: true, STREAM: false, PACKET_FILTER: false, }, RecvTSBPDDelay: uint16(120), SendTSBPDDelay: uint16(120), } sendcif.HasSID = true sendcif.StreamId = "foobar" p.MarshalCIF(sendcif) buf.Reset() err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) } <-singleReqReceived } func TestListenMultipleIPs(t *testing.T) { ln, err := Listen("srt", "0.0.0.0:6003", DefaultConfig()) require.NoError(t, err) defer ln.Close() serverDone := make(chan struct{}) go func() { defer close(serverDone) req, err := ln.Accept2() require.NoError(t, err) conn, err := req.Accept() require.NoError(t, err) defer conn.Close() localAddr, ok := conn.LocalAddr().(*net.UDPAddr) require.True(t, ok) require.Equal(t, "127.0.0.2", localAddr.IP.String()) }() // Dial to the secondary loopback address. Without the fix the listener // responds from 127.0.0.1 (kernel routing choice), which the client's // connected socket discards, causing Dial to time out. clientConn, err := Dial("srt", "127.0.0.2:6003", DefaultConfig()) require.NoError(t, err) defer clientConn.Close() <-serverDone } func TestListenAcceptAndDiscardRepeatedHandshakes(t *testing.T) { ln, err := Listen("srt", "127.0.0.1:6003", DefaultConfig()) require.NoError(t, err) singleReqAccepted := make(chan struct{}) listenDone := make(chan struct{}) defer func() { <-listenDone }() defer ln.Close() go func() { defer close(listenDone) for { req, err := ln.Accept2() if err != nil { break } conn, err := req.Accept() require.NoError(t, err) defer conn.Close() close(singleReqAccepted) } }() conn, err := net.Dial("udp", "127.0.0.1:6003") require.NoError(t, err) defer conn.Close() // write induction request p := packet.NewPacket(conn.RemoteAddr()) p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 sendcif := &packet.CIFHandshake{ IsRequest: true, Version: 4, EncryptionField: 0, ExtensionField: 2, InitialPacketSequenceNumber: circular.New(10000, packet.MAX_SEQUENCENUMBER), MaxTransmissionUnitSize: MAX_MSS_SIZE, MaxFlowWindowSize: 25600, HandshakeType: packet.HSTYPE_INDUCTION, SRTSocketId: 55555, SynCookie: 0, } sendcif.PeerIP.FromNetAddr(conn.LocalAddr()) p.MarshalCIF(sendcif) var buf bytes.Buffer err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // read induction response inbuf := make([]byte, MAX_MSS_SIZE) n, err := conn.Read(inbuf) require.NoError(t, err) p, err = packet.NewPacketFromData(conn.RemoteAddr(), inbuf[:n]) require.NoError(t, err) recvcif := &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) // write conclusion request p.Header().IsControlPacket = true p.Header().ControlType = packet.CTRLTYPE_HANDSHAKE p.Header().SubType = 0 p.Header().TypeSpecific = 0 p.Header().Timestamp = 0 p.Header().DestinationSocketId = 0 sendcif.Version = 5 sendcif.ExtensionField = recvcif.ExtensionField sendcif.HandshakeType = packet.HSTYPE_CONCLUSION sendcif.SRTSocketId = 234425644 sendcif.SynCookie = recvcif.SynCookie sendcif.HasHS = true sendcif.SRTHS = &packet.CIFHandshakeExtension{ SRTVersion: SRT_VERSION, SRTFlags: packet.CIFHandshakeExtensionFlags{ TSBPDSND: true, TSBPDRCV: true, CRYPT: true, TLPKTDROP: true, PERIODICNAK: true, REXMITFLG: true, STREAM: false, PACKET_FILTER: false, }, RecvTSBPDDelay: uint16(120), SendTSBPDDelay: uint16(120), } sendcif.HasSID = true sendcif.StreamId = "foobar" p.MarshalCIF(sendcif) buf.Reset() err = p.Marshal(&buf) require.NoError(t, err) _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // read conclusion response n, err = conn.Read(inbuf) require.NoError(t, err) p, err = packet.NewPacketFromData(conn.RemoteAddr(), inbuf[:n]) require.NoError(t, err) recvcif = &packet.CIFHandshake{} err = p.UnmarshalCIF(recvcif) require.NoError(t, err) require.Equal(t, packet.HSTYPE_CONCLUSION, recvcif.HandshakeType) require.False(t, recvcif.IsRequest) <-singleReqAccepted // write conclusion request, again _, err = conn.Write(buf.Bytes()) require.NoError(t, err) // wait some time to make sure that close(singleReqAccepted) is not triggered time.Sleep(500 * time.Millisecond) } ================================================ FILE: log.go ================================================ package srt import ( "runtime" "strings" "time" ) // Logger is for logging debug messages. type Logger interface { // HasTopic returns whether this Logger is logging messages of that topic. HasTopic(topic string) bool // Print adds a new message to the message queue. The message itself is // a function that returns the string to be logges. It will only be // executed if HasTopic returns true on the given topic. Print(topic string, socketId uint32, skip int, message func() string) // Listen returns a read channel for Log messages. Listen() <-chan Log // Close closes the logger. No more messages will be logged. Close() } // logger implements a Logger type logger struct { logQueue chan Log topics map[string]bool } // NewLogger returns a Logger that only listens on the given list of topics. func NewLogger(topics []string) Logger { l := &logger{ logQueue: make(chan Log, 1024), topics: make(map[string]bool), } for _, topic := range topics { l.topics[topic] = true } return l } func (l *logger) HasTopic(topic string) bool { if len(l.topics) == 0 { return false } if ok := l.topics[topic]; ok { return true } len := len(topic) for { i := strings.LastIndexByte(topic[:len], ':') if i == -1 { break } len = i if ok := l.topics[topic[:len]]; !ok { continue } return true } return false } func (l *logger) Print(topic string, socketId uint32, skip int, message func() string) { if !l.HasTopic(topic) { return } _, file, line, _ := runtime.Caller(skip) msg := Log{ Time: time.Now(), SocketId: socketId, Topic: topic, Message: message(), File: file, Line: line, } // Write to log queue, but don't block if it's full select { case l.logQueue <- msg: default: } } func (l *logger) Listen() <-chan Log { return l.logQueue } func (l *logger) Close() { close(l.logQueue) } // Log represents a log message type Log struct { Time time.Time // Time of when this message has been logged SocketId uint32 // The socketid if connection related, 0 otherwise Topic string // The topic of this message Message string // The message itself File string // The file in which this message has been dispatched Line int // The line number in the file in which this message has been dispatched } ================================================ FILE: log_test.go ================================================ package srt import ( "testing" "github.com/stretchr/testify/require" ) func TestHasTopic(t *testing.T) { l := NewLogger([]string{ "packet:recv:dump", }) ok := l.HasTopic("foobar") require.False(t, ok) ok = l.HasTopic("packet:recv:dump") require.True(t, ok) ok = l.HasTopic("packet:recv") require.False(t, ok) ok = l.HasTopic("packet") require.False(t, ok) } var result bool func BenchmarkHasTopicNil(b *testing.B) { l := NewLogger(nil) var r bool for n := 0; n < b.N; n++ { r = l.HasTopic("foobar") } result = r } func BenchmarkHasTopicD1(b *testing.B) { l := NewLogger([]string{ "packet:recv:dump", }) var r bool for n := 0; n < b.N; n++ { r = l.HasTopic("packet") } result = r } func BenchmarkHasTopicD2(b *testing.B) { l := NewLogger([]string{ "packet:recv:dump", }) var r bool for n := 0; n < b.N; n++ { r = l.HasTopic("packet:recv") } result = r } func BenchmarkHasTopicD3(b *testing.B) { l := NewLogger([]string{ "packet:recv:dump", }) var r bool for n := 0; n < b.N; n++ { r = l.HasTopic("packet:recv:dump") } result = r } ================================================ FILE: net/ip.go ================================================ package net import ( "encoding/binary" "fmt" "net" "strings" ) type IP struct { ip net.IP } func (i *IP) setDefault() { i.ip = net.IPv4(127, 0, 0, 1) } func (i *IP) isValid() bool { if i.ip == nil || i.ip.String() == "
}
```
fgprof is compatible with the `go tool pprof` visualizer, so taking and analyzing a 3s profile is as simple as:
```
go tool pprof --http=:6061 http://localhost:6060/debug/fgprof?seconds=3
```

Additionally fgprof supports the plain text format used by Brendan Gregg's [FlameGraph](http://www.brendangregg.com/flamegraphs.html) utility:
```
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
curl -s 'localhost:6060/debug/fgprof?seconds=3&format=folded' > fgprof.folded
./flamegraph.pl fgprof.folded > fgprof.svg
```

Which tool you prefer is up to you, but one thing I like about Gregg's tool is that you can filter the plaintext files using grep which can be very useful when analyzing large programs.
If you don't have a program to profile right now, you can `go run ./example` which should allow you to reproduce the graphs you see above. If you've never seen such graphs before, and are unsure how to read them, head over to Brendan Gregg's [Flame Graph](http://www.brendangregg.com/flamegraphs.html) page.
## The Problem
Let's say you've been tasked to optimize a simple program that has a loop calling out to three functions:
```go
func main() {
for {
// Http request to a web service that might be slow.
slowNetworkRequest()
// Some heavy CPU computation.
cpuIntensiveTask()
// Poorly named function that you don't understand yet.
weirdFunction()
}
}
```
One way to decide which of these three functions you should focus your attention on would be to wrap each function call like this:
```go
start := time.Start()
slowNetworkRequest()
fmt.Printf("slowNetworkRequest: %s\n", time.Since(start))
// ...
```
However, this can be very tedious for large programs. You'll also have to figure out how to average the numbers in case they fluctuate. And once you've done that, you'll have to repeat the process for the functions called by the function you decide to focus on.
### /debug/pprof/profile
So, this seems like a perfect use case for a profiler. Let's try the `/debug/pprof/profile` endpoint of the builtin `net/http/pprof` pkg to analyze our program for 10s:
```go
import _ "net/http/pprof"
func main() {
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
//
}
```
```
go tool pprof -http=:6061 http://localhost:6060/debug/pprof/profile?seconds=10
```
That was easy! Looks like we're spending all our time in `cpuIntensiveTask()`, so let's focus on that?

But before we get carried away, let's quickly double check this assumption by manually timing our function calls with `time.Since()` as described above:
```
slowNetworkRequest: 66.815041ms
cpuIntensiveTask: 30.000672ms
weirdFunction: 10.64764ms
slowNetworkRequest: 67.194516ms
cpuIntensiveTask: 30.000912ms
weirdFunction: 10.105371ms
// ...
```
Oh no, the builtin CPU profiler is misleading us! How is that possible? Well, it turns out the builtin profiler only shows On-CPU time. Time spent waiting on I/O is completely hidden from us.
### /debug/pprof/trace
Let's try something else. The `/debug/pprof/trace` endpoint includes a "synchronization blocking profile", maybe that's what we need?
```
curl -so pprof.trace http://localhost:6060/debug/pprof/trace?seconds=10
go tool trace --pprof=sync pprof.trace > sync.pprof
go tool pprof --http=:6061 sync.pprof
```
Oh no, we're being mislead again. This profiler thinks all our time is spent on `slowNetworkRequest()`. It's completely missing `cpuIntensiveTask()`. And what about `weirdFunction()`? It seems like no builtin profiler can see it?

### /debug/fgprof
So what can we do? Let's try fgprof, which is designed to analyze mixed I/O and CPU workloads like the one we're dealing with here. We can easily add it alongside the builtin profilers.
```go
import(
_ "net/http/pprof"
"github.com/felixge/fgprof"
)
func main() {
http.DefaultServeMux.Handle("/debug/fgprof", fgprof.Handler())
go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()
//
}
```
```
go tool pprof --http=:6061 http://localhost:6060/debug/fgprof?seconds=10
```
Finally, a profile that shows all three of our functions and how much time we're spending on them. It also turns out our `weirdFunction()` was simply calling `time.Sleep()`, how weird indeed!

## How it Works
### fgprof
fgprof is implemented as a background goroutine that wakes up 99 times per second and calls `runtime.GoroutineProfile`. This returns a list of all goroutines regardless of their current On/Off CPU scheduling status and their call stacks.
This data is used to maintain an in-memory stack counter which can be converted to the pprof or folded output format. The meat of the implementation is super simple and < 100 lines of code, you should [check it out](./fgprof.go).
The overhead of fgprof increases with the number of active goroutines (including those waiting on I/O, Channels, Locks, etc.) executed by your program. If your program typically has less than 1000 active goroutines, you shouldn't have much to worry about. However, at 10k or more goroutines fgprof might start to cause some noticeable overhead.
### Go's builtin CPU Profiler
The builtin Go CPU profiler uses the [setitimer(2)](https://linux.die.net/man/2/setitimer) system call to ask the operating system to be sent a `SIGPROF` signal 100 times a second. Each signal stops the Go process and gets delivered to a random thread's `sigtrampgo()` function. This function then proceeds to call `sigprof()` or `sigprofNonGo()` to record the thread's current stack.
Since Go uses non-blocking I/O, Goroutines that wait on I/O are parked and not running on any threads. Therefore they end up being largely invisible to Go's builtin CPU profiler.
## Known Issues
There is no perfect approach to profiling, and fgprof is no exception. Below is a list of known issues that will hopefully not be of practical concern for most users, but are important to highlight.
- Internal C functions are not showing up in the stack traces, e.g. `runtime.nanotime` which is called by `time.Since` in the example program.
- The current implementation is relying on the Go scheduler to schedule the internal goroutine at a fixed sample rate. Scheduler delays, especially biased ones, might cause inaccuracies.
## Credits
The following articles helped me to learn more about how profilers in general, and the Go profiler in particular work.
- [How do Ruby & Python profilers work?](https://jvns.ca/blog/2017/12/17/how-do-ruby---python-profilers-work-/) by Julia Evans
- [Profiling Go programs with pprof](https://jvns.ca/blog/2017/09/24/profiling-go-with-pprof/) by Julia Evans
## License
fgprof is licensed under the MIT License.
================================================
FILE: vendor/github.com/felixge/fgprof/fgprof.go
================================================
// fgprof is a sampling Go profiler that allows you to analyze On-CPU as well
// as [Off-CPU](http://www.brendangregg.com/offcpuanalysis.html) (e.g. I/O)
// time together.
package fgprof
import (
"fmt"
"io"
"runtime"
"sort"
"strings"
"time"
"github.com/google/pprof/profile"
)
// Format decides how the output is rendered to the user.
type Format string
const (
// FormatFolded is used by Brendan Gregg's FlameGraph utility, see
// https://github.com/brendangregg/FlameGraph#2-fold-stacks.
FormatFolded Format = "folded"
// FormatPprof is used by Google's pprof utility, see
// https://github.com/google/pprof/blob/master/proto/README.md.
FormatPprof Format = "pprof"
)
// Start begins profiling the goroutines of the program and returns a function
// that needs to be invoked by the caller to stop the profiling and write the
// results to w using the given format.
func Start(w io.Writer, format Format) func() error {
startTime := time.Now()
// Go's CPU profiler uses 100hz, but 99hz might be less likely to result in
// accidental synchronization with the program we're profiling.
const hz = 99
ticker := time.NewTicker(time.Second / hz)
stopCh := make(chan struct{})
prof := &profiler{}
profile := newWallclockProfile()
go func() {
defer ticker.Stop()
for {
select {
case <-ticker.C:
stacks := prof.GoroutineProfile()
profile.Add(stacks)
case <-stopCh:
return
}
}
}()
return func() error {
stopCh <- struct{}{}
endTime := time.Now()
profile.Ignore(prof.SelfFrames()...)
return profile.Export(w, format, hz, startTime, endTime)
}
}
// profiler provides a convenient and performant way to access
// runtime.GoroutineProfile().
type profiler struct {
stacks []runtime.StackRecord
selfFrame *runtime.Frame
}
// GoroutineProfile returns the stacks of all goroutines currently managed by
// the scheduler. This includes both goroutines that are currently running
// (On-CPU), as well as waiting (Off-CPU).
func (p *profiler) GoroutineProfile() []runtime.StackRecord {
if p.selfFrame == nil {
// Determine the runtime.Frame of this func so we can hide it from our
// profiling output.
rpc := make([]uintptr, 1)
n := runtime.Callers(1, rpc)
if n < 1 {
panic("could not determine selfFrame")
}
selfFrame, _ := runtime.CallersFrames(rpc).Next()
p.selfFrame = &selfFrame
}
// We don't know how many goroutines exist, so we have to grow p.stacks
// dynamically. We overshoot by 10% since it's possible that more goroutines
// are launched in between two calls to GoroutineProfile. Once p.stacks
// reaches the maximum number of goroutines used by the program, it will get
// reused indefinitely, eliminating GoroutineProfile calls and allocations.
//
// TODO(fg) There might be workloads where it would be nice to shrink
// p.stacks dynamically as well, but let's not over-engineer this until we
// understand those cases better.
for {
n, ok := runtime.GoroutineProfile(p.stacks)
if !ok {
p.stacks = make([]runtime.StackRecord, int(float64(n)*1.1))
} else {
return p.stacks[0:n]
}
}
}
// SelfFrames returns frames that belong to the profiler so that we can ignore
// them when exporting the final profile.
func (p *profiler) SelfFrames() []*runtime.Frame {
if p.selfFrame != nil {
return []*runtime.Frame{p.selfFrame}
}
return nil
}
func newWallclockProfile() *wallclockProfile {
return &wallclockProfile{stacks: map[[32]uintptr]*wallclockStack{}}
}
// wallclockProfile holds a wallclock profile that can be exported in different
// formats.
type wallclockProfile struct {
stacks map[[32]uintptr]*wallclockStack
ignore []*runtime.Frame
}
// wallclockStack holds the symbolized frames of a stack trace and the number
// of times it has been seen.
type wallclockStack struct {
frames []*runtime.Frame
count int
}
// Ignore sets a list of frames that should be ignored when exporting the
// profile.
func (p *wallclockProfile) Ignore(frames ...*runtime.Frame) {
p.ignore = frames
}
// Add adds the given stack traces to the profile.
func (p *wallclockProfile) Add(stackRecords []runtime.StackRecord) {
for _, stackRecord := range stackRecords {
if _, ok := p.stacks[stackRecord.Stack0]; !ok {
ws := &wallclockStack{}
// symbolize pcs into frames
frames := runtime.CallersFrames(stackRecord.Stack())
for {
frame, more := frames.Next()
ws.frames = append(ws.frames, &frame)
if !more {
break
}
}
p.stacks[stackRecord.Stack0] = ws
}
p.stacks[stackRecord.Stack0].count++
}
}
func (p *wallclockProfile) Export(w io.Writer, f Format, hz int, startTime, endTime time.Time) error {
switch f {
case FormatFolded:
return p.exportFolded(w)
case FormatPprof:
return p.exportPprof(hz, startTime, endTime).Write(w)
default:
return fmt.Errorf("unknown format: %q", f)
}
}
// exportStacks returns the stacks in this profile except those that have been
// set to Ignore().
func (p *wallclockProfile) exportStacks() []*wallclockStack {
stacks := make([]*wallclockStack, 0, len(p.stacks))
nextStack:
for _, ws := range p.stacks {
for _, f := range ws.frames {
for _, igf := range p.ignore {
if f.Entry == igf.Entry {
continue nextStack
}
}
}
stacks = append(stacks, ws)
}
return stacks
}
func (p *wallclockProfile) exportFolded(w io.Writer) error {
var lines []string
stacks := p.exportStacks()
for _, ws := range stacks {
var foldedStack []string
for _, f := range ws.frames {
foldedStack = append(foldedStack, f.Function)
}
line := fmt.Sprintf("%s %d", strings.Join(foldedStack, ";"), ws.count)
lines = append(lines, line)
}
sort.Strings(lines)
_, err := io.WriteString(w, strings.Join(lines, "\n")+"\n")
return err
}
func (p *wallclockProfile) exportPprof(hz int, startTime, endTime time.Time) *profile.Profile {
prof := &profile.Profile{}
m := &profile.Mapping{ID: 1, HasFunctions: true}
prof.Period = int64(1e9 / hz) // Number of nanoseconds between samples.
prof.TimeNanos = startTime.UnixNano()
prof.DurationNanos = int64(endTime.Sub(startTime))
prof.Mapping = []*profile.Mapping{m}
prof.SampleType = []*profile.ValueType{
{
Type: "samples",
Unit: "count",
},
{
Type: "time",
Unit: "nanoseconds",
},
}
prof.PeriodType = &profile.ValueType{
Type: "wallclock",
Unit: "nanoseconds",
}
type functionKey struct {
Name string
Filename string
}
funcIdx := map[functionKey]*profile.Function{}
type locationKey struct {
Function functionKey
Line int
}
locationIdx := map[locationKey]*profile.Location{}
for _, ws := range p.exportStacks() {
sample := &profile.Sample{
Value: []int64{
int64(ws.count),
int64(1000 * 1000 * 1000 / hz * ws.count),
},
}
for _, frame := range ws.frames {
fnKey := functionKey{Name: frame.Function, Filename: frame.File}
function, ok := funcIdx[fnKey]
if !ok {
function = &profile.Function{
ID: uint64(len(prof.Function)) + 1,
Name: frame.Function,
SystemName: frame.Function,
Filename: frame.File,
}
funcIdx[fnKey] = function
prof.Function = append(prof.Function, function)
}
locKey := locationKey{Function: fnKey, Line: frame.Line}
location, ok := locationIdx[locKey]
if !ok {
location = &profile.Location{
ID: uint64(len(prof.Location)) + 1,
Mapping: m,
Line: []profile.Line{{
Function: function,
Line: int64(frame.Line),
}},
}
locationIdx[locKey] = location
prof.Location = append(prof.Location, location)
}
sample.Location = append(sample.Location, location)
}
prof.Sample = append(prof.Sample, sample)
}
return prof
}
type symbolizedStacks map[[32]uintptr][]frameCount
func (w wallclockProfile) Symbolize(exclude *runtime.Frame) symbolizedStacks {
m := make(symbolizedStacks)
outer:
for stack0, ws := range w.stacks {
frames := runtime.CallersFrames((&runtime.StackRecord{Stack0: stack0}).Stack())
for {
frame, more := frames.Next()
if frame.Entry == exclude.Entry {
continue outer
}
m[stack0] = append(m[stack0], frameCount{Frame: &frame, Count: ws.count})
if !more {
break
}
}
}
return m
}
type frameCount struct {
*runtime.Frame
Count int
}
================================================
FILE: vendor/github.com/felixge/fgprof/handler.go
================================================
package fgprof
import (
"fmt"
"net/http"
"strconv"
"time"
)
// Handler returns an http handler that takes an optional "seconds" query
// argument that defaults to "30" and produces a profile over this duration.
// The optional "format" parameter controls if the output is written in
// Google's "pprof" format (default) or Brendan Gregg's "folded" stack format.
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var seconds int
var err error
if s := r.URL.Query().Get("seconds"); s == "" {
seconds = 30
} else if seconds, err = strconv.Atoi(s); err != nil || seconds <= 0 {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "bad seconds: %d: %s\n", seconds, err)
return
}
format := Format(r.URL.Query().Get("format"))
if format == "" {
format = FormatPprof
}
stop := Start(w, format)
defer stop()
time.Sleep(time.Duration(seconds) * time.Second)
})
}
================================================
FILE: vendor/github.com/google/pprof/AUTHORS
================================================
# This is the official list of pprof authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as:
# Name or Organization
# The email address is not required for organizations.
Google Inc.
================================================
FILE: vendor/github.com/google/pprof/CONTRIBUTORS
================================================
# People who have agreed to one of the CLAs and can contribute patches.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# https://developers.google.com/open-source/cla/individual
# https://developers.google.com/open-source/cla/corporate
#
# Names should be added to this file as:
# Name
Raul Silvera
Tipp Moseley
Hyoun Kyu Cho
Martin Spier
Taco de Wolff
Andrew Hunter
================================================
FILE: vendor/github.com/google/pprof/LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: vendor/github.com/google/pprof/profile/encode.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profile
import (
"errors"
"sort"
)
func (p *Profile) decoder() []decoder {
return profileDecoder
}
// preEncode populates the unexported fields to be used by encode
// (with suffix X) from the corresponding exported fields. The
// exported fields are cleared up to facilitate testing.
func (p *Profile) preEncode() {
strings := make(map[string]int)
addString(strings, "")
for _, st := range p.SampleType {
st.typeX = addString(strings, st.Type)
st.unitX = addString(strings, st.Unit)
}
for _, s := range p.Sample {
s.labelX = nil
var keys []string
for k := range s.Label {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
vs := s.Label[k]
for _, v := range vs {
s.labelX = append(s.labelX,
label{
keyX: addString(strings, k),
strX: addString(strings, v),
},
)
}
}
var numKeys []string
for k := range s.NumLabel {
numKeys = append(numKeys, k)
}
sort.Strings(numKeys)
for _, k := range numKeys {
keyX := addString(strings, k)
vs := s.NumLabel[k]
units := s.NumUnit[k]
for i, v := range vs {
var unitX int64
if len(units) != 0 {
unitX = addString(strings, units[i])
}
s.labelX = append(s.labelX,
label{
keyX: keyX,
numX: v,
unitX: unitX,
},
)
}
}
s.locationIDX = make([]uint64, len(s.Location))
for i, loc := range s.Location {
s.locationIDX[i] = loc.ID
}
}
for _, m := range p.Mapping {
m.fileX = addString(strings, m.File)
m.buildIDX = addString(strings, m.BuildID)
}
for _, l := range p.Location {
for i, ln := range l.Line {
if ln.Function != nil {
l.Line[i].functionIDX = ln.Function.ID
} else {
l.Line[i].functionIDX = 0
}
}
if l.Mapping != nil {
l.mappingIDX = l.Mapping.ID
} else {
l.mappingIDX = 0
}
}
for _, f := range p.Function {
f.nameX = addString(strings, f.Name)
f.systemNameX = addString(strings, f.SystemName)
f.filenameX = addString(strings, f.Filename)
}
p.dropFramesX = addString(strings, p.DropFrames)
p.keepFramesX = addString(strings, p.KeepFrames)
if pt := p.PeriodType; pt != nil {
pt.typeX = addString(strings, pt.Type)
pt.unitX = addString(strings, pt.Unit)
}
p.commentX = nil
for _, c := range p.Comments {
p.commentX = append(p.commentX, addString(strings, c))
}
p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
p.stringTable = make([]string, len(strings))
for s, i := range strings {
p.stringTable[i] = s
}
}
func (p *Profile) encode(b *buffer) {
for _, x := range p.SampleType {
encodeMessage(b, 1, x)
}
for _, x := range p.Sample {
encodeMessage(b, 2, x)
}
for _, x := range p.Mapping {
encodeMessage(b, 3, x)
}
for _, x := range p.Location {
encodeMessage(b, 4, x)
}
for _, x := range p.Function {
encodeMessage(b, 5, x)
}
encodeStrings(b, 6, p.stringTable)
encodeInt64Opt(b, 7, p.dropFramesX)
encodeInt64Opt(b, 8, p.keepFramesX)
encodeInt64Opt(b, 9, p.TimeNanos)
encodeInt64Opt(b, 10, p.DurationNanos)
if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
encodeMessage(b, 11, p.PeriodType)
}
encodeInt64Opt(b, 12, p.Period)
encodeInt64s(b, 13, p.commentX)
encodeInt64(b, 14, p.defaultSampleTypeX)
}
var profileDecoder = []decoder{
nil, // 0
// repeated ValueType sample_type = 1
func(b *buffer, m message) error {
x := new(ValueType)
pp := m.(*Profile)
pp.SampleType = append(pp.SampleType, x)
return decodeMessage(b, x)
},
// repeated Sample sample = 2
func(b *buffer, m message) error {
x := new(Sample)
pp := m.(*Profile)
pp.Sample = append(pp.Sample, x)
return decodeMessage(b, x)
},
// repeated Mapping mapping = 3
func(b *buffer, m message) error {
x := new(Mapping)
pp := m.(*Profile)
pp.Mapping = append(pp.Mapping, x)
return decodeMessage(b, x)
},
// repeated Location location = 4
func(b *buffer, m message) error {
x := new(Location)
x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer
pp := m.(*Profile)
pp.Location = append(pp.Location, x)
err := decodeMessage(b, x)
var tmp []Line
x.Line = append(tmp, x.Line...) // Shrink to allocated size
return err
},
// repeated Function function = 5
func(b *buffer, m message) error {
x := new(Function)
pp := m.(*Profile)
pp.Function = append(pp.Function, x)
return decodeMessage(b, x)
},
// repeated string string_table = 6
func(b *buffer, m message) error {
err := decodeStrings(b, &m.(*Profile).stringTable)
if err != nil {
return err
}
if m.(*Profile).stringTable[0] != "" {
return errors.New("string_table[0] must be ''")
}
return nil
},
// int64 drop_frames = 7
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
// int64 keep_frames = 8
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
// int64 time_nanos = 9
func(b *buffer, m message) error {
if m.(*Profile).TimeNanos != 0 {
return errConcatProfile
}
return decodeInt64(b, &m.(*Profile).TimeNanos)
},
// int64 duration_nanos = 10
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
// ValueType period_type = 11
func(b *buffer, m message) error {
x := new(ValueType)
pp := m.(*Profile)
pp.PeriodType = x
return decodeMessage(b, x)
},
// int64 period = 12
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
// repeated int64 comment = 13
func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
// int64 defaultSampleType = 14
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
}
// postDecode takes the unexported fields populated by decode (with
// suffix X) and populates the corresponding exported fields.
// The unexported fields are cleared up to facilitate testing.
func (p *Profile) postDecode() error {
var err error
mappings := make(map[uint64]*Mapping, len(p.Mapping))
mappingIds := make([]*Mapping, len(p.Mapping)+1)
for _, m := range p.Mapping {
m.File, err = getString(p.stringTable, &m.fileX, err)
m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
if m.ID < uint64(len(mappingIds)) {
mappingIds[m.ID] = m
} else {
mappings[m.ID] = m
}
}
functions := make(map[uint64]*Function, len(p.Function))
functionIds := make([]*Function, len(p.Function)+1)
for _, f := range p.Function {
f.Name, err = getString(p.stringTable, &f.nameX, err)
f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
f.Filename, err = getString(p.stringTable, &f.filenameX, err)
if f.ID < uint64(len(functionIds)) {
functionIds[f.ID] = f
} else {
functions[f.ID] = f
}
}
locations := make(map[uint64]*Location, len(p.Location))
locationIds := make([]*Location, len(p.Location)+1)
for _, l := range p.Location {
if id := l.mappingIDX; id < uint64(len(mappingIds)) {
l.Mapping = mappingIds[id]
} else {
l.Mapping = mappings[id]
}
l.mappingIDX = 0
for i, ln := range l.Line {
if id := ln.functionIDX; id != 0 {
l.Line[i].functionIDX = 0
if id < uint64(len(functionIds)) {
l.Line[i].Function = functionIds[id]
} else {
l.Line[i].Function = functions[id]
}
}
}
if l.ID < uint64(len(locationIds)) {
locationIds[l.ID] = l
} else {
locations[l.ID] = l
}
}
for _, st := range p.SampleType {
st.Type, err = getString(p.stringTable, &st.typeX, err)
st.Unit, err = getString(p.stringTable, &st.unitX, err)
}
for _, s := range p.Sample {
labels := make(map[string][]string, len(s.labelX))
numLabels := make(map[string][]int64, len(s.labelX))
numUnits := make(map[string][]string, len(s.labelX))
for _, l := range s.labelX {
var key, value string
key, err = getString(p.stringTable, &l.keyX, err)
if l.strX != 0 {
value, err = getString(p.stringTable, &l.strX, err)
labels[key] = append(labels[key], value)
} else if l.numX != 0 || l.unitX != 0 {
numValues := numLabels[key]
units := numUnits[key]
if l.unitX != 0 {
var unit string
unit, err = getString(p.stringTable, &l.unitX, err)
units = padStringArray(units, len(numValues))
numUnits[key] = append(units, unit)
}
numLabels[key] = append(numLabels[key], l.numX)
}
}
if len(labels) > 0 {
s.Label = labels
}
if len(numLabels) > 0 {
s.NumLabel = numLabels
for key, units := range numUnits {
if len(units) > 0 {
numUnits[key] = padStringArray(units, len(numLabels[key]))
}
}
s.NumUnit = numUnits
}
s.Location = make([]*Location, len(s.locationIDX))
for i, lid := range s.locationIDX {
if lid < uint64(len(locationIds)) {
s.Location[i] = locationIds[lid]
} else {
s.Location[i] = locations[lid]
}
}
s.locationIDX = nil
}
p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
if pt := p.PeriodType; pt == nil {
p.PeriodType = &ValueType{}
}
if pt := p.PeriodType; pt != nil {
pt.Type, err = getString(p.stringTable, &pt.typeX, err)
pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
}
for _, i := range p.commentX {
var c string
c, err = getString(p.stringTable, &i, err)
p.Comments = append(p.Comments, c)
}
p.commentX = nil
p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
p.stringTable = nil
return err
}
// padStringArray pads arr with enough empty strings to make arr
// length l when arr's length is less than l.
func padStringArray(arr []string, l int) []string {
if l <= len(arr) {
return arr
}
return append(arr, make([]string, l-len(arr))...)
}
func (p *ValueType) decoder() []decoder {
return valueTypeDecoder
}
func (p *ValueType) encode(b *buffer) {
encodeInt64Opt(b, 1, p.typeX)
encodeInt64Opt(b, 2, p.unitX)
}
var valueTypeDecoder = []decoder{
nil, // 0
// optional int64 type = 1
func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
// optional int64 unit = 2
func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
}
func (p *Sample) decoder() []decoder {
return sampleDecoder
}
func (p *Sample) encode(b *buffer) {
encodeUint64s(b, 1, p.locationIDX)
encodeInt64s(b, 2, p.Value)
for _, x := range p.labelX {
encodeMessage(b, 3, x)
}
}
var sampleDecoder = []decoder{
nil, // 0
// repeated uint64 location = 1
func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
// repeated int64 value = 2
func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
// repeated Label label = 3
func(b *buffer, m message) error {
s := m.(*Sample)
n := len(s.labelX)
s.labelX = append(s.labelX, label{})
return decodeMessage(b, &s.labelX[n])
},
}
func (p label) decoder() []decoder {
return labelDecoder
}
func (p label) encode(b *buffer) {
encodeInt64Opt(b, 1, p.keyX)
encodeInt64Opt(b, 2, p.strX)
encodeInt64Opt(b, 3, p.numX)
encodeInt64Opt(b, 4, p.unitX)
}
var labelDecoder = []decoder{
nil, // 0
// optional int64 key = 1
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) },
// optional int64 str = 2
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) },
// optional int64 num = 3
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) },
// optional int64 num = 4
func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) },
}
func (p *Mapping) decoder() []decoder {
return mappingDecoder
}
func (p *Mapping) encode(b *buffer) {
encodeUint64Opt(b, 1, p.ID)
encodeUint64Opt(b, 2, p.Start)
encodeUint64Opt(b, 3, p.Limit)
encodeUint64Opt(b, 4, p.Offset)
encodeInt64Opt(b, 5, p.fileX)
encodeInt64Opt(b, 6, p.buildIDX)
encodeBoolOpt(b, 7, p.HasFunctions)
encodeBoolOpt(b, 8, p.HasFilenames)
encodeBoolOpt(b, 9, p.HasLineNumbers)
encodeBoolOpt(b, 10, p.HasInlineFrames)
}
var mappingDecoder = []decoder{
nil, // 0
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) }, // optional uint64 id = 1
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) }, // optional uint64 memory_offset = 2
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) }, // optional uint64 memory_limit = 3
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) }, // optional uint64 file_offset = 4
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) }, // optional int64 filename = 5
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) }, // optional int64 build_id = 6
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) }, // optional bool has_functions = 7
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) }, // optional bool has_filenames = 8
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) }, // optional bool has_line_numbers = 9
func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
}
func (p *Location) decoder() []decoder {
return locationDecoder
}
func (p *Location) encode(b *buffer) {
encodeUint64Opt(b, 1, p.ID)
encodeUint64Opt(b, 2, p.mappingIDX)
encodeUint64Opt(b, 3, p.Address)
for i := range p.Line {
encodeMessage(b, 4, &p.Line[i])
}
encodeBoolOpt(b, 5, p.IsFolded)
}
var locationDecoder = []decoder{
nil, // 0
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) }, // optional uint64 id = 1;
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) }, // optional uint64 address = 3;
func(b *buffer, m message) error { // repeated Line line = 4
pp := m.(*Location)
n := len(pp.Line)
pp.Line = append(pp.Line, Line{})
return decodeMessage(b, &pp.Line[n])
},
func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5;
}
func (p *Line) decoder() []decoder {
return lineDecoder
}
func (p *Line) encode(b *buffer) {
encodeUint64Opt(b, 1, p.functionIDX)
encodeInt64Opt(b, 2, p.Line)
}
var lineDecoder = []decoder{
nil, // 0
// optional uint64 function_id = 1
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
// optional int64 line = 2
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
}
func (p *Function) decoder() []decoder {
return functionDecoder
}
func (p *Function) encode(b *buffer) {
encodeUint64Opt(b, 1, p.ID)
encodeInt64Opt(b, 2, p.nameX)
encodeInt64Opt(b, 3, p.systemNameX)
encodeInt64Opt(b, 4, p.filenameX)
encodeInt64Opt(b, 5, p.StartLine)
}
var functionDecoder = []decoder{
nil, // 0
// optional uint64 id = 1
func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
// optional int64 function_name = 2
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
// optional int64 function_system_name = 3
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
// repeated int64 filename = 4
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
// optional int64 start_line = 5
func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
}
func addString(strings map[string]int, s string) int64 {
i, ok := strings[s]
if !ok {
i = len(strings)
strings[s] = i
}
return int64(i)
}
func getString(strings []string, strng *int64, err error) (string, error) {
if err != nil {
return "", err
}
s := int(*strng)
if s < 0 || s >= len(strings) {
return "", errMalformed
}
*strng = 0
return strings[s], nil
}
================================================
FILE: vendor/github.com/google/pprof/profile/filter.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profile
// Implements methods to filter samples from profiles.
import "regexp"
// FilterSamplesByName filters the samples in a profile and only keeps
// samples where at least one frame matches focus but none match ignore.
// Returns true is the corresponding regexp matched at least one sample.
func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) {
focusOrIgnore := make(map[uint64]bool)
hidden := make(map[uint64]bool)
for _, l := range p.Location {
if ignore != nil && l.matchesName(ignore) {
im = true
focusOrIgnore[l.ID] = false
} else if focus == nil || l.matchesName(focus) {
fm = true
focusOrIgnore[l.ID] = true
}
if hide != nil && l.matchesName(hide) {
hm = true
l.Line = l.unmatchedLines(hide)
if len(l.Line) == 0 {
hidden[l.ID] = true
}
}
if show != nil {
l.Line = l.matchedLines(show)
if len(l.Line) == 0 {
hidden[l.ID] = true
} else {
hnm = true
}
}
}
s := make([]*Sample, 0, len(p.Sample))
for _, sample := range p.Sample {
if focusedAndNotIgnored(sample.Location, focusOrIgnore) {
if len(hidden) > 0 {
var locs []*Location
for _, loc := range sample.Location {
if !hidden[loc.ID] {
locs = append(locs, loc)
}
}
if len(locs) == 0 {
// Remove sample with no locations (by not adding it to s).
continue
}
sample.Location = locs
}
s = append(s, sample)
}
}
p.Sample = s
return
}
// ShowFrom drops all stack frames above the highest matching frame and returns
// whether a match was found. If showFrom is nil it returns false and does not
// modify the profile.
//
// Example: consider a sample with frames [A, B, C, B], where A is the root.
// ShowFrom(nil) returns false and has frames [A, B, C, B].
// ShowFrom(A) returns true and has frames [A, B, C, B].
// ShowFrom(B) returns true and has frames [B, C, B].
// ShowFrom(C) returns true and has frames [C, B].
// ShowFrom(D) returns false and drops the sample because no frames remain.
func (p *Profile) ShowFrom(showFrom *regexp.Regexp) (matched bool) {
if showFrom == nil {
return false
}
// showFromLocs stores location IDs that matched ShowFrom.
showFromLocs := make(map[uint64]bool)
// Apply to locations.
for _, loc := range p.Location {
if filterShowFromLocation(loc, showFrom) {
showFromLocs[loc.ID] = true
matched = true
}
}
// For all samples, strip locations after the highest matching one.
s := make([]*Sample, 0, len(p.Sample))
for _, sample := range p.Sample {
for i := len(sample.Location) - 1; i >= 0; i-- {
if showFromLocs[sample.Location[i].ID] {
sample.Location = sample.Location[:i+1]
s = append(s, sample)
break
}
}
}
p.Sample = s
return matched
}
// filterShowFromLocation tests a showFrom regex against a location, removes
// lines after the last match and returns whether a match was found. If the
// mapping is matched, then all lines are kept.
func filterShowFromLocation(loc *Location, showFrom *regexp.Regexp) bool {
if m := loc.Mapping; m != nil && showFrom.MatchString(m.File) {
return true
}
if i := loc.lastMatchedLineIndex(showFrom); i >= 0 {
loc.Line = loc.Line[:i+1]
return true
}
return false
}
// lastMatchedLineIndex returns the index of the last line that matches a regex,
// or -1 if no match is found.
func (loc *Location) lastMatchedLineIndex(re *regexp.Regexp) int {
for i := len(loc.Line) - 1; i >= 0; i-- {
if fn := loc.Line[i].Function; fn != nil {
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
return i
}
}
}
return -1
}
// FilterTagsByName filters the tags in a profile and only keeps
// tags that match show and not hide.
func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) {
matchRemove := func(name string) bool {
matchShow := show == nil || show.MatchString(name)
matchHide := hide != nil && hide.MatchString(name)
if matchShow {
sm = true
}
if matchHide {
hm = true
}
return !matchShow || matchHide
}
for _, s := range p.Sample {
for lab := range s.Label {
if matchRemove(lab) {
delete(s.Label, lab)
}
}
for lab := range s.NumLabel {
if matchRemove(lab) {
delete(s.NumLabel, lab)
}
}
}
return
}
// matchesName returns whether the location matches the regular
// expression. It checks any available function names, file names, and
// mapping object filename.
func (loc *Location) matchesName(re *regexp.Regexp) bool {
for _, ln := range loc.Line {
if fn := ln.Function; fn != nil {
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
return true
}
}
}
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
return true
}
return false
}
// unmatchedLines returns the lines in the location that do not match
// the regular expression.
func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line {
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
return nil
}
var lines []Line
for _, ln := range loc.Line {
if fn := ln.Function; fn != nil {
if re.MatchString(fn.Name) || re.MatchString(fn.Filename) {
continue
}
}
lines = append(lines, ln)
}
return lines
}
// matchedLines returns the lines in the location that match
// the regular expression.
func (loc *Location) matchedLines(re *regexp.Regexp) []Line {
if m := loc.Mapping; m != nil && re.MatchString(m.File) {
return loc.Line
}
var lines []Line
for _, ln := range loc.Line {
if fn := ln.Function; fn != nil {
if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) {
continue
}
}
lines = append(lines, ln)
}
return lines
}
// focusedAndNotIgnored looks up a slice of ids against a map of
// focused/ignored locations. The map only contains locations that are
// explicitly focused or ignored. Returns whether there is at least
// one focused location but no ignored locations.
func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool {
var f bool
for _, loc := range locs {
if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore {
if focus {
// Found focused location. Must keep searching in case there
// is an ignored one as well.
f = true
} else {
// Found ignored location. Can return false right away.
return false
}
}
}
return f
}
// TagMatch selects tags for filtering
type TagMatch func(s *Sample) bool
// FilterSamplesByTag removes all samples from the profile, except
// those that match focus and do not match the ignore regular
// expression.
func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) {
samples := make([]*Sample, 0, len(p.Sample))
for _, s := range p.Sample {
focused, ignored := true, false
if focus != nil {
focused = focus(s)
}
if ignore != nil {
ignored = ignore(s)
}
fm = fm || focused
im = im || ignored
if focused && !ignored {
samples = append(samples, s)
}
}
p.Sample = samples
return
}
================================================
FILE: vendor/github.com/google/pprof/profile/index.go
================================================
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profile
import (
"fmt"
"strconv"
"strings"
)
// SampleIndexByName returns the appropriate index for a value of sample index.
// If numeric, it returns the number, otherwise it looks up the text in the
// profile sample types.
func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) {
if sampleIndex == "" {
if dst := p.DefaultSampleType; dst != "" {
for i, t := range sampleTypes(p) {
if t == dst {
return i, nil
}
}
}
// By default select the last sample value
return len(p.SampleType) - 1, nil
}
if i, err := strconv.Atoi(sampleIndex); err == nil {
if i < 0 || i >= len(p.SampleType) {
return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1)
}
return i, nil
}
// Remove the inuse_ prefix to support legacy pprof options
// "inuse_space" and "inuse_objects" for profiles containing types
// "space" and "objects".
noInuse := strings.TrimPrefix(sampleIndex, "inuse_")
for i, t := range p.SampleType {
if t.Type == sampleIndex || t.Type == noInuse {
return i, nil
}
}
return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p))
}
func sampleTypes(p *Profile) []string {
types := make([]string, len(p.SampleType))
for i, t := range p.SampleType {
types[i] = t.Type
}
return types
}
================================================
FILE: vendor/github.com/google/pprof/profile/legacy_java_profile.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file implements parsers to convert java legacy profiles into
// the profile.proto format.
package profile
import (
"bytes"
"fmt"
"io"
"path/filepath"
"regexp"
"strconv"
"strings"
)
var (
attributeRx = regexp.MustCompile(`([\w ]+)=([\w ]+)`)
javaSampleRx = regexp.MustCompile(` *(\d+) +(\d+) +@ +([ x0-9a-f]*)`)
javaLocationRx = regexp.MustCompile(`^\s*0x([[:xdigit:]]+)\s+(.*)\s*$`)
javaLocationFileLineRx = regexp.MustCompile(`^(.*)\s+\((.+):(-?[[:digit:]]+)\)$`)
javaLocationPathRx = regexp.MustCompile(`^(.*)\s+\((.*)\)$`)
)
// javaCPUProfile returns a new Profile from profilez data.
// b is the profile bytes after the header, period is the profiling
// period, and parse is a function to parse 8-byte chunks from the
// profile in its native endianness.
func javaCPUProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
p := &Profile{
Period: period * 1000,
PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
SampleType: []*ValueType{{Type: "samples", Unit: "count"}, {Type: "cpu", Unit: "nanoseconds"}},
}
var err error
var locs map[uint64]*Location
if b, locs, err = parseCPUSamples(b, parse, false, p); err != nil {
return nil, err
}
if err = parseJavaLocations(b, locs, p); err != nil {
return nil, err
}
// Strip out addresses for better merge.
if err = p.Aggregate(true, true, true, true, false); err != nil {
return nil, err
}
return p, nil
}
// parseJavaProfile returns a new profile from heapz or contentionz
// data. b is the profile bytes after the header.
func parseJavaProfile(b []byte) (*Profile, error) {
h := bytes.SplitAfterN(b, []byte("\n"), 2)
if len(h) < 2 {
return nil, errUnrecognized
}
p := &Profile{
PeriodType: &ValueType{},
}
header := string(bytes.TrimSpace(h[0]))
var err error
var pType string
switch header {
case "--- heapz 1 ---":
pType = "heap"
case "--- contentionz 1 ---":
pType = "contention"
default:
return nil, errUnrecognized
}
if b, err = parseJavaHeader(pType, h[1], p); err != nil {
return nil, err
}
var locs map[uint64]*Location
if b, locs, err = parseJavaSamples(pType, b, p); err != nil {
return nil, err
}
if err = parseJavaLocations(b, locs, p); err != nil {
return nil, err
}
// Strip out addresses for better merge.
if err = p.Aggregate(true, true, true, true, false); err != nil {
return nil, err
}
return p, nil
}
// parseJavaHeader parses the attribute section on a java profile and
// populates a profile. Returns the remainder of the buffer after all
// attributes.
func parseJavaHeader(pType string, b []byte, p *Profile) ([]byte, error) {
nextNewLine := bytes.IndexByte(b, byte('\n'))
for nextNewLine != -1 {
line := string(bytes.TrimSpace(b[0:nextNewLine]))
if line != "" {
h := attributeRx.FindStringSubmatch(line)
if h == nil {
// Not a valid attribute, exit.
return b, nil
}
attribute, value := strings.TrimSpace(h[1]), strings.TrimSpace(h[2])
var err error
switch pType + "/" + attribute {
case "heap/format", "cpu/format", "contention/format":
if value != "java" {
return nil, errUnrecognized
}
case "heap/resolution":
p.SampleType = []*ValueType{
{Type: "inuse_objects", Unit: "count"},
{Type: "inuse_space", Unit: value},
}
case "contention/resolution":
p.SampleType = []*ValueType{
{Type: "contentions", Unit: "count"},
{Type: "delay", Unit: value},
}
case "contention/sampling period":
p.PeriodType = &ValueType{
Type: "contentions", Unit: "count",
}
if p.Period, err = strconv.ParseInt(value, 0, 64); err != nil {
return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
}
case "contention/ms since reset":
millis, err := strconv.ParseInt(value, 0, 64)
if err != nil {
return nil, fmt.Errorf("failed to parse attribute %s: %v", line, err)
}
p.DurationNanos = millis * 1000 * 1000
default:
return nil, errUnrecognized
}
}
// Grab next line.
b = b[nextNewLine+1:]
nextNewLine = bytes.IndexByte(b, byte('\n'))
}
return b, nil
}
// parseJavaSamples parses the samples from a java profile and
// populates the Samples in a profile. Returns the remainder of the
// buffer after the samples.
func parseJavaSamples(pType string, b []byte, p *Profile) ([]byte, map[uint64]*Location, error) {
nextNewLine := bytes.IndexByte(b, byte('\n'))
locs := make(map[uint64]*Location)
for nextNewLine != -1 {
line := string(bytes.TrimSpace(b[0:nextNewLine]))
if line != "" {
sample := javaSampleRx.FindStringSubmatch(line)
if sample == nil {
// Not a valid sample, exit.
return b, locs, nil
}
// Java profiles have data/fields inverted compared to other
// profile types.
var err error
value1, value2, value3 := sample[2], sample[1], sample[3]
addrs, err := parseHexAddresses(value3)
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
var sloc []*Location
for _, addr := range addrs {
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
Address: addr,
}
p.Location = append(p.Location, loc)
locs[addr] = loc
}
sloc = append(sloc, loc)
}
s := &Sample{
Value: make([]int64, 2),
Location: sloc,
}
if s.Value[0], err = strconv.ParseInt(value1, 0, 64); err != nil {
return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
}
if s.Value[1], err = strconv.ParseInt(value2, 0, 64); err != nil {
return nil, nil, fmt.Errorf("parsing sample %s: %v", line, err)
}
switch pType {
case "heap":
const javaHeapzSamplingRate = 524288 // 512K
if s.Value[0] == 0 {
return nil, nil, fmt.Errorf("parsing sample %s: second value must be non-zero", line)
}
s.NumLabel = map[string][]int64{"bytes": {s.Value[1] / s.Value[0]}}
s.Value[0], s.Value[1] = scaleHeapSample(s.Value[0], s.Value[1], javaHeapzSamplingRate)
case "contention":
if period := p.Period; period != 0 {
s.Value[0] = s.Value[0] * p.Period
s.Value[1] = s.Value[1] * p.Period
}
}
p.Sample = append(p.Sample, s)
}
// Grab next line.
b = b[nextNewLine+1:]
nextNewLine = bytes.IndexByte(b, byte('\n'))
}
return b, locs, nil
}
// parseJavaLocations parses the location information in a java
// profile and populates the Locations in a profile. It uses the
// location addresses from the profile as both the ID of each
// location.
func parseJavaLocations(b []byte, locs map[uint64]*Location, p *Profile) error {
r := bytes.NewBuffer(b)
fns := make(map[string]*Function)
for {
line, err := r.ReadString('\n')
if err != nil {
if err != io.EOF {
return err
}
if line == "" {
break
}
}
if line = strings.TrimSpace(line); line == "" {
continue
}
jloc := javaLocationRx.FindStringSubmatch(line)
if len(jloc) != 3 {
continue
}
addr, err := strconv.ParseUint(jloc[1], 16, 64)
if err != nil {
return fmt.Errorf("parsing sample %s: %v", line, err)
}
loc := locs[addr]
if loc == nil {
// Unused/unseen
continue
}
var lineFunc, lineFile string
var lineNo int64
if fileLine := javaLocationFileLineRx.FindStringSubmatch(jloc[2]); len(fileLine) == 4 {
// Found a line of the form: "function (file:line)"
lineFunc, lineFile = fileLine[1], fileLine[2]
if n, err := strconv.ParseInt(fileLine[3], 10, 64); err == nil && n > 0 {
lineNo = n
}
} else if filePath := javaLocationPathRx.FindStringSubmatch(jloc[2]); len(filePath) == 3 {
// If there's not a file:line, it's a shared library path.
// The path isn't interesting, so just give the .so.
lineFunc, lineFile = filePath[1], filepath.Base(filePath[2])
} else if strings.Contains(jloc[2], "generated stub/JIT") {
lineFunc = "STUB"
} else {
// Treat whole line as the function name. This is used by the
// java agent for internal states such as "GC" or "VM".
lineFunc = jloc[2]
}
fn := fns[lineFunc]
if fn == nil {
fn = &Function{
Name: lineFunc,
SystemName: lineFunc,
Filename: lineFile,
}
fns[lineFunc] = fn
p.Function = append(p.Function, fn)
}
loc.Line = []Line{
{
Function: fn,
Line: lineNo,
},
}
loc.Address = 0
}
p.remapLocationIDs()
p.remapFunctionIDs()
p.remapMappingIDs()
return nil
}
================================================
FILE: vendor/github.com/google/pprof/profile/legacy_profile.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file implements parsers to convert legacy profiles into the
// profile.proto format.
package profile
import (
"bufio"
"bytes"
"fmt"
"io"
"math"
"regexp"
"strconv"
"strings"
)
var (
countStartRE = regexp.MustCompile(`\A(\S+) profile: total \d+\z`)
countRE = regexp.MustCompile(`\A(\d+) @(( 0x[0-9a-f]+)+)\z`)
heapHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] *@ *(heap[_a-z0-9]*)/?(\d*)`)
heapSampleRE = regexp.MustCompile(`(-?\d+): *(-?\d+) *\[ *(\d+): *(\d+) *] @([ x0-9a-f]*)`)
contentionSampleRE = regexp.MustCompile(`(\d+) *(\d+) @([ x0-9a-f]*)`)
hexNumberRE = regexp.MustCompile(`0x[0-9a-f]+`)
growthHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ growthz?`)
fragmentationHeaderRE = regexp.MustCompile(`heap profile: *(\d+): *(\d+) *\[ *(\d+): *(\d+) *\] @ fragmentationz?`)
threadzStartRE = regexp.MustCompile(`--- threadz \d+ ---`)
threadStartRE = regexp.MustCompile(`--- Thread ([[:xdigit:]]+) \(name: (.*)/(\d+)\) stack: ---`)
// Regular expressions to parse process mappings. Support the format used by Linux /proc/.../maps and other tools.
// Recommended format:
// Start End object file name offset(optional) linker build id
// 0x40000-0x80000 /path/to/binary (@FF00) abc123456
spaceDigits = `\s+[[:digit:]]+`
hexPair = `\s+[[:xdigit:]]+:[[:xdigit:]]+`
oSpace = `\s*`
// Capturing expressions.
cHex = `(?:0x)?([[:xdigit:]]+)`
cHexRange = `\s*` + cHex + `[\s-]?` + oSpace + cHex + `:?`
cSpaceString = `(?:\s+(\S+))?`
cSpaceHex = `(?:\s+([[:xdigit:]]+))?`
cSpaceAtOffset = `(?:\s+\(@([[:xdigit:]]+)\))?`
cPerm = `(?:\s+([-rwxp]+))?`
procMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceHex + hexPair + spaceDigits + cSpaceString)
briefMapsRE = regexp.MustCompile(`^` + cHexRange + cPerm + cSpaceString + cSpaceAtOffset + cSpaceHex)
// Regular expression to parse log data, of the form:
// ... file:line] msg...
logInfoRE = regexp.MustCompile(`^[^\[\]]+:[0-9]+]\s`)
)
func isSpaceOrComment(line string) bool {
trimmed := strings.TrimSpace(line)
return len(trimmed) == 0 || trimmed[0] == '#'
}
// parseGoCount parses a Go count profile (e.g., threadcreate or
// goroutine) and returns a new Profile.
func parseGoCount(b []byte) (*Profile, error) {
s := bufio.NewScanner(bytes.NewBuffer(b))
// Skip comments at the beginning of the file.
for s.Scan() && isSpaceOrComment(s.Text()) {
}
if err := s.Err(); err != nil {
return nil, err
}
m := countStartRE.FindStringSubmatch(s.Text())
if m == nil {
return nil, errUnrecognized
}
profileType := m[1]
p := &Profile{
PeriodType: &ValueType{Type: profileType, Unit: "count"},
Period: 1,
SampleType: []*ValueType{{Type: profileType, Unit: "count"}},
}
locations := make(map[uint64]*Location)
for s.Scan() {
line := s.Text()
if isSpaceOrComment(line) {
continue
}
if strings.HasPrefix(line, "---") {
break
}
m := countRE.FindStringSubmatch(line)
if m == nil {
return nil, errMalformed
}
n, err := strconv.ParseInt(m[1], 0, 64)
if err != nil {
return nil, errMalformed
}
fields := strings.Fields(m[2])
locs := make([]*Location, 0, len(fields))
for _, stk := range fields {
addr, err := strconv.ParseUint(stk, 0, 64)
if err != nil {
return nil, errMalformed
}
// Adjust all frames by -1 to land on top of the call instruction.
addr--
loc := locations[addr]
if loc == nil {
loc = &Location{
Address: addr,
}
locations[addr] = loc
p.Location = append(p.Location, loc)
}
locs = append(locs, loc)
}
p.Sample = append(p.Sample, &Sample{
Location: locs,
Value: []int64{n},
})
}
if err := s.Err(); err != nil {
return nil, err
}
if err := parseAdditionalSections(s, p); err != nil {
return nil, err
}
return p, nil
}
// remapLocationIDs ensures there is a location for each address
// referenced by a sample, and remaps the samples to point to the new
// location ids.
func (p *Profile) remapLocationIDs() {
seen := make(map[*Location]bool, len(p.Location))
var locs []*Location
for _, s := range p.Sample {
for _, l := range s.Location {
if seen[l] {
continue
}
l.ID = uint64(len(locs) + 1)
locs = append(locs, l)
seen[l] = true
}
}
p.Location = locs
}
func (p *Profile) remapFunctionIDs() {
seen := make(map[*Function]bool, len(p.Function))
var fns []*Function
for _, l := range p.Location {
for _, ln := range l.Line {
fn := ln.Function
if fn == nil || seen[fn] {
continue
}
fn.ID = uint64(len(fns) + 1)
fns = append(fns, fn)
seen[fn] = true
}
}
p.Function = fns
}
// remapMappingIDs matches location addresses with existing mappings
// and updates them appropriately. This is O(N*M), if this ever shows
// up as a bottleneck, evaluate sorting the mappings and doing a
// binary search, which would make it O(N*log(M)).
func (p *Profile) remapMappingIDs() {
// Some profile handlers will incorrectly set regions for the main
// executable if its section is remapped. Fix them through heuristics.
if len(p.Mapping) > 0 {
// Remove the initial mapping if named '/anon_hugepage' and has a
// consecutive adjacent mapping.
if m := p.Mapping[0]; strings.HasPrefix(m.File, "/anon_hugepage") {
if len(p.Mapping) > 1 && m.Limit == p.Mapping[1].Start {
p.Mapping = p.Mapping[1:]
}
}
}
// Subtract the offset from the start of the main mapping if it
// ends up at a recognizable start address.
if len(p.Mapping) > 0 {
const expectedStart = 0x400000
if m := p.Mapping[0]; m.Start-m.Offset == expectedStart {
m.Start = expectedStart
m.Offset = 0
}
}
// Associate each location with an address to the corresponding
// mapping. Create fake mapping if a suitable one isn't found.
var fake *Mapping
nextLocation:
for _, l := range p.Location {
a := l.Address
if l.Mapping != nil || a == 0 {
continue
}
for _, m := range p.Mapping {
if m.Start <= a && a < m.Limit {
l.Mapping = m
continue nextLocation
}
}
// Work around legacy handlers failing to encode the first
// part of mappings split into adjacent ranges.
for _, m := range p.Mapping {
if m.Offset != 0 && m.Start-m.Offset <= a && a < m.Start {
m.Start -= m.Offset
m.Offset = 0
l.Mapping = m
continue nextLocation
}
}
// If there is still no mapping, create a fake one.
// This is important for the Go legacy handler, which produced
// no mappings.
if fake == nil {
fake = &Mapping{
ID: 1,
Limit: ^uint64(0),
}
p.Mapping = append(p.Mapping, fake)
}
l.Mapping = fake
}
// Reset all mapping IDs.
for i, m := range p.Mapping {
m.ID = uint64(i + 1)
}
}
var cpuInts = []func([]byte) (uint64, []byte){
get32l,
get32b,
get64l,
get64b,
}
func get32l(b []byte) (uint64, []byte) {
if len(b) < 4 {
return 0, nil
}
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24, b[4:]
}
func get32b(b []byte) (uint64, []byte) {
if len(b) < 4 {
return 0, nil
}
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24, b[4:]
}
func get64l(b []byte) (uint64, []byte) {
if len(b) < 8 {
return 0, nil
}
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56, b[8:]
}
func get64b(b []byte) (uint64, []byte) {
if len(b) < 8 {
return 0, nil
}
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56, b[8:]
}
// parseCPU parses a profilez legacy profile and returns a newly
// populated Profile.
//
// The general format for profilez samples is a sequence of words in
// binary format. The first words are a header with the following data:
// 1st word -- 0
// 2nd word -- 3
// 3rd word -- 0 if a c++ application, 1 if a java application.
// 4th word -- Sampling period (in microseconds).
// 5th word -- Padding.
func parseCPU(b []byte) (*Profile, error) {
var parse func([]byte) (uint64, []byte)
var n1, n2, n3, n4, n5 uint64
for _, parse = range cpuInts {
var tmp []byte
n1, tmp = parse(b)
n2, tmp = parse(tmp)
n3, tmp = parse(tmp)
n4, tmp = parse(tmp)
n5, tmp = parse(tmp)
if tmp != nil && n1 == 0 && n2 == 3 && n3 == 0 && n4 > 0 && n5 == 0 {
b = tmp
return cpuProfile(b, int64(n4), parse)
}
if tmp != nil && n1 == 0 && n2 == 3 && n3 == 1 && n4 > 0 && n5 == 0 {
b = tmp
return javaCPUProfile(b, int64(n4), parse)
}
}
return nil, errUnrecognized
}
// cpuProfile returns a new Profile from C++ profilez data.
// b is the profile bytes after the header, period is the profiling
// period, and parse is a function to parse 8-byte chunks from the
// profile in its native endianness.
func cpuProfile(b []byte, period int64, parse func(b []byte) (uint64, []byte)) (*Profile, error) {
p := &Profile{
Period: period * 1000,
PeriodType: &ValueType{Type: "cpu", Unit: "nanoseconds"},
SampleType: []*ValueType{
{Type: "samples", Unit: "count"},
{Type: "cpu", Unit: "nanoseconds"},
},
}
var err error
if b, _, err = parseCPUSamples(b, parse, true, p); err != nil {
return nil, err
}
// If *most* samples have the same second-to-the-bottom frame, it
// strongly suggests that it is an uninteresting artifact of
// measurement -- a stack frame pushed by the signal handler. The
// bottom frame is always correct as it is picked up from the signal
// structure, not the stack. Check if this is the case and if so,
// remove.
// Remove up to two frames.
maxiter := 2
// Allow one different sample for this many samples with the same
// second-to-last frame.
similarSamples := 32
margin := len(p.Sample) / similarSamples
for iter := 0; iter < maxiter; iter++ {
addr1 := make(map[uint64]int)
for _, s := range p.Sample {
if len(s.Location) > 1 {
a := s.Location[1].Address
addr1[a] = addr1[a] + 1
}
}
for id1, count := range addr1 {
if count >= len(p.Sample)-margin {
// Found uninteresting frame, strip it out from all samples
for _, s := range p.Sample {
if len(s.Location) > 1 && s.Location[1].Address == id1 {
s.Location = append(s.Location[:1], s.Location[2:]...)
}
}
break
}
}
}
if err := p.ParseMemoryMap(bytes.NewBuffer(b)); err != nil {
return nil, err
}
cleanupDuplicateLocations(p)
return p, nil
}
func cleanupDuplicateLocations(p *Profile) {
// The profile handler may duplicate the leaf frame, because it gets
// its address both from stack unwinding and from the signal
// context. Detect this and delete the duplicate, which has been
// adjusted by -1. The leaf address should not be adjusted as it is
// not a call.
for _, s := range p.Sample {
if len(s.Location) > 1 && s.Location[0].Address == s.Location[1].Address+1 {
s.Location = append(s.Location[:1], s.Location[2:]...)
}
}
}
// parseCPUSamples parses a collection of profilez samples from a
// profile.
//
// profilez samples are a repeated sequence of stack frames of the
// form:
// 1st word -- The number of times this stack was encountered.
// 2nd word -- The size of the stack (StackSize).
// 3rd word -- The first address on the stack.
// ...
// StackSize + 2 -- The last address on the stack
// The last stack trace is of the form:
// 1st word -- 0
// 2nd word -- 1
// 3rd word -- 0
//
// Addresses from stack traces may point to the next instruction after
// each call. Optionally adjust by -1 to land somewhere on the actual
// call (except for the leaf, which is not a call).
func parseCPUSamples(b []byte, parse func(b []byte) (uint64, []byte), adjust bool, p *Profile) ([]byte, map[uint64]*Location, error) {
locs := make(map[uint64]*Location)
for len(b) > 0 {
var count, nstk uint64
count, b = parse(b)
nstk, b = parse(b)
if b == nil || nstk > uint64(len(b)/4) {
return nil, nil, errUnrecognized
}
var sloc []*Location
addrs := make([]uint64, nstk)
for i := 0; i < int(nstk); i++ {
addrs[i], b = parse(b)
}
if count == 0 && nstk == 1 && addrs[0] == 0 {
// End of data marker
break
}
for i, addr := range addrs {
if adjust && i > 0 {
addr--
}
loc := locs[addr]
if loc == nil {
loc = &Location{
Address: addr,
}
locs[addr] = loc
p.Location = append(p.Location, loc)
}
sloc = append(sloc, loc)
}
p.Sample = append(p.Sample,
&Sample{
Value: []int64{int64(count), int64(count) * p.Period},
Location: sloc,
})
}
// Reached the end without finding the EOD marker.
return b, locs, nil
}
// parseHeap parses a heapz legacy or a growthz profile and
// returns a newly populated Profile.
func parseHeap(b []byte) (p *Profile, err error) {
s := bufio.NewScanner(bytes.NewBuffer(b))
if !s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
return nil, errUnrecognized
}
p = &Profile{}
sampling := ""
hasAlloc := false
line := s.Text()
p.PeriodType = &ValueType{Type: "space", Unit: "bytes"}
if header := heapHeaderRE.FindStringSubmatch(line); header != nil {
sampling, p.Period, hasAlloc, err = parseHeapHeader(line)
if err != nil {
return nil, err
}
} else if header = growthHeaderRE.FindStringSubmatch(line); header != nil {
p.Period = 1
} else if header = fragmentationHeaderRE.FindStringSubmatch(line); header != nil {
p.Period = 1
} else {
return nil, errUnrecognized
}
if hasAlloc {
// Put alloc before inuse so that default pprof selection
// will prefer inuse_space.
p.SampleType = []*ValueType{
{Type: "alloc_objects", Unit: "count"},
{Type: "alloc_space", Unit: "bytes"},
{Type: "inuse_objects", Unit: "count"},
{Type: "inuse_space", Unit: "bytes"},
}
} else {
p.SampleType = []*ValueType{
{Type: "objects", Unit: "count"},
{Type: "space", Unit: "bytes"},
}
}
locs := make(map[uint64]*Location)
for s.Scan() {
line := strings.TrimSpace(s.Text())
if isSpaceOrComment(line) {
continue
}
if isMemoryMapSentinel(line) {
break
}
value, blocksize, addrs, err := parseHeapSample(line, p.Period, sampling, hasAlloc)
if err != nil {
return nil, err
}
var sloc []*Location
for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
// each call. Adjust by -1 to land somewhere on the actual call.
addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
Address: addr,
}
p.Location = append(p.Location, loc)
locs[addr] = loc
}
sloc = append(sloc, loc)
}
p.Sample = append(p.Sample, &Sample{
Value: value,
Location: sloc,
NumLabel: map[string][]int64{"bytes": {blocksize}},
})
}
if err := s.Err(); err != nil {
return nil, err
}
if err := parseAdditionalSections(s, p); err != nil {
return nil, err
}
return p, nil
}
func parseHeapHeader(line string) (sampling string, period int64, hasAlloc bool, err error) {
header := heapHeaderRE.FindStringSubmatch(line)
if header == nil {
return "", 0, false, errUnrecognized
}
if len(header[6]) > 0 {
if period, err = strconv.ParseInt(header[6], 10, 64); err != nil {
return "", 0, false, errUnrecognized
}
}
if (header[3] != header[1] && header[3] != "0") || (header[4] != header[2] && header[4] != "0") {
hasAlloc = true
}
switch header[5] {
case "heapz_v2", "heap_v2":
return "v2", period, hasAlloc, nil
case "heapprofile":
return "", 1, hasAlloc, nil
case "heap":
return "v2", period / 2, hasAlloc, nil
default:
return "", 0, false, errUnrecognized
}
}
// parseHeapSample parses a single row from a heap profile into a new Sample.
func parseHeapSample(line string, rate int64, sampling string, includeAlloc bool) (value []int64, blocksize int64, addrs []uint64, err error) {
sampleData := heapSampleRE.FindStringSubmatch(line)
if len(sampleData) != 6 {
return nil, 0, nil, fmt.Errorf("unexpected number of sample values: got %d, want 6", len(sampleData))
}
// This is a local-scoped helper function to avoid needing to pass
// around rate, sampling and many return parameters.
addValues := func(countString, sizeString string, label string) error {
count, err := strconv.ParseInt(countString, 10, 64)
if err != nil {
return fmt.Errorf("malformed sample: %s: %v", line, err)
}
size, err := strconv.ParseInt(sizeString, 10, 64)
if err != nil {
return fmt.Errorf("malformed sample: %s: %v", line, err)
}
if count == 0 && size != 0 {
return fmt.Errorf("%s count was 0 but %s bytes was %d", label, label, size)
}
if count != 0 {
blocksize = size / count
if sampling == "v2" {
count, size = scaleHeapSample(count, size, rate)
}
}
value = append(value, count, size)
return nil
}
if includeAlloc {
if err := addValues(sampleData[3], sampleData[4], "allocation"); err != nil {
return nil, 0, nil, err
}
}
if err := addValues(sampleData[1], sampleData[2], "inuse"); err != nil {
return nil, 0, nil, err
}
addrs, err = parseHexAddresses(sampleData[5])
if err != nil {
return nil, 0, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
return value, blocksize, addrs, nil
}
// parseHexAddresses extracts hex numbers from a string, attempts to convert
// each to an unsigned 64-bit number and returns the resulting numbers as a
// slice, or an error if the string contains hex numbers which are too large to
// handle (which means a malformed profile).
func parseHexAddresses(s string) ([]uint64, error) {
hexStrings := hexNumberRE.FindAllString(s, -1)
var addrs []uint64
for _, s := range hexStrings {
if addr, err := strconv.ParseUint(s, 0, 64); err == nil {
addrs = append(addrs, addr)
} else {
return nil, fmt.Errorf("failed to parse as hex 64-bit number: %s", s)
}
}
return addrs, nil
}
// scaleHeapSample adjusts the data from a heapz Sample to
// account for its probability of appearing in the collected
// data. heapz profiles are a sampling of the memory allocations
// requests in a program. We estimate the unsampled value by dividing
// each collected sample by its probability of appearing in the
// profile. heapz v2 profiles rely on a poisson process to determine
// which samples to collect, based on the desired average collection
// rate R. The probability of a sample of size S to appear in that
// profile is 1-exp(-S/R).
func scaleHeapSample(count, size, rate int64) (int64, int64) {
if count == 0 || size == 0 {
return 0, 0
}
if rate <= 1 {
// if rate==1 all samples were collected so no adjustment is needed.
// if rate<1 treat as unknown and skip scaling.
return count, size
}
avgSize := float64(size) / float64(count)
scale := 1 / (1 - math.Exp(-avgSize/float64(rate)))
return int64(float64(count) * scale), int64(float64(size) * scale)
}
// parseContention parses a mutex or contention profile. There are 2 cases:
// "--- contentionz " for legacy C++ profiles (and backwards compatibility)
// "--- mutex:" or "--- contention:" for profiles generated by the Go runtime.
func parseContention(b []byte) (*Profile, error) {
s := bufio.NewScanner(bytes.NewBuffer(b))
if !s.Scan() {
if err := s.Err(); err != nil {
return nil, err
}
return nil, errUnrecognized
}
switch l := s.Text(); {
case strings.HasPrefix(l, "--- contentionz "):
case strings.HasPrefix(l, "--- mutex:"):
case strings.HasPrefix(l, "--- contention:"):
default:
return nil, errUnrecognized
}
p := &Profile{
PeriodType: &ValueType{Type: "contentions", Unit: "count"},
Period: 1,
SampleType: []*ValueType{
{Type: "contentions", Unit: "count"},
{Type: "delay", Unit: "nanoseconds"},
},
}
var cpuHz int64
// Parse text of the form "attribute = value" before the samples.
const delimiter = "="
for s.Scan() {
line := s.Text()
if line = strings.TrimSpace(line); isSpaceOrComment(line) {
continue
}
if strings.HasPrefix(line, "---") {
break
}
attr := strings.SplitN(line, delimiter, 2)
if len(attr) != 2 {
break
}
key, val := strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1])
var err error
switch key {
case "cycles/second":
if cpuHz, err = strconv.ParseInt(val, 0, 64); err != nil {
return nil, errUnrecognized
}
case "sampling period":
if p.Period, err = strconv.ParseInt(val, 0, 64); err != nil {
return nil, errUnrecognized
}
case "ms since reset":
ms, err := strconv.ParseInt(val, 0, 64)
if err != nil {
return nil, errUnrecognized
}
p.DurationNanos = ms * 1000 * 1000
case "format":
// CPP contentionz profiles don't have format.
return nil, errUnrecognized
case "resolution":
// CPP contentionz profiles don't have resolution.
return nil, errUnrecognized
case "discarded samples":
default:
return nil, errUnrecognized
}
}
if err := s.Err(); err != nil {
return nil, err
}
locs := make(map[uint64]*Location)
for {
line := strings.TrimSpace(s.Text())
if strings.HasPrefix(line, "---") {
break
}
if !isSpaceOrComment(line) {
value, addrs, err := parseContentionSample(line, p.Period, cpuHz)
if err != nil {
return nil, err
}
var sloc []*Location
for _, addr := range addrs {
// Addresses from stack traces point to the next instruction after
// each call. Adjust by -1 to land somewhere on the actual call.
addr--
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
Address: addr,
}
p.Location = append(p.Location, loc)
locs[addr] = loc
}
sloc = append(sloc, loc)
}
p.Sample = append(p.Sample, &Sample{
Value: value,
Location: sloc,
})
}
if !s.Scan() {
break
}
}
if err := s.Err(); err != nil {
return nil, err
}
if err := parseAdditionalSections(s, p); err != nil {
return nil, err
}
return p, nil
}
// parseContentionSample parses a single row from a contention profile
// into a new Sample.
func parseContentionSample(line string, period, cpuHz int64) (value []int64, addrs []uint64, err error) {
sampleData := contentionSampleRE.FindStringSubmatch(line)
if sampleData == nil {
return nil, nil, errUnrecognized
}
v1, err := strconv.ParseInt(sampleData[1], 10, 64)
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
v2, err := strconv.ParseInt(sampleData[2], 10, 64)
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
// Unsample values if period and cpuHz are available.
// - Delays are scaled to cycles and then to nanoseconds.
// - Contentions are scaled to cycles.
if period > 0 {
if cpuHz > 0 {
cpuGHz := float64(cpuHz) / 1e9
v1 = int64(float64(v1) * float64(period) / cpuGHz)
}
v2 = v2 * period
}
value = []int64{v2, v1}
addrs, err = parseHexAddresses(sampleData[3])
if err != nil {
return nil, nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
return value, addrs, nil
}
// parseThread parses a Threadz profile and returns a new Profile.
func parseThread(b []byte) (*Profile, error) {
s := bufio.NewScanner(bytes.NewBuffer(b))
// Skip past comments and empty lines seeking a real header.
for s.Scan() && isSpaceOrComment(s.Text()) {
}
line := s.Text()
if m := threadzStartRE.FindStringSubmatch(line); m != nil {
// Advance over initial comments until first stack trace.
for s.Scan() {
if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") {
break
}
}
} else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
return nil, errUnrecognized
}
p := &Profile{
SampleType: []*ValueType{{Type: "thread", Unit: "count"}},
PeriodType: &ValueType{Type: "thread", Unit: "count"},
Period: 1,
}
locs := make(map[uint64]*Location)
// Recognize each thread and populate profile samples.
for !isMemoryMapSentinel(line) {
if strings.HasPrefix(line, "---- no stack trace for") {
line = ""
break
}
if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 {
return nil, errUnrecognized
}
var addrs []uint64
var err error
line, addrs, err = parseThreadSample(s)
if err != nil {
return nil, err
}
if len(addrs) == 0 {
// We got a --same as previous threads--. Bump counters.
if len(p.Sample) > 0 {
s := p.Sample[len(p.Sample)-1]
s.Value[0]++
}
continue
}
var sloc []*Location
for i, addr := range addrs {
// Addresses from stack traces point to the next instruction after
// each call. Adjust by -1 to land somewhere on the actual call
// (except for the leaf, which is not a call).
if i > 0 {
addr--
}
loc := locs[addr]
if locs[addr] == nil {
loc = &Location{
Address: addr,
}
p.Location = append(p.Location, loc)
locs[addr] = loc
}
sloc = append(sloc, loc)
}
p.Sample = append(p.Sample, &Sample{
Value: []int64{1},
Location: sloc,
})
}
if err := parseAdditionalSections(s, p); err != nil {
return nil, err
}
cleanupDuplicateLocations(p)
return p, nil
}
// parseThreadSample parses a symbolized or unsymbolized stack trace.
// Returns the first line after the traceback, the sample (or nil if
// it hits a 'same-as-previous' marker) and an error.
func parseThreadSample(s *bufio.Scanner) (nextl string, addrs []uint64, err error) {
var line string
sameAsPrevious := false
for s.Scan() {
line = strings.TrimSpace(s.Text())
if line == "" {
continue
}
if strings.HasPrefix(line, "---") {
break
}
if strings.Contains(line, "same as previous thread") {
sameAsPrevious = true
continue
}
curAddrs, err := parseHexAddresses(line)
if err != nil {
return "", nil, fmt.Errorf("malformed sample: %s: %v", line, err)
}
addrs = append(addrs, curAddrs...)
}
if err := s.Err(); err != nil {
return "", nil, err
}
if sameAsPrevious {
return line, nil, nil
}
return line, addrs, nil
}
// parseAdditionalSections parses any additional sections in the
// profile, ignoring any unrecognized sections.
func parseAdditionalSections(s *bufio.Scanner, p *Profile) error {
for !isMemoryMapSentinel(s.Text()) && s.Scan() {
}
if err := s.Err(); err != nil {
return err
}
return p.ParseMemoryMapFromScanner(s)
}
// ParseProcMaps parses a memory map in the format of /proc/self/maps.
// ParseMemoryMap should be called after setting on a profile to
// associate locations to the corresponding mapping based on their
// address.
func ParseProcMaps(rd io.Reader) ([]*Mapping, error) {
s := bufio.NewScanner(rd)
return parseProcMapsFromScanner(s)
}
func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) {
var mapping []*Mapping
var attrs []string
const delimiter = "="
r := strings.NewReplacer()
for s.Scan() {
line := r.Replace(removeLoggingInfo(s.Text()))
m, err := parseMappingEntry(line)
if err != nil {
if err == errUnrecognized {
// Recognize assignments of the form: attr=value, and replace
// $attr with value on subsequent mappings.
if attr := strings.SplitN(line, delimiter, 2); len(attr) == 2 {
attrs = append(attrs, "$"+strings.TrimSpace(attr[0]), strings.TrimSpace(attr[1]))
r = strings.NewReplacer(attrs...)
}
// Ignore any unrecognized entries
continue
}
return nil, err
}
if m == nil {
continue
}
mapping = append(mapping, m)
}
if err := s.Err(); err != nil {
return nil, err
}
return mapping, nil
}
// removeLoggingInfo detects and removes log prefix entries generated
// by the glog package. If no logging prefix is detected, the string
// is returned unmodified.
func removeLoggingInfo(line string) string {
if match := logInfoRE.FindStringIndex(line); match != nil {
return line[match[1]:]
}
return line
}
// ParseMemoryMap parses a memory map in the format of
// /proc/self/maps, and overrides the mappings in the current profile.
// It renumbers the samples and locations in the profile correspondingly.
func (p *Profile) ParseMemoryMap(rd io.Reader) error {
return p.ParseMemoryMapFromScanner(bufio.NewScanner(rd))
}
// ParseMemoryMapFromScanner parses a memory map in the format of
// /proc/self/maps or a variety of legacy format, and overrides the
// mappings in the current profile. It renumbers the samples and
// locations in the profile correspondingly.
func (p *Profile) ParseMemoryMapFromScanner(s *bufio.Scanner) error {
mapping, err := parseProcMapsFromScanner(s)
if err != nil {
return err
}
p.Mapping = append(p.Mapping, mapping...)
p.massageMappings()
p.remapLocationIDs()
p.remapFunctionIDs()
p.remapMappingIDs()
return nil
}
func parseMappingEntry(l string) (*Mapping, error) {
var start, end, perm, file, offset, buildID string
if me := procMapsRE.FindStringSubmatch(l); len(me) == 6 {
start, end, perm, offset, file = me[1], me[2], me[3], me[4], me[5]
} else if me := briefMapsRE.FindStringSubmatch(l); len(me) == 7 {
start, end, perm, file, offset, buildID = me[1], me[2], me[3], me[4], me[5], me[6]
} else {
return nil, errUnrecognized
}
var err error
mapping := &Mapping{
File: file,
BuildID: buildID,
}
if perm != "" && !strings.Contains(perm, "x") {
// Skip non-executable entries.
return nil, nil
}
if mapping.Start, err = strconv.ParseUint(start, 16, 64); err != nil {
return nil, errUnrecognized
}
if mapping.Limit, err = strconv.ParseUint(end, 16, 64); err != nil {
return nil, errUnrecognized
}
if offset != "" {
if mapping.Offset, err = strconv.ParseUint(offset, 16, 64); err != nil {
return nil, errUnrecognized
}
}
return mapping, nil
}
var memoryMapSentinels = []string{
"--- Memory map: ---",
"MAPPED_LIBRARIES:",
}
// isMemoryMapSentinel returns true if the string contains one of the
// known sentinels for memory map information.
func isMemoryMapSentinel(line string) bool {
for _, s := range memoryMapSentinels {
if strings.Contains(line, s) {
return true
}
}
return false
}
func (p *Profile) addLegacyFrameInfo() {
switch {
case isProfileType(p, heapzSampleTypes):
p.DropFrames, p.KeepFrames = allocRxStr, allocSkipRxStr
case isProfileType(p, contentionzSampleTypes):
p.DropFrames, p.KeepFrames = lockRxStr, ""
default:
p.DropFrames, p.KeepFrames = cpuProfilerRxStr, ""
}
}
var heapzSampleTypes = [][]string{
{"allocations", "size"}, // early Go pprof profiles
{"objects", "space"},
{"inuse_objects", "inuse_space"},
{"alloc_objects", "alloc_space"},
{"alloc_objects", "alloc_space", "inuse_objects", "inuse_space"}, // Go pprof legacy profiles
}
var contentionzSampleTypes = [][]string{
{"contentions", "delay"},
}
func isProfileType(p *Profile, types [][]string) bool {
st := p.SampleType
nextType:
for _, t := range types {
if len(st) != len(t) {
continue
}
for i := range st {
if st[i].Type != t[i] {
continue nextType
}
}
return true
}
return false
}
var allocRxStr = strings.Join([]string{
// POSIX entry points.
`calloc`,
`cfree`,
`malloc`,
`free`,
`memalign`,
`do_memalign`,
`(__)?posix_memalign`,
`pvalloc`,
`valloc`,
`realloc`,
// TC malloc.
`tcmalloc::.*`,
`tc_calloc`,
`tc_cfree`,
`tc_malloc`,
`tc_free`,
`tc_memalign`,
`tc_posix_memalign`,
`tc_pvalloc`,
`tc_valloc`,
`tc_realloc`,
`tc_new`,
`tc_delete`,
`tc_newarray`,
`tc_deletearray`,
`tc_new_nothrow`,
`tc_newarray_nothrow`,
// Memory-allocation routines on OS X.
`malloc_zone_malloc`,
`malloc_zone_calloc`,
`malloc_zone_valloc`,
`malloc_zone_realloc`,
`malloc_zone_memalign`,
`malloc_zone_free`,
// Go runtime
`runtime\..*`,
// Other misc. memory allocation routines
`BaseArena::.*`,
`(::)?do_malloc_no_errno`,
`(::)?do_malloc_pages`,
`(::)?do_malloc`,
`DoSampledAllocation`,
`MallocedMemBlock::MallocedMemBlock`,
`_M_allocate`,
`__builtin_(vec_)?delete`,
`__builtin_(vec_)?new`,
`__gnu_cxx::new_allocator::allocate`,
`__libc_malloc`,
`__malloc_alloc_template::allocate`,
`allocate`,
`cpp_alloc`,
`operator new(\[\])?`,
`simple_alloc::allocate`,
}, `|`)
var allocSkipRxStr = strings.Join([]string{
// Preserve Go runtime frames that appear in the middle/bottom of
// the stack.
`runtime\.panic`,
`runtime\.reflectcall`,
`runtime\.call[0-9]*`,
}, `|`)
var cpuProfilerRxStr = strings.Join([]string{
`ProfileData::Add`,
`ProfileData::prof_handler`,
`CpuProfiler::prof_handler`,
`__pthread_sighandler`,
`__restore`,
}, `|`)
var lockRxStr = strings.Join([]string{
`RecordLockProfileData`,
`(base::)?RecordLockProfileData.*`,
`(base::)?SubmitMutexProfileData.*`,
`(base::)?SubmitSpinLockProfileData.*`,
`(base::Mutex::)?AwaitCommon.*`,
`(base::Mutex::)?Unlock.*`,
`(base::Mutex::)?UnlockSlow.*`,
`(base::Mutex::)?ReaderUnlock.*`,
`(base::MutexLock::)?~MutexLock.*`,
`(Mutex::)?AwaitCommon.*`,
`(Mutex::)?Unlock.*`,
`(Mutex::)?UnlockSlow.*`,
`(Mutex::)?ReaderUnlock.*`,
`(MutexLock::)?~MutexLock.*`,
`(SpinLock::)?Unlock.*`,
`(SpinLock::)?SlowUnlock.*`,
`(SpinLockHolder::)?~SpinLockHolder.*`,
}, `|`)
================================================
FILE: vendor/github.com/google/pprof/profile/merge.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package profile
import (
"fmt"
"sort"
"strconv"
"strings"
)
// Compact performs garbage collection on a profile to remove any
// unreferenced fields. This is useful to reduce the size of a profile
// after samples or locations have been removed.
func (p *Profile) Compact() *Profile {
p, _ = Merge([]*Profile{p})
return p
}
// Merge merges all the profiles in profs into a single Profile.
// Returns a new profile independent of the input profiles. The merged
// profile is compacted to eliminate unused samples, locations,
// functions and mappings. Profiles must have identical profile sample
// and period types or the merge will fail. profile.Period of the
// resulting profile will be the maximum of all profiles, and
// profile.TimeNanos will be the earliest nonzero one. Merges are
// associative with the caveat of the first profile having some
// specialization in how headers are combined. There may be other
// subtleties now or in the future regarding associativity.
func Merge(srcs []*Profile) (*Profile, error) {
if len(srcs) == 0 {
return nil, fmt.Errorf("no profiles to merge")
}
p, err := combineHeaders(srcs)
if err != nil {
return nil, err
}
pm := &profileMerger{
p: p,
samples: make(map[sampleKey]*Sample, len(srcs[0].Sample)),
locations: make(map[locationKey]*Location, len(srcs[0].Location)),
functions: make(map[functionKey]*Function, len(srcs[0].Function)),
mappings: make(map[mappingKey]*Mapping, len(srcs[0].Mapping)),
}
for _, src := range srcs {
// Clear the profile-specific hash tables
pm.locationsByID = make(map[uint64]*Location, len(src.Location))
pm.functionsByID = make(map[uint64]*Function, len(src.Function))
pm.mappingsByID = make(map[uint64]mapInfo, len(src.Mapping))
if len(pm.mappings) == 0 && len(src.Mapping) > 0 {
// The Mapping list has the property that the first mapping
// represents the main binary. Take the first Mapping we see,
// otherwise the operations below will add mappings in an
// arbitrary order.
pm.mapMapping(src.Mapping[0])
}
for _, s := range src.Sample {
if !isZeroSample(s) {
pm.mapSample(s)
}
}
}
for _, s := range p.Sample {
if isZeroSample(s) {
// If there are any zero samples, re-merge the profile to GC
// them.
return Merge([]*Profile{p})
}
}
return p, nil
}
// Normalize normalizes the source profile by multiplying each value in profile by the
// ratio of the sum of the base profile's values of that sample type to the sum of the
// source profile's value of that sample type.
func (p *Profile) Normalize(pb *Profile) error {
if err := p.compatible(pb); err != nil {
return err
}
baseVals := make([]int64, len(p.SampleType))
for _, s := range pb.Sample {
for i, v := range s.Value {
baseVals[i] += v
}
}
srcVals := make([]int64, len(p.SampleType))
for _, s := range p.Sample {
for i, v := range s.Value {
srcVals[i] += v
}
}
normScale := make([]float64, len(baseVals))
for i := range baseVals {
if srcVals[i] == 0 {
normScale[i] = 0.0
} else {
normScale[i] = float64(baseVals[i]) / float64(srcVals[i])
}
}
p.ScaleN(normScale)
return nil
}
func isZeroSample(s *Sample) bool {
for _, v := range s.Value {
if v != 0 {
return false
}
}
return true
}
type profileMerger struct {
p *Profile
// Memoization tables within a profile.
locationsByID map[uint64]*Location
functionsByID map[uint64]*Function
mappingsByID map[uint64]mapInfo
// Memoization tables for profile entities.
samples map[sampleKey]*Sample
locations map[locationKey]*Location
functions map[functionKey]*Function
mappings map[mappingKey]*Mapping
}
type mapInfo struct {
m *Mapping
offset int64
}
func (pm *profileMerger) mapSample(src *Sample) *Sample {
s := &Sample{
Location: make([]*Location, len(src.Location)),
Value: make([]int64, len(src.Value)),
Label: make(map[string][]string, len(src.Label)),
NumLabel: make(map[string][]int64, len(src.NumLabel)),
NumUnit: make(map[string][]string, len(src.NumLabel)),
}
for i, l := range src.Location {
s.Location[i] = pm.mapLocation(l)
}
for k, v := range src.Label {
vv := make([]string, len(v))
copy(vv, v)
s.Label[k] = vv
}
for k, v := range src.NumLabel {
u := src.NumUnit[k]
vv := make([]int64, len(v))
uu := make([]string, len(u))
copy(vv, v)
copy(uu, u)
s.NumLabel[k] = vv
s.NumUnit[k] = uu
}
// Check memoization table. Must be done on the remapped location to
// account for the remapped mapping. Add current values to the
// existing sample.
k := s.key()
if ss, ok := pm.samples[k]; ok {
for i, v := range src.Value {
ss.Value[i] += v
}
return ss
}
copy(s.Value, src.Value)
pm.samples[k] = s
pm.p.Sample = append(pm.p.Sample, s)
return s
}
// key generates sampleKey to be used as a key for maps.
func (sample *Sample) key() sampleKey {
ids := make([]string, len(sample.Location))
for i, l := range sample.Location {
ids[i] = strconv.FormatUint(l.ID, 16)
}
labels := make([]string, 0, len(sample.Label))
for k, v := range sample.Label {
labels = append(labels, fmt.Sprintf("%q%q", k, v))
}
sort.Strings(labels)
numlabels := make([]string, 0, len(sample.NumLabel))
for k, v := range sample.NumLabel {
numlabels = append(numlabels, fmt.Sprintf("%q%x%x", k, v, sample.NumUnit[k]))
}
sort.Strings(numlabels)
return sampleKey{
strings.Join(ids, "|"),
strings.Join(labels, ""),
strings.Join(numlabels, ""),
}
}
type sampleKey struct {
locations string
labels string
numlabels string
}
func (pm *profileMerger) mapLocation(src *Location) *Location {
if src == nil {
return nil
}
if l, ok := pm.locationsByID[src.ID]; ok {
return l
}
mi := pm.mapMapping(src.Mapping)
l := &Location{
ID: uint64(len(pm.p.Location) + 1),
Mapping: mi.m,
Address: uint64(int64(src.Address) + mi.offset),
Line: make([]Line, len(src.Line)),
IsFolded: src.IsFolded,
}
for i, ln := range src.Line {
l.Line[i] = pm.mapLine(ln)
}
// Check memoization table. Must be done on the remapped location to
// account for the remapped mapping ID.
k := l.key()
if ll, ok := pm.locations[k]; ok {
pm.locationsByID[src.ID] = ll
return ll
}
pm.locationsByID[src.ID] = l
pm.locations[k] = l
pm.p.Location = append(pm.p.Location, l)
return l
}
// key generates locationKey to be used as a key for maps.
func (l *Location) key() locationKey {
key := locationKey{
addr: l.Address,
isFolded: l.IsFolded,
}
if l.Mapping != nil {
// Normalizes address to handle address space randomization.
key.addr -= l.Mapping.Start
key.mappingID = l.Mapping.ID
}
lines := make([]string, len(l.Line)*2)
for i, line := range l.Line {
if line.Function != nil {
lines[i*2] = strconv.FormatUint(line.Function.ID, 16)
}
lines[i*2+1] = strconv.FormatInt(line.Line, 16)
}
key.lines = strings.Join(lines, "|")
return key
}
type locationKey struct {
addr, mappingID uint64
lines string
isFolded bool
}
func (pm *profileMerger) mapMapping(src *Mapping) mapInfo {
if src == nil {
return mapInfo{}
}
if mi, ok := pm.mappingsByID[src.ID]; ok {
return mi
}
// Check memoization tables.
mk := src.key()
if m, ok := pm.mappings[mk]; ok {
mi := mapInfo{m, int64(m.Start) - int64(src.Start)}
pm.mappingsByID[src.ID] = mi
return mi
}
m := &Mapping{
ID: uint64(len(pm.p.Mapping) + 1),
Start: src.Start,
Limit: src.Limit,
Offset: src.Offset,
File: src.File,
BuildID: src.BuildID,
HasFunctions: src.HasFunctions,
HasFilenames: src.HasFilenames,
HasLineNumbers: src.HasLineNumbers,
HasInlineFrames: src.HasInlineFrames,
}
pm.p.Mapping = append(pm.p.Mapping, m)
// Update memoization tables.
pm.mappings[mk] = m
mi := mapInfo{m, 0}
pm.mappingsByID[src.ID] = mi
return mi
}
// key generates encoded strings of Mapping to be used as a key for
// maps.
func (m *Mapping) key() mappingKey {
// Normalize addresses to handle address space randomization.
// Round up to next 4K boundary to avoid minor discrepancies.
const mapsizeRounding = 0x1000
size := m.Limit - m.Start
size = size + mapsizeRounding - 1
size = size - (size % mapsizeRounding)
key := mappingKey{
size: size,
offset: m.Offset,
}
switch {
case m.BuildID != "":
key.buildIDOrFile = m.BuildID
case m.File != "":
key.buildIDOrFile = m.File
default:
// A mapping containing neither build ID nor file name is a fake mapping. A
// key with empty buildIDOrFile is used for fake mappings so that they are
// treated as the same mapping during merging.
}
return key
}
type mappingKey struct {
size, offset uint64
buildIDOrFile string
}
func (pm *profileMerger) mapLine(src Line) Line {
ln := Line{
Function: pm.mapFunction(src.Function),
Line: src.Line,
}
return ln
}
func (pm *profileMerger) mapFunction(src *Function) *Function {
if src == nil {
return nil
}
if f, ok := pm.functionsByID[src.ID]; ok {
return f
}
k := src.key()
if f, ok := pm.functions[k]; ok {
pm.functionsByID[src.ID] = f
return f
}
f := &Function{
ID: uint64(len(pm.p.Function) + 1),
Name: src.Name,
SystemName: src.SystemName,
Filename: src.Filename,
StartLine: src.StartLine,
}
pm.functions[k] = f
pm.functionsByID[src.ID] = f
pm.p.Function = append(pm.p.Function, f)
return f
}
// key generates a struct to be used as a key for maps.
func (f *Function) key() functionKey {
return functionKey{
f.StartLine,
f.Name,
f.SystemName,
f.Filename,
}
}
type functionKey struct {
startLine int64
name, systemName, fileName string
}
// combineHeaders checks that all profiles can be merged and returns
// their combined profile.
func combineHeaders(srcs []*Profile) (*Profile, error) {
for _, s := range srcs[1:] {
if err := srcs[0].compatible(s); err != nil {
return nil, err
}
}
var timeNanos, durationNanos, period int64
var comments []string
seenComments := map[string]bool{}
var defaultSampleType string
for _, s := range srcs {
if timeNanos == 0 || s.TimeNanos < timeNanos {
timeNanos = s.TimeNanos
}
durationNanos += s.DurationNanos
if period == 0 || period < s.Period {
period = s.Period
}
for _, c := range s.Comments {
if seen := seenComments[c]; !seen {
comments = append(comments, c)
seenComments[c] = true
}
}
if defaultSampleType == "" {
defaultSampleType = s.DefaultSampleType
}
}
p := &Profile{
SampleType: make([]*ValueType, len(srcs[0].SampleType)),
DropFrames: srcs[0].DropFrames,
KeepFrames: srcs[0].KeepFrames,
TimeNanos: timeNanos,
DurationNanos: durationNanos,
PeriodType: srcs[0].PeriodType,
Period: period,
Comments: comments,
DefaultSampleType: defaultSampleType,
}
copy(p.SampleType, srcs[0].SampleType)
return p, nil
}
// compatible determines if two profiles can be compared/merged.
// returns nil if the profiles are compatible; otherwise an error with
// details on the incompatibility.
func (p *Profile) compatible(pb *Profile) error {
if !equalValueType(p.PeriodType, pb.PeriodType) {
return fmt.Errorf("incompatible period types %v and %v", p.PeriodType, pb.PeriodType)
}
if len(p.SampleType) != len(pb.SampleType) {
return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
}
for i := range p.SampleType {
if !equalValueType(p.SampleType[i], pb.SampleType[i]) {
return fmt.Errorf("incompatible sample types %v and %v", p.SampleType, pb.SampleType)
}
}
return nil
}
// equalValueType returns true if the two value types are semantically
// equal. It ignores the internal fields used during encode/decode.
func equalValueType(st1, st2 *ValueType) bool {
return st1.Type == st2.Type && st1.Unit == st2.Unit
}
================================================
FILE: vendor/github.com/google/pprof/profile/profile.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package profile provides a representation of profile.proto and
// methods to encode/decode profiles in this format.
package profile
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"math"
"path/filepath"
"regexp"
"sort"
"strings"
"sync"
"time"
)
// Profile is an in-memory representation of profile.proto.
type Profile struct {
SampleType []*ValueType
DefaultSampleType string
Sample []*Sample
Mapping []*Mapping
Location []*Location
Function []*Function
Comments []string
DropFrames string
KeepFrames string
TimeNanos int64
DurationNanos int64
PeriodType *ValueType
Period int64
// The following fields are modified during encoding and copying,
// so are protected by a Mutex.
encodeMu sync.Mutex
commentX []int64
dropFramesX int64
keepFramesX int64
stringTable []string
defaultSampleTypeX int64
}
// ValueType corresponds to Profile.ValueType
type ValueType struct {
Type string // cpu, wall, inuse_space, etc
Unit string // seconds, nanoseconds, bytes, etc
typeX int64
unitX int64
}
// Sample corresponds to Profile.Sample
type Sample struct {
Location []*Location
Value []int64
Label map[string][]string
NumLabel map[string][]int64
NumUnit map[string][]string
locationIDX []uint64
labelX []label
}
// label corresponds to Profile.Label
type label struct {
keyX int64
// Exactly one of the two following values must be set
strX int64
numX int64 // Integer value for this label
// can be set if numX has value
unitX int64
}
// Mapping corresponds to Profile.Mapping
type Mapping struct {
ID uint64
Start uint64
Limit uint64
Offset uint64
File string
BuildID string
HasFunctions bool
HasFilenames bool
HasLineNumbers bool
HasInlineFrames bool
fileX int64
buildIDX int64
}
// Location corresponds to Profile.Location
type Location struct {
ID uint64
Mapping *Mapping
Address uint64
Line []Line
IsFolded bool
mappingIDX uint64
}
// Line corresponds to Profile.Line
type Line struct {
Function *Function
Line int64
functionIDX uint64
}
// Function corresponds to Profile.Function
type Function struct {
ID uint64
Name string
SystemName string
Filename string
StartLine int64
nameX int64
systemNameX int64
filenameX int64
}
// Parse parses a profile and checks for its validity. The input
// may be a gzip-compressed encoded protobuf or one of many legacy
// profile formats which may be unsupported in the future.
func Parse(r io.Reader) (*Profile, error) {
data, err := ioutil.ReadAll(r)
if err != nil {
return nil, err
}
return ParseData(data)
}
// ParseData parses a profile from a buffer and checks for its
// validity.
func ParseData(data []byte) (*Profile, error) {
var p *Profile
var err error
if len(data) >= 2 && data[0] == 0x1f && data[1] == 0x8b {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err == nil {
data, err = ioutil.ReadAll(gz)
}
if err != nil {
return nil, fmt.Errorf("decompressing profile: %v", err)
}
}
if p, err = ParseUncompressed(data); err != nil && err != errNoData && err != errConcatProfile {
p, err = parseLegacy(data)
}
if err != nil {
return nil, fmt.Errorf("parsing profile: %v", err)
}
if err := p.CheckValid(); err != nil {
return nil, fmt.Errorf("malformed profile: %v", err)
}
return p, nil
}
var errUnrecognized = fmt.Errorf("unrecognized profile format")
var errMalformed = fmt.Errorf("malformed profile format")
var errNoData = fmt.Errorf("empty input file")
var errConcatProfile = fmt.Errorf("concatenated profiles detected")
func parseLegacy(data []byte) (*Profile, error) {
parsers := []func([]byte) (*Profile, error){
parseCPU,
parseHeap,
parseGoCount, // goroutine, threadcreate
parseThread,
parseContention,
parseJavaProfile,
}
for _, parser := range parsers {
p, err := parser(data)
if err == nil {
p.addLegacyFrameInfo()
return p, nil
}
if err != errUnrecognized {
return nil, err
}
}
return nil, errUnrecognized
}
// ParseUncompressed parses an uncompressed protobuf into a profile.
func ParseUncompressed(data []byte) (*Profile, error) {
if len(data) == 0 {
return nil, errNoData
}
p := &Profile{}
if err := unmarshal(data, p); err != nil {
return nil, err
}
if err := p.postDecode(); err != nil {
return nil, err
}
return p, nil
}
var libRx = regexp.MustCompile(`([.]so$|[.]so[._][0-9]+)`)
// massageMappings applies heuristic-based changes to the profile
// mappings to account for quirks of some environments.
func (p *Profile) massageMappings() {
// Merge adjacent regions with matching names, checking that the offsets match
if len(p.Mapping) > 1 {
mappings := []*Mapping{p.Mapping[0]}
for _, m := range p.Mapping[1:] {
lm := mappings[len(mappings)-1]
if adjacent(lm, m) {
lm.Limit = m.Limit
if m.File != "" {
lm.File = m.File
}
if m.BuildID != "" {
lm.BuildID = m.BuildID
}
p.updateLocationMapping(m, lm)
continue
}
mappings = append(mappings, m)
}
p.Mapping = mappings
}
// Use heuristics to identify main binary and move it to the top of the list of mappings
for i, m := range p.Mapping {
file := strings.TrimSpace(strings.Replace(m.File, "(deleted)", "", -1))
if len(file) == 0 {
continue
}
if len(libRx.FindStringSubmatch(file)) > 0 {
continue
}
if file[0] == '[' {
continue
}
// Swap what we guess is main to position 0.
p.Mapping[0], p.Mapping[i] = p.Mapping[i], p.Mapping[0]
break
}
// Keep the mapping IDs neatly sorted
for i, m := range p.Mapping {
m.ID = uint64(i + 1)
}
}
// adjacent returns whether two mapping entries represent the same
// mapping that has been split into two. Check that their addresses are adjacent,
// and if the offsets match, if they are available.
func adjacent(m1, m2 *Mapping) bool {
if m1.File != "" && m2.File != "" {
if m1.File != m2.File {
return false
}
}
if m1.BuildID != "" && m2.BuildID != "" {
if m1.BuildID != m2.BuildID {
return false
}
}
if m1.Limit != m2.Start {
return false
}
if m1.Offset != 0 && m2.Offset != 0 {
offset := m1.Offset + (m1.Limit - m1.Start)
if offset != m2.Offset {
return false
}
}
return true
}
func (p *Profile) updateLocationMapping(from, to *Mapping) {
for _, l := range p.Location {
if l.Mapping == from {
l.Mapping = to
}
}
}
func serialize(p *Profile) []byte {
p.encodeMu.Lock()
p.preEncode()
b := marshal(p)
p.encodeMu.Unlock()
return b
}
// Write writes the profile as a gzip-compressed marshaled protobuf.
func (p *Profile) Write(w io.Writer) error {
zw := gzip.NewWriter(w)
defer zw.Close()
_, err := zw.Write(serialize(p))
return err
}
// WriteUncompressed writes the profile as a marshaled protobuf.
func (p *Profile) WriteUncompressed(w io.Writer) error {
_, err := w.Write(serialize(p))
return err
}
// CheckValid tests whether the profile is valid. Checks include, but are
// not limited to:
// - len(Profile.Sample[n].value) == len(Profile.value_unit)
// - Sample.id has a corresponding Profile.Location
func (p *Profile) CheckValid() error {
// Check that sample values are consistent
sampleLen := len(p.SampleType)
if sampleLen == 0 && len(p.Sample) != 0 {
return fmt.Errorf("missing sample type information")
}
for _, s := range p.Sample {
if s == nil {
return fmt.Errorf("profile has nil sample")
}
if len(s.Value) != sampleLen {
return fmt.Errorf("mismatch: sample has %d values vs. %d types", len(s.Value), len(p.SampleType))
}
for _, l := range s.Location {
if l == nil {
return fmt.Errorf("sample has nil location")
}
}
}
// Check that all mappings/locations/functions are in the tables
// Check that there are no duplicate ids
mappings := make(map[uint64]*Mapping, len(p.Mapping))
for _, m := range p.Mapping {
if m == nil {
return fmt.Errorf("profile has nil mapping")
}
if m.ID == 0 {
return fmt.Errorf("found mapping with reserved ID=0")
}
if mappings[m.ID] != nil {
return fmt.Errorf("multiple mappings with same id: %d", m.ID)
}
mappings[m.ID] = m
}
functions := make(map[uint64]*Function, len(p.Function))
for _, f := range p.Function {
if f == nil {
return fmt.Errorf("profile has nil function")
}
if f.ID == 0 {
return fmt.Errorf("found function with reserved ID=0")
}
if functions[f.ID] != nil {
return fmt.Errorf("multiple functions with same id: %d", f.ID)
}
functions[f.ID] = f
}
locations := make(map[uint64]*Location, len(p.Location))
for _, l := range p.Location {
if l == nil {
return fmt.Errorf("profile has nil location")
}
if l.ID == 0 {
return fmt.Errorf("found location with reserved id=0")
}
if locations[l.ID] != nil {
return fmt.Errorf("multiple locations with same id: %d", l.ID)
}
locations[l.ID] = l
if m := l.Mapping; m != nil {
if m.ID == 0 || mappings[m.ID] != m {
return fmt.Errorf("inconsistent mapping %p: %d", m, m.ID)
}
}
for _, ln := range l.Line {
f := ln.Function
if f == nil {
return fmt.Errorf("location id: %d has a line with nil function", l.ID)
}
if f.ID == 0 || functions[f.ID] != f {
return fmt.Errorf("inconsistent function %p: %d", f, f.ID)
}
}
}
return nil
}
// Aggregate merges the locations in the profile into equivalence
// classes preserving the request attributes. It also updates the
// samples to point to the merged locations.
func (p *Profile) Aggregate(inlineFrame, function, filename, linenumber, address bool) error {
for _, m := range p.Mapping {
m.HasInlineFrames = m.HasInlineFrames && inlineFrame
m.HasFunctions = m.HasFunctions && function
m.HasFilenames = m.HasFilenames && filename
m.HasLineNumbers = m.HasLineNumbers && linenumber
}
// Aggregate functions
if !function || !filename {
for _, f := range p.Function {
if !function {
f.Name = ""
f.SystemName = ""
}
if !filename {
f.Filename = ""
}
}
}
// Aggregate locations
if !inlineFrame || !address || !linenumber {
for _, l := range p.Location {
if !inlineFrame && len(l.Line) > 1 {
l.Line = l.Line[len(l.Line)-1:]
}
if !linenumber {
for i := range l.Line {
l.Line[i].Line = 0
}
}
if !address {
l.Address = 0
}
}
}
return p.CheckValid()
}
// NumLabelUnits returns a map of numeric label keys to the units
// associated with those keys and a map of those keys to any units
// that were encountered but not used.
// Unit for a given key is the first encountered unit for that key. If multiple
// units are encountered for values paired with a particular key, then the first
// unit encountered is used and all other units are returned in sorted order
// in map of ignored units.
// If no units are encountered for a particular key, the unit is then inferred
// based on the key.
func (p *Profile) NumLabelUnits() (map[string]string, map[string][]string) {
numLabelUnits := map[string]string{}
ignoredUnits := map[string]map[string]bool{}
encounteredKeys := map[string]bool{}
// Determine units based on numeric tags for each sample.
for _, s := range p.Sample {
for k := range s.NumLabel {
encounteredKeys[k] = true
for _, unit := range s.NumUnit[k] {
if unit == "" {
continue
}
if wantUnit, ok := numLabelUnits[k]; !ok {
numLabelUnits[k] = unit
} else if wantUnit != unit {
if v, ok := ignoredUnits[k]; ok {
v[unit] = true
} else {
ignoredUnits[k] = map[string]bool{unit: true}
}
}
}
}
}
// Infer units for keys without any units associated with
// numeric tag values.
for key := range encounteredKeys {
unit := numLabelUnits[key]
if unit == "" {
switch key {
case "alignment", "request":
numLabelUnits[key] = "bytes"
default:
numLabelUnits[key] = key
}
}
}
// Copy ignored units into more readable format
unitsIgnored := make(map[string][]string, len(ignoredUnits))
for key, values := range ignoredUnits {
units := make([]string, len(values))
i := 0
for unit := range values {
units[i] = unit
i++
}
sort.Strings(units)
unitsIgnored[key] = units
}
return numLabelUnits, unitsIgnored
}
// String dumps a text representation of a profile. Intended mainly
// for debugging purposes.
func (p *Profile) String() string {
ss := make([]string, 0, len(p.Comments)+len(p.Sample)+len(p.Mapping)+len(p.Location))
for _, c := range p.Comments {
ss = append(ss, "Comment: "+c)
}
if pt := p.PeriodType; pt != nil {
ss = append(ss, fmt.Sprintf("PeriodType: %s %s", pt.Type, pt.Unit))
}
ss = append(ss, fmt.Sprintf("Period: %d", p.Period))
if p.TimeNanos != 0 {
ss = append(ss, fmt.Sprintf("Time: %v", time.Unix(0, p.TimeNanos)))
}
if p.DurationNanos != 0 {
ss = append(ss, fmt.Sprintf("Duration: %.4v", time.Duration(p.DurationNanos)))
}
ss = append(ss, "Samples:")
var sh1 string
for _, s := range p.SampleType {
dflt := ""
if s.Type == p.DefaultSampleType {
dflt = "[dflt]"
}
sh1 = sh1 + fmt.Sprintf("%s/%s%s ", s.Type, s.Unit, dflt)
}
ss = append(ss, strings.TrimSpace(sh1))
for _, s := range p.Sample {
ss = append(ss, s.string())
}
ss = append(ss, "Locations")
for _, l := range p.Location {
ss = append(ss, l.string())
}
ss = append(ss, "Mappings")
for _, m := range p.Mapping {
ss = append(ss, m.string())
}
return strings.Join(ss, "\n") + "\n"
}
// string dumps a text representation of a mapping. Intended mainly
// for debugging purposes.
func (m *Mapping) string() string {
bits := ""
if m.HasFunctions {
bits = bits + "[FN]"
}
if m.HasFilenames {
bits = bits + "[FL]"
}
if m.HasLineNumbers {
bits = bits + "[LN]"
}
if m.HasInlineFrames {
bits = bits + "[IN]"
}
return fmt.Sprintf("%d: %#x/%#x/%#x %s %s %s",
m.ID,
m.Start, m.Limit, m.Offset,
m.File,
m.BuildID,
bits)
}
// string dumps a text representation of a location. Intended mainly
// for debugging purposes.
func (l *Location) string() string {
ss := []string{}
locStr := fmt.Sprintf("%6d: %#x ", l.ID, l.Address)
if m := l.Mapping; m != nil {
locStr = locStr + fmt.Sprintf("M=%d ", m.ID)
}
if l.IsFolded {
locStr = locStr + "[F] "
}
if len(l.Line) == 0 {
ss = append(ss, locStr)
}
for li := range l.Line {
lnStr := "??"
if fn := l.Line[li].Function; fn != nil {
lnStr = fmt.Sprintf("%s %s:%d s=%d",
fn.Name,
fn.Filename,
l.Line[li].Line,
fn.StartLine)
if fn.Name != fn.SystemName {
lnStr = lnStr + "(" + fn.SystemName + ")"
}
}
ss = append(ss, locStr+lnStr)
// Do not print location details past the first line
locStr = " "
}
return strings.Join(ss, "\n")
}
// string dumps a text representation of a sample. Intended mainly
// for debugging purposes.
func (s *Sample) string() string {
ss := []string{}
var sv string
for _, v := range s.Value {
sv = fmt.Sprintf("%s %10d", sv, v)
}
sv = sv + ": "
for _, l := range s.Location {
sv = sv + fmt.Sprintf("%d ", l.ID)
}
ss = append(ss, sv)
const labelHeader = " "
if len(s.Label) > 0 {
ss = append(ss, labelHeader+labelsToString(s.Label))
}
if len(s.NumLabel) > 0 {
ss = append(ss, labelHeader+numLabelsToString(s.NumLabel, s.NumUnit))
}
return strings.Join(ss, "\n")
}
// labelsToString returns a string representation of a
// map representing labels.
func labelsToString(labels map[string][]string) string {
ls := []string{}
for k, v := range labels {
ls = append(ls, fmt.Sprintf("%s:%v", k, v))
}
sort.Strings(ls)
return strings.Join(ls, " ")
}
// numLabelsToString returns a string representation of a map
// representing numeric labels.
func numLabelsToString(numLabels map[string][]int64, numUnits map[string][]string) string {
ls := []string{}
for k, v := range numLabels {
units := numUnits[k]
var labelString string
if len(units) == len(v) {
values := make([]string, len(v))
for i, vv := range v {
values[i] = fmt.Sprintf("%d %s", vv, units[i])
}
labelString = fmt.Sprintf("%s:%v", k, values)
} else {
labelString = fmt.Sprintf("%s:%v", k, v)
}
ls = append(ls, labelString)
}
sort.Strings(ls)
return strings.Join(ls, " ")
}
// SetLabel sets the specified key to the specified value for all samples in the
// profile.
func (p *Profile) SetLabel(key string, value []string) {
for _, sample := range p.Sample {
if sample.Label == nil {
sample.Label = map[string][]string{key: value}
} else {
sample.Label[key] = value
}
}
}
// RemoveLabel removes all labels associated with the specified key for all
// samples in the profile.
func (p *Profile) RemoveLabel(key string) {
for _, sample := range p.Sample {
delete(sample.Label, key)
}
}
// HasLabel returns true if a sample has a label with indicated key and value.
func (s *Sample) HasLabel(key, value string) bool {
for _, v := range s.Label[key] {
if v == value {
return true
}
}
return false
}
// DiffBaseSample returns true if a sample belongs to the diff base and false
// otherwise.
func (s *Sample) DiffBaseSample() bool {
return s.HasLabel("pprof::base", "true")
}
// Scale multiplies all sample values in a profile by a constant and keeps
// only samples that have at least one non-zero value.
func (p *Profile) Scale(ratio float64) {
if ratio == 1 {
return
}
ratios := make([]float64, len(p.SampleType))
for i := range p.SampleType {
ratios[i] = ratio
}
p.ScaleN(ratios)
}
// ScaleN multiplies each sample values in a sample by a different amount
// and keeps only samples that have at least one non-zero value.
func (p *Profile) ScaleN(ratios []float64) error {
if len(p.SampleType) != len(ratios) {
return fmt.Errorf("mismatched scale ratios, got %d, want %d", len(ratios), len(p.SampleType))
}
allOnes := true
for _, r := range ratios {
if r != 1 {
allOnes = false
break
}
}
if allOnes {
return nil
}
fillIdx := 0
for _, s := range p.Sample {
keepSample := false
for i, v := range s.Value {
if ratios[i] != 1 {
val := int64(math.Round(float64(v) * ratios[i]))
s.Value[i] = val
keepSample = keepSample || val != 0
}
}
if keepSample {
p.Sample[fillIdx] = s
fillIdx++
}
}
p.Sample = p.Sample[:fillIdx]
return nil
}
// HasFunctions determines if all locations in this profile have
// symbolized function information.
func (p *Profile) HasFunctions() bool {
for _, l := range p.Location {
if l.Mapping != nil && !l.Mapping.HasFunctions {
return false
}
}
return true
}
// HasFileLines determines if all locations in this profile have
// symbolized file and line number information.
func (p *Profile) HasFileLines() bool {
for _, l := range p.Location {
if l.Mapping != nil && (!l.Mapping.HasFilenames || !l.Mapping.HasLineNumbers) {
return false
}
}
return true
}
// Unsymbolizable returns true if a mapping points to a binary for which
// locations can't be symbolized in principle, at least now. Examples are
// "[vdso]", [vsyscall]" and some others, see the code.
func (m *Mapping) Unsymbolizable() bool {
name := filepath.Base(m.File)
return strings.HasPrefix(name, "[") || strings.HasPrefix(name, "linux-vdso") || strings.HasPrefix(m.File, "/dev/dri/")
}
// Copy makes a fully independent copy of a profile.
func (p *Profile) Copy() *Profile {
pp := &Profile{}
if err := unmarshal(serialize(p), pp); err != nil {
panic(err)
}
if err := pp.postDecode(); err != nil {
panic(err)
}
return pp
}
================================================
FILE: vendor/github.com/google/pprof/profile/proto.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// This file is a simple protocol buffer encoder and decoder.
// The format is described at
// https://developers.google.com/protocol-buffers/docs/encoding
//
// A protocol message must implement the message interface:
// decoder() []decoder
// encode(*buffer)
//
// The decode method returns a slice indexed by field number that gives the
// function to decode that field.
// The encode method encodes its receiver into the given buffer.
//
// The two methods are simple enough to be implemented by hand rather than
// by using a protocol compiler.
//
// See profile.go for examples of messages implementing this interface.
//
// There is no support for groups, message sets, or "has" bits.
package profile
import (
"errors"
"fmt"
)
type buffer struct {
field int // field tag
typ int // proto wire type code for field
u64 uint64
data []byte
tmp [16]byte
}
type decoder func(*buffer, message) error
type message interface {
decoder() []decoder
encode(*buffer)
}
func marshal(m message) []byte {
var b buffer
m.encode(&b)
return b.data
}
func encodeVarint(b *buffer, x uint64) {
for x >= 128 {
b.data = append(b.data, byte(x)|0x80)
x >>= 7
}
b.data = append(b.data, byte(x))
}
func encodeLength(b *buffer, tag int, len int) {
encodeVarint(b, uint64(tag)<<3|2)
encodeVarint(b, uint64(len))
}
func encodeUint64(b *buffer, tag int, x uint64) {
// append varint to b.data
encodeVarint(b, uint64(tag)<<3)
encodeVarint(b, x)
}
func encodeUint64s(b *buffer, tag int, x []uint64) {
if len(x) > 2 {
// Use packed encoding
n1 := len(b.data)
for _, u := range x {
encodeVarint(b, u)
}
n2 := len(b.data)
encodeLength(b, tag, n2-n1)
n3 := len(b.data)
copy(b.tmp[:], b.data[n2:n3])
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
copy(b.data[n1:], b.tmp[:n3-n2])
return
}
for _, u := range x {
encodeUint64(b, tag, u)
}
}
func encodeUint64Opt(b *buffer, tag int, x uint64) {
if x == 0 {
return
}
encodeUint64(b, tag, x)
}
func encodeInt64(b *buffer, tag int, x int64) {
u := uint64(x)
encodeUint64(b, tag, u)
}
func encodeInt64s(b *buffer, tag int, x []int64) {
if len(x) > 2 {
// Use packed encoding
n1 := len(b.data)
for _, u := range x {
encodeVarint(b, uint64(u))
}
n2 := len(b.data)
encodeLength(b, tag, n2-n1)
n3 := len(b.data)
copy(b.tmp[:], b.data[n2:n3])
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
copy(b.data[n1:], b.tmp[:n3-n2])
return
}
for _, u := range x {
encodeInt64(b, tag, u)
}
}
func encodeInt64Opt(b *buffer, tag int, x int64) {
if x == 0 {
return
}
encodeInt64(b, tag, x)
}
func encodeString(b *buffer, tag int, x string) {
encodeLength(b, tag, len(x))
b.data = append(b.data, x...)
}
func encodeStrings(b *buffer, tag int, x []string) {
for _, s := range x {
encodeString(b, tag, s)
}
}
func encodeBool(b *buffer, tag int, x bool) {
if x {
encodeUint64(b, tag, 1)
} else {
encodeUint64(b, tag, 0)
}
}
func encodeBoolOpt(b *buffer, tag int, x bool) {
if x {
encodeBool(b, tag, x)
}
}
func encodeMessage(b *buffer, tag int, m message) {
n1 := len(b.data)
m.encode(b)
n2 := len(b.data)
encodeLength(b, tag, n2-n1)
n3 := len(b.data)
copy(b.tmp[:], b.data[n2:n3])
copy(b.data[n1+(n3-n2):], b.data[n1:n2])
copy(b.data[n1:], b.tmp[:n3-n2])
}
func unmarshal(data []byte, m message) (err error) {
b := buffer{data: data, typ: 2}
return decodeMessage(&b, m)
}
func le64(p []byte) uint64 {
return uint64(p[0]) | uint64(p[1])<<8 | uint64(p[2])<<16 | uint64(p[3])<<24 | uint64(p[4])<<32 | uint64(p[5])<<40 | uint64(p[6])<<48 | uint64(p[7])<<56
}
func le32(p []byte) uint32 {
return uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
}
func decodeVarint(data []byte) (uint64, []byte, error) {
var u uint64
for i := 0; ; i++ {
if i >= 10 || i >= len(data) {
return 0, nil, errors.New("bad varint")
}
u |= uint64(data[i]&0x7F) << uint(7*i)
if data[i]&0x80 == 0 {
return u, data[i+1:], nil
}
}
}
func decodeField(b *buffer, data []byte) ([]byte, error) {
x, data, err := decodeVarint(data)
if err != nil {
return nil, err
}
b.field = int(x >> 3)
b.typ = int(x & 7)
b.data = nil
b.u64 = 0
switch b.typ {
case 0:
b.u64, data, err = decodeVarint(data)
if err != nil {
return nil, err
}
case 1:
if len(data) < 8 {
return nil, errors.New("not enough data")
}
b.u64 = le64(data[:8])
data = data[8:]
case 2:
var n uint64
n, data, err = decodeVarint(data)
if err != nil {
return nil, err
}
if n > uint64(len(data)) {
return nil, errors.New("too much data")
}
b.data = data[:n]
data = data[n:]
case 5:
if len(data) < 4 {
return nil, errors.New("not enough data")
}
b.u64 = uint64(le32(data[:4]))
data = data[4:]
default:
return nil, fmt.Errorf("unknown wire type: %d", b.typ)
}
return data, nil
}
func checkType(b *buffer, typ int) error {
if b.typ != typ {
return errors.New("type mismatch")
}
return nil
}
func decodeMessage(b *buffer, m message) error {
if err := checkType(b, 2); err != nil {
return err
}
dec := m.decoder()
data := b.data
for len(data) > 0 {
// pull varint field# + type
var err error
data, err = decodeField(b, data)
if err != nil {
return err
}
if b.field >= len(dec) || dec[b.field] == nil {
continue
}
if err := dec[b.field](b, m); err != nil {
return err
}
}
return nil
}
func decodeInt64(b *buffer, x *int64) error {
if err := checkType(b, 0); err != nil {
return err
}
*x = int64(b.u64)
return nil
}
func decodeInt64s(b *buffer, x *[]int64) error {
if b.typ == 2 {
// Packed encoding
data := b.data
tmp := make([]int64, 0, len(data)) // Maximally sized
for len(data) > 0 {
var u uint64
var err error
if u, data, err = decodeVarint(data); err != nil {
return err
}
tmp = append(tmp, int64(u))
}
*x = append(*x, tmp...)
return nil
}
var i int64
if err := decodeInt64(b, &i); err != nil {
return err
}
*x = append(*x, i)
return nil
}
func decodeUint64(b *buffer, x *uint64) error {
if err := checkType(b, 0); err != nil {
return err
}
*x = b.u64
return nil
}
func decodeUint64s(b *buffer, x *[]uint64) error {
if b.typ == 2 {
data := b.data
// Packed encoding
tmp := make([]uint64, 0, len(data)) // Maximally sized
for len(data) > 0 {
var u uint64
var err error
if u, data, err = decodeVarint(data); err != nil {
return err
}
tmp = append(tmp, u)
}
*x = append(*x, tmp...)
return nil
}
var u uint64
if err := decodeUint64(b, &u); err != nil {
return err
}
*x = append(*x, u)
return nil
}
func decodeString(b *buffer, x *string) error {
if err := checkType(b, 2); err != nil {
return err
}
*x = string(b.data)
return nil
}
func decodeStrings(b *buffer, x *[]string) error {
var s string
if err := decodeString(b, &s); err != nil {
return err
}
*x = append(*x, s)
return nil
}
func decodeBool(b *buffer, x *bool) error {
if err := checkType(b, 0); err != nil {
return err
}
if int64(b.u64) == 0 {
*x = false
} else {
*x = true
}
return nil
}
================================================
FILE: vendor/github.com/google/pprof/profile/prune.go
================================================
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Implements methods to remove frames from profiles.
package profile
import (
"fmt"
"regexp"
"strings"
)
var (
reservedNames = []string{"(anonymous namespace)", "operator()"}
bracketRx = func() *regexp.Regexp {
var quotedNames []string
for _, name := range append(reservedNames, "(") {
quotedNames = append(quotedNames, regexp.QuoteMeta(name))
}
return regexp.MustCompile(strings.Join(quotedNames, "|"))
}()
)
// simplifyFunc does some primitive simplification of function names.
func simplifyFunc(f string) string {
// Account for leading '.' on the PPC ELF v1 ABI.
funcName := strings.TrimPrefix(f, ".")
// Account for unsimplified names -- try to remove the argument list by trimming
// starting from the first '(', but skipping reserved names that have '('.
for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) {
foundReserved := false
for _, res := range reservedNames {
if funcName[ind[0]:ind[1]] == res {
foundReserved = true
break
}
}
if !foundReserved {
funcName = funcName[:ind[0]]
break
}
}
return funcName
}
// Prune removes all nodes beneath a node matching dropRx, and not
// matching keepRx. If the root node of a Sample matches, the sample
// will have an empty stack.
func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) {
prune := make(map[uint64]bool)
pruneBeneath := make(map[uint64]bool)
for _, loc := range p.Location {
var i int
for i = len(loc.Line) - 1; i >= 0; i-- {
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
funcName := simplifyFunc(fn.Name)
if dropRx.MatchString(funcName) {
if keepRx == nil || !keepRx.MatchString(funcName) {
break
}
}
}
}
if i >= 0 {
// Found matching entry to prune.
pruneBeneath[loc.ID] = true
// Remove the matching location.
if i == len(loc.Line)-1 {
// Matched the top entry: prune the whole location.
prune[loc.ID] = true
} else {
loc.Line = loc.Line[i+1:]
}
}
}
// Prune locs from each Sample
for _, sample := range p.Sample {
// Scan from the root to the leaves to find the prune location.
// Do not prune frames before the first user frame, to avoid
// pruning everything.
foundUser := false
for i := len(sample.Location) - 1; i >= 0; i-- {
id := sample.Location[i].ID
if !prune[id] && !pruneBeneath[id] {
foundUser = true
continue
}
if !foundUser {
continue
}
if prune[id] {
sample.Location = sample.Location[i+1:]
break
}
if pruneBeneath[id] {
sample.Location = sample.Location[i:]
break
}
}
}
}
// RemoveUninteresting prunes and elides profiles using built-in
// tables of uninteresting function names.
func (p *Profile) RemoveUninteresting() error {
var keep, drop *regexp.Regexp
var err error
if p.DropFrames != "" {
if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil {
return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err)
}
if p.KeepFrames != "" {
if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil {
return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err)
}
}
p.Prune(drop, keep)
}
return nil
}
// PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself.
//
// Please see the example below to understand this method as well as
// the difference from Prune method.
//
// A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline.
//
// PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A.
// Prune(A, nil) returns [B,C,B,D] by removing A itself.
//
// PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom.
// Prune(B, nil) returns [D] because a matching node is found by scanning from the root.
func (p *Profile) PruneFrom(dropRx *regexp.Regexp) {
pruneBeneath := make(map[uint64]bool)
for _, loc := range p.Location {
for i := 0; i < len(loc.Line); i++ {
if fn := loc.Line[i].Function; fn != nil && fn.Name != "" {
funcName := simplifyFunc(fn.Name)
if dropRx.MatchString(funcName) {
// Found matching entry to prune.
pruneBeneath[loc.ID] = true
loc.Line = loc.Line[i:]
break
}
}
}
}
// Prune locs from each Sample
for _, sample := range p.Sample {
// Scan from the bottom leaf to the root to find the prune location.
for i, loc := range sample.Location {
if pruneBeneath[loc.ID] {
sample.Location = sample.Location[i:]
break
}
}
}
}
================================================
FILE: vendor/github.com/pkg/profile/.travis.yml
================================================
language: go
go_import_path: github.com/pkg/profile
go:
- 1.13.x
- 1.14.x
- tip
script:
- go test -race github.com/pkg/profile
================================================
FILE: vendor/github.com/pkg/profile/AUTHORS
================================================
Dave Cheney
================================================
FILE: vendor/github.com/pkg/profile/LICENSE
================================================
Copyright (c) 2013 Dave Cheney. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/github.com/pkg/profile/README.md
================================================
profile
=======
Simple profiling support package for Go
[](https://travis-ci.org/pkg/profile) [](http://godoc.org/github.com/pkg/profile)
installation
------------
go get github.com/pkg/profile
usage
-----
Enabling profiling in your application is as simple as one line at the top of your main function
```go
import "github.com/pkg/profile"
func main() {
defer profile.Start().Stop()
...
}
```
options
-------
What to profile is controlled by config value passed to profile.Start.
By default CPU profiling is enabled.
```go
import "github.com/pkg/profile"
func main() {
// p.Stop() must be called before the program exits to
// ensure profiling information is written to disk.
p := profile.Start(profile.MemProfile, profile.ProfilePath("."), profile.NoShutdownHook)
...
// You can enable different kinds of memory profiling, either Heap or Allocs where Heap
// profiling is the default with profile.MemProfile.
p := profile.Start(profile.MemProfileAllocs, profile.ProfilePath("."), profile.NoShutdownHook)
}
```
Several convenience package level values are provided for cpu, memory, and block (contention) profiling.
For more complex options, consult the [documentation](http://godoc.org/github.com/pkg/profile).
contributing
------------
We welcome pull requests, bug fixes and issue reports.
Before proposing a change, please discuss it first by raising an issue.
================================================
FILE: vendor/github.com/pkg/profile/profile.go
================================================
// Package profile provides a simple way to manage runtime/pprof
// profiling of your Go application.
package profile
import (
"io/ioutil"
"log"
"os"
"os/signal"
"path/filepath"
"runtime"
"runtime/pprof"
"runtime/trace"
"sync/atomic"
"github.com/felixge/fgprof"
)
const (
cpuMode = iota
memMode
mutexMode
blockMode
traceMode
threadCreateMode
goroutineMode
clockMode
)
// Profile represents an active profiling session.
type Profile struct {
// quiet suppresses informational messages during profiling.
quiet bool
// noShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
noShutdownHook bool
// mode holds the type of profiling that will be made
mode int
// path holds the base path where various profiling files are written.
// If blank, the base path will be generated by ioutil.TempDir.
path string
// memProfileRate holds the rate for the memory profile.
memProfileRate int
// memProfileType holds the profile type for memory
// profiles. Allowed values are `heap` and `allocs`.
memProfileType string
// closer holds a cleanup function that run after each profile
closer func()
// stopped records if a call to profile.Stop has been made
stopped uint32
}
// NoShutdownHook controls whether the profiling package should
// hook SIGINT to write profiles cleanly.
// Programs with more sophisticated signal handling should set
// this to true and ensure the Stop() function returned from Start()
// is called during shutdown.
func NoShutdownHook(p *Profile) { p.noShutdownHook = true }
// Quiet suppresses informational messages during profiling.
func Quiet(p *Profile) { p.quiet = true }
// CPUProfile enables cpu profiling.
// It disables any previous profiling settings.
func CPUProfile(p *Profile) { p.mode = cpuMode }
// DefaultMemProfileRate is the default memory profiling rate.
// See also http://golang.org/pkg/runtime/#pkg-variables
const DefaultMemProfileRate = 4096
// MemProfile enables memory profiling.
// It disables any previous profiling settings.
func MemProfile(p *Profile) {
p.memProfileRate = DefaultMemProfileRate
p.mode = memMode
}
// MemProfileRate enables memory profiling at the preferred rate.
// It disables any previous profiling settings.
func MemProfileRate(rate int) func(*Profile) {
return func(p *Profile) {
p.memProfileRate = rate
p.mode = memMode
}
}
// MemProfileHeap changes which type of memory profiling to profile
// the heap.
func MemProfileHeap(p *Profile) {
p.memProfileType = "heap"
p.mode = memMode
}
// MemProfileAllocs changes which type of memory to profile
// allocations.
func MemProfileAllocs(p *Profile) {
p.memProfileType = "allocs"
p.mode = memMode
}
// MutexProfile enables mutex profiling.
// It disables any previous profiling settings.
func MutexProfile(p *Profile) { p.mode = mutexMode }
// BlockProfile enables block (contention) profiling.
// It disables any previous profiling settings.
func BlockProfile(p *Profile) { p.mode = blockMode }
// Trace profile enables execution tracing.
// It disables any previous profiling settings.
func TraceProfile(p *Profile) { p.mode = traceMode }
// ThreadcreationProfile enables thread creation profiling..
// It disables any previous profiling settings.
func ThreadcreationProfile(p *Profile) { p.mode = threadCreateMode }
// GoroutineProfile enables goroutine profiling.
// It disables any previous profiling settings.
func GoroutineProfile(p *Profile) { p.mode = goroutineMode }
// ClockProfile enables wall clock (fgprof) profiling.
// It disables any previous profiling settings.
func ClockProfile(p *Profile) { p.mode = clockMode }
// ProfilePath controls the base path where various profiling
// files are written. If blank, the base path will be generated
// by ioutil.TempDir.
func ProfilePath(path string) func(*Profile) {
return func(p *Profile) {
p.path = path
}
}
// Stop stops the profile and flushes any unwritten data.
func (p *Profile) Stop() {
if !atomic.CompareAndSwapUint32(&p.stopped, 0, 1) {
// someone has already called close
return
}
p.closer()
atomic.StoreUint32(&started, 0)
}
// started is non zero if a profile is running.
var started uint32
// Start starts a new profiling session.
// The caller should call the Stop method on the value returned
// to cleanly stop profiling.
func Start(options ...func(*Profile)) interface {
Stop()
} {
if !atomic.CompareAndSwapUint32(&started, 0, 1) {
log.Fatal("profile: Start() already called")
}
var prof Profile
for _, option := range options {
option(&prof)
}
path, err := func() (string, error) {
if p := prof.path; p != "" {
return p, os.MkdirAll(p, 0777)
}
return ioutil.TempDir("", "profile")
}()
if err != nil {
log.Fatalf("profile: could not create initial output directory: %v", err)
}
logf := func(format string, args ...interface{}) {
if !prof.quiet {
log.Printf(format, args...)
}
}
if prof.memProfileType == "" {
prof.memProfileType = "heap"
}
switch prof.mode {
case cpuMode:
fn := filepath.Join(path, "cpu.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create cpu profile %q: %v", fn, err)
}
logf("profile: cpu profiling enabled, %s", fn)
pprof.StartCPUProfile(f)
prof.closer = func() {
pprof.StopCPUProfile()
f.Close()
logf("profile: cpu profiling disabled, %s", fn)
}
case memMode:
fn := filepath.Join(path, "mem.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create memory profile %q: %v", fn, err)
}
old := runtime.MemProfileRate
runtime.MemProfileRate = prof.memProfileRate
logf("profile: memory profiling enabled (rate %d), %s", runtime.MemProfileRate, fn)
prof.closer = func() {
pprof.Lookup(prof.memProfileType).WriteTo(f, 0)
f.Close()
runtime.MemProfileRate = old
logf("profile: memory profiling disabled, %s", fn)
}
case mutexMode:
fn := filepath.Join(path, "mutex.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create mutex profile %q: %v", fn, err)
}
runtime.SetMutexProfileFraction(1)
logf("profile: mutex profiling enabled, %s", fn)
prof.closer = func() {
if mp := pprof.Lookup("mutex"); mp != nil {
mp.WriteTo(f, 0)
}
f.Close()
runtime.SetMutexProfileFraction(0)
logf("profile: mutex profiling disabled, %s", fn)
}
case blockMode:
fn := filepath.Join(path, "block.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create block profile %q: %v", fn, err)
}
runtime.SetBlockProfileRate(1)
logf("profile: block profiling enabled, %s", fn)
prof.closer = func() {
pprof.Lookup("block").WriteTo(f, 0)
f.Close()
runtime.SetBlockProfileRate(0)
logf("profile: block profiling disabled, %s", fn)
}
case threadCreateMode:
fn := filepath.Join(path, "threadcreation.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create thread creation profile %q: %v", fn, err)
}
logf("profile: thread creation profiling enabled, %s", fn)
prof.closer = func() {
if mp := pprof.Lookup("threadcreate"); mp != nil {
mp.WriteTo(f, 0)
}
f.Close()
logf("profile: thread creation profiling disabled, %s", fn)
}
case traceMode:
fn := filepath.Join(path, "trace.out")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create trace output file %q: %v", fn, err)
}
if err := trace.Start(f); err != nil {
log.Fatalf("profile: could not start trace: %v", err)
}
logf("profile: trace enabled, %s", fn)
prof.closer = func() {
trace.Stop()
logf("profile: trace disabled, %s", fn)
}
case goroutineMode:
fn := filepath.Join(path, "goroutine.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create goroutine profile %q: %v", fn, err)
}
logf("profile: goroutine profiling enabled, %s", fn)
prof.closer = func() {
if mp := pprof.Lookup("goroutine"); mp != nil {
mp.WriteTo(f, 0)
}
f.Close()
logf("profile: goroutine profiling disabled, %s", fn)
}
case clockMode:
fn := filepath.Join(path, "clock.pprof")
f, err := os.Create(fn)
if err != nil {
log.Fatalf("profile: could not create clock profile %q: %v", fn, err)
}
logf("profile: clock profiling enabled, %s", fn)
stop := fgprof.Start(f, fgprof.FormatPprof)
prof.closer = func() {
stop()
f.Close()
logf("profile: clock profiling disabled, %s", fn)
}
}
if !prof.noShutdownHook {
go func() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
<-c
log.Println("profile: caught interrupt, stopping profiles")
prof.Stop()
os.Exit(0)
}()
}
return &prof
}
================================================
FILE: vendor/github.com/pmezard/go-difflib/LICENSE
================================================
Copyright (c) 2013, Patrick Mezard
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
The names of its contributors may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/github.com/pmezard/go-difflib/difflib/difflib.go
================================================
// Package difflib is a partial port of Python difflib module.
//
// It provides tools to compare sequences of strings and generate textual diffs.
//
// The following class and functions have been ported:
//
// - SequenceMatcher
//
// - unified_diff
//
// - context_diff
//
// Getting unified diffs was the main goal of the port. Keep in mind this code
// is mostly suitable to output text differences in a human friendly way, there
// are no guarantees generated diffs are consumable by patch(1).
package difflib
import (
"bufio"
"bytes"
"fmt"
"io"
"strings"
)
func min(a, b int) int {
if a < b {
return a
}
return b
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func calculateRatio(matches, length int) float64 {
if length > 0 {
return 2.0 * float64(matches) / float64(length)
}
return 1.0
}
type Match struct {
A int
B int
Size int
}
type OpCode struct {
Tag byte
I1 int
I2 int
J1 int
J2 int
}
// SequenceMatcher compares sequence of strings. The basic
// algorithm predates, and is a little fancier than, an algorithm
// published in the late 1980's by Ratcliff and Obershelp under the
// hyperbolic name "gestalt pattern matching". The basic idea is to find
// the longest contiguous matching subsequence that contains no "junk"
// elements (R-O doesn't address junk). The same idea is then applied
// recursively to the pieces of the sequences to the left and to the right
// of the matching subsequence. This does not yield minimal edit
// sequences, but does tend to yield matches that "look right" to people.
//
// SequenceMatcher tries to compute a "human-friendly diff" between two
// sequences. Unlike e.g. UNIX(tm) diff, the fundamental notion is the
// longest *contiguous* & junk-free matching subsequence. That's what
// catches peoples' eyes. The Windows(tm) windiff has another interesting
// notion, pairing up elements that appear uniquely in each sequence.
// That, and the method here, appear to yield more intuitive difference
// reports than does diff. This method appears to be the least vulnerable
// to synching up on blocks of "junk lines", though (like blank lines in
// ordinary text files, or maybe "" lines in HTML files). That may be
// because this is the only method of the 3 that has a *concept* of
// "junk" .
//
// Timing: Basic R-O is cubic time worst case and quadratic time expected
// case. SequenceMatcher is quadratic time for the worst case and has
// expected-case behavior dependent in a complicated way on how many
// elements the sequences have in common; best case time is linear.
type SequenceMatcher struct {
a []string
b []string
b2j map[string][]int
IsJunk func(string) bool
autoJunk bool
bJunk map[string]struct{}
matchingBlocks []Match
fullBCount map[string]int
bPopular map[string]struct{}
opCodes []OpCode
}
func NewMatcher(a, b []string) *SequenceMatcher {
m := SequenceMatcher{autoJunk: true}
m.SetSeqs(a, b)
return &m
}
func NewMatcherWithJunk(a, b []string, autoJunk bool,
isJunk func(string) bool) *SequenceMatcher {
m := SequenceMatcher{IsJunk: isJunk, autoJunk: autoJunk}
m.SetSeqs(a, b)
return &m
}
// Set two sequences to be compared.
func (m *SequenceMatcher) SetSeqs(a, b []string) {
m.SetSeq1(a)
m.SetSeq2(b)
}
// Set the first sequence to be compared. The second sequence to be compared is
// not changed.
//
// SequenceMatcher computes and caches detailed information about the second
// sequence, so if you want to compare one sequence S against many sequences,
// use .SetSeq2(s) once and call .SetSeq1(x) repeatedly for each of the other
// sequences.
//
// See also SetSeqs() and SetSeq2().
func (m *SequenceMatcher) SetSeq1(a []string) {
if &a == &m.a {
return
}
m.a = a
m.matchingBlocks = nil
m.opCodes = nil
}
// Set the second sequence to be compared. The first sequence to be compared is
// not changed.
func (m *SequenceMatcher) SetSeq2(b []string) {
if &b == &m.b {
return
}
m.b = b
m.matchingBlocks = nil
m.opCodes = nil
m.fullBCount = nil
m.chainB()
}
func (m *SequenceMatcher) chainB() {
// Populate line -> index mapping
b2j := map[string][]int{}
for i, s := range m.b {
indices := b2j[s]
indices = append(indices, i)
b2j[s] = indices
}
// Purge junk elements
m.bJunk = map[string]struct{}{}
if m.IsJunk != nil {
junk := m.bJunk
for s, _ := range b2j {
if m.IsJunk(s) {
junk[s] = struct{}{}
}
}
for s, _ := range junk {
delete(b2j, s)
}
}
// Purge remaining popular elements
popular := map[string]struct{}{}
n := len(m.b)
if m.autoJunk && n >= 200 {
ntest := n/100 + 1
for s, indices := range b2j {
if len(indices) > ntest {
popular[s] = struct{}{}
}
}
for s, _ := range popular {
delete(b2j, s)
}
}
m.bPopular = popular
m.b2j = b2j
}
func (m *SequenceMatcher) isBJunk(s string) bool {
_, ok := m.bJunk[s]
return ok
}
// Find longest matching block in a[alo:ahi] and b[blo:bhi].
//
// If IsJunk is not defined:
//
// Return (i,j,k) such that a[i:i+k] is equal to b[j:j+k], where
// alo <= i <= i+k <= ahi
// blo <= j <= j+k <= bhi
// and for all (i',j',k') meeting those conditions,
// k >= k'
// i <= i'
// and if i == i', j <= j'
//
// In other words, of all maximal matching blocks, return one that
// starts earliest in a, and of all those maximal matching blocks that
// start earliest in a, return the one that starts earliest in b.
//
// If IsJunk is defined, first the longest matching block is
// determined as above, but with the additional restriction that no
// junk element appears in the block. Then that block is extended as
// far as possible by matching (only) junk elements on both sides. So
// the resulting block never matches on junk except as identical junk
// happens to be adjacent to an "interesting" match.
//
// If no blocks match, return (alo, blo, 0).
func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Match {
// CAUTION: stripping common prefix or suffix would be incorrect.
// E.g.,
// ab
// acab
// Longest matching block is "ab", but if common prefix is
// stripped, it's "a" (tied with "b"). UNIX(tm) diff does so
// strip, so ends up claiming that ab is changed to acab by
// inserting "ca" in the middle. That's minimal but unintuitive:
// "it's obvious" that someone inserted "ac" at the front.
// Windiff ends up at the same place as diff, but by pairing up
// the unique 'b's and then matching the first two 'a's.
besti, bestj, bestsize := alo, blo, 0
// find longest junk-free match
// during an iteration of the loop, j2len[j] = length of longest
// junk-free match ending with a[i-1] and b[j]
j2len := map[int]int{}
for i := alo; i != ahi; i++ {
// look at all instances of a[i] in b; note that because
// b2j has no junk keys, the loop is skipped if a[i] is junk
newj2len := map[int]int{}
for _, j := range m.b2j[m.a[i]] {
// a[i] matches b[j]
if j < blo {
continue
}
if j >= bhi {
break
}
k := j2len[j-1] + 1
newj2len[j] = k
if k > bestsize {
besti, bestj, bestsize = i-k+1, j-k+1, k
}
}
j2len = newj2len
}
// Extend the best by non-junk elements on each end. In particular,
// "popular" non-junk elements aren't in b2j, which greatly speeds
// the inner loop above, but also means "the best" match so far
// doesn't contain any junk *or* popular non-junk elements.
for besti > alo && bestj > blo && !m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
!m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
// Now that we have a wholly interesting match (albeit possibly
// empty!), we may as well suck up the matching junk on each
// side of it too. Can't think of a good reason not to, and it
// saves post-processing the (possibly considerable) expense of
// figuring out what to do with it. In the case of an empty
// interesting match, this is clearly the right thing to do,
// because no other kind of match is possible in the regions.
for besti > alo && bestj > blo && m.isBJunk(m.b[bestj-1]) &&
m.a[besti-1] == m.b[bestj-1] {
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
}
for besti+bestsize < ahi && bestj+bestsize < bhi &&
m.isBJunk(m.b[bestj+bestsize]) &&
m.a[besti+bestsize] == m.b[bestj+bestsize] {
bestsize += 1
}
return Match{A: besti, B: bestj, Size: bestsize}
}
// Return list of triples describing matching subsequences.
//
// Each triple is of the form (i, j, n), and means that
// a[i:i+n] == b[j:j+n]. The triples are monotonically increasing in
// i and in j. It's also guaranteed that if (i, j, n) and (i', j', n') are
// adjacent triples in the list, and the second is not the last triple in the
// list, then i+n != i' or j+n != j'. IOW, adjacent triples never describe
// adjacent equal blocks.
//
// The last triple is a dummy, (len(a), len(b), 0), and is the only
// triple with n==0.
func (m *SequenceMatcher) GetMatchingBlocks() []Match {
if m.matchingBlocks != nil {
return m.matchingBlocks
}
var matchBlocks func(alo, ahi, blo, bhi int, matched []Match) []Match
matchBlocks = func(alo, ahi, blo, bhi int, matched []Match) []Match {
match := m.findLongestMatch(alo, ahi, blo, bhi)
i, j, k := match.A, match.B, match.Size
if match.Size > 0 {
if alo < i && blo < j {
matched = matchBlocks(alo, i, blo, j, matched)
}
matched = append(matched, match)
if i+k < ahi && j+k < bhi {
matched = matchBlocks(i+k, ahi, j+k, bhi, matched)
}
}
return matched
}
matched := matchBlocks(0, len(m.a), 0, len(m.b), nil)
// It's possible that we have adjacent equal blocks in the
// matching_blocks list now.
nonAdjacent := []Match{}
i1, j1, k1 := 0, 0, 0
for _, b := range matched {
// Is this block adjacent to i1, j1, k1?
i2, j2, k2 := b.A, b.B, b.Size
if i1+k1 == i2 && j1+k1 == j2 {
// Yes, so collapse them -- this just increases the length of
// the first block by the length of the second, and the first
// block so lengthened remains the block to compare against.
k1 += k2
} else {
// Not adjacent. Remember the first block (k1==0 means it's
// the dummy we started with), and make the second block the
// new block to compare against.
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
i1, j1, k1 = i2, j2, k2
}
}
if k1 > 0 {
nonAdjacent = append(nonAdjacent, Match{i1, j1, k1})
}
nonAdjacent = append(nonAdjacent, Match{len(m.a), len(m.b), 0})
m.matchingBlocks = nonAdjacent
return m.matchingBlocks
}
// Return list of 5-tuples describing how to turn a into b.
//
// Each tuple is of the form (tag, i1, i2, j1, j2). The first tuple
// has i1 == j1 == 0, and remaining tuples have i1 == the i2 from the
// tuple preceding it, and likewise for j1 == the previous j2.
//
// The tags are characters, with these meanings:
//
// 'r' (replace): a[i1:i2] should be replaced by b[j1:j2]
//
// 'd' (delete): a[i1:i2] should be deleted, j1==j2 in this case.
//
// 'i' (insert): b[j1:j2] should be inserted at a[i1:i1], i1==i2 in this case.
//
// 'e' (equal): a[i1:i2] == b[j1:j2]
func (m *SequenceMatcher) GetOpCodes() []OpCode {
if m.opCodes != nil {
return m.opCodes
}
i, j := 0, 0
matching := m.GetMatchingBlocks()
opCodes := make([]OpCode, 0, len(matching))
for _, m := range matching {
// invariant: we've pumped out correct diffs to change
// a[:i] into b[:j], and the next matching block is
// a[ai:ai+size] == b[bj:bj+size]. So we need to pump
// out a diff to change a[i:ai] into b[j:bj], pump out
// the matching block, and move (i,j) beyond the match
ai, bj, size := m.A, m.B, m.Size
tag := byte(0)
if i < ai && j < bj {
tag = 'r'
} else if i < ai {
tag = 'd'
} else if j < bj {
tag = 'i'
}
if tag > 0 {
opCodes = append(opCodes, OpCode{tag, i, ai, j, bj})
}
i, j = ai+size, bj+size
// the list of matching blocks is terminated by a
// sentinel with size 0
if size > 0 {
opCodes = append(opCodes, OpCode{'e', ai, i, bj, j})
}
}
m.opCodes = opCodes
return m.opCodes
}
// Isolate change clusters by eliminating ranges with no changes.
//
// Return a generator of groups with up to n lines of context.
// Each group is in the same format as returned by GetOpCodes().
func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
if n < 0 {
n = 3
}
codes := m.GetOpCodes()
if len(codes) == 0 {
codes = []OpCode{OpCode{'e', 0, 1, 0, 1}}
}
// Fixup leading and trailing groups if they show no changes.
if codes[0].Tag == 'e' {
c := codes[0]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[0] = OpCode{c.Tag, max(i1, i2-n), i2, max(j1, j2-n), j2}
}
if codes[len(codes)-1].Tag == 'e' {
c := codes[len(codes)-1]
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
codes[len(codes)-1] = OpCode{c.Tag, i1, min(i2, i1+n), j1, min(j2, j1+n)}
}
nn := n + n
groups := [][]OpCode{}
group := []OpCode{}
for _, c := range codes {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
// End the current group and start a new one whenever
// there is a large range with no changes.
if c.Tag == 'e' && i2-i1 > nn {
group = append(group, OpCode{c.Tag, i1, min(i2, i1+n),
j1, min(j2, j1+n)})
groups = append(groups, group)
group = []OpCode{}
i1, j1 = max(i1, i2-n), max(j1, j2-n)
}
group = append(group, OpCode{c.Tag, i1, i2, j1, j2})
}
if len(group) > 0 && !(len(group) == 1 && group[0].Tag == 'e') {
groups = append(groups, group)
}
return groups
}
// Return a measure of the sequences' similarity (float in [0,1]).
//
// Where T is the total number of elements in both sequences, and
// M is the number of matches, this is 2.0*M / T.
// Note that this is 1 if the sequences are identical, and 0 if
// they have nothing in common.
//
// .Ratio() is expensive to compute if you haven't already computed
// .GetMatchingBlocks() or .GetOpCodes(), in which case you may
// want to try .QuickRatio() or .RealQuickRation() first to get an
// upper bound.
func (m *SequenceMatcher) Ratio() float64 {
matches := 0
for _, m := range m.GetMatchingBlocks() {
matches += m.Size
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() relatively quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute.
func (m *SequenceMatcher) QuickRatio() float64 {
// viewing a and b as multisets, set matches to the cardinality
// of their intersection; this counts the number of matches
// without regard to order, so is clearly an upper bound
if m.fullBCount == nil {
m.fullBCount = map[string]int{}
for _, s := range m.b {
m.fullBCount[s] = m.fullBCount[s] + 1
}
}
// avail[x] is the number of times x appears in 'b' less the
// number of times we've seen it in 'a' so far ... kinda
avail := map[string]int{}
matches := 0
for _, s := range m.a {
n, ok := avail[s]
if !ok {
n = m.fullBCount[s]
}
avail[s] = n - 1
if n > 0 {
matches += 1
}
}
return calculateRatio(matches, len(m.a)+len(m.b))
}
// Return an upper bound on ratio() very quickly.
//
// This isn't defined beyond that it is an upper bound on .Ratio(), and
// is faster to compute than either .Ratio() or .QuickRatio().
func (m *SequenceMatcher) RealQuickRatio() float64 {
la, lb := len(m.a), len(m.b)
return calculateRatio(min(la, lb), la+lb)
}
// Convert range to the "ed" format
func formatRangeUnified(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 1 {
return fmt.Sprintf("%d", beginning)
}
if length == 0 {
beginning -= 1 // empty ranges begin at line just before the range
}
return fmt.Sprintf("%d,%d", beginning, length)
}
// Unified diff parameters
type UnifiedDiff struct {
A []string // First sequence lines
FromFile string // First file name
FromDate string // First file time
B []string // Second sequence lines
ToFile string // Second file name
ToDate string // Second file time
Eol string // Headers end of line, defaults to LF
Context int // Number of context lines
}
// Compare two sequences of lines; generate the delta as a unified diff.
//
// Unified diffs are a compact way of showing line changes and a few
// lines of context. The number of context lines is set by 'n' which
// defaults to three.
//
// By default, the diff control lines (those with ---, +++, or @@) are
// created with a trailing newline. This is helpful so that inputs
// created from file.readlines() result in diffs that are suitable for
// file.writelines() since both the inputs and outputs have trailing
// newlines.
//
// For inputs that do not have trailing newlines, set the lineterm
// argument to "" so that the output will be uniformly newline free.
//
// The unidiff format normally has a header for filenames and modification
// times. Any or all of these may be specified using strings for
// 'fromfile', 'tofile', 'fromfiledate', and 'tofiledate'.
// The modification times are normally expressed in the ISO 8601 format.
func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
wf := func(format string, args ...interface{}) error {
_, err := buf.WriteString(fmt.Sprintf(format, args...))
return err
}
ws := func(s string) error {
_, err := buf.WriteString(s)
return err
}
if len(diff.Eol) == 0 {
diff.Eol = "\n"
}
started := false
m := NewMatcher(diff.A, diff.B)
for _, g := range m.GetGroupedOpCodes(diff.Context) {
if !started {
started = true
fromDate := ""
if len(diff.FromDate) > 0 {
fromDate = "\t" + diff.FromDate
}
toDate := ""
if len(diff.ToDate) > 0 {
toDate = "\t" + diff.ToDate
}
if diff.FromFile != "" || diff.ToFile != "" {
err := wf("--- %s%s%s", diff.FromFile, fromDate, diff.Eol)
if err != nil {
return err
}
err = wf("+++ %s%s%s", diff.ToFile, toDate, diff.Eol)
if err != nil {
return err
}
}
}
first, last := g[0], g[len(g)-1]
range1 := formatRangeUnified(first.I1, last.I2)
range2 := formatRangeUnified(first.J1, last.J2)
if err := wf("@@ -%s +%s @@%s", range1, range2, diff.Eol); err != nil {
return err
}
for _, c := range g {
i1, i2, j1, j2 := c.I1, c.I2, c.J1, c.J2
if c.Tag == 'e' {
for _, line := range diff.A[i1:i2] {
if err := ws(" " + line); err != nil {
return err
}
}
continue
}
if c.Tag == 'r' || c.Tag == 'd' {
for _, line := range diff.A[i1:i2] {
if err := ws("-" + line); err != nil {
return err
}
}
}
if c.Tag == 'r' || c.Tag == 'i' {
for _, line := range diff.B[j1:j2] {
if err := ws("+" + line); err != nil {
return err
}
}
}
}
}
return nil
}
// Like WriteUnifiedDiff but returns the diff a string.
func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
w := &bytes.Buffer{}
err := WriteUnifiedDiff(w, diff)
return string(w.Bytes()), err
}
// Convert range to the "ed" format.
func formatRangeContext(start, stop int) string {
// Per the diff spec at http://www.unix.org/single_unix_specification/
beginning := start + 1 // lines start numbering with one
length := stop - start
if length == 0 {
beginning -= 1 // empty ranges begin at line just before the range
}
if length <= 1 {
return fmt.Sprintf("%d", beginning)
}
return fmt.Sprintf("%d,%d", beginning, beginning+length-1)
}
type ContextDiff UnifiedDiff
// Compare two sequences of lines; generate the delta as a context diff.
//
// Context diffs are a compact way of showing line changes and a few
// lines of context. The number of context lines is set by diff.Context
// which defaults to three.
//
// By default, the diff control lines (those with *** or ---) are
// created with a trailing newline.
//
// For inputs that do not have trailing newlines, set the diff.Eol
// argument to "" so that the output will be uniformly newline free.
//
// The context diff format normally has a header for filenames and
// modification times. Any or all of these may be specified using
// strings for diff.FromFile, diff.ToFile, diff.FromDate, diff.ToDate.
// The modification times are normally expressed in the ISO 8601 format.
// If not specified, the strings default to blanks.
func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
buf := bufio.NewWriter(writer)
defer buf.Flush()
var diffErr error
wf := func(format string, args ...interface{}) {
_, err := buf.WriteString(fmt.Sprintf(format, args...))
if diffErr == nil && err != nil {
diffErr = err
}
}
ws := func(s string) {
_, err := buf.WriteString(s)
if diffErr == nil && err != nil {
diffErr = err
}
}
if len(diff.Eol) == 0 {
diff.Eol = "\n"
}
prefix := map[byte]string{
'i': "+ ",
'd': "- ",
'r': "! ",
'e': " ",
}
started := false
m := NewMatcher(diff.A, diff.B)
for _, g := range m.GetGroupedOpCodes(diff.Context) {
if !started {
started = true
fromDate := ""
if len(diff.FromDate) > 0 {
fromDate = "\t" + diff.FromDate
}
toDate := ""
if len(diff.ToDate) > 0 {
toDate = "\t" + diff.ToDate
}
if diff.FromFile != "" || diff.ToFile != "" {
wf("*** %s%s%s", diff.FromFile, fromDate, diff.Eol)
wf("--- %s%s%s", diff.ToFile, toDate, diff.Eol)
}
}
first, last := g[0], g[len(g)-1]
ws("***************" + diff.Eol)
range1 := formatRangeContext(first.I1, last.I2)
wf("*** %s ****%s", range1, diff.Eol)
for _, c := range g {
if c.Tag == 'r' || c.Tag == 'd' {
for _, cc := range g {
if cc.Tag == 'i' {
continue
}
for _, line := range diff.A[cc.I1:cc.I2] {
ws(prefix[cc.Tag] + line)
}
}
break
}
}
range2 := formatRangeContext(first.J1, last.J2)
wf("--- %s ----%s", range2, diff.Eol)
for _, c := range g {
if c.Tag == 'r' || c.Tag == 'i' {
for _, cc := range g {
if cc.Tag == 'd' {
continue
}
for _, line := range diff.B[cc.J1:cc.J2] {
ws(prefix[cc.Tag] + line)
}
}
break
}
}
}
return diffErr
}
// Like WriteContextDiff but returns the diff a string.
func GetContextDiffString(diff ContextDiff) (string, error) {
w := &bytes.Buffer{}
err := WriteContextDiff(w, diff)
return string(w.Bytes()), err
}
// Split a string on "\n" while preserving them. The output can be used
// as input for UnifiedDiff and ContextDiff structures.
func SplitLines(s string) []string {
lines := strings.SplitAfter(s, "\n")
lines[len(lines)-1] += "\n"
return lines
}
================================================
FILE: vendor/github.com/stretchr/testify/LICENSE
================================================
MIT License
Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_compare.go
================================================
package assert
import (
"bytes"
"fmt"
"reflect"
"time"
)
// Deprecated: CompareType has only ever been for internal use and has accidentally been published since v1.6.0. Do not use it.
type CompareType = compareResult
type compareResult int
const (
compareLess compareResult = iota - 1
compareEqual
compareGreater
)
var (
intType = reflect.TypeOf(int(1))
int8Type = reflect.TypeOf(int8(1))
int16Type = reflect.TypeOf(int16(1))
int32Type = reflect.TypeOf(int32(1))
int64Type = reflect.TypeOf(int64(1))
uintType = reflect.TypeOf(uint(1))
uint8Type = reflect.TypeOf(uint8(1))
uint16Type = reflect.TypeOf(uint16(1))
uint32Type = reflect.TypeOf(uint32(1))
uint64Type = reflect.TypeOf(uint64(1))
uintptrType = reflect.TypeOf(uintptr(1))
float32Type = reflect.TypeOf(float32(1))
float64Type = reflect.TypeOf(float64(1))
stringType = reflect.TypeOf("")
timeType = reflect.TypeOf(time.Time{})
bytesType = reflect.TypeOf([]byte{})
)
func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, bool) {
obj1Value := reflect.ValueOf(obj1)
obj2Value := reflect.ValueOf(obj2)
// throughout this switch we try and avoid calling .Convert() if possible,
// as this has a pretty big performance impact
switch kind {
case reflect.Int:
{
intobj1, ok := obj1.(int)
if !ok {
intobj1 = obj1Value.Convert(intType).Interface().(int)
}
intobj2, ok := obj2.(int)
if !ok {
intobj2 = obj2Value.Convert(intType).Interface().(int)
}
if intobj1 > intobj2 {
return compareGreater, true
}
if intobj1 == intobj2 {
return compareEqual, true
}
if intobj1 < intobj2 {
return compareLess, true
}
}
case reflect.Int8:
{
int8obj1, ok := obj1.(int8)
if !ok {
int8obj1 = obj1Value.Convert(int8Type).Interface().(int8)
}
int8obj2, ok := obj2.(int8)
if !ok {
int8obj2 = obj2Value.Convert(int8Type).Interface().(int8)
}
if int8obj1 > int8obj2 {
return compareGreater, true
}
if int8obj1 == int8obj2 {
return compareEqual, true
}
if int8obj1 < int8obj2 {
return compareLess, true
}
}
case reflect.Int16:
{
int16obj1, ok := obj1.(int16)
if !ok {
int16obj1 = obj1Value.Convert(int16Type).Interface().(int16)
}
int16obj2, ok := obj2.(int16)
if !ok {
int16obj2 = obj2Value.Convert(int16Type).Interface().(int16)
}
if int16obj1 > int16obj2 {
return compareGreater, true
}
if int16obj1 == int16obj2 {
return compareEqual, true
}
if int16obj1 < int16obj2 {
return compareLess, true
}
}
case reflect.Int32:
{
int32obj1, ok := obj1.(int32)
if !ok {
int32obj1 = obj1Value.Convert(int32Type).Interface().(int32)
}
int32obj2, ok := obj2.(int32)
if !ok {
int32obj2 = obj2Value.Convert(int32Type).Interface().(int32)
}
if int32obj1 > int32obj2 {
return compareGreater, true
}
if int32obj1 == int32obj2 {
return compareEqual, true
}
if int32obj1 < int32obj2 {
return compareLess, true
}
}
case reflect.Int64:
{
int64obj1, ok := obj1.(int64)
if !ok {
int64obj1 = obj1Value.Convert(int64Type).Interface().(int64)
}
int64obj2, ok := obj2.(int64)
if !ok {
int64obj2 = obj2Value.Convert(int64Type).Interface().(int64)
}
if int64obj1 > int64obj2 {
return compareGreater, true
}
if int64obj1 == int64obj2 {
return compareEqual, true
}
if int64obj1 < int64obj2 {
return compareLess, true
}
}
case reflect.Uint:
{
uintobj1, ok := obj1.(uint)
if !ok {
uintobj1 = obj1Value.Convert(uintType).Interface().(uint)
}
uintobj2, ok := obj2.(uint)
if !ok {
uintobj2 = obj2Value.Convert(uintType).Interface().(uint)
}
if uintobj1 > uintobj2 {
return compareGreater, true
}
if uintobj1 == uintobj2 {
return compareEqual, true
}
if uintobj1 < uintobj2 {
return compareLess, true
}
}
case reflect.Uint8:
{
uint8obj1, ok := obj1.(uint8)
if !ok {
uint8obj1 = obj1Value.Convert(uint8Type).Interface().(uint8)
}
uint8obj2, ok := obj2.(uint8)
if !ok {
uint8obj2 = obj2Value.Convert(uint8Type).Interface().(uint8)
}
if uint8obj1 > uint8obj2 {
return compareGreater, true
}
if uint8obj1 == uint8obj2 {
return compareEqual, true
}
if uint8obj1 < uint8obj2 {
return compareLess, true
}
}
case reflect.Uint16:
{
uint16obj1, ok := obj1.(uint16)
if !ok {
uint16obj1 = obj1Value.Convert(uint16Type).Interface().(uint16)
}
uint16obj2, ok := obj2.(uint16)
if !ok {
uint16obj2 = obj2Value.Convert(uint16Type).Interface().(uint16)
}
if uint16obj1 > uint16obj2 {
return compareGreater, true
}
if uint16obj1 == uint16obj2 {
return compareEqual, true
}
if uint16obj1 < uint16obj2 {
return compareLess, true
}
}
case reflect.Uint32:
{
uint32obj1, ok := obj1.(uint32)
if !ok {
uint32obj1 = obj1Value.Convert(uint32Type).Interface().(uint32)
}
uint32obj2, ok := obj2.(uint32)
if !ok {
uint32obj2 = obj2Value.Convert(uint32Type).Interface().(uint32)
}
if uint32obj1 > uint32obj2 {
return compareGreater, true
}
if uint32obj1 == uint32obj2 {
return compareEqual, true
}
if uint32obj1 < uint32obj2 {
return compareLess, true
}
}
case reflect.Uint64:
{
uint64obj1, ok := obj1.(uint64)
if !ok {
uint64obj1 = obj1Value.Convert(uint64Type).Interface().(uint64)
}
uint64obj2, ok := obj2.(uint64)
if !ok {
uint64obj2 = obj2Value.Convert(uint64Type).Interface().(uint64)
}
if uint64obj1 > uint64obj2 {
return compareGreater, true
}
if uint64obj1 == uint64obj2 {
return compareEqual, true
}
if uint64obj1 < uint64obj2 {
return compareLess, true
}
}
case reflect.Float32:
{
float32obj1, ok := obj1.(float32)
if !ok {
float32obj1 = obj1Value.Convert(float32Type).Interface().(float32)
}
float32obj2, ok := obj2.(float32)
if !ok {
float32obj2 = obj2Value.Convert(float32Type).Interface().(float32)
}
if float32obj1 > float32obj2 {
return compareGreater, true
}
if float32obj1 == float32obj2 {
return compareEqual, true
}
if float32obj1 < float32obj2 {
return compareLess, true
}
}
case reflect.Float64:
{
float64obj1, ok := obj1.(float64)
if !ok {
float64obj1 = obj1Value.Convert(float64Type).Interface().(float64)
}
float64obj2, ok := obj2.(float64)
if !ok {
float64obj2 = obj2Value.Convert(float64Type).Interface().(float64)
}
if float64obj1 > float64obj2 {
return compareGreater, true
}
if float64obj1 == float64obj2 {
return compareEqual, true
}
if float64obj1 < float64obj2 {
return compareLess, true
}
}
case reflect.String:
{
stringobj1, ok := obj1.(string)
if !ok {
stringobj1 = obj1Value.Convert(stringType).Interface().(string)
}
stringobj2, ok := obj2.(string)
if !ok {
stringobj2 = obj2Value.Convert(stringType).Interface().(string)
}
if stringobj1 > stringobj2 {
return compareGreater, true
}
if stringobj1 == stringobj2 {
return compareEqual, true
}
if stringobj1 < stringobj2 {
return compareLess, true
}
}
// Check for known struct types we can check for compare results.
case reflect.Struct:
{
// All structs enter here. We're not interested in most types.
if !obj1Value.CanConvert(timeType) {
break
}
// time.Time can be compared!
timeObj1, ok := obj1.(time.Time)
if !ok {
timeObj1 = obj1Value.Convert(timeType).Interface().(time.Time)
}
timeObj2, ok := obj2.(time.Time)
if !ok {
timeObj2 = obj2Value.Convert(timeType).Interface().(time.Time)
}
if timeObj1.Before(timeObj2) {
return compareLess, true
}
if timeObj1.Equal(timeObj2) {
return compareEqual, true
}
return compareGreater, true
}
case reflect.Slice:
{
// We only care about the []byte type.
if !obj1Value.CanConvert(bytesType) {
break
}
// []byte can be compared!
bytesObj1, ok := obj1.([]byte)
if !ok {
bytesObj1 = obj1Value.Convert(bytesType).Interface().([]byte)
}
bytesObj2, ok := obj2.([]byte)
if !ok {
bytesObj2 = obj2Value.Convert(bytesType).Interface().([]byte)
}
return compareResult(bytes.Compare(bytesObj1, bytesObj2)), true
}
case reflect.Uintptr:
{
uintptrObj1, ok := obj1.(uintptr)
if !ok {
uintptrObj1 = obj1Value.Convert(uintptrType).Interface().(uintptr)
}
uintptrObj2, ok := obj2.(uintptr)
if !ok {
uintptrObj2 = obj2Value.Convert(uintptrType).Interface().(uintptr)
}
if uintptrObj1 > uintptrObj2 {
return compareGreater, true
}
if uintptrObj1 == uintptrObj2 {
return compareEqual, true
}
if uintptrObj1 < uintptrObj2 {
return compareLess, true
}
}
}
return compareEqual, false
}
// Greater asserts that the first element is greater than the second
//
// assert.Greater(t, 2, 1)
// assert.Greater(t, float64(2), float64(1))
// assert.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
failMessage := fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2)
return compareTwoValues(t, e1, e2, []compareResult{compareGreater}, failMessage, msgAndArgs...)
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// assert.GreaterOrEqual(t, 2, 1)
// assert.GreaterOrEqual(t, 2, 2)
// assert.GreaterOrEqual(t, "b", "a")
// assert.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
failMessage := fmt.Sprintf("\"%v\" is not greater than or equal to \"%v\"", e1, e2)
return compareTwoValues(t, e1, e2, []compareResult{compareGreater, compareEqual}, failMessage, msgAndArgs...)
}
// Less asserts that the first element is less than the second
//
// assert.Less(t, 1, 2)
// assert.Less(t, float64(1), float64(2))
// assert.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
failMessage := fmt.Sprintf("\"%v\" is not less than \"%v\"", e1, e2)
return compareTwoValues(t, e1, e2, []compareResult{compareLess}, failMessage, msgAndArgs...)
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// assert.LessOrEqual(t, 1, 2)
// assert.LessOrEqual(t, 2, 2)
// assert.LessOrEqual(t, "a", "b")
// assert.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
failMessage := fmt.Sprintf("\"%v\" is not less than or equal to \"%v\"", e1, e2)
return compareTwoValues(t, e1, e2, []compareResult{compareLess, compareEqual}, failMessage, msgAndArgs...)
}
// Positive asserts that the specified element is positive
//
// assert.Positive(t, 1)
// assert.Positive(t, 1.23)
func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
zero := reflect.Zero(reflect.TypeOf(e))
failMessage := fmt.Sprintf("\"%v\" is not positive", e)
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareGreater}, failMessage, msgAndArgs...)
}
// Negative asserts that the specified element is negative
//
// assert.Negative(t, -1)
// assert.Negative(t, -1.23)
func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
zero := reflect.Zero(reflect.TypeOf(e))
failMessage := fmt.Sprintf("\"%v\" is not negative", e)
return compareTwoValues(t, e, zero.Interface(), []compareResult{compareLess}, failMessage, msgAndArgs...)
}
func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
e1Kind := reflect.ValueOf(e1).Kind()
e2Kind := reflect.ValueOf(e2).Kind()
if e1Kind != e2Kind {
return Fail(t, "Elements should be the same type", msgAndArgs...)
}
compareResult, isComparable := compare(e1, e2, e1Kind)
if !isComparable {
return Fail(t, fmt.Sprintf(`Can not compare type "%T"`, e1), msgAndArgs...)
}
if !containsValue(allowedComparesResults, compareResult) {
return Fail(t, failMessage, msgAndArgs...)
}
return true
}
func containsValue(values []compareResult, value compareResult) bool {
for _, v := range values {
if v == value {
return true
}
}
return false
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_format.go
================================================
// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
package assert
import (
http "net/http"
url "net/url"
time "time"
)
// Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Condition(t, comp, append([]interface{}{msg}, args...)...)
}
// Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return DirExists(t, path, append([]interface{}{msg}, args...)...)
}
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
}
// Emptyf asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// assert.Emptyf(t, obj, "error message %s", "formatted")
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Empty(t, object, append([]interface{}{msg}, args...)...)
}
// Equalf asserts that two objects are equal.
//
// assert.Equalf(t, 123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
}
// EqualExportedValuesf asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// assert.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
// assert.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualExportedValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// assert.Errorf(t, err, "error message %s", "formatted")
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Error(t, err, append([]interface{}{msg}, args...)...)
}
// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
}
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted")
func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ErrorContains(t, theError, contains, append([]interface{}{msg}, args...)...)
}
// ErrorIsf asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Eventually(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
}
// EventuallyWithTf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// assert.EventuallyWithTf(t, func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithTf(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EventuallyWithT(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
}
// Exactlyf asserts that two objects are equal in value and type.
//
// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
}
// FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
}
// Falsef asserts that the specified value is false.
//
// assert.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return False(t, value, append([]interface{}{msg}, args...)...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FileExists(t, path, append([]interface{}{msg}, args...)...)
}
// Greaterf asserts that the first element is greater than the second
//
// assert.Greaterf(t, 2, 1, "error message %s", "formatted")
// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
// assert.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Greater(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
}
// HTTPErrorf asserts that a specified handler returns an error status code.
//
// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCode(t, handler, method, url, values, statuscode, append([]interface{}{msg}, args...)...)
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
}
// Implementsf asserts that an object is implemented by the specified interface.
//
// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
}
// InDeltaf asserts that the two numerals are within delta of each other.
//
// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
}
// IsDecreasingf asserts that the collection is decreasing
//
// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsDecreasing(t, object, append([]interface{}{msg}, args...)...)
}
// IsIncreasingf asserts that the collection is increasing
//
// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsIncreasing(t, object, append([]interface{}{msg}, args...)...)
}
// IsNonDecreasingf asserts that the collection is not decreasing
//
// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsNonDecreasing(t, object, append([]interface{}{msg}, args...)...)
}
// IsNonIncreasingf asserts that the collection is not increasing
//
// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsNonIncreasing(t, object, append([]interface{}{msg}, args...)...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// assert.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsNotType(t, theType, object, append([]interface{}{msg}, args...)...)
}
// IsTypef asserts that the specified objects are of the same type.
//
// assert.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
}
// JSONEqf asserts that two JSON strings are equivalent.
//
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Len(t, object, length, append([]interface{}{msg}, args...)...)
}
// Lessf asserts that the first element is less than the second
//
// assert.Lessf(t, 1, 2, "error message %s", "formatted")
// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
// assert.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Less(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return LessOrEqual(t, e1, e2, append([]interface{}{msg}, args...)...)
}
// Negativef asserts that the specified element is negative
//
// assert.Negativef(t, -1, "error message %s", "formatted")
// assert.Negativef(t, -1.23, "error message %s", "formatted")
func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Negative(t, e, append([]interface{}{msg}, args...)...)
}
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Never(t, condition, waitFor, tick, append([]interface{}{msg}, args...)...)
}
// Nilf asserts that the specified object is nil.
//
// assert.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Nil(t, object, append([]interface{}{msg}, args...)...)
}
// NoDirExistsf checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NoDirExists(t, path, append([]interface{}{msg}, args...)...)
}
// NoErrorf asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoErrorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj)
// }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NoError(t, err, append([]interface{}{msg}, args...)...)
}
// NoFileExistsf checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NoFileExists(t, path, append([]interface{}{msg}, args...)...)
}
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// assert.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// assert.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
}
// NotEmptyf asserts that the specified object is NOT [Empty].
//
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1])
// }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotErrorAs(t, err, target, append([]interface{}{msg}, args...)...)
}
// NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotErrorIs(t, err, target, append([]interface{}{msg}, args...)...)
}
// NotImplementsf asserts that an object does not implement the specified interface.
//
// assert.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotImplements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
}
// NotNilf asserts that the specified object is not nil.
//
// assert.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotNil(t, object, append([]interface{}{msg}, args...)...)
}
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotPanics(t, f, append([]interface{}{msg}, args...)...)
}
// NotRegexpf asserts that a specified regexp does not match a string.
//
// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
// NotSamef asserts that two pointers do not reference the same object.
//
// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotSame(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
// assert.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// assert.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// assert.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
}
// NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotZero(t, i, append([]interface{}{msg}, args...)...)
}
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Panics(t, f, append([]interface{}{msg}, args...)...)
}
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return PanicsWithError(t, errString, f, append([]interface{}{msg}, args...)...)
}
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
}
// Positivef asserts that the specified element is positive
//
// assert.Positivef(t, 1, "error message %s", "formatted")
// assert.Positivef(t, 1.23, "error message %s", "formatted")
func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Positive(t, e, append([]interface{}{msg}, args...)...)
}
// Regexpf asserts that a specified regexp matches a string.
//
// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
}
// Samef asserts that two pointers reference the same object.
//
// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Same(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
// assert.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// assert.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// assert.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
}
// Truef asserts that the specified value is true.
//
// assert.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return True(t, value, append([]interface{}{msg}, args...)...)
}
// WithinDurationf asserts that the two times are within duration delta of each other.
//
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
}
// WithinRangef asserts that a time is within a time range (inclusive).
//
// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return WithinRange(t, actual, start, end, append([]interface{}{msg}, args...)...)
}
// YAMLEqf asserts that two YAML strings are equivalent.
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return YAMLEq(t, expected, actual, append([]interface{}{msg}, args...)...)
}
// Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Zero(t, i, append([]interface{}{msg}, args...)...)
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl
================================================
{{.CommentFormat}}
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
if h, ok := t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_forward.go
================================================
// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
package assert
import (
http "net/http"
url "net/url"
time "time"
)
// Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Condition(a.t, comp, msgAndArgs...)
}
// Conditionf uses a Comparison to assert a complex condition.
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Conditionf(a.t, comp, msg, args...)
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// a.Contains("Hello World", "World")
// a.Contains(["Hello", "World"], "World")
// a.Contains({"Hello": "World"}, "Hello")
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Contains(a.t, s, contains, msgAndArgs...)
}
// Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// a.Containsf("Hello World", "World", "error message %s", "formatted")
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Containsf(a.t, s, contains, msg, args...)
}
// DirExists checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return DirExists(a.t, path, msgAndArgs...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return DirExistsf(a.t, path, msg, args...)
}
// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ElementsMatchf(a.t, listA, listB, msg, args...)
}
// Empty asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// a.Empty(obj)
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Empty(a.t, object, msgAndArgs...)
}
// Emptyf asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// a.Emptyf(obj, "error message %s", "formatted")
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Emptyf(a.t, object, msg, args...)
}
// Equal asserts that two objects are equal.
//
// a.Equal(123, 123)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Equal(a.t, expected, actual, msgAndArgs...)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString)
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualError(a.t, theError, errString, msgAndArgs...)
}
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualErrorf(a.t, theError, errString, msg, args...)
}
// EqualExportedValues asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true
// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false
func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualExportedValues(a.t, expected, actual, msgAndArgs...)
}
// EqualExportedValuesf asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualExportedValuesf(a.t, expected, actual, msg, args...)
}
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValues(uint32(123), int32(123))
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualValues(a.t, expected, actual, msgAndArgs...)
}
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualValuesf(a.t, expected, actual, msg, args...)
}
// Equalf asserts that two objects are equal.
//
// a.Equalf(123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Equalf(a.t, expected, actual, msg, args...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// a.Error(err)
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Error(a.t, err, msgAndArgs...)
}
// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorAs(a.t, err, target, msgAndArgs...)
}
// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorAsf(a.t, err, target, msg, args...)
}
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// a.ErrorContains(err, expectedErrorSubString)
func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorContains(a.t, theError, contains, msgAndArgs...)
}
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted")
func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorContainsf(a.t, theError, contains, msg, args...)
}
// ErrorIs asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorIs(a.t, err, target, msgAndArgs...)
}
// ErrorIsf asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ErrorIsf(a.t, err, target, msg, args...)
}
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// a.Errorf(err, "error message %s", "formatted")
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Errorf(a.t, err, msg, args...)
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
}
// EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
}
// EventuallyWithTf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
}
// Exactly asserts that two objects are equal in value and type.
//
// a.Exactly(int32(123), int64(123))
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Exactly(a.t, expected, actual, msgAndArgs...)
}
// Exactlyf asserts that two objects are equal in value and type.
//
// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Exactlyf(a.t, expected, actual, msg, args...)
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Fail(a.t, failureMessage, msgAndArgs...)
}
// FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FailNow(a.t, failureMessage, msgAndArgs...)
}
// FailNowf fails test
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FailNowf(a.t, failureMessage, msg, args...)
}
// Failf reports a failure through
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Failf(a.t, failureMessage, msg, args...)
}
// False asserts that the specified value is false.
//
// a.False(myBool)
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return False(a.t, value, msgAndArgs...)
}
// Falsef asserts that the specified value is false.
//
// a.Falsef(myBool, "error message %s", "formatted")
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Falsef(a.t, value, msg, args...)
}
// FileExists checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FileExists(a.t, path, msgAndArgs...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FileExistsf(a.t, path, msg, args...)
}
// Greater asserts that the first element is greater than the second
//
// a.Greater(2, 1)
// a.Greater(float64(2), float64(1))
// a.Greater("b", "a")
func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Greater(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqual(2, 1)
// a.GreaterOrEqual(2, 2)
// a.GreaterOrEqual("b", "a")
// a.GreaterOrEqual("b", "b")
func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return GreaterOrEqualf(a.t, e1, e2, msg, args...)
}
// Greaterf asserts that the first element is greater than the second
//
// a.Greaterf(2, 1, "error message %s", "formatted")
// a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
// a.Greaterf("b", "a", "error message %s", "formatted")
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Greaterf(a.t, e1, e2, msg, args...)
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPError asserts that a specified handler returns an error status code.
//
// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPErrorf asserts that a specified handler returns an error status code.
//
// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
//
// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
}
// Implements asserts that an object is implemented by the specified interface.
//
// a.Implements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Implements(a.t, interfaceObject, object, msgAndArgs...)
}
// Implementsf asserts that an object is implemented by the specified interface.
//
// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Implementsf(a.t, interfaceObject, object, msg, args...)
}
// InDelta asserts that the two numerals are within delta of each other.
//
// a.InDelta(math.Pi, 22/7.0, 0.01)
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
}
// InDeltaf asserts that the two numerals are within delta of each other.
//
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaf(a.t, expected, actual, delta, msg, args...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
}
// IsDecreasing asserts that the collection is decreasing
//
// a.IsDecreasing([]int{2, 1, 0})
// a.IsDecreasing([]float{2, 1})
// a.IsDecreasing([]string{"b", "a"})
func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsDecreasing(a.t, object, msgAndArgs...)
}
// IsDecreasingf asserts that the collection is decreasing
//
// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted")
// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted")
// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted")
func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsDecreasingf(a.t, object, msg, args...)
}
// IsIncreasing asserts that the collection is increasing
//
// a.IsIncreasing([]int{1, 2, 3})
// a.IsIncreasing([]float{1, 2})
// a.IsIncreasing([]string{"a", "b"})
func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsIncreasing(a.t, object, msgAndArgs...)
}
// IsIncreasingf asserts that the collection is increasing
//
// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted")
// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted")
// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted")
func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsIncreasingf(a.t, object, msg, args...)
}
// IsNonDecreasing asserts that the collection is not decreasing
//
// a.IsNonDecreasing([]int{1, 1, 2})
// a.IsNonDecreasing([]float{1, 2})
// a.IsNonDecreasing([]string{"a", "b"})
func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNonDecreasing(a.t, object, msgAndArgs...)
}
// IsNonDecreasingf asserts that the collection is not decreasing
//
// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted")
// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted")
// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted")
func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNonDecreasingf(a.t, object, msg, args...)
}
// IsNonIncreasing asserts that the collection is not increasing
//
// a.IsNonIncreasing([]int{2, 1, 1})
// a.IsNonIncreasing([]float{2, 1})
// a.IsNonIncreasing([]string{"b", "a"})
func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNonIncreasing(a.t, object, msgAndArgs...)
}
// IsNonIncreasingf asserts that the collection is not increasing
//
// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted")
// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted")
// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted")
func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNonIncreasingf(a.t, object, msg, args...)
}
// IsNotType asserts that the specified objects are not of the same type.
//
// a.IsNotType(&NotMyStruct{}, &MyStruct{})
func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNotType(a.t, theType, object, msgAndArgs...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsNotTypef(a.t, theType, object, msg, args...)
}
// IsType asserts that the specified objects are of the same type.
//
// a.IsType(&MyStruct{}, &MyStruct{})
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsType(a.t, expectedType, object, msgAndArgs...)
}
// IsTypef asserts that the specified objects are of the same type.
//
// a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsTypef(a.t, expectedType, object, msg, args...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return JSONEq(a.t, expected, actual, msgAndArgs...)
}
// JSONEqf asserts that two JSON strings are equivalent.
//
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return JSONEqf(a.t, expected, actual, msg, args...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// a.Len(mySlice, 3)
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Len(a.t, object, length, msgAndArgs...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// a.Lenf(mySlice, 3, "error message %s", "formatted")
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Lenf(a.t, object, length, msg, args...)
}
// Less asserts that the first element is less than the second
//
// a.Less(1, 2)
// a.Less(float64(1), float64(2))
// a.Less("a", "b")
func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Less(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// a.LessOrEqual(1, 2)
// a.LessOrEqual(2, 2)
// a.LessOrEqual("a", "b")
// a.LessOrEqual("b", "b")
func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return LessOrEqual(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// a.LessOrEqualf(1, 2, "error message %s", "formatted")
// a.LessOrEqualf(2, 2, "error message %s", "formatted")
// a.LessOrEqualf("a", "b", "error message %s", "formatted")
// a.LessOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return LessOrEqualf(a.t, e1, e2, msg, args...)
}
// Lessf asserts that the first element is less than the second
//
// a.Lessf(1, 2, "error message %s", "formatted")
// a.Lessf(float64(1), float64(2), "error message %s", "formatted")
// a.Lessf("a", "b", "error message %s", "formatted")
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Lessf(a.t, e1, e2, msg, args...)
}
// Negative asserts that the specified element is negative
//
// a.Negative(-1)
// a.Negative(-1.23)
func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Negative(a.t, e, msgAndArgs...)
}
// Negativef asserts that the specified element is negative
//
// a.Negativef(-1, "error message %s", "formatted")
// a.Negativef(-1.23, "error message %s", "formatted")
func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Negativef(a.t, e, msg, args...)
}
// Never asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Never(a.t, condition, waitFor, tick, msgAndArgs...)
}
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Neverf(a.t, condition, waitFor, tick, msg, args...)
}
// Nil asserts that the specified object is nil.
//
// a.Nil(err)
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Nil(a.t, object, msgAndArgs...)
}
// Nilf asserts that the specified object is nil.
//
// a.Nilf(err, "error message %s", "formatted")
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Nilf(a.t, object, msg, args...)
}
// NoDirExists checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoDirExists(a.t, path, msgAndArgs...)
}
// NoDirExistsf checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoDirExistsf(a.t, path, msg, args...)
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if a.NoError(err) {
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoError(a.t, err, msgAndArgs...)
}
// NoErrorf asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if a.NoErrorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoErrorf(a.t, err, msg, args...)
}
// NoFileExists checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoFileExists(a.t, path, msgAndArgs...)
}
// NoFileExistsf checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoFileExistsf(a.t, path, msg, args...)
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// a.NotContains("Hello World", "Earth")
// a.NotContains(["Hello", "World"], "Earth")
// a.NotContains({"Hello": "World"}, "Earth")
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotContains(a.t, s, contains, msgAndArgs...)
}
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotContainsf(a.t, s, contains, msg, args...)
}
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
//
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotElementsMatchf(a.t, listA, listB, msg, args...)
}
// NotEmpty asserts that the specified object is NOT [Empty].
//
// if a.NotEmpty(obj) {
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEmpty(a.t, object, msgAndArgs...)
}
// NotEmptyf asserts that the specified object is NOT [Empty].
//
// if a.NotEmptyf(obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEmptyf(a.t, object, msg, args...)
}
// NotEqual asserts that the specified values are NOT equal.
//
// a.NotEqual(obj1, obj2)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqual(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValues(obj1, obj2)
func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualValues(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualValuesf(a.t, expected, actual, msg, args...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualf(a.t, expected, actual, msg, args...)
}
// NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorAs(a.t, err, target, msgAndArgs...)
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorAsf(a.t, err, target, msg, args...)
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorIs(a.t, err, target, msgAndArgs...)
}
// NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotErrorIsf(a.t, err, target, msg, args...)
}
// NotImplements asserts that an object does not implement the specified interface.
//
// a.NotImplements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotImplements(a.t, interfaceObject, object, msgAndArgs...)
}
// NotImplementsf asserts that an object does not implement the specified interface.
//
// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotImplementsf(a.t, interfaceObject, object, msg, args...)
}
// NotNil asserts that the specified object is not nil.
//
// a.NotNil(err)
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotNil(a.t, object, msgAndArgs...)
}
// NotNilf asserts that the specified object is not nil.
//
// a.NotNilf(err, "error message %s", "formatted")
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotNilf(a.t, object, msg, args...)
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// a.NotPanics(func(){ RemainCalm() })
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotPanics(a.t, f, msgAndArgs...)
}
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotPanicsf(a.t, f, msg, args...)
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting")
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotRegexp(a.t, rx, str, msgAndArgs...)
}
// NotRegexpf asserts that a specified regexp does not match a string.
//
// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotRegexpf(a.t, rx, str, msg, args...)
}
// NotSame asserts that two pointers do not reference the same object.
//
// a.NotSame(ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSame(a.t, expected, actual, msgAndArgs...)
}
// NotSamef asserts that two pointers do not reference the same object.
//
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSamef(a.t, expected, actual, msg, args...)
}
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubset([1, 3, 4], [1, 2])
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
// a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
// a.NotSubset({"x": 1, "y": 2}, ["z"])
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSubset(a.t, list, subset, msgAndArgs...)
}
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSubsetf(a.t, list, subset, msg, args...)
}
// NotZero asserts that i is not the zero value for its type.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotZero(a.t, i, msgAndArgs...)
}
// NotZerof asserts that i is not the zero value for its type.
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotZerof(a.t, i, msg, args...)
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// a.Panics(func(){ GoCrazy() })
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Panics(a.t, f, msgAndArgs...)
}
// PanicsWithError asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithError(a.t, errString, f, msgAndArgs...)
}
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithErrorf(a.t, errString, f, msg, args...)
}
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithValue(a.t, expected, f, msgAndArgs...)
}
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithValuef(a.t, expected, f, msg, args...)
}
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
//
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Panicsf(a.t, f, msg, args...)
}
// Positive asserts that the specified element is positive
//
// a.Positive(1)
// a.Positive(1.23)
func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Positive(a.t, e, msgAndArgs...)
}
// Positivef asserts that the specified element is positive
//
// a.Positivef(1, "error message %s", "formatted")
// a.Positivef(1.23, "error message %s", "formatted")
func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Positivef(a.t, e, msg, args...)
}
// Regexp asserts that a specified regexp matches a string.
//
// a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting")
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Regexp(a.t, rx, str, msgAndArgs...)
}
// Regexpf asserts that a specified regexp matches a string.
//
// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Regexpf(a.t, rx, str, msg, args...)
}
// Same asserts that two pointers reference the same object.
//
// a.Same(ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Same(a.t, expected, actual, msgAndArgs...)
}
// Samef asserts that two pointers reference the same object.
//
// a.Samef(ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Samef(a.t, expected, actual, msg, args...)
}
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subset([1, 2, 3], [1, 2])
// a.Subset({"x": 1, "y": 2}, {"x": 1})
// a.Subset([1, 2, 3], {1: "one", 2: "two"})
// a.Subset({"x": 1, "y": 2}, ["x"])
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Subset(a.t, list, subset, msgAndArgs...)
}
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Subsetf(a.t, list, subset, msg, args...)
}
// True asserts that the specified value is true.
//
// a.True(myBool)
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return True(a.t, value, msgAndArgs...)
}
// Truef asserts that the specified value is true.
//
// a.Truef(myBool, "error message %s", "formatted")
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Truef(a.t, value, msg, args...)
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
// WithinDurationf asserts that the two times are within duration delta of each other.
//
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinDurationf(a.t, expected, actual, delta, msg, args...)
}
// WithinRange asserts that a time is within a time range (inclusive).
//
// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinRange(a.t, actual, start, end, msgAndArgs...)
}
// WithinRangef asserts that a time is within a time range (inclusive).
//
// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinRangef(a.t, actual, start, end, msg, args...)
}
// YAMLEq asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return YAMLEq(a.t, expected, actual, msgAndArgs...)
}
// YAMLEqf asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return YAMLEqf(a.t, expected, actual, msg, args...)
}
// Zero asserts that i is the zero value for its type.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Zero(a.t, i, msgAndArgs...)
}
// Zerof asserts that i is the zero value for its type.
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Zerof(a.t, i, msg, args...)
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl
================================================
{{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
if h, ok := a.t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertion_order.go
================================================
package assert
import (
"fmt"
"reflect"
)
// isOrdered checks that collection contains orderable elements.
func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool {
objKind := reflect.TypeOf(object).Kind()
if objKind != reflect.Slice && objKind != reflect.Array {
return false
}
objValue := reflect.ValueOf(object)
objLen := objValue.Len()
if objLen <= 1 {
return true
}
value := objValue.Index(0)
valueInterface := value.Interface()
firstValueKind := value.Kind()
for i := 1; i < objLen; i++ {
prevValue := value
prevValueInterface := valueInterface
value = objValue.Index(i)
valueInterface = value.Interface()
compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind)
if !isComparable {
return Fail(t, fmt.Sprintf(`Can not compare type "%T" and "%T"`, value, prevValue), msgAndArgs...)
}
if !containsValue(allowedComparesResults, compareResult) {
return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...)
}
}
return true
}
// IsIncreasing asserts that the collection is increasing
//
// assert.IsIncreasing(t, []int{1, 2, 3})
// assert.IsIncreasing(t, []float{1, 2})
// assert.IsIncreasing(t, []string{"a", "b"})
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...)
}
// IsNonIncreasing asserts that the collection is not increasing
//
// assert.IsNonIncreasing(t, []int{2, 1, 1})
// assert.IsNonIncreasing(t, []float{2, 1})
// assert.IsNonIncreasing(t, []string{"b", "a"})
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...)
}
// IsDecreasing asserts that the collection is decreasing
//
// assert.IsDecreasing(t, []int{2, 1, 0})
// assert.IsDecreasing(t, []float{2, 1})
// assert.IsDecreasing(t, []string{"b", "a"})
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...)
}
// IsNonDecreasing asserts that the collection is not decreasing
//
// assert.IsNonDecreasing(t, []int{1, 1, 2})
// assert.IsNonDecreasing(t, []float{1, 2})
// assert.IsNonDecreasing(t, []string{"a", "b"})
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...)
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/assertions.go
================================================
package assert
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"math"
"os"
"reflect"
"regexp"
"runtime"
"runtime/debug"
"strings"
"time"
"unicode"
"unicode/utf8"
"github.com/davecgh/go-spew/spew"
"github.com/pmezard/go-difflib/difflib"
// Wrapper around gopkg.in/yaml.v3
"github.com/stretchr/testify/assert/yaml"
)
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_format.go.tmpl"
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Errorf(format string, args ...interface{})
}
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
// for table driven tests.
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
// for table driven tests.
type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
// for table driven tests.
type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
// PanicAssertionFunc is a common function prototype when validating a panic value. Can be useful
// for table driven tests.
type PanicAssertionFunc = func(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool
// Comparison is a custom function that returns true on success and false on failure
type Comparison func() (success bool)
/*
Helper functions
*/
// ObjectsAreEqual determines if two objects are considered equal.
//
// This function does no assertion of any kind.
func ObjectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil {
return expected == actual
}
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
// copyExportedFields iterates downward through nested data structures and creates a copy
// that only contains the exported struct fields.
func copyExportedFields(expected interface{}) interface{} {
if isNil(expected) {
return expected
}
expectedType := reflect.TypeOf(expected)
expectedKind := expectedType.Kind()
expectedValue := reflect.ValueOf(expected)
switch expectedKind {
case reflect.Struct:
result := reflect.New(expectedType).Elem()
for i := 0; i < expectedType.NumField(); i++ {
field := expectedType.Field(i)
isExported := field.IsExported()
if isExported {
fieldValue := expectedValue.Field(i)
if isNil(fieldValue) || isNil(fieldValue.Interface()) {
continue
}
newValue := copyExportedFields(fieldValue.Interface())
result.Field(i).Set(reflect.ValueOf(newValue))
}
}
return result.Interface()
case reflect.Ptr:
result := reflect.New(expectedType.Elem())
unexportedRemoved := copyExportedFields(expectedValue.Elem().Interface())
result.Elem().Set(reflect.ValueOf(unexportedRemoved))
return result.Interface()
case reflect.Array, reflect.Slice:
var result reflect.Value
if expectedKind == reflect.Array {
result = reflect.New(reflect.ArrayOf(expectedValue.Len(), expectedType.Elem())).Elem()
} else {
result = reflect.MakeSlice(expectedType, expectedValue.Len(), expectedValue.Len())
}
for i := 0; i < expectedValue.Len(); i++ {
index := expectedValue.Index(i)
if isNil(index) {
continue
}
unexportedRemoved := copyExportedFields(index.Interface())
result.Index(i).Set(reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
case reflect.Map:
result := reflect.MakeMap(expectedType)
for _, k := range expectedValue.MapKeys() {
index := expectedValue.MapIndex(k)
unexportedRemoved := copyExportedFields(index.Interface())
result.SetMapIndex(k, reflect.ValueOf(unexportedRemoved))
}
return result.Interface()
default:
return expected
}
}
// ObjectsExportedFieldsAreEqual determines if the exported (public) fields of two objects are
// considered equal. This comparison of only exported fields is applied recursively to nested data
// structures.
//
// This function does no assertion of any kind.
//
// Deprecated: Use [EqualExportedValues] instead.
func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
expectedCleaned := copyExportedFields(expected)
actualCleaned := copyExportedFields(actual)
return ObjectsAreEqualValues(expectedCleaned, actualCleaned)
}
// ObjectsAreEqualValues gets whether two objects are equal, or if their
// values are equal.
func ObjectsAreEqualValues(expected, actual interface{}) bool {
if ObjectsAreEqual(expected, actual) {
return true
}
expectedValue := reflect.ValueOf(expected)
actualValue := reflect.ValueOf(actual)
if !expectedValue.IsValid() || !actualValue.IsValid() {
return false
}
expectedType := expectedValue.Type()
actualType := actualValue.Type()
if !expectedType.ConvertibleTo(actualType) {
return false
}
if !isNumericType(expectedType) || !isNumericType(actualType) {
// Attempt comparison after type conversion
return reflect.DeepEqual(
expectedValue.Convert(actualType).Interface(), actual,
)
}
// If BOTH values are numeric, there are chances of false positives due
// to overflow or underflow. So, we need to make sure to always convert
// the smaller type to a larger type before comparing.
if expectedType.Size() >= actualType.Size() {
return actualValue.Convert(expectedType).Interface() == expected
}
return expectedValue.Convert(actualType).Interface() == actual
}
// isNumericType returns true if the type is one of:
// int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64,
// float32, float64, complex64, complex128
func isNumericType(t reflect.Type) bool {
return t.Kind() >= reflect.Int && t.Kind() <= reflect.Complex128
}
/* CallerInfo is necessary because the assert functions use the testing object
internally, causing it to print the file:line of the assert method, rather than where
the problem actually occurred in calling code.*/
// CallerInfo returns an array of strings containing the file and line number
// of each stack frame leading from the current test to the assert call that
// failed.
func CallerInfo() []string {
var pc uintptr
var file string
var line int
var name string
const stackFrameBufferSize = 10
pcs := make([]uintptr, stackFrameBufferSize)
callers := []string{}
offset := 1
for {
n := runtime.Callers(offset, pcs)
if n == 0 {
break
}
frames := runtime.CallersFrames(pcs[:n])
for {
frame, more := frames.Next()
pc = frame.PC
file = frame.File
line = frame.Line
// This is a huge edge case, but it will panic if this is the case, see #180
if file == "" {
break
}
f := runtime.FuncForPC(pc)
if f == nil {
break
}
name = f.Name()
// testing.tRunner is the standard library function that calls
// tests. Subtests are called directly by tRunner, without going through
// the Test/Benchmark/Example function that contains the t.Run calls, so
// with subtests we should break when we hit tRunner, without adding it
// to the list of callers.
if name == "testing.tRunner" {
break
}
parts := strings.Split(file, "/")
if len(parts) > 1 {
filename := parts[len(parts)-1]
dir := parts[len(parts)-2]
if (dir != "assert" && dir != "mock" && dir != "require") || filename == "mock_test.go" {
callers = append(callers, fmt.Sprintf("%s:%d", file, line))
}
}
// Drop the package
dotPos := strings.LastIndexByte(name, '.')
name = name[dotPos+1:]
if isTest(name, "Test") ||
isTest(name, "Benchmark") ||
isTest(name, "Example") {
break
}
if !more {
break
}
}
// Next batch
offset += cap(pcs)
}
return callers
}
// Stolen from the `go test` tool.
// isTest tells whether name looks like a test (or benchmark, according to prefix).
// It is a Test (say) if there is a character after Test that is not a lower-case letter.
// We don't want TesticularCancer.
func isTest(name, prefix string) bool {
if !strings.HasPrefix(name, prefix) {
return false
}
if len(name) == len(prefix) { // "Test" is ok
return true
}
r, _ := utf8.DecodeRuneInString(name[len(prefix):])
return !unicode.IsLower(r)
}
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
if len(msgAndArgs) == 0 || msgAndArgs == nil {
return ""
}
if len(msgAndArgs) == 1 {
msg := msgAndArgs[0]
if msgAsStr, ok := msg.(string); ok {
return msgAsStr
}
return fmt.Sprintf("%+v", msg)
}
if len(msgAndArgs) > 1 {
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
}
return ""
}
// Aligns the provided message so that all lines after the first line start at the same location as the first line.
// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab).
// The longestLabelLen parameter specifies the length of the longest label in the output (required because this is the
// basis on which the alignment occurs).
func indentMessageLines(message string, longestLabelLen int) string {
outBuf := new(bytes.Buffer)
for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ {
// no need to align first line because it starts at the correct location (after the label)
if i != 0 {
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
}
outBuf.WriteString(scanner.Text())
}
return outBuf.String()
}
type failNower interface {
FailNow()
}
// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, failureMessage, msgAndArgs...)
// We cannot extend TestingT with FailNow() and
// maintain backwards compatibility, so we fallback
// to panicking when FailNow is not available in
// TestingT.
// See issue #263
if t, ok := t.(failNower); ok {
t.FailNow()
} else {
panic("test failed and t is missing `FailNow()`")
}
return false
}
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
content := []labeledContent{
{"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
{"Error", failureMessage},
}
// Add test name if the Go version supports it
if n, ok := t.(interface {
Name() string
}); ok {
content = append(content, labeledContent{"Test", n.Name()})
}
message := messageFromMsgAndArgs(msgAndArgs...)
if len(message) > 0 {
content = append(content, labeledContent{"Messages", message})
}
t.Errorf("\n%s", ""+labeledOutput(content...))
return false
}
type labeledContent struct {
label string
content string
}
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
//
// \t{{label}}:{{align_spaces}}\t{{content}}\n
//
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
// alignment is achieved, "\t{{content}}\n" is added for the output.
//
// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line.
func labeledOutput(content ...labeledContent) string {
longestLabel := 0
for _, v := range content {
if len(v.label) > longestLabel {
longestLabel = len(v.label)
}
}
var output string
for _, v := range content {
output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
}
return output
}
// Implements asserts that an object is implemented by the specified interface.
//
// assert.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
interfaceType := reflect.TypeOf(interfaceObject).Elem()
if object == nil {
return Fail(t, fmt.Sprintf("Cannot check if nil implements %v", interfaceType), msgAndArgs...)
}
if !reflect.TypeOf(object).Implements(interfaceType) {
return Fail(t, fmt.Sprintf("%T must implement %v", object, interfaceType), msgAndArgs...)
}
return true
}
// NotImplements asserts that an object does not implement the specified interface.
//
// assert.NotImplements(t, (*MyInterface)(nil), new(MyObject))
func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
interfaceType := reflect.TypeOf(interfaceObject).Elem()
if object == nil {
return Fail(t, fmt.Sprintf("Cannot check if nil does not implement %v", interfaceType), msgAndArgs...)
}
if reflect.TypeOf(object).Implements(interfaceType) {
return Fail(t, fmt.Sprintf("%T implements %v", object, interfaceType), msgAndArgs...)
}
return true
}
func isType(expectedType, object interface{}) bool {
return ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType))
}
// IsType asserts that the specified objects are of the same type.
//
// assert.IsType(t, &MyStruct{}, &MyStruct{})
func IsType(t TestingT, expectedType, object interface{}, msgAndArgs ...interface{}) bool {
if isType(expectedType, object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Object expected to be of type %T, but was %T", expectedType, object), msgAndArgs...)
}
// IsNotType asserts that the specified objects are not of the same type.
//
// assert.IsNotType(t, &NotMyStruct{}, &MyStruct{})
func IsNotType(t TestingT, theType, object interface{}, msgAndArgs ...interface{}) bool {
if !isType(theType, object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Object type expected to be different than %T", theType), msgAndArgs...)
}
// Equal asserts that two objects are equal.
//
// assert.Equal(t, 123, 123)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
expected, actual, err), msgAndArgs...)
}
if !ObjectsAreEqual(expected, actual) {
diff := diff(expected, actual)
expected, actual = formatUnequalValues(expected, actual)
return Fail(t, fmt.Sprintf("Not equal: \n"+
"expected: %s\n"+
"actual : %s%s", expected, actual, diff), msgAndArgs...)
}
return true
}
// validateEqualArgs checks whether provided arguments can be safely used in the
// Equal/NotEqual functions.
func validateEqualArgs(expected, actual interface{}) error {
if expected == nil && actual == nil {
return nil
}
if isFunction(expected) || isFunction(actual) {
return errors.New("cannot take func type as argument")
}
return nil
}
// Same asserts that two pointers reference the same object.
//
// assert.Same(t, ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
same, ok := samePointers(expected, actual)
if !ok {
return Fail(t, "Both arguments must be pointers", msgAndArgs...)
}
if !same {
// both are pointers but not the same type & pointing to the same address
return Fail(t, fmt.Sprintf("Not same: \n"+
"expected: %p %#[1]v\n"+
"actual : %p %#[2]v",
expected, actual), msgAndArgs...)
}
return true
}
// NotSame asserts that two pointers do not reference the same object.
//
// assert.NotSame(t, ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
same, ok := samePointers(expected, actual)
if !ok {
// fails when the arguments are not pointers
return !(Fail(t, "Both arguments must be pointers", msgAndArgs...))
}
if same {
return Fail(t, fmt.Sprintf(
"Expected and actual point to the same object: %p %#[1]v",
expected), msgAndArgs...)
}
return true
}
// samePointers checks if two generic interface objects are pointers of the same
// type pointing to the same object. It returns two values: same indicating if
// they are the same type and point to the same object, and ok indicating that
// both inputs are pointers.
func samePointers(first, second interface{}) (same bool, ok bool) {
firstPtr, secondPtr := reflect.ValueOf(first), reflect.ValueOf(second)
if firstPtr.Kind() != reflect.Ptr || secondPtr.Kind() != reflect.Ptr {
return false, false // not both are pointers
}
firstType, secondType := reflect.TypeOf(first), reflect.TypeOf(second)
if firstType != secondType {
return false, true // both are pointers, but of different types
}
// compare pointer addresses
return first == second, true
}
// formatUnequalValues takes two values of arbitrary types and returns string
// representations appropriate to be presented to the user.
//
// If the values are not of like type, the returned strings will be prefixed
// with the type name, and the value will be enclosed in parentheses similar
// to a type conversion in the Go grammar.
func formatUnequalValues(expected, actual interface{}) (e string, a string) {
if reflect.TypeOf(expected) != reflect.TypeOf(actual) {
return fmt.Sprintf("%T(%s)", expected, truncatingFormat(expected)),
fmt.Sprintf("%T(%s)", actual, truncatingFormat(actual))
}
switch expected.(type) {
case time.Duration:
return fmt.Sprintf("%v", expected), fmt.Sprintf("%v", actual)
}
return truncatingFormat(expected), truncatingFormat(actual)
}
// truncatingFormat formats the data and truncates it if it's too long.
//
// This helps keep formatted error messages lines from exceeding the
// bufio.MaxScanTokenSize max line length that the go testing framework imposes.
func truncatingFormat(data interface{}) string {
value := fmt.Sprintf("%#v", data)
max := bufio.MaxScanTokenSize - 100 // Give us some space the type info too if needed.
if len(value) > max {
value = value[0:max] + "<... truncated>"
}
return value
}
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// assert.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !ObjectsAreEqualValues(expected, actual) {
diff := diff(expected, actual)
expected, actual = formatUnequalValues(expected, actual)
return Fail(t, fmt.Sprintf("Not equal: \n"+
"expected: %s\n"+
"actual : %s%s", expected, actual, diff), msgAndArgs...)
}
return true
}
// EqualExportedValues asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// assert.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
// assert.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
func EqualExportedValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual)
if aType != bType {
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
}
expected = copyExportedFields(expected)
actual = copyExportedFields(actual)
if !ObjectsAreEqualValues(expected, actual) {
diff := diff(expected, actual)
expected, actual = formatUnequalValues(expected, actual)
return Fail(t, fmt.Sprintf("Not equal (comparing only exported fields): \n"+
"expected: %s\n"+
"actual : %s%s", expected, actual, diff), msgAndArgs...)
}
return true
}
// Exactly asserts that two objects are equal in value and type.
//
// assert.Exactly(t, int32(123), int64(123))
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual)
if aType != bType {
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
}
return Equal(t, expected, actual, msgAndArgs...)
}
// NotNil asserts that the specified object is not nil.
//
// assert.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if !isNil(object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Expected value not to be nil.", msgAndArgs...)
}
// isNil checks if a specified object is nil or not, without Failing.
func isNil(object interface{}) bool {
if object == nil {
return true
}
value := reflect.ValueOf(object)
switch value.Kind() {
case
reflect.Chan, reflect.Func,
reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
return value.IsNil()
}
return false
}
// Nil asserts that the specified object is nil.
//
// assert.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if isNil(object) {
return true
}
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...)
}
// isEmpty gets whether the specified object is considered empty or not.
func isEmpty(object interface{}) bool {
// get nil case out of the way
if object == nil {
return true
}
return isEmptyValue(reflect.ValueOf(object))
}
// isEmptyValue gets whether the specified reflect.Value is considered empty or not.
func isEmptyValue(objValue reflect.Value) bool {
if objValue.IsZero() {
return true
}
// Special cases of non-zero values that we consider empty
switch objValue.Kind() {
// collection types are empty when they have no element
// Note: array types are empty when they match their zero-initialized state.
case reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
// non-nil pointers are empty if the value they point to is empty
case reflect.Ptr:
return isEmptyValue(objValue.Elem())
}
return false
}
// Empty asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// assert.Empty(t, obj)
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := isEmpty(object)
if !pass {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, fmt.Sprintf("Should be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// NotEmpty asserts that the specified object is NOT [Empty].
//
// if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1])
// }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
pass := !isEmpty(object)
if !pass {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, fmt.Sprintf("Should NOT be empty, but was %v", object), msgAndArgs...)
}
return pass
}
// getLen tries to get the length of an object.
// It returns (0, false) if impossible.
func getLen(x interface{}) (length int, ok bool) {
v := reflect.ValueOf(x)
defer func() {
ok = recover() == nil
}()
return v.Len(), true
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// assert.Len(t, mySlice, 3)
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
l, ok := getLen(object)
if !ok {
return Fail(t, fmt.Sprintf("\"%v\" could not be applied builtin len()", object), msgAndArgs...)
}
if l != length {
return Fail(t, fmt.Sprintf("\"%v\" should have %d item(s), but has %d", object, length, l), msgAndArgs...)
}
return true
}
// True asserts that the specified value is true.
//
// assert.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if !value {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Should be true", msgAndArgs...)
}
return true
}
// False asserts that the specified value is false.
//
// assert.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if value {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "Should be false", msgAndArgs...)
}
return true
}
// NotEqual asserts that the specified values are NOT equal.
//
// assert.NotEqual(t, obj1, obj2)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
expected, actual, err), msgAndArgs...)
}
if ObjectsAreEqual(expected, actual) {
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
}
return true
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// assert.NotEqualValues(t, obj1, obj2)
func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if ObjectsAreEqualValues(expected, actual) {
return Fail(t, fmt.Sprintf("Should not be: %#v\n", actual), msgAndArgs...)
}
return true
}
// containsElement try loop over the list check if the list includes the element.
// return (false, false) if impossible.
// return (true, false) if element was not found.
// return (true, true) if element was found.
func containsElement(list interface{}, element interface{}) (ok, found bool) {
listValue := reflect.ValueOf(list)
listType := reflect.TypeOf(list)
if listType == nil {
return false, false
}
listKind := listType.Kind()
defer func() {
if e := recover(); e != nil {
ok = false
found = false
}
}()
if listKind == reflect.String {
elementValue := reflect.ValueOf(element)
return true, strings.Contains(listValue.String(), elementValue.String())
}
if listKind == reflect.Map {
mapKeys := listValue.MapKeys()
for i := 0; i < len(mapKeys); i++ {
if ObjectsAreEqual(mapKeys[i].Interface(), element) {
return true, true
}
}
return true, false
}
for i := 0; i < listValue.Len(); i++ {
if ObjectsAreEqual(listValue.Index(i).Interface(), element) {
return true, true
}
}
return true, false
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// assert.Contains(t, "Hello World", "World")
// assert.Contains(t, ["Hello", "World"], "World")
// assert.Contains(t, {"Hello": "World"}, "Hello")
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ok, found := containsElement(s, contains)
if !ok {
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
}
if !found {
return Fail(t, fmt.Sprintf("%#v does not contain %#v", s, contains), msgAndArgs...)
}
return true
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// assert.NotContains(t, "Hello World", "Earth")
// assert.NotContains(t, ["Hello", "World"], "Earth")
// assert.NotContains(t, {"Hello": "World"}, "Earth")
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ok, found := containsElement(s, contains)
if !ok {
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", s), msgAndArgs...)
}
if found {
return Fail(t, fmt.Sprintf("%#v should not contain %#v", s, contains), msgAndArgs...)
}
return true
}
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.Subset(t, [1, 2, 3], [1, 2])
// assert.Subset(t, {"x": 1, "y": 2}, {"x": 1})
// assert.Subset(t, [1, 2, 3], {1: "one", 2: "two"})
// assert.Subset(t, {"x": 1, "y": 2}, ["x"])
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if subset == nil {
return true // we consider nil to be equal to the nil set
}
listKind := reflect.TypeOf(list).Kind()
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
}
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
}
if subsetKind == reflect.Map && listKind == reflect.Map {
subsetMap := reflect.ValueOf(subset)
actualMap := reflect.ValueOf(list)
for _, k := range subsetMap.MapKeys() {
ev := subsetMap.MapIndex(k)
av := actualMap.MapIndex(k)
if !av.IsValid() {
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
}
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, subset), msgAndArgs...)
}
}
return true
}
subsetList := reflect.ValueOf(subset)
if subsetKind == reflect.Map {
keys := make([]interface{}, subsetList.Len())
for idx, key := range subsetList.MapKeys() {
keys[idx] = key.Interface()
}
subsetList = reflect.ValueOf(keys)
}
for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element)
if !ok {
return Fail(t, fmt.Sprintf("%#v could not be applied builtin len()", list), msgAndArgs...)
}
if !found {
return Fail(t, fmt.Sprintf("%#v does not contain %#v", list, element), msgAndArgs...)
}
}
return true
}
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// assert.NotSubset(t, [1, 3, 4], [1, 2])
// assert.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
// assert.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})
// assert.NotSubset(t, {"x": 1, "y": 2}, ["z"])
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if subset == nil {
return Fail(t, "nil is the empty set which is a subset of every set", msgAndArgs...)
}
listKind := reflect.TypeOf(list).Kind()
if listKind != reflect.Array && listKind != reflect.Slice && listKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", list, listKind), msgAndArgs...)
}
subsetKind := reflect.TypeOf(subset).Kind()
if subsetKind != reflect.Array && subsetKind != reflect.Slice && subsetKind != reflect.Map {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s", subset, subsetKind), msgAndArgs...)
}
if subsetKind == reflect.Map && listKind == reflect.Map {
subsetMap := reflect.ValueOf(subset)
actualMap := reflect.ValueOf(list)
for _, k := range subsetMap.MapKeys() {
ev := subsetMap.MapIndex(k)
av := actualMap.MapIndex(k)
if !av.IsValid() {
return true
}
if !ObjectsAreEqual(ev.Interface(), av.Interface()) {
return true
}
}
return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
}
subsetList := reflect.ValueOf(subset)
if subsetKind == reflect.Map {
keys := make([]interface{}, subsetList.Len())
for idx, key := range subsetList.MapKeys() {
keys[idx] = key.Interface()
}
subsetList = reflect.ValueOf(keys)
}
for i := 0; i < subsetList.Len(); i++ {
element := subsetList.Index(i).Interface()
ok, found := containsElement(list, element)
if !ok {
return Fail(t, fmt.Sprintf("%q could not be applied builtin len()", list), msgAndArgs...)
}
if !found {
return true
}
}
return Fail(t, fmt.Sprintf("%q is a subset of %q", subset, list), msgAndArgs...)
}
// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isEmpty(listA) && isEmpty(listB) {
return true
}
if !isList(t, listA, msgAndArgs...) || !isList(t, listB, msgAndArgs...) {
return false
}
extraA, extraB := diffLists(listA, listB)
if len(extraA) == 0 && len(extraB) == 0 {
return true
}
return Fail(t, formatListDiff(listA, listB, extraA, extraB), msgAndArgs...)
}
// isList checks that the provided value is array or slice.
func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok bool) {
kind := reflect.TypeOf(list).Kind()
if kind != reflect.Array && kind != reflect.Slice {
return Fail(t, fmt.Sprintf("%q has an unsupported type %s, expecting array or slice", list, kind),
msgAndArgs...)
}
return true
}
// diffLists diffs two arrays/slices and returns slices of elements that are only in A and only in B.
// If some element is present multiple times, each instance is counted separately (e.g. if something is 2x in A and
// 5x in B, it will be 0x in extraA and 3x in extraB). The order of items in both lists is ignored.
func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
aValue := reflect.ValueOf(listA)
bValue := reflect.ValueOf(listB)
aLen := aValue.Len()
bLen := bValue.Len()
// Mark indexes in bValue that we already used
visited := make([]bool, bLen)
for i := 0; i < aLen; i++ {
element := aValue.Index(i).Interface()
found := false
for j := 0; j < bLen; j++ {
if visited[j] {
continue
}
if ObjectsAreEqual(bValue.Index(j).Interface(), element) {
visited[j] = true
found = true
break
}
}
if !found {
extraA = append(extraA, element)
}
}
for j := 0; j < bLen; j++ {
if visited[j] {
continue
}
extraB = append(extraB, bValue.Index(j).Interface())
}
return
}
func formatListDiff(listA, listB interface{}, extraA, extraB []interface{}) string {
var msg bytes.Buffer
msg.WriteString("elements differ")
if len(extraA) > 0 {
msg.WriteString("\n\nextra elements in list A:\n")
msg.WriteString(spewConfig.Sdump(extraA))
}
if len(extraB) > 0 {
msg.WriteString("\n\nextra elements in list B:\n")
msg.WriteString(spewConfig.Sdump(extraB))
}
msg.WriteString("\n\nlistA:\n")
msg.WriteString(spewConfig.Sdump(listA))
msg.WriteString("\n\nlistB:\n")
msg.WriteString(spewConfig.Sdump(listB))
return msg.String()
}
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// assert.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
//
// assert.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
func NotElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isEmpty(listA) && isEmpty(listB) {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}
if !isList(t, listA, msgAndArgs...) {
return Fail(t, "listA is not a list type", msgAndArgs...)
}
if !isList(t, listB, msgAndArgs...) {
return Fail(t, "listB is not a list type", msgAndArgs...)
}
extraA, extraB := diffLists(listA, listB)
if len(extraA) == 0 && len(extraB) == 0 {
return Fail(t, "listA and listB contain the same elements", msgAndArgs)
}
return true
}
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
result := comp()
if !result {
Fail(t, "Condition failed!", msgAndArgs...)
}
return result
}
// PanicTestFunc defines a func that should be passed to the assert.Panics and assert.NotPanics
// methods, and represents a simple func that takes no arguments, and returns nothing.
type PanicTestFunc func()
// didPanic returns true if the function passed to it panics. Otherwise, it returns false.
func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stack string) {
didPanic = true
defer func() {
message = recover()
if didPanic {
stack = string(debug.Stack())
}
}()
// call the target function
f()
didPanic = false
return
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// assert.Panics(t, func(){ GoCrazy() })
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if funcDidPanic, panicValue, _ := didPanic(f); !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
}
return true
}
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
funcDidPanic, panicValue, panickedStack := didPanic(f)
if !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
}
if panicValue != expected {
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, expected, panicValue, panickedStack), msgAndArgs...)
}
return true
}
// PanicsWithError asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
funcDidPanic, panicValue, panickedStack := didPanic(f)
if !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
}
panicErr, ok := panicValue.(error)
if !ok || panicErr.Error() != errString {
return Fail(t, fmt.Sprintf("func %#v should panic with error message:\t%#v\n\tPanic value:\t%#v\n\tPanic stack:\t%s", f, errString, panicValue, panickedStack), msgAndArgs...)
}
return true
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// assert.NotPanics(t, func(){ RemainCalm() })
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if funcDidPanic, panicValue, panickedStack := didPanic(f); funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v\n\tPanic stack:\t%s", f, panicValue, panickedStack), msgAndArgs...)
}
return true
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
dt := expected.Sub(actual)
if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
}
return true
}
// WithinRange asserts that a time is within a time range (inclusive).
//
// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if end.Before(start) {
return Fail(t, "Start should be before end", msgAndArgs...)
}
if actual.Before(start) {
return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is before the range", actual, start, end), msgAndArgs...)
} else if actual.After(end) {
return Fail(t, fmt.Sprintf("Time %v expected to be in time range %v to %v, but is after the range", actual, start, end), msgAndArgs...)
}
return true
}
func toFloat(x interface{}) (float64, bool) {
var xf float64
xok := true
switch xn := x.(type) {
case uint:
xf = float64(xn)
case uint8:
xf = float64(xn)
case uint16:
xf = float64(xn)
case uint32:
xf = float64(xn)
case uint64:
xf = float64(xn)
case int:
xf = float64(xn)
case int8:
xf = float64(xn)
case int16:
xf = float64(xn)
case int32:
xf = float64(xn)
case int64:
xf = float64(xn)
case float32:
xf = float64(xn)
case float64:
xf = xn
case time.Duration:
xf = float64(xn)
default:
xok = false
}
return xf, xok
}
// InDelta asserts that the two numerals are within delta of each other.
//
// assert.InDelta(t, math.Pi, 22/7.0, 0.01)
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
if !aok || !bok {
return Fail(t, "Parameters must be numerical", msgAndArgs...)
}
if math.IsNaN(af) && math.IsNaN(bf) {
return true
}
if math.IsNaN(af) {
return Fail(t, "Expected must not be NaN", msgAndArgs...)
}
if math.IsNaN(bf) {
return Fail(t, fmt.Sprintf("Expected %v with delta %v, but was NaN", expected, delta), msgAndArgs...)
}
dt := af - bf
if dt < -delta || dt > delta {
return Fail(t, fmt.Sprintf("Max difference between %v and %v allowed is %v, but difference was %v", expected, actual, delta, dt), msgAndArgs...)
}
return true
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice {
return Fail(t, "Parameters must be slice", msgAndArgs...)
}
actualSlice := reflect.ValueOf(actual)
expectedSlice := reflect.ValueOf(expected)
for i := 0; i < actualSlice.Len(); i++ {
result := InDelta(t, actualSlice.Index(i).Interface(), expectedSlice.Index(i).Interface(), delta, msgAndArgs...)
if !result {
return result
}
}
return true
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Map ||
reflect.TypeOf(expected).Kind() != reflect.Map {
return Fail(t, "Arguments must be maps", msgAndArgs...)
}
expectedMap := reflect.ValueOf(expected)
actualMap := reflect.ValueOf(actual)
if expectedMap.Len() != actualMap.Len() {
return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
}
for _, k := range expectedMap.MapKeys() {
ev := expectedMap.MapIndex(k)
av := actualMap.MapIndex(k)
if !ev.IsValid() {
return Fail(t, fmt.Sprintf("missing key %q in expected map", k), msgAndArgs...)
}
if !av.IsValid() {
return Fail(t, fmt.Sprintf("missing key %q in actual map", k), msgAndArgs...)
}
if !InDelta(
t,
ev.Interface(),
av.Interface(),
delta,
msgAndArgs...,
) {
return false
}
}
return true
}
func calcRelativeError(expected, actual interface{}) (float64, error) {
af, aok := toFloat(expected)
bf, bok := toFloat(actual)
if !aok || !bok {
return 0, fmt.Errorf("Parameters must be numerical")
}
if math.IsNaN(af) && math.IsNaN(bf) {
return 0, nil
}
if math.IsNaN(af) {
return 0, errors.New("expected value must not be NaN")
}
if af == 0 {
return 0, fmt.Errorf("expected value must have a value other than zero to calculate the relative error")
}
if math.IsNaN(bf) {
return 0, errors.New("actual value must not be NaN")
}
return math.Abs(af-bf) / math.Abs(af), nil
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if math.IsNaN(epsilon) {
return Fail(t, "epsilon must not be NaN", msgAndArgs...)
}
actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil {
return Fail(t, err.Error(), msgAndArgs...)
}
if math.IsNaN(actualEpsilon) {
return Fail(t, "relative error is NaN", msgAndArgs...)
}
if actualEpsilon > epsilon {
return Fail(t, fmt.Sprintf("Relative error is too high: %#v (expected)\n"+
" < %#v (actual)", epsilon, actualEpsilon), msgAndArgs...)
}
return true
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil {
return Fail(t, "Parameters must be slice", msgAndArgs...)
}
expectedSlice := reflect.ValueOf(expected)
actualSlice := reflect.ValueOf(actual)
if expectedSlice.Type().Kind() != reflect.Slice {
return Fail(t, "Expected value must be slice", msgAndArgs...)
}
expectedLen := expectedSlice.Len()
if !IsType(t, expected, actual) || !Len(t, actual, expectedLen) {
return false
}
for i := 0; i < expectedLen; i++ {
if !InEpsilon(t, expectedSlice.Index(i).Interface(), actualSlice.Index(i).Interface(), epsilon, "at index %d", i) {
return false
}
}
return true
}
/*
Errors
*/
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if assert.NoError(t, err) {
// assert.Equal(t, expectedObj, actualObj)
// }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
if err != nil {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
}
return true
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// assert.Error(t, err)
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
if err == nil {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, "An error is expected but got nil.", msgAndArgs...)
}
return true
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString)
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !Error(t, theError, msgAndArgs...) {
return false
}
expected := errString
actual := theError.Error()
// don't need to use deep equals here, we know they are both strings
if expected != actual {
return Fail(t, fmt.Sprintf("Error message not equal:\n"+
"expected: %q\n"+
"actual : %q", expected, actual), msgAndArgs...)
}
return true
}
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// assert.ErrorContains(t, err, expectedErrorSubString)
func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !Error(t, theError, msgAndArgs...) {
return false
}
actual := theError.Error()
if !strings.Contains(actual, contains) {
return Fail(t, fmt.Sprintf("Error %#v does not contain %#v", actual, contains), msgAndArgs...)
}
return true
}
// matchRegexp return true if a specified regexp matches a string.
func matchRegexp(rx interface{}, str interface{}) bool {
var r *regexp.Regexp
if rr, ok := rx.(*regexp.Regexp); ok {
r = rr
} else {
r = regexp.MustCompile(fmt.Sprint(rx))
}
switch v := str.(type) {
case []byte:
return r.Match(v)
case string:
return r.MatchString(v)
default:
return r.MatchString(fmt.Sprint(v))
}
}
// Regexp asserts that a specified regexp matches a string.
//
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
match := matchRegexp(rx, str)
if !match {
Fail(t, fmt.Sprintf("Expect \"%v\" to match \"%v\"", str, rx), msgAndArgs...)
}
return match
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
match := matchRegexp(rx, str)
if match {
Fail(t, fmt.Sprintf("Expect \"%v\" to NOT match \"%v\"", str, rx), msgAndArgs...)
}
return !match
}
// Zero asserts that i is the zero value for its type.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
}
return true
}
// NotZero asserts that i is not the zero value for its type.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
}
return true
}
// FileExists checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
}
return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
}
if info.IsDir() {
return Fail(t, fmt.Sprintf("%q is a directory", path), msgAndArgs...)
}
return true
}
// NoFileExists checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path)
if err != nil {
return true
}
if info.IsDir() {
return true
}
return Fail(t, fmt.Sprintf("file %q exists", path), msgAndArgs...)
}
// DirExists checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
return Fail(t, fmt.Sprintf("unable to find file %q", path), msgAndArgs...)
}
return Fail(t, fmt.Sprintf("error when running os.Lstat(%q): %s", path, err), msgAndArgs...)
}
if !info.IsDir() {
return Fail(t, fmt.Sprintf("%q is a file", path), msgAndArgs...)
}
return true
}
// NoDirExists checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path)
if err != nil {
if os.IsNotExist(err) {
return true
}
return true
}
if !info.IsDir() {
return true
}
return Fail(t, fmt.Sprintf("directory %q exists", path), msgAndArgs...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var expectedJSONAsInterface, actualJSONAsInterface interface{}
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid json.\nJSON parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
// Shortcut if same bytes
if actual == expected {
return true
}
if err := json.Unmarshal([]byte(actual), &actualJSONAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid json.\nJSON parsing error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedJSONAsInterface, actualJSONAsInterface, msgAndArgs...)
}
// YAMLEq asserts that two YAML strings are equivalent.
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var expectedYAMLAsInterface, actualYAMLAsInterface interface{}
if err := yaml.Unmarshal([]byte(expected), &expectedYAMLAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Expected value ('%s') is not valid yaml.\nYAML parsing error: '%s'", expected, err.Error()), msgAndArgs...)
}
// Shortcut if same bytes
if actual == expected {
return true
}
if err := yaml.Unmarshal([]byte(actual), &actualYAMLAsInterface); err != nil {
return Fail(t, fmt.Sprintf("Input ('%s') needs to be valid yaml.\nYAML error: '%s'", actual, err.Error()), msgAndArgs...)
}
return Equal(t, expectedYAMLAsInterface, actualYAMLAsInterface, msgAndArgs...)
}
func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
t := reflect.TypeOf(v)
k := t.Kind()
if k == reflect.Ptr {
t = t.Elem()
k = t.Kind()
}
return t, k
}
// diff returns a diff of both values as long as both are of the same type and
// are a struct, map, slice, array or string. Otherwise it returns an empty string.
func diff(expected interface{}, actual interface{}) string {
if expected == nil || actual == nil {
return ""
}
et, ek := typeAndKind(expected)
at, _ := typeAndKind(actual)
if et != at {
return ""
}
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
return ""
}
var e, a string
switch et {
case reflect.TypeOf(""):
e = reflect.ValueOf(expected).String()
a = reflect.ValueOf(actual).String()
case reflect.TypeOf(time.Time{}):
e = spewConfigStringerEnabled.Sdump(expected)
a = spewConfigStringerEnabled.Sdump(actual)
default:
e = spewConfig.Sdump(expected)
a = spewConfig.Sdump(actual)
}
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e),
B: difflib.SplitLines(a),
FromFile: "Expected",
FromDate: "",
ToFile: "Actual",
ToDate: "",
Context: 1,
})
return "\n\nDiff:\n" + diff
}
func isFunction(arg interface{}) bool {
if arg == nil {
return false
}
return reflect.TypeOf(arg).Kind() == reflect.Func
}
var spewConfig = spew.ConfigState{
Indent: " ",
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
DisableMethods: true,
MaxDepth: 10,
}
var spewConfigStringerEnabled = spew.ConfigState{
Indent: " ",
DisablePointerAddresses: true,
DisableCapacities: true,
SortKeys: true,
MaxDepth: 10,
}
type tHelper = interface {
Helper()
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ch := make(chan bool, 1)
checkCond := func() { ch <- condition() }
timer := time.NewTimer(waitFor)
defer timer.Stop()
ticker := time.NewTicker(tick)
defer ticker.Stop()
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tickC:
tickC = nil
go checkCond()
case v := <-ch:
if v {
return true
}
tickC = ticker.C
}
}
}
// CollectT implements the TestingT interface and collects all errors.
type CollectT struct {
// A slice of errors. Non-nil slice denotes a failure.
// If it's non-nil but len(c.errors) == 0, this is also a failure
// obtained by direct c.FailNow() call.
errors []error
}
// Helper is like [testing.T.Helper] but does nothing.
func (CollectT) Helper() {}
// Errorf collects the error.
func (c *CollectT) Errorf(format string, args ...interface{}) {
c.errors = append(c.errors, fmt.Errorf(format, args...))
}
// FailNow stops execution by calling runtime.Goexit.
func (c *CollectT) FailNow() {
c.fail()
runtime.Goexit()
}
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
func (*CollectT) Reset() {
panic("Reset() is deprecated")
}
// Deprecated: That was a method for internal usage that should not have been published. Now just panics.
func (*CollectT) Copy(TestingT) {
panic("Copy() is deprecated")
}
func (c *CollectT) fail() {
if !c.failed() {
c.errors = []error{} // Make it non-nil to mark a failure.
}
}
func (c *CollectT) failed() bool {
return c.errors != nil
}
// EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// assert.EventuallyWithT(t, func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithT(t TestingT, condition func(collect *CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var lastFinishedTickErrs []error
ch := make(chan *CollectT, 1)
checkCond := func() {
collect := new(CollectT)
defer func() {
ch <- collect
}()
condition(collect)
}
timer := time.NewTimer(waitFor)
defer timer.Stop()
ticker := time.NewTicker(tick)
defer ticker.Stop()
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
for _, err := range lastFinishedTickErrs {
t.Errorf("%v", err)
}
return Fail(t, "Condition never satisfied", msgAndArgs...)
case <-tickC:
tickC = nil
go checkCond()
case collect := <-ch:
if !collect.failed() {
return true
}
// Keep the errors from the last ended condition, so that they can be copied to t if timeout is reached.
lastFinishedTickErrs = collect.errors
tickC = ticker.C
}
}
}
// Never asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ch := make(chan bool, 1)
checkCond := func() { ch <- condition() }
timer := time.NewTimer(waitFor)
defer timer.Stop()
ticker := time.NewTicker(tick)
defer ticker.Stop()
var tickC <-chan time.Time
// Check the condition once first on the initial call.
go checkCond()
for {
select {
case <-timer.C:
return true
case <-tickC:
tickC = nil
go checkCond()
case v := <-ch:
if v {
return Fail(t, "Condition satisfied", msgAndArgs...)
}
tickC = ticker.C
}
}
}
// ErrorIs asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if errors.Is(err, target) {
return true
}
var expectedText string
if target != nil {
expectedText = target.Error()
if err == nil {
return Fail(t, fmt.Sprintf("Expected error with %q in chain but got nil.", expectedText), msgAndArgs...)
}
}
chain := buildErrorChainString(err, false)
return Fail(t, fmt.Sprintf("Target error should be in err chain:\n"+
"expected: %q\n"+
"in chain: %s", expectedText, chain,
), msgAndArgs...)
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !errors.Is(err, target) {
return true
}
var expectedText string
if target != nil {
expectedText = target.Error()
}
chain := buildErrorChainString(err, false)
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
"found: %q\n"+
"in chain: %s", expectedText, chain,
), msgAndArgs...)
}
// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if errors.As(err, target) {
return true
}
expectedType := reflect.TypeOf(target).Elem().String()
if err == nil {
return Fail(t, fmt.Sprintf("An error is expected but got nil.\n"+
"expected: %s", expectedType), msgAndArgs...)
}
chain := buildErrorChainString(err, true)
return Fail(t, fmt.Sprintf("Should be in error chain:\n"+
"expected: %s\n"+
"in chain: %s", expectedType, chain,
), msgAndArgs...)
}
// NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !errors.As(err, target) {
return true
}
chain := buildErrorChainString(err, true)
return Fail(t, fmt.Sprintf("Target error should not be in err chain:\n"+
"found: %s\n"+
"in chain: %s", reflect.TypeOf(target).Elem().String(), chain,
), msgAndArgs...)
}
func unwrapAll(err error) (errs []error) {
errs = append(errs, err)
switch x := err.(type) {
case interface{ Unwrap() error }:
err = x.Unwrap()
if err == nil {
return
}
errs = append(errs, unwrapAll(err)...)
case interface{ Unwrap() []error }:
for _, err := range x.Unwrap() {
errs = append(errs, unwrapAll(err)...)
}
}
return
}
func buildErrorChainString(err error, withType bool) string {
if err == nil {
return ""
}
var chain string
errs := unwrapAll(err)
for i := range errs {
if i != 0 {
chain += "\n\t"
}
chain += fmt.Sprintf("%q", errs[i].Error())
if withType {
chain += fmt.Sprintf(" (%T)", errs[i])
}
}
return chain
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/doc.go
================================================
// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.
//
// # Note
//
// All functions in this package return a bool value indicating whether the assertion has passed.
//
// # Example Usage
//
// The following is a complete example using assert in a standard test function:
//
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
//
// func TestSomething(t *testing.T) {
//
// var a string = "Hello"
// var b string = "Hello"
//
// assert.Equal(t, a, b, "The two words should be the same.")
//
// }
//
// if you assert many times, use the format below:
//
// import (
// "testing"
// "github.com/stretchr/testify/assert"
// )
//
// func TestSomething(t *testing.T) {
// assert := assert.New(t)
//
// var a string = "Hello"
// var b string = "Hello"
//
// assert.Equal(a, b, "The two words should be the same.")
// }
//
// # Assertions
//
// Assertions allow you to easily write test code, and are global funcs in the `assert` package.
// All assertion functions take, as the first argument, the `*testing.T` object provided by the
// testing framework. This allows the assertion funcs to write the failings and other details to
// the correct place.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
package assert
================================================
FILE: vendor/github.com/stretchr/testify/assert/errors.go
================================================
package assert
import (
"errors"
)
// AnError is an error instance useful for testing. If the code does not care
// about error specifics, and only needs to return the error for example, this
// error should be used to make the test code more readable.
var AnError = errors.New("assert.AnError general error for testing")
================================================
FILE: vendor/github.com/stretchr/testify/assert/forward_assertions.go
================================================
package assert
// Assertions provides assertion methods around the
// TestingT interface.
type Assertions struct {
t TestingT
}
// New makes a new Assertions object for the specified TestingT.
func New(t TestingT) *Assertions {
return &Assertions{
t: t,
}
}
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs"
================================================
FILE: vendor/github.com/stretchr/testify/assert/http_assertions.go
================================================
package assert
import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strings"
)
// httpCode is a helper that returns HTTP code of the response. It returns -1 and
// an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder()
req, err := http.NewRequest(method, url, http.NoBody)
if err != nil {
return -1, err
}
req.URL.RawQuery = values.Encode()
handler(w, req)
return w.Code, nil
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent
if !isSuccessCode {
Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isSuccessCode
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect
if !isRedirectCode {
Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isRedirectCode
}
// HTTPError asserts that a specified handler returns an error status code.
//
// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
isErrorCode := code >= http.StatusBadRequest
if !isErrorCode {
Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...)
}
return isErrorCode
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values)
if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...)
}
successful := code == statuscode
if !successful {
Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...)
}
return successful
}
// HTTPBody is a helper that returns HTTP body of the response. It returns
// empty string if building a new request fails.
func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string {
w := httptest.NewRecorder()
if len(values) > 0 {
url += "?" + values.Encode()
}
req, err := http.NewRequest(method, url, http.NoBody)
if err != nil {
return ""
}
handler(w, req)
return w.Body.String()
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
if !contains {
Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
}
return contains
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str))
if contains {
Fail(t, fmt.Sprintf("Expected response body for %q to NOT contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...)
}
return !contains
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go
================================================
//go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default
// Package yaml is an implementation of YAML functions that calls a pluggable implementation.
//
// This implementation is selected with the testify_yaml_custom build tag.
//
// go test -tags testify_yaml_custom
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3].
//
// In your test package:
//
// import assertYaml "github.com/stretchr/testify/assert/yaml"
//
// func init() {
// assertYaml.Unmarshal = func (in []byte, out interface{}) error {
// // ...
// return nil
// }
// }
package yaml
var Unmarshal func(in []byte, out interface{}) error
================================================
FILE: vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go
================================================
//go:build !testify_yaml_fail && !testify_yaml_custom
// Package yaml is just an indirection to handle YAML deserialization.
//
// This package is just an indirection that allows the builder to override the
// indirection with an alternative implementation of this package that uses
// another implementation of YAML deserialization. This allows to not either not
// use YAML deserialization at all, or to use another implementation than
// [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]).
//
// Alternative implementations are selected using build tags:
//
// - testify_yaml_fail: [Unmarshal] always fails with an error
// - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it
// before calling any of [github.com/stretchr/testify/assert.YAMLEq] or
// [github.com/stretchr/testify/assert.YAMLEqf].
//
// Usage:
//
// go test -tags testify_yaml_fail
//
// You can check with "go list" which implementation is linked:
//
// go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
// go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml
//
// [PR #1120]: https://github.com/stretchr/testify/pull/1120
package yaml
import goyaml "gopkg.in/yaml.v3"
// Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal].
func Unmarshal(in []byte, out interface{}) error {
return goyaml.Unmarshal(in, out)
}
================================================
FILE: vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go
================================================
//go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default
// Package yaml is an implementation of YAML functions that always fail.
//
// This implementation can be used at build time to replace the default implementation
// to avoid linking with [gopkg.in/yaml.v3]:
//
// go test -tags testify_yaml_fail
package yaml
import "errors"
var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)")
func Unmarshal([]byte, interface{}) error {
return errNotImplemented
}
================================================
FILE: vendor/github.com/stretchr/testify/require/doc.go
================================================
// Package require implements the same assertions as the `assert` package but
// stops test execution when a test fails.
//
// # Example Usage
//
// The following is a complete example using require in a standard test function:
//
// import (
// "testing"
// "github.com/stretchr/testify/require"
// )
//
// func TestSomething(t *testing.T) {
//
// var a string = "Hello"
// var b string = "Hello"
//
// require.Equal(t, a, b, "The two words should be the same.")
//
// }
//
// # Assertions
//
// The `require` package have same global functions as in the `assert` package,
// but instead of returning a boolean result they call `t.FailNow()`.
// A consequence of this is that it must be called from the goroutine running
// the test function, not from other goroutines created during the test.
//
// Every assertion function also takes an optional string message as the final argument,
// allowing custom error messages to be appended to the message the assertion method outputs.
package require
================================================
FILE: vendor/github.com/stretchr/testify/require/forward_requirements.go
================================================
package require
// Assertions provides assertion methods around the
// TestingT interface.
type Assertions struct {
t TestingT
}
// New makes a new Assertions object for the specified TestingT.
func New(t TestingT) *Assertions {
return &Assertions{
t: t,
}
}
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs"
================================================
FILE: vendor/github.com/stretchr/testify/require/require.go
================================================
// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
package require
import (
assert "github.com/stretchr/testify/assert"
http "net/http"
url "net/url"
time "time"
)
// Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Condition(t, comp, msgAndArgs...) {
return
}
t.FailNow()
}
// Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Conditionf(t, comp, msg, args...) {
return
}
t.FailNow()
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// require.Contains(t, "Hello World", "World")
// require.Contains(t, ["Hello", "World"], "World")
// require.Contains(t, {"Hello": "World"}, "Hello")
func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Contains(t, s, contains, msgAndArgs...) {
return
}
t.FailNow()
}
// Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// require.Containsf(t, "Hello World", "World", "error message %s", "formatted")
// require.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// require.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Containsf(t, s, contains, msg, args...) {
return
}
t.FailNow()
}
// DirExists checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.DirExists(t, path, msgAndArgs...) {
return
}
t.FailNow()
}
// DirExistsf checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.DirExistsf(t, path, msg, args...) {
return
}
t.FailNow()
}
// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// require.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ElementsMatch(t, listA, listB, msgAndArgs...) {
return
}
t.FailNow()
}
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// require.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ElementsMatchf(t, listA, listB, msg, args...) {
return
}
t.FailNow()
}
// Empty asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// require.Empty(t, obj)
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Empty(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// Emptyf asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// require.Emptyf(t, obj, "error message %s", "formatted")
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Emptyf(t, object, msg, args...) {
return
}
t.FailNow()
}
// Equal asserts that two objects are equal.
//
// require.Equal(t, 123, 123)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Equal(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// require.EqualError(t, err, expectedErrorString)
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualError(t, theError, errString, msgAndArgs...) {
return
}
t.FailNow()
}
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// require.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualErrorf(t, theError, errString, msg, args...) {
return
}
t.FailNow()
}
// EqualExportedValues asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// require.EqualExportedValues(t, S{1, 2}, S{1, 3}) => true
// require.EqualExportedValues(t, S{1, 2}, S{2, 3}) => false
func EqualExportedValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualExportedValues(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// EqualExportedValuesf asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// require.EqualExportedValuesf(t, S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
// require.EqualExportedValuesf(t, S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
func EqualExportedValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualExportedValuesf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// require.EqualValues(t, uint32(123), int32(123))
func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualValues(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// require.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted")
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EqualValuesf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Equalf asserts that two objects are equal.
//
// require.Equalf(t, 123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Equalf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// require.Error(t, err)
func Error(t TestingT, err error, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Error(t, err, msgAndArgs...) {
return
}
t.FailNow()
}
// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorAs(t, err, target, msgAndArgs...) {
return
}
t.FailNow()
}
// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorAsf(t, err, target, msg, args...) {
return
}
t.FailNow()
}
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// require.ErrorContains(t, err, expectedErrorSubString)
func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorContains(t, theError, contains, msgAndArgs...) {
return
}
t.FailNow()
}
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// require.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted")
func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorContainsf(t, theError, contains, msg, args...) {
return
}
t.FailNow()
}
// ErrorIs asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorIs(t, err, target, msgAndArgs...) {
return
}
t.FailNow()
}
// ErrorIsf asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.ErrorIsf(t, err, target, msg, args...) {
return
}
t.FailNow()
}
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// require.Errorf(t, err, "error message %s", "formatted")
func Errorf(t TestingT, err error, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Errorf(t, err, msg, args...) {
return
}
t.FailNow()
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// require.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond)
func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) {
return
}
t.FailNow()
}
// EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// require.EventuallyWithT(t, func(c *require.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// require.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EventuallyWithT(t, condition, waitFor, tick, msgAndArgs...) {
return
}
t.FailNow()
}
// EventuallyWithTf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// require.EventuallyWithTf(t, func(c *require.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// require.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func EventuallyWithTf(t TestingT, condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.EventuallyWithTf(t, condition, waitFor, tick, msg, args...) {
return
}
t.FailNow()
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// require.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) {
return
}
t.FailNow()
}
// Exactly asserts that two objects are equal in value and type.
//
// require.Exactly(t, int32(123), int64(123))
func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Exactly(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// Exactlyf asserts that two objects are equal in value and type.
//
// require.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted")
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Exactlyf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Fail(t, failureMessage, msgAndArgs...) {
return
}
t.FailNow()
}
// FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.FailNow(t, failureMessage, msgAndArgs...) {
return
}
t.FailNow()
}
// FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.FailNowf(t, failureMessage, msg, args...) {
return
}
t.FailNow()
}
// Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Failf(t, failureMessage, msg, args...) {
return
}
t.FailNow()
}
// False asserts that the specified value is false.
//
// require.False(t, myBool)
func False(t TestingT, value bool, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.False(t, value, msgAndArgs...) {
return
}
t.FailNow()
}
// Falsef asserts that the specified value is false.
//
// require.Falsef(t, myBool, "error message %s", "formatted")
func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Falsef(t, value, msg, args...) {
return
}
t.FailNow()
}
// FileExists checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.FileExists(t, path, msgAndArgs...) {
return
}
t.FailNow()
}
// FileExistsf checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.FileExistsf(t, path, msg, args...) {
return
}
t.FailNow()
}
// Greater asserts that the first element is greater than the second
//
// require.Greater(t, 2, 1)
// require.Greater(t, float64(2), float64(1))
// require.Greater(t, "b", "a")
func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Greater(t, e1, e2, msgAndArgs...) {
return
}
t.FailNow()
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// require.GreaterOrEqual(t, 2, 1)
// require.GreaterOrEqual(t, 2, 2)
// require.GreaterOrEqual(t, "b", "a")
// require.GreaterOrEqual(t, "b", "b")
func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) {
return
}
t.FailNow()
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// require.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted")
// require.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted")
// require.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted")
// require.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted")
func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.GreaterOrEqualf(t, e1, e2, msg, args...) {
return
}
t.FailNow()
}
// Greaterf asserts that the first element is greater than the second
//
// require.Greaterf(t, 2, 1, "error message %s", "formatted")
// require.Greaterf(t, float64(2), float64(1), "error message %s", "formatted")
// require.Greaterf(t, "b", "a", "error message %s", "formatted")
func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Greaterf(t, e1, e2, msg, args...) {
return
}
t.FailNow()
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// require.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
// require.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) {
return
}
t.FailNow()
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// require.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
// require.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) {
return
}
t.FailNow()
}
// HTTPError asserts that a specified handler returns an error status code.
//
// require.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPErrorf asserts that a specified handler returns an error status code.
//
// require.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) {
return
}
t.FailNow()
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// require.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
//
// require.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) {
return
}
t.FailNow()
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// require.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// require.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) {
return
}
t.FailNow()
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// require.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) {
return
}
t.FailNow()
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// require.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) {
return
}
t.FailNow()
}
// Implements asserts that an object is implemented by the specified interface.
//
// require.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Implements(t, interfaceObject, object, msgAndArgs...) {
return
}
t.FailNow()
}
// Implementsf asserts that an object is implemented by the specified interface.
//
// require.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Implementsf(t, interfaceObject, object, msg, args...) {
return
}
t.FailNow()
}
// InDelta asserts that the two numerals are within delta of each other.
//
// require.InDelta(t, math.Pi, 22/7.0, 0.01)
func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDelta(t, expected, actual, delta, msgAndArgs...) {
return
}
t.FailNow()
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValues(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) {
return
}
t.FailNow()
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) {
return
}
t.FailNow()
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) {
return
}
t.FailNow()
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) {
return
}
t.FailNow()
}
// InDeltaf asserts that the two numerals are within delta of each other.
//
// require.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InDeltaf(t, expected, actual, delta, msg, args...) {
return
}
t.FailNow()
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) {
return
}
t.FailNow()
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) {
return
}
t.FailNow()
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) {
return
}
t.FailNow()
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) {
return
}
t.FailNow()
}
// IsDecreasing asserts that the collection is decreasing
//
// require.IsDecreasing(t, []int{2, 1, 0})
// require.IsDecreasing(t, []float{2, 1})
// require.IsDecreasing(t, []string{"b", "a"})
func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsDecreasing(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsDecreasingf asserts that the collection is decreasing
//
// require.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted")
// require.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted")
// require.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsDecreasingf(t, object, msg, args...) {
return
}
t.FailNow()
}
// IsIncreasing asserts that the collection is increasing
//
// require.IsIncreasing(t, []int{1, 2, 3})
// require.IsIncreasing(t, []float{1, 2})
// require.IsIncreasing(t, []string{"a", "b"})
func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsIncreasing(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsIncreasingf asserts that the collection is increasing
//
// require.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted")
// require.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted")
// require.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsIncreasingf(t, object, msg, args...) {
return
}
t.FailNow()
}
// IsNonDecreasing asserts that the collection is not decreasing
//
// require.IsNonDecreasing(t, []int{1, 1, 2})
// require.IsNonDecreasing(t, []float{1, 2})
// require.IsNonDecreasing(t, []string{"a", "b"})
func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNonDecreasing(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsNonDecreasingf asserts that the collection is not decreasing
//
// require.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted")
// require.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted")
// require.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted")
func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNonDecreasingf(t, object, msg, args...) {
return
}
t.FailNow()
}
// IsNonIncreasing asserts that the collection is not increasing
//
// require.IsNonIncreasing(t, []int{2, 1, 1})
// require.IsNonIncreasing(t, []float{2, 1})
// require.IsNonIncreasing(t, []string{"b", "a"})
func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNonIncreasing(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsNonIncreasingf asserts that the collection is not increasing
//
// require.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted")
// require.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted")
// require.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted")
func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNonIncreasingf(t, object, msg, args...) {
return
}
t.FailNow()
}
// IsNotType asserts that the specified objects are not of the same type.
//
// require.IsNotType(t, &NotMyStruct{}, &MyStruct{})
func IsNotType(t TestingT, theType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNotType(t, theType, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// require.IsNotTypef(t, &NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsNotTypef(t TestingT, theType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsNotTypef(t, theType, object, msg, args...) {
return
}
t.FailNow()
}
// IsType asserts that the specified objects are of the same type.
//
// require.IsType(t, &MyStruct{}, &MyStruct{})
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsType(t, expectedType, object, msgAndArgs...) {
return
}
t.FailNow()
}
// IsTypef asserts that the specified objects are of the same type.
//
// require.IsTypef(t, &MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.IsTypef(t, expectedType, object, msg, args...) {
return
}
t.FailNow()
}
// JSONEq asserts that two JSON strings are equivalent.
//
// require.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.JSONEq(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// JSONEqf asserts that two JSON strings are equivalent.
//
// require.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.JSONEqf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// require.Len(t, mySlice, 3)
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Len(t, object, length, msgAndArgs...) {
return
}
t.FailNow()
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// require.Lenf(t, mySlice, 3, "error message %s", "formatted")
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Lenf(t, object, length, msg, args...) {
return
}
t.FailNow()
}
// Less asserts that the first element is less than the second
//
// require.Less(t, 1, 2)
// require.Less(t, float64(1), float64(2))
// require.Less(t, "a", "b")
func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Less(t, e1, e2, msgAndArgs...) {
return
}
t.FailNow()
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// require.LessOrEqual(t, 1, 2)
// require.LessOrEqual(t, 2, 2)
// require.LessOrEqual(t, "a", "b")
// require.LessOrEqual(t, "b", "b")
func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.LessOrEqual(t, e1, e2, msgAndArgs...) {
return
}
t.FailNow()
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// require.LessOrEqualf(t, 1, 2, "error message %s", "formatted")
// require.LessOrEqualf(t, 2, 2, "error message %s", "formatted")
// require.LessOrEqualf(t, "a", "b", "error message %s", "formatted")
// require.LessOrEqualf(t, "b", "b", "error message %s", "formatted")
func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.LessOrEqualf(t, e1, e2, msg, args...) {
return
}
t.FailNow()
}
// Lessf asserts that the first element is less than the second
//
// require.Lessf(t, 1, 2, "error message %s", "formatted")
// require.Lessf(t, float64(1), float64(2), "error message %s", "formatted")
// require.Lessf(t, "a", "b", "error message %s", "formatted")
func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Lessf(t, e1, e2, msg, args...) {
return
}
t.FailNow()
}
// Negative asserts that the specified element is negative
//
// require.Negative(t, -1)
// require.Negative(t, -1.23)
func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Negative(t, e, msgAndArgs...) {
return
}
t.FailNow()
}
// Negativef asserts that the specified element is negative
//
// require.Negativef(t, -1, "error message %s", "formatted")
// require.Negativef(t, -1.23, "error message %s", "formatted")
func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Negativef(t, e, msg, args...) {
return
}
t.FailNow()
}
// Never asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// require.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond)
func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Never(t, condition, waitFor, tick, msgAndArgs...) {
return
}
t.FailNow()
}
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// require.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Neverf(t, condition, waitFor, tick, msg, args...) {
return
}
t.FailNow()
}
// Nil asserts that the specified object is nil.
//
// require.Nil(t, err)
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Nil(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// Nilf asserts that the specified object is nil.
//
// require.Nilf(t, err, "error message %s", "formatted")
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Nilf(t, object, msg, args...) {
return
}
t.FailNow()
}
// NoDirExists checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoDirExists(t, path, msgAndArgs...) {
return
}
t.FailNow()
}
// NoDirExistsf checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoDirExistsf(t, path, msg, args...) {
return
}
t.FailNow()
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if require.NoError(t, err) {
// require.Equal(t, expectedObj, actualObj)
// }
func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoError(t, err, msgAndArgs...) {
return
}
t.FailNow()
}
// NoErrorf asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if require.NoErrorf(t, err, "error message %s", "formatted") {
// require.Equal(t, expectedObj, actualObj)
// }
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoErrorf(t, err, msg, args...) {
return
}
t.FailNow()
}
// NoFileExists checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoFileExists(t, path, msgAndArgs...) {
return
}
t.FailNow()
}
// NoFileExistsf checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NoFileExistsf(t, path, msg, args...) {
return
}
t.FailNow()
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// require.NotContains(t, "Hello World", "Earth")
// require.NotContains(t, ["Hello", "World"], "Earth")
// require.NotContains(t, {"Hello": "World"}, "Earth")
func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotContains(t, s, contains, msgAndArgs...) {
return
}
t.FailNow()
}
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// require.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
// require.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// require.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotContainsf(t, s, contains, msg, args...) {
return
}
t.FailNow()
}
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// require.NotElementsMatch(t, [1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// require.NotElementsMatch(t, [1, 1, 2, 3], [1, 2, 3]) -> true
//
// require.NotElementsMatch(t, [1, 2, 3], [1, 2, 4]) -> true
func NotElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotElementsMatch(t, listA, listB, msgAndArgs...) {
return
}
t.FailNow()
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// require.NotElementsMatchf(t, [1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// require.NotElementsMatchf(t, [1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func NotElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotElementsMatchf(t, listA, listB, msg, args...) {
return
}
t.FailNow()
}
// NotEmpty asserts that the specified object is NOT [Empty].
//
// if require.NotEmpty(t, obj) {
// require.Equal(t, "two", obj[1])
// }
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEmpty(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// NotEmptyf asserts that the specified object is NOT [Empty].
//
// if require.NotEmptyf(t, obj, "error message %s", "formatted") {
// require.Equal(t, "two", obj[1])
// }
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEmptyf(t, object, msg, args...) {
return
}
t.FailNow()
}
// NotEqual asserts that the specified values are NOT equal.
//
// require.NotEqual(t, obj1, obj2)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqual(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// require.NotEqualValues(t, obj1, obj2)
func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqualValues(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// require.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted")
func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqualValuesf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// NotEqualf asserts that the specified values are NOT equal.
//
// require.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotEqualf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotErrorAs(t, err, target, msgAndArgs...) {
return
}
t.FailNow()
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func NotErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotErrorAsf(t, err, target, msg, args...) {
return
}
t.FailNow()
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotErrorIs(t, err, target, msgAndArgs...) {
return
}
t.FailNow()
}
// NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotErrorIsf(t, err, target, msg, args...) {
return
}
t.FailNow()
}
// NotImplements asserts that an object does not implement the specified interface.
//
// require.NotImplements(t, (*MyInterface)(nil), new(MyObject))
func NotImplements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotImplements(t, interfaceObject, object, msgAndArgs...) {
return
}
t.FailNow()
}
// NotImplementsf asserts that an object does not implement the specified interface.
//
// require.NotImplementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func NotImplementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotImplementsf(t, interfaceObject, object, msg, args...) {
return
}
t.FailNow()
}
// NotNil asserts that the specified object is not nil.
//
// require.NotNil(t, err)
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotNil(t, object, msgAndArgs...) {
return
}
t.FailNow()
}
// NotNilf asserts that the specified object is not nil.
//
// require.NotNilf(t, err, "error message %s", "formatted")
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotNilf(t, object, msg, args...) {
return
}
t.FailNow()
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// require.NotPanics(t, func(){ RemainCalm() })
func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotPanics(t, f, msgAndArgs...) {
return
}
t.FailNow()
}
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// require.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotPanicsf(t, f, msg, args...) {
return
}
t.FailNow()
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// require.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// require.NotRegexp(t, "^start", "it's not starting")
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotRegexp(t, rx, str, msgAndArgs...) {
return
}
t.FailNow()
}
// NotRegexpf asserts that a specified regexp does not match a string.
//
// require.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// require.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotRegexpf(t, rx, str, msg, args...) {
return
}
t.FailNow()
}
// NotSame asserts that two pointers do not reference the same object.
//
// require.NotSame(t, ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotSame(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// NotSamef asserts that two pointers do not reference the same object.
//
// require.NotSamef(t, ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotSamef(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// require.NotSubset(t, [1, 3, 4], [1, 2])
// require.NotSubset(t, {"x": 1, "y": 2}, {"z": 3})
// require.NotSubset(t, [1, 3, 4], {1: "one", 2: "two"})
// require.NotSubset(t, {"x": 1, "y": 2}, ["z"])
func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotSubset(t, list, subset, msgAndArgs...) {
return
}
t.FailNow()
}
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// require.NotSubsetf(t, [1, 3, 4], [1, 2], "error message %s", "formatted")
// require.NotSubsetf(t, {"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// require.NotSubsetf(t, [1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// require.NotSubsetf(t, {"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotSubsetf(t, list, subset, msg, args...) {
return
}
t.FailNow()
}
// NotZero asserts that i is not the zero value for its type.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotZero(t, i, msgAndArgs...) {
return
}
t.FailNow()
}
// NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.NotZerof(t, i, msg, args...) {
return
}
t.FailNow()
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// require.Panics(t, func(){ GoCrazy() })
func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Panics(t, f, msgAndArgs...) {
return
}
t.FailNow()
}
// PanicsWithError asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// require.PanicsWithError(t, "crazy error", func(){ GoCrazy() })
func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.PanicsWithError(t, errString, f, msgAndArgs...) {
return
}
t.FailNow()
}
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// require.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.PanicsWithErrorf(t, errString, f, msg, args...) {
return
}
t.FailNow()
}
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// require.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.PanicsWithValue(t, expected, f, msgAndArgs...) {
return
}
t.FailNow()
}
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// require.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.PanicsWithValuef(t, expected, f, msg, args...) {
return
}
t.FailNow()
}
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
//
// require.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Panicsf(t, f, msg, args...) {
return
}
t.FailNow()
}
// Positive asserts that the specified element is positive
//
// require.Positive(t, 1)
// require.Positive(t, 1.23)
func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Positive(t, e, msgAndArgs...) {
return
}
t.FailNow()
}
// Positivef asserts that the specified element is positive
//
// require.Positivef(t, 1, "error message %s", "formatted")
// require.Positivef(t, 1.23, "error message %s", "formatted")
func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Positivef(t, e, msg, args...) {
return
}
t.FailNow()
}
// Regexp asserts that a specified regexp matches a string.
//
// require.Regexp(t, regexp.MustCompile("start"), "it's starting")
// require.Regexp(t, "start...$", "it's not starting")
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Regexp(t, rx, str, msgAndArgs...) {
return
}
t.FailNow()
}
// Regexpf asserts that a specified regexp matches a string.
//
// require.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// require.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Regexpf(t, rx, str, msg, args...) {
return
}
t.FailNow()
}
// Same asserts that two pointers reference the same object.
//
// require.Same(t, ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Same(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// Samef asserts that two pointers reference the same object.
//
// require.Samef(t, ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Samef(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// require.Subset(t, [1, 2, 3], [1, 2])
// require.Subset(t, {"x": 1, "y": 2}, {"x": 1})
// require.Subset(t, [1, 2, 3], {1: "one", 2: "two"})
// require.Subset(t, {"x": 1, "y": 2}, ["x"])
func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Subset(t, list, subset, msgAndArgs...) {
return
}
t.FailNow()
}
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// require.Subsetf(t, [1, 2, 3], [1, 2], "error message %s", "formatted")
// require.Subsetf(t, {"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// require.Subsetf(t, [1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// require.Subsetf(t, {"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Subsetf(t, list, subset, msg, args...) {
return
}
t.FailNow()
}
// True asserts that the specified value is true.
//
// require.True(t, myBool)
func True(t TestingT, value bool, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.True(t, value, msgAndArgs...) {
return
}
t.FailNow()
}
// Truef asserts that the specified value is true.
//
// require.Truef(t, myBool, "error message %s", "formatted")
func Truef(t TestingT, value bool, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Truef(t, value, msg, args...) {
return
}
t.FailNow()
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// require.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) {
return
}
t.FailNow()
}
// WithinDurationf asserts that the two times are within duration delta of each other.
//
// require.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.WithinDurationf(t, expected, actual, delta, msg, args...) {
return
}
t.FailNow()
}
// WithinRange asserts that a time is within a time range (inclusive).
//
// require.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.WithinRange(t, actual, start, end, msgAndArgs...) {
return
}
t.FailNow()
}
// WithinRangef asserts that a time is within a time range (inclusive).
//
// require.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.WithinRangef(t, actual, start, end, msg, args...) {
return
}
t.FailNow()
}
// YAMLEq asserts that two YAML strings are equivalent.
func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.YAMLEq(t, expected, actual, msgAndArgs...) {
return
}
t.FailNow()
}
// YAMLEqf asserts that two YAML strings are equivalent.
func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.YAMLEqf(t, expected, actual, msg, args...) {
return
}
t.FailNow()
}
// Zero asserts that i is the zero value for its type.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Zero(t, i, msgAndArgs...) {
return
}
t.FailNow()
}
// Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if assert.Zerof(t, i, msg, args...) {
return
}
t.FailNow()
}
================================================
FILE: vendor/github.com/stretchr/testify/require/require.go.tmpl
================================================
{{ replace .Comment "assert." "require."}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
if h, ok := t.(tHelper); ok { h.Helper() }
if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
t.FailNow()
}
================================================
FILE: vendor/github.com/stretchr/testify/require/require_forward.go
================================================
// Code generated with github.com/stretchr/testify/_codegen; DO NOT EDIT.
package require
import (
assert "github.com/stretchr/testify/assert"
http "net/http"
url "net/url"
time "time"
)
// Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Condition(a.t, comp, msgAndArgs...)
}
// Conditionf uses a Comparison to assert a complex condition.
func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Conditionf(a.t, comp, msg, args...)
}
// Contains asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// a.Contains("Hello World", "World")
// a.Contains(["Hello", "World"], "World")
// a.Contains({"Hello": "World"}, "Hello")
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Contains(a.t, s, contains, msgAndArgs...)
}
// Containsf asserts that the specified string, list(array, slice...) or map contains the
// specified substring or element.
//
// a.Containsf("Hello World", "World", "error message %s", "formatted")
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Containsf(a.t, s, contains, msg, args...)
}
// DirExists checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
DirExists(a.t, path, msgAndArgs...)
}
// DirExistsf checks whether a directory exists in the given path. It also fails
// if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
DirExistsf(a.t, path, msg, args...)
}
// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match.
//
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ElementsMatchf(a.t, listA, listB, msg, args...)
}
// Empty asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// a.Empty(obj)
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Empty(a.t, object, msgAndArgs...)
}
// Emptyf asserts that the given value is "empty".
//
// [Zero values] are "empty".
//
// Arrays are "empty" if every element is the zero value of the type (stricter than "empty").
//
// Slices, maps and channels with zero length are "empty".
//
// Pointer values are "empty" if the pointer is nil or if the pointed value is "empty".
//
// a.Emptyf(obj, "error message %s", "formatted")
//
// [Zero values]: https://go.dev/ref/spec#The_zero_value
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Emptyf(a.t, object, msg, args...)
}
// Equal asserts that two objects are equal.
//
// a.Equal(123, 123)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Equal(a.t, expected, actual, msgAndArgs...)
}
// EqualError asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString)
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualError(a.t, theError, errString, msgAndArgs...)
}
// EqualErrorf asserts that a function returned an error (i.e. not `nil`)
// and that it is equal to the provided error.
//
// actualObj, err := SomeFunction()
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualErrorf(a.t, theError, errString, msg, args...)
}
// EqualExportedValues asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// a.EqualExportedValues(S{1, 2}, S{1, 3}) => true
// a.EqualExportedValues(S{1, 2}, S{2, 3}) => false
func (a *Assertions) EqualExportedValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualExportedValues(a.t, expected, actual, msgAndArgs...)
}
// EqualExportedValuesf asserts that the types of two objects are equal and their public
// fields are also equal. This is useful for comparing structs that have private fields
// that could potentially differ.
//
// type S struct {
// Exported int
// notExported int
// }
// a.EqualExportedValuesf(S{1, 2}, S{1, 3}, "error message %s", "formatted") => true
// a.EqualExportedValuesf(S{1, 2}, S{2, 3}, "error message %s", "formatted") => false
func (a *Assertions) EqualExportedValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualExportedValuesf(a.t, expected, actual, msg, args...)
}
// EqualValues asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValues(uint32(123), int32(123))
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualValues(a.t, expected, actual, msgAndArgs...)
}
// EqualValuesf asserts that two objects are equal or convertible to the larger
// type and equal.
//
// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted")
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualValuesf(a.t, expected, actual, msg, args...)
}
// Equalf asserts that two objects are equal.
//
// a.Equalf(123, 123, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail.
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Equalf(a.t, expected, actual, msg, args...)
}
// Error asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// a.Error(err)
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Error(a.t, err, msgAndArgs...)
}
// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorAs(a.t, err, target, msgAndArgs...)
}
// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value.
// This is a wrapper for errors.As.
func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorAsf(a.t, err, target, msg, args...)
}
// ErrorContains asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// a.ErrorContains(err, expectedErrorSubString)
func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorContains(a.t, theError, contains, msgAndArgs...)
}
// ErrorContainsf asserts that a function returned an error (i.e. not `nil`)
// and that the error contains the specified substring.
//
// actualObj, err := SomeFunction()
// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted")
func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorContainsf(a.t, theError, contains, msg, args...)
}
// ErrorIs asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorIs(a.t, err, target, msgAndArgs...)
}
// ErrorIsf asserts that at least one of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ErrorIsf(a.t, err, target, msg, args...)
}
// Errorf asserts that a function returned an error (i.e. not `nil`).
//
// actualObj, err := SomeFunction()
// a.Errorf(err, "error message %s", "formatted")
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Errorf(a.t, err, msg, args...)
}
// Eventually asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond)
func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Eventually(a.t, condition, waitFor, tick, msgAndArgs...)
}
// EventuallyWithT asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// a.EventuallyWithT(func(c *assert.CollectT) {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithT(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EventuallyWithT(a.t, condition, waitFor, tick, msgAndArgs...)
}
// EventuallyWithTf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick. In contrast to Eventually,
// it supplies a CollectT to the condition function, so that the condition
// function can use the CollectT to call other assertions.
// The condition is considered "met" if no errors are raised in a tick.
// The supplied CollectT collects all errors from one tick (if there are any).
// If the condition is not met before waitFor, the collected errors of
// the last tick are copied to t.
//
// externalValue := false
// go func() {
// time.Sleep(8*time.Second)
// externalValue = true
// }()
// a.EventuallyWithTf(func(c *assert.CollectT, "error message %s", "formatted") {
// // add assertions as needed; any assertion failure will fail the current tick
// assert.True(c, externalValue, "expected 'externalValue' to be true")
// }, 10*time.Second, 1*time.Second, "external state has not changed to 'true'; still false")
func (a *Assertions) EventuallyWithTf(condition func(collect *assert.CollectT), waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EventuallyWithTf(a.t, condition, waitFor, tick, msg, args...)
}
// Eventuallyf asserts that given condition will be met in waitFor time,
// periodically checking target function each tick.
//
// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Eventuallyf(a.t, condition, waitFor, tick, msg, args...)
}
// Exactly asserts that two objects are equal in value and type.
//
// a.Exactly(int32(123), int64(123))
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Exactly(a.t, expected, actual, msgAndArgs...)
}
// Exactlyf asserts that two objects are equal in value and type.
//
// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted")
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Exactlyf(a.t, expected, actual, msg, args...)
}
// Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Fail(a.t, failureMessage, msgAndArgs...)
}
// FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FailNow(a.t, failureMessage, msgAndArgs...)
}
// FailNowf fails test
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FailNowf(a.t, failureMessage, msg, args...)
}
// Failf reports a failure through
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Failf(a.t, failureMessage, msg, args...)
}
// False asserts that the specified value is false.
//
// a.False(myBool)
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
False(a.t, value, msgAndArgs...)
}
// Falsef asserts that the specified value is false.
//
// a.Falsef(myBool, "error message %s", "formatted")
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Falsef(a.t, value, msg, args...)
}
// FileExists checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FileExists(a.t, path, msgAndArgs...)
}
// FileExistsf checks whether a file exists in the given path. It also fails if
// the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FileExistsf(a.t, path, msg, args...)
}
// Greater asserts that the first element is greater than the second
//
// a.Greater(2, 1)
// a.Greater(float64(2), float64(1))
// a.Greater("b", "a")
func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Greater(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqual asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqual(2, 1)
// a.GreaterOrEqual(2, 2)
// a.GreaterOrEqual("b", "a")
// a.GreaterOrEqual("b", "b")
func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
GreaterOrEqual(a.t, e1, e2, msgAndArgs...)
}
// GreaterOrEqualf asserts that the first element is greater than or equal to the second
//
// a.GreaterOrEqualf(2, 1, "error message %s", "formatted")
// a.GreaterOrEqualf(2, 2, "error message %s", "formatted")
// a.GreaterOrEqualf("b", "a", "error message %s", "formatted")
// a.GreaterOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
GreaterOrEqualf(a.t, e1, e2, msg, args...)
}
// Greaterf asserts that the first element is greater than the second
//
// a.Greaterf(2, 1, "error message %s", "formatted")
// a.Greaterf(float64(2), float64(1), "error message %s", "formatted")
// a.Greaterf("b", "a", "error message %s", "formatted")
func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Greaterf(a.t, e1, e2, msg, args...)
}
// HTTPBodyContains asserts that a specified handler returns a
// body that contains a string.
//
// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string.
//
// a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string.
//
// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
}
// HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string.
//
// a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
}
// HTTPError asserts that a specified handler returns an error status code.
//
// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPError(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPErrorf asserts that a specified handler returns an error status code.
//
// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPErrorf(a.t, handler, method, url, values, msg, args...)
}
// HTTPRedirect asserts that a specified handler returns a redirect status code.
//
// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPRedirectf asserts that a specified handler returns a redirect status code.
//
// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}}
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
}
// HTTPStatusCode asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...)
}
// HTTPStatusCodef asserts that a specified handler returns a specified status code.
//
// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...)
}
// HTTPSuccess asserts that a specified handler returns a success status code.
//
// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
}
// HTTPSuccessf asserts that a specified handler returns a success status code.
//
// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
}
// Implements asserts that an object is implemented by the specified interface.
//
// a.Implements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Implements(a.t, interfaceObject, object, msgAndArgs...)
}
// Implementsf asserts that an object is implemented by the specified interface.
//
// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Implementsf(a.t, interfaceObject, object, msg, args...)
}
// InDelta asserts that the two numerals are within delta of each other.
//
// a.InDelta(math.Pi, 22/7.0, 0.01)
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDelta(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
}
// InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
}
// InDeltaSlicef is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
}
// InDeltaf asserts that the two numerals are within delta of each other.
//
// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted")
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaf(a.t, expected, actual, delta, msg, args...)
}
// InEpsilon asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
}
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
}
// InEpsilonf asserts that expected and actual have a relative error less than epsilon
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
}
// IsDecreasing asserts that the collection is decreasing
//
// a.IsDecreasing([]int{2, 1, 0})
// a.IsDecreasing([]float{2, 1})
// a.IsDecreasing([]string{"b", "a"})
func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsDecreasing(a.t, object, msgAndArgs...)
}
// IsDecreasingf asserts that the collection is decreasing
//
// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted")
// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted")
// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted")
func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsDecreasingf(a.t, object, msg, args...)
}
// IsIncreasing asserts that the collection is increasing
//
// a.IsIncreasing([]int{1, 2, 3})
// a.IsIncreasing([]float{1, 2})
// a.IsIncreasing([]string{"a", "b"})
func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsIncreasing(a.t, object, msgAndArgs...)
}
// IsIncreasingf asserts that the collection is increasing
//
// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted")
// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted")
// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted")
func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsIncreasingf(a.t, object, msg, args...)
}
// IsNonDecreasing asserts that the collection is not decreasing
//
// a.IsNonDecreasing([]int{1, 1, 2})
// a.IsNonDecreasing([]float{1, 2})
// a.IsNonDecreasing([]string{"a", "b"})
func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNonDecreasing(a.t, object, msgAndArgs...)
}
// IsNonDecreasingf asserts that the collection is not decreasing
//
// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted")
// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted")
// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted")
func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNonDecreasingf(a.t, object, msg, args...)
}
// IsNonIncreasing asserts that the collection is not increasing
//
// a.IsNonIncreasing([]int{2, 1, 1})
// a.IsNonIncreasing([]float{2, 1})
// a.IsNonIncreasing([]string{"b", "a"})
func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNonIncreasing(a.t, object, msgAndArgs...)
}
// IsNonIncreasingf asserts that the collection is not increasing
//
// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted")
// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted")
// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted")
func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNonIncreasingf(a.t, object, msg, args...)
}
// IsNotType asserts that the specified objects are not of the same type.
//
// a.IsNotType(&NotMyStruct{}, &MyStruct{})
func (a *Assertions) IsNotType(theType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNotType(a.t, theType, object, msgAndArgs...)
}
// IsNotTypef asserts that the specified objects are not of the same type.
//
// a.IsNotTypef(&NotMyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsNotTypef(theType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsNotTypef(a.t, theType, object, msg, args...)
}
// IsType asserts that the specified objects are of the same type.
//
// a.IsType(&MyStruct{}, &MyStruct{})
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsType(a.t, expectedType, object, msgAndArgs...)
}
// IsTypef asserts that the specified objects are of the same type.
//
// a.IsTypef(&MyStruct{}, &MyStruct{}, "error message %s", "formatted")
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsTypef(a.t, expectedType, object, msg, args...)
}
// JSONEq asserts that two JSON strings are equivalent.
//
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
JSONEq(a.t, expected, actual, msgAndArgs...)
}
// JSONEqf asserts that two JSON strings are equivalent.
//
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
JSONEqf(a.t, expected, actual, msg, args...)
}
// Len asserts that the specified object has specific length.
// Len also fails if the object has a type that len() not accept.
//
// a.Len(mySlice, 3)
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Len(a.t, object, length, msgAndArgs...)
}
// Lenf asserts that the specified object has specific length.
// Lenf also fails if the object has a type that len() not accept.
//
// a.Lenf(mySlice, 3, "error message %s", "formatted")
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Lenf(a.t, object, length, msg, args...)
}
// Less asserts that the first element is less than the second
//
// a.Less(1, 2)
// a.Less(float64(1), float64(2))
// a.Less("a", "b")
func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Less(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqual asserts that the first element is less than or equal to the second
//
// a.LessOrEqual(1, 2)
// a.LessOrEqual(2, 2)
// a.LessOrEqual("a", "b")
// a.LessOrEqual("b", "b")
func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
LessOrEqual(a.t, e1, e2, msgAndArgs...)
}
// LessOrEqualf asserts that the first element is less than or equal to the second
//
// a.LessOrEqualf(1, 2, "error message %s", "formatted")
// a.LessOrEqualf(2, 2, "error message %s", "formatted")
// a.LessOrEqualf("a", "b", "error message %s", "formatted")
// a.LessOrEqualf("b", "b", "error message %s", "formatted")
func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
LessOrEqualf(a.t, e1, e2, msg, args...)
}
// Lessf asserts that the first element is less than the second
//
// a.Lessf(1, 2, "error message %s", "formatted")
// a.Lessf(float64(1), float64(2), "error message %s", "formatted")
// a.Lessf("a", "b", "error message %s", "formatted")
func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Lessf(a.t, e1, e2, msg, args...)
}
// Negative asserts that the specified element is negative
//
// a.Negative(-1)
// a.Negative(-1.23)
func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Negative(a.t, e, msgAndArgs...)
}
// Negativef asserts that the specified element is negative
//
// a.Negativef(-1, "error message %s", "formatted")
// a.Negativef(-1.23, "error message %s", "formatted")
func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Negativef(a.t, e, msg, args...)
}
// Never asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond)
func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Never(a.t, condition, waitFor, tick, msgAndArgs...)
}
// Neverf asserts that the given condition doesn't satisfy in waitFor time,
// periodically checking the target function each tick.
//
// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted")
func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Neverf(a.t, condition, waitFor, tick, msg, args...)
}
// Nil asserts that the specified object is nil.
//
// a.Nil(err)
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Nil(a.t, object, msgAndArgs...)
}
// Nilf asserts that the specified object is nil.
//
// a.Nilf(err, "error message %s", "formatted")
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Nilf(a.t, object, msg, args...)
}
// NoDirExists checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoDirExists(a.t, path, msgAndArgs...)
}
// NoDirExistsf checks whether a directory does not exist in the given path.
// It fails if the path points to an existing _directory_ only.
func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoDirExistsf(a.t, path, msg, args...)
}
// NoError asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if a.NoError(err) {
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoError(a.t, err, msgAndArgs...)
}
// NoErrorf asserts that a function returned no error (i.e. `nil`).
//
// actualObj, err := SomeFunction()
// if a.NoErrorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj)
// }
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoErrorf(a.t, err, msg, args...)
}
// NoFileExists checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoFileExists(a.t, path, msgAndArgs...)
}
// NoFileExistsf checks whether a file does not exist in a given path. It fails
// if the path points to an existing _file_ only.
func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoFileExistsf(a.t, path, msg, args...)
}
// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// a.NotContains("Hello World", "Earth")
// a.NotContains(["Hello", "World"], "Earth")
// a.NotContains({"Hello": "World"}, "Earth")
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotContains(a.t, s, contains, msgAndArgs...)
}
// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the
// specified substring or element.
//
// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotContainsf(a.t, s, contains, msg, args...)
}
// NotElementsMatch asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 1, 2, 3]) -> false
//
// a.NotElementsMatch([1, 1, 2, 3], [1, 2, 3]) -> true
//
// a.NotElementsMatch([1, 2, 3], [1, 2, 4]) -> true
func (a *Assertions) NotElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotElementsMatch(a.t, listA, listB, msgAndArgs...)
}
// NotElementsMatchf asserts that the specified listA(array, slice...) is NOT equal to specified
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should not match.
// This is an inverse of ElementsMatch.
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 1, 2, 3], "error message %s", "formatted") -> false
//
// a.NotElementsMatchf([1, 1, 2, 3], [1, 2, 3], "error message %s", "formatted") -> true
//
// a.NotElementsMatchf([1, 2, 3], [1, 2, 4], "error message %s", "formatted") -> true
func (a *Assertions) NotElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotElementsMatchf(a.t, listA, listB, msg, args...)
}
// NotEmpty asserts that the specified object is NOT [Empty].
//
// if a.NotEmpty(obj) {
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEmpty(a.t, object, msgAndArgs...)
}
// NotEmptyf asserts that the specified object is NOT [Empty].
//
// if a.NotEmptyf(obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1])
// }
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEmptyf(a.t, object, msg, args...)
}
// NotEqual asserts that the specified values are NOT equal.
//
// a.NotEqual(obj1, obj2)
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqual(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValues asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValues(obj1, obj2)
func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualValues(a.t, expected, actual, msgAndArgs...)
}
// NotEqualValuesf asserts that two objects are not equal even when converted to the same type
//
// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted")
func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualValuesf(a.t, expected, actual, msg, args...)
}
// NotEqualf asserts that the specified values are NOT equal.
//
// a.NotEqualf(obj1, obj2, "error message %s", "formatted")
//
// Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualf(a.t, expected, actual, msg, args...)
}
// NotErrorAs asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAs(err error, target interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorAs(a.t, err, target, msgAndArgs...)
}
// NotErrorAsf asserts that none of the errors in err's chain matches target,
// but if so, sets target to that error value.
func (a *Assertions) NotErrorAsf(err error, target interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorAsf(a.t, err, target, msg, args...)
}
// NotErrorIs asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorIs(a.t, err, target, msgAndArgs...)
}
// NotErrorIsf asserts that none of the errors in err's chain matches target.
// This is a wrapper for errors.Is.
func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotErrorIsf(a.t, err, target, msg, args...)
}
// NotImplements asserts that an object does not implement the specified interface.
//
// a.NotImplements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) NotImplements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotImplements(a.t, interfaceObject, object, msgAndArgs...)
}
// NotImplementsf asserts that an object does not implement the specified interface.
//
// a.NotImplementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted")
func (a *Assertions) NotImplementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotImplementsf(a.t, interfaceObject, object, msg, args...)
}
// NotNil asserts that the specified object is not nil.
//
// a.NotNil(err)
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotNil(a.t, object, msgAndArgs...)
}
// NotNilf asserts that the specified object is not nil.
//
// a.NotNilf(err, "error message %s", "formatted")
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotNilf(a.t, object, msg, args...)
}
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// a.NotPanics(func(){ RemainCalm() })
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotPanics(a.t, f, msgAndArgs...)
}
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
//
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotPanicsf(a.t, f, msg, args...)
}
// NotRegexp asserts that a specified regexp does not match a string.
//
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting")
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotRegexp(a.t, rx, str, msgAndArgs...)
}
// NotRegexpf asserts that a specified regexp does not match a string.
//
// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotRegexpf(a.t, rx, str, msg, args...)
}
// NotSame asserts that two pointers do not reference the same object.
//
// a.NotSame(ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSame(a.t, expected, actual, msgAndArgs...)
}
// NotSamef asserts that two pointers do not reference the same object.
//
// a.NotSamef(ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSamef(a.t, expected, actual, msg, args...)
}
// NotSubset asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubset([1, 3, 4], [1, 2])
// a.NotSubset({"x": 1, "y": 2}, {"z": 3})
// a.NotSubset([1, 3, 4], {1: "one", 2: "two"})
// a.NotSubset({"x": 1, "y": 2}, ["z"])
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSubset(a.t, list, subset, msgAndArgs...)
}
// NotSubsetf asserts that the list (array, slice, or map) does NOT contain all
// elements given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.NotSubsetf([1, 3, 4], [1, 2], "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, {"z": 3}, "error message %s", "formatted")
// a.NotSubsetf([1, 3, 4], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.NotSubsetf({"x": 1, "y": 2}, ["z"], "error message %s", "formatted")
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSubsetf(a.t, list, subset, msg, args...)
}
// NotZero asserts that i is not the zero value for its type.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotZero(a.t, i, msgAndArgs...)
}
// NotZerof asserts that i is not the zero value for its type.
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotZerof(a.t, i, msg, args...)
}
// Panics asserts that the code inside the specified PanicTestFunc panics.
//
// a.Panics(func(){ GoCrazy() })
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Panics(a.t, f, msgAndArgs...)
}
// PanicsWithError asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// a.PanicsWithError("crazy error", func(){ GoCrazy() })
func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithError(a.t, errString, f, msgAndArgs...)
}
// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc
// panics, and that the recovered panic value is an error that satisfies the
// EqualError comparison.
//
// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithErrorf(a.t, errString, f, msg, args...)
}
// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// a.PanicsWithValue("crazy error", func(){ GoCrazy() })
func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithValue(a.t, expected, f, msgAndArgs...)
}
// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that
// the recovered panic value equals the expected panic value.
//
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithValuef(a.t, expected, f, msg, args...)
}
// Panicsf asserts that the code inside the specified PanicTestFunc panics.
//
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Panicsf(a.t, f, msg, args...)
}
// Positive asserts that the specified element is positive
//
// a.Positive(1)
// a.Positive(1.23)
func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Positive(a.t, e, msgAndArgs...)
}
// Positivef asserts that the specified element is positive
//
// a.Positivef(1, "error message %s", "formatted")
// a.Positivef(1.23, "error message %s", "formatted")
func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Positivef(a.t, e, msg, args...)
}
// Regexp asserts that a specified regexp matches a string.
//
// a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting")
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Regexp(a.t, rx, str, msgAndArgs...)
}
// Regexpf asserts that a specified regexp matches a string.
//
// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Regexpf(a.t, rx, str, msg, args...)
}
// Same asserts that two pointers reference the same object.
//
// a.Same(ptr1, ptr2)
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Same(a.t, expected, actual, msgAndArgs...)
}
// Samef asserts that two pointers reference the same object.
//
// a.Samef(ptr1, ptr2, "error message %s", "formatted")
//
// Both arguments must be pointer variables. Pointer variable sameness is
// determined based on the equality of both type and value.
func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Samef(a.t, expected, actual, msg, args...)
}
// Subset asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subset([1, 2, 3], [1, 2])
// a.Subset({"x": 1, "y": 2}, {"x": 1})
// a.Subset([1, 2, 3], {1: "one", 2: "two"})
// a.Subset({"x": 1, "y": 2}, ["x"])
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Subset(a.t, list, subset, msgAndArgs...)
}
// Subsetf asserts that the list (array, slice, or map) contains all elements
// given in the subset (array, slice, or map).
// Map elements are key-value pairs unless compared with an array or slice where
// only the map key is evaluated.
//
// a.Subsetf([1, 2, 3], [1, 2], "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, {"x": 1}, "error message %s", "formatted")
// a.Subsetf([1, 2, 3], {1: "one", 2: "two"}, "error message %s", "formatted")
// a.Subsetf({"x": 1, "y": 2}, ["x"], "error message %s", "formatted")
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Subsetf(a.t, list, subset, msg, args...)
}
// True asserts that the specified value is true.
//
// a.True(myBool)
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
True(a.t, value, msgAndArgs...)
}
// Truef asserts that the specified value is true.
//
// a.Truef(myBool, "error message %s", "formatted")
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Truef(a.t, value, msg, args...)
}
// WithinDuration asserts that the two times are within duration delta of each other.
//
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
}
// WithinDurationf asserts that the two times are within duration delta of each other.
//
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinDurationf(a.t, expected, actual, delta, msg, args...)
}
// WithinRange asserts that a time is within a time range (inclusive).
//
// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second))
func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinRange(a.t, actual, start, end, msgAndArgs...)
}
// WithinRangef asserts that a time is within a time range (inclusive).
//
// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted")
func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinRangef(a.t, actual, start, end, msg, args...)
}
// YAMLEq asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
YAMLEq(a.t, expected, actual, msgAndArgs...)
}
// YAMLEqf asserts that two YAML strings are equivalent.
func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
YAMLEqf(a.t, expected, actual, msg, args...)
}
// Zero asserts that i is the zero value for its type.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Zero(a.t, i, msgAndArgs...)
}
// Zerof asserts that i is the zero value for its type.
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Zerof(a.t, i, msg, args...)
}
================================================
FILE: vendor/github.com/stretchr/testify/require/require_forward.go.tmpl
================================================
{{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
if h, ok := a.t.(tHelper); ok { h.Helper() }
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
}
================================================
FILE: vendor/github.com/stretchr/testify/require/requirements.go
================================================
package require
// TestingT is an interface wrapper around *testing.T
type TestingT interface {
Errorf(format string, args ...interface{})
FailNow()
}
type tHelper = interface {
Helper()
}
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
// for table driven tests.
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
// for table driven tests.
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
// for table driven tests.
type BoolAssertionFunc func(TestingT, bool, ...interface{})
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{})
//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs"
================================================
FILE: vendor/golang.org/x/net/LICENSE
================================================
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/golang.org/x/net/PATENTS
================================================
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
================================================
FILE: vendor/golang.org/x/net/bpf/asm.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
import "fmt"
// Assemble converts insts into raw instructions suitable for loading
// into a BPF virtual machine.
//
// Currently, no optimization is attempted, the assembled program flow
// is exactly as provided.
func Assemble(insts []Instruction) ([]RawInstruction, error) {
ret := make([]RawInstruction, len(insts))
var err error
for i, inst := range insts {
ret[i], err = inst.Assemble()
if err != nil {
return nil, fmt.Errorf("assembling instruction %d: %s", i+1, err)
}
}
return ret, nil
}
// Disassemble attempts to parse raw back into
// Instructions. Unrecognized RawInstructions are assumed to be an
// extension not implemented by this package, and are passed through
// unchanged to the output. The allDecoded value reports whether insts
// contains no RawInstructions.
func Disassemble(raw []RawInstruction) (insts []Instruction, allDecoded bool) {
insts = make([]Instruction, len(raw))
allDecoded = true
for i, r := range raw {
insts[i] = r.Disassemble()
if _, ok := insts[i].(RawInstruction); ok {
allDecoded = false
}
}
return insts, allDecoded
}
================================================
FILE: vendor/golang.org/x/net/bpf/constants.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
// A Register is a register of the BPF virtual machine.
type Register uint16
const (
// RegA is the accumulator register. RegA is always the
// destination register of ALU operations.
RegA Register = iota
// RegX is the indirection register, used by LoadIndirect
// operations.
RegX
)
// An ALUOp is an arithmetic or logic operation.
type ALUOp uint16
// ALU binary operation types.
const (
ALUOpAdd ALUOp = iota << 4
ALUOpSub
ALUOpMul
ALUOpDiv
ALUOpOr
ALUOpAnd
ALUOpShiftLeft
ALUOpShiftRight
aluOpNeg // Not exported because it's the only unary ALU operation, and gets its own instruction type.
ALUOpMod
ALUOpXor
)
// A JumpTest is a comparison operator used in conditional jumps.
type JumpTest uint16
// Supported operators for conditional jumps.
// K can be RegX for JumpIfX
const (
// K == A
JumpEqual JumpTest = iota
// K != A
JumpNotEqual
// K > A
JumpGreaterThan
// K < A
JumpLessThan
// K >= A
JumpGreaterOrEqual
// K <= A
JumpLessOrEqual
// K & A != 0
JumpBitsSet
// K & A == 0
JumpBitsNotSet
)
// An Extension is a function call provided by the kernel that
// performs advanced operations that are expensive or impossible
// within the BPF virtual machine.
//
// Extensions are only implemented by the Linux kernel.
//
// TODO: should we prune this list? Some of these extensions seem
// either broken or near-impossible to use correctly, whereas other
// (len, random, ifindex) are quite useful.
type Extension int
// Extension functions available in the Linux kernel.
const (
// extOffset is the negative maximum number of instructions used
// to load instructions by overloading the K argument.
extOffset = -0x1000
// ExtLen returns the length of the packet.
ExtLen Extension = 1
// ExtProto returns the packet's L3 protocol type.
ExtProto Extension = 0
// ExtType returns the packet's type (skb->pkt_type in the kernel)
//
// TODO: better documentation. How nice an API do we want to
// provide for these esoteric extensions?
ExtType Extension = 4
// ExtPayloadOffset returns the offset of the packet payload, or
// the first protocol header that the kernel does not know how to
// parse.
ExtPayloadOffset Extension = 52
// ExtInterfaceIndex returns the index of the interface on which
// the packet was received.
ExtInterfaceIndex Extension = 8
// ExtNetlinkAttr returns the netlink attribute of type X at
// offset A.
ExtNetlinkAttr Extension = 12
// ExtNetlinkAttrNested returns the nested netlink attribute of
// type X at offset A.
ExtNetlinkAttrNested Extension = 16
// ExtMark returns the packet's mark value.
ExtMark Extension = 20
// ExtQueue returns the packet's assigned hardware queue.
ExtQueue Extension = 24
// ExtLinkLayerType returns the packet's hardware address type
// (e.g. Ethernet, Infiniband).
ExtLinkLayerType Extension = 28
// ExtRXHash returns the packets receive hash.
//
// TODO: figure out what this rxhash actually is.
ExtRXHash Extension = 32
// ExtCPUID returns the ID of the CPU processing the current
// packet.
ExtCPUID Extension = 36
// ExtVLANTag returns the packet's VLAN tag.
ExtVLANTag Extension = 44
// ExtVLANTagPresent returns non-zero if the packet has a VLAN
// tag.
//
// TODO: I think this might be a lie: it reads bit 0x1000 of the
// VLAN header, which changed meaning in recent revisions of the
// spec - this extension may now return meaningless information.
ExtVLANTagPresent Extension = 48
// ExtVLANProto returns 0x8100 if the frame has a VLAN header,
// 0x88a8 if the frame has a "Q-in-Q" double VLAN header, or some
// other value if no VLAN information is present.
ExtVLANProto Extension = 60
// ExtRand returns a uniformly random uint32.
ExtRand Extension = 56
)
// The following gives names to various bit patterns used in opcode construction.
const (
opMaskCls uint16 = 0x7
// opClsLoad masks
opMaskLoadDest = 0x01
opMaskLoadWidth = 0x18
opMaskLoadMode = 0xe0
// opClsALU & opClsJump
opMaskOperand = 0x08
opMaskOperator = 0xf0
)
const (
// +---------------+-----------------+---+---+---+
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 0 |
// +---------------+-----------------+---+---+---+
opClsLoadA uint16 = iota
// +---------------+-----------------+---+---+---+
// | AddrMode (3b) | LoadWidth (2b) | 0 | 0 | 1 |
// +---------------+-----------------+---+---+---+
opClsLoadX
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
// +---+---+---+---+---+---+---+---+
opClsStoreA
// +---+---+---+---+---+---+---+---+
// | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
// +---+---+---+---+---+---+---+---+
opClsStoreX
// +---------------+-----------------+---+---+---+
// | Operator (4b) | OperandSrc (1b) | 1 | 0 | 0 |
// +---------------+-----------------+---+---+---+
opClsALU
// +-----------------------------+---+---+---+---+
// | TestOperator (4b) | 0 | 1 | 0 | 1 |
// +-----------------------------+---+---+---+---+
opClsJump
// +---+-------------------------+---+---+---+---+
// | 0 | 0 | 0 | RetSrc (1b) | 0 | 1 | 1 | 0 |
// +---+-------------------------+---+---+---+---+
opClsReturn
// +---+-------------------------+---+---+---+---+
// | 0 | 0 | 0 | TXAorTAX (1b) | 0 | 1 | 1 | 1 |
// +---+-------------------------+---+---+---+---+
opClsMisc
)
const (
opAddrModeImmediate uint16 = iota << 5
opAddrModeAbsolute
opAddrModeIndirect
opAddrModeScratch
opAddrModePacketLen // actually an extension, not an addressing mode.
opAddrModeMemShift
)
const (
opLoadWidth4 uint16 = iota << 3
opLoadWidth2
opLoadWidth1
)
// Operand for ALU and Jump instructions
type opOperand uint16
// Supported operand sources.
const (
opOperandConstant opOperand = iota << 3
opOperandX
)
// An jumpOp is a conditional jump condition.
type jumpOp uint16
// Supported jump conditions.
const (
opJumpAlways jumpOp = iota << 4
opJumpEqual
opJumpGT
opJumpGE
opJumpSet
)
const (
opRetSrcConstant uint16 = iota << 4
opRetSrcA
)
const (
opMiscTAX = 0x00
opMiscTXA = 0x80
)
================================================
FILE: vendor/golang.org/x/net/bpf/doc.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package bpf implements marshaling and unmarshaling of programs for the
Berkeley Packet Filter virtual machine, and provides a Go implementation
of the virtual machine.
BPF's main use is to specify a packet filter for network taps, so that
the kernel doesn't have to expensively copy every packet it sees to
userspace. However, it's been repurposed to other areas where running
user code in-kernel is needed. For example, Linux's seccomp uses BPF
to apply security policies to system calls. For simplicity, this
documentation refers only to packets, but other uses of BPF have their
own data payloads.
BPF programs run in a restricted virtual machine. It has almost no
access to kernel functions, and while conditional branches are
allowed, they can only jump forwards, to guarantee that there are no
infinite loops.
# The virtual machine
The BPF VM is an accumulator machine. Its main register, called
register A, is an implicit source and destination in all arithmetic
and logic operations. The machine also has 16 scratch registers for
temporary storage, and an indirection register (register X) for
indirect memory access. All registers are 32 bits wide.
Each run of a BPF program is given one packet, which is placed in the
VM's read-only "main memory". LoadAbsolute and LoadIndirect
instructions can fetch up to 32 bits at a time into register A for
examination.
The goal of a BPF program is to produce and return a verdict (uint32),
which tells the kernel what to do with the packet. In the context of
packet filtering, the returned value is the number of bytes of the
packet to forward to userspace, or 0 to ignore the packet. Other
contexts like seccomp define their own return values.
In order to simplify programs, attempts to read past the end of the
packet terminate the program execution with a verdict of 0 (ignore
packet). This means that the vast majority of BPF programs don't need
to do any explicit bounds checking.
In addition to the bytes of the packet, some BPF programs have access
to extensions, which are essentially calls to kernel utility
functions. Currently, the only extensions supported by this package
are the Linux packet filter extensions.
# Examples
This packet filter selects all ARP packets.
bpf.Assemble([]bpf.Instruction{
// Load "EtherType" field from the ethernet header.
bpf.LoadAbsolute{Off: 12, Size: 2},
// Skip over the next instruction if EtherType is not ARP.
bpf.JumpIf{Cond: bpf.JumpNotEqual, Val: 0x0806, SkipTrue: 1},
// Verdict is "send up to 4k of the packet to userspace."
bpf.RetConstant{Val: 4096},
// Verdict is "ignore packet."
bpf.RetConstant{Val: 0},
})
This packet filter captures a random 1% sample of traffic.
bpf.Assemble([]bpf.Instruction{
// Get a 32-bit random number from the Linux kernel.
bpf.LoadExtension{Num: bpf.ExtRand},
// 1% dice roll?
bpf.JumpIf{Cond: bpf.JumpLessThan, Val: 2^32/100, SkipFalse: 1},
// Capture.
bpf.RetConstant{Val: 4096},
// Ignore.
bpf.RetConstant{Val: 0},
})
*/
package bpf // import "golang.org/x/net/bpf"
================================================
FILE: vendor/golang.org/x/net/bpf/instructions.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
import "fmt"
// An Instruction is one instruction executed by the BPF virtual
// machine.
type Instruction interface {
// Assemble assembles the Instruction into a RawInstruction.
Assemble() (RawInstruction, error)
}
// A RawInstruction is a raw BPF virtual machine instruction.
type RawInstruction struct {
// Operation to execute.
Op uint16
// For conditional jump instructions, the number of instructions
// to skip if the condition is true/false.
Jt uint8
Jf uint8
// Constant parameter. The meaning depends on the Op.
K uint32
}
// Assemble implements the Instruction Assemble method.
func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
// Disassemble parses ri into an Instruction and returns it. If ri is
// not recognized by this package, ri itself is returned.
func (ri RawInstruction) Disassemble() Instruction {
switch ri.Op & opMaskCls {
case opClsLoadA, opClsLoadX:
reg := Register(ri.Op & opMaskLoadDest)
sz := 0
switch ri.Op & opMaskLoadWidth {
case opLoadWidth4:
sz = 4
case opLoadWidth2:
sz = 2
case opLoadWidth1:
sz = 1
default:
return ri
}
switch ri.Op & opMaskLoadMode {
case opAddrModeImmediate:
if sz != 4 {
return ri
}
return LoadConstant{Dst: reg, Val: ri.K}
case opAddrModeScratch:
if sz != 4 || ri.K > 15 {
return ri
}
return LoadScratch{Dst: reg, N: int(ri.K)}
case opAddrModeAbsolute:
if ri.K > extOffset+0xffffffff {
return LoadExtension{Num: Extension(-extOffset + ri.K)}
}
return LoadAbsolute{Size: sz, Off: ri.K}
case opAddrModeIndirect:
return LoadIndirect{Size: sz, Off: ri.K}
case opAddrModePacketLen:
if sz != 4 {
return ri
}
return LoadExtension{Num: ExtLen}
case opAddrModeMemShift:
return LoadMemShift{Off: ri.K}
default:
return ri
}
case opClsStoreA:
if ri.Op != opClsStoreA || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegA, N: int(ri.K)}
case opClsStoreX:
if ri.Op != opClsStoreX || ri.K > 15 {
return ri
}
return StoreScratch{Src: RegX, N: int(ri.K)}
case opClsALU:
switch op := ALUOp(ri.Op & opMaskOperator); op {
case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
switch operand := opOperand(ri.Op & opMaskOperand); operand {
case opOperandX:
return ALUOpX{Op: op}
case opOperandConstant:
return ALUOpConstant{Op: op, Val: ri.K}
default:
return ri
}
case aluOpNeg:
return NegateA{}
default:
return ri
}
case opClsJump:
switch op := jumpOp(ri.Op & opMaskOperator); op {
case opJumpAlways:
return Jump{Skip: ri.K}
case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
switch operand := opOperand(ri.Op & opMaskOperand); operand {
case opOperandX:
return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
case opOperandConstant:
return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
default:
return ri
}
default:
return ri
}
case opClsReturn:
switch ri.Op {
case opClsReturn | opRetSrcA:
return RetA{}
case opClsReturn | opRetSrcConstant:
return RetConstant{Val: ri.K}
default:
return ri
}
case opClsMisc:
switch ri.Op {
case opClsMisc | opMiscTAX:
return TAX{}
case opClsMisc | opMiscTXA:
return TXA{}
default:
return ri
}
default:
panic("unreachable") // switch is exhaustive on the bit pattern
}
}
func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
var test JumpTest
// Decode "fake" jump conditions that don't appear in machine code
// Ensures the Assemble -> Disassemble stage recreates the same instructions
// See https://github.com/golang/go/issues/18470
if skipTrue == 0 {
switch op {
case opJumpEqual:
test = JumpNotEqual
case opJumpGT:
test = JumpLessOrEqual
case opJumpGE:
test = JumpLessThan
case opJumpSet:
test = JumpBitsNotSet
}
return test, skipFalse, 0
}
switch op {
case opJumpEqual:
test = JumpEqual
case opJumpGT:
test = JumpGreaterThan
case opJumpGE:
test = JumpGreaterOrEqual
case opJumpSet:
test = JumpBitsSet
}
return test, skipTrue, skipFalse
}
// LoadConstant loads Val into register Dst.
type LoadConstant struct {
Dst Register
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a LoadConstant) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
}
// String returns the instruction in assembler notation.
func (a LoadConstant) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld #%d", a.Val)
case RegX:
return fmt.Sprintf("ldx #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadScratch loads scratch[N] into register Dst.
type LoadScratch struct {
Dst Register
N int // 0-15
}
// Assemble implements the Instruction Assemble method.
func (a LoadScratch) Assemble() (RawInstruction, error) {
if a.N < 0 || a.N > 15 {
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
}
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
}
// String returns the instruction in assembler notation.
func (a LoadScratch) String() string {
switch a.Dst {
case RegA:
return fmt.Sprintf("ld M[%d]", a.N)
case RegX:
return fmt.Sprintf("ldx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
// register A.
type LoadAbsolute struct {
Off uint32
Size int // 1, 2 or 4
}
// Assemble implements the Instruction Assemble method.
func (a LoadAbsolute) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadAbsolute) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [%d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [%d]", a.Off)
case 4: // word
if a.Off > extOffset+0xffffffff {
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
}
return fmt.Sprintf("ld [%d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
// into register A.
type LoadIndirect struct {
Off uint32
Size int // 1, 2 or 4
}
// Assemble implements the Instruction Assemble method.
func (a LoadIndirect) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadIndirect) String() string {
switch a.Size {
case 1: // byte
return fmt.Sprintf("ldb [x + %d]", a.Off)
case 2: // half word
return fmt.Sprintf("ldh [x + %d]", a.Off)
case 4: // word
return fmt.Sprintf("ld [x + %d]", a.Off)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
// by 4 and stores the result in register X.
//
// This instruction is mainly useful to load into X the length of an
// IPv4 packet header in a single instruction, rather than have to do
// the arithmetic on the header's first byte by hand.
type LoadMemShift struct {
Off uint32
}
// Assemble implements the Instruction Assemble method.
func (a LoadMemShift) Assemble() (RawInstruction, error) {
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
}
// String returns the instruction in assembler notation.
func (a LoadMemShift) String() string {
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
}
// LoadExtension invokes a linux-specific extension and stores the
// result in register A.
type LoadExtension struct {
Num Extension
}
// Assemble implements the Instruction Assemble method.
func (a LoadExtension) Assemble() (RawInstruction, error) {
if a.Num == ExtLen {
return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
}
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
}
// String returns the instruction in assembler notation.
func (a LoadExtension) String() string {
switch a.Num {
case ExtLen:
return "ld #len"
case ExtProto:
return "ld #proto"
case ExtType:
return "ld #type"
case ExtPayloadOffset:
return "ld #poff"
case ExtInterfaceIndex:
return "ld #ifidx"
case ExtNetlinkAttr:
return "ld #nla"
case ExtNetlinkAttrNested:
return "ld #nlan"
case ExtMark:
return "ld #mark"
case ExtQueue:
return "ld #queue"
case ExtLinkLayerType:
return "ld #hatype"
case ExtRXHash:
return "ld #rxhash"
case ExtCPUID:
return "ld #cpu"
case ExtVLANTag:
return "ld #vlan_tci"
case ExtVLANTagPresent:
return "ld #vlan_avail"
case ExtVLANProto:
return "ld #vlan_tpid"
case ExtRand:
return "ld #rand"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// StoreScratch stores register Src into scratch[N].
type StoreScratch struct {
Src Register
N int // 0-15
}
// Assemble implements the Instruction Assemble method.
func (a StoreScratch) Assemble() (RawInstruction, error) {
if a.N < 0 || a.N > 15 {
return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
}
var op uint16
switch a.Src {
case RegA:
op = opClsStoreA
case RegX:
op = opClsStoreX
default:
return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
}
return RawInstruction{
Op: op,
K: uint32(a.N),
}, nil
}
// String returns the instruction in assembler notation.
func (a StoreScratch) String() string {
switch a.Src {
case RegA:
return fmt.Sprintf("st M[%d]", a.N)
case RegX:
return fmt.Sprintf("stx M[%d]", a.N)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpConstant executes A = A Val.
type ALUOpConstant struct {
Op ALUOp
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a ALUOpConstant) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
K: a.Val,
}, nil
}
// String returns the instruction in assembler notation.
func (a ALUOpConstant) String() string {
switch a.Op {
case ALUOpAdd:
return fmt.Sprintf("add #%d", a.Val)
case ALUOpSub:
return fmt.Sprintf("sub #%d", a.Val)
case ALUOpMul:
return fmt.Sprintf("mul #%d", a.Val)
case ALUOpDiv:
return fmt.Sprintf("div #%d", a.Val)
case ALUOpMod:
return fmt.Sprintf("mod #%d", a.Val)
case ALUOpAnd:
return fmt.Sprintf("and #%d", a.Val)
case ALUOpOr:
return fmt.Sprintf("or #%d", a.Val)
case ALUOpXor:
return fmt.Sprintf("xor #%d", a.Val)
case ALUOpShiftLeft:
return fmt.Sprintf("lsh #%d", a.Val)
case ALUOpShiftRight:
return fmt.Sprintf("rsh #%d", a.Val)
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// ALUOpX executes A = A X
type ALUOpX struct {
Op ALUOp
}
// Assemble implements the Instruction Assemble method.
func (a ALUOpX) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
}, nil
}
// String returns the instruction in assembler notation.
func (a ALUOpX) String() string {
switch a.Op {
case ALUOpAdd:
return "add x"
case ALUOpSub:
return "sub x"
case ALUOpMul:
return "mul x"
case ALUOpDiv:
return "div x"
case ALUOpMod:
return "mod x"
case ALUOpAnd:
return "and x"
case ALUOpOr:
return "or x"
case ALUOpXor:
return "xor x"
case ALUOpShiftLeft:
return "lsh x"
case ALUOpShiftRight:
return "rsh x"
default:
return fmt.Sprintf("unknown instruction: %#v", a)
}
}
// NegateA executes A = -A.
type NegateA struct{}
// Assemble implements the Instruction Assemble method.
func (a NegateA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsALU | uint16(aluOpNeg),
}, nil
}
// String returns the instruction in assembler notation.
func (a NegateA) String() string {
return fmt.Sprintf("neg")
}
// Jump skips the following Skip instructions in the program.
type Jump struct {
Skip uint32
}
// Assemble implements the Instruction Assemble method.
func (a Jump) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsJump | uint16(opJumpAlways),
K: a.Skip,
}, nil
}
// String returns the instruction in assembler notation.
func (a Jump) String() string {
return fmt.Sprintf("ja %d", a.Skip)
}
// JumpIf skips the following Skip instructions in the program if A
// Val is true.
type JumpIf struct {
Cond JumpTest
Val uint32
SkipTrue uint8
SkipFalse uint8
}
// Assemble implements the Instruction Assemble method.
func (a JumpIf) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIf) String() string {
return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
}
// JumpIfX skips the following Skip instructions in the program if A
// X is true.
type JumpIfX struct {
Cond JumpTest
SkipTrue uint8
SkipFalse uint8
}
// Assemble implements the Instruction Assemble method.
func (a JumpIfX) Assemble() (RawInstruction, error) {
return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
}
// String returns the instruction in assembler notation.
func (a JumpIfX) String() string {
return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
}
// jumpToRaw assembles a jump instruction into a RawInstruction
func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
var (
cond jumpOp
flip bool
)
switch test {
case JumpEqual:
cond = opJumpEqual
case JumpNotEqual:
cond, flip = opJumpEqual, true
case JumpGreaterThan:
cond = opJumpGT
case JumpLessThan:
cond, flip = opJumpGE, true
case JumpGreaterOrEqual:
cond = opJumpGE
case JumpLessOrEqual:
cond, flip = opJumpGT, true
case JumpBitsSet:
cond = opJumpSet
case JumpBitsNotSet:
cond, flip = opJumpSet, true
default:
return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
}
jt, jf := skipTrue, skipFalse
if flip {
jt, jf = jf, jt
}
return RawInstruction{
Op: opClsJump | uint16(cond) | uint16(operand),
Jt: jt,
Jf: jf,
K: k,
}, nil
}
// jumpToString converts a jump instruction to assembler notation
func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
switch cond {
// K == A
case JumpEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
// K != A
case JumpNotEqual:
return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
// K > A
case JumpGreaterThan:
return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
// K < A
case JumpLessThan:
return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
// K >= A
case JumpGreaterOrEqual:
return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
// K <= A
case JumpLessOrEqual:
return fmt.Sprintf("jle %s,%d", operand, skipTrue)
// K & A != 0
case JumpBitsSet:
if skipFalse > 0 {
return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
}
return fmt.Sprintf("jset %s,%d", operand, skipTrue)
// K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
case JumpBitsNotSet:
return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
default:
return fmt.Sprintf("unknown JumpTest %#v", cond)
}
}
func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
if skipTrue > 0 {
if skipFalse > 0 {
return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
}
return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
}
return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
}
// RetA exits the BPF program, returning the value of register A.
type RetA struct{}
// Assemble implements the Instruction Assemble method.
func (a RetA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsReturn | opRetSrcA,
}, nil
}
// String returns the instruction in assembler notation.
func (a RetA) String() string {
return fmt.Sprintf("ret a")
}
// RetConstant exits the BPF program, returning a constant value.
type RetConstant struct {
Val uint32
}
// Assemble implements the Instruction Assemble method.
func (a RetConstant) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsReturn | opRetSrcConstant,
K: a.Val,
}, nil
}
// String returns the instruction in assembler notation.
func (a RetConstant) String() string {
return fmt.Sprintf("ret #%d", a.Val)
}
// TXA copies the value of register X to register A.
type TXA struct{}
// Assemble implements the Instruction Assemble method.
func (a TXA) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsMisc | opMiscTXA,
}, nil
}
// String returns the instruction in assembler notation.
func (a TXA) String() string {
return fmt.Sprintf("txa")
}
// TAX copies the value of register A to register X.
type TAX struct{}
// Assemble implements the Instruction Assemble method.
func (a TAX) Assemble() (RawInstruction, error) {
return RawInstruction{
Op: opClsMisc | opMiscTAX,
}, nil
}
// String returns the instruction in assembler notation.
func (a TAX) String() string {
return fmt.Sprintf("tax")
}
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
var (
cls uint16
sz uint16
)
switch dst {
case RegA:
cls = opClsLoadA
case RegX:
cls = opClsLoadX
default:
return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
}
switch loadSize {
case 1:
sz = opLoadWidth1
case 2:
sz = opLoadWidth2
case 4:
sz = opLoadWidth4
default:
return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
}
return RawInstruction{
Op: cls | sz | mode,
K: k,
}, nil
}
================================================
FILE: vendor/golang.org/x/net/bpf/setter.go
================================================
// 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.
package bpf
// A Setter is a type which can attach a compiled BPF filter to itself.
type Setter interface {
SetBPF(filter []RawInstruction) error
}
================================================
FILE: vendor/golang.org/x/net/bpf/vm.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
import (
"errors"
"fmt"
)
// A VM is an emulated BPF virtual machine.
type VM struct {
filter []Instruction
}
// NewVM returns a new VM using the input BPF program.
func NewVM(filter []Instruction) (*VM, error) {
if len(filter) == 0 {
return nil, errors.New("one or more Instructions must be specified")
}
for i, ins := range filter {
check := len(filter) - (i + 1)
switch ins := ins.(type) {
// Check for out-of-bounds jumps in instructions
case Jump:
if check <= int(ins.Skip) {
return nil, fmt.Errorf("cannot jump %d instructions; jumping past program bounds", ins.Skip)
}
case JumpIf:
if check <= int(ins.SkipTrue) {
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
}
if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
}
case JumpIfX:
if check <= int(ins.SkipTrue) {
return nil, fmt.Errorf("cannot jump %d instructions in true case; jumping past program bounds", ins.SkipTrue)
}
if check <= int(ins.SkipFalse) {
return nil, fmt.Errorf("cannot jump %d instructions in false case; jumping past program bounds", ins.SkipFalse)
}
// Check for division or modulus by zero
case ALUOpConstant:
if ins.Val != 0 {
break
}
switch ins.Op {
case ALUOpDiv, ALUOpMod:
return nil, errors.New("cannot divide by zero using ALUOpConstant")
}
// Check for unknown extensions
case LoadExtension:
switch ins.Num {
case ExtLen:
default:
return nil, fmt.Errorf("extension %d not implemented", ins.Num)
}
}
}
// Make sure last instruction is a return instruction
switch filter[len(filter)-1].(type) {
case RetA, RetConstant:
default:
return nil, errors.New("BPF program must end with RetA or RetConstant")
}
// Though our VM works using disassembled instructions, we
// attempt to assemble the input filter anyway to ensure it is compatible
// with an operating system VM.
_, err := Assemble(filter)
return &VM{
filter: filter,
}, err
}
// Run runs the VM's BPF program against the input bytes.
// Run returns the number of bytes accepted by the BPF program, and any errors
// which occurred while processing the program.
func (v *VM) Run(in []byte) (int, error) {
var (
// Registers of the virtual machine
regA uint32
regX uint32
regScratch [16]uint32
// OK is true if the program should continue processing the next
// instruction, or false if not, causing the loop to break
ok = true
)
// TODO(mdlayher): implement:
// - NegateA:
// - would require a change from uint32 registers to int32
// registers
// TODO(mdlayher): add interop tests that check signedness of ALU
// operations against kernel implementation, and make sure Go
// implementation matches behavior
for i := 0; i < len(v.filter) && ok; i++ {
ins := v.filter[i]
switch ins := ins.(type) {
case ALUOpConstant:
regA = aluOpConstant(ins, regA)
case ALUOpX:
regA, ok = aluOpX(ins, regA, regX)
case Jump:
i += int(ins.Skip)
case JumpIf:
jump := jumpIf(ins, regA)
i += jump
case JumpIfX:
jump := jumpIfX(ins, regA, regX)
i += jump
case LoadAbsolute:
regA, ok = loadAbsolute(ins, in)
case LoadConstant:
regA, regX = loadConstant(ins, regA, regX)
case LoadExtension:
regA = loadExtension(ins, in)
case LoadIndirect:
regA, ok = loadIndirect(ins, in, regX)
case LoadMemShift:
regX, ok = loadMemShift(ins, in)
case LoadScratch:
regA, regX = loadScratch(ins, regScratch, regA, regX)
case RetA:
return int(regA), nil
case RetConstant:
return int(ins.Val), nil
case StoreScratch:
regScratch = storeScratch(ins, regScratch, regA, regX)
case TAX:
regX = regA
case TXA:
regA = regX
default:
return 0, fmt.Errorf("unknown Instruction at index %d: %T", i, ins)
}
}
return 0, nil
}
================================================
FILE: vendor/golang.org/x/net/bpf/vm_instructions.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package bpf
import (
"encoding/binary"
"fmt"
)
func aluOpConstant(ins ALUOpConstant, regA uint32) uint32 {
return aluOpCommon(ins.Op, regA, ins.Val)
}
func aluOpX(ins ALUOpX, regA uint32, regX uint32) (uint32, bool) {
// Guard against division or modulus by zero by terminating
// the program, as the OS BPF VM does
if regX == 0 {
switch ins.Op {
case ALUOpDiv, ALUOpMod:
return 0, false
}
}
return aluOpCommon(ins.Op, regA, regX), true
}
func aluOpCommon(op ALUOp, regA uint32, value uint32) uint32 {
switch op {
case ALUOpAdd:
return regA + value
case ALUOpSub:
return regA - value
case ALUOpMul:
return regA * value
case ALUOpDiv:
// Division by zero not permitted by NewVM and aluOpX checks
return regA / value
case ALUOpOr:
return regA | value
case ALUOpAnd:
return regA & value
case ALUOpShiftLeft:
return regA << value
case ALUOpShiftRight:
return regA >> value
case ALUOpMod:
// Modulus by zero not permitted by NewVM and aluOpX checks
return regA % value
case ALUOpXor:
return regA ^ value
default:
return regA
}
}
func jumpIf(ins JumpIf, regA uint32) int {
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, ins.Val)
}
func jumpIfX(ins JumpIfX, regA uint32, regX uint32) int {
return jumpIfCommon(ins.Cond, ins.SkipTrue, ins.SkipFalse, regA, regX)
}
func jumpIfCommon(cond JumpTest, skipTrue, skipFalse uint8, regA uint32, value uint32) int {
var ok bool
switch cond {
case JumpEqual:
ok = regA == value
case JumpNotEqual:
ok = regA != value
case JumpGreaterThan:
ok = regA > value
case JumpLessThan:
ok = regA < value
case JumpGreaterOrEqual:
ok = regA >= value
case JumpLessOrEqual:
ok = regA <= value
case JumpBitsSet:
ok = (regA & value) != 0
case JumpBitsNotSet:
ok = (regA & value) == 0
}
if ok {
return int(skipTrue)
}
return int(skipFalse)
}
func loadAbsolute(ins LoadAbsolute, in []byte) (uint32, bool) {
offset := int(ins.Off)
size := ins.Size
return loadCommon(in, offset, size)
}
func loadConstant(ins LoadConstant, regA uint32, regX uint32) (uint32, uint32) {
switch ins.Dst {
case RegA:
regA = ins.Val
case RegX:
regX = ins.Val
}
return regA, regX
}
func loadExtension(ins LoadExtension, in []byte) uint32 {
switch ins.Num {
case ExtLen:
return uint32(len(in))
default:
panic(fmt.Sprintf("unimplemented extension: %d", ins.Num))
}
}
func loadIndirect(ins LoadIndirect, in []byte, regX uint32) (uint32, bool) {
offset := int(ins.Off) + int(regX)
size := ins.Size
return loadCommon(in, offset, size)
}
func loadMemShift(ins LoadMemShift, in []byte) (uint32, bool) {
offset := int(ins.Off)
// Size of LoadMemShift is always 1 byte
if !inBounds(len(in), offset, 1) {
return 0, false
}
// Mask off high 4 bits and multiply low 4 bits by 4
return uint32(in[offset]&0x0f) * 4, true
}
func inBounds(inLen int, offset int, size int) bool {
return offset+size <= inLen
}
func loadCommon(in []byte, offset int, size int) (uint32, bool) {
if !inBounds(len(in), offset, size) {
return 0, false
}
switch size {
case 1:
return uint32(in[offset]), true
case 2:
return uint32(binary.BigEndian.Uint16(in[offset : offset+size])), true
case 4:
return uint32(binary.BigEndian.Uint32(in[offset : offset+size])), true
default:
panic(fmt.Sprintf("invalid load size: %d", size))
}
}
func loadScratch(ins LoadScratch, regScratch [16]uint32, regA uint32, regX uint32) (uint32, uint32) {
switch ins.Dst {
case RegA:
regA = regScratch[ins.N]
case RegX:
regX = regScratch[ins.N]
}
return regA, regX
}
func storeScratch(ins StoreScratch, regScratch [16]uint32, regA uint32, regX uint32) [16]uint32 {
switch ins.Src {
case RegA:
regScratch[ins.N] = regA
case RegX:
regScratch[ins.N] = regX
}
return regScratch
}
================================================
FILE: vendor/golang.org/x/net/internal/iana/const.go
================================================
// go generate gen.go
// Code generated by the command above; DO NOT EDIT.
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
package iana // import "golang.org/x/net/internal/iana"
// Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
const (
DiffServCS0 = 0x00 // CS0
DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x03 // CE (Congestion Experienced)
)
// Protocol Numbers, Updated: 2017-10-13
const (
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
ProtocolICMP = 1 // Internet Control Message
ProtocolIGMP = 2 // Internet Group Management
ProtocolGGP = 3 // Gateway-to-Gateway
ProtocolIPv4 = 4 // IPv4 encapsulation
ProtocolST = 5 // Stream
ProtocolTCP = 6 // Transmission Control
ProtocolCBT = 7 // CBT
ProtocolEGP = 8 // Exterior Gateway Protocol
ProtocolIGP = 9 // any private interior gateway (used by Cisco for their IGRP)
ProtocolBBNRCCMON = 10 // BBN RCC Monitoring
ProtocolNVPII = 11 // Network Voice Protocol
ProtocolPUP = 12 // PUP
ProtocolEMCON = 14 // EMCON
ProtocolXNET = 15 // Cross Net Debugger
ProtocolCHAOS = 16 // Chaos
ProtocolUDP = 17 // User Datagram
ProtocolMUX = 18 // Multiplexing
ProtocolDCNMEAS = 19 // DCN Measurement Subsystems
ProtocolHMP = 20 // Host Monitoring
ProtocolPRM = 21 // Packet Radio Measurement
ProtocolXNSIDP = 22 // XEROX NS IDP
ProtocolTRUNK1 = 23 // Trunk-1
ProtocolTRUNK2 = 24 // Trunk-2
ProtocolLEAF1 = 25 // Leaf-1
ProtocolLEAF2 = 26 // Leaf-2
ProtocolRDP = 27 // Reliable Data Protocol
ProtocolIRTP = 28 // Internet Reliable Transaction
ProtocolISOTP4 = 29 // ISO Transport Protocol Class 4
ProtocolNETBLT = 30 // Bulk Data Transfer Protocol
ProtocolMFENSP = 31 // MFE Network Services Protocol
ProtocolMERITINP = 32 // MERIT Internodal Protocol
ProtocolDCCP = 33 // Datagram Congestion Control Protocol
Protocol3PC = 34 // Third Party Connect Protocol
ProtocolIDPR = 35 // Inter-Domain Policy Routing Protocol
ProtocolXTP = 36 // XTP
ProtocolDDP = 37 // Datagram Delivery Protocol
ProtocolIDPRCMTP = 38 // IDPR Control Message Transport Proto
ProtocolTPPP = 39 // TP++ Transport Protocol
ProtocolIL = 40 // IL Transport Protocol
ProtocolIPv6 = 41 // IPv6 encapsulation
ProtocolSDRP = 42 // Source Demand Routing Protocol
ProtocolIPv6Route = 43 // Routing Header for IPv6
ProtocolIPv6Frag = 44 // Fragment Header for IPv6
ProtocolIDRP = 45 // Inter-Domain Routing Protocol
ProtocolRSVP = 46 // Reservation Protocol
ProtocolGRE = 47 // Generic Routing Encapsulation
ProtocolDSR = 48 // Dynamic Source Routing Protocol
ProtocolBNA = 49 // BNA
ProtocolESP = 50 // Encap Security Payload
ProtocolAH = 51 // Authentication Header
ProtocolINLSP = 52 // Integrated Net Layer Security TUBA
ProtocolNARP = 54 // NBMA Address Resolution Protocol
ProtocolMOBILE = 55 // IP Mobility
ProtocolTLSP = 56 // Transport Layer Security Protocol using Kryptonet key management
ProtocolSKIP = 57 // SKIP
ProtocolIPv6ICMP = 58 // ICMP for IPv6
ProtocolIPv6NoNxt = 59 // No Next Header for IPv6
ProtocolIPv6Opts = 60 // Destination Options for IPv6
ProtocolCFTP = 62 // CFTP
ProtocolSATEXPAK = 64 // SATNET and Backroom EXPAK
ProtocolKRYPTOLAN = 65 // Kryptolan
ProtocolRVD = 66 // MIT Remote Virtual Disk Protocol
ProtocolIPPC = 67 // Internet Pluribus Packet Core
ProtocolSATMON = 69 // SATNET Monitoring
ProtocolVISA = 70 // VISA Protocol
ProtocolIPCV = 71 // Internet Packet Core Utility
ProtocolCPNX = 72 // Computer Protocol Network Executive
ProtocolCPHB = 73 // Computer Protocol Heart Beat
ProtocolWSN = 74 // Wang Span Network
ProtocolPVP = 75 // Packet Video Protocol
ProtocolBRSATMON = 76 // Backroom SATNET Monitoring
ProtocolSUNND = 77 // SUN ND PROTOCOL-Temporary
ProtocolWBMON = 78 // WIDEBAND Monitoring
ProtocolWBEXPAK = 79 // WIDEBAND EXPAK
ProtocolISOIP = 80 // ISO Internet Protocol
ProtocolVMTP = 81 // VMTP
ProtocolSECUREVMTP = 82 // SECURE-VMTP
ProtocolVINES = 83 // VINES
ProtocolTTP = 84 // Transaction Transport Protocol
ProtocolIPTM = 84 // Internet Protocol Traffic Manager
ProtocolNSFNETIGP = 85 // NSFNET-IGP
ProtocolDGP = 86 // Dissimilar Gateway Protocol
ProtocolTCF = 87 // TCF
ProtocolEIGRP = 88 // EIGRP
ProtocolOSPFIGP = 89 // OSPFIGP
ProtocolSpriteRPC = 90 // Sprite RPC Protocol
ProtocolLARP = 91 // Locus Address Resolution Protocol
ProtocolMTP = 92 // Multicast Transport Protocol
ProtocolAX25 = 93 // AX.25 Frames
ProtocolIPIP = 94 // IP-within-IP Encapsulation Protocol
ProtocolSCCSP = 96 // Semaphore Communications Sec. Pro.
ProtocolETHERIP = 97 // Ethernet-within-IP Encapsulation
ProtocolENCAP = 98 // Encapsulation Header
ProtocolGMTP = 100 // GMTP
ProtocolIFMP = 101 // Ipsilon Flow Management Protocol
ProtocolPNNI = 102 // PNNI over IP
ProtocolPIM = 103 // Protocol Independent Multicast
ProtocolARIS = 104 // ARIS
ProtocolSCPS = 105 // SCPS
ProtocolQNX = 106 // QNX
ProtocolAN = 107 // Active Networks
ProtocolIPComp = 108 // IP Payload Compression Protocol
ProtocolSNP = 109 // Sitara Networks Protocol
ProtocolCompaqPeer = 110 // Compaq Peer Protocol
ProtocolIPXinIP = 111 // IPX in IP
ProtocolVRRP = 112 // Virtual Router Redundancy Protocol
ProtocolPGM = 113 // PGM Reliable Transport Protocol
ProtocolL2TP = 115 // Layer Two Tunneling Protocol
ProtocolDDX = 116 // D-II Data Exchange (DDX)
ProtocolIATP = 117 // Interactive Agent Transfer Protocol
ProtocolSTP = 118 // Schedule Transfer Protocol
ProtocolSRP = 119 // SpectraLink Radio Protocol
ProtocolUTI = 120 // UTI
ProtocolSMP = 121 // Simple Message Protocol
ProtocolPTP = 123 // Performance Transparency Protocol
ProtocolISIS = 124 // ISIS over IPv4
ProtocolFIRE = 125 // FIRE
ProtocolCRTP = 126 // Combat Radio Transport Protocol
ProtocolCRUDP = 127 // Combat Radio User Datagram
ProtocolSSCOPMCE = 128 // SSCOPMCE
ProtocolIPLT = 129 // IPLT
ProtocolSPS = 130 // Secure Packet Shield
ProtocolPIPE = 131 // Private IP Encapsulation within IP
ProtocolSCTP = 132 // Stream Control Transmission Protocol
ProtocolFC = 133 // Fibre Channel
ProtocolRSVPE2EIGNORE = 134 // RSVP-E2E-IGNORE
ProtocolMobilityHeader = 135 // Mobility Header
ProtocolUDPLite = 136 // UDPLite
ProtocolMPLSinIP = 137 // MPLS-in-IP
ProtocolMANET = 138 // MANET Protocols
ProtocolHIP = 139 // Host Identity Protocol
ProtocolShim6 = 140 // Shim6 Protocol
ProtocolWESP = 141 // Wrapped Encapsulating Security Payload
ProtocolROHC = 142 // Robust Header Compression
ProtocolReserved = 255 // Reserved
)
// Address Family Numbers, Updated: 2018-04-02
const (
AddrFamilyIPv4 = 1 // IP (IP version 4)
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
AddrFamilyNSAP = 3 // NSAP
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
AddrFamilyBBN1822 = 5 // BBN 1822
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
AddrFamilyE163 = 7 // E.163
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
AddrFamilyF69 = 9 // F.69 (Telex)
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
AddrFamilyIPX = 11 // IPX
AddrFamilyAppletalk = 12 // Appletalk
AddrFamilyDecnetIV = 13 // Decnet IV
AddrFamilyBanyanVines = 14 // Banyan Vines
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
AddrFamilyDNS = 16 // DNS (Domain Name System)
AddrFamilyDistinguishedName = 17 // Distinguished Name
AddrFamilyASNumber = 18 // AS Number
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
AddrFamilyGWID = 24 // GWID
AddrFamilyL2VPN = 25 // AFI for L2VPN information
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
AddrFamilyBGPLS = 16388 // BGP-LS
AddrFamily48bitMAC = 16389 // 48-bit MAC
AddrFamily64bitMAC = 16390 // 64-bit MAC
AddrFamilyOUI = 16391 // OUI
AddrFamilyMACFinal24bits = 16392 // MAC/24
AddrFamilyMACFinal40bits = 16393 // MAC/40
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
func (h *cmsghdr) len() int { return int(h.Len) }
func (h *cmsghdr) lvl() int { return int(h.Level) }
func (h *cmsghdr) typ() int { return int(h.Type) }
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_bsd.go
================================================
// 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 aix || darwin || dragonfly || freebsd || netbsd || openbsd
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_linux_32bit.go
================================================
// 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 (arm || mips || mipsle || 386 || ppc) && linux
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_linux_64bit.go
================================================
// 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 (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint64(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_solaris_64bit.go
================================================
// 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 amd64 && solaris
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = uint32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
package socket
func controlHeaderLen() int {
return 0
}
func controlMessageLen(dataLen int) int {
return 0
}
func controlMessageSpace(dataLen int) int {
return 0
}
type cmsghdr struct{}
func (h *cmsghdr) len() int { return 0 }
func (h *cmsghdr) lvl() int { return 0 }
func (h *cmsghdr) typ() int { return 0 }
func (h *cmsghdr) set(l, lvl, typ int) {}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_unix.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
import "golang.org/x/sys/unix"
func controlHeaderLen() int {
return unix.CmsgLen(0)
}
func controlMessageLen(dataLen int) int {
return unix.CmsgLen(dataLen)
}
func controlMessageSpace(dataLen int) int {
return unix.CmsgSpace(dataLen)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/cmsghdr_zos_s390x.go
================================================
// 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.
package socket
func (h *cmsghdr) set(l, lvl, typ int) {
h.Len = int32(l)
h.Level = int32(lvl)
h.Type = int32(typ)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/complete_dontwait.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package socket
import (
"syscall"
)
// ioComplete checks the flags and result of a syscall, to be used as return
// value in a syscall.RawConn.Read or Write callback.
func ioComplete(flags int, operr error) bool {
if flags&syscall.MSG_DONTWAIT != 0 {
// Caller explicitly said don't wait, so always return immediately.
return true
}
if operr == syscall.EAGAIN || operr == syscall.EWOULDBLOCK {
// No data available, block for I/O and try again.
return false
}
return true
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/complete_nodontwait.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || windows || zos
package socket
import (
"syscall"
)
// ioComplete checks the flags and result of a syscall, to be used as return
// value in a syscall.RawConn.Read or Write callback.
func ioComplete(flags int, operr error) bool {
if operr == syscall.EAGAIN || operr == syscall.EWOULDBLOCK {
// No data available, block for I/O and try again.
return false
}
return true
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/empty.s
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin
// This exists solely so we can linkname in symbols from syscall.
================================================
FILE: vendor/golang.org/x/net/internal/socket/error_unix.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
import "syscall"
var (
errEAGAIN error = syscall.EAGAIN
errEINVAL error = syscall.EINVAL
errENOENT error = syscall.ENOENT
)
// errnoErr returns common boxed Errno values, to prevent allocations
// at runtime.
func errnoErr(errno syscall.Errno) error {
switch errno {
case 0:
return nil
case syscall.EAGAIN:
return errEAGAIN
case syscall.EINVAL:
return errEINVAL
case syscall.ENOENT:
return errENOENT
}
return errno
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/error_windows.go
================================================
// 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.
package socket
import "syscall"
var (
errERROR_IO_PENDING error = syscall.ERROR_IO_PENDING
errEINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent allocations
// at runtime.
func errnoErr(errno syscall.Errno) error {
switch errno {
case 0:
return nil
case syscall.ERROR_IO_PENDING:
return errERROR_IO_PENDING
case syscall.EINVAL:
return errEINVAL
}
return errno
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/iovec_32bit.go
================================================
// 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 (arm || mips || mipsle || 386 || ppc) && (darwin || dragonfly || freebsd || linux || netbsd || openbsd)
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*byte)(unsafe.Pointer(&b[0]))
v.Len = uint32(l)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/iovec_64bit.go
================================================
// 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 (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*byte)(unsafe.Pointer(&b[0]))
v.Len = uint64(l)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/iovec_solaris_64bit.go
================================================
// 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 amd64 && solaris
package socket
import "unsafe"
func (v *iovec) set(b []byte) {
l := len(b)
if l == 0 {
return
}
v.Base = (*int8)(unsafe.Pointer(&b[0]))
v.Len = uint64(l)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/iovec_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
package socket
type iovec struct{}
func (v *iovec) set(b []byte) {}
================================================
FILE: vendor/golang.org/x/net/internal/socket/mmsghdr_stub.go
================================================
// 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 !aix && !linux && !netbsd
package socket
import "net"
type mmsghdr struct{}
type mmsghdrs []mmsghdr
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
return nil
}
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
return nil
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/mmsghdr_unix.go
================================================
// 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 aix || linux || netbsd
package socket
import (
"net"
"os"
"sync"
"syscall"
)
type mmsghdrs []mmsghdr
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
for i := range hs {
ms[i].N = int(hs[i].Len)
ms[i].NN = hs[i].Hdr.controllen()
ms[i].Flags = hs[i].Hdr.flags()
if parseFn != nil {
var err error
ms[i].Addr, err = parseFn(hs[i].Hdr.name(), hint)
if err != nil {
return err
}
}
}
return nil
}
// mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
type mmsghdrsPacker struct {
// hs are the pre-allocated mmsghdrs.
hs mmsghdrs
// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
// We use one large buffer for all messages and slice it up.
sockaddrs []byte
// vs are the pre-allocated iovecs.
// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
// if the number of buffers per message is distributed differently between calls.
vs []iovec
}
func (p *mmsghdrsPacker) prepare(ms []Message) {
n := len(ms)
if n <= cap(p.hs) {
p.hs = p.hs[:n]
} else {
p.hs = make(mmsghdrs, n)
}
if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
} else {
p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
}
nb := 0
for _, m := range ms {
nb += len(m.Buffers)
}
if nb <= cap(p.vs) {
p.vs = p.vs[:nb]
} else {
p.vs = make([]iovec, nb)
}
}
func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
p.prepare(ms)
hs := p.hs
vsRest := p.vs
saRest := p.sockaddrs
for i := range hs {
nvs := len(ms[i].Buffers)
vs := vsRest[:nvs]
vsRest = vsRest[nvs:]
var sa []byte
if parseFn != nil {
sa = saRest[:sizeofSockaddrInet6]
saRest = saRest[sizeofSockaddrInet6:]
} else if marshalFn != nil {
n := marshalFn(ms[i].Addr, saRest)
if n > 0 {
sa = saRest[:n]
saRest = saRest[n:]
}
}
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
}
return hs
}
// syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
// It is reusable, to amortize the overhead of allocating a closure for the function passed to
// RawConn.Read/Write.
type syscaller struct {
n int
operr error
hs mmsghdrs
flags int
boundRecvmmsgF func(uintptr) bool
boundSendmmsgF func(uintptr) bool
}
func (r *syscaller) init() {
r.boundRecvmmsgF = r.recvmmsgF
r.boundSendmmsgF = r.sendmmsgF
}
func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
r.n = 0
r.operr = nil
r.hs = hs
r.flags = flags
if err := c.Read(r.boundRecvmmsgF); err != nil {
return r.n, err
}
if r.operr != nil {
return r.n, os.NewSyscallError("recvmmsg", r.operr)
}
return r.n, nil
}
func (r *syscaller) recvmmsgF(s uintptr) bool {
r.n, r.operr = recvmmsg(s, r.hs, r.flags)
return ioComplete(r.flags, r.operr)
}
func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
r.n = 0
r.operr = nil
r.hs = hs
r.flags = flags
if err := c.Write(r.boundSendmmsgF); err != nil {
return r.n, err
}
if r.operr != nil {
return r.n, os.NewSyscallError("sendmmsg", r.operr)
}
return r.n, nil
}
func (r *syscaller) sendmmsgF(s uintptr) bool {
r.n, r.operr = sendmmsg(s, r.hs, r.flags)
return ioComplete(r.flags, r.operr)
}
// mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
type mmsgTmps struct {
packer mmsghdrsPacker
syscaller syscaller
}
var defaultMmsgTmpsPool = mmsgTmpsPool{
p: sync.Pool{
New: func() interface{} {
tmps := new(mmsgTmps)
tmps.syscaller.init()
return tmps
},
},
}
type mmsgTmpsPool struct {
p sync.Pool
}
func (p *mmsgTmpsPool) Get() *mmsgTmps {
m := p.p.Get().(*mmsgTmps)
// Clear fields up to the len (not the cap) of the slice,
// assuming that the previous caller only used that many elements.
for i := range m.packer.sockaddrs {
m.packer.sockaddrs[i] = 0
}
m.packer.sockaddrs = m.packer.sockaddrs[:0]
for i := range m.packer.vs {
m.packer.vs[i] = iovec{}
}
m.packer.vs = m.packer.vs[:0]
for i := range m.packer.hs {
m.packer.hs[i].Len = 0
m.packer.hs[i].Hdr = msghdr{}
}
m.packer.hs = m.packer.hs[:0]
return m
}
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
p.p.Put(tmps)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_bsd.go
================================================
// 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 aix || darwin || dragonfly || freebsd || netbsd || openbsd
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
h.setIov(vs)
if len(oob) > 0 {
h.Control = (*byte)(unsafe.Pointer(&oob[0]))
h.Controllen = uint32(len(oob))
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) name() []byte {
if h.Name != nil && h.Namelen > 0 {
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
}
return nil
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_bsdvar.go
================================================
// 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 aix || darwin || dragonfly || freebsd || netbsd
package socket
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = int32(l)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_linux.go
================================================
// 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.
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
h.setIov(vs)
if len(oob) > 0 {
h.setControl(oob)
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) name() []byte {
if h.Name != nil && h.Namelen > 0 {
return (*[sizeofSockaddrInet6]byte)(unsafe.Pointer(h.Name))[:h.Namelen]
}
return nil
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_linux_32bit.go
================================================
// 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 (arm || mips || mipsle || 386 || ppc) && linux
package socket
import "unsafe"
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint32(l)
}
func (h *msghdr) setControl(b []byte) {
h.Control = (*byte)(unsafe.Pointer(&b[0]))
h.Controllen = uint32(len(b))
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_linux_64bit.go
================================================
// 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 (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
package socket
import "unsafe"
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint64(l)
}
func (h *msghdr) setControl(b []byte) {
h.Control = (*byte)(unsafe.Pointer(&b[0]))
h.Controllen = uint64(len(b))
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_openbsd.go
================================================
// 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.
package socket
func (h *msghdr) setIov(vs []iovec) {
l := len(vs)
if l == 0 {
return
}
h.Iov = &vs[0]
h.Iovlen = uint32(l)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_solaris_64bit.go
================================================
// 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 amd64 && solaris
package socket
import (
"encoding/binary"
"unsafe"
)
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
if len(vs) > 0 {
h.Iov = &vs[0]
h.Iovlen = int32(len(vs))
}
if len(oob) > 0 {
h.Accrights = (*int8)(unsafe.Pointer(&oob[0]))
h.Accrightslen = int32(len(oob))
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) controllen() int {
return int(h.Accrightslen)
}
func (h *msghdr) flags() int {
return int(binary.NativeEndian.Uint32(h.Pad_cgo_2[:]))
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
package socket
type msghdr struct{}
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {}
func (h *msghdr) name() []byte { return nil }
func (h *msghdr) controllen() int { return 0 }
func (h *msghdr) flags() int { return 0 }
================================================
FILE: vendor/golang.org/x/net/internal/socket/msghdr_zos_s390x.go
================================================
// 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 s390x && zos
package socket
import "unsafe"
func (h *msghdr) pack(vs []iovec, bs [][]byte, oob []byte, sa []byte) {
for i := range vs {
vs[i].set(bs[i])
}
if len(vs) > 0 {
h.Iov = &vs[0]
h.Iovlen = int32(len(vs))
}
if len(oob) > 0 {
h.Control = (*byte)(unsafe.Pointer(&oob[0]))
h.Controllen = uint32(len(oob))
}
if sa != nil {
h.Name = (*byte)(unsafe.Pointer(&sa[0]))
h.Namelen = uint32(len(sa))
}
}
func (h *msghdr) controllen() int {
return int(h.Controllen)
}
func (h *msghdr) flags() int {
return int(h.Flags)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/norace.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !race
package socket
func (m *Message) raceRead() {
}
func (m *Message) raceWrite() {
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/race.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build race
package socket
import (
"runtime"
"unsafe"
)
// This package reads and writes the Message buffers using a
// direct system call, which the race detector can't see.
// These functions tell the race detector what is going on during the syscall.
func (m *Message) raceRead() {
for _, b := range m.Buffers {
if len(b) > 0 {
runtime.RaceReadRange(unsafe.Pointer(&b[0]), len(b))
}
}
if b := m.OOB; len(b) > 0 {
runtime.RaceReadRange(unsafe.Pointer(&b[0]), len(b))
}
}
func (m *Message) raceWrite() {
for _, b := range m.Buffers {
if len(b) > 0 {
runtime.RaceWriteRange(unsafe.Pointer(&b[0]), len(b))
}
}
if b := m.OOB; len(b) > 0 {
runtime.RaceWriteRange(unsafe.Pointer(&b[0]), len(b))
}
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/rawconn.go
================================================
// 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.
package socket
import (
"errors"
"net"
"os"
"syscall"
)
// A Conn represents a raw connection.
type Conn struct {
network string
c syscall.RawConn
}
// tcpConn is an interface implemented by net.TCPConn.
// It can be used for interface assertions to check if a net.Conn is a TCP connection.
type tcpConn interface {
SyscallConn() (syscall.RawConn, error)
SetLinger(int) error
}
var _ tcpConn = (*net.TCPConn)(nil)
// udpConn is an interface implemented by net.UDPConn.
// It can be used for interface assertions to check if a net.Conn is a UDP connection.
type udpConn interface {
SyscallConn() (syscall.RawConn, error)
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
}
var _ udpConn = (*net.UDPConn)(nil)
// ipConn is an interface implemented by net.IPConn.
// It can be used for interface assertions to check if a net.Conn is an IP connection.
type ipConn interface {
SyscallConn() (syscall.RawConn, error)
ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *net.IPAddr, err error)
}
var _ ipConn = (*net.IPConn)(nil)
// NewConn returns a new raw connection.
func NewConn(c net.Conn) (*Conn, error) {
var err error
var cc Conn
switch c := c.(type) {
case tcpConn:
cc.network = "tcp"
cc.c, err = c.SyscallConn()
case udpConn:
cc.network = "udp"
cc.c, err = c.SyscallConn()
case ipConn:
cc.network = "ip"
cc.c, err = c.SyscallConn()
default:
return nil, errors.New("unknown connection type")
}
if err != nil {
return nil, err
}
return &cc, nil
}
func (o *Option) get(c *Conn, b []byte) (int, error) {
var operr error
var n int
fn := func(s uintptr) {
n, operr = getsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return 0, err
}
return n, os.NewSyscallError("getsockopt", operr)
}
func (o *Option) set(c *Conn, b []byte) error {
var operr error
fn := func(s uintptr) {
operr = setsockopt(s, o.Level, o.Name, b)
}
if err := c.c.Control(fn); err != nil {
return err
}
return os.NewSyscallError("setsockopt", operr)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/rawconn_mmsg.go
================================================
// 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 linux
package socket
import (
"net"
)
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
for i := range ms {
ms[i].raceWrite()
}
tmps := defaultMmsgTmpsPool.Get()
defer defaultMmsgTmpsPool.Put(tmps)
var parseFn func([]byte, string) (net.Addr, error)
if c.network != "tcp" {
parseFn = parseInetAddr
}
hs := tmps.packer.pack(ms, parseFn, nil)
n, err := tmps.syscaller.recvmmsg(c.c, hs, flags)
if err != nil {
return n, err
}
if err := hs[:n].unpack(ms[:n], parseFn, c.network); err != nil {
return n, err
}
return n, nil
}
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
for i := range ms {
ms[i].raceRead()
}
tmps := defaultMmsgTmpsPool.Get()
defer defaultMmsgTmpsPool.Put(tmps)
var marshalFn func(net.Addr, []byte) int
if c.network != "tcp" {
marshalFn = marshalInetAddr
}
hs := tmps.packer.pack(ms, nil, marshalFn)
n, err := tmps.syscaller.sendmmsg(c.c, hs, flags)
if err != nil {
return n, err
}
if err := hs[:n].unpack(ms[:n], nil, ""); err != nil {
return n, err
}
return n, nil
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/rawconn_msg.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package socket
import (
"net"
"os"
)
func (c *Conn) recvMsg(m *Message, flags int) error {
m.raceWrite()
var (
operr error
n int
oobn int
recvflags int
from net.Addr
)
fn := func(s uintptr) bool {
n, oobn, recvflags, from, operr = recvmsg(s, m.Buffers, m.OOB, flags, c.network)
return ioComplete(flags, operr)
}
if err := c.c.Read(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("recvmsg", operr)
}
m.Addr = from
m.N = n
m.NN = oobn
m.Flags = recvflags
return nil
}
func (c *Conn) sendMsg(m *Message, flags int) error {
m.raceRead()
var (
operr error
n int
)
fn := func(s uintptr) bool {
n, operr = sendmsg(s, m.Buffers, m.OOB, m.Addr, flags)
return ioComplete(flags, operr)
}
if err := c.c.Write(fn); err != nil {
return err
}
if operr != nil {
return os.NewSyscallError("sendmsg", operr)
}
m.N = n
m.NN = len(m.OOB)
return nil
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/rawconn_nommsg.go
================================================
// 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 !linux
package socket
func (c *Conn) recvMsgs(ms []Message, flags int) (int, error) {
return 0, errNotImplemented
}
func (c *Conn) sendMsgs(ms []Message, flags int) (int, error) {
return 0, errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/rawconn_nomsg.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package socket
func (c *Conn) recvMsg(m *Message, flags int) error {
return errNotImplemented
}
func (c *Conn) sendMsg(m *Message, flags int) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/socket.go
================================================
// 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.
// Package socket provides a portable interface for socket system
// calls.
package socket // import "golang.org/x/net/internal/socket"
import (
"encoding/binary"
"errors"
"net"
"runtime"
"unsafe"
)
var errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
// An Option represents a sticky socket option.
type Option struct {
Level int // level
Name int // name; must be equal or greater than 1
Len int // length of value in bytes; must be equal or greater than 1
}
// Get reads a value for the option from the kernel.
// It returns the number of bytes written into b.
func (o *Option) Get(c *Conn, b []byte) (int, error) {
if o.Name < 1 || o.Len < 1 {
return 0, errors.New("invalid option")
}
if len(b) < o.Len {
return 0, errors.New("short buffer")
}
return o.get(c, b)
}
// GetInt returns an integer value for the option.
//
// The Len field of Option must be either 1 or 4.
func (o *Option) GetInt(c *Conn) (int, error) {
if o.Len != 1 && o.Len != 4 {
return 0, errors.New("invalid option")
}
var b []byte
var bb [4]byte
if o.Len == 1 {
b = bb[:1]
} else {
b = bb[:4]
}
n, err := o.get(c, b)
if err != nil {
return 0, err
}
if n != o.Len {
return 0, errors.New("invalid option length")
}
if o.Len == 1 {
return int(b[0]), nil
}
return int(binary.NativeEndian.Uint32(b[:4])), nil
}
// Set writes the option and value to the kernel.
func (o *Option) Set(c *Conn, b []byte) error {
if o.Name < 1 || o.Len < 1 {
return errors.New("invalid option")
}
if len(b) < o.Len {
return errors.New("short buffer")
}
return o.set(c, b)
}
// SetInt writes the option and value to the kernel.
//
// The Len field of Option must be either 1 or 4.
func (o *Option) SetInt(c *Conn, v int) error {
if o.Len != 1 && o.Len != 4 {
return errors.New("invalid option")
}
var b []byte
if o.Len == 1 {
b = []byte{byte(v)}
} else {
var bb [4]byte
binary.NativeEndian.PutUint32(bb[:o.Len], uint32(v))
b = bb[:4]
}
return o.set(c, b)
}
// ControlMessageSpace returns the whole length of control message.
func ControlMessageSpace(dataLen int) int {
return controlMessageSpace(dataLen)
}
// A ControlMessage represents the head message in a stream of control
// messages.
//
// A control message comprises of a header, data and a few padding
// fields to conform to the interface to the kernel.
//
// See RFC 3542 for further information.
type ControlMessage []byte
// Data returns the data field of the control message at the head on
// m.
func (m ControlMessage) Data(dataLen int) []byte {
l := controlHeaderLen()
if len(m) < l || len(m) < l+dataLen {
return nil
}
return m[l : l+dataLen]
}
// Next returns the control message at the next on m.
//
// Next works only for standard control messages.
func (m ControlMessage) Next(dataLen int) ControlMessage {
l := ControlMessageSpace(dataLen)
if len(m) < l {
return nil
}
return m[l:]
}
// MarshalHeader marshals the header fields of the control message at
// the head on m.
func (m ControlMessage) MarshalHeader(lvl, typ, dataLen int) error {
if len(m) < controlHeaderLen() {
return errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(dataLen), lvl, typ)
return nil
}
// ParseHeader parses and returns the header fields of the control
// message at the head on m.
func (m ControlMessage) ParseHeader() (lvl, typ, dataLen int, err error) {
l := controlHeaderLen()
if len(m) < l {
return 0, 0, 0, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
return h.lvl(), h.typ(), int(uint64(h.len()) - uint64(l)), nil
}
// Marshal marshals the control message at the head on m, and returns
// the next control message.
func (m ControlMessage) Marshal(lvl, typ int, data []byte) (ControlMessage, error) {
l := len(data)
if len(m) < ControlMessageSpace(l) {
return nil, errors.New("short message")
}
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
h.set(controlMessageLen(l), lvl, typ)
if l > 0 {
copy(m.Data(l), data)
}
return m.Next(l), nil
}
// Parse parses m as a single or multiple control messages.
//
// Parse works for both standard and compatible messages.
func (m ControlMessage) Parse() ([]ControlMessage, error) {
var ms []ControlMessage
for len(m) >= controlHeaderLen() {
h := (*cmsghdr)(unsafe.Pointer(&m[0]))
l := h.len()
if l <= 0 {
return nil, errors.New("invalid header length")
}
if uint64(l) < uint64(controlHeaderLen()) {
return nil, errors.New("invalid message length")
}
if uint64(l) > uint64(len(m)) {
return nil, errors.New("short buffer")
}
// On message reception:
//
// |<- ControlMessageSpace --------------->|
// |<- controlMessageLen ---------->| |
// |<- controlHeaderLen ->| | |
// +---------------+------+---------+------+
// | Header | PadH | Data | PadD |
// +---------------+------+---------+------+
//
// On compatible message reception:
//
// | ... |<- controlMessageLen ----------->|
// | ... |<- controlHeaderLen ->| |
// +-----+---------------+------+----------+
// | ... | Header | PadH | Data |
// +-----+---------------+------+----------+
ms = append(ms, ControlMessage(m[:l]))
ll := l - controlHeaderLen()
if len(m) >= ControlMessageSpace(ll) {
m = m[ControlMessageSpace(ll):]
} else {
m = m[controlMessageLen(ll):]
}
}
return ms, nil
}
// NewControlMessage returns a new stream of control messages.
func NewControlMessage(dataLen []int) ControlMessage {
var l int
for i := range dataLen {
l += ControlMessageSpace(dataLen[i])
}
return make([]byte, l)
}
// A Message represents an IO message.
type Message struct {
// When writing, the Buffers field must contain at least one
// byte to write.
// When reading, the Buffers field will always contain a byte
// to read.
Buffers [][]byte
// OOB contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
OOB []byte
// Addr specifies a destination address when writing.
// It can be nil when the underlying protocol of the raw
// connection uses connection-oriented communication.
// After a successful read, it may contain the source address
// on the received packet.
Addr net.Addr
N int // # of bytes read or written from/to Buffers
NN int // # of bytes read or written from/to OOB
Flags int // protocol-specific information on the received message
}
// RecvMsg wraps recvmsg system call.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
func (c *Conn) RecvMsg(m *Message, flags int) error {
return c.recvMsg(m, flags)
}
// SendMsg wraps sendmsg system call.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
func (c *Conn) SendMsg(m *Message, flags int) error {
return c.sendMsg(m, flags)
}
// RecvMsgs wraps recvmmsg system call.
//
// It returns the number of processed messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// Only Linux supports this.
func (c *Conn) RecvMsgs(ms []Message, flags int) (int, error) {
return c.recvMsgs(ms, flags)
}
// SendMsgs wraps sendmmsg system call.
//
// It returns the number of processed messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// Only Linux supports this.
func (c *Conn) SendMsgs(ms []Message, flags int) (int, error) {
return c.sendMsgs(ms, flags)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_bsd.go
================================================
// 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 aix || darwin || dragonfly || freebsd || openbsd || solaris
package socket
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_const_unix.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package socket
import "golang.org/x/sys/unix"
const (
sysAF_UNSPEC = unix.AF_UNSPEC
sysAF_INET = unix.AF_INET
sysAF_INET6 = unix.AF_INET6
sysSOCK_RAW = unix.SOCK_RAW
sizeofSockaddrInet4 = unix.SizeofSockaddrInet4
sizeofSockaddrInet6 = unix.SizeofSockaddrInet6
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux.go
================================================
// 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 linux && !s390x && !386
package socket
import (
"syscall"
"unsafe"
)
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_386.go
================================================
// 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.
package socket
import (
"syscall"
"unsafe"
)
const (
sysRECVMMSG = 0x13
sysSENDMMSG = 0x14
)
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
func rawsocketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, errno := socketcall(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, errno := socketcall(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_386.s
================================================
// 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.
#include "textflag.h"
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_amd64.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x12b
sysSENDMMSG = 0x133
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_arm.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x16d
sysSENDMMSG = 0x176
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_arm64.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0xf3
sysSENDMMSG = 0x10d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_loong64.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build loong64
package socket
const (
sysRECVMMSG = 0xf3
sysSENDMMSG = 0x10d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_mips.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x10ef
sysSENDMMSG = 0x10f7
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_mips64.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x14ae
sysSENDMMSG = 0x14b6
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_mips64le.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x14ae
sysSENDMMSG = 0x14b6
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_mipsle.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x10ef
sysSENDMMSG = 0x10f7
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_ppc.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socket
const (
sysRECVMMSG = 0x157
sysSENDMMSG = 0x15d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_ppc64.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x157
sysSENDMMSG = 0x15d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_ppc64le.go
================================================
// 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.
package socket
const (
sysRECVMMSG = 0x157
sysSENDMMSG = 0x15d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_riscv64.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build riscv64
package socket
const (
sysRECVMMSG = 0xf3
sysSENDMMSG = 0x10d
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_s390x.go
================================================
// 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.
package socket
import (
"syscall"
"unsafe"
)
const (
sysRECVMMSG = 0x13
sysSENDMMSG = 0x14
)
func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
func rawsocketcall(call, a0, a1, a2, a3, a4, a5 uintptr) (uintptr, syscall.Errno)
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, errno := socketcall(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, errno := socketcall(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_linux_s390x.s
================================================
// 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.
#include "textflag.h"
TEXT ·socketcall(SB),NOSPLIT,$0-72
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-72
JMP syscall·rawsocketcall(SB)
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_netbsd.go
================================================
// 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.
package socket
import (
"syscall"
"unsafe"
)
const (
sysRECVMMSG = 0x1db
sysSENDMMSG = 0x1dc
)
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysRECVMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
n, _, errno := syscall.Syscall6(sysSENDMMSG, s, uintptr(unsafe.Pointer(&hs[0])), uintptr(len(hs)), uintptr(flags), 0, 0)
return int(n), errnoErr(errno)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_posix.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package socket
import (
"encoding/binary"
"errors"
"net"
"runtime"
"strconv"
"sync"
"time"
)
// marshalInetAddr writes a in sockaddr format into the buffer b.
// The buffer must be sufficiently large (sizeofSockaddrInet4/6).
// Returns the number of bytes written.
func marshalInetAddr(a net.Addr, b []byte) int {
switch a := a.(type) {
case *net.TCPAddr:
return marshalSockaddr(a.IP, a.Port, a.Zone, b)
case *net.UDPAddr:
return marshalSockaddr(a.IP, a.Port, a.Zone, b)
case *net.IPAddr:
return marshalSockaddr(a.IP, 0, a.Zone, b)
default:
return 0
}
}
func marshalSockaddr(ip net.IP, port int, zone string, b []byte) int {
if ip4 := ip.To4(); ip4 != nil {
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
binary.NativeEndian.PutUint16(b[:2], uint16(sysAF_INET))
default:
b[0] = sizeofSockaddrInet4
b[1] = sysAF_INET
}
binary.BigEndian.PutUint16(b[2:4], uint16(port))
copy(b[4:8], ip4)
return sizeofSockaddrInet4
}
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
binary.NativeEndian.PutUint16(b[:2], uint16(sysAF_INET6))
default:
b[0] = sizeofSockaddrInet6
b[1] = sysAF_INET6
}
binary.BigEndian.PutUint16(b[2:4], uint16(port))
copy(b[8:24], ip6)
if zone != "" {
binary.NativeEndian.PutUint32(b[24:28], uint32(zoneCache.index(zone)))
}
return sizeofSockaddrInet6
}
return 0
}
func parseInetAddr(b []byte, network string) (net.Addr, error) {
if len(b) < 2 {
return nil, errors.New("invalid address")
}
var af int
switch runtime.GOOS {
case "android", "illumos", "linux", "solaris", "windows":
af = int(binary.NativeEndian.Uint16(b[:2]))
default:
af = int(b[1])
}
var ip net.IP
var zone string
if af == sysAF_INET {
if len(b) < sizeofSockaddrInet4 {
return nil, errors.New("short address")
}
ip = make(net.IP, net.IPv4len)
copy(ip, b[4:8])
}
if af == sysAF_INET6 {
if len(b) < sizeofSockaddrInet6 {
return nil, errors.New("short address")
}
ip = make(net.IP, net.IPv6len)
copy(ip, b[8:24])
if id := int(binary.NativeEndian.Uint32(b[24:28])); id > 0 {
zone = zoneCache.name(id)
}
}
switch network {
case "tcp", "tcp4", "tcp6":
return &net.TCPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
case "udp", "udp4", "udp6":
return &net.UDPAddr{IP: ip, Port: int(binary.BigEndian.Uint16(b[2:4])), Zone: zone}, nil
default:
return &net.IPAddr{IP: ip, Zone: zone}, nil
}
}
// An ipv6ZoneCache represents a cache holding partial network
// interface information. It is used for reducing the cost of IPv6
// addressing scope zone resolution.
//
// Multiple names sharing the index are managed by first-come
// first-served basis for consistency.
type ipv6ZoneCache struct {
sync.RWMutex // guard the following
lastFetched time.Time // last time routing information was fetched
toIndex map[string]int // interface name to its index
toName map[int]string // interface index to its name
}
var zoneCache = ipv6ZoneCache{
toIndex: make(map[string]int),
toName: make(map[int]string),
}
// update refreshes the network interface information if the cache was last
// updated more than 1 minute ago, or if force is set. It returns whether the
// cache was updated.
func (zc *ipv6ZoneCache) update(ift []net.Interface, force bool) (updated bool) {
zc.Lock()
defer zc.Unlock()
now := time.Now()
if !force && zc.lastFetched.After(now.Add(-60*time.Second)) {
return false
}
zc.lastFetched = now
if len(ift) == 0 {
var err error
if ift, err = net.Interfaces(); err != nil {
return false
}
}
zc.toIndex = make(map[string]int, len(ift))
zc.toName = make(map[int]string, len(ift))
for _, ifi := range ift {
zc.toIndex[ifi.Name] = ifi.Index
if _, ok := zc.toName[ifi.Index]; !ok {
zc.toName[ifi.Index] = ifi.Name
}
}
return true
}
func (zc *ipv6ZoneCache) name(zone int) string {
updated := zoneCache.update(nil, false)
zoneCache.RLock()
name, ok := zoneCache.toName[zone]
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
name, ok = zoneCache.toName[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
name = strconv.Itoa(zone)
}
return name
}
func (zc *ipv6ZoneCache) index(zone string) int {
updated := zoneCache.update(nil, false)
zoneCache.RLock()
index, ok := zoneCache.toIndex[zone]
zoneCache.RUnlock()
if !ok && !updated {
zoneCache.update(nil, true)
zoneCache.RLock()
index, ok = zoneCache.toIndex[zone]
zoneCache.RUnlock()
}
if !ok { // last resort
index, _ = strconv.Atoi(zone)
}
return index
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package socket
import "net"
const (
sysAF_UNSPEC = 0x0
sysAF_INET = 0x2
sysAF_INET6 = 0xa
sysSOCK_RAW = 0x3
sizeofSockaddrInet4 = 0x10
sizeofSockaddrInet6 = 0x1c
)
func marshalInetAddr(ip net.IP, port int, zone string) []byte {
return nil
}
func parseInetAddr(b []byte, network string) (net.Addr, error) {
return nil, errNotImplemented
}
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
return 0, errNotImplemented
}
func setsockopt(s uintptr, level, name int, b []byte) error {
return errNotImplemented
}
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
return 0, 0, 0, nil, errNotImplemented
}
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
return 0, errNotImplemented
}
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_unix.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package socket
import (
"net"
"unsafe"
"golang.org/x/sys/unix"
)
//go:linkname syscall_getsockopt syscall.getsockopt
func syscall_getsockopt(s, level, name int, val unsafe.Pointer, vallen *uint32) error
//go:linkname syscall_setsockopt syscall.setsockopt
func syscall_setsockopt(s, level, name int, val unsafe.Pointer, vallen uintptr) error
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
l := uint32(len(b))
err := syscall_getsockopt(int(s), level, name, unsafe.Pointer(&b[0]), &l)
return int(l), err
}
func setsockopt(s uintptr, level, name int, b []byte) error {
return syscall_setsockopt(int(s), level, name, unsafe.Pointer(&b[0]), uintptr(len(b)))
}
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
var unixFrom unix.Sockaddr
n, oobn, recvflags, unixFrom, err = unix.RecvmsgBuffers(int(s), buffers, oob, flags)
if unixFrom != nil {
from = sockaddrToAddr(unixFrom, network)
}
return
}
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
var unixTo unix.Sockaddr
if to != nil {
unixTo = addrToSockaddr(to)
}
return unix.SendmsgBuffers(int(s), buffers, oob, unixTo, flags)
}
// addrToSockaddr converts a net.Addr to a unix.Sockaddr.
func addrToSockaddr(a net.Addr) unix.Sockaddr {
var (
ip net.IP
port int
zone string
)
switch a := a.(type) {
case *net.TCPAddr:
ip = a.IP
port = a.Port
zone = a.Zone
case *net.UDPAddr:
ip = a.IP
port = a.Port
zone = a.Zone
case *net.IPAddr:
ip = a.IP
zone = a.Zone
default:
return nil
}
if ip4 := ip.To4(); ip4 != nil {
sa := unix.SockaddrInet4{Port: port}
copy(sa.Addr[:], ip4)
return &sa
}
if ip6 := ip.To16(); ip6 != nil && ip.To4() == nil {
sa := unix.SockaddrInet6{Port: port}
copy(sa.Addr[:], ip6)
if zone != "" {
sa.ZoneId = uint32(zoneCache.index(zone))
}
return &sa
}
return nil
}
// sockaddrToAddr converts a unix.Sockaddr to a net.Addr.
func sockaddrToAddr(sa unix.Sockaddr, network string) net.Addr {
var (
ip net.IP
port int
zone string
)
switch sa := sa.(type) {
case *unix.SockaddrInet4:
ip = make(net.IP, net.IPv4len)
copy(ip, sa.Addr[:])
port = sa.Port
case *unix.SockaddrInet6:
ip = make(net.IP, net.IPv6len)
copy(ip, sa.Addr[:])
port = sa.Port
if sa.ZoneId > 0 {
zone = zoneCache.name(int(sa.ZoneId))
}
default:
return nil
}
switch network {
case "tcp", "tcp4", "tcp6":
return &net.TCPAddr{IP: ip, Port: port, Zone: zone}
case "udp", "udp4", "udp6":
return &net.UDPAddr{IP: ip, Port: port, Zone: zone}
default:
return &net.IPAddr{IP: ip, Zone: zone}
}
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_windows.go
================================================
// 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.
package socket
import (
"net"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
func probeProtocolStack() int {
var p uintptr
return int(unsafe.Sizeof(p))
}
const (
sysAF_UNSPEC = windows.AF_UNSPEC
sysAF_INET = windows.AF_INET
sysAF_INET6 = windows.AF_INET6
sysSOCK_RAW = windows.SOCK_RAW
sizeofSockaddrInet4 = 0x10
sizeofSockaddrInet6 = 0x1c
)
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
l := uint32(len(b))
err := syscall.Getsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(unsafe.Pointer(&b[0])), (*int32)(unsafe.Pointer(&l)))
return int(l), err
}
func setsockopt(s uintptr, level, name int, b []byte) error {
return syscall.Setsockopt(syscall.Handle(s), int32(level), int32(name), (*byte)(unsafe.Pointer(&b[0])), int32(len(b)))
}
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
return 0, 0, 0, nil, errNotImplemented
}
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
return 0, errNotImplemented
}
func recvmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
func sendmmsg(s uintptr, hs []mmsghdr, flags int) (int, error) {
return 0, errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_zos_s390x.go
================================================
// 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.
package socket
import (
"net"
"syscall"
"unsafe"
)
func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
func syscall_syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
func probeProtocolStack() int {
return 4 // sizeof(int) on GOOS=zos GOARCH=s390x
}
func getsockopt(s uintptr, level, name int, b []byte) (int, error) {
l := uint32(len(b))
_, _, errno := syscall_syscall6(syscall.SYS_GETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(unsafe.Pointer(&l)), 0)
return int(l), errnoErr(errno)
}
func setsockopt(s uintptr, level, name int, b []byte) error {
_, _, errno := syscall_syscall6(syscall.SYS_SETSOCKOPT, s, uintptr(level), uintptr(name), uintptr(unsafe.Pointer(&b[0])), uintptr(len(b)), 0)
return errnoErr(errno)
}
func recvmsg(s uintptr, buffers [][]byte, oob []byte, flags int, network string) (n, oobn int, recvflags int, from net.Addr, err error) {
var h msghdr
vs := make([]iovec, len(buffers))
var sa []byte
if network != "tcp" {
sa = make([]byte, sizeofSockaddrInet6)
}
h.pack(vs, buffers, oob, sa)
sn, _, errno := syscall_syscall(syscall.SYS___RECVMSG_A, s, uintptr(unsafe.Pointer(&h)), uintptr(flags))
n = int(sn)
oobn = h.controllen()
recvflags = h.flags()
err = errnoErr(errno)
if network != "tcp" {
var err2 error
from, err2 = parseInetAddr(sa, network)
if err2 != nil && err == nil {
err = err2
}
}
return
}
func sendmsg(s uintptr, buffers [][]byte, oob []byte, to net.Addr, flags int) (int, error) {
var h msghdr
vs := make([]iovec, len(buffers))
var sa []byte
if to != nil {
var a [sizeofSockaddrInet6]byte
n := marshalInetAddr(to, a[:])
sa = a[:n]
}
h.pack(vs, buffers, oob, sa)
n, _, errno := syscall_syscall(syscall.SYS___SENDMSG_A, s, uintptr(unsafe.Pointer(&h)), uintptr(flags))
return int(n), errnoErr(errno)
}
================================================
FILE: vendor/golang.org/x/net/internal/socket/sys_zos_s390x.s
================================================
// 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.
#include "textflag.h"
TEXT ·syscall_syscall(SB),NOSPLIT,$0
JMP syscall·_syscall(SB)
TEXT ·syscall_syscall6(SB),NOSPLIT,$0
JMP syscall·_syscall6(SB)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_aix_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_aix.go
// Added for go1.11 compatibility
//go:build aix
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_darwin_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_darwin_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_dragonfly_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_dragonfly.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_freebsd_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_freebsd_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_freebsd_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_freebsd_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_loong64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build loong64
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_0 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_mips.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_mips64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_mips64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_mipsle.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_ppc.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_ppc64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build riscv64
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_0 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_linux_s390x.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint64
Control *byte
Controllen uint64
Flags int32
Pad_cgo_1 [4]byte
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint64
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x38
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_netbsd_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_netbsd_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen int32
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_netbsd_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
Pad_cgo_0 [4]byte
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint32
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen uint32
Pad_cgo_1 [4]byte
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_mips64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_openbsd_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Iov *iovec
Iovlen uint32
Control *byte
Controllen uint32
Flags int32
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_solaris_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_solaris.go
package socket
type iovec struct {
Base *int8
Len uint64
}
type msghdr struct {
Name *byte
Namelen uint32
Pad_cgo_0 [4]byte
Iov *iovec
Iovlen int32
Pad_cgo_1 [4]byte
Accrights *int8
Accrightslen int32
Pad_cgo_2 [4]byte
}
type cmsghdr struct {
Len uint32
Level int32
Type int32
}
const (
sizeofIovec = 0x10
sizeofMsghdr = 0x30
)
================================================
FILE: vendor/golang.org/x/net/internal/socket/zsys_zos_s390x.go
================================================
// 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.
package socket
type iovec struct {
Base *byte
Len uint64
}
type msghdr struct {
Name *byte
Iov *iovec
Control *byte
Flags int32
Namelen uint32
Iovlen int32
Controllen uint32
}
type cmsghdr struct {
Len int32
Level int32
Type int32
}
const sizeofCmsghdr = 12
================================================
FILE: vendor/golang.org/x/net/ipv4/batch.go
================================================
// 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.
package ipv4
import (
"net"
"runtime"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// PacketConn are not implemented.
// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// RawConn are not implemented.
// A Message represents an IO message.
//
// type Message struct {
// Buffers [][]byte
// OOB []byte
// Addr net.Addr
// N int
// NN int
// Flags int
// }
//
// The Buffers fields represents a list of contiguous buffers, which
// can be used for vectored IO, for example, putting a header and a
// payload in each slice.
// When writing, the Buffers field must contain at least one byte to
// write.
// When reading, the Buffers field will always contain a byte to read.
//
// The OOB field contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
// It can be nil when not required.
//
// The Addr field specifies a destination address when writing.
// It can be nil when the underlying protocol of the endpoint uses
// connection-oriented communication.
// After a successful read, it may contain the source address on the
// received packet.
//
// The N field indicates the number of bytes read or written from/to
// Buffers.
//
// The NN field indicates the number of bytes read or written from/to
// OOB.
//
// The Flags field contains protocol-specific information on the
// received message.
type Message = socket.Message
// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
//
// Unlike the ReadFrom method, it doesn't strip the IPv4 header
// followed by option headers from the received IPv4 datagram when the
// underlying transport is net.IPConn. Each Buffers field of Message
// must be large enough to accommodate an IPv4 header and option
// headers.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.RecvMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.RecvMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
if compatFreeBSD32 && ms[0].NN > 0 {
adjustFreeBSD32(&ms[0])
}
return n, err
}
}
// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.SendMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.SendMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
}
}
// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.RecvMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.RecvMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
if compatFreeBSD32 && ms[0].NN > 0 {
adjustFreeBSD32(&ms[0])
}
return n, err
}
}
// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *packetHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.SendMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.SendMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
return n, err
}
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control.go
================================================
// Copyright 2012 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 ipv4
import (
"fmt"
"net"
"sync"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
)
type rawOpt struct {
sync.RWMutex
cflags ControlFlags
}
func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
type ControlFlags uint
const (
FlagTTL ControlFlags = 1 << iota // pass the TTL on the received packet
FlagSrc // pass the source address on the received packet
FlagDst // pass the destination address on the received packet
FlagInterface // pass the interface index on the received packet
)
// A ControlMessage represents per packet basis IP-level socket options.
type ControlMessage struct {
// Receiving socket options: SetControlMessage allows to
// receive the options from the protocol stack using ReadFrom
// method of PacketConn or RawConn.
//
// Specifying socket options: ControlMessage for WriteTo
// method of PacketConn or RawConn allows to send the options
// to the protocol stack.
//
TTL int // time-to-live, receiving only
Src net.IP // source address, specifying only
Dst net.IP // destination address, receiving only
IfIndex int // interface index, must be 1 <= value when specifying
}
func (cm *ControlMessage) String() string {
if cm == nil {
return ""
}
return fmt.Sprintf("ttl=%d src=%v dst=%v ifindex=%d", cm.TTL, cm.Src, cm.Dst, cm.IfIndex)
}
// Marshal returns the binary encoding of cm.
func (cm *ControlMessage) Marshal() []byte {
if cm == nil {
return nil
}
var m socket.ControlMessage
if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To4() != nil || cm.IfIndex > 0) {
m = socket.NewControlMessage([]int{ctlOpts[ctlPacketInfo].length})
}
if len(m) > 0 {
ctlOpts[ctlPacketInfo].marshal(m, cm)
}
return m
}
// Parse parses b as a control message and stores the result in cm.
func (cm *ControlMessage) Parse(b []byte) error {
ms, err := socket.ControlMessage(b).Parse()
if err != nil {
return err
}
for _, m := range ms {
lvl, typ, l, err := m.ParseHeader()
if err != nil {
return err
}
if lvl != iana.ProtocolIP {
continue
}
switch {
case typ == ctlOpts[ctlTTL].name && l >= ctlOpts[ctlTTL].length:
ctlOpts[ctlTTL].parse(cm, m.Data(l))
case typ == ctlOpts[ctlDst].name && l >= ctlOpts[ctlDst].length:
ctlOpts[ctlDst].parse(cm, m.Data(l))
case typ == ctlOpts[ctlInterface].name && l >= ctlOpts[ctlInterface].length:
ctlOpts[ctlInterface].parse(cm, m.Data(l))
case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
}
}
return nil
}
// NewControlMessage returns a new control message.
//
// The returned message is large enough for options specified by cf.
func NewControlMessage(cf ControlFlags) []byte {
opt := rawOpt{cflags: cf}
var l int
if opt.isset(FlagTTL) && ctlOpts[ctlTTL].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlTTL].length)
}
if ctlOpts[ctlPacketInfo].name > 0 {
if opt.isset(FlagSrc | FlagDst | FlagInterface) {
l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
}
} else {
if opt.isset(FlagDst) && ctlOpts[ctlDst].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlDst].length)
}
if opt.isset(FlagInterface) && ctlOpts[ctlInterface].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlInterface].length)
}
}
var b []byte
if l > 0 {
b = make([]byte, l)
}
return b
}
// Ancillary data socket options
const (
ctlTTL = iota // header field
ctlSrc // header field
ctlDst // header field
ctlInterface // inbound or outbound interface
ctlPacketInfo // inbound or outbound packet path
ctlMax
)
// A ctlOpt represents a binding for ancillary data socket option.
type ctlOpt struct {
name int // option name, must be equal or greater than 1
length int // option length
marshal func([]byte, *ControlMessage) []byte
parse func(*ControlMessage, []byte)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_bsd.go
================================================
// Copyright 2012 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 aix || darwin || dragonfly || freebsd || netbsd || openbsd
package ipv4
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshalDst(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, unix.IP_RECVDSTADDR, net.IPv4len)
return m.Next(net.IPv4len)
}
func parseDst(cm *ControlMessage, b []byte) {
if len(cm.Dst) < net.IPv4len {
cm.Dst = make(net.IP, net.IPv4len)
}
copy(cm.Dst, b[:net.IPv4len])
}
func marshalInterface(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, sockoptReceiveInterface, syscall.SizeofSockaddrDatalink)
return m.Next(syscall.SizeofSockaddrDatalink)
}
func parseInterface(cm *ControlMessage, b []byte) {
var sadl syscall.SockaddrDatalink
copy((*[unsafe.Sizeof(sadl)]byte)(unsafe.Pointer(&sadl))[:], b)
cm.IfIndex = int(sadl.Index)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_pktinfo.go
================================================
// 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 darwin || linux || solaris
package ipv4
import (
"net"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, unix.IP_PKTINFO, sizeofInetPktinfo)
if cm != nil {
pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.Spec_dst[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInetPktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*inetPktinfo)(unsafe.Pointer(&b[0]))
cm.IfIndex = int(pi.Ifindex)
if len(cm.Dst) < net.IPv4len {
cm.Dst = make(net.IP, net.IPv4len)
}
copy(cm.Dst, pi.Addr[:])
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_stub.go
================================================
// Copyright 2012 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv4
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_unix.go
================================================
// Copyright 2012 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
package ipv4
import (
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if so, ok := sockOpts[ssoReceiveTTL]; ok && cf&FlagTTL != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagTTL)
} else {
opt.clear(FlagTTL)
}
}
if so, ok := sockOpts[ssoPacketInfo]; ok {
if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
} else {
opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
}
}
} else {
if so, ok := sockOpts[ssoReceiveDst]; ok && cf&FlagDst != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagDst)
} else {
opt.clear(FlagDst)
}
}
if so, ok := sockOpts[ssoReceiveInterface]; ok && cf&FlagInterface != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagInterface)
} else {
opt.clear(FlagInterface)
}
}
}
return nil
}
func marshalTTL(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, unix.IP_RECVTTL, 1)
return m.Next(1)
}
func parseTTL(cm *ControlMessage, b []byte) {
cm.TTL = int(*(*byte)(unsafe.Pointer(&b[:1][0])))
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_windows.go
================================================
// Copyright 2012 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 ipv4
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
// TODO(mikio): implement this
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/control_zos.go
================================================
// 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.
package ipv4
import (
"net"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIP, unix.IP_PKTINFO, sizeofInetPktinfo)
if cm != nil {
pi := (*inetPktinfo)(unsafe.Pointer(&m.Data(sizeofInetPktinfo)[0]))
if ip := cm.Src.To4(); ip != nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInetPktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*inetPktinfo)(unsafe.Pointer(&b[0]))
cm.IfIndex = int(pi.Ifindex)
if len(cm.Dst) < net.IPv4len {
cm.Dst = make(net.IP, net.IPv4len)
}
copy(cm.Dst, pi.Addr[:])
}
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if so, ok := sockOpts[ssoReceiveTTL]; ok && cf&FlagTTL != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagTTL)
} else {
opt.clear(FlagTTL)
}
}
if so, ok := sockOpts[ssoPacketInfo]; ok {
if cf&(FlagSrc|FlagDst|FlagInterface) != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(cf & (FlagSrc | FlagDst | FlagInterface))
} else {
opt.clear(cf & (FlagSrc | FlagDst | FlagInterface))
}
}
} else {
if so, ok := sockOpts[ssoReceiveDst]; ok && cf&FlagDst != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagDst)
} else {
opt.clear(FlagDst)
}
}
if so, ok := sockOpts[ssoReceiveInterface]; ok && cf&FlagInterface != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagInterface)
} else {
opt.clear(FlagInterface)
}
}
}
return nil
}
================================================
FILE: vendor/golang.org/x/net/ipv4/dgramopt.go
================================================
// Copyright 2012 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 ipv4
import (
"net"
"golang.org/x/net/bpf"
)
// MulticastTTL returns the time-to-live field value for outgoing
// multicast packets.
func (c *dgramOpt) MulticastTTL() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoMulticastTTL]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetMulticastTTL sets the time-to-live field value for future
// outgoing multicast packets.
func (c *dgramOpt) SetMulticastTTL(ttl int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastTTL]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, ttl)
}
// MulticastInterface returns the default interface for multicast
// packet transmissions.
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return nil, errNotImplemented
}
return so.getMulticastInterface(c.Conn)
}
// SetMulticastInterface sets the default interface for future
// multicast packet transmissions.
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return errNotImplemented
}
return so.setMulticastInterface(c.Conn, ifi)
}
// MulticastLoopback reports whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) MulticastLoopback() (bool, error) {
if !c.ok() {
return false, errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return false, errNotImplemented
}
on, err := so.GetInt(c.Conn)
if err != nil {
return false, err
}
return on == 1, nil
}
// SetMulticastLoopback sets whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, boolint(on))
}
// JoinGroup joins the group address group on the interface ifi.
// By default all sources that can cast data to group are accepted.
// It's possible to mute and unmute data transmission from a specific
// source by using ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup.
// JoinGroup uses the system assigned multicast interface when ifi is
// nil, although this is not recommended because the assignment
// depends on platforms and sometimes it might require routing
// configuration.
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// LeaveGroup leaves the group address group on the interface ifi
// regardless of whether the group is any-source group or
// source-specific group.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// JoinSourceSpecificGroup joins the source-specific group comprising
// group and source on the interface ifi.
// JoinSourceSpecificGroup uses the system assigned multicast
// interface when ifi is nil, although this is not recommended because
// the assignment depends on platforms and sometimes it might require
// routing configuration.
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP4(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// LeaveSourceSpecificGroup leaves the source-specific group on the
// interface ifi.
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP4(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// ExcludeSourceSpecificGroup excludes the source-specific group from
// the already joined any-source groups by JoinGroup on the interface
// ifi.
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoBlockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP4(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// IncludeSourceSpecificGroup includes the excluded source-specific
// group by ExcludeSourceSpecificGroup again on the interface ifi.
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoUnblockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP4(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP4(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// ICMPFilter returns an ICMP filter.
// Currently only Linux supports this.
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return nil, errNotImplemented
}
return so.getICMPFilter(c.Conn)
}
// SetICMPFilter deploys the ICMP filter.
// Currently only Linux supports this.
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return errNotImplemented
}
return so.setICMPFilter(c.Conn, f)
}
// SetBPF attaches a BPF program to the connection.
//
// Only supported on Linux.
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoAttachFilter]
if !ok {
return errNotImplemented
}
return so.setBPF(c.Conn, filter)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/doc.go
================================================
// Copyright 2012 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 ipv4 implements IP-level socket options for the Internet
// Protocol version 4.
//
// The package provides IP-level socket options that allow
// manipulation of IPv4 facilities.
//
// The IPv4 protocol and basic host requirements for IPv4 are defined
// in RFC 791 and RFC 1122.
// Host extensions for multicasting and socket interface extensions
// for multicast source filters are defined in RFC 1112 and RFC 3678.
// IGMPv1, IGMPv2 and IGMPv3 are defined in RFC 1112, RFC 2236 and RFC
// 3376.
// Source-specific multicast is defined in RFC 4607.
//
// # Unicasting
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
// that use the IPv4 transport. When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
// important, Conn is used to set the type-of-service field on the
// IPv4 header for each packet.
//
// ln, err := net.Listen("tcp4", "0.0.0.0:1024")
// if err != nil {
// // error handling
// }
// defer ln.Close()
// for {
// c, err := ln.Accept()
// if err != nil {
// // error handling
// }
// go func(c net.Conn) {
// defer c.Close()
//
// The outgoing packets will be labeled DiffServ assured forwarding
// class 1 low drop precedence, known as AF11 packets.
//
// if err := ipv4.NewConn(c).SetTOS(0x28); err != nil {
// // error handling
// }
// if _, err := c.Write(data); err != nil {
// // error handling
// }
// }(c)
// }
//
// # Multicasting
//
// The options for multicasting are available for net.UDPConn and
// net.IPConn which are created as network connections that use the
// IPv4 transport. A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// multicast groups.
//
// en0, err := net.InterfaceByName("en0")
// if err != nil {
// // error handling
// }
// en1, err := net.InterfaceByIndex(911)
// if err != nil {
// // error handling
// }
// group := net.IPv4(224, 0, 0, 250)
//
// First, an application listens to an appropriate address with an
// appropriate service port.
//
// c, err := net.ListenPacket("udp4", "0.0.0.0:1024")
// if err != nil {
// // error handling
// }
// defer c.Close()
//
// Second, the application joins multicast groups, starts listening to
// the groups on the specified network interfaces. Note that the
// service port for transport layer protocol does not matter with this
// operation as joining groups affects only network and link layer
// protocols, such as IPv4 and Ethernet.
//
// p := ipv4.NewPacketConn(c)
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
// // error handling
// }
//
// The application might set per packet control message transmissions
// between the protocol stack within the kernel. When the application
// needs a destination address on an incoming packet,
// SetControlMessage of PacketConn is used to enable control message
// transmissions.
//
// if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil {
// // error handling
// }
//
// The application could identify whether the received packets are
// of interest by using the control message that contains the
// destination address of the received packet.
//
// b := make([]byte, 1500)
// for {
// n, cm, src, err := p.ReadFrom(b)
// if err != nil {
// // error handling
// }
// if cm.Dst.IsMulticast() {
// if cm.Dst.Equal(group) {
// // joined group, do something
// } else {
// // unknown group, discard
// continue
// }
// }
//
// The application can also send both unicast and multicast packets.
//
// p.SetTOS(0x0)
// p.SetTTL(16)
// if _, err := p.WriteTo(data, nil, src); err != nil {
// // error handling
// }
// dst := &net.UDPAddr{IP: group, Port: 1024}
// for _, ifi := range []*net.Interface{en0, en1} {
// if err := p.SetMulticastInterface(ifi); err != nil {
// // error handling
// }
// p.SetMulticastTTL(2)
// if _, err := p.WriteTo(data, nil, dst); err != nil {
// // error handling
// }
// }
// }
//
// # More multicasting
//
// An application that uses PacketConn or RawConn may join multiple
// multicast groups. For example, a UDP listener with port 1024 might
// join two different groups across over two different network
// interfaces by using:
//
// c, err := net.ListenPacket("udp4", "0.0.0.0:1024")
// if err != nil {
// // error handling
// }
// defer c.Close()
// p := ipv4.NewPacketConn(c)
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 249)}); err != nil {
// // error handling
// }
//
// It is possible for multiple UDP listeners that listen on the same
// UDP port to join the same multicast group. The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
//
// c1, err := net.ListenPacket("udp4", "224.0.0.0:1024")
// if err != nil {
// // error handling
// }
// defer c1.Close()
// c2, err := net.ListenPacket("udp4", "224.0.0.0:1024")
// if err != nil {
// // error handling
// }
// defer c2.Close()
// p1 := ipv4.NewPacketConn(c1)
// if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
// // error handling
// }
// p2 := ipv4.NewPacketConn(c2)
// if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
// // error handling
// }
//
// Also it is possible for the application to leave or rejoin a
// multicast group on the network interface.
//
// if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 248)}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.IPv4(224, 0, 0, 250)}); err != nil {
// // error handling
// }
//
// # Source-specific multicasting
//
// An application that uses PacketConn or RawConn on IGMPv3 supported
// platform is able to join source-specific multicast groups.
// The application may use JoinSourceSpecificGroup and
// LeaveSourceSpecificGroup for the operation known as "include" mode,
//
// ssmgroup := net.UDPAddr{IP: net.IPv4(232, 7, 8, 9)}
// ssmsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 1)}
// if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
// // error handling
// }
// if err := p.LeaveSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
// // error handling
// }
//
// or JoinGroup, ExcludeSourceSpecificGroup,
// IncludeSourceSpecificGroup and LeaveGroup for the operation known
// as "exclude" mode.
//
// exclsource := net.UDPAddr{IP: net.IPv4(192, 168, 0, 254)}
// if err := p.JoinGroup(en0, &ssmgroup); err != nil {
// // error handling
// }
// if err := p.ExcludeSourceSpecificGroup(en0, &ssmgroup, &exclsource); err != nil {
// // error handling
// }
// if err := p.LeaveGroup(en0, &ssmgroup); err != nil {
// // error handling
// }
//
// Note that it depends on each platform implementation what happens
// when an application which runs on IGMPv3 unsupported platform uses
// JoinSourceSpecificGroup and LeaveSourceSpecificGroup.
// In general the platform tries to fall back to conversations using
// IGMPv1 or IGMPv2 and starts to listen to multicast traffic.
// In the fallback case, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup may return an error.
package ipv4 // import "golang.org/x/net/ipv4"
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
================================================
FILE: vendor/golang.org/x/net/ipv4/endpoint.go
================================================
// Copyright 2012 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 ipv4
import (
"net"
"time"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the JoinSourceSpecificGroup,
// LeaveSourceSpecificGroup, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup methods of PacketConn and RawConn are
// not implemented.
// A Conn represents a network endpoint that uses the IPv4 transport.
// It is used to control basic IP-level socket options such as TOS and
// TTL.
type Conn struct {
genericOpt
}
type genericOpt struct {
*socket.Conn
}
func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// NewConn returns a new Conn.
func NewConn(c net.Conn) *Conn {
cc, _ := socket.NewConn(c)
return &Conn{
genericOpt: genericOpt{Conn: cc},
}
}
// A PacketConn represents a packet network endpoint that uses the
// IPv4 transport. It is used to control several IP-level socket
// options including multicasting. It also provides datagram based
// network I/O methods specific to the IPv4 and higher layer protocols
// such as UDP.
type PacketConn struct {
genericOpt
dgramOpt
payloadHandler
}
type dgramOpt struct {
*socket.Conn
}
func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage sets the per packet IP-level socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetWriteDeadline(t)
}
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.PacketConn.Close()
}
// NewPacketConn returns a new PacketConn using c as its underlying
// transport.
func NewPacketConn(c net.PacketConn) *PacketConn {
cc, _ := socket.NewConn(c.(net.Conn))
p := &PacketConn{
genericOpt: genericOpt{Conn: cc},
dgramOpt: dgramOpt{Conn: cc},
payloadHandler: payloadHandler{PacketConn: c, Conn: cc},
}
return p
}
// A RawConn represents a packet network endpoint that uses the IPv4
// transport. It is used to control several IP-level socket options
// including IPv4 header manipulation. It also provides datagram
// based network I/O methods specific to the IPv4 and higher layer
// protocols that handle IPv4 datagram directly such as OSPF, GRE.
type RawConn struct {
genericOpt
dgramOpt
packetHandler
}
// SetControlMessage sets the per packet IP-level socket options.
func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.packetHandler.ok() {
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.packetHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// endpoint.
func (c *RawConn) SetDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return errInvalidConn
}
return c.packetHandler.IPConn.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the
// endpoint.
func (c *RawConn) SetReadDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return errInvalidConn
}
return c.packetHandler.IPConn.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the
// endpoint.
func (c *RawConn) SetWriteDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return errInvalidConn
}
return c.packetHandler.IPConn.SetWriteDeadline(t)
}
// Close closes the endpoint.
func (c *RawConn) Close() error {
if !c.packetHandler.ok() {
return errInvalidConn
}
return c.packetHandler.IPConn.Close()
}
// NewRawConn returns a new RawConn using c as its underlying
// transport.
func NewRawConn(c net.PacketConn) (*RawConn, error) {
cc, err := socket.NewConn(c.(net.Conn))
if err != nil {
return nil, err
}
r := &RawConn{
genericOpt: genericOpt{Conn: cc},
dgramOpt: dgramOpt{Conn: cc},
packetHandler: packetHandler{IPConn: c.(*net.IPConn), Conn: cc},
}
so, ok := sockOpts[ssoHeaderPrepend]
if !ok {
return nil, errNotImplemented
}
if err := so.SetInt(r.dgramOpt.Conn, boolint(true)); err != nil {
return nil, err
}
return r, nil
}
================================================
FILE: vendor/golang.org/x/net/ipv4/genericopt.go
================================================
// Copyright 2012 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 ipv4
// TOS returns the type-of-service field value for outgoing packets.
func (c *genericOpt) TOS() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTOS]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetTOS sets the type-of-service field value for future outgoing
// packets.
func (c *genericOpt) SetTOS(tos int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoTOS]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, tos)
}
// TTL returns the time-to-live field value for outgoing packets.
func (c *genericOpt) TTL() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTTL]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetTTL sets the time-to-live field value for future outgoing
// packets.
func (c *genericOpt) SetTTL(ttl int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoTTL]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, ttl)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/header.go
================================================
// Copyright 2012 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 ipv4
import (
"encoding/binary"
"fmt"
"net"
"runtime"
)
const (
Version = 4 // protocol version
HeaderLen = 20 // header length without extension headers
)
type HeaderFlags int
const (
MoreFragments HeaderFlags = 1 << iota // more fragments flag
DontFragment // don't fragment flag
)
// A Header represents an IPv4 header.
type Header struct {
Version int // protocol version
Len int // header length
TOS int // type-of-service
TotalLen int // packet total length
ID int // identification
Flags HeaderFlags // flags
FragOff int // fragment offset
TTL int // time-to-live
Protocol int // next protocol
Checksum int // checksum
Src net.IP // source address
Dst net.IP // destination address
Options []byte // options, extension headers
}
func (h *Header) String() string {
if h == nil {
return ""
}
return fmt.Sprintf("ver=%d hdrlen=%d tos=%#x totallen=%d id=%#x flags=%#x fragoff=%#x ttl=%d proto=%d cksum=%#x src=%v dst=%v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst)
}
// Marshal returns the binary encoding of h.
//
// The returned slice is in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func (h *Header) Marshal() ([]byte, error) {
if h == nil {
return nil, errNilHeader
}
if h.Len < HeaderLen {
return nil, errHeaderTooShort
}
hdrlen := HeaderLen + len(h.Options)
b := make([]byte, hdrlen)
b[0] = byte(Version<<4 | (hdrlen >> 2 & 0x0f))
b[1] = byte(h.TOS)
flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
switch runtime.GOOS {
case "darwin", "ios", "dragonfly", "netbsd":
binary.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
binary.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
case "freebsd":
if freebsdVersion < 1100000 {
binary.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
binary.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
} else {
binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
}
default:
binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
}
binary.BigEndian.PutUint16(b[4:6], uint16(h.ID))
b[8] = byte(h.TTL)
b[9] = byte(h.Protocol)
binary.BigEndian.PutUint16(b[10:12], uint16(h.Checksum))
if ip := h.Src.To4(); ip != nil {
copy(b[12:16], ip[:net.IPv4len])
}
if ip := h.Dst.To4(); ip != nil {
copy(b[16:20], ip[:net.IPv4len])
} else {
return nil, errMissingAddress
}
if len(h.Options) > 0 {
copy(b[HeaderLen:], h.Options)
}
return b, nil
}
// Parse parses b as an IPv4 header and stores the result in h.
//
// The provided b must be in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func (h *Header) Parse(b []byte) error {
if h == nil || b == nil {
return errNilHeader
}
if len(b) < HeaderLen {
return errHeaderTooShort
}
hdrlen := int(b[0]&0x0f) << 2
if len(b) < hdrlen {
return errExtHeaderTooShort
}
h.Version = int(b[0] >> 4)
h.Len = hdrlen
h.TOS = int(b[1])
h.ID = int(binary.BigEndian.Uint16(b[4:6]))
h.TTL = int(b[8])
h.Protocol = int(b[9])
h.Checksum = int(binary.BigEndian.Uint16(b[10:12]))
h.Src = net.IPv4(b[12], b[13], b[14], b[15])
h.Dst = net.IPv4(b[16], b[17], b[18], b[19])
switch runtime.GOOS {
case "darwin", "ios", "dragonfly", "netbsd":
h.TotalLen = int(binary.NativeEndian.Uint16(b[2:4])) + hdrlen
h.FragOff = int(binary.NativeEndian.Uint16(b[6:8]))
case "freebsd":
if freebsdVersion < 1100000 {
h.TotalLen = int(binary.NativeEndian.Uint16(b[2:4]))
if freebsdVersion < 1000000 {
h.TotalLen += hdrlen
}
h.FragOff = int(binary.NativeEndian.Uint16(b[6:8]))
} else {
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
}
default:
h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
}
h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13
h.FragOff = h.FragOff & 0x1fff
optlen := hdrlen - HeaderLen
if optlen > 0 && len(b) >= hdrlen {
if cap(h.Options) < optlen {
h.Options = make([]byte, optlen)
} else {
h.Options = h.Options[:optlen]
}
copy(h.Options, b[HeaderLen:hdrlen])
}
return nil
}
// ParseHeader parses b as an IPv4 header.
//
// The provided b must be in the format used by a raw IP socket on the
// local system.
// This may differ from the wire format, depending on the system.
func ParseHeader(b []byte) (*Header, error) {
h := new(Header)
if err := h.Parse(b); err != nil {
return nil, err
}
return h, nil
}
================================================
FILE: vendor/golang.org/x/net/ipv4/helper.go
================================================
// Copyright 2012 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 ipv4
import (
"errors"
"net"
"runtime"
"golang.org/x/net/internal/socket"
)
var (
errInvalidConn = errors.New("invalid connection")
errMissingAddress = errors.New("missing address")
errNilHeader = errors.New("nil header")
errHeaderTooShort = errors.New("header too short")
errExtHeaderTooShort = errors.New("extension header too short")
errInvalidConnType = errors.New("invalid conn type")
errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
// See https://www.freebsd.org/doc/en/books/porters-handbook/versions.html.
freebsdVersion uint32
compatFreeBSD32 bool // 386 emulation on amd64
)
// See golang.org/issue/30899.
func adjustFreeBSD32(m *socket.Message) {
// FreeBSD 12.0-RELEASE is affected by https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=236737
if 1200086 <= freebsdVersion && freebsdVersion < 1201000 {
l := (m.NN + 4 - 1) &^ (4 - 1)
if m.NN < l && l <= len(m.OOB) {
m.NN = l
}
}
}
func boolint(b bool) int {
if b {
return 1
}
return 0
}
func netAddrToIP4(a net.Addr) net.IP {
switch v := a.(type) {
case *net.UDPAddr:
if ip := v.IP.To4(); ip != nil {
return ip
}
case *net.IPAddr:
if ip := v.IP.To4(); ip != nil {
return ip
}
}
return nil
}
func opAddr(a net.Addr) net.Addr {
switch a.(type) {
case *net.TCPAddr:
if a == nil {
return nil
}
case *net.UDPAddr:
if a == nil {
return nil
}
case *net.IPAddr:
if a == nil {
return nil
}
}
return a
}
================================================
FILE: vendor/golang.org/x/net/ipv4/iana.go
================================================
// go generate gen.go
// Code generated by the command above; DO NOT EDIT.
package ipv4
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
const (
ICMPTypeEchoReply ICMPType = 0 // Echo Reply
ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable
ICMPTypeRedirect ICMPType = 5 // Redirect
ICMPTypeEcho ICMPType = 8 // Echo
ICMPTypeRouterAdvertisement ICMPType = 9 // Router Advertisement
ICMPTypeRouterSolicitation ICMPType = 10 // Router Solicitation
ICMPTypeTimeExceeded ICMPType = 11 // Time Exceeded
ICMPTypeParameterProblem ICMPType = 12 // Parameter Problem
ICMPTypeTimestamp ICMPType = 13 // Timestamp
ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply
ICMPTypePhoturis ICMPType = 40 // Photuris
ICMPTypeExtendedEchoRequest ICMPType = 42 // Extended Echo Request
ICMPTypeExtendedEchoReply ICMPType = 43 // Extended Echo Reply
)
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
var icmpTypes = map[ICMPType]string{
0: "echo reply",
3: "destination unreachable",
5: "redirect",
8: "echo",
9: "router advertisement",
10: "router solicitation",
11: "time exceeded",
12: "parameter problem",
13: "timestamp",
14: "timestamp reply",
40: "photuris",
42: "extended echo request",
43: "extended echo reply",
}
================================================
FILE: vendor/golang.org/x/net/ipv4/icmp.go
================================================
// Copyright 2013 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 ipv4
import "golang.org/x/net/internal/iana"
// An ICMPType represents a type of ICMP message.
type ICMPType int
func (typ ICMPType) String() string {
s, ok := icmpTypes[typ]
if !ok {
return ""
}
return s
}
// Protocol returns the ICMPv4 protocol number.
func (typ ICMPType) Protocol() int {
return iana.ProtocolICMP
}
// An ICMPFilter represents an ICMP message filter for incoming
// packets. The filter belongs to a packet delivery path on a host and
// it cannot interact with forwarding packets or tunnel-outer packets.
//
// Note: RFC 8200 defines a reasonable role model and it works not
// only for IPv6 but IPv4. A node means a device that implements IP.
// A router means a node that forwards IP packets not explicitly
// addressed to itself, and a host means a node that is not a router.
type ICMPFilter struct {
icmpFilter
}
// Accept accepts incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Accept(typ ICMPType) {
f.accept(typ)
}
// Block blocks incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Block(typ ICMPType) {
f.block(typ)
}
// SetAll sets the filter action to the filter.
func (f *ICMPFilter) SetAll(block bool) {
f.setAll(block)
}
// WillBlock reports whether the ICMP type will be blocked.
func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
return f.willBlock(typ)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/icmp_linux.go
================================================
// 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.
package ipv4
func (f *icmpFilter) accept(typ ICMPType) {
f.Data &^= 1 << (uint32(typ) & 31)
}
func (f *icmpFilter) block(typ ICMPType) {
f.Data |= 1 << (uint32(typ) & 31)
}
func (f *icmpFilter) setAll(block bool) {
if block {
f.Data = 1<<32 - 1
} else {
f.Data = 0
}
}
func (f *icmpFilter) willBlock(typ ICMPType) bool {
return f.Data&(1<<(uint32(typ)&31)) != 0
}
================================================
FILE: vendor/golang.org/x/net/ipv4/icmp_stub.go
================================================
// 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 !linux
package ipv4
const sizeofICMPFilter = 0x0
type icmpFilter struct {
}
func (f *icmpFilter) accept(typ ICMPType) {
}
func (f *icmpFilter) block(typ ICMPType) {
}
func (f *icmpFilter) setAll(block bool) {
}
func (f *icmpFilter) willBlock(typ ICMPType) bool {
return false
}
================================================
FILE: vendor/golang.org/x/net/ipv4/packet.go
================================================
// Copyright 2012 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 ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ReadFrom and WriteTo methods of RawConn
// are not implemented.
// A packetHandler represents the IPv4 datagram handler.
type packetHandler struct {
*net.IPConn
*socket.Conn
rawOpt
}
func (c *packetHandler) ok() bool { return c != nil && c.IPConn != nil && c.Conn != nil }
// ReadFrom reads an IPv4 datagram from the endpoint c, copying the
// datagram into b. It returns the received datagram as the IPv4
// header h, the payload p and the control message cm.
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
if !c.ok() {
return nil, nil, nil, errInvalidConn
}
c.rawOpt.RLock()
m := socket.Message{
Buffers: [][]byte{b},
OOB: NewControlMessage(c.rawOpt.cflags),
}
c.rawOpt.RUnlock()
if err := c.RecvMsg(&m, 0); err != nil {
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
var hs []byte
if hs, p, err = slicePacket(b[:m.N]); err != nil {
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
if h, err = ParseHeader(hs); err != nil {
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
if m.NN > 0 {
if compatFreeBSD32 {
adjustFreeBSD32(&m)
}
cm = new(ControlMessage)
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
return nil, nil, nil, &net.OpError{Op: "read", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Err: err}
}
}
if src, ok := m.Addr.(*net.IPAddr); ok && cm != nil {
cm.Src = src.IP
}
return
}
func slicePacket(b []byte) (h, p []byte, err error) {
if len(b) < HeaderLen {
return nil, nil, errHeaderTooShort
}
hdrlen := int(b[0]&0x0f) << 2
return b[:hdrlen], b[hdrlen:], nil
}
// WriteTo writes an IPv4 datagram through the endpoint c, copying the
// datagram from the IPv4 header h and the payload p. The control
// message cm allows the datagram path and the outgoing interface to be
// specified. Currently only Darwin and Linux support this. The cm
// may be nil if control of the outgoing datagram is not required.
//
// The IPv4 header h must contain appropriate fields that include:
//
// Version =
// Len =
// TOS =
// TotalLen =
// ID = platform sets an appropriate value if ID is zero
// FragOff =
// TTL =
// Protocol =
// Checksum = platform sets an appropriate value if Checksum is zero
// Src = platform sets an appropriate value if Src is nil
// Dst =
// Options = optional
func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
if !c.ok() {
return errInvalidConn
}
m := socket.Message{
OOB: cm.Marshal(),
}
wh, err := h.Marshal()
if err != nil {
return err
}
m.Buffers = [][]byte{wh, p}
dst := new(net.IPAddr)
if cm != nil {
if ip := cm.Dst.To4(); ip != nil {
dst.IP = ip
}
}
if dst.IP == nil {
dst.IP = h.Dst
}
m.Addr = dst
if err := c.SendMsg(&m, 0); err != nil {
return &net.OpError{Op: "write", Net: c.IPConn.LocalAddr().Network(), Source: c.IPConn.LocalAddr(), Addr: opAddr(dst), Err: err}
}
return nil
}
================================================
FILE: vendor/golang.org/x/net/ipv4/payload.go
================================================
// Copyright 2012 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 ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
// methods of PacketConn is not implemented.
// A payloadHandler represents the IPv4 datagram payload handler.
type payloadHandler struct {
net.PacketConn
*socket.Conn
rawOpt
}
func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil && c.Conn != nil }
================================================
FILE: vendor/golang.org/x/net/ipv4/payload_cmsg.go
================================================
// Copyright 2012 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, errInvalidConn
}
c.rawOpt.RLock()
m := socket.Message{
OOB: NewControlMessage(c.rawOpt.cflags),
}
c.rawOpt.RUnlock()
switch c.PacketConn.(type) {
case *net.UDPConn:
m.Buffers = [][]byte{b}
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
case *net.IPConn:
h := make([]byte, HeaderLen)
m.Buffers = [][]byte{h, b}
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
hdrlen := int(h[0]&0x0f) << 2
if hdrlen > len(h) {
d := hdrlen - len(h)
copy(b, b[d:])
m.N -= d
} else {
m.N -= hdrlen
}
default:
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
}
if m.NN > 0 {
if compatFreeBSD32 {
adjustFreeBSD32(&m)
}
cm = new(ControlMessage)
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
cm.Src = netAddrToIP4(m.Addr)
}
return m.N, cm, m.Addr, nil
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
// Currently only Darwin and Linux support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, errInvalidConn
}
m := socket.Message{
Buffers: [][]byte{b},
OOB: cm.Marshal(),
Addr: dst,
}
err = c.SendMsg(&m, 0)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err}
}
return m.N, err
}
================================================
FILE: vendor/golang.org/x/net/ipv4/payload_nocmsg.go
================================================
// Copyright 2012 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
package ipv4
import "net"
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, errInvalidConn
}
if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
return 0, nil, nil, err
}
return
}
// WriteTo writes a payload of the IPv4 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the datagram path and the outgoing interface to be specified.
// Currently only Darwin and Linux support this. The cm may be nil if
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, errInvalidConn
}
if dst == nil {
return 0, errMissingAddress
}
return c.PacketConn.WriteTo(b, dst)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sockopt.go
================================================
// 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.
package ipv4
import "golang.org/x/net/internal/socket"
// Sticky socket options
const (
ssoTOS = iota // header field for unicast packet
ssoTTL // header field for unicast packet
ssoMulticastTTL // header field for multicast packet
ssoMulticastInterface // outbound interface for multicast packet
ssoMulticastLoopback // loopback for multicast packet
ssoReceiveTTL // header field on received packet
ssoReceiveDst // header field on received packet
ssoReceiveInterface // inbound interface on received packet
ssoPacketInfo // incbound or outbound packet path
ssoHeaderPrepend // ipv4 header prepend
ssoStripHeader // strip ipv4 header
ssoICMPFilter // icmp filter
ssoJoinGroup // any-source multicast
ssoLeaveGroup // any-source multicast
ssoJoinSourceGroup // source-specific multicast
ssoLeaveSourceGroup // source-specific multicast
ssoBlockSourceGroup // any-source or source-specific multicast
ssoUnblockSourceGroup // any-source or source-specific multicast
ssoAttachFilter // attach BPF for filtering inbound traffic
)
// Sticky socket option value types
const (
ssoTypeIPMreq = iota + 1
ssoTypeIPMreqn
ssoTypeGroupReq
ssoTypeGroupSourceReq
)
// A sockOpt represents a binding for sticky socket option.
type sockOpt struct {
socket.Option
typ int // hint for option value type; optional
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sockopt_posix.go
================================================
// Copyright 2012 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package ipv4
import (
"net"
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
switch so.typ {
case ssoTypeIPMreqn:
return so.getIPMreqn(c)
default:
return so.getMulticastIf(c)
}
}
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
switch so.typ {
case ssoTypeIPMreqn:
return so.setIPMreqn(c, ifi, nil)
default:
return so.setMulticastIf(c, ifi)
}
}
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
b := make([]byte, so.Len)
n, err := so.Get(c, b)
if err != nil {
return nil, err
}
if n != sizeofICMPFilter {
return nil, errNotImplemented
}
return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
}
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
b := (*[sizeofICMPFilter]byte)(unsafe.Pointer(f))[:sizeofICMPFilter]
return so.Set(c, b)
}
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
switch so.typ {
case ssoTypeIPMreq:
return so.setIPMreq(c, ifi, grp)
case ssoTypeIPMreqn:
return so.setIPMreqn(c, ifi, grp)
case ssoTypeGroupReq:
return so.setGroupReq(c, ifi, grp)
default:
return errNotImplemented
}
}
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return so.setGroupSourceReq(c, ifi, grp, src)
}
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return so.setAttachFilter(c, f)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sockopt_stub.go
================================================
// Copyright 2012 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv4
import (
"net"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
return errNotImplemented
}
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
return errNotImplemented
}
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_aix.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Added for go1.11 compatibility
//go:build aix
package ipv4
import (
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
// IP_RECVIF is defined on AIX but doesn't work. IP_RECVINTERFACE must be used instead.
const sockoptReceiveInterface = unix.IP_RECVINTERFACE
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 1, marshalTTL, parseTTL},
ctlDst: {unix.IP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
ctlInterface: {unix.IP_RECVINTERFACE, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 1}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVDSTADDR, Len: 4}},
ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVINTERFACE, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_asmreq.go
================================================
// Copyright 2012 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 aix || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || windows
package ipv4
import (
"errors"
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
var errNoSuchInterface = errors.New("no such interface")
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
mreq := ipMreq{Multiaddr: [4]byte{grp[0], grp[1], grp[2], grp[3]}}
if err := setIPMreqInterface(&mreq, ifi); err != nil {
return err
}
b := (*[sizeofIPMreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPMreq]
return so.Set(c, b)
}
func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
var b [4]byte
if _, err := so.Get(c, b[:]); err != nil {
return nil, err
}
ifi, err := netIP4ToInterface(net.IPv4(b[0], b[1], b[2], b[3]))
if err != nil {
return nil, err
}
return ifi, nil
}
func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
ip, err := netInterfaceToIP4(ifi)
if err != nil {
return err
}
var b [4]byte
copy(b[:], ip)
return so.Set(c, b[:])
}
func setIPMreqInterface(mreq *ipMreq, ifi *net.Interface) error {
if ifi == nil {
return nil
}
ifat, err := ifi.Addrs()
if err != nil {
return err
}
for _, ifa := range ifat {
switch ifa := ifa.(type) {
case *net.IPAddr:
if ip := ifa.IP.To4(); ip != nil {
copy(mreq.Interface[:], ip)
return nil
}
case *net.IPNet:
if ip := ifa.IP.To4(); ip != nil {
copy(mreq.Interface[:], ip)
return nil
}
}
}
return errNoSuchInterface
}
func netIP4ToInterface(ip net.IP) (*net.Interface, error) {
ift, err := net.Interfaces()
if err != nil {
return nil, err
}
for _, ifi := range ift {
ifat, err := ifi.Addrs()
if err != nil {
return nil, err
}
for _, ifa := range ifat {
switch ifa := ifa.(type) {
case *net.IPAddr:
if ip.Equal(ifa.IP) {
return &ifi, nil
}
case *net.IPNet:
if ip.Equal(ifa.IP) {
return &ifi, nil
}
}
}
}
return nil, errNoSuchInterface
}
func netInterfaceToIP4(ifi *net.Interface) (net.IP, error) {
if ifi == nil {
return net.IPv4zero.To4(), nil
}
ifat, err := ifi.Addrs()
if err != nil {
return nil, err
}
for _, ifa := range ifat {
switch ifa := ifa.(type) {
case *net.IPAddr:
if ip := ifa.IP.To4(); ip != nil {
return ip, nil
}
case *net.IPNet:
if ip := ifa.IP.To4(); ip != nil {
return ip, nil
}
}
}
return nil, errNoSuchInterface
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_asmreq_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !windows
package ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
func (so *sockOpt) getMulticastIf(c *socket.Conn) (*net.Interface, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setMulticastIf(c *socket.Conn, ifi *net.Interface) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_asmreqn.go
================================================
// 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 darwin || freebsd || linux
package ipv4
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
b := make([]byte, so.Len)
if _, err := so.Get(c, b); err != nil {
return nil, err
}
mreqn := (*unix.IPMreqn)(unsafe.Pointer(&b[0]))
if mreqn.Ifindex == 0 {
return nil, nil
}
ifi, err := net.InterfaceByIndex(int(mreqn.Ifindex))
if err != nil {
return nil, err
}
return ifi, nil
}
func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var mreqn unix.IPMreqn
if ifi != nil {
mreqn.Ifindex = int32(ifi.Index)
}
if grp != nil {
mreqn.Multiaddr = [4]byte{grp[0], grp[1], grp[2], grp[3]}
}
b := (*[unix.SizeofIPMreqn]byte)(unsafe.Pointer(&mreqn))[:unix.SizeofIPMreqn]
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_asmreqn_stub.go
================================================
// 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 !darwin && !freebsd && !linux
package ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getIPMreqn(c *socket.Conn) (*net.Interface, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setIPMreqn(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_bpf.go
================================================
// 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 linux
package ipv4
import (
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
prog := unix.SockFprog{
Len: uint16(len(f)),
Filter: (*unix.SockFilter)(unsafe.Pointer(&f[0])),
}
b := (*[unix.SizeofSockFprog]byte)(unsafe.Pointer(&prog))[:unix.SizeofSockFprog]
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_bpf_stub.go
================================================
// 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 !linux
package ipv4
import (
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_bsd.go
================================================
// 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 netbsd || openbsd
package ipv4
import (
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
const sockoptReceiveInterface = unix.IP_RECVIF
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 1, marshalTTL, parseTTL},
ctlDst: {unix.IP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
ctlInterface: {unix.IP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 1}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVDSTADDR, Len: 4}},
ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVIF, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_darwin.go
================================================
// 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.
package ipv4
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
const sockoptReceiveInterface = unix.IP_RECVIF
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 1, marshalTTL, parseTTL},
ctlDst: {unix.IP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
ctlInterface: {unix.IP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
ctlPacketInfo: {unix.IP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: unix.SizeofIPMreqn}, typ: ssoTypeIPMreqn},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 4}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVDSTADDR, Len: 4}},
ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVIF, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoStripHeader: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_STRIPHDR, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoPacketInfo: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVPKTINFO, Len: 4}},
}
)
func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
sa = (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 132))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_dragonfly.go
================================================
// 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.
package ipv4
import (
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
const sockoptReceiveInterface = unix.IP_RECVIF
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 1, marshalTTL, parseTTL},
ctlDst: {unix.IP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
ctlInterface: {unix.IP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 4}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVDSTADDR, Len: 4}},
ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVIF, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_freebsd.go
================================================
// 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.
package ipv4
import (
"net"
"runtime"
"strings"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
const sockoptReceiveInterface = unix.IP_RECVIF
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 1, marshalTTL, parseTTL},
ctlDst: {unix.IP_RECVDSTADDR, net.IPv4len, marshalDst, parseDst},
ctlInterface: {unix.IP_RECVIF, syscall.SizeofSockaddrDatalink, marshalInterface, parseInterface},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 4}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoReceiveDst: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVDSTADDR, Len: 4}},
ssoReceiveInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVIF, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func init() {
freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
if freebsdVersion >= 1000000 {
sockOpts[ssoMulticastInterface] = &sockOpt{Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: unix.SizeofIPMreqn}, typ: ssoTypeIPMreqn}
}
if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" {
archs, _ := syscall.Sysctl("kern.supported_archs")
for _, s := range strings.Fields(archs) {
if s == "amd64" {
compatFreeBSD32 = true
break
}
}
}
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(&gr.Group))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(&gsr.Group))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
sa = (*sockaddrInet)(unsafe.Pointer(&gsr.Source))
sa.Len = sizeofSockaddrInet
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_linux.go
================================================
// 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.
package ipv4
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_TTL, 1, marshalTTL, parseTTL},
ctlPacketInfo: {unix.IP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: unix.SizeofIPMreqn}, typ: ssoTypeIPMreqn},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 4}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoPacketInfo: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_PKTINFO, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolReserved, Name: unix.ICMP_FILTER, Len: sizeofICMPFilter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoAttachFilter: {Option: socket.Option{Level: unix.SOL_SOCKET, Name: unix.SO_ATTACH_FILTER, Len: unix.SizeofSockFprog}},
}
)
func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
sa = (*sockaddrInet)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_solaris.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ipv4
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
const sockoptReceiveInterface = unix.IP_RECVIF
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTTL: {unix.IP_RECVTTL, 4, marshalTTL, parseTTL},
ctlPacketInfo: {unix.IP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
sockOpts = map[int]sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 1}},
ssoReceiveTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVTTL, Len: 4}},
ssoPacketInfo: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVPKTINFO, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], grp)
sa = (*sockaddrInet)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 260))
sa.Family = syscall.AF_INET
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_ssmreq.go
================================================
// 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 darwin || freebsd || linux || solaris
package ipv4
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var gr groupReq
if ifi != nil {
gr.Interface = uint32(ifi.Index)
}
gr.setGroup(grp)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupReq + 4]byte
s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))[:sizeofGroupReq]
}
return so.Set(c, b)
}
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
var gsr groupSourceReq
if ifi != nil {
gsr.Interface = uint32(ifi.Index)
}
gsr.setSourceGroup(grp, src)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupSourceReq + 4]byte
s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))[:sizeofGroupSourceReq]
}
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_ssmreq_stub.go
================================================
// 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 !darwin && !freebsd && !linux && !solaris
package ipv4
import (
"net"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv4
var (
ctlOpts = [ctlMax]ctlOpt{}
sockOpts = map[int]*sockOpt{}
)
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_windows.go
================================================
// 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.
package ipv4
import (
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/windows"
)
const (
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
)
type ipMreq struct {
Multiaddr [4]byte
Interface [4]byte
}
type ipMreqSource struct {
Multiaddr [4]byte
Sourceaddr [4]byte
Interface [4]byte
}
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms738586(v=vs.85).aspx
var (
ctlOpts = [ctlMax]ctlOpt{}
sockOpts = map[int]*sockOpt{
ssoTOS: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_TOS, Len: 4}},
ssoTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_TTL, Len: 4}},
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_MULTICAST_TTL, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_MULTICAST_LOOP, Len: 4}},
ssoHeaderPrepend: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_HDRINCL, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_ADD_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: windows.IP_DROP_MEMBERSHIP, Len: sizeofIPMreq}, typ: ssoTypeIPMreq},
}
)
================================================
FILE: vendor/golang.org/x/net/ipv4/sys_zos.go
================================================
// 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.
package ipv4
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlPacketInfo: {unix.IP_PKTINFO, sizeofInetPktinfo, marshalPacketInfo, parsePacketInfo},
}
sockOpts = map[int]*sockOpt{
ssoMulticastTTL: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_TTL, Len: 1}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_IF, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_MULTICAST_LOOP, Len: 1}},
ssoPacketInfo: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.IP_RECVPKTINFO, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIP, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func (pi *inetPktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet4)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET
sa.Len = sizeofSockaddrInet4
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet4)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET
sa.Len = sizeofSockaddrInet4
copy(sa.Addr[:], grp)
sa = (*sockaddrInet4)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET
sa.Len = sizeofSockaddrInet4
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_aix_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_aix.go
// Added for go1.11 compatibility
//go:build aix
package ipv4
const (
sizeofIPMreq = 0x8
)
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_darwin.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type inetPktinfo struct {
Ifindex uint32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [128]byte
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [128]byte
Pad_cgo_1 [128]byte
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_dragonfly.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_dragonfly.go
package ipv4
const (
sizeofIPMreq = 0x8
)
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_freebsd_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_freebsd_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_freebsd_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_freebsd_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]uint8
X__ss_align int64
X__ss_pad2 [112]uint8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]uint8
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_freebsd_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv4
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]uint8
X__ss_align int64
X__ss_pad2 [112]uint8
}
type sockaddrInet struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte /* in_addr */
Zero [8]uint8
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_loong64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build loong64
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_mips.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_mips64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_mips64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_mipsle.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_ppc.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]uint8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_ppc64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build riscv64
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_linux_s390x.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv4
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofSockExtendedErr = 0x10
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPFilter = 0x4
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
X__pad [8]uint8
}
type inetPktinfo struct {
Ifindex int32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type sockExtendedErr struct {
Errno uint32
Origin uint8
Type uint8
Code uint8
Pad uint8
Info uint32
Data uint32
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr uint32
Interface uint32
Sourceaddr uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpFilter struct {
Data uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_netbsd.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package ipv4
const (
sizeofIPMreq = 0x8
)
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_openbsd.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package ipv4
const (
sizeofIPMreq = 0x8
)
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_solaris.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_solaris.go
package ipv4
const (
sizeofSockaddrStorage = 0x100
sizeofSockaddrInet = 0x10
sizeofInetPktinfo = 0xc
sizeofIPMreq = 0x8
sizeofIPMreqSource = 0xc
sizeofGroupReq = 0x104
sizeofGroupSourceReq = 0x204
)
type sockaddrStorage struct {
Family uint16
X_ss_pad1 [6]int8
X_ss_align float64
X_ss_pad2 [240]int8
}
type sockaddrInet struct {
Family uint16
Port uint16
Addr [4]byte /* in_addr */
Zero [8]int8
}
type inetPktinfo struct {
Ifindex uint32
Spec_dst [4]byte /* in_addr */
Addr [4]byte /* in_addr */
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type ipMreqSource struct {
Multiaddr [4]byte /* in_addr */
Sourceaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [256]byte
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [256]byte
Pad_cgo_1 [256]byte
}
================================================
FILE: vendor/golang.org/x/net/ipv4/zsys_zos_s390x.go
================================================
// 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.
// Hand edited based on zerrors_zos_s390x.go
// TODO(Bill O'Farrell): auto-generate.
package ipv4
const (
sizeofIPMreq = 8
sizeofSockaddrInet4 = 16
sizeofSockaddrStorage = 128
sizeofGroupReq = 136
sizeofGroupSourceReq = 264
sizeofInetPktinfo = 8
)
type sockaddrInet4 struct {
Len uint8
Family uint8
Port uint16
Addr [4]byte
Zero [8]uint8
}
type inetPktinfo struct {
Addr [4]byte
Ifindex uint32
}
type sockaddrStorage struct {
Len uint8
Family byte
ss_pad1 [6]byte
ss_align int64
ss_pad2 [112]byte
}
type groupReq struct {
Interface uint32
reserved uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
reserved uint32
Group sockaddrStorage
Source sockaddrStorage
}
type ipMreq struct {
Multiaddr [4]byte /* in_addr */
Interface [4]byte /* in_addr */
}
================================================
FILE: vendor/golang.org/x/net/ipv6/batch.go
================================================
// 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.
package ipv6
import (
"net"
"runtime"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ReadBatch and WriteBatch methods of
// PacketConn are not implemented.
// A Message represents an IO message.
//
// type Message struct {
// Buffers [][]byte
// OOB []byte
// Addr net.Addr
// N int
// NN int
// Flags int
// }
//
// The Buffers fields represents a list of contiguous buffers, which
// can be used for vectored IO, for example, putting a header and a
// payload in each slice.
// When writing, the Buffers field must contain at least one byte to
// write.
// When reading, the Buffers field will always contain a byte to read.
//
// The OOB field contains protocol-specific control or miscellaneous
// ancillary data known as out-of-band data.
// It can be nil when not required.
//
// The Addr field specifies a destination address when writing.
// It can be nil when the underlying protocol of the endpoint uses
// connection-oriented communication.
// After a successful read, it may contain the source address on the
// received packet.
//
// The N field indicates the number of bytes read or written from/to
// Buffers.
//
// The NN field indicates the number of bytes read or written from/to
// OOB.
//
// The Flags field contains protocol-specific information on the
// received message.
type Message = socket.Message
// ReadBatch reads a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_PEEK.
//
// On a successful read it returns the number of messages received, up
// to len(ms).
//
// On Linux, a batch read will be optimized.
// On other platforms, this method will read only a single message.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.RecvMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.RecvMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
}
}
// WriteBatch writes a batch of messages.
//
// The provided flags is a set of platform-dependent flags, such as
// syscall.MSG_DONTROUTE.
//
// It returns the number of messages written on a successful write.
//
// On Linux, a batch write will be optimized.
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
n, err := c.SendMsgs([]socket.Message(ms), flags)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
default:
n := 1
err := c.SendMsg(&ms[0], flags)
if err != nil {
n = 0
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
return n, err
}
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control.go
================================================
// Copyright 2013 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 ipv6
import (
"fmt"
"net"
"sync"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
)
// Note that RFC 3542 obsoletes RFC 2292 but OS X Snow Leopard and the
// former still support RFC 2292 only. Please be aware that almost
// all protocol implementations prohibit using a combination of RFC
// 2292 and RFC 3542 for some practical reasons.
type rawOpt struct {
sync.RWMutex
cflags ControlFlags
}
func (c *rawOpt) set(f ControlFlags) { c.cflags |= f }
func (c *rawOpt) clear(f ControlFlags) { c.cflags &^= f }
func (c *rawOpt) isset(f ControlFlags) bool { return c.cflags&f != 0 }
// A ControlFlags represents per packet basis IP-level socket option
// control flags.
type ControlFlags uint
const (
FlagTrafficClass ControlFlags = 1 << iota // pass the traffic class on the received packet
FlagHopLimit // pass the hop limit on the received packet
FlagSrc // pass the source address on the received packet
FlagDst // pass the destination address on the received packet
FlagInterface // pass the interface index on the received packet
FlagPathMTU // pass the path MTU on the received packet path
)
const flagPacketInfo = FlagDst | FlagInterface
// A ControlMessage represents per packet basis IP-level socket
// options.
type ControlMessage struct {
// Receiving socket options: SetControlMessage allows to
// receive the options from the protocol stack using ReadFrom
// method of PacketConn.
//
// Specifying socket options: ControlMessage for WriteTo
// method of PacketConn allows to send the options to the
// protocol stack.
//
TrafficClass int // traffic class, must be 1 <= value <= 255 when specifying
HopLimit int // hop limit, must be 1 <= value <= 255 when specifying
Src net.IP // source address, specifying only
Dst net.IP // destination address, receiving only
IfIndex int // interface index, must be 1 <= value when specifying
NextHop net.IP // next hop address, specifying only
MTU int // path MTU, receiving only
}
func (cm *ControlMessage) String() string {
if cm == nil {
return ""
}
return fmt.Sprintf("tclass=%#x hoplim=%d src=%v dst=%v ifindex=%d nexthop=%v mtu=%d", cm.TrafficClass, cm.HopLimit, cm.Src, cm.Dst, cm.IfIndex, cm.NextHop, cm.MTU)
}
// Marshal returns the binary encoding of cm.
func (cm *ControlMessage) Marshal() []byte {
if cm == nil {
return nil
}
var l int
tclass := false
if ctlOpts[ctlTrafficClass].name > 0 && cm.TrafficClass > 0 {
tclass = true
l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
}
hoplimit := false
if ctlOpts[ctlHopLimit].name > 0 && cm.HopLimit > 0 {
hoplimit = true
l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
}
pktinfo := false
if ctlOpts[ctlPacketInfo].name > 0 && (cm.Src.To16() != nil && cm.Src.To4() == nil || cm.IfIndex > 0) {
pktinfo = true
l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
}
nexthop := false
if ctlOpts[ctlNextHop].name > 0 && cm.NextHop.To16() != nil && cm.NextHop.To4() == nil {
nexthop = true
l += socket.ControlMessageSpace(ctlOpts[ctlNextHop].length)
}
var b []byte
if l > 0 {
b = make([]byte, l)
bb := b
if tclass {
bb = ctlOpts[ctlTrafficClass].marshal(bb, cm)
}
if hoplimit {
bb = ctlOpts[ctlHopLimit].marshal(bb, cm)
}
if pktinfo {
bb = ctlOpts[ctlPacketInfo].marshal(bb, cm)
}
if nexthop {
bb = ctlOpts[ctlNextHop].marshal(bb, cm)
}
}
return b
}
// Parse parses b as a control message and stores the result in cm.
func (cm *ControlMessage) Parse(b []byte) error {
ms, err := socket.ControlMessage(b).Parse()
if err != nil {
return err
}
for _, m := range ms {
lvl, typ, l, err := m.ParseHeader()
if err != nil {
return err
}
if lvl != iana.ProtocolIPv6 {
continue
}
switch {
case typ == ctlOpts[ctlTrafficClass].name && l >= ctlOpts[ctlTrafficClass].length:
ctlOpts[ctlTrafficClass].parse(cm, m.Data(l))
case typ == ctlOpts[ctlHopLimit].name && l >= ctlOpts[ctlHopLimit].length:
ctlOpts[ctlHopLimit].parse(cm, m.Data(l))
case typ == ctlOpts[ctlPacketInfo].name && l >= ctlOpts[ctlPacketInfo].length:
ctlOpts[ctlPacketInfo].parse(cm, m.Data(l))
case typ == ctlOpts[ctlPathMTU].name && l >= ctlOpts[ctlPathMTU].length:
ctlOpts[ctlPathMTU].parse(cm, m.Data(l))
}
}
return nil
}
// NewControlMessage returns a new control message.
//
// The returned message is large enough for options specified by cf.
func NewControlMessage(cf ControlFlags) []byte {
opt := rawOpt{cflags: cf}
var l int
if opt.isset(FlagTrafficClass) && ctlOpts[ctlTrafficClass].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlTrafficClass].length)
}
if opt.isset(FlagHopLimit) && ctlOpts[ctlHopLimit].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlHopLimit].length)
}
if opt.isset(flagPacketInfo) && ctlOpts[ctlPacketInfo].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlPacketInfo].length)
}
if opt.isset(FlagPathMTU) && ctlOpts[ctlPathMTU].name > 0 {
l += socket.ControlMessageSpace(ctlOpts[ctlPathMTU].length)
}
var b []byte
if l > 0 {
b = make([]byte, l)
}
return b
}
// Ancillary data socket options
const (
ctlTrafficClass = iota // header field
ctlHopLimit // header field
ctlPacketInfo // inbound or outbound packet path
ctlNextHop // nexthop
ctlPathMTU // path mtu
ctlMax
)
// A ctlOpt represents a binding for ancillary data socket option.
type ctlOpt struct {
name int // option name, must be equal or greater than 1
length int // option length
marshal func([]byte, *ControlMessage) []byte
parse func(*ControlMessage, []byte)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control_rfc2292_unix.go
================================================
// Copyright 2013 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 darwin
package ipv6
import (
"encoding/binary"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshal2292HopLimit(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_2292HOPLIMIT, 4)
if cm != nil {
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
return m.Next(4)
}
func marshal2292PacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_2292PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInet6Pktinfo)
}
func marshal2292NextHop(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_2292NEXTHOP, sizeofSockaddrInet6)
if cm != nil {
sa := (*sockaddrInet6)(unsafe.Pointer(&m.Data(sizeofSockaddrInet6)[0]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
return m.Next(sizeofSockaddrInet6)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control_rfc3542_unix.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import (
"encoding/binary"
"net"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func marshalTrafficClass(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_TCLASS, 4)
if cm != nil {
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.TrafficClass))
}
return m.Next(4)
}
func parseTrafficClass(cm *ControlMessage, b []byte) {
cm.TrafficClass = int(binary.NativeEndian.Uint32(b[:4]))
}
func marshalHopLimit(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_HOPLIMIT, 4)
if cm != nil {
binary.NativeEndian.PutUint32(m.Data(4), uint32(cm.HopLimit))
}
return m.Next(4)
}
func parseHopLimit(cm *ControlMessage, b []byte) {
cm.HopLimit = int(binary.NativeEndian.Uint32(b[:4]))
}
func marshalPacketInfo(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_PKTINFO, sizeofInet6Pktinfo)
if cm != nil {
pi := (*inet6Pktinfo)(unsafe.Pointer(&m.Data(sizeofInet6Pktinfo)[0]))
if ip := cm.Src.To16(); ip != nil && ip.To4() == nil {
copy(pi.Addr[:], ip)
}
if cm.IfIndex > 0 {
pi.setIfindex(cm.IfIndex)
}
}
return m.Next(sizeofInet6Pktinfo)
}
func parsePacketInfo(cm *ControlMessage, b []byte) {
pi := (*inet6Pktinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, pi.Addr[:])
cm.IfIndex = int(pi.Ifindex)
}
func marshalNextHop(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_NEXTHOP, sizeofSockaddrInet6)
if cm != nil {
sa := (*sockaddrInet6)(unsafe.Pointer(&m.Data(sizeofSockaddrInet6)[0]))
sa.setSockaddr(cm.NextHop, cm.IfIndex)
}
return m.Next(sizeofSockaddrInet6)
}
func parseNextHop(cm *ControlMessage, b []byte) {
}
func marshalPathMTU(b []byte, cm *ControlMessage) []byte {
m := socket.ControlMessage(b)
m.MarshalHeader(iana.ProtocolIPv6, unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo)
return m.Next(sizeofIPv6Mtuinfo)
}
func parsePathMTU(cm *ControlMessage, b []byte) {
mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
if len(cm.Dst) < net.IPv6len {
cm.Dst = make(net.IP, net.IPv6len)
}
copy(cm.Dst, mi.Addr.Addr[:])
cm.IfIndex = int(mi.Addr.Scope_id)
cm.MTU = int(mi.Mtu)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control_stub.go
================================================
// Copyright 2013 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv6
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control_unix.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
opt.Lock()
defer opt.Unlock()
if so, ok := sockOpts[ssoReceiveTrafficClass]; ok && cf&FlagTrafficClass != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagTrafficClass)
} else {
opt.clear(FlagTrafficClass)
}
}
if so, ok := sockOpts[ssoReceiveHopLimit]; ok && cf&FlagHopLimit != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagHopLimit)
} else {
opt.clear(FlagHopLimit)
}
}
if so, ok := sockOpts[ssoReceivePacketInfo]; ok && cf&flagPacketInfo != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(cf & flagPacketInfo)
} else {
opt.clear(cf & flagPacketInfo)
}
}
if so, ok := sockOpts[ssoReceivePathMTU]; ok && cf&FlagPathMTU != 0 {
if err := so.SetInt(c, boolint(on)); err != nil {
return err
}
if on {
opt.set(FlagPathMTU)
} else {
opt.clear(FlagPathMTU)
}
}
return nil
}
================================================
FILE: vendor/golang.org/x/net/ipv6/control_windows.go
================================================
// Copyright 2013 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 ipv6
import "golang.org/x/net/internal/socket"
func setControlMessage(c *socket.Conn, opt *rawOpt, cf ControlFlags, on bool) error {
// TODO(mikio): implement this
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/dgramopt.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"golang.org/x/net/bpf"
)
// MulticastHopLimit returns the hop limit field value for outgoing
// multicast packets.
func (c *dgramOpt) MulticastHopLimit() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetMulticastHopLimit sets the hop limit field value for future
// outgoing multicast packets.
func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, hoplim)
}
// MulticastInterface returns the default interface for multicast
// packet transmissions.
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return nil, errNotImplemented
}
return so.getMulticastInterface(c.Conn)
}
// SetMulticastInterface sets the default interface for future
// multicast packet transmissions.
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
return errNotImplemented
}
return so.setMulticastInterface(c.Conn, ifi)
}
// MulticastLoopback reports whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) MulticastLoopback() (bool, error) {
if !c.ok() {
return false, errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return false, errNotImplemented
}
on, err := so.GetInt(c.Conn)
if err != nil {
return false, err
}
return on == 1, nil
}
// SetMulticastLoopback sets whether transmitted multicast packets
// should be copied and send back to the originator.
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, boolint(on))
}
// JoinGroup joins the group address group on the interface ifi.
// By default all sources that can cast data to group are accepted.
// It's possible to mute and unmute data transmission from a specific
// source by using ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup.
// JoinGroup uses the system assigned multicast interface when ifi is
// nil, although this is not recommended because the assignment
// depends on platforms and sometimes it might require routing
// configuration.
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// LeaveGroup leaves the group address group on the interface ifi
// regardless of whether the group is any-source group or
// source-specific group.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
return so.setGroup(c.Conn, ifi, grp)
}
// JoinSourceSpecificGroup joins the source-specific group comprising
// group and source on the interface ifi.
// JoinSourceSpecificGroup uses the system assigned multicast
// interface when ifi is nil, although this is not recommended because
// the assignment depends on platforms and sometimes it might require
// routing configuration.
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoJoinSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// LeaveSourceSpecificGroup leaves the source-specific group on the
// interface ifi.
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// ExcludeSourceSpecificGroup excludes the source-specific group from
// the already joined any-source groups by JoinGroup on the interface
// ifi.
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoBlockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// IncludeSourceSpecificGroup includes the excluded source-specific
// group by ExcludeSourceSpecificGroup again on the interface ifi.
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoUnblockSourceGroup]
if !ok {
return errNotImplemented
}
grp := netAddrToIP16(group)
if grp == nil {
return errMissingAddress
}
src := netAddrToIP16(source)
if src == nil {
return errMissingAddress
}
return so.setSourceGroup(c.Conn, ifi, grp, src)
}
// Checksum reports whether the kernel will compute, store or verify a
// checksum for both incoming and outgoing packets. If on is true, it
// returns an offset in bytes into the data of where the checksum
// field is located.
func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
if !c.ok() {
return false, 0, errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
return false, 0, errNotImplemented
}
offset, err = so.GetInt(c.Conn)
if err != nil {
return false, 0, err
}
if offset < 0 {
return false, 0, nil
}
return true, offset, nil
}
// SetChecksum enables the kernel checksum processing. If on is true,
// the offset should be an offset in bytes into the data of where the
// checksum field is located.
func (c *dgramOpt) SetChecksum(on bool, offset int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
return errNotImplemented
}
if !on {
offset = -1
}
return so.SetInt(c.Conn, offset)
}
// ICMPFilter returns an ICMP filter.
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
if !c.ok() {
return nil, errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return nil, errNotImplemented
}
return so.getICMPFilter(c.Conn)
}
// SetICMPFilter deploys the ICMP filter.
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
return errNotImplemented
}
return so.setICMPFilter(c.Conn, f)
}
// SetBPF attaches a BPF program to the connection.
//
// Only supported on Linux.
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoAttachFilter]
if !ok {
return errNotImplemented
}
return so.setBPF(c.Conn, filter)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/doc.go
================================================
// Copyright 2013 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 ipv6 implements IP-level socket options for the Internet
// Protocol version 6.
//
// The package provides IP-level socket options that allow
// manipulation of IPv6 facilities.
//
// The IPv6 protocol is defined in RFC 8200.
// Socket interface extensions are defined in RFC 3493, RFC 3542 and
// RFC 3678.
// MLDv1 and MLDv2 are defined in RFC 2710 and RFC 3810.
// Source-specific multicast is defined in RFC 4607.
//
// On Darwin, this package requires OS X Mavericks version 10.9 or
// above, or equivalent.
//
// # Unicasting
//
// The options for unicasting are available for net.TCPConn,
// net.UDPConn and net.IPConn which are created as network connections
// that use the IPv6 transport. When a single TCP connection carrying
// a data flow of multiple packets needs to indicate the flow is
// important, Conn is used to set the traffic class field on the IPv6
// header for each packet.
//
// ln, err := net.Listen("tcp6", "[::]:1024")
// if err != nil {
// // error handling
// }
// defer ln.Close()
// for {
// c, err := ln.Accept()
// if err != nil {
// // error handling
// }
// go func(c net.Conn) {
// defer c.Close()
//
// The outgoing packets will be labeled DiffServ assured forwarding
// class 1 low drop precedence, known as AF11 packets.
//
// if err := ipv6.NewConn(c).SetTrafficClass(0x28); err != nil {
// // error handling
// }
// if _, err := c.Write(data); err != nil {
// // error handling
// }
// }(c)
// }
//
// # Multicasting
//
// The options for multicasting are available for net.UDPConn and
// net.IPConn which are created as network connections that use the
// IPv6 transport. A few network facilities must be prepared before
// you begin multicasting, at a minimum joining network interfaces and
// multicast groups.
//
// en0, err := net.InterfaceByName("en0")
// if err != nil {
// // error handling
// }
// en1, err := net.InterfaceByIndex(911)
// if err != nil {
// // error handling
// }
// group := net.ParseIP("ff02::114")
//
// First, an application listens to an appropriate address with an
// appropriate service port.
//
// c, err := net.ListenPacket("udp6", "[::]:1024")
// if err != nil {
// // error handling
// }
// defer c.Close()
//
// Second, the application joins multicast groups, starts listening to
// the groups on the specified network interfaces. Note that the
// service port for transport layer protocol does not matter with this
// operation as joining groups affects only network and link layer
// protocols, such as IPv6 and Ethernet.
//
// p := ipv6.NewPacketConn(c)
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: group}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en1, &net.UDPAddr{IP: group}); err != nil {
// // error handling
// }
//
// The application might set per packet control message transmissions
// between the protocol stack within the kernel. When the application
// needs a destination address on an incoming packet,
// SetControlMessage of PacketConn is used to enable control message
// transmissions.
//
// if err := p.SetControlMessage(ipv6.FlagDst, true); err != nil {
// // error handling
// }
//
// The application could identify whether the received packets are
// of interest by using the control message that contains the
// destination address of the received packet.
//
// b := make([]byte, 1500)
// for {
// n, rcm, src, err := p.ReadFrom(b)
// if err != nil {
// // error handling
// }
// if rcm.Dst.IsMulticast() {
// if rcm.Dst.Equal(group) {
// // joined group, do something
// } else {
// // unknown group, discard
// continue
// }
// }
//
// The application can also send both unicast and multicast packets.
//
// p.SetTrafficClass(0x0)
// p.SetHopLimit(16)
// if _, err := p.WriteTo(data[:n], nil, src); err != nil {
// // error handling
// }
// dst := &net.UDPAddr{IP: group, Port: 1024}
// wcm := ipv6.ControlMessage{TrafficClass: 0xe0, HopLimit: 1}
// for _, ifi := range []*net.Interface{en0, en1} {
// wcm.IfIndex = ifi.Index
// if _, err := p.WriteTo(data[:n], &wcm, dst); err != nil {
// // error handling
// }
// }
// }
//
// # More multicasting
//
// An application that uses PacketConn may join multiple multicast
// groups. For example, a UDP listener with port 1024 might join two
// different groups across over two different network interfaces by
// using:
//
// c, err := net.ListenPacket("udp6", "[::]:1024")
// if err != nil {
// // error handling
// }
// defer c.Close()
// p := ipv6.NewPacketConn(c)
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::1:114")}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en1, &net.UDPAddr{IP: net.ParseIP("ff02::2:114")}); err != nil {
// // error handling
// }
//
// It is possible for multiple UDP listeners that listen on the same
// UDP port to join the same multicast group. The net package will
// provide a socket that listens to a wildcard address with reusable
// UDP port when an appropriate multicast address prefix is passed to
// the net.ListenPacket or net.ListenUDP.
//
// c1, err := net.ListenPacket("udp6", "[ff02::]:1024")
// if err != nil {
// // error handling
// }
// defer c1.Close()
// c2, err := net.ListenPacket("udp6", "[ff02::]:1024")
// if err != nil {
// // error handling
// }
// defer c2.Close()
// p1 := ipv6.NewPacketConn(c1)
// if err := p1.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
// // error handling
// }
// p2 := ipv6.NewPacketConn(c2)
// if err := p2.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
// // error handling
// }
//
// Also it is possible for the application to leave or rejoin a
// multicast group on the network interface.
//
// if err := p.LeaveGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff02::114")}); err != nil {
// // error handling
// }
// if err := p.JoinGroup(en0, &net.UDPAddr{IP: net.ParseIP("ff01::114")}); err != nil {
// // error handling
// }
//
// # Source-specific multicasting
//
// An application that uses PacketConn on MLDv2 supported platform is
// able to join source-specific multicast groups.
// The application may use JoinSourceSpecificGroup and
// LeaveSourceSpecificGroup for the operation known as "include" mode,
//
// ssmgroup := net.UDPAddr{IP: net.ParseIP("ff32::8000:9")}
// ssmsource := net.UDPAddr{IP: net.ParseIP("fe80::cafe")}
// if err := p.JoinSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
// // error handling
// }
// if err := p.LeaveSourceSpecificGroup(en0, &ssmgroup, &ssmsource); err != nil {
// // error handling
// }
//
// or JoinGroup, ExcludeSourceSpecificGroup,
// IncludeSourceSpecificGroup and LeaveGroup for the operation known
// as "exclude" mode.
//
// exclsource := net.UDPAddr{IP: net.ParseIP("fe80::dead")}
// if err := p.JoinGroup(en0, &ssmgroup); err != nil {
// // error handling
// }
// if err := p.ExcludeSourceSpecificGroup(en0, &ssmgroup, &exclsource); err != nil {
// // error handling
// }
// if err := p.LeaveGroup(en0, &ssmgroup); err != nil {
// // error handling
// }
//
// Note that it depends on each platform implementation what happens
// when an application which runs on MLDv2 unsupported platform uses
// JoinSourceSpecificGroup and LeaveSourceSpecificGroup.
// In general the platform tries to fall back to conversations using
// MLDv1 and starts to listen to multicast traffic.
// In the fallback case, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup may return an error.
package ipv6 // import "golang.org/x/net/ipv6"
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
================================================
FILE: vendor/golang.org/x/net/ipv6/endpoint.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"time"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the JoinSourceSpecificGroup,
// LeaveSourceSpecificGroup, ExcludeSourceSpecificGroup and
// IncludeSourceSpecificGroup methods of PacketConn are not
// implemented.
// A Conn represents a network endpoint that uses IPv6 transport.
// It allows to set basic IP-level socket options such as traffic
// class and hop limit.
type Conn struct {
genericOpt
}
type genericOpt struct {
*socket.Conn
}
func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// PathMTU returns a path MTU value for the destination associated
// with the endpoint.
func (c *Conn) PathMTU() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoPathMTU]
if !ok {
return 0, errNotImplemented
}
_, mtu, err := so.getMTUInfo(c.Conn)
if err != nil {
return 0, err
}
return mtu, nil
}
// NewConn returns a new Conn.
func NewConn(c net.Conn) *Conn {
cc, _ := socket.NewConn(c)
return &Conn{
genericOpt: genericOpt{Conn: cc},
}
}
// A PacketConn represents a packet network endpoint that uses IPv6
// transport. It is used to control several IP-level socket options
// including IPv6 header manipulation. It also provides datagram
// based network I/O methods specific to the IPv6 and higher layer
// protocols such as OSPF, GRE, and UDP.
type PacketConn struct {
genericOpt
dgramOpt
payloadHandler
}
type dgramOpt struct {
*socket.Conn
}
func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage allows to receive the per packet basis IP-level
// socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
// SetDeadline sets the read and write deadlines associated with the
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetDeadline(t)
}
// SetReadDeadline sets the read deadline associated with the
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetReadDeadline(t)
}
// SetWriteDeadline sets the write deadline associated with the
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.SetWriteDeadline(t)
}
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.payloadHandler.ok() {
return errInvalidConn
}
return c.payloadHandler.Close()
}
// NewPacketConn returns a new PacketConn using c as its underlying
// transport.
func NewPacketConn(c net.PacketConn) *PacketConn {
cc, _ := socket.NewConn(c.(net.Conn))
return &PacketConn{
genericOpt: genericOpt{Conn: cc},
dgramOpt: dgramOpt{Conn: cc},
payloadHandler: payloadHandler{PacketConn: c, Conn: cc},
}
}
================================================
FILE: vendor/golang.org/x/net/ipv6/genericopt.go
================================================
// Copyright 2013 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 ipv6
// TrafficClass returns the traffic class field value for outgoing
// packets.
func (c *genericOpt) TrafficClass() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetTrafficClass sets the traffic class field value for future
// outgoing packets.
func (c *genericOpt) SetTrafficClass(tclass int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, tclass)
}
// HopLimit returns the hop limit field value for outgoing packets.
func (c *genericOpt) HopLimit() (int, error) {
if !c.ok() {
return 0, errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {
return 0, errNotImplemented
}
return so.GetInt(c.Conn)
}
// SetHopLimit sets the hop limit field value for future outgoing
// packets.
func (c *genericOpt) SetHopLimit(hoplim int) error {
if !c.ok() {
return errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {
return errNotImplemented
}
return so.SetInt(c.Conn, hoplim)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/header.go
================================================
// 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.
package ipv6
import (
"encoding/binary"
"fmt"
"net"
)
const (
Version = 6 // protocol version
HeaderLen = 40 // header length
)
// A Header represents an IPv6 base header.
type Header struct {
Version int // protocol version
TrafficClass int // traffic class
FlowLabel int // flow label
PayloadLen int // payload length
NextHeader int // next header
HopLimit int // hop limit
Src net.IP // source address
Dst net.IP // destination address
}
func (h *Header) String() string {
if h == nil {
return ""
}
return fmt.Sprintf("ver=%d tclass=%#x flowlbl=%#x payloadlen=%d nxthdr=%d hoplim=%d src=%v dst=%v", h.Version, h.TrafficClass, h.FlowLabel, h.PayloadLen, h.NextHeader, h.HopLimit, h.Src, h.Dst)
}
// ParseHeader parses b as an IPv6 base header.
func ParseHeader(b []byte) (*Header, error) {
if len(b) < HeaderLen {
return nil, errHeaderTooShort
}
h := &Header{
Version: int(b[0]) >> 4,
TrafficClass: int(b[0]&0x0f)<<4 | int(b[1])>>4,
FlowLabel: int(b[1]&0x0f)<<16 | int(b[2])<<8 | int(b[3]),
PayloadLen: int(binary.BigEndian.Uint16(b[4:6])),
NextHeader: int(b[6]),
HopLimit: int(b[7]),
}
h.Src = make(net.IP, net.IPv6len)
copy(h.Src, b[8:24])
h.Dst = make(net.IP, net.IPv6len)
copy(h.Dst, b[24:40])
return h, nil
}
================================================
FILE: vendor/golang.org/x/net/ipv6/helper.go
================================================
// Copyright 2013 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 ipv6
import (
"errors"
"net"
"runtime"
)
var (
errInvalidConn = errors.New("invalid connection")
errMissingAddress = errors.New("missing address")
errHeaderTooShort = errors.New("header too short")
errInvalidConnType = errors.New("invalid conn type")
errNotImplemented = errors.New("not implemented on " + runtime.GOOS + "/" + runtime.GOARCH)
)
func boolint(b bool) int {
if b {
return 1
}
return 0
}
func netAddrToIP16(a net.Addr) net.IP {
switch v := a.(type) {
case *net.UDPAddr:
if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
return ip
}
case *net.IPAddr:
if ip := v.IP.To16(); ip != nil && ip.To4() == nil {
return ip
}
}
return nil
}
func opAddr(a net.Addr) net.Addr {
switch a.(type) {
case *net.TCPAddr:
if a == nil {
return nil
}
case *net.UDPAddr:
if a == nil {
return nil
}
case *net.IPAddr:
if a == nil {
return nil
}
}
return a
}
================================================
FILE: vendor/golang.org/x/net/ipv6/iana.go
================================================
// go generate gen.go
// Code generated by the command above; DO NOT EDIT.
package ipv6
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
const (
ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable
ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big
ICMPTypeTimeExceeded ICMPType = 3 // Time Exceeded
ICMPTypeParameterProblem ICMPType = 4 // Parameter Problem
ICMPTypeEchoRequest ICMPType = 128 // Echo Request
ICMPTypeEchoReply ICMPType = 129 // Echo Reply
ICMPTypeMulticastListenerQuery ICMPType = 130 // Multicast Listener Query
ICMPTypeMulticastListenerReport ICMPType = 131 // Multicast Listener Report
ICMPTypeMulticastListenerDone ICMPType = 132 // Multicast Listener Done
ICMPTypeRouterSolicitation ICMPType = 133 // Router Solicitation
ICMPTypeRouterAdvertisement ICMPType = 134 // Router Advertisement
ICMPTypeNeighborSolicitation ICMPType = 135 // Neighbor Solicitation
ICMPTypeNeighborAdvertisement ICMPType = 136 // Neighbor Advertisement
ICMPTypeRedirect ICMPType = 137 // Redirect Message
ICMPTypeRouterRenumbering ICMPType = 138 // Router Renumbering
ICMPTypeNodeInformationQuery ICMPType = 139 // ICMP Node Information Query
ICMPTypeNodeInformationResponse ICMPType = 140 // ICMP Node Information Response
ICMPTypeInverseNeighborDiscoverySolicitation ICMPType = 141 // Inverse Neighbor Discovery Solicitation Message
ICMPTypeInverseNeighborDiscoveryAdvertisement ICMPType = 142 // Inverse Neighbor Discovery Advertisement Message
ICMPTypeVersion2MulticastListenerReport ICMPType = 143 // Version 2 Multicast Listener Report
ICMPTypeHomeAgentAddressDiscoveryRequest ICMPType = 144 // Home Agent Address Discovery Request Message
ICMPTypeHomeAgentAddressDiscoveryReply ICMPType = 145 // Home Agent Address Discovery Reply Message
ICMPTypeMobilePrefixSolicitation ICMPType = 146 // Mobile Prefix Solicitation
ICMPTypeMobilePrefixAdvertisement ICMPType = 147 // Mobile Prefix Advertisement
ICMPTypeCertificationPathSolicitation ICMPType = 148 // Certification Path Solicitation Message
ICMPTypeCertificationPathAdvertisement ICMPType = 149 // Certification Path Advertisement Message
ICMPTypeMulticastRouterAdvertisement ICMPType = 151 // Multicast Router Advertisement
ICMPTypeMulticastRouterSolicitation ICMPType = 152 // Multicast Router Solicitation
ICMPTypeMulticastRouterTermination ICMPType = 153 // Multicast Router Termination
ICMPTypeFMIPv6 ICMPType = 154 // FMIPv6 Messages
ICMPTypeRPLControl ICMPType = 155 // RPL Control Message
ICMPTypeILNPv6LocatorUpdate ICMPType = 156 // ILNPv6 Locator Update Message
ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request
ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation
ICMPTypeMPLControl ICMPType = 159 // MPL Control Message
ICMPTypeExtendedEchoRequest ICMPType = 160 // Extended Echo Request
ICMPTypeExtendedEchoReply ICMPType = 161 // Extended Echo Reply
)
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
var icmpTypes = map[ICMPType]string{
1: "destination unreachable",
2: "packet too big",
3: "time exceeded",
4: "parameter problem",
128: "echo request",
129: "echo reply",
130: "multicast listener query",
131: "multicast listener report",
132: "multicast listener done",
133: "router solicitation",
134: "router advertisement",
135: "neighbor solicitation",
136: "neighbor advertisement",
137: "redirect message",
138: "router renumbering",
139: "icmp node information query",
140: "icmp node information response",
141: "inverse neighbor discovery solicitation message",
142: "inverse neighbor discovery advertisement message",
143: "version 2 multicast listener report",
144: "home agent address discovery request message",
145: "home agent address discovery reply message",
146: "mobile prefix solicitation",
147: "mobile prefix advertisement",
148: "certification path solicitation message",
149: "certification path advertisement message",
151: "multicast router advertisement",
152: "multicast router solicitation",
153: "multicast router termination",
154: "fmipv6 messages",
155: "rpl control message",
156: "ilnpv6 locator update message",
157: "duplicate address request",
158: "duplicate address confirmation",
159: "mpl control message",
160: "extended echo request",
161: "extended echo reply",
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp.go
================================================
// Copyright 2013 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 ipv6
import "golang.org/x/net/internal/iana"
// BUG(mikio): On Windows, methods related to ICMPFilter are not
// implemented.
// An ICMPType represents a type of ICMP message.
type ICMPType int
func (typ ICMPType) String() string {
s, ok := icmpTypes[typ]
if !ok {
return ""
}
return s
}
// Protocol returns the ICMPv6 protocol number.
func (typ ICMPType) Protocol() int {
return iana.ProtocolIPv6ICMP
}
// An ICMPFilter represents an ICMP message filter for incoming
// packets. The filter belongs to a packet delivery path on a host and
// it cannot interact with forwarding packets or tunnel-outer packets.
//
// Note: RFC 8200 defines a reasonable role model. A node means a
// device that implements IP. A router means a node that forwards IP
// packets not explicitly addressed to itself, and a host means a node
// that is not a router.
type ICMPFilter struct {
icmpv6Filter
}
// Accept accepts incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Accept(typ ICMPType) {
f.accept(typ)
}
// Block blocks incoming ICMP packets including the type field value
// typ.
func (f *ICMPFilter) Block(typ ICMPType) {
f.block(typ)
}
// SetAll sets the filter action to the filter.
func (f *ICMPFilter) SetAll(block bool) {
f.setAll(block)
}
// WillBlock reports whether the ICMP type will be blocked.
func (f *ICMPFilter) WillBlock(typ ICMPType) bool {
return f.willBlock(typ)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_bsd.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || netbsd || openbsd
package ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
f.Filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) block(typ ICMPType) {
f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Filt {
if block {
f.Filt[i] = 0
} else {
f.Filt[i] = 1<<32 - 1
}
}
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_linux.go
================================================
// Copyright 2013 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 ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
f.Data[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) block(typ ICMPType) {
f.Data[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Data {
if block {
f.Data[i] = 1<<32 - 1
} else {
f.Data[i] = 0
}
}
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Data[typ>>5]&(1<<(uint32(typ)&31)) != 0
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_solaris.go
================================================
// Copyright 2013 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 ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
f.X__icmp6_filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) block(typ ICMPType) {
f.X__icmp6_filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) setAll(block bool) {
for i := range f.X__icmp6_filt {
if block {
f.X__icmp6_filt[i] = 0
} else {
f.X__icmp6_filt[i] = 1<<32 - 1
}
}
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.X__icmp6_filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_stub.go
================================================
// Copyright 2013 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv6
type icmpv6Filter struct {
}
func (f *icmpv6Filter) accept(typ ICMPType) {
}
func (f *icmpv6Filter) block(typ ICMPType) {
}
func (f *icmpv6Filter) setAll(block bool) {
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return false
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_windows.go
================================================
// Copyright 2013 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 ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
// TODO(mikio): implement this
}
func (f *icmpv6Filter) block(typ ICMPType) {
// TODO(mikio): implement this
}
func (f *icmpv6Filter) setAll(block bool) {
// TODO(mikio): implement this
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
// TODO(mikio): implement this
return false
}
================================================
FILE: vendor/golang.org/x/net/ipv6/icmp_zos.go
================================================
// 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.
package ipv6
func (f *icmpv6Filter) accept(typ ICMPType) {
f.Filt[typ>>5] |= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) block(typ ICMPType) {
f.Filt[typ>>5] &^= 1 << (uint32(typ) & 31)
}
func (f *icmpv6Filter) setAll(block bool) {
for i := range f.Filt {
if block {
f.Filt[i] = 0
} else {
f.Filt[i] = 1<<32 - 1
}
}
}
func (f *icmpv6Filter) willBlock(typ ICMPType) bool {
return f.Filt[typ>>5]&(1<<(uint32(typ)&31)) == 0
}
================================================
FILE: vendor/golang.org/x/net/ipv6/payload.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
// BUG(mikio): On Windows, the ControlMessage for ReadFrom and WriteTo
// methods of PacketConn is not implemented.
// A payloadHandler represents the IPv6 datagram payload handler.
type payloadHandler struct {
net.PacketConn
*socket.Conn
rawOpt
}
func (c *payloadHandler) ok() bool { return c != nil && c.PacketConn != nil && c.Conn != nil }
================================================
FILE: vendor/golang.org/x/net/ipv6/payload_cmsg.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
// ReadFrom reads a payload of the received IPv6 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, errInvalidConn
}
c.rawOpt.RLock()
m := socket.Message{
Buffers: [][]byte{b},
OOB: NewControlMessage(c.rawOpt.cflags),
}
c.rawOpt.RUnlock()
switch c.PacketConn.(type) {
case *net.UDPConn:
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
case *net.IPConn:
if err := c.RecvMsg(&m, 0); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
default:
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: errInvalidConnType}
}
if m.NN > 0 {
cm = new(ControlMessage)
if err := cm.Parse(m.OOB[:m.NN]); err != nil {
return 0, nil, nil, &net.OpError{Op: "read", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Err: err}
}
cm.Src = netAddrToIP16(m.Addr)
}
return m.N, cm, m.Addr, nil
}
// WriteTo writes a payload of the IPv6 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the IPv6 header fields and the datagram path to be specified. The
// cm may be nil if control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, errInvalidConn
}
m := socket.Message{
Buffers: [][]byte{b},
OOB: cm.Marshal(),
Addr: dst,
}
err = c.SendMsg(&m, 0)
if err != nil {
err = &net.OpError{Op: "write", Net: c.PacketConn.LocalAddr().Network(), Source: c.PacketConn.LocalAddr(), Addr: opAddr(dst), Err: err}
}
return m.N, err
}
================================================
FILE: vendor/golang.org/x/net/ipv6/payload_nocmsg.go
================================================
// Copyright 2013 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
package ipv6
import "net"
// ReadFrom reads a payload of the received IPv6 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
// bytes copied into b, the control message cm and the source address
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, errInvalidConn
}
if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
return 0, nil, nil, err
}
return
}
// WriteTo writes a payload of the IPv6 datagram, to the destination
// address dst through the endpoint c, copying the payload from b. It
// returns the number of bytes written. The control message cm allows
// the IPv6 header fields and the datagram path to be specified. The
// cm may be nil if control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, errInvalidConn
}
if dst == nil {
return 0, errMissingAddress
}
return c.PacketConn.WriteTo(b, dst)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sockopt.go
================================================
// 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.
package ipv6
import "golang.org/x/net/internal/socket"
// Sticky socket options
const (
ssoTrafficClass = iota // header field for unicast packet, RFC 3542
ssoHopLimit // header field for unicast packet, RFC 3493
ssoMulticastInterface // outbound interface for multicast packet, RFC 3493
ssoMulticastHopLimit // header field for multicast packet, RFC 3493
ssoMulticastLoopback // loopback for multicast packet, RFC 3493
ssoReceiveTrafficClass // header field on received packet, RFC 3542
ssoReceiveHopLimit // header field on received packet, RFC 2292 or 3542
ssoReceivePacketInfo // incbound or outbound packet path, RFC 2292 or 3542
ssoReceivePathMTU // path mtu, RFC 3542
ssoPathMTU // path mtu, RFC 3542
ssoChecksum // packet checksum, RFC 2292 or 3542
ssoICMPFilter // icmp filter, RFC 2292 or 3542
ssoJoinGroup // any-source multicast, RFC 3493
ssoLeaveGroup // any-source multicast, RFC 3493
ssoJoinSourceGroup // source-specific multicast
ssoLeaveSourceGroup // source-specific multicast
ssoBlockSourceGroup // any-source or source-specific multicast
ssoUnblockSourceGroup // any-source or source-specific multicast
ssoAttachFilter // attach BPF for filtering inbound traffic
)
// Sticky socket option value types
const (
ssoTypeIPMreq = iota + 1
ssoTypeGroupReq
ssoTypeGroupSourceReq
)
// A sockOpt represents a binding for sticky socket option.
type sockOpt struct {
socket.Option
typ int // hint for option value type; optional
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sockopt_posix.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows || zos
package ipv6
import (
"net"
"runtime"
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
n, err := so.GetInt(c)
if err != nil {
return nil, err
}
return net.InterfaceByIndex(n)
}
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
var n int
if ifi != nil {
n = ifi.Index
}
return so.SetInt(c, n)
}
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
b := make([]byte, so.Len)
n, err := so.Get(c, b)
if err != nil {
return nil, err
}
if n != sizeofICMPv6Filter {
return nil, errNotImplemented
}
return (*ICMPFilter)(unsafe.Pointer(&b[0])), nil
}
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
b := (*[sizeofICMPv6Filter]byte)(unsafe.Pointer(f))[:sizeofICMPv6Filter]
return so.Set(c, b)
}
func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
b := make([]byte, so.Len)
n, err := so.Get(c, b)
if err != nil {
return nil, 0, err
}
if n != sizeofIPv6Mtuinfo {
return nil, 0, errNotImplemented
}
mi := (*ipv6Mtuinfo)(unsafe.Pointer(&b[0]))
if mi.Addr.Scope_id == 0 || runtime.GOOS == "aix" {
// AIX kernel might return a wrong address.
return nil, int(mi.Mtu), nil
}
ifi, err := net.InterfaceByIndex(int(mi.Addr.Scope_id))
if err != nil {
return nil, 0, err
}
return ifi, int(mi.Mtu), nil
}
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
switch so.typ {
case ssoTypeIPMreq:
return so.setIPMreq(c, ifi, grp)
case ssoTypeGroupReq:
return so.setGroupReq(c, ifi, grp)
default:
return errNotImplemented
}
}
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return so.setGroupSourceReq(c, ifi, grp, src)
}
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return so.setAttachFilter(c, f)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sockopt_stub.go
================================================
// Copyright 2013 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv6
import (
"net"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) getMulticastInterface(c *socket.Conn) (*net.Interface, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setMulticastInterface(c *socket.Conn, ifi *net.Interface) error {
return errNotImplemented
}
func (so *sockOpt) getICMPFilter(c *socket.Conn) (*ICMPFilter, error) {
return nil, errNotImplemented
}
func (so *sockOpt) setICMPFilter(c *socket.Conn, f *ICMPFilter) error {
return errNotImplemented
}
func (so *sockOpt) getMTUInfo(c *socket.Conn) (*net.Interface, int, error) {
return nil, 0, errNotImplemented
}
func (so *sockOpt) setGroup(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setSourceGroup(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setBPF(c *socket.Conn, f []bpf.RawInstruction) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_aix.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Added for go1.11 compatibility
//go:build aix
package ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {unix.IPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 132))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_asmreq.go
================================================
// Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
package ipv6
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var mreq ipv6Mreq
copy(mreq.Multiaddr[:], grp)
if ifi != nil {
mreq.setIfindex(ifi.Index)
}
b := (*[sizeofIPv6Mreq]byte)(unsafe.Pointer(&mreq))[:sizeofIPv6Mreq]
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_asmreq_stub.go
================================================
// Copyright 2013 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows
package ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setIPMreq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_bpf.go
================================================
// 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 linux
package ipv6
import (
"unsafe"
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
prog := unix.SockFprog{
Len: uint16(len(f)),
Filter: (*unix.SockFilter)(unsafe.Pointer(&f[0])),
}
b := (*[unix.SizeofSockFprog]byte)(unsafe.Pointer(&prog))[:unix.SizeofSockFprog]
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_bpf_stub.go
================================================
// 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 !linux
package ipv6
import (
"golang.org/x/net/bpf"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setAttachFilter(c *socket.Conn, f []bpf.RawInstruction) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_bsd.go
================================================
// Copyright 2013 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 dragonfly || netbsd || openbsd
package ipv6
import (
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {unix.IPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_darwin.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {unix.IPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 132))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_freebsd.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"runtime"
"strings"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {unix.IPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func init() {
if runtime.GOOS == "freebsd" && runtime.GOARCH == "386" {
archs, _ := syscall.Sysctl("kern.supported_archs")
for _, s := range strings.Fields(archs) {
if s == "amd64" {
compatFreeBSD32 = true
break
}
}
}
}
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
sa.Len = sizeofSockaddrInet6
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_linux.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolReserved, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMPV6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoAttachFilter: {Option: socket.Option{Level: unix.SOL_SOCKET, Name: unix.SO_ATTACH_FILTER, Len: unix.SizeofSockFprog}},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = int32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Ifindex = int32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_solaris.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlTrafficClass: {unix.IPV6_TCLASS, 4, marshalTrafficClass, parseTrafficClass},
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlNextHop: {unix.IPV6_NEXTHOP, sizeofSockaddrInet6, marshalNextHop, parseNextHop},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoPathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_PATHMTU, Len: sizeofIPv6Mtuinfo}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gr)) + 4))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 4))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(uintptr(unsafe.Pointer(gsr)) + 260))
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_ssmreq.go
================================================
// 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 aix || darwin || freebsd || linux || solaris || zos
package ipv6
import (
"net"
"unsafe"
"golang.org/x/net/internal/socket"
)
var compatFreeBSD32 bool // 386 emulation on amd64
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
var gr groupReq
if ifi != nil {
gr.Interface = uint32(ifi.Index)
}
gr.setGroup(grp)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupReq + 4]byte
s := (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupReq]byte)(unsafe.Pointer(&gr))[:sizeofGroupReq]
}
return so.Set(c, b)
}
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
var gsr groupSourceReq
if ifi != nil {
gsr.Interface = uint32(ifi.Index)
}
gsr.setSourceGroup(grp, src)
var b []byte
if compatFreeBSD32 {
var d [sizeofGroupSourceReq + 4]byte
s := (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))
copy(d[:4], s[:4])
copy(d[8:], s[4:])
b = d[:]
} else {
b = (*[sizeofGroupSourceReq]byte)(unsafe.Pointer(&gsr))[:sizeofGroupSourceReq]
}
return so.Set(c, b)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_ssmreq_stub.go
================================================
// 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 !aix && !darwin && !freebsd && !linux && !solaris && !zos
package ipv6
import (
"net"
"golang.org/x/net/internal/socket"
)
func (so *sockOpt) setGroupReq(c *socket.Conn, ifi *net.Interface, grp net.IP) error {
return errNotImplemented
}
func (so *sockOpt) setGroupSourceReq(c *socket.Conn, ifi *net.Interface, grp, src net.IP) error {
return errNotImplemented
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_stub.go
================================================
// 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 !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !windows && !zos
package ipv6
var (
ctlOpts = [ctlMax]ctlOpt{}
sockOpts = map[int]*sockOpt{}
)
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_windows.go
================================================
// Copyright 2013 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 ipv6
import (
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/windows"
)
const (
sizeofSockaddrInet6 = 0x1c
sizeofIPv6Mreq = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofICMPv6Filter = 0
)
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type icmpv6Filter struct {
// TODO(mikio): implement this
}
var (
ctlOpts = [ctlMax]ctlOpt{}
sockOpts = map[int]*sockOpt{
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_MULTICAST_LOOP, Len: 4}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_JOIN_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: windows.IPV6_LEAVE_GROUP, Len: sizeofIPv6Mreq}, typ: ssoTypeIPMreq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (mreq *ipv6Mreq) setIfindex(i int) {
mreq.Interface = uint32(i)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/sys_zos.go
================================================
// 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.
package ipv6
import (
"net"
"syscall"
"unsafe"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/socket"
"golang.org/x/sys/unix"
)
var (
ctlOpts = [ctlMax]ctlOpt{
ctlHopLimit: {unix.IPV6_HOPLIMIT, 4, marshalHopLimit, parseHopLimit},
ctlPacketInfo: {unix.IPV6_PKTINFO, sizeofInet6Pktinfo, marshalPacketInfo, parsePacketInfo},
ctlPathMTU: {unix.IPV6_PATHMTU, sizeofIPv6Mtuinfo, marshalPathMTU, parsePathMTU},
}
sockOpts = map[int]*sockOpt{
ssoTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_TCLASS, Len: 4}},
ssoHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_UNICAST_HOPS, Len: 4}},
ssoMulticastInterface: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_IF, Len: 4}},
ssoMulticastHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_HOPS, Len: 4}},
ssoMulticastLoopback: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_MULTICAST_LOOP, Len: 4}},
ssoReceiveTrafficClass: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVTCLASS, Len: 4}},
ssoReceiveHopLimit: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVHOPLIMIT, Len: 4}},
ssoReceivePacketInfo: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPKTINFO, Len: 4}},
ssoReceivePathMTU: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_RECVPATHMTU, Len: 4}},
ssoChecksum: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.IPV6_CHECKSUM, Len: 4}},
ssoICMPFilter: {Option: socket.Option{Level: iana.ProtocolIPv6ICMP, Name: unix.ICMP6_FILTER, Len: sizeofICMPv6Filter}},
ssoJoinGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoLeaveGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_GROUP, Len: sizeofGroupReq}, typ: ssoTypeGroupReq},
ssoJoinSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_JOIN_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoLeaveSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_LEAVE_SOURCE_GROUP, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoBlockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_BLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
ssoUnblockSourceGroup: {Option: socket.Option{Level: iana.ProtocolIPv6, Name: unix.MCAST_UNBLOCK_SOURCE, Len: sizeofGroupSourceReq}, typ: ssoTypeGroupSourceReq},
}
)
func (sa *sockaddrInet6) setSockaddr(ip net.IP, i int) {
sa.Family = syscall.AF_INET6
copy(sa.Addr[:], ip)
sa.Scope_id = uint32(i)
}
func (pi *inet6Pktinfo) setIfindex(i int) {
pi.Ifindex = uint32(i)
}
func (gr *groupReq) setGroup(grp net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gr.Group))
sa.Family = syscall.AF_INET6
sa.Len = sizeofSockaddrInet6
copy(sa.Addr[:], grp)
}
func (gsr *groupSourceReq) setSourceGroup(grp, src net.IP) {
sa := (*sockaddrInet6)(unsafe.Pointer(&gsr.Group))
sa.Family = syscall.AF_INET6
sa.Len = sizeofSockaddrInet6
copy(sa.Addr[:], grp)
sa = (*sockaddrInet6)(unsafe.Pointer(&gsr.Source))
sa.Family = syscall.AF_INET6
sa.Len = sizeofSockaddrInet6
copy(sa.Addr[:], src)
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_aix_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_aix.go
// Added for go1.11 compatibility
//go:build aix
package ipv6
const (
sizeofSockaddrStorage = 0x508
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x510
sizeofGroupSourceReq = 0xa18
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
X__ss_len uint8
Family uint8
X__ss_pad1 [6]uint8
X__ss_align int64
X__ss_pad2 [1265]uint8
Pad_cgo_0 [7]byte
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type icmpv6Filter struct {
Filt [8]uint32
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_darwin.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_darwin.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type icmpv6Filter struct {
Filt [8]uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [128]byte
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [128]byte
Pad_cgo_1 [128]byte
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_dragonfly.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_dragonfly.go
package ipv6
const (
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofICMPv6Filter = 0x20
)
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_freebsd_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_freebsd_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_freebsd_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]int8
X__ss_align int64
X__ss_pad2 [112]int8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_freebsd_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]uint8
X__ss_align int64
X__ss_pad2 [112]uint8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_freebsd_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_freebsd.go
package ipv6
const (
sizeofSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Len uint8
Family uint8
X__ss_pad1 [6]uint8
X__ss_align int64
X__ss_pad2 [112]uint8
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_386.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_amd64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_arm.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_arm64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_loong64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build loong64
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_mips.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_mips64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_mips64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_mipsle.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_ppc.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x84
sizeofGroupSourceReq = 0x104
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]uint8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_ppc64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_ppc64le.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_riscv64.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
//go:build riscv64
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_linux_s390x.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_linux.go
package ipv6
const (
sizeofKernelSockaddrStorage = 0x80
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6FlowlabelReq = 0x20
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x88
sizeofGroupSourceReq = 0x108
sizeofICMPv6Filter = 0x20
)
type kernelSockaddrStorage struct {
Family uint16
X__data [126]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex int32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6FlowlabelReq struct {
Dst [16]byte /* in6_addr */
Label uint32
Action uint8
Share uint8
Flags uint16
Expires uint16
Linger uint16
X__flr_pad uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Ifindex int32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [4]byte
Group kernelSockaddrStorage
Source kernelSockaddrStorage
}
type icmpv6Filter struct {
Data [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_netbsd.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_netbsd.go
package ipv6
const (
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofICMPv6Filter = 0x20
)
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_openbsd.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_openbsd.go
package ipv6
const (
sizeofSockaddrInet6 = 0x1c
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x20
sizeofIPv6Mreq = 0x14
sizeofICMPv6Filter = 0x20
)
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_solaris.go
================================================
// Code generated by cmd/cgo -godefs; DO NOT EDIT.
// cgo -godefs defs_solaris.go
package ipv6
const (
sizeofSockaddrStorage = 0x100
sizeofSockaddrInet6 = 0x20
sizeofInet6Pktinfo = 0x14
sizeofIPv6Mtuinfo = 0x24
sizeofIPv6Mreq = 0x14
sizeofGroupReq = 0x104
sizeofGroupSourceReq = 0x204
sizeofICMPv6Filter = 0x20
)
type sockaddrStorage struct {
Family uint16
X_ss_pad1 [6]int8
X_ss_align float64
X_ss_pad2 [240]int8
}
type sockaddrInet6 struct {
Family uint16
Port uint16
Flowinfo uint32
Addr [16]byte /* in6_addr */
Scope_id uint32
X__sin6_src_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte /* in6_addr */
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type ipv6Mreq struct {
Multiaddr [16]byte /* in6_addr */
Interface uint32
}
type groupReq struct {
Interface uint32
Pad_cgo_0 [256]byte
}
type groupSourceReq struct {
Interface uint32
Pad_cgo_0 [256]byte
Pad_cgo_1 [256]byte
}
type icmpv6Filter struct {
X__icmp6_filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/net/ipv6/zsys_zos_s390x.go
================================================
// 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.
// Hand edited based on zerrors_zos_s390x.go
// TODO(Bill O'Farrell): auto-generate.
package ipv6
const (
sizeofSockaddrStorage = 128
sizeofICMPv6Filter = 32
sizeofInet6Pktinfo = 20
sizeofIPv6Mtuinfo = 32
sizeofSockaddrInet6 = 28
sizeofGroupReq = 136
sizeofGroupSourceReq = 264
)
type sockaddrStorage struct {
Len uint8
Family byte
ss_pad1 [6]byte
ss_align int64
ss_pad2 [112]byte
}
type sockaddrInet6 struct {
Len uint8
Family uint8
Port uint16
Flowinfo uint32
Addr [16]byte
Scope_id uint32
}
type inet6Pktinfo struct {
Addr [16]byte
Ifindex uint32
}
type ipv6Mtuinfo struct {
Addr sockaddrInet6
Mtu uint32
}
type groupReq struct {
Interface uint32
reserved uint32
Group sockaddrStorage
}
type groupSourceReq struct {
Interface uint32
reserved uint32
Group sockaddrStorage
Source sockaddrStorage
}
type icmpv6Filter struct {
Filt [8]uint32
}
================================================
FILE: vendor/golang.org/x/sys/LICENSE
================================================
Copyright 2009 The Go Authors.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
================================================
FILE: vendor/golang.org/x/sys/PATENTS
================================================
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.
================================================
FILE: vendor/golang.org/x/sys/unix/.gitignore
================================================
_obj/
unix.test
================================================
FILE: vendor/golang.org/x/sys/unix/README.md
================================================
# Building `sys/unix`
The sys/unix package provides access to the raw system call interface of the
underlying operating system. See: https://godoc.org/golang.org/x/sys/unix
Porting Go to a new architecture/OS combination or adding syscalls, types, or
constants to an existing architecture/OS pair requires some manual effort;
however, there are tools that automate much of the process.
## Build Systems
There are currently two ways we generate the necessary files. We are currently
migrating the build system to use containers so the builds are reproducible.
This is being done on an OS-by-OS basis. Please update this documentation as
components of the build system change.
### Old Build System (currently for `GOOS != "linux"`)
The old build system generates the Go files based on the C header files
present on your system. This means that files
for a given GOOS/GOARCH pair must be generated on a system with that OS and
architecture. This also means that the generated code can differ from system
to system, based on differences in the header files.
To avoid this, if you are using the old build system, only generate the Go
files on an installation with unmodified header files. It is also important to
keep track of which version of the OS the files were generated from (ex.
Darwin 14 vs Darwin 15). This makes it easier to track the progress of changes
and have each OS upgrade correspond to a single change.
To build the files for your current OS and architecture, make sure GOOS and
GOARCH are set correctly and run `mkall.sh`. This will generate the files for
your specific system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go
### New Build System (currently for `GOOS == "linux"`)
The new build system uses a Docker container to generate the go files directly
from source checkouts of the kernel and various system libraries. This means
that on any platform that supports Docker, all the files using the new build
system can be generated at once, and generated files will not change based on
what the person running the scripts has installed on their computer.
The OS specific files for the new build system are located in the `${GOOS}`
directory, and the build is coordinated by the `${GOOS}/mkall.go` program. When
the kernel or system library updates, modify the Dockerfile at
`${GOOS}/Dockerfile` to checkout the new release of the source.
To build all the files under the new build system, you must be on an amd64/Linux
system and have your GOOS and GOARCH set accordingly. Running `mkall.sh` will
then generate all of the files for all of the GOOS/GOARCH pairs in the new build
system. Running `mkall.sh -n` shows the commands that will be run.
Requirements: bash, go, docker
## Component files
This section describes the various files used in the code generation process.
It also contains instructions on how to modify these files to add a new
architecture/OS or to add additional syscalls, types, or constants. Note that
if you are using the new build system, the scripts/programs cannot be called normally.
They must be called from within the docker container.
### asm files
The hand-written assembly file at `asm_${GOOS}_${GOARCH}.s` implements system
call dispatch. There are three entry points:
```
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
```
The first and second are the standard ones; they differ only in how many
arguments can be passed to the kernel. The third is for low-level use by the
ForkExec wrapper. Unlike the first two, it does not call into the scheduler to
let it know that a system call is running.
When porting Go to a new architecture/OS, this file must be implemented for
each GOOS/GOARCH pair.
### mksysnum
Mksysnum is a Go program located at `${GOOS}/mksysnum.go` (or `mksysnum_${GOOS}.go`
for the old system). This program takes in a list of header files containing the
syscall number declarations and parses them to produce the corresponding list of
Go numeric constants. See `zsysnum_${GOOS}_${GOARCH}.go` for the generated
constants.
Adding new syscall numbers is mostly done by running the build on a sufficiently
new installation of the target OS (or updating the source checkouts for the
new build system). However, depending on the OS, you may need to update the
parsing in mksysnum.
### mksyscall.go
The `syscall.go`, `syscall_${GOOS}.go`, `syscall_${GOOS}_${GOARCH}.go` are
hand-written Go files which implement system calls (for unix, the specific OS,
or the specific OS/Architecture pair respectively) that need special handling
and list `//sys` comments giving prototypes for ones that can be generated.
The mksyscall.go program takes the `//sys` and `//sysnb` comments and converts
them into syscalls. This requires the name of the prototype in the comment to
match a syscall number in the `zsysnum_${GOOS}_${GOARCH}.go` file. The function
prototype can be exported (capitalized) or not.
Adding a new syscall often just requires adding a new `//sys` function prototype
with the desired arguments and a capitalized name so it is exported. However, if
you want the interface to the syscall to be different, often one will make an
unexported `//sys` prototype, and then write a custom wrapper in
`syscall_${GOOS}.go`.
### types files
For each OS, there is a hand-written Go file at `${GOOS}/types.go` (or
`types_${GOOS}.go` on the old system). This file includes standard C headers and
creates Go type aliases to the corresponding C types. The file is then fed
through godef to get the Go compatible definitions. Finally, the generated code
is fed though mkpost.go to format the code correctly and remove any hidden or
private identifiers. This cleaned-up code is written to
`ztypes_${GOOS}_${GOARCH}.go`.
The hardest part about preparing this file is figuring out which headers to
include and which symbols need to be `#define`d to get the actual data
structures that pass through to the kernel system calls. Some C libraries
preset alternate versions for binary compatibility and translate them on the
way in and out of system calls, but there is almost always a `#define` that can
get the real ones.
See `types_darwin.go` and `linux/types.go` for examples.
To add a new type, add in the necessary include statement at the top of the
file (if it is not already there) and add in a type alias line. Note that if
your type is significantly different on different architectures, you may need
some `#if/#elif` macros in your include statements.
### mkerrors.sh
This script is used to generate the system's various constants. This doesn't
just include the error numbers and error strings, but also the signal numbers
and a wide variety of miscellaneous constants. The constants come from the list
of include files in the `includes_${uname}` variable. A regex then picks out
the desired `#define` statements, and generates the corresponding Go constants.
The error numbers and strings are generated from `#include `, and the
signal numbers and strings are generated from `#include `. All of
these constants are written to `zerrors_${GOOS}_${GOARCH}.go` via a C program,
`_errors.c`, which prints out all the constants.
To add a constant, add the header that includes it to the appropriate variable.
Then, edit the regex (if necessary) to match the desired constant. Avoid making
the regex too broad to avoid matching unintended constants.
### internal/mkmerge
This program is used to extract duplicate const, func, and type declarations
from the generated architecture-specific files listed below, and merge these
into a common file for each OS.
The merge is performed in the following steps:
1. Construct the set of common code that is identical in all architecture-specific files.
2. Write this common code to the merged file.
3. Remove the common code from all architecture-specific files.
## Generated files
### `zerrors_${GOOS}_${GOARCH}.go`
A file containing all of the system's generated error numbers, error strings,
signal numbers, and constants. Generated by `mkerrors.sh` (see above).
### `zsyscall_${GOOS}_${GOARCH}.go`
A file containing all the generated syscalls for a specific GOOS and GOARCH.
Generated by `mksyscall.go` (see above).
### `zsysnum_${GOOS}_${GOARCH}.go`
A list of numeric constants for all the syscall number of the specific GOOS
and GOARCH. Generated by mksysnum (see above).
### `ztypes_${GOOS}_${GOARCH}.go`
A file containing Go types for passing into (or returning from) syscalls.
Generated by godefs and the types file (see above).
================================================
FILE: vendor/golang.org/x/sys/unix/affinity_linux.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// CPU affinity functions
package unix
import (
"math/bits"
"unsafe"
)
const cpuSetSize = _CPU_SETSIZE / _NCPUBITS
// CPUSet represents a bit mask of CPUs, to be used with [SchedGetaffinity], [SchedSetaffinity],
// and [SetMemPolicy].
//
// Note this type can only represent CPU IDs 0 through 1023.
// Use [CPUSetDynamic]/[NewCPUSet] instead to avoid this limit.
type CPUSet [cpuSetSize]cpuMask
// CPUSetDynamic represents a bit mask of CPUs, to be used with [SchedGetaffinityDynamic],
// [SchedSetaffinityDynamic], and [SetMemPolicyDynamic]. Use [NewCPUSet] to allocate.
type CPUSetDynamic []cpuMask
func schedAffinity(trap uintptr, pid int, size uintptr, ptr unsafe.Pointer) error {
_, _, e := RawSyscall(trap, uintptr(pid), uintptr(size), uintptr(ptr))
if e != 0 {
return errnoErr(e)
}
return nil
}
// SchedGetaffinity gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedGetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
}
// SchedSetaffinity sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinity(pid int, set *CPUSet) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, unsafe.Sizeof(*set), unsafe.Pointer(set))
}
// Zero clears the set s, so that it contains no CPUs.
func (s *CPUSet) Zero() {
clear(s[:])
}
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinity]
// will silently ignore any invalid CPU bits in [CPUSet] so this is an
// efficient way of resetting the CPU affinity of a process.
func (s *CPUSet) Fill() {
cpuMaskFill(s[:])
}
func cpuBitsIndex(cpu int) int {
return cpu / _NCPUBITS
}
func cpuBitsMask(cpu int) cpuMask {
return cpuMask(1 << (uint(cpu) % _NCPUBITS))
}
func cpuMaskFill(s []cpuMask) {
for i := range s {
s[i] = ^cpuMask(0)
}
}
func cpuMaskSet(s []cpuMask, cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] |= cpuBitsMask(cpu)
}
}
func cpuMaskClear(s []cpuMask, cpu int) {
i := cpuBitsIndex(cpu)
if i < len(s) {
s[i] &^= cpuBitsMask(cpu)
}
}
func cpuMaskIsSet(s []cpuMask, cpu int) bool {
i := cpuBitsIndex(cpu)
if i < len(s) {
return s[i]&cpuBitsMask(cpu) != 0
}
return false
}
func cpuMaskCount(s []cpuMask) int {
c := 0
for _, b := range s {
c += bits.OnesCount64(uint64(b))
}
return c
}
// Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
func (s *CPUSet) Set(cpu int) {
cpuMaskSet(s[:], cpu)
}
// Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
func (s *CPUSet) Clear(cpu int) {
cpuMaskClear(s[:], cpu)
}
// IsSet reports whether cpu is in the set s.
func (s *CPUSet) IsSet(cpu int) bool {
return cpuMaskIsSet(s[:], cpu)
}
// Count returns the number of CPUs in the set s.
func (s *CPUSet) Count() int {
return cpuMaskCount(s[:])
}
// NewCPUSet creates a CPU affinity mask capable of representing CPU IDs
// up to maxCPU (exclusive).
func NewCPUSet(maxCPU int) CPUSetDynamic {
numMasks := (maxCPU + _NCPUBITS - 1) / _NCPUBITS
if numMasks == 0 {
numMasks = 1
}
return make(CPUSetDynamic, numMasks)
}
// Zero clears the set s, so that it contains no CPUs.
func (s CPUSetDynamic) Zero() {
clear(s)
}
// Fill adds all possible CPU bits to the set s. On Linux, [SchedSetaffinityDynamic]
// will silently ignore any invalid CPU bits in [CPUSetDynamic] so this is an
// efficient way of resetting the CPU affinity of a process.
func (s CPUSetDynamic) Fill() {
cpuMaskFill(s)
}
// Set adds cpu to the set s. If cpu is out of bounds for s, no action is taken.
func (s CPUSetDynamic) Set(cpu int) {
cpuMaskSet(s, cpu)
}
// Clear removes cpu from the set s. If cpu is out of bounds for s, no action is taken.
func (s CPUSetDynamic) Clear(cpu int) {
cpuMaskClear(s, cpu)
}
// IsSet reports whether cpu is in the set s.
func (s CPUSetDynamic) IsSet(cpu int) bool {
return cpuMaskIsSet(s, cpu)
}
// Count returns the number of CPUs in the set s.
func (s CPUSetDynamic) Count() int {
return cpuMaskCount(s)
}
func (s CPUSetDynamic) size() uintptr {
return uintptr(len(s)) * unsafe.Sizeof(cpuMask(0))
}
func (s CPUSetDynamic) pointer() unsafe.Pointer {
if len(s) == 0 {
return nil
}
return unsafe.Pointer(&s[0])
}
// SchedGetaffinityDynamic gets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
//
// If the set is smaller than the size of the affinity mask used by the kernel,
// [EINVAL] is returned.
func SchedGetaffinityDynamic(pid int, set CPUSetDynamic) error {
return schedAffinity(SYS_SCHED_GETAFFINITY, pid, set.size(), set.pointer())
}
// SchedSetaffinityDynamic sets the CPU affinity mask of the thread specified by pid.
// If pid is 0 the calling thread is used.
func SchedSetaffinityDynamic(pid int, set CPUSetDynamic) error {
return schedAffinity(SYS_SCHED_SETAFFINITY, pid, set.size(), set.pointer())
}
================================================
FILE: vendor/golang.org/x/sys/unix/aliases.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
import "syscall"
type Signal = syscall.Signal
type Errno = syscall.Errno
type SysProcAttr = syscall.SysProcAttr
================================================
FILE: vendor/golang.org/x/sys/unix/asm_aix_ppc64.s
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
//
TEXT ·syscall6(SB),NOSPLIT,$0-88
JMP syscall·syscall6(SB)
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
JMP syscall·rawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_386.s
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for 386 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_amd64.s
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for AMD64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_arm.s
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
B syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_arm64.s
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for ARM64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_ppc64.s
================================================
// Copyright 2022 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 (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
//
// System call support for ppc64, BSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_bsd_riscv64.s
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build (darwin || freebsd || netbsd || openbsd) && gc
#include "textflag.h"
// System call support for RISCV64 BSD
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_386.s
================================================
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for 386, Linux
//
// See ../runtime/sys_linux_386.s for the reason why we always use int 0x80
// instead of the glibc-specific "CALL 0x10(GS)".
#define INVOKE_SYSCALL INT $0x80
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
CALL runtime·entersyscall(SB)
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVL trap+0(FP), AX // syscall entry
MOVL a1+4(FP), BX
MOVL a2+8(FP), CX
MOVL a3+12(FP), DX
MOVL $0, SI
MOVL $0, DI
INVOKE_SYSCALL
MOVL AX, r1+16(FP)
MOVL DX, r2+20(FP)
RET
TEXT ·socketcall(SB),NOSPLIT,$0-36
JMP syscall·socketcall(SB)
TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
JMP syscall·rawsocketcall(SB)
TEXT ·seek(SB),NOSPLIT,$0-28
JMP syscall·seek(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_amd64.s
================================================
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for AMD64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
MOVQ a3+24(FP), DX
MOVQ $0, R10
MOVQ $0, R8
MOVQ $0, R9
MOVQ trap+0(FP), AX // syscall entry
SYSCALL
MOVQ AX, r1+32(FP)
MOVQ DX, r2+40(FP)
RET
TEXT ·gettimeofday(SB),NOSPLIT,$0-16
JMP syscall·gettimeofday(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_arm.s
================================================
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System calls for arm, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R7
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
MOVW $0, R3
MOVW $0, R4
MOVW $0, R5
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW trap+0(FP), R7 // syscall entry
MOVW a1+4(FP), R0
MOVW a2+8(FP), R1
MOVW a3+12(FP), R2
SWI $0
MOVW R0, r1+16(FP)
MOVW $0, R0
MOVW R0, r2+20(FP)
RET
TEXT ·seek(SB),NOSPLIT,$0-28
B syscall·seek(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_arm64.s
================================================
// 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 linux && arm64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
B syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
B syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP) // r1
MOVD R1, r2+40(FP) // r2
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
B syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
B syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R0
MOVD a2+16(FP), R1
MOVD a3+24(FP), R2
MOVD $0, R3
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall entry
SVC
MOVD R0, r1+32(FP)
MOVD R1, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_loong64.s
================================================
// Copyright 2022 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 linux && loong64 && gc
#include "textflag.h"
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R11 // syscall entry
SYSCALL
MOVV R4, r1+32(FP)
MOVV R0, r2+40(FP) // r2 is not used. Always set to 0
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_mips64x.s
================================================
// 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 linux && (mips64 || mips64le) && gc
#include "textflag.h"
//
// System calls for mips64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
JAL runtime·entersyscall(SB)
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV R0, R7
MOVV R0, R8
MOVV R0, R9
MOVV trap+0(FP), R2 // syscall entry
SYSCALL
MOVV R2, r1+32(FP)
MOVV R3, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_mipsx.s
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (mips || mipsle) && gc
#include "textflag.h"
//
// System calls for mips, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-28
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-40
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-52
JMP syscall·Syscall9(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-24
JAL runtime·entersyscall(SB)
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW R0, R7
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP) // r1
MOVW R3, r2+20(FP) // r2
JAL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-28
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-24
MOVW a1+4(FP), R4
MOVW a2+8(FP), R5
MOVW a3+12(FP), R6
MOVW trap+0(FP), R2 // syscall entry
SYSCALL
MOVW R2, r1+16(FP)
MOVW R3, r2+20(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_ppc64x.s
================================================
// 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 linux && (ppc64 || ppc64le) && gc
#include "textflag.h"
//
// System calls for ppc64, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R3
MOVD a2+16(FP), R4
MOVD a3+24(FP), R5
MOVD R0, R6
MOVD R0, R7
MOVD R0, R8
MOVD trap+0(FP), R9 // syscall entry
SYSCALL R9
MOVD R3, r1+32(FP)
MOVD R4, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_riscv64.s
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build riscv64 && gc
#include "textflag.h"
//
// System calls for linux/riscv64.
//
// Where available, just jump to package syscall's implementation of
// these functions.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
CALL runtime·entersyscall(SB)
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP) // r1
MOV A1, r2+40(FP) // r2
CALL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOV a1+8(FP), A0
MOV a2+16(FP), A1
MOV a3+24(FP), A2
MOV trap+0(FP), A7 // syscall entry
ECALL
MOV A0, r1+32(FP)
MOV A1, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_linux_s390x.s
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && s390x && gc
#include "textflag.h"
//
// System calls for s390x, Linux
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
BR syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
BR syscall·Syscall6(SB)
TEXT ·SyscallNoError(SB),NOSPLIT,$0-48
BL runtime·entersyscall(SB)
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
BL runtime·exitsyscall(SB)
RET
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
BR syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
BR syscall·RawSyscall6(SB)
TEXT ·RawSyscallNoError(SB),NOSPLIT,$0-48
MOVD a1+8(FP), R2
MOVD a2+16(FP), R3
MOVD a3+24(FP), R4
MOVD $0, R5
MOVD $0, R6
MOVD $0, R7
MOVD trap+0(FP), R1 // syscall entry
SYSCALL
MOVD R2, r1+32(FP)
MOVD R3, r2+40(FP)
RET
================================================
FILE: vendor/golang.org/x/sys/unix/asm_openbsd_mips64.s
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build gc
#include "textflag.h"
//
// System call support for mips64, OpenBSD
//
// Just jump to package syscall's implementation for all these functions.
// The runtime may know about them.
TEXT ·Syscall(SB),NOSPLIT,$0-56
JMP syscall·Syscall(SB)
TEXT ·Syscall6(SB),NOSPLIT,$0-80
JMP syscall·Syscall6(SB)
TEXT ·Syscall9(SB),NOSPLIT,$0-104
JMP syscall·Syscall9(SB)
TEXT ·RawSyscall(SB),NOSPLIT,$0-56
JMP syscall·RawSyscall(SB)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
JMP syscall·RawSyscall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_solaris_amd64.s
================================================
// 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 gc
#include "textflag.h"
//
// System calls for amd64, Solaris are implemented in runtime/syscall_solaris.go
//
TEXT ·sysvicall6(SB),NOSPLIT,$0-88
JMP syscall·sysvicall6(SB)
TEXT ·rawSysvicall6(SB),NOSPLIT,$0-88
JMP syscall·rawSysvicall6(SB)
================================================
FILE: vendor/golang.org/x/sys/unix/asm_zos_s390x.s
================================================
// 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 && gc
#include "textflag.h"
#define PSALAA 1208(R0)
#define GTAB64(x) 80(x)
#define LCA64(x) 88(x)
#define SAVSTACK_ASYNC(x) 336(x) // in the LCA
#define CAA(x) 8(x)
#define CEECAATHDID(x) 976(x) // in the CAA
#define EDCHPXV(x) 1016(x) // in the CAA
#define GOCB(x) 1104(x) // in the CAA
// SS_*, where x=SAVSTACK_ASYNC
#define SS_LE(x) 0(x)
#define SS_GO(x) 8(x)
#define SS_ERRNO(x) 16(x)
#define SS_ERRNOJR(x) 20(x)
// Function Descriptor Offsets
#define __errno 0x156*16
#define __err2ad 0x16C*16
// Call Instructions
#define LE_CALL BYTE $0x0D; BYTE $0x76 // BL R7, R6
#define SVC_LOAD BYTE $0x0A; BYTE $0x08 // SVC 08 LOAD
#define SVC_DELETE BYTE $0x0A; BYTE $0x09 // SVC 09 DELETE
DATA zosLibVec<>(SB)/8, $0
GLOBL zosLibVec<>(SB), NOPTR, $8
TEXT ·initZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R8
MOVD EDCHPXV(R8), R8
MOVD R8, zosLibVec<>(SB)
RET
TEXT ·GetZosLibVec(SB), NOSPLIT|NOFRAME, $0-0
MOVD zosLibVec<>(SB), R8
MOVD R8, ret+0(FP)
RET
TEXT ·clearErrno(SB), NOSPLIT, $0-0
BL addrerrno<>(SB)
MOVD $0, 0(R3)
RET
// Returns the address of errno in R3.
TEXT addrerrno<>(SB), NOSPLIT|NOFRAME, $0-0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get __errno FuncDesc.
MOVD CAA(R8), R9
MOVD EDCHPXV(R9), R9
ADD $(__errno), R9
LMG 0(R9), R5, R6
// Switch to saved LE stack.
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R4
MOVD $0, 0(R9)
// Call __errno function.
LE_CALL
NOPH
// Switch back to Go stack.
XOR R0, R0 // Restore R0 to $0.
MOVD R4, 0(R9) // Save stack pointer.
RET
// func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
TEXT ·svcCall(SB), NOSPLIT, $0
BL runtime·save_g(SB) // Save g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD R15, 0(R9)
MOVD argv+8(FP), R1 // Move function arguments into registers
MOVD dsa+16(FP), g
MOVD fnptr+0(FP), R15
BYTE $0x0D // Branch to function
BYTE $0xEF
BL runtime·load_g(SB) // Restore g and stack pointer
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD SAVSTACK_ASYNC(R8), R9
MOVD 0(R9), R15
RET
// func svcLoad(name *byte) unsafe.Pointer
TEXT ·svcLoad(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD $0x80000000, R1
MOVD $0, R15
SVC_LOAD
MOVW R15, R3 // Save return code from SVC
MOVD R2, R15 // Restore go stack pointer
CMP R3, $0 // Check SVC return code
BNE error
MOVD $-2, R3 // Reset last bit of entry point to zero
AND R0, R3
MOVD R3, ret+8(FP) // Return entry point returned by SVC
CMP R0, R3 // Check if last bit of entry point was set
BNE done
MOVD R15, R2 // Save go stack pointer
MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08)
SVC_DELETE
MOVD R2, R15 // Restore go stack pointer
error:
MOVD $0, ret+8(FP) // Return 0 on failure
done:
XOR R0, R0 // Reset r0 to 0
RET
// func svcUnload(name *byte, fnptr unsafe.Pointer) int64
TEXT ·svcUnload(SB), NOSPLIT, $0
MOVD R15, R2 // Save go stack pointer
MOVD name+0(FP), R0 // Move SVC args into registers
MOVD fnptr+8(FP), R15
SVC_DELETE
XOR R0, R0 // Reset r0 to 0
MOVD R15, R1 // Save SVC return code
MOVD R2, R15 // Restore go stack pointer
MOVD R1, ret+16(FP) // Return SVC return code
RET
// func gettid() uint64
TEXT ·gettid(SB), NOSPLIT, $0
// Get library control area (LCA).
MOVW PSALAA, R8
MOVD LCA64(R8), R8
// Get CEECAATHDID
MOVD CAA(R8), R9
MOVD CEECAATHDID(R9), R9
MOVD R9, ret+0(FP)
RET
//
// Call LE function, if the return is -1
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithErr(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $-1 // compare result to -1
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// Call LE function, if the return is 0
// errno and errno2 is retrieved
//
TEXT ·CallLeFuncWithPtrReturn(SB), NOSPLIT, $0
MOVW PSALAA, R8
MOVD LCA64(R8), R8
MOVD CAA(R8), R9
MOVD g, GOCB(R9)
// Restore LE stack.
MOVD SAVSTACK_ASYNC(R8), R9 // R9-> LE stack frame saving address
MOVD 0(R9), R4 // R4-> restore previously saved stack frame pointer
MOVD parms_base+8(FP), R7 // R7 -> argument array
MOVD parms_len+16(FP), R8 // R8 number of arguments
// arg 1 ---> R1
CMP R8, $0
BEQ docall
SUB $1, R8
MOVD 0(R7), R1
// arg 2 ---> R2
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R2
// arg 3 --> R3
CMP R8, $0
BEQ docall
SUB $1, R8
ADD $8, R7
MOVD 0(R7), R3
CMP R8, $0
BEQ docall
MOVD $2176+16, R6 // starting LE stack address-8 to store 4th argument
repeat:
ADD $8, R7
MOVD 0(R7), R0 // advance arg pointer by 8 byte
ADD $8, R6 // advance LE argument address by 8 byte
MOVD R0, (R4)(R6*1) // copy argument from go-slice to le-frame
SUB $1, R8
CMP R8, $0
BNE repeat
docall:
MOVD funcdesc+0(FP), R8 // R8-> function descriptor
LMG 0(R8), R5, R6
MOVD $0, 0(R9) // R9 address of SAVSTACK_ASYNC
LE_CALL // balr R7, R6 (return #1)
NOPH
MOVD R3, ret+32(FP)
CMP R3, $0 // compare result to 0
BNE done
// retrieve errno and errno2
MOVD zosLibVec<>(SB), R8
ADD $(__errno), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __errno (return #3)
NOPH
MOVWZ 0(R3), R3
MOVD R3, err+48(FP)
MOVD zosLibVec<>(SB), R8
ADD $(__err2ad), R8
LMG 0(R8), R5, R6
LE_CALL // balr R7, R6 __err2ad (return #2)
NOPH
MOVW (R3), R2 // retrieve errno2
MOVD R2, errno2+40(FP) // store in return area
XOR R2, R2
MOVWZ R2, (R3) // clear errno2
done:
MOVD R4, 0(R9) // Save stack pointer.
RET
//
// function to test if a pointer can be safely dereferenced (content read)
// return 0 for succces
//
TEXT ·ptrtest(SB), NOSPLIT, $0-16
MOVD arg+0(FP), R10 // test pointer in R10
// set up R2 to point to CEECAADMC
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
// set up R5 to point to the "shunt" path which set 1 to R3 (failure)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
// if r3 is not zero (failed) then branch to finish
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
// stomic store shunt address in R5 into CEECAADMC
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
// now try reading from the test pointer in R10, if it fails it branches to the "lghi" instruction above
BYTE $0xE3; BYTE $0x9A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 9,0(10)
// finish here, restore 0 into CEECAADMC
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R3, ret+8(FP) // result in R3
RET
//
// function to test if a untptr can be loaded from a pointer
// return 1: the 8-byte content
// 2: 0 for success, 1 for failure
//
// func safeload(ptr uintptr) ( value uintptr, error uintptr)
TEXT ·safeload(SB), NOSPLIT, $0-24
MOVD ptr+0(FP), R10 // test pointer in R10
MOVD $0x0, R6
BYTE $0xE3; BYTE $0x20; BYTE $0x04; BYTE $0xB8; BYTE $0x00; BYTE $0x17 // llgt 2,1208
BYTE $0xB9; BYTE $0x17; BYTE $0x00; BYTE $0x22 // llgtr 2,2
BYTE $0xA5; BYTE $0x26; BYTE $0x7F; BYTE $0xFF // nilh 2,32767
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x58; BYTE $0x00; BYTE $0x04 // lg 2,88(2)
BYTE $0xE3; BYTE $0x22; BYTE $0x00; BYTE $0x08; BYTE $0x00; BYTE $0x04 // lg 2,8(2)
BYTE $0x41; BYTE $0x22; BYTE $0x03; BYTE $0x68 // la 2,872(2)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x33 // xgr 3,3
BYTE $0xA7; BYTE $0x55; BYTE $0x00; BYTE $0x04 // bras 5,lbl1
BYTE $0xA7; BYTE $0x39; BYTE $0x00; BYTE $0x01 // lghi 3,1
BYTE $0xB9; BYTE $0x02; BYTE $0x00; BYTE $0x33 // lbl1 ltgr 3,3
BYTE $0xA7; BYTE $0x74; BYTE $0x00; BYTE $0x08 // brc b'0111',lbl2
BYTE $0xE3; BYTE $0x52; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 5,0(2)
BYTE $0xE3; BYTE $0x6A; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x04 // lg 6,0(10)
BYTE $0xB9; BYTE $0x82; BYTE $0x00; BYTE $0x99 // lbl2 xgr 9,9
BYTE $0xE3; BYTE $0x92; BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x24 // stg 9,0(2)
MOVD R6, value+8(FP) // result in R6
MOVD R3, error+16(FP) // error in R3
RET
================================================
FILE: vendor/golang.org/x/sys/unix/auxv.go
================================================
// Copyright 2025 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.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
package unix
import (
"syscall"
"unsafe"
)
//go:linkname runtime_getAuxv runtime.getAuxv
func runtime_getAuxv() []uintptr
// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs.
// The returned slice is always a fresh copy, owned by the caller.
// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed,
// which happens in some locked-down environments and build modes.
func Auxv() ([][2]uintptr, error) {
vec := runtime_getAuxv()
vecLen := len(vec)
if vecLen == 0 {
return nil, syscall.ENOENT
}
if vecLen%2 != 0 {
return nil, syscall.EINVAL
}
result := make([]uintptr, vecLen)
copy(result, vec)
return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil
}
================================================
FILE: vendor/golang.org/x/sys/unix/auxv_unsupported.go
================================================
// Copyright 2025 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.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
package unix
import "syscall"
func Auxv() ([][2]uintptr, error) {
return nil, syscall.ENOTSUP
}
================================================
FILE: vendor/golang.org/x/sys/unix/bluetooth_linux.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Bluetooth sockets and messages
package unix
// Bluetooth Protocols
const (
BTPROTO_L2CAP = 0
BTPROTO_HCI = 1
BTPROTO_SCO = 2
BTPROTO_RFCOMM = 3
BTPROTO_BNEP = 4
BTPROTO_CMTP = 5
BTPROTO_HIDP = 6
BTPROTO_AVDTP = 7
)
const (
HCI_CHANNEL_RAW = 0
HCI_CHANNEL_USER = 1
HCI_CHANNEL_MONITOR = 2
HCI_CHANNEL_CONTROL = 3
HCI_CHANNEL_LOGGING = 4
)
// Socketoption Level
const (
SOL_BLUETOOTH = 0x112
SOL_HCI = 0x0
SOL_L2CAP = 0x6
SOL_RFCOMM = 0x12
SOL_SCO = 0x11
)
================================================
FILE: vendor/golang.org/x/sys/unix/bpxsvc_zos.go
================================================
// 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
}
================================================
FILE: vendor/golang.org/x/sys/unix/bpxsvc_zos.s
================================================
// 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
================================================
FILE: vendor/golang.org/x/sys/unix/cap_freebsd.go
================================================
// 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 freebsd
package unix
import (
"errors"
"fmt"
)
// Go implementation of C mostly found in /usr/src/sys/kern/subr_capability.c
const (
// This is the version of CapRights this package understands. See C implementation for parallels.
capRightsGoVersion = CAP_RIGHTS_VERSION_00
capArSizeMin = CAP_RIGHTS_VERSION_00 + 2
capArSizeMax = capRightsGoVersion + 2
)
var (
bit2idx = []int{
-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1,
4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
}
)
func capidxbit(right uint64) int {
return int((right >> 57) & 0x1f)
}
func rightToIndex(right uint64) (int, error) {
idx := capidxbit(right)
if idx < 0 || idx >= len(bit2idx) {
return -2, fmt.Errorf("index for right 0x%x out of range", right)
}
return bit2idx[idx], nil
}
func caprver(right uint64) int {
return int(right >> 62)
}
func capver(rights *CapRights) int {
return caprver(rights.Rights[0])
}
func caparsize(rights *CapRights) int {
return capver(rights) + 2
}
// CapRightsSet sets the permissions in setrights in rights.
func CapRightsSet(rights *CapRights, setrights []uint64) error {
// This is essentially a copy of cap_rights_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch")
}
rights.Rights[i] |= right
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsClear clears the permissions in clearrights from rights.
func CapRightsClear(rights *CapRights, clearrights []uint64) error {
// This is essentially a copy of cap_rights_vclear()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return errors.New("bad rights size")
}
for _, right := range clearrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return err
}
if i >= n {
return errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch")
}
rights.Rights[i] &= ^(right & 0x01FFFFFFFFFFFFFF)
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return errors.New("index mismatch (after assign)")
}
}
return nil
}
// CapRightsIsSet checks whether all the permissions in setrights are present in rights.
func CapRightsIsSet(rights *CapRights, setrights []uint64) (bool, error) {
// This is essentially a copy of cap_rights_is_vset()
if capver(rights) != CAP_RIGHTS_VERSION_00 {
return false, fmt.Errorf("bad rights version %d", capver(rights))
}
n := caparsize(rights)
if n < capArSizeMin || n > capArSizeMax {
return false, errors.New("bad rights size")
}
for _, right := range setrights {
if caprver(right) != CAP_RIGHTS_VERSION_00 {
return false, errors.New("bad right version")
}
i, err := rightToIndex(right)
if err != nil {
return false, err
}
if i >= n {
return false, errors.New("index overflow")
}
if capidxbit(rights.Rights[i]) != capidxbit(right) {
return false, errors.New("index mismatch")
}
if (rights.Rights[i] & right) != right {
return false, nil
}
}
return true, nil
}
func capright(idx uint64, bit uint64) uint64 {
return ((1 << (57 + idx)) | bit)
}
// CapRightsInit returns a pointer to an initialised CapRights structure filled with rights.
// See man cap_rights_init(3) and rights(4).
func CapRightsInit(rights []uint64) (*CapRights, error) {
var r CapRights
r.Rights[0] = (capRightsGoVersion << 62) | capright(0, 0)
r.Rights[1] = capright(1, 0)
err := CapRightsSet(&r, rights)
if err != nil {
return nil, err
}
return &r, nil
}
// CapRightsLimit reduces the operations permitted on fd to at most those contained in rights.
// The capability rights on fd can never be increased by CapRightsLimit.
// See man cap_rights_limit(2) and rights(4).
func CapRightsLimit(fd uintptr, rights *CapRights) error {
return capRightsLimit(int(fd), rights)
}
// CapRightsGet returns a CapRights structure containing the operations permitted on fd.
// See man cap_rights_get(3) and rights(4).
func CapRightsGet(fd uintptr) (*CapRights, error) {
r, err := CapRightsInit(nil)
if err != nil {
return nil, err
}
err = capRightsGet(capRightsGoVersion, int(fd), r)
if err != nil {
return nil, err
}
return r, nil
}
================================================
FILE: vendor/golang.org/x/sys/unix/constants.go
================================================
// 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
const (
R_OK = 0x4
W_OK = 0x2
X_OK = 0x1
)
================================================
FILE: vendor/golang.org/x/sys/unix/dev_aix_ppc.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix && ppc
// Functions to access/create device major and minor numbers matching the
// encoding used by AIX.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 16) & 0xffff)
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff)
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return uint64(((major) << 16) | (minor))
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_aix_ppc64.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix && ppc64
// Functions to access/create device major and minor numbers matching the
// encoding used AIX.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x3fffffff00000000) >> 32)
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
return uint32((dev & 0x00000000ffffffff) >> 0)
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
var DEVNO64 uint64
DEVNO64 = 0x8000000000000000
return ((uint64(major) << 32) | (uint64(minor) & 0x00000000FFFFFFFF) | DEVNO64)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_darwin.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in Darwin's sys/types.h header.
package unix
// Major returns the major component of a Darwin device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 24) & 0xff)
}
// Minor returns the minor component of a Darwin device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffffff)
}
// Mkdev returns a Darwin device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 24) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_dragonfly.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in Dragonfly's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a DragonFlyBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a DragonFlyBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a DragonFlyBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_freebsd.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in FreeBSD's sys/types.h header.
//
// The information below is extracted and adapted from sys/types.h:
//
// Minor gives a cookie instead of an index since in order to avoid changing the
// meanings of bits 0-15 or wasting time and space shifting bits 16-31 for
// devices that don't use them.
package unix
// Major returns the major component of a FreeBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 8) & 0xff)
}
// Minor returns the minor component of a FreeBSD device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0xffff00ff)
}
// Mkdev returns a FreeBSD device number generated from the given major and
// minor components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 8) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_linux.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used by the Linux kernel and glibc.
//
// The information below is extracted and adapted from bits/sysmacros.h in the
// glibc sources:
//
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
// number and m is a hex digit of the minor number. This is backward compatible
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
// backward compatible with the Linux kernel, which for some architectures uses
// 32-bit dev_t, encoded as mmmM MMmm.
package unix
// Major returns the major component of a Linux device number.
func Major(dev uint64) uint32 {
major := uint32((dev & 0x00000000000fff00) >> 8)
major |= uint32((dev & 0xfffff00000000000) >> 32)
return major
}
// Minor returns the minor component of a Linux device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x00000000000000ff) >> 0)
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
return minor
}
// Mkdev returns a Linux device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) & 0x00000fff) << 8
dev |= (uint64(major) & 0xfffff000) << 32
dev |= (uint64(minor) & 0x000000ff) << 0
dev |= (uint64(minor) & 0xffffff00) << 12
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_netbsd.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in NetBSD's sys/types.h header.
package unix
// Major returns the major component of a NetBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x000fff00) >> 8)
}
// Minor returns the minor component of a NetBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xfff00000) >> 12)
return minor
}
// Mkdev returns a NetBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x000fff00
dev |= (uint64(minor) << 12) & 0xfff00000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_openbsd.go
================================================
// 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.
// Functions to access/create device major and minor numbers matching the
// encoding used in OpenBSD's sys/types.h header.
package unix
// Major returns the major component of an OpenBSD device number.
func Major(dev uint64) uint32 {
return uint32((dev & 0x0000ff00) >> 8)
}
// Minor returns the minor component of an OpenBSD device number.
func Minor(dev uint64) uint32 {
minor := uint32((dev & 0x000000ff) >> 0)
minor |= uint32((dev & 0xffff0000) >> 8)
return minor
}
// Mkdev returns an OpenBSD device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
dev := (uint64(major) << 8) & 0x0000ff00
dev |= (uint64(minor) << 8) & 0xffff0000
dev |= (uint64(minor) << 0) & 0x000000ff
return dev
}
================================================
FILE: vendor/golang.org/x/sys/unix/dev_zos.go
================================================
// 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
// Functions to access/create device major and minor numbers matching the
// encoding used by z/OS.
//
// The information below is extracted and adapted from macros.
package unix
// Major returns the major component of a z/OS device number.
func Major(dev uint64) uint32 {
return uint32((dev >> 16) & 0x0000FFFF)
}
// Minor returns the minor component of a z/OS device number.
func Minor(dev uint64) uint32 {
return uint32(dev & 0x0000FFFF)
}
// Mkdev returns a z/OS device number generated from the given major and minor
// components.
func Mkdev(major, minor uint32) uint64 {
return (uint64(major) << 16) | uint64(minor)
}
================================================
FILE: vendor/golang.org/x/sys/unix/dirent.go
================================================
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
import "unsafe"
// readInt returns the size-bytes unsigned integer in native byte order at offset off.
func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
if len(b) < int(off+size) {
return 0, false
}
if isBigEndian {
return readIntBE(b[off:], size), true
}
return readIntLE(b[off:], size), true
}
func readIntBE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[1]) | uint64(b[0])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[3]) | uint64(b[2])<<8 | uint64(b[1])<<16 | uint64(b[0])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
func readIntLE(b []byte, size uintptr) uint64 {
switch size {
case 1:
return uint64(b[0])
case 2:
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8
case 4:
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
case 8:
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
default:
panic("syscall: readInt with unsupported size")
}
}
// ParseDirent parses up to max directory entries in buf,
// appending the names to names. It returns the number of
// bytes consumed from buf, the number of entries added
// to names, and the new names slice.
func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
origlen := len(buf)
count = 0
for max != 0 && len(buf) > 0 {
reclen, ok := direntReclen(buf)
if !ok || reclen > uint64(len(buf)) {
return origlen, count, names
}
rec := buf[:reclen]
buf = buf[reclen:]
ino, ok := direntIno(rec)
if !ok {
break
}
if ino == 0 { // File absent in directory.
continue
}
const namoff = uint64(unsafe.Offsetof(Dirent{}.Name))
namlen, ok := direntNamlen(rec)
if !ok || namoff+namlen > uint64(len(rec)) {
break
}
name := rec[namoff : namoff+namlen]
for i, c := range name {
if c == 0 {
name = name[:i]
break
}
}
// Check for useless names before allocating a string.
if string(name) == "." || string(name) == ".." {
continue
}
max--
count++
names = append(names, string(name))
}
return origlen - len(buf), count, names
}
================================================
FILE: vendor/golang.org/x/sys/unix/endian_big.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64
package unix
const isBigEndian = true
================================================
FILE: vendor/golang.org/x/sys/unix/endian_little.go
================================================
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || loong64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh
package unix
const isBigEndian = false
================================================
FILE: vendor/golang.org/x/sys/unix/env_unix.go
================================================
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
// Unix environment variables.
package unix
import "syscall"
func Getenv(key string) (value string, found bool) {
return syscall.Getenv(key)
}
func Setenv(key, value string) error {
return syscall.Setenv(key, value)
}
func Clearenv() {
syscall.Clearenv()
}
func Environ() []string {
return syscall.Environ()
}
func Unsetenv(key string) error {
return syscall.Unsetenv(key)
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl.go
================================================
// 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 dragonfly || freebsd || linux || netbsd
package unix
import "unsafe"
// fcntl64Syscall is usually SYS_FCNTL, but is overridden on 32-bit Linux
// systems by fcntl_linux_32bit.go to be SYS_FCNTL64.
var fcntl64Syscall uintptr = SYS_FCNTL
func fcntl(fd int, cmd, arg int) (int, error) {
valptr, _, errno := Syscall(fcntl64Syscall, uintptr(fd), uintptr(cmd), uintptr(arg))
var err error
if errno != 0 {
err = errno
}
return int(valptr), err
}
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return fcntl(int(fd), cmd, arg)
}
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(unsafe.Pointer(lk)))
if errno == 0 {
return nil
}
return errno
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl_darwin.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
import "unsafe"
// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
return fcntl(int(fd), cmd, arg)
}
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(lk))))
return err
}
// FcntlFstore performs a fcntl syscall for the F_PREALLOCATE command.
func FcntlFstore(fd uintptr, cmd int, fstore *Fstore_t) error {
_, err := fcntl(int(fd), cmd, int(uintptr(unsafe.Pointer(fstore))))
return err
}
================================================
FILE: vendor/golang.org/x/sys/unix/fcntl_linux_32bit.go
================================================
// 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 (linux && 386) || (linux && arm) || (linux && mips) || (linux && mipsle) || (linux && ppc)
package unix
func init() {
// On 32-bit Linux systems, the fcntl syscall that matches Go's
// Flock_t type is SYS_FCNTL64, not SYS_FCNTL.
fcntl64Syscall = SYS_FCNTL64
}
================================================
FILE: vendor/golang.org/x/sys/unix/fdset.go
================================================
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
package unix
// Set adds fd to the set fds.
func (fds *FdSet) Set(fd int) {
fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS))
}
// Clear removes fd from the set fds.
func (fds *FdSet) Clear(fd int) {
fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS))
}
// IsSet returns whether fd is in the set fds.
func (fds *FdSet) IsSet(fd int) bool {
return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0
}
// Zero clears the set fds.
func (fds *FdSet) Zero() {
clear(fds.Bits[:])
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo.go
================================================
// 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 gccgo && !aix && !hurd
package unix
import "syscall"
// We can't use the gc-syntax .s files for gccgo. On the plus side
// much of the functionality can be written directly in Go.
func realSyscallNoError(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r uintptr)
func realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r, errno uintptr)
func SyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
syscall.Entersyscall()
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
syscall.Exitsyscall()
return r, 0
}
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) {
syscall.Entersyscall()
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9)
syscall.Exitsyscall()
return r, 0, syscall.Errno(errno)
}
func RawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr) {
r := realSyscallNoError(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
return r, 0
}
func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
r, errno := realSyscall(trap, a1, a2, a3, 0, 0, 0, 0, 0, 0)
return r, 0, syscall.Errno(errno)
}
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) {
r, errno := realSyscall(trap, a1, a2, a3, a4, a5, a6, 0, 0, 0)
return r, 0, syscall.Errno(errno)
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo_c.c
================================================
// 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 gccgo && !aix && !hurd
#include
#include
#include
#define _STRINGIFY2_(x) #x
#define _STRINGIFY_(x) _STRINGIFY2_(x)
#define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
// Call syscall from C code because the gccgo support for calling from
// Go to C does not support varargs functions.
struct ret {
uintptr_t r;
uintptr_t err;
};
struct ret gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscall");
struct ret
gccgoRealSyscall(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
struct ret r;
errno = 0;
r.r = syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
r.err = errno;
return r;
}
uintptr_t gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
__asm__(GOSYM_PREFIX GOPKGPATH ".realSyscallNoError");
uintptr_t
gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4, uintptr_t a5, uintptr_t a6, uintptr_t a7, uintptr_t a8, uintptr_t a9)
{
return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9);
}
================================================
FILE: vendor/golang.org/x/sys/unix/gccgo_linux_amd64.go
================================================
// 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 gccgo && linux && amd64
package unix
import "syscall"
//extern gettimeofday
func realGettimeofday(*Timeval, *byte) int32
func gettimeofday(tv *Timeval) (err syscall.Errno) {
r := realGettimeofday(tv, nil)
if r < 0 {
return syscall.GetErrno()
}
return 0
}
================================================
FILE: vendor/golang.org/x/sys/unix/ifreq_linux.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux
package unix
import (
"unsafe"
)
// Helpers for dealing with ifreq since it contains a union and thus requires a
// lot of unsafe.Pointer casts to use properly.
// An Ifreq is a type-safe wrapper around the raw ifreq struct. An Ifreq
// contains an interface name and a union of arbitrary data which can be
// accessed using the Ifreq's methods. To create an Ifreq, use the NewIfreq
// function.
//
// Use the Name method to access the stored interface name. The union data
// fields can be get and set using the following methods:
// - Uint16/SetUint16: flags
// - Uint32/SetUint32: ifindex, metric, mtu
type Ifreq struct{ raw ifreq }
// NewIfreq creates an Ifreq with the input network interface name after
// validating the name does not exceed IFNAMSIZ-1 (trailing NULL required)
// bytes.
func NewIfreq(name string) (*Ifreq, error) {
// Leave room for terminating NULL byte.
if len(name) >= IFNAMSIZ {
return nil, EINVAL
}
var ifr ifreq
copy(ifr.Ifrn[:], name)
return &Ifreq{raw: ifr}, nil
}
// TODO(mdlayher): get/set methods for hardware address sockaddr, char array, etc.
// Name returns the interface name associated with the Ifreq.
func (ifr *Ifreq) Name() string {
return ByteSliceToString(ifr.raw.Ifrn[:])
}
// According to netdevice(7), only AF_INET addresses are returned for numerous
// sockaddr ioctls. For convenience, we expose these as Inet4Addr since the Port
// field and other data is always empty.
// Inet4Addr returns the Ifreq union data from an embedded sockaddr as a C
// in_addr/Go []byte (4-byte IPv4 address) value. If the sockaddr family is not
// AF_INET, an error is returned.
func (ifr *Ifreq) Inet4Addr() ([]byte, error) {
raw := *(*RawSockaddrInet4)(unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]))
if raw.Family != AF_INET {
// Cannot safely interpret raw.Addr bytes as an IPv4 address.
return nil, EINVAL
}
return raw.Addr[:], nil
}
// SetInet4Addr sets a C in_addr/Go []byte (4-byte IPv4 address) value in an
// embedded sockaddr within the Ifreq's union data. v must be 4 bytes in length
// or an error will be returned.
func (ifr *Ifreq) SetInet4Addr(v []byte) error {
if len(v) != 4 {
return EINVAL
}
var addr [4]byte
copy(addr[:], v)
ifr.clear()
*(*RawSockaddrInet4)(
unsafe.Pointer(&ifr.raw.Ifru[:SizeofSockaddrInet4][0]),
) = RawSockaddrInet4{
// Always set IP family as ioctls would require it anyway.
Family: AF_INET,
Addr: addr,
}
return nil
}
// Uint16 returns the Ifreq union data as a C short/Go uint16 value.
func (ifr *Ifreq) Uint16() uint16 {
return *(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0]))
}
// SetUint16 sets a C short/Go uint16 value as the Ifreq's union data.
func (ifr *Ifreq) SetUint16(v uint16) {
ifr.clear()
*(*uint16)(unsafe.Pointer(&ifr.raw.Ifru[:2][0])) = v
}
// Uint32 returns the Ifreq union data as a C int/Go uint32 value.
func (ifr *Ifreq) Uint32() uint32 {
return *(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0]))
}
// SetUint32 sets a C int/Go uint32 value as the Ifreq's union data.
func (ifr *Ifreq) SetUint32(v uint32) {
ifr.clear()
*(*uint32)(unsafe.Pointer(&ifr.raw.Ifru[:4][0])) = v
}
// clear zeroes the ifreq's union field to prevent trailing garbage data from
// being sent to the kernel if an ifreq is reused.
func (ifr *Ifreq) clear() {
clear(ifr.raw.Ifru[:])
}
// TODO(mdlayher): export as IfreqData? For now we can provide helpers such as
// IoctlGetEthtoolDrvinfo which use these APIs under the hood.
// An ifreqData is an Ifreq which carries pointer data. To produce an ifreqData,
// use the Ifreq.withData method.
type ifreqData struct {
name [IFNAMSIZ]byte
// A type separate from ifreq is required in order to comply with the
// unsafe.Pointer rules since the "pointer-ness" of data would not be
// preserved if it were cast into the byte array of a raw ifreq.
data unsafe.Pointer
// Pad to the same size as ifreq.
_ [len(ifreq{}.Ifru) - SizeofPtr]byte
}
// withData produces an ifreqData with the pointer p set for ioctls which require
// arbitrary pointer data.
func (ifr Ifreq) withData(p unsafe.Pointer) ifreqData {
return ifreqData{
name: ifr.raw.Ifrn,
data: p,
}
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_linux.go
================================================
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package unix
import "unsafe"
// IoctlRetInt performs an ioctl operation specified by req on a device
// associated with opened file descriptor fd, and returns a non-negative
// integer that is returned by the ioctl syscall.
func IoctlRetInt(fd int, req uint) (int, error) {
ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
if err != 0 {
return 0, err
}
return int(ret), nil
}
func IoctlGetUint32(fd int, req uint) (uint32, error) {
var value uint32
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetRTCTime(fd int) (*RTCTime, error) {
var value RTCTime
err := ioctlPtr(fd, RTC_RD_TIME, unsafe.Pointer(&value))
return &value, err
}
func IoctlSetRTCTime(fd int, value *RTCTime) error {
return ioctlPtr(fd, RTC_SET_TIME, unsafe.Pointer(value))
}
func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
var value RTCWkAlrm
err := ioctlPtr(fd, RTC_WKALM_RD, unsafe.Pointer(&value))
return &value, err
}
func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
return ioctlPtr(fd, RTC_WKALM_SET, unsafe.Pointer(value))
}
// IoctlGetEthtoolDrvinfo fetches ethtool driver information for the network
// device specified by ifname.
func IoctlGetEthtoolDrvinfo(fd int, ifname string) (*EthtoolDrvinfo, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := EthtoolDrvinfo{Cmd: ETHTOOL_GDRVINFO}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
return &value, err
}
// IoctlGetEthtoolTsInfo fetches ethtool timestamping and PHC
// association for the network device specified by ifname.
func IoctlGetEthtoolTsInfo(fd int, ifname string) (*EthtoolTsInfo, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := EthtoolTsInfo{Cmd: ETHTOOL_GET_TS_INFO}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCETHTOOL, &ifrd)
return &value, err
}
// IoctlGetHwTstamp retrieves the hardware timestamping configuration
// for the network device specified by ifname.
func IoctlGetHwTstamp(fd int, ifname string) (*HwTstampConfig, error) {
ifr, err := NewIfreq(ifname)
if err != nil {
return nil, err
}
value := HwTstampConfig{}
ifrd := ifr.withData(unsafe.Pointer(&value))
err = ioctlIfreqData(fd, SIOCGHWTSTAMP, &ifrd)
return &value, err
}
// IoctlSetHwTstamp updates the hardware timestamping configuration for
// the network device specified by ifname.
func IoctlSetHwTstamp(fd int, ifname string, cfg *HwTstampConfig) error {
ifr, err := NewIfreq(ifname)
if err != nil {
return err
}
ifrd := ifr.withData(unsafe.Pointer(cfg))
return ioctlIfreqData(fd, SIOCSHWTSTAMP, &ifrd)
}
// FdToClockID derives the clock ID from the file descriptor number
// - see clock_gettime(3), FD_TO_CLOCKID macros. The resulting ID is
// suitable for system calls like ClockGettime.
func FdToClockID(fd int) int32 { return int32((int(^fd) << 3) | 3) }
// IoctlPtpClockGetcaps returns the description of a given PTP device.
func IoctlPtpClockGetcaps(fd int) (*PtpClockCaps, error) {
var value PtpClockCaps
err := ioctlPtr(fd, PTP_CLOCK_GETCAPS2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpSysOffsetPrecise returns a description of the clock
// offset compared to the system clock.
func IoctlPtpSysOffsetPrecise(fd int) (*PtpSysOffsetPrecise, error) {
var value PtpSysOffsetPrecise
err := ioctlPtr(fd, PTP_SYS_OFFSET_PRECISE2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpSysOffsetExtended returns an extended description of the
// clock offset compared to the system clock. The samples parameter
// specifies the desired number of measurements.
func IoctlPtpSysOffsetExtended(fd int, samples uint) (*PtpSysOffsetExtended, error) {
value := PtpSysOffsetExtended{Samples: uint32(samples)}
err := ioctlPtr(fd, PTP_SYS_OFFSET_EXTENDED2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpPinGetfunc returns the configuration of the specified
// I/O pin on given PTP device.
func IoctlPtpPinGetfunc(fd int, index uint) (*PtpPinDesc, error) {
value := PtpPinDesc{Index: uint32(index)}
err := ioctlPtr(fd, PTP_PIN_GETFUNC2, unsafe.Pointer(&value))
return &value, err
}
// IoctlPtpPinSetfunc updates configuration of the specified PTP
// I/O pin.
func IoctlPtpPinSetfunc(fd int, pd *PtpPinDesc) error {
return ioctlPtr(fd, PTP_PIN_SETFUNC2, unsafe.Pointer(pd))
}
// IoctlPtpPeroutRequest configures the periodic output mode of the
// PTP I/O pins.
func IoctlPtpPeroutRequest(fd int, r *PtpPeroutRequest) error {
return ioctlPtr(fd, PTP_PEROUT_REQUEST2, unsafe.Pointer(r))
}
// IoctlPtpExttsRequest configures the external timestamping mode
// of the PTP I/O pins.
func IoctlPtpExttsRequest(fd int, r *PtpExttsRequest) error {
return ioctlPtr(fd, PTP_EXTTS_REQUEST2, unsafe.Pointer(r))
}
// IoctlGetWatchdogInfo fetches information about a watchdog device from the
// Linux watchdog API. For more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func IoctlGetWatchdogInfo(fd int) (*WatchdogInfo, error) {
var value WatchdogInfo
err := ioctlPtr(fd, WDIOC_GETSUPPORT, unsafe.Pointer(&value))
return &value, err
}
// IoctlWatchdogKeepalive issues a keepalive ioctl to a watchdog device. For
// more information, see:
// https://www.kernel.org/doc/html/latest/watchdog/watchdog-api.html.
func IoctlWatchdogKeepalive(fd int) error {
// arg is ignored and not a pointer, so ioctl is fine instead of ioctlPtr.
return ioctl(fd, WDIOC_KEEPALIVE, 0)
}
// IoctlFileCloneRange performs an FICLONERANGE ioctl operation to clone the
// range of data conveyed in value to the file associated with the file
// descriptor destFd. See the ioctl_ficlonerange(2) man page for details.
func IoctlFileCloneRange(destFd int, value *FileCloneRange) error {
return ioctlPtr(destFd, FICLONERANGE, unsafe.Pointer(value))
}
// IoctlFileClone performs an FICLONE ioctl operation to clone the entire file
// associated with the file description srcFd to the file associated with the
// file descriptor destFd. See the ioctl_ficlone(2) man page for details.
func IoctlFileClone(destFd, srcFd int) error {
return ioctl(destFd, FICLONE, uintptr(srcFd))
}
type FileDedupeRange struct {
Src_offset uint64
Src_length uint64
Reserved1 uint16
Reserved2 uint32
Info []FileDedupeRangeInfo
}
type FileDedupeRangeInfo struct {
Dest_fd int64
Dest_offset uint64
Bytes_deduped uint64
Status int32
Reserved uint32
}
// IoctlFileDedupeRange performs an FIDEDUPERANGE ioctl operation to share the
// range of data conveyed in value from the file associated with the file
// descriptor srcFd to the value.Info destinations. See the
// ioctl_fideduperange(2) man page for details.
func IoctlFileDedupeRange(srcFd int, value *FileDedupeRange) error {
buf := make([]byte, SizeofRawFileDedupeRange+
len(value.Info)*SizeofRawFileDedupeRangeInfo)
rawrange := (*RawFileDedupeRange)(unsafe.Pointer(&buf[0]))
rawrange.Src_offset = value.Src_offset
rawrange.Src_length = value.Src_length
rawrange.Dest_count = uint16(len(value.Info))
rawrange.Reserved1 = value.Reserved1
rawrange.Reserved2 = value.Reserved2
for i := range value.Info {
rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
uintptr(i*SizeofRawFileDedupeRangeInfo)))
rawinfo.Dest_fd = value.Info[i].Dest_fd
rawinfo.Dest_offset = value.Info[i].Dest_offset
rawinfo.Bytes_deduped = value.Info[i].Bytes_deduped
rawinfo.Status = value.Info[i].Status
rawinfo.Reserved = value.Info[i].Reserved
}
err := ioctlPtr(srcFd, FIDEDUPERANGE, unsafe.Pointer(&buf[0]))
// Output
for i := range value.Info {
rawinfo := (*RawFileDedupeRangeInfo)(unsafe.Pointer(
uintptr(unsafe.Pointer(&buf[0])) + uintptr(SizeofRawFileDedupeRange) +
uintptr(i*SizeofRawFileDedupeRangeInfo)))
value.Info[i].Dest_fd = rawinfo.Dest_fd
value.Info[i].Dest_offset = rawinfo.Dest_offset
value.Info[i].Bytes_deduped = rawinfo.Bytes_deduped
value.Info[i].Status = rawinfo.Status
value.Info[i].Reserved = rawinfo.Reserved
}
return err
}
func IoctlHIDGetDesc(fd int, value *HIDRawReportDescriptor) error {
return ioctlPtr(fd, HIDIOCGRDESC, unsafe.Pointer(value))
}
func IoctlHIDGetRawInfo(fd int) (*HIDRawDevInfo, error) {
var value HIDRawDevInfo
err := ioctlPtr(fd, HIDIOCGRAWINFO, unsafe.Pointer(&value))
return &value, err
}
func IoctlHIDGetRawName(fd int) (string, error) {
var value [_HIDIOCGRAWNAME_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWNAME, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
func IoctlHIDGetRawPhys(fd int) (string, error) {
var value [_HIDIOCGRAWPHYS_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWPHYS, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
func IoctlHIDGetRawUniq(fd int) (string, error) {
var value [_HIDIOCGRAWUNIQ_LEN]byte
err := ioctlPtr(fd, _HIDIOCGRAWUNIQ, unsafe.Pointer(&value[0]))
return ByteSliceToString(value[:]), err
}
// IoctlIfreq performs an ioctl using an Ifreq structure for input and/or
// output. See the netdevice(7) man page for details.
func IoctlIfreq(fd int, req uint, value *Ifreq) error {
// It is possible we will add more fields to *Ifreq itself later to prevent
// misuse, so pass the raw *ifreq directly.
return ioctlPtr(fd, req, unsafe.Pointer(&value.raw))
}
// TODO(mdlayher): export if and when IfreqData is exported.
// ioctlIfreqData performs an ioctl using an ifreqData structure for input
// and/or output. See the netdevice(7) man page for details.
func ioctlIfreqData(fd int, req uint, value *ifreqData) error {
// The memory layout of IfreqData (type-safe) and ifreq (not type-safe) are
// identical so pass *IfreqData directly.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlKCMClone attaches a new file descriptor to a multiplexor by cloning an
// existing KCM socket, returning a structure containing the file descriptor of
// the new socket.
func IoctlKCMClone(fd int) (*KCMClone, error) {
var info KCMClone
if err := ioctlPtr(fd, SIOCKCMCLONE, unsafe.Pointer(&info)); err != nil {
return nil, err
}
return &info, nil
}
// IoctlKCMAttach attaches a TCP socket and associated BPF program file
// descriptor to a multiplexor.
func IoctlKCMAttach(fd int, info KCMAttach) error {
return ioctlPtr(fd, SIOCKCMATTACH, unsafe.Pointer(&info))
}
// IoctlKCMUnattach unattaches a TCP socket file descriptor from a multiplexor.
func IoctlKCMUnattach(fd int, info KCMUnattach) error {
return ioctlPtr(fd, SIOCKCMUNATTACH, unsafe.Pointer(&info))
}
// IoctlLoopGetStatus64 gets the status of the loop device associated with the
// file descriptor fd using the LOOP_GET_STATUS64 operation.
func IoctlLoopGetStatus64(fd int) (*LoopInfo64, error) {
var value LoopInfo64
if err := ioctlPtr(fd, LOOP_GET_STATUS64, unsafe.Pointer(&value)); err != nil {
return nil, err
}
return &value, nil
}
// IoctlLoopSetStatus64 sets the status of the loop device associated with the
// file descriptor fd using the LOOP_SET_STATUS64 operation.
func IoctlLoopSetStatus64(fd int, value *LoopInfo64) error {
return ioctlPtr(fd, LOOP_SET_STATUS64, unsafe.Pointer(value))
}
// IoctlLoopConfigure configures all loop device parameters in a single step
func IoctlLoopConfigure(fd int, value *LoopConfig) error {
return ioctlPtr(fd, LOOP_CONFIGURE, unsafe.Pointer(value))
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_signed.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build aix || solaris
package unix
import "unsafe"
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req int, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req int, value int) error {
v := int32(value)
return ioctlPtr(fd, req, unsafe.Pointer(&v))
}
// IoctlSetString performs an ioctl operation which sets a string value
// on fd, using the specified request number.
func IoctlSetString(fd int, req int, value string) error {
bs := append([]byte(value), 0)
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req int, value *Termios) error {
// TODO: if we get the chance, remove the req parameter.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req int) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
func IoctlGetTermios(fd int, req int) (*Termios, error) {
var value Termios
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_unsigned.go
================================================
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin || dragonfly || freebsd || hurd || linux || netbsd || openbsd
package unix
import "unsafe"
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req uint, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetPointerInt performs an ioctl operation which sets an
// integer value on fd, using the specified request number. The ioctl
// argument is called with a pointer to the integer value, rather than
// passing the integer value directly.
func IoctlSetPointerInt(fd int, req uint, value int) error {
v := int32(value)
return ioctlPtr(fd, req, unsafe.Pointer(&v))
}
// IoctlSetString performs an ioctl operation which sets a string value
// on fd, using the specified request number.
func IoctlSetString(fd int, req uint, value string) error {
bs := append([]byte(value), 0)
return ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req uint, value *Termios) error {
// TODO: if we get the chance, remove the req parameter.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req uint) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
var value Termios
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/ioctl_zos.go
================================================
// 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 (
"runtime"
"unsafe"
)
// ioctl itself should not be exposed directly, but additional get/set
// functions for specific types are permissible.
// IoctlSetInt performs an ioctl operation which sets an integer value
// on fd, using the specified request number.
func IoctlSetInt(fd int, req int, value int) error {
return ioctl(fd, req, uintptr(value))
}
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
//
// To change fd's window size, the req argument should be TIOCSWINSZ.
func IoctlSetWinsize(fd int, req int, value *Winsize) error {
// TODO: if we get the chance, remove the req parameter and
// hardcode TIOCSWINSZ.
return ioctlPtr(fd, req, unsafe.Pointer(value))
}
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCSETS, TCSETSW, or TCSETSF
func IoctlSetTermios(fd int, req int, value *Termios) error {
if (req != TCSETS) && (req != TCSETSW) && (req != TCSETSF) {
return ENOSYS
}
err := Tcsetattr(fd, int(req), value)
runtime.KeepAlive(value)
return err
}
// IoctlGetInt performs an ioctl operation which gets an integer value
// from fd, using the specified request number.
//
// A few ioctl requests use the return value as an output parameter;
// for those, IoctlRetInt should be used instead of this function.
func IoctlGetInt(fd int, req int) (int, error) {
var value int
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return value, err
}
func IoctlGetWinsize(fd int, req int) (*Winsize, error) {
var value Winsize
err := ioctlPtr(fd, req, unsafe.Pointer(&value))
return &value, err
}
// IoctlGetTermios performs an ioctl on fd with a *Termios.
//
// The req value is expected to be TCGETS
func IoctlGetTermios(fd int, req int) (*Termios, error) {
var value Termios
if req != TCGETS {
return &value, ENOSYS
}
err := Tcgetattr(fd, &value)
return &value, err
}
================================================
FILE: vendor/golang.org/x/sys/unix/mkall.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# This script runs or (given -n) prints suggested commands to generate files for
# the Architecture/OS specified by the GOARCH and GOOS environment variables.
# See README.md for more information about how the build system works.
GOOSARCH="${GOOS}_${GOARCH}"
# defaults
mksyscall="go run mksyscall.go"
mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go"
mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
mkasm=
run="sh"
cmd=""
case "$1" in
-syscalls)
for i in zsyscall*go
do
# Run the command line that appears in the first line
# of the generated file to regenerate it.
sed 1q $i | sed 's;^// ;;' | sh > _$i && gofmt < _$i > $i
rm _$i
done
exit 0
;;
-n)
run="cat"
cmd="echo"
shift
esac
case "$#" in
0)
;;
*)
echo 'usage: mkall.sh [-n]' 1>&2
exit 2
esac
if [[ "$GOOS" = "linux" ]]; then
# Use the Docker-based build system
# Files generated through docker (use $cmd so you can Ctl-C the build or run)
set -e
$cmd docker build --tag generate:$GOOS $GOOS
$cmd docker run --rm --interactive --tty --volume $(cd -- "$(dirname -- "$0")/.." && pwd):/build generate:$GOOS
exit
fi
GOOSARCH_in=syscall_$GOOSARCH.go
case "$GOOSARCH" in
_* | *_ | _)
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
exit 1
;;
aix_ppc)
mkerrors="$mkerrors -maix32"
mksyscall="go run mksyscall_aix_ppc.go -aix"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
aix_ppc64)
mkerrors="$mkerrors -maix64"
mksyscall="go run mksyscall_aix_ppc64.go -aix"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
darwin_amd64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm.go"
;;
darwin_arm64)
mkerrors="$mkerrors -m64"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
mkasm="go run mkasm.go"
;;
dragonfly_amd64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -dragonfly"
mksysnum="go run mksysnum.go 'https://gitweb.dragonflybsd.org/dragonfly.git/blob_plain/HEAD:/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_386)
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_amd64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
freebsd_arm)
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -arm"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_arm64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
freebsd_riscv64)
mkerrors="$mkerrors -m64"
mksysnum="go run mksysnum.go 'https://cgit.freebsd.org/src/plain/sys/kern/syscalls.master?h=stable/12'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
netbsd_386)
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32 -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_amd64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
netbsd_arm)
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -netbsd -arm"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
netbsd_arm64)
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -netbsd"
mksysnum="go run mksysnum.go 'http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/sys/kern/syscalls.master'"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_386)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m32"
mksyscall="go run mksyscall.go -l32 -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_amd64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
openbsd_arm)
mkasm="go run mkasm.go"
mkerrors="$mkerrors"
mksyscall="go run mksyscall.go -l32 -openbsd -arm -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_arm64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_mips64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_ppc64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
openbsd_riscv64)
mkasm="go run mkasm.go"
mkerrors="$mkerrors -m64"
mksyscall="go run mksyscall.go -openbsd -libc"
mksysctl="go run mksysctl_openbsd.go"
# Let the type of C char be signed for making the bare syscall
# API consistent across platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
solaris_amd64)
mksyscall="go run mksyscall_solaris.go"
mkerrors="$mkerrors -m64"
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
illumos_amd64)
mksyscall="go run mksyscall_solaris.go"
mkerrors=
mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;;
*)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
exit 1
;;
esac
(
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
case "$GOOS" in
*)
syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
darwin | dragonfly | freebsd | netbsd | openbsd)
syscall_goos="syscall_bsd.go $syscall_goos"
;;
esac
if [ -n "$mksyscall" ]; then
if [ "$GOOSARCH" == "aix_ppc64" ]; then
# aix/ppc64 script generates files instead of writing to stdin.
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
elif [ "$GOOS" == "illumos" ]; then
# illumos code generation requires a --illumos switch
echo "$mksyscall -illumos -tags illumos,$GOARCH syscall_illumos.go |gofmt > zsyscall_illumos_$GOARCH.go";
# illumos implies solaris, so solaris code generation is also required
echo "$mksyscall -tags solaris,$GOARCH syscall_solaris.go syscall_solaris_$GOARCH.go |gofmt >zsyscall_solaris_$GOARCH.go";
else
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
fi
fi
esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go | go run mkpost.go > ztypes_$GOOSARCH.go"; fi
if [ -n "$mkasm" ]; then echo "$mkasm $GOOS $GOARCH"; fi
) | $run
================================================
FILE: vendor/golang.org/x/sys/unix/mkerrors.sh
================================================
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.
unset LANG
export LC_ALL=C
export LC_CTYPE=C
if test -z "$GOARCH" -o -z "$GOOS"; then
echo 1>&2 "GOARCH or GOOS not defined in environment"
exit 1
fi
# Check that we are using the new build system if we should
if [[ "$GOOS" = "linux" ]] && [[ "$GOLANG_SYS_BUILD" != "docker" ]]; then
echo 1>&2 "In the Docker based build system, mkerrors should not be called directly."
echo 1>&2 "See README.md"
exit 1
fi
if [[ "$GOOS" = "aix" ]]; then
CC=${CC:-gcc}
else
CC=${CC:-cc}
fi
if [[ "$GOOS" = "solaris" ]]; then
# Assumes GNU versions of utilities in PATH.
export PATH=/usr/gnu/bin:$PATH
fi
uname=$(uname)
includes_AIX='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define AF_LOCAL AF_UNIX
'
includes_Darwin='
#define _DARWIN_C_SOURCE
#define KERNEL 1
#define _DARWIN_USE_64_BIT_INODE
#define __APPLE_USE_RFC_3542
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// for backwards compatibility because moved TIOCREMOTE to Kernel.framework after MacOSX12.0.sdk.
#define TIOCREMOTE 0x80047469
'
includes_DragonFly='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
'
includes_FreeBSD='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if __FreeBSD__ >= 10
#define IFT_CARP 0xf8 // IFT_CARP is deprecated in FreeBSD 10
#undef SIOCAIFADDR
#define SIOCAIFADDR _IOW(105, 26, struct oifaliasreq) // ifaliasreq contains if_data
#undef SIOCSIFPHYADDR
#define SIOCSIFPHYADDR _IOW(105, 70, struct oifaliasreq) // ifaliasreq contains if_data
#endif
'
includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#ifndef __LP64__
#define _FILE_OFFSET_BITS 64
#endif
#define _GNU_SOURCE
// See the description in unix/linux/types.go
#if defined(__ARM_EABI__) || \
(defined(__mips__) && (_MIPS_SIM == _ABIO32)) || \
(defined(__powerpc__) && (!defined(__powerpc64__)))
# ifdef _TIME_BITS
# undef _TIME_BITS
# endif
# define _TIME_BITS 32
#endif
// is broken on powerpc64, as it fails to include definitions of
// these structures. We just include them copied from .
#if defined(__powerpc__)
struct sgttyb {
char sg_ispeed;
char sg_ospeed;
char sg_erase;
char sg_kill;
short sg_flags;
};
struct tchars {
char t_intrc;
char t_quitc;
char t_startc;
char t_stopc;
char t_eofc;
char t_brkc;
};
struct ltchars {
char t_suspc;
char t_dsuspc;
char t_rprntc;
char t_flushc;
char t_werasc;
char t_lnextc;
};
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#if defined(__sparc__)
// On sparc{,64}, the kernel defines struct termios2 itself which clashes with the
// definition in glibc. As only the error constants are needed here, include the
// generic termibits.h (which is included by termbits.h on sparc).
#include
#else
#include
#endif
#ifndef PTRACE_GETREGS
#define PTRACE_GETREGS 0xc
#endif
#ifndef PTRACE_SETREGS
#define PTRACE_SETREGS 0xd
#endif
#ifdef SOL_BLUETOOTH
// SPARC includes this in /usr/include/sparc64-linux-gnu/bits/socket.h
// but it is already in bluetooth_linux.go
#undef SOL_BLUETOOTH
#endif
// Certain constants are missing from the fs/crypto UAPI
#define FS_KEY_DESC_PREFIX "fscrypt:"
#define FS_KEY_DESC_PREFIX_SIZE 8
#define FS_MAX_KEY_SIZE 64
// The code generator produces -0x1 for (~0), but an unsigned value is necessary
// for the tipc_subscr timeout __u32 field.
#undef TIPC_WAIT_FOREVER
#define TIPC_WAIT_FOREVER 0xffffffff
// Copied from linux/netfilter/nf_nat.h
// Including linux/netfilter/nf_nat.h here causes conflicts between linux/in.h
// and netinet/in.h.
#define NF_NAT_RANGE_MAP_IPS (1 << 0)
#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.
// Keep in sync with the size of the referenced fields.
#define _HIDIOCGRAWNAME_LEN 128 // sizeof_field(struct hid_device, name)
#define _HIDIOCGRAWPHYS_LEN 64 // sizeof_field(struct hid_device, phys)
#define _HIDIOCGRAWUNIQ_LEN 64 // sizeof_field(struct hid_device, uniq)
#define _HIDIOCGRAWNAME HIDIOCGRAWNAME(_HIDIOCGRAWNAME_LEN)
#define _HIDIOCGRAWPHYS HIDIOCGRAWPHYS(_HIDIOCGRAWPHYS_LEN)
#define _HIDIOCGRAWUNIQ HIDIOCGRAWUNIQ(_HIDIOCGRAWUNIQ_LEN)
// Renamed in v6.16, commit c6d732c38f93 ("net: ethtool: remove duplicate defines for family info")
#define ETHTOOL_FAMILY_NAME ETHTOOL_GENL_NAME
#define ETHTOOL_FAMILY_VERSION ETHTOOL_GENL_VERSION
'
includes_NetBSD='
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include