Unix.Sockets.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. MODULE Sockets; (** AUTHOR "G.F."; PURPOSE "Interface to Unix sockets" *)
  2. (* derived from NetBase.Mod, BD / 13.2.96 *)
  3. (* 1998.04.27 g.f. Linux PPC version *)
  4. (* 1099.05.17 g.f. adapted to Threads *)
  5. (* 1999.11.22 g.f. Solaris x86 version *)
  6. (* 2000.02.18 g.f. adapted to Solaris 8 *)
  7. (* 2001.01.06 g.f. [c] - flag for new compiler *)
  8. (* 2007.07.06 g.f. IP address format converted to IP.Adr *)
  9. IMPORT S := SYSTEM, Unix, Trace, IP;
  10. CONST
  11. (*listen *)
  12. Backlog = 5; (* max number of pending connections *)
  13. TYPE
  14. SocketAdr* = POINTER TO RECORD
  15. family* : INTEGER;
  16. port* : INTEGER; (* in network byte order! *)
  17. END;
  18. SocketAdrV4* = POINTER TO RECORD (SocketAdr)
  19. v4Adr* : LONGINT;
  20. zero* : ARRAY 8 OF CHAR
  21. END;
  22. SocketAdrV6* = POINTER TO RECORD (SocketAdr)
  23. flowinfo* : LONGINT;
  24. v6Adr* : ARRAY 16 OF CHAR;
  25. scopeId* : LONGINT;
  26. srcId* : LONGINT
  27. END;
  28. NameBuf = POINTER TO RECORD
  29. buf: ARRAY 64 OF CHAR
  30. END;
  31. SocketOption = RECORD END;
  32. Linger = RECORD (SocketOption)
  33. onoff : LONGINT;
  34. linger : LONGINT;
  35. END;
  36. Switch = RECORD (SocketOption)
  37. onoff : LONGINT
  38. END;
  39. VAR
  40. socket : PROCEDURE {C} ( af, typ, protocol: LONGINT ): LONGINT;
  41. setsockopt : PROCEDURE {C} ( s: LONGINT; level, optname: LONGINT; VAR opt: SocketOption; optlen: LONGINT): LONGINT;
  42. accept : PROCEDURE {C} ( s: LONGINT; adrPtr: ADDRESS; VAR adrlen: LONGINT ): LONGINT;
  43. bind : PROCEDURE {C} ( s: LONGINT; adr: SocketAdr; adrlen: LONGINT ): LONGINT;
  44. connect : PROCEDURE {C} ( s: LONGINT; adr: SocketAdr; adrlen: LONGINT ): LONGINT;
  45. listen : PROCEDURE {C} ( s: LONGINT; backlog: LONGINT ): LONGINT;
  46. recv : PROCEDURE {C} ( s: LONGINT; buf: ADDRESS; len, flags: LONGINT ): LONGINT;
  47. send : PROCEDURE {C} ( s: LONGINT; buf: ADDRESS; len, flags: LONGINT ): LONGINT;
  48. recvfrom : PROCEDURE {C} ( s: LONGINT; buf: ADDRESS; len, flags: LONGINT; from: NameBuf; VAR flen: LONGINT ): LONGINT;
  49. sendto : PROCEDURE {C} ( s: LONGINT; buf: ADDRESS; len, flags: LONGINT; to: SocketAdr; tolen: LONGINT ): LONGINT;
  50. shutdown : PROCEDURE {C} ( s: LONGINT; how: LONGINT );
  51. getpeername : PROCEDURE {C} ( s: LONGINT; adr: NameBuf; VAR adrlen: LONGINT ): LONGINT;
  52. getsockname : PROCEDURE {C} ( s: LONGINT; adr: NameBuf; VAR adrlen: LONGINT ): LONGINT;
  53. htonl : PROCEDURE {C} ( hostlong : LONGINT ): LONGINT;
  54. htons : PROCEDURE {C} ( hostshort : LONGINT ): LONGINT;
  55. ntohl : PROCEDURE {C} ( netlong : LONGINT ): LONGINT;
  56. ntohs : PROCEDURE {C} ( netshort : LONGINT ): LONGINT;
  57. PROCEDURE NewSocketAdr*( ip: IP.Adr; port: LONGINT ): SocketAdr;
  58. VAR sadr4: SocketAdrV4; sadr6: SocketAdrV6; i: LONGINT;
  59. BEGIN
  60. CASE ip.usedProtocol OF
  61. | -1:
  62. NEW( sadr4 );
  63. sadr4.family := Unix.AFINET;
  64. sadr4.port := IntToNet( SHORT( port ) );
  65. sadr4.v4Adr := 0;
  66. RETURN sadr4
  67. | IP.IPv4:
  68. NEW( sadr4 );
  69. sadr4.family := Unix.AFINET;
  70. sadr4.port := IntToNet( SHORT( port ) );
  71. sadr4.v4Adr := ip.ipv4Adr;
  72. RETURN sadr4
  73. | IP.IPv6:
  74. NEW( sadr6 );
  75. sadr6.family := Unix.AFINET6;
  76. sadr6.port := IntToNet( SHORT( port ) );
  77. sadr6.flowinfo := 0;
  78. FOR i := 0 TO 15 DO sadr6.v6Adr[i] := ip.ipv6Adr[i] END;
  79. sadr6.scopeId := 0;
  80. sadr6.srcId := 0;
  81. RETURN sadr6
  82. ELSE
  83. HALT( 99 )
  84. END
  85. END NewSocketAdr;
  86. PROCEDURE SockAdrToIPAdr*( sadr: SocketAdr ): IP.Adr;
  87. VAR ip: IP.Adr; i: LONGINT;
  88. BEGIN
  89. IF sadr IS SocketAdrV4 THEN
  90. ip.usedProtocol := IP.IPv4;
  91. ip.ipv4Adr := sadr(SocketAdrV4).v4Adr;
  92. ip.ipv6Adr := ""
  93. ELSE
  94. ip.usedProtocol := IP.IPv6;
  95. ip.ipv4Adr := 0;
  96. FOR i := 0 TO 15 DO
  97. ip.ipv6Adr[i] := sadr(SocketAdrV6).v6Adr[i]
  98. END
  99. END;
  100. RETURN ip
  101. END SockAdrToIPAdr;
  102. PROCEDURE GetPortNumber*( sadr: SocketAdr ): LONGINT;
  103. VAR port: LONGINT;
  104. BEGIN
  105. port := NetToInt( sadr.port );
  106. IF port < 0 THEN port := port + 10000H END;
  107. RETURN port
  108. END GetPortNumber;
  109. PROCEDURE BufToSocketAdr( CONST buf: ARRAY OF CHAR; len: LONGINT ): SocketAdr;
  110. VAR adr4: SocketAdrV4; adr6: SocketAdrV6;
  111. BEGIN
  112. IF len = Unix.SockAddrSizeV4 THEN
  113. NEW( adr4 );
  114. S.MOVE( ADDRESSOF( buf ), ADDRESSOF( adr4^), len );
  115. RETURN adr4
  116. ELSE
  117. NEW( adr6 );
  118. S.MOVE( ADDRESSOF( buf ), ADDRESSOF( adr6^), len );
  119. RETURN adr6
  120. END
  121. END BufToSocketAdr;
  122. PROCEDURE Accept*( s: LONGINT ): LONGINT;
  123. VAR len, err: LONGINT; new: LONGINT;
  124. BEGIN
  125. len := 0;
  126. REPEAT
  127. new := accept( s, 0, len );
  128. IF new < 0 THEN err := Unix.errno() END
  129. UNTIL (new > 0) OR (err # Unix.EINTR);
  130. IF new < 0 THEN Unix.Perror( "Sockets.Accept" ) END;
  131. RETURN new
  132. END Accept;
  133. PROCEDURE Bind*( s: LONGINT; addr: SocketAdr): BOOLEAN;
  134. VAR err, len: LONGINT;
  135. BEGIN
  136. IF addr.family = Unix.AFINET THEN len := Unix.SockAddrSizeV4 ELSE len := Unix.SockAddrSizeV6 END;
  137. err:= bind( s, addr, len );
  138. RETURN err = 0
  139. END Bind;
  140. PROCEDURE Close*( s: LONGINT );
  141. VAR err: LONGINT;
  142. BEGIN
  143. shutdown( s, Unix.ShutRDWR );
  144. err := Unix.close( s );
  145. END Close;
  146. PROCEDURE Connect*( s: LONGINT; addr: SocketAdr ): BOOLEAN;
  147. VAR err, len: LONGINT;
  148. BEGIN
  149. IF addr.family = Unix.AFINET THEN len := Unix.SockAddrSizeV4 ELSE len := Unix.SockAddrSizeV6 END;
  150. err:= connect( s, addr, len );
  151. IF err = 0 THEN
  152. RETURN TRUE
  153. ELSE
  154. Unix.Perror( "Sockets.Connect: " );
  155. RETURN FALSE
  156. END;
  157. RETURN err = 0
  158. END Connect;
  159. PROCEDURE GetSockName*( s: LONGINT ): SocketAdr;
  160. VAR len, err: LONGINT; buf: NameBuf;
  161. BEGIN
  162. NEW( buf ); len := 64;
  163. err := getsockname( s, buf, len );
  164. IF err = 0 THEN
  165. RETURN BufToSocketAdr( buf.buf, len )
  166. ELSE
  167. Unix.Perror( "Sockets.GetSockName" );
  168. RETURN NIL
  169. END
  170. END GetSockName;
  171. PROCEDURE GetPeerName*( s: LONGINT ): SocketAdr;
  172. VAR err, len: LONGINT; buf: NameBuf;
  173. BEGIN
  174. NEW( buf ); len := 64;
  175. err:= getpeername( s, buf, len );
  176. IF err = 0 THEN
  177. RETURN BufToSocketAdr( buf.buf, len )
  178. ELSE
  179. Unix.Perror( "Sockets.GetPeerName" );
  180. RETURN NIL
  181. END
  182. END GetPeerName;
  183. PROCEDURE Listen*( s: LONGINT ): BOOLEAN;
  184. VAR err: LONGINT;
  185. BEGIN
  186. err := listen( s, Backlog );
  187. RETURN err = 0
  188. END Listen;
  189. PROCEDURE Recv*( s: LONGINT; VAR buf: ARRAY OF CHAR; pos: LONGINT; VAR len: LONGINT; flags: LONGINT ): BOOLEAN;
  190. VAR res, err: LONGINT;
  191. BEGIN
  192. REPEAT
  193. res := recv( s, ADDRESSOF( buf[pos] ), len, flags );
  194. IF res < 0 THEN err := Unix.errno() END
  195. UNTIL (res >= 0) OR (err # Unix.EINTR);
  196. IF err >= 0 THEN
  197. len:= res; RETURN TRUE
  198. ELSE
  199. Unix.Perror( "Sockets.Recv" );
  200. len:= 0; RETURN FALSE
  201. END
  202. END Recv;
  203. PROCEDURE Send*( s: LONGINT; CONST buf: ARRAY OF CHAR; pos: LONGINT; VAR len: LONGINT ): BOOLEAN;
  204. VAR err: LONGINT;
  205. BEGIN
  206. ASSERT( LEN(buf)-pos >= len );
  207. err := send( s, ADDRESSOF( buf[pos] ), len, 0 );
  208. IF err >= 0 THEN
  209. len := err; RETURN TRUE
  210. ELSE
  211. Unix.Perror( "Sockets.Send" );
  212. len := 0; RETURN FALSE
  213. END
  214. END Send;
  215. PROCEDURE RecvFrom*( s: LONGINT; VAR from: SocketAdr;
  216. VAR buf: ARRAY OF CHAR; pos: LONGINT; VAR len: LONGINT ): BOOLEAN;
  217. VAR res, err, size: LONGINT; nbuf: NameBuf;
  218. BEGIN
  219. NEW( nbuf ); size := 64;
  220. REPEAT
  221. res := recvfrom( s, ADDRESSOF(buf[pos]), LEN( buf ) - pos, 0, nbuf, size );
  222. IF res < 0 THEN err := Unix.errno() END
  223. UNTIL (res >= 0) OR (err # Unix.EINTR);
  224. IF res >= 0 THEN
  225. from := BufToSocketAdr( nbuf.buf, size );
  226. len := res; RETURN TRUE
  227. ELSE
  228. Unix.Perror( "Sockets.RecvFrom" );
  229. len := 0; RETURN FALSE
  230. END
  231. END RecvFrom;
  232. PROCEDURE SendTo*( s: LONGINT; dest: SocketAdr; CONST buf: ARRAY OF CHAR; pos, len: LONGINT ): BOOLEAN;
  233. VAR err, size: LONGINT;
  234. BEGIN
  235. ASSERT( LEN(buf) - pos >= len );
  236. IF dest.family = Unix.AFINET THEN size := Unix.SockAddrSizeV4 ELSE size := Unix.SockAddrSizeV6 END;
  237. err:= sendto( s, ADDRESSOF( buf[pos] ), len, 0, dest, size );
  238. IF err >= 0 THEN
  239. RETURN TRUE
  240. ELSE
  241. Unix.Perror( "Sockets.SendTo" );
  242. RETURN FALSE
  243. END
  244. END SendTo;
  245. PROCEDURE Socket* ( af, typ, protocol: LONGINT ): LONGINT;
  246. VAR s: LONGINT;
  247. BEGIN
  248. s := socket( af, typ, protocol );
  249. RETURN s
  250. END Socket;
  251. PROCEDURE Available*( s: LONGINT ): LONGINT;
  252. VAR available, err: LONGINT;
  253. BEGIN
  254. available := 0;
  255. err := Unix.ioctl( s, Unix.FioNRead, ADDRESSOF( available ) );
  256. IF err = 0 THEN
  257. RETURN available
  258. ELSE
  259. Unix.Perror( "Sockets.Available (ioctl)" );
  260. RETURN -1
  261. END
  262. END Available;
  263. PROCEDURE Requested*( s: LONGINT ): BOOLEAN;
  264. CONST
  265. SLen = Unix.FdSetLen;
  266. SetBits = SIZEOF( SET32 ) * 8;
  267. VAR
  268. res, i: LONGINT;
  269. readfds: Unix.FdSet;
  270. timeout: Unix.Timeval;
  271. BEGIN
  272. timeout.sec := 0; timeout.usec := 0;
  273. FOR i := 0 TO SLen - 1 DO readfds[i] := {} END;
  274. INCL( readfds[s DIV SetBits], s MOD SetBits );
  275. res := Unix.select( s+1, ADDRESSOF( readfds ), 0, 0, timeout );
  276. RETURN res > 0
  277. END Requested;
  278. PROCEDURE AwaitPacket*( s: LONGINT; ms: LONGINT ): BOOLEAN;
  279. CONST
  280. SLen = Unix.FdSetLen;
  281. SetBits = SIZEOF( SET32 ) * 8;
  282. VAR
  283. res, err, i: LONGINT;
  284. readfds: Unix.FdSet;
  285. timeout: Unix.Timeval;
  286. BEGIN
  287. timeout.sec := ms DIV 1000; ms := ms MOD 1000;
  288. timeout.usec := 1000*ms;
  289. FOR i := 0 TO SLen - 1 DO readfds[i] := {} END;
  290. INCL( readfds[s DIV SetBits], s MOD SetBits );
  291. REPEAT
  292. res := Unix.select( s+1, ADDRESSOF( readfds ), 0, 0, timeout );
  293. IF res < 0 THEN err := Unix.errno() END
  294. UNTIL (res >= 0) OR (err # Unix.EINTR);
  295. RETURN res > 0
  296. END AwaitPacket;
  297. PROCEDURE SetLinger* ( s: LONGINT ): BOOLEAN;
  298. VAR
  299. linger: Linger;
  300. err: LONGINT;
  301. BEGIN
  302. linger.onoff := 1; linger.linger := 1;
  303. err := setsockopt( s, Unix.SoLSocket, Unix.SoLinger, linger, SIZE OF Linger);
  304. IF err # 0 THEN Unix.Perror( "Sockets.SetLinger (setsockopt)" ) END;
  305. RETURN err = 0
  306. END SetLinger;
  307. PROCEDURE KeepAlive* ( s: LONGINT; enable: BOOLEAN ): BOOLEAN;
  308. VAR
  309. opt: Switch;
  310. err: LONGINT;
  311. BEGIN
  312. IF enable THEN opt.onoff := 1 ELSE opt.onoff := 0 END;
  313. err := setsockopt( s, Unix.SoLSocket, Unix.SoKeepAlive, opt, SIZE OF Switch );
  314. IF err # 0 THEN Unix.Perror( "Sockets.KeepAlive (setsockopt)" ) END;
  315. RETURN err = 0
  316. END KeepAlive;
  317. PROCEDURE NoDelay* ( s: LONGINT; enable: BOOLEAN ): BOOLEAN;
  318. VAR
  319. opt: Switch;
  320. err: LONGINT;
  321. BEGIN
  322. IF enable THEN opt.onoff := 1 ELSE opt.onoff := 0 END;
  323. err := setsockopt( s, Unix.SoLSocket, Unix.SoNoDelay, opt, SIZE OF Switch );
  324. IF err # 0 THEN Unix.Perror( "Sockets.NoDelay (setsockopt)" ) END;
  325. RETURN err = 0
  326. END NoDelay;
  327. PROCEDURE NetToInt* (x: INTEGER): INTEGER;
  328. BEGIN
  329. RETURN SHORT(ntohs(LONG(x)))
  330. END NetToInt;
  331. PROCEDURE IntToNet* (x: INTEGER): INTEGER;
  332. BEGIN
  333. RETURN SHORT(htons(LONG(x)))
  334. END IntToNet;
  335. PROCEDURE NetToLInt* (x: LONGINT): LONGINT;
  336. BEGIN
  337. RETURN ntohl(x)
  338. END NetToLInt;
  339. PROCEDURE LIntToNet* (x: LONGINT): LONGINT;
  340. BEGIN
  341. RETURN htonl(x)
  342. END LIntToNet;
  343. PROCEDURE Init;
  344. VAR slib: ADDRESS;
  345. BEGIN
  346. IF Unix.Version = "Solaris" THEN
  347. slib := Unix.Dlopen( "libsocket.so.1", 2 );
  348. IF slib = 0 THEN slib := Unix.Dlopen( "libsocket.so", 2 ) END;
  349. IF slib = 0 THEN Trace.StringLn( "Unix.Dlopen( 'libsocket.so' ) failed") END;
  350. ELSE
  351. slib := Unix.libc
  352. END;
  353. Unix.Dlsym( slib, "accept", ADDRESSOF( accept ) );
  354. Unix.Dlsym( slib, "bind", ADDRESSOF( bind ) );
  355. Unix.Dlsym( slib, "connect", ADDRESSOF( connect ) );
  356. Unix.Dlsym( slib, "shutdown", ADDRESSOF( shutdown ) );
  357. Unix.Dlsym( slib, "getpeername", ADDRESSOF( getpeername ) );
  358. Unix.Dlsym( slib, "htonl", ADDRESSOF( htonl ) );
  359. Unix.Dlsym( slib, "htons", ADDRESSOF( htons ) );
  360. Unix.Dlsym( slib, "listen", ADDRESSOF( listen ) );
  361. Unix.Dlsym( slib, "ntohl", ADDRESSOF( ntohl ) );
  362. Unix.Dlsym( slib, "ntohs", ADDRESSOF( ntohs ) );
  363. Unix.Dlsym( slib, "recv", ADDRESSOF( recv ) );
  364. Unix.Dlsym( slib, "recvfrom", ADDRESSOF( recvfrom ) );
  365. Unix.Dlsym( slib, "send", ADDRESSOF( send ) );
  366. Unix.Dlsym( slib, "sendto", ADDRESSOF( sendto ) );
  367. Unix.Dlsym( slib, "setsockopt", ADDRESSOF( setsockopt ) );
  368. Unix.Dlsym( slib, "socket", ADDRESSOF( socket ) );
  369. Unix.Dlsym( slib, "getsockname", ADDRESSOF( getsockname ) );
  370. END Init;
  371. BEGIN
  372. Init
  373. END Sockets.