macuuid.pp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. {$mode objfpc}
  2. {$H+}
  3. {$IFNDEF FPC_DOTTEDUNITS}
  4. unit macuuid;
  5. {$ENDIF FPC_DOTTEDUNITS}
  6. Interface
  7. {$IFDEF FPC_DOTTEDUNITS}
  8. uses System.SysUtils;
  9. {$ELSE FPC_DOTTEDUNITS}
  10. uses SysUtils;
  11. {$ENDIF FPC_DOTTEDUNITS}
  12. Function CreateMacGUID(Out GUID : TGUID) : Integer;
  13. Implementation
  14. {$IFDEF FPC_DOTTEDUNITS}
  15. uses UnixApi.Types, System.Net.Sockets, UnixApi.Base, UnixApi.Unix;
  16. {$ELSE FPC_DOTTEDUNITS}
  17. uses unixtype, sockets, baseunix, unix;
  18. {$ENDIF FPC_DOTTEDUNITS}
  19. Const
  20. MAX_ADJUSTMENT = 10;
  21. IPPROTO_IP = 0;
  22. // AF_INET = 2;
  23. // SOCK_DGRAM = 2;
  24. IF_NAMESIZE = 16;
  25. SIOCGIFCONF = $8912;
  26. SIOCGIFHWADDR = $8927;
  27. Type
  28. {$packrecords c}
  29. tifr_ifrn = record
  30. case integer of
  31. 0 : (ifrn_name: array [0..IF_NAMESIZE-1] of AnsiChar);
  32. end;
  33. tifmap = record
  34. mem_start : culong;
  35. mem_end : culong;
  36. base_addr : cushort;
  37. irq : cuchar;
  38. dma : cuchar;
  39. port : cuchar;
  40. end;
  41. PIFrec = ^TIFrec;
  42. TIFrec = record
  43. ifr_ifrn : tifr_ifrn;
  44. case integer of
  45. 0 : (ifru_addr : TSockAddr);
  46. 1 : (ifru_dstaddr : TSockAddr);
  47. 2 : (ifru_broadaddr : TSockAddr);
  48. 3 : (ifru_netmask : TSockAddr);
  49. 4 : (ifru_hwaddr : TSockAddr);
  50. 5 : (ifru_flags : cshort);
  51. 6 : (ifru_ivalue : cint);
  52. 7 : (ifru_mtu : cint);
  53. 8 : (ifru_map : tifmap);
  54. 9 : (ifru_slave : Array[0..IF_NAMESIZE-1] of AnsiChar);
  55. 10 : (ifru_newname : Array[0..IF_NAMESIZE-1] of AnsiChar);
  56. 11 : (ifru_data : pointer);
  57. end;
  58. TIFConf = record
  59. ifc_len : cint;
  60. case integer of
  61. 0 : (ifcu_buf : pointer);
  62. 1 : (ifcu_req : ^tifrec);
  63. end;
  64. tuuid = record
  65. time_low : cardinal;
  66. time_mid : Word;
  67. time_hi_and_version : Word;
  68. clock_seq : Word;
  69. node : Array[0..5] of byte;
  70. end;
  71. Var
  72. MacAddr : Packed Array[1..6] of byte = (0,0,0,0,0,0);
  73. MacAddrTried : Byte = 0 ;
  74. Last : TTimeVal = (tv_sec:0;tv_usec:0);
  75. ClockSeq : Word = 0;
  76. AdjustMent : Integer = 0;
  77. Procedure GetRandomBytes(Var Buf; NBytes : Integer);
  78. Var
  79. I : Integer;
  80. P : PByte;
  81. begin
  82. P:=@Buf;
  83. Randomize;
  84. For I:=0 to NBytes-1 do
  85. P[i]:=Random(256);
  86. end;
  87. Function GetMacAddr : Boolean;
  88. var
  89. i,j,n,Sd : Integer;
  90. buf : Array[0..1023] of byte;
  91. ifc : TIfConf;
  92. ifr : TIFRec;
  93. ifp : PIFRec;
  94. p : PAnsiChar;
  95. begin
  96. Result:=MacAddrTried>0;
  97. If Result then
  98. Result:=MacAddrTried>1
  99. else
  100. begin
  101. MacAddrTried:=1;
  102. sd:=fpSocket(AF_INET,SOCK_DGRAM,IPPROTO_IP);
  103. if (sd<0) then
  104. exit;
  105. Try
  106. ifc.ifc_len:=Sizeof(Buf);
  107. ifc.ifcu_buf:=@buf;
  108. if fpioctl(sd, SIOCGIFCONF, @ifc)<0 then
  109. Exit;
  110. n:= ifc.ifc_len;
  111. i:=0;
  112. While (Not Result) and (I<N) do
  113. begin
  114. ifp:=PIFRec(PByte(ifc.ifcu_buf)+i);
  115. move(ifp^.ifr_ifrn.ifrn_name,ifr.ifr_ifrn.ifrn_name,IF_NAMESIZE);
  116. if (fpioctl(sd, SIOCGIFHWADDR, @ifr) >= 0) then
  117. begin
  118. P:=PAnsiChar(@ifr.ifru_hwaddr.sa_data);
  119. Result:=(p[0]<>#0) or (p[1]<>#0) or (p[2]<>#0)
  120. or (p[3]<>#0) or (p[4]<>#0) or (p[5]<>#0);
  121. If Result Then
  122. begin
  123. Move(P^,MacAddr,SizeOf(MacAddr));
  124. MacAddrTried:=2;
  125. // DumpMacAddr;
  126. end;
  127. end;
  128. I:=I+sizeof(tifrec);
  129. end;
  130. Finally
  131. fileClose(sd);
  132. end;
  133. end;
  134. end;
  135. Function GetClock(Var ClockHigh,ClockLow : Cardinal; Var RetClockSeq : Word) : boolean;
  136. Var
  137. TV : TTImeVal;
  138. ClockReg : QWord;
  139. OK : Boolean;
  140. begin
  141. OK:=True;
  142. Repeat
  143. FPGetTimeOfDay(@Tv,Nil);
  144. If (Last.tv_sec=0) and (last.tv_sec=0) then
  145. begin
  146. GetRandomBytes(ClockSeq,SizeOf(ClockSeq));
  147. ClockSeq:=ClockSeq and $1FFF;
  148. last:=TV;
  149. Dec(last.tv_sec);
  150. end;
  151. if (tv.tv_sec<last.tv_sec) or
  152. ((tv.tv_sec=last.tv_sec) and (tv.tv_usec<last.tv_usec)) then
  153. begin
  154. ClockSeq:=(ClockSeq+1) and $1FFF;
  155. Adjustment:=0;
  156. Last:=Tv;
  157. end
  158. else if (tv.tv_sec=last.tv_sec) and (tv.tv_usec=last.tv_usec) then
  159. begin
  160. If Adjustment>=MAX_ADJUSTMENT then
  161. OK:=False
  162. else
  163. inc(AdjustMent);
  164. end
  165. else
  166. begin
  167. AdjustMent:=0;
  168. Last:=tv;
  169. end;
  170. Until OK;
  171. ClockReg:=tv.tv_usec*10+adjustment;
  172. Inc(ClockReg,tv.tv_sec*10000000);
  173. Inc(ClockReg,($01B21DD2 shl 32) + $13814000);
  174. ClockHigh :=Hi(ClockReg);
  175. ClockLow :=Lo(ClockReg);
  176. RetClockSeq :=ClockSeq;
  177. Result :=True;
  178. end;
  179. Procedure UUIDPack(Const UU : TUUID; Var GUID : TGUID);
  180. Var
  181. tmp : Cardinal;
  182. P : PByte;
  183. begin
  184. P:=PByte(@GUID);
  185. tmp:=uu.time_low;
  186. P[3]:=tmp and $FF;
  187. tmp:=tmp shr 8;
  188. P[2]:=tmp and $FF;
  189. tmp:=tmp shr 8;
  190. P[1]:=tmp and $FF;
  191. tmp:=tmp shr 8;
  192. P[0]:=tmp and $FF;
  193. tmp:=uu.time_mid;
  194. P[5]:=tmp and $FF;
  195. tmp:=tmp shr 8;
  196. P[4]:=tmp and $FF;
  197. tmp:=uu.time_hi_and_version;
  198. P[7]:=tmp and $FF;
  199. tmp:=tmp shr 8;
  200. P[6]:=tmp and $FF;
  201. tmp:=uu.clock_seq;
  202. P[9]:=tmp and $FF;
  203. tmp:=tmp shr 8;
  204. P[8]:=tmp and $FF;
  205. Move(uu.node,P[10],6);
  206. end;
  207. Procedure DumpMacAddr;
  208. var
  209. I : Integer;
  210. begin
  211. Write('Mac Addr: ');
  212. For i:=1 to 6 do
  213. write(hexstr(MacAddr[i],2),':');
  214. end;
  215. Function CreateMacGUID(Out GUID : TGUID) : Integer;
  216. Var
  217. UU : TUUId;
  218. ClockMid : Cardinal;
  219. begin
  220. Result:=Ord(not GetMacAddr);
  221. If (Result=0) then
  222. begin
  223. // DumpMacAddr;
  224. // Writeln;
  225. GetClock(ClockMid,uu.time_low,uu.clock_seq);
  226. uu.Clock_seq:=uu.Clock_seq or $8000;
  227. uu.time_mid:=lo(clockMid);
  228. uu.time_hi_and_version:=hi(ClockMid) or $1000;
  229. move(MacAddr,uu.node,sizeof(MacAddr));
  230. UUIDPack(UU,GUID);
  231. end;
  232. end;
  233. initialization
  234. OnCreateGUID:=@CreateMacGUID;
  235. end.