in unix/syscall_zos_s390x.go [906:1103]
func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) {
jobname := []byte("\x5c\x40\x40\x40\x40\x40\x40\x40") // "*"
responseBuffer := [4096]byte{0}
var bufferAlet, reasonCode uint32 = 0, 0
var bufferLen, returnValue, returnCode int32 = 4096, 0, 0
dsa := [18]uint64{0}
var argv [7]unsafe.Pointer
argv[0] = unsafe.Pointer(&jobname[0])
argv[1] = unsafe.Pointer(&responseBuffer[0])
argv[2] = unsafe.Pointer(&bufferAlet)
argv[3] = unsafe.Pointer(&bufferLen)
argv[4] = unsafe.Pointer(&returnValue)
argv[5] = unsafe.Pointer(&returnCode)
argv[6] = unsafe.Pointer(&reasonCode)
request := (*struct {
header nwmHeader
filter nwmFilter
})(unsafe.Pointer(&responseBuffer[0]))
EZBNMIF4 := svcLoad(&svcNameTable[svc_EZBNMIF4][0])
if EZBNMIF4 == nil {
return nil, errnoErr(EINVAL)
}
// GetGlobalStats EZBNMIF4 call
request.header.ident = nwmHeaderIdentifier
request.header.length = uint32(unsafe.Sizeof(request.header))
request.header.version = nwmCurrentVer
request.header.nwmType = nwmGlobalStatsType
request.header.options = 0x80000000
svcCall(EZBNMIF4, &argv[0], &dsa[0])
// outputDesc field is filled by EZBNMIF4 on success
if returnCode != 0 || request.header.outputDesc.offset == 0 {
return nil, errnoErr(EINVAL)
}
// Check that EZBNMIF4 returned a nwmRecHeader
recHeader := (*nwmRecHeader)(unsafe.Pointer(&responseBuffer[request.header.outputDesc.offset]))
if recHeader.ident != nwmRecHeaderIdentifier {
return nil, errnoErr(EINVAL)
}
// Parse nwmTriplets to get offsets of returned entries
var sections []*uint64
var sectionDesc *nwmTriplet = (*nwmTriplet)(unsafe.Pointer(&responseBuffer[0]))
for i := uint32(0); i < uint32(recHeader.number); i++ {
offset := request.header.outputDesc.offset + uint32(unsafe.Sizeof(*recHeader)) + i*uint32(unsafe.Sizeof(*sectionDesc))
sectionDesc = (*nwmTriplet)(unsafe.Pointer(&responseBuffer[offset]))
for j := uint32(0); j < sectionDesc.number; j++ {
offset = request.header.outputDesc.offset + sectionDesc.offset + j*sectionDesc.length
sections = append(sections, (*uint64)(unsafe.Pointer(&responseBuffer[offset])))
}
}
// Find nwmTCPStatsEntry in returned entries
var tcpStats *nwmTCPStatsEntry = nil
for _, ptr := range sections {
switch *ptr {
case nwmTCPStatsIdentifier:
if tcpStats != nil {
return nil, errnoErr(EINVAL)
}
tcpStats = (*nwmTCPStatsEntry)(unsafe.Pointer(ptr))
case nwmIPStatsIdentifier:
case nwmIPGStatsIdentifier:
case nwmUDPStatsIdentifier:
case nwmICMPGStatsEntry:
case nwmICMPTStatsEntry:
default:
return nil, errnoErr(EINVAL)
}
}
if tcpStats == nil {
return nil, errnoErr(EINVAL)
}
// GetConnectionDetail EZBNMIF4 call
responseBuffer = [4096]byte{0}
dsa = [18]uint64{0}
bufferAlet, reasonCode = 0, 0
bufferLen, returnValue, returnCode = 4096, 0, 0
nameptr := (*uint32)(unsafe.Pointer(uintptr(0x21c))) // Get jobname of current process
nameptr = (*uint32)(unsafe.Pointer(uintptr(*nameptr + 12)))
argv[0] = unsafe.Pointer(uintptr(*nameptr))
request.header.ident = nwmHeaderIdentifier
request.header.length = uint32(unsafe.Sizeof(request.header))
request.header.version = nwmCurrentVer
request.header.nwmType = nwmTCPConnType
request.header.options = 0x80000000
request.filter.ident = nwmFilterIdentifier
var localSockaddr RawSockaddrAny
socklen := _Socklen(SizeofSockaddrAny)
err := getsockname(fd, &localSockaddr, &socklen)
if err != nil {
return nil, errnoErr(EINVAL)
}
if localSockaddr.Addr.Family == AF_INET {
localSockaddr := (*RawSockaddrInet4)(unsafe.Pointer(&localSockaddr.Addr))
localSockFilter := (*RawSockaddrInet4)(unsafe.Pointer(&request.filter.local[0]))
localSockFilter.Family = AF_INET
var i int
for i = 0; i < 4; i++ {
if localSockaddr.Addr[i] != 0 {
break
}
}
if i != 4 {
request.filter.flags |= nwmFilterLclAddrMask
for i = 0; i < 4; i++ {
localSockFilter.Addr[i] = localSockaddr.Addr[i]
}
}
if localSockaddr.Port != 0 {
request.filter.flags |= nwmFilterLclPortMask
localSockFilter.Port = localSockaddr.Port
}
} else if localSockaddr.Addr.Family == AF_INET6 {
localSockaddr := (*RawSockaddrInet6)(unsafe.Pointer(&localSockaddr.Addr))
localSockFilter := (*RawSockaddrInet6)(unsafe.Pointer(&request.filter.local[0]))
localSockFilter.Family = AF_INET6
var i int
for i = 0; i < 16; i++ {
if localSockaddr.Addr[i] != 0 {
break
}
}
if i != 16 {
request.filter.flags |= nwmFilterLclAddrMask
for i = 0; i < 16; i++ {
localSockFilter.Addr[i] = localSockaddr.Addr[i]
}
}
if localSockaddr.Port != 0 {
request.filter.flags |= nwmFilterLclPortMask
localSockFilter.Port = localSockaddr.Port
}
}
svcCall(EZBNMIF4, &argv[0], &dsa[0])
// outputDesc field is filled by EZBNMIF4 on success
if returnCode != 0 || request.header.outputDesc.offset == 0 {
return nil, errnoErr(EINVAL)
}
// Check that EZBNMIF4 returned a nwmConnEntry
conn := (*nwmConnEntry)(unsafe.Pointer(&responseBuffer[request.header.outputDesc.offset]))
if conn.ident != nwmTCPConnIdentifier {
return nil, errnoErr(EINVAL)
}
// Copy data from the returned data structures into tcpInfo
// Stats from nwmConnEntry are specific to that connection.
// Stats from nwmTCPStatsEntry are global (to the interface?)
// Fields may not be an exact match. Some fields have no equivalent.
var tcpinfo TCPInfo
tcpinfo.State = uint8(conn.state)
tcpinfo.Ca_state = 0 // dummy
tcpinfo.Retransmits = uint8(tcpStats.retransSegs)
tcpinfo.Probes = uint8(tcpStats.outWinProbes)
tcpinfo.Backoff = 0 // dummy
tcpinfo.Options = 0 // dummy
tcpinfo.Rto = tcpStats.retransTimeouts
tcpinfo.Ato = tcpStats.outDelayAcks
tcpinfo.Snd_mss = conn.sendMSS
tcpinfo.Rcv_mss = conn.sendMSS // dummy
tcpinfo.Unacked = 0 // dummy
tcpinfo.Sacked = 0 // dummy
tcpinfo.Lost = 0 // dummy
tcpinfo.Retrans = conn.reXmtCount
tcpinfo.Fackets = 0 // dummy
tcpinfo.Last_data_sent = uint32(*(*uint64)(unsafe.Pointer(&conn.lastActivity[0])))
tcpinfo.Last_ack_sent = uint32(*(*uint64)(unsafe.Pointer(&conn.outOldestTime[0])))
tcpinfo.Last_data_recv = uint32(*(*uint64)(unsafe.Pointer(&conn.inOldestTime[0])))
tcpinfo.Last_ack_recv = uint32(*(*uint64)(unsafe.Pointer(&conn.inOldestTime[0])))
tcpinfo.Pmtu = conn.sendMSS // dummy, NWMIfRouteMtu is a candidate
tcpinfo.Rcv_ssthresh = conn.ssThresh
tcpinfo.Rtt = conn.roundTripTime
tcpinfo.Rttvar = conn.roundTripVar
tcpinfo.Snd_ssthresh = conn.ssThresh // dummy
tcpinfo.Snd_cwnd = conn.congestionWnd
tcpinfo.Advmss = conn.sendMSS // dummy
tcpinfo.Reordering = 0 // dummy
tcpinfo.Rcv_rtt = conn.roundTripTime // dummy
tcpinfo.Rcv_space = conn.sendMSS // dummy
tcpinfo.Total_retrans = conn.reXmtCount
svcUnload(&svcNameTable[svc_EZBNMIF4][0], EZBNMIF4)
return &tcpinfo, nil
}