{$endif}\r
\r
TLInetSockAddr4 = packed Record\r
+ {$ifdef bsd}\r
+ len:byte;\r
+ family:byte;\r
+ {$else}\r
family:Word;\r
+ {$endif}\r
port :Word;\r
addr :uint32;\r
pad :array [0..7] of byte; //zipplet 20170204 - originally this was 1..8 for some reason\r
\r
{$ifdef ipv6}\r
TLInetSockAddr6 = packed record\r
+ {$ifdef bsd}\r
+ sin6_len:byte;\r
+ sin6_family:byte;\r
+ {$else}\r
sin6_family: word;\r
+ {$endif}\r
sin6_port: word;\r
sin6_flowinfo: uint32;\r
sin6_addr: tin6_addr;\r
fillchar(inaddr,sizeof(inaddr),0);\r
//writeln('converted address '+addr+' to binip '+ipbintostr(biniptemp));\r
if addr.family = AF_INET then begin\r
+ {$ifdef bsd}\r
+ inAddr.InAddr.Len := sizeof(tlinetsockaddr4);\r
+ {$endif}\r
inAddr.InAddr.family:=AF_INET;\r
inAddr.InAddr.port:=htons(strtointdef(port,0));\r
inAddr.InAddr.addr:=addr.ip;\r
end else\r
{$ifdef ipv6}\r
if addr.family = AF_INET6 then begin\r
+ {$ifdef bsd}\r
+ inAddr.InAddr6.sin6_len := sizeof(tlinetsockaddr6);\r
+ {$endif}\r
inAddr.InAddr6.sin6_family:=AF_INET6;\r
inAddr.InAddr6.sin6_port:=htons(strtointdef(port,0));\r
inAddr.InAddr6.sin6_addr:=addr.ip6;\r
uses\r
baseunix,unix,sockets,sysutils;\r
\r
+{$ifdef linux}\r
\r
function getlocalips_internal(wantfamily:integer):tbiniplist;\r
const\r
IF_NAMESIZE=16;\r
+ SIOCGIFCONF=$8912;\r
\r
- {$ifdef linux}SIOCGIFCONF=$8912;{$endif}\r
- {$ifdef bsd}{$ifdef cpu386}SIOCGIFCONF=$C0086924;{$endif}{$endif}\r
-\r
- {amd64: mac OS X: $C00C6924; freeBSD: $c0106924}\r
type\r
tifconf=packed record\r
ifc_len:taddrint;\r
if (fpioctl(s,SIOCGIFCONF,@ifc) < 0) then begin\r
raise exception.create('getv4localips ioctl failed');\r
end;\r
- if (lastlen = ifc.ifc_len) then break; \r
+ if (lastlen = ifc.ifc_len) then break;\r
lastlen := ifc.ifc_len;\r
len := len * 2;\r
until false;\r
- \r
+\r
ifr2 := ifr;\r
ifrmax := pointer(taddrint(ifr) + ifc.ifc_len);\r
while (ifr2 < ifrmax) do begin\r
{calculate len}\r
ad := @ifr2.ifru_addr;\r
\r
- {$ifdef bsd}\r
- len := ad.inaddr.len + IF_NAMESIZE;\r
- if (len < sizeof(tifrec)) then \r
- {$endif}\r
len := sizeof(tifrec);\r
\r
if (len < sizeof(tifrec)) then break; {not enough left}\r
FileClose(s);\r
end;\r
\r
+{$endif} //linux\r
+\r
+{$ifdef bsd}\r
+\r
+type\r
+ pifaddrs = ^Tifaddrs;\r
+ Tifaddrs = record\r
+ ifa_next: pifaddrs;\r
+ ifa_name: pansichar;\r
+ ifa_flags: cuint; // Interface flags (IFF_UP, IFF_BROADCAST, etc.)\r
+ ifa_addr: Pinetsockaddrv;\r
+ ifa_netmask: psockaddr;\r
+ ifa_dstaddr: psockaddr; // union: Destination address (P-t-P) or broadcast address\r
+ ifa_data: Pointer;\r
+ end;\r
+\r
+const\r
+ IFF_UP=1; //interface is administratively enabled\r
+\r
+function getifaddrs(var ifap: pifaddrs): cint; cdecl; external 'c' name 'getifaddrs';\r
+function freeifaddrs(ifap: pifaddrs): cint; cdecl; external 'c' name 'freeifaddrs';\r
+\r
+\r
+function getlocalips_internal(wantfamily:integer):tbiniplist;\r
+var\r
+ IfList: pifaddrs;\r
+ IfPtr: pifaddrs;\r
+ sa: PinetSockAddrV;\r
+begin\r
+ result := biniplist_new;\r
+\r
+ if getifaddrs(IfList) <> 0 then raise exception.create('getlocalips getifaddrs failed');\r
+\r
+ IfPtr := IfList;\r
+ while IfPtr <> nil do begin\r
+ if ((IfPtr^.ifa_flags and IFF_UP) <> 0) then begin\r
+ sa := IfPtr^.ifa_addr;\r
+ //if (sa <> nil) then writeln(sa^.inaddr.len,' ',sa^.inaddr.family);\r
+\r
+ if (sa <> nil) and (sa^.inaddr.family = wantfamily) then begin\r
+ biniplist_add(result, inaddrvtobinip(sa^));\r
+ end;\r
+ end;\r
+ IfPtr := IfPtr^.ifa_next;\r
+ end;\r
+\r
+ freeifaddrs(IfList);\r
+end;\r
+\r
+{$endif} //bsd\r
+\r
+\r
{$ifdef ipv6}\r
function getv6localips:tbiniplist;\r
+{$ifndef bsd}\r
var\r
t:textfile;\r
s,s2:ansistring;\r
ip:tbinip;\r
a:integer;\r
+{$endif}\r
begin\r
+ {$ifdef bsd}\r
+ result := getlocalips_internal(AF_INET6);\r
+ {$else}\r
+ //linux\r
result := biniplist_new;\r
\r
assignfile(t,'/proc/net/if_inet6');\r
if ip.family <> 0 then biniplist_add(result,ip);\r
end;\r
closefile(t);\r
+ {$endif}\r
end;\r
{$endif} //ipv6\r
\r
end;\r
\r
\r
+{$ifdef bsd}\r
+function arc4random: cardinal; cdecl; external 'c' name 'arc4random';\r
+procedure arc4random_buf(buf: Pointer; nbytes: SizeUInt); cdecl; external 'c' name 'arc4random_buf';\r
+function arc4random_uniform(upper_bound: cardinal): cardinal; cdecl; external 'c' name 'arc4random_uniform';\r
+{$endif}\r
+\r
+\r
{$ifdef linux}\r
{$ifdef i386}\r
const sys_getrandom = 355;\r
a := do_syscall(sys_getrandom,tsysparam(@l.devrnd),sizeof(l.devrnd),0);\r
{$endif}\r
\r
+ {$ifdef bsd}\r
+ a := sizeof(l.devrnd);\r
+ arc4random_buf(@l.devrnd, a);\r
+ {$endif}\r
+\r
if (a < sizeof(l.devrnd)) then begin\r
{if syscall misses or fails, fall back to /dev/urandom}\r
assignfile(f,'/dev/urandom');\r
end;\r
\r
\r
+{\r
+select in linux/sysV subtracts from timeout for time spent in it, but in BSD it doesn't\r
+enabling select_no_autotv here makes doSelect mimic the decrement behavior, in case the caller needs it\r
+the caller here in lcoreselect does not need it, and enabling it would have a slight perf hit.\r
+it is safe for this to be enabled even if the OS does it too (it will not subtract twice)\r
+it is currently disabled but can be enabled if needed\r
+}\r
+{$ifndef linux}{-$define select_no_autotv}{$endif}\r
+\r
Function doSelect(timeOut:PTimeVal):longint;//inline;\r
var\r
localtimeval : ttimeval;\r
maxslocal : integer;\r
+ {$ifdef select_no_autotv}\r
+ timeoutcopy,tvstart,tvend : ttimeval;\r
+ {$endif}\r
begin\r
//unblock signals\r
//zeromemory(@sset,sizeof(sset));\r
{$ifndef nosignal}\r
sigprocmask(SIG_UNBLOCK,@blockset,nil);\r
{$endif}\r
+\r
+ {$ifdef select_no_autotv}\r
+ if assigned(timeout) then begin\r
+ timeoutcopy.tv_sec := timeOut.tv_sec;\r
+ timeoutcopy.tv_usec := timeOut.tv_usec;\r
+ gettimemonotonic(tvstart);\r
+ end;\r
+ {$endif}\r
+\r
result := select(maxslocal+1,@FDSR,@FDSW,nil,timeout);\r
if result <= 0 then begin\r
fd_zero(FDSR);\r
end else begin\r
raise esocketexception.create('select returned error '+inttostr(linuxerror));\r
end;\r
+ end\r
+ {$ifdef select_no_autotv}\r
+ else if (result = 0) and assigned(timeout) then begin\r
+ //timeout reached: zero the timeval\r
+ timeout.tv_sec := 0;\r
+ timeout.tv_usec := 0;\r
end;\r
+ end else if assigned(timeout) then begin\r
+ //successful result: subtract elapsed time\r
+ gettimemonotonic(tvend);\r
+ tv_subtract(tvend,tvstart);\r
+ tv_subtract(timeoutcopy,tvend);\r
+ timeout.tv_sec := timeoutcopy.tv_sec;\r
+ timeout.tv_usec := timeoutcopy.tv_usec;\r
+ if (timeout.tv_sec < 0) then begin\r
+ timeout.tv_sec := 0;\r
+ timeout.tv_usec := 0;\r
+ end;\r
+ {$endif} //select_no_autotv\r
end;\r
+\r
{$ifndef nosignal}\r
sigprocmask(SIG_BLOCK,@blockset,nil);\r
{$endif}\r