PageRenderTime 62ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/Library/System/Socket/experimental/socket.sa

https://bitbucket.org/starware/sather
Unknown | 652 lines | 419 code | 233 blank | 0 comment | 0 complexity | 097683458767abb1d26628152b807c0f MD5 | raw file
Possible License(s): GPL-3.0, LGPL-3.0
  1. class SOCKET is
  2. -- This class implements bidirectional communication of strings between
  3. -- processes (intra- or inter-machine) using sockets. Both reads and writes
  4. -- may block waiting for the other process to rendezvous.
  5. -- There are four versions of socket creation - initiating and
  6. -- connecting sockets for either a local machine socket or for an Internet
  7. -- one! Dead sockets may be returned if the name or port arguments are
  8. -- already in use (when initiating) or if no matching initiator was found
  9. -- within num_connect_attempts seconds (when attempting to connect) or if
  10. -- an invalid hostname is given (when attempting to connect) or in anomalous
  11. -- circumstances (in which case a message appears on stderr).
  12. -- NOTE This version is an interim fix until integrated into the new Network
  13. -- library.!!!!!
  14. -- Version 1.5 May 99. Copyright K Hopper, U of Waikato
  15. -- Development History
  16. -- -------------------
  17. -- Date Who By Detail
  18. -- ---- ------ ------
  19. -- 8 Jan 93 db Original for Sather 0.2
  20. -- 14 Apr 95 db Revised for 1.0
  21. -- 12 Dec 95 db Revised for 1.0.9
  22. -- 4 Jun 96 db Revised for 1.1
  23. -- 14 May 99 mdb Now communicates with non-Sather sockets!
  24. -- 16 May 99 kh Interim re-write
  25. private const Packet_Size : INT := 1518 ; -- Ethernet max!
  26. private attr id : INT ; -- Unix descriptor for socket.
  27. private attr is_dead_var : BOOL ; -- Indicates if socket operational
  28. private attr use_exceptions_var : BOOL ;
  29. -- This indicates whether an exception is to be raised when failure
  30. -- occurs.
  31. shared num_connect_attempts : INT := 10 ;
  32. -- Connecting sockets will look once per second for a matching initiator
  33. -- this many times before failing.
  34. shared unix_socket_directory : STR := "/tmp/" ;
  35. -- This is the name of the directory where unix-domain server sockets are
  36. -- to be created.
  37. min_port_num : INT is
  38. -- This routine returns the minimum port number established by the
  39. -- underlying socket interface.
  40. return C_SOCKET::min_port_num
  41. end ;
  42. reasonable_filename(
  43. name : STR
  44. ) : BOOL is
  45. -- This routine is provided to test whether the given name is a
  46. -- reasonable unix-style file name. [This will disappear when the new
  47. -- required library is adopted.]
  48. loop
  49. loc_ch : CHAR := name.elt! ;
  50. if ~loc_ch.is_alphanum
  51. and loc_ch /= '-'
  52. and loc_ch /= '_'
  53. and loc_ch /= '.' then
  54. return false
  55. end
  56. end ;
  57. return true
  58. end ;
  59. create_initiating_unix(
  60. name : STR
  61. ) : SAME
  62. pre void(self)
  63. post result.is_dead_var
  64. or (result.id /= 0)
  65. is
  66. -- This routine attempts to initiate a new socket with the given name.
  67. -- It then blocks until another process creates a connecting socket with the
  68. -- same name on the same machine. The name argument must be a legal Unix
  69. -- filename. If an error occurs then a dead socket is returned.
  70. res : SAME := new ;
  71. if ~reasonable_filename(name) then
  72. res.is_dead_var := true ;
  73. return res
  74. end ;
  75. res.id := C_SOCKET::make_initiating_socket_unix(
  76. unix_socket_directory + name) ;
  77. if res.id < INT::zero then -- creation failed!
  78. res.is_dead_var := true
  79. end ;
  80. C_SOCKET::ignore_broken_pipe_signals ; -- tell the OS!
  81. return res
  82. end ;
  83. create_connecting_unix(
  84. name : STR
  85. ) : SAME
  86. pre void(self)
  87. post result.is_dead_var
  88. or (result.id /= 0)
  89. is
  90. -- This routine attempts to connect to an existing unix-domain socket
  91. -- with the given name. Attempts will be made once per second up to
  92. -- num_connect_attempts seconds. The name argument must be a legal unix
  93. -- filename. If an error occurs then the socket returned is dead!
  94. res : SAME := new ;
  95. if ~reasonable_filename(name) then
  96. res.is_dead_var := true ;
  97. return res
  98. end ;
  99. res.id := C_SOCKET::make_connecting_socket_unix(
  100. unix_socket_directory + name) ;
  101. if res.id < INT::zero then -- failed!
  102. res.is_dead_var := true
  103. end ;
  104. C_SOCKET::ignore_broken_pipe_signals ; -- tell OS - ????????
  105. return res
  106. end ;
  107. create_initiating_inet(
  108. port : INT
  109. ) : SAME
  110. pre void(self)
  111. and (port >= min_port_num)
  112. post result.is_dead_var
  113. or (result.id /= 0)
  114. is
  115. -- This routine initiates a local Internet socket on the given port, then
  116. -- blocks until another process does a 'create_connecting_inet' to this port.
  117. -- If an error occurs then a dead socket is returned.
  118. res : SAME := new ;
  119. res.id := C_SOCKET::make_initiating_socket_inet(port) ;
  120. if res.id < INT::zero then
  121. res.is_dead_var := true
  122. end ;
  123. C_SOCKET::ignore_broken_pipe_signals ; -- needed even in inet case ?????
  124. return res
  125. end ;
  126. create_connecting_inet(
  127. host : STR,
  128. port : INT
  129. ) : SAME
  130. pre void(self)
  131. and (port >= min_port_num)
  132. post result.is_dead_var
  133. or (result.id /= 0)
  134. is
  135. -- This routine attempts to connect to an existing Internet socket on
  136. -- the given port of the named host. Attempts will be made once per second
  137. -- for num_connect_attempts seconds. If an error occurs then a dead socket
  138. -- is returned.
  139. res : SAME := new ;
  140. res.id := C_SOCKET::make_connecting_socket_inet(host,port) ;
  141. if res.id < INT::zero then
  142. res.is_dead_var := true
  143. end ;
  144. C_SOCKET::ignore_broken_pipe_signals ; -- needed even in inet case ?????
  145. return res
  146. end ;
  147. close
  148. pre ~void(self)
  149. and (id /= 0)
  150. post is_dead_var
  151. is
  152. -- Thsi routine closes the socket and marks it dead.
  153. C_SOCKET::close_socket(id) ;
  154. is_dead_var := true
  155. end ;
  156. use_exceptions(
  157. val : BOOL
  158. )
  159. pre ~void(self)
  160. and ~is_dead_var
  161. post (use_exceptions_var = val)
  162. is
  163. -- This routine provides the facility to turn on the raising of an
  164. -- exception when I/O failure occurs if the argument is true, turning it off
  165. -- if the argument is false. The circumstances under which an exception will
  166. -- be raised are :-
  167. --
  168. -- (1) the socket dies due to external factors (usually termination of
  169. -- the peer socket's process) in the course of any operation other than
  170. -- an explicit `is_dead' check.
  171. --
  172. -- (2) a caller attempts to read or write using an already closed or
  173. -- dead socket. Note that in any case, `is_dead' will be set when a
  174. -- socket dies or is closed.
  175. --
  176. -- If exceptions are turned on when the socket is already dead, an exception
  177. -- is raised.
  178. use_exceptions_var := val
  179. end ;
  180. is_using_exceptions : BOOL is
  181. -- This predicate returns true if and only if this socket is using
  182. -- exception raising in the event of an error occurring.
  183. return use_exceptions_var
  184. end ;
  185. is_dead : BOOL is
  186. -- This predicate returns true if and only if this socket is alive and
  187. -- able to communicate with its peer.
  188. -- NOTE The routine is_healthy should catch all cases where the socket is
  189. -- effectively dead but has not yet failed.
  190. if ~is_dead_var
  191. and (C_SOCKET::is_healthy(id) = 0) then
  192. close
  193. end ;
  194. return is_dead_var
  195. end ;
  196. can_read_without_block : BOOL
  197. pre ~void(self)
  198. post true
  199. is
  200. -- This predicate returns true if and only if the socket is alive and
  201. -- data is available such that get_str will not block.
  202. return ~is_dead_var
  203. and (C_SOCKET::able_to_read(id) /= 0)
  204. end ;
  205. can_write_without_block : BOOL
  206. pre ~void(self)
  207. post true
  208. is
  209. -- This predicate returns true if and only if the socket is alive and
  210. -- writing will not block due to full buffers.
  211. return ~is_dead_var
  212. and (C_SOCKET::able_to_write(id) /= 0)
  213. end ;
  214. private die(
  215. msg : STR
  216. ) is
  217. -- This private routine closes the socket (thereby marking it dead) and
  218. -- raises an exception if use_exceptions_var is true.
  219. close ;
  220. if use_exceptions_var then
  221. raise SOCKET_EXCEPTION::create(msg)
  222. end
  223. end ;
  224. get_str : STR
  225. pre ~void(self)
  226. and ~is_dead_var
  227. post true
  228. is
  229. -- This routine returns the next text string from the peer socket. If
  230. -- an empty string is returned then the sender may have sent a void string.
  231. -- If no string is available this routine will block until one is received.
  232. -- Should the socket die during communication then void is returned
  233. res : STR ;
  234. buff : STR ;
  235. count : INT := Packet_Size ;
  236. length : INT := INT::zero ;
  237. loop
  238. while!(count = Packet_Size) ;
  239. buff := "X".repeat(Packet_Size) ;
  240. count := C_SOCKET::receive_str(id,buff,Packet_Size) ;
  241. if count = -1 then -- an error has occurred!
  242. die("Socket died while sending string") ;
  243. return void
  244. elsif count > 0 then
  245. length := length + count ;
  246. res := res.plus(buff.head(count))
  247. end
  248. end ;
  249. if length = INT::zero then -- so create a void one!
  250. res := STR::create
  251. end ;
  252. return res
  253. end ;
  254. plus(
  255. str : $STR
  256. )
  257. pre ~void(self)
  258. and ~is_dead_var
  259. and ~void(str)
  260. post true
  261. is
  262. -- This routine appends str to the socket connected to self. If the
  263. -- buffer is full then this routine will block until the receiving process
  264. -- retrieves the string. If an error occurs then the socket dies!
  265. str_to_send : STR := str.str ;
  266. if (C_SOCKET::is_healthy(id) = INT::zero) then -- already dead!
  267. die("Socket found dead when preparing to send string") ;
  268. return
  269. end ;
  270. status : INT := C_SOCKET::send_str(id,str_to_send,str_to_send.size) ;
  271. if status = 0 then
  272. die("Socket died while sending string")
  273. end
  274. end ;
  275. plus(
  276. str : $STR
  277. ) : SAME
  278. pre ~void(self)
  279. and ~is_dead_var
  280. and ~void(str)
  281. post true
  282. is
  283. -- This routine appends the string to the socket and then returns self.
  284. plus(str) ;
  285. return self
  286. end ;
  287. block_until_can_read
  288. pre ~void(self)
  289. and ~is_dead_var
  290. post can_read_without_block
  291. is
  292. -- This routine blocks in a non-busy wait until this socket can be read.
  293. C_SOCKET::block_until_can_read(id)
  294. end ;
  295. block_until_can_write
  296. pre ~void(self)
  297. and ~is_dead_var
  298. post can_write_without_block
  299. is
  300. -- This routine blocks in a non-busy wait until the socket can be
  301. -- written to without blocking.
  302. C_SOCKET::block_until_can_write(id)
  303. end ;
  304. end ; -- SOCKET
  305. ------------------------------------------------------------------------------
  306. class SOCKET_EXCEPTION is -- < $STR is
  307. -- This class implements an oboslescent exceptiin facility for use by
  308. -- the SOCKET class pending incorporation into the new Network library.
  309. -- Version 1.1 May 99. Copyright K Hopper, U of Waikato
  310. -- Development History
  311. -- -------------------
  312. -- Date Who By Detail
  313. -- ---- ------ ------
  314. -- 8 Jan 93 db Original for Sather 0.2
  315. -- 16 May 99 kh Revised style for interim use.
  316. private attr msg : STR ;
  317. create(
  318. str : STR
  319. ) : SAME is
  320. -- This routine returns a new object with the associated message.
  321. res : SAME := new ;
  322. res.msg := str ;
  323. return res
  324. end ;
  325. str : STR is
  326. -- This routine returns a string message indicating the error.
  327. return "SOCKET_EXCEPTION: " + msg
  328. end ;
  329. end ; -- SOCKET_EXCEPTION
  330. ------------------------------------------------------------------------------
  331. external C class C_SOCKET is
  332. -- This class defines the interface between the Sather socket class and
  333. -- the run-time support facility. This is for interim use pending the issue
  334. -- of the new Network library.
  335. -- Version 1.1 May 99. Copyright K Hopper, U of Waikato
  336. -- Development History
  337. -- -------------------
  338. -- Date Who By Detail
  339. -- ---- ------ ------
  340. -- 8 Jan 93 db Original for Sather 0.2
  341. -- 16 May 99 kh Revised for interim use.
  342. min_port_num : INT ;
  343. -- This routine returns the number which indicates the minimum port
  344. -- number which may be opened on the current machine.
  345. ignore_broken_pipe_signals ;
  346. -- This routine requests the operating system socket mechanism to ignore
  347. -- any broken pipe signals in respect of this process/thread.
  348. make_initiating_socket_unix(
  349. name : STR
  350. ) : INT ;
  351. -- This routine creates an initiating local unix socket. It returns the
  352. -- handle to the socket (or -1 if an error has occurred).
  353. make_connecting_socket_unix(
  354. name : STR
  355. ) : INT ;
  356. -- This routine creates a connecting local unix socket. It returns the
  357. -- handle to the socket (or -1 if an error has occurred).
  358. make_initiating_socket_inet(
  359. port : INT
  360. ) : INT ;
  361. -- This routine creates an initiating local internet socket. It returns
  362. -- the handle to the socket (or -1 if an error has occurred).
  363. make_connecting_socket_inet(
  364. server_name : STR,
  365. server_port : INT
  366. ) : INT ;
  367. -- This routine creates a connecting remote unix socket on the given
  368. -- port on the indicated network server/host. It returns the handle to the
  369. -- socket (or -1 if an error has occurred).
  370. close_socket(
  371. socket_handle : INT
  372. ) ;
  373. -- This routine closes the external socket to which self is attached.
  374. receive_str(
  375. socket_handle : INT,
  376. str : STR,
  377. length : INT
  378. ) : INT ;
  379. -- This routine attempts to read a string from the indicated socket into
  380. -- the given buffer up to size length, returning either the length actually
  381. -- read or -1 if an error has occurred.
  382. send_str(
  383. socket_handle : INT,
  384. str : STR,
  385. length : INT
  386. ) : INT ;
  387. -- This routine appends the given string (of the given length) to the
  388. -- indicated socket attached to self.
  389. able_to_read(
  390. socket_handle : INT
  391. ) : INT ;
  392. -- This predicate returns 1 if the socket indicated may be read without
  393. -- blocking, otherwise zero.
  394. able_to_write(
  395. socket_handle : INT
  396. ) : INT ;
  397. -- This predicate returns 1 if the socket indicated may be written to
  398. -- without blocking, otherwise zero.
  399. is_healthy(
  400. socket_handle : INT
  401. ) : INT ;
  402. -- This routine returns 1 if and only if the socket indicated is not
  403. -- dead.
  404. block_until_can_read(
  405. socket_handle : INT
  406. ) ;
  407. -- This routine makes the calling thread wait (in a non-busy manner)
  408. -- until the indicated socket can be read.
  409. block_until_can_write(
  410. socket_handle : INT
  411. ) ;
  412. -- This routine makes the calling thread wait (in a non-busy manner)
  413. -- until the indicated socket can be written to.
  414. nconnatt : INT is
  415. -- This interface routine is a 'call-back' from the OS socket mechanism
  416. -- to find out the number of connection attempts to make!
  417. return SOCKET::num_connect_attempts
  418. end ;
  419. end ; -- C_SOCKET