This repository was archived by the owner on May 24, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwrite.go
More file actions
48 lines (41 loc) · 1.46 KB
/
write.go
File metadata and controls
48 lines (41 loc) · 1.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package rawnet
import (
"fmt"
"os"
"syscall"
"unsafe"
)
// With raw packet quite often data needs to be prefixed, however that means a
// lot of bytes needs to be copied over and this is generally a bad idea in
// term of performances. We can avoid that by not concatenating data but
// instead pass all the data to be written in an array of buffers.
//
// The code below comes from: https://github.com/google/vectorio
// Writev calls writev() syscall, but first convert a [][]byte to []sycall.Iovec, return number of bytes written and an error
func Writev(f *os.File, in [][]byte) (nw int, err error) {
iovec := make([]syscall.Iovec, len(in))
for i, slice := range in {
iovec[i] = syscall.Iovec{&slice[0], uint64(len(slice))}
}
// using f.Fd() makes SetDeadline() not working. Is it something we
// care about? What does SyscallConn().Write() cost in terms of perfs?
//nw, err = WritevRaw(uintptr(f.Fd()), iovec)
c, err := f.SyscallConn()
if err != nil {
return 0, err
}
err = c.Write(func(fd uintptr) (done bool) {
nw, err = WritevRaw(fd, iovec)
return true
})
return
}
// WritevRaw calls writev() syscall like Writev, but expects a slice of syscall.Iovec
func WritevRaw(fd uintptr, iovec []syscall.Iovec) (nw int, err error) {
nwRaw, _, errno := syscall.Syscall(syscall.SYS_WRITEV, fd, uintptr(unsafe.Pointer(&iovec[0])), uintptr(len(iovec)))
nw = int(nwRaw)
if errno != 0 {
err = fmt.Errorf("writev failed with error: %w", syscall.Errno(errno))
}
return
}