Unix.Sockets.Mod 12 KB

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