PageRenderTime 48ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/brl/socket.monkey

https://github.com/Sonickidnextgen/monkey_ambiguityfix_80a
Unknown | 590 lines | 449 code | 141 blank | 0 comment | 0 complexity | d8d18ea224a6d4a7f5a7fd11d6bc790b MD5 | raw file
Possible License(s): GPL-3.0
  1. Import brl.databuffer
  2. Import brl.asyncevent
  3. #If Not BRL_SOCKET_IMPLEMENTED
  4. #If LANG="cpp" Or LANG="java"
  5. #BRL_SOCKET_IMPLEMENTED=True
  6. Import "native/socket.${LANG}"
  7. #If LANG="cpp"
  8. Import "native/socket_winrt.cpp"
  9. #Endif
  10. #Endif
  11. #If Not BRL_SOCKET_IMPLEMENTED
  12. #Error "Native Socket class not implemented."
  13. #Endif
  14. Private
  15. Import brl.thread
  16. Extern Private
  17. Class BBSocketAddress
  18. Method Set:Void( host:String,port:Int )
  19. Method Set:Void( address:BBSocketAddress )
  20. Method Host:String()
  21. Method Port:Int()
  22. End
  23. Class BBSocket
  24. Method Open:Bool( protocol:Int )
  25. Method Close:Void()
  26. Method Bind:Bool( host:String,port:Int )
  27. Method Connect:Bool( host:String,port:Int )
  28. Method Listen:Bool( backlog:Int )
  29. Method Accept:Bool()
  30. Method Accepted:BBSocket()
  31. Method Send:Int( buf:BBDataBuffer,offset:Int,count:Int )
  32. Method Receive:Int( buf:BBDataBuffer,offset:Int,count:Int )
  33. Method SendTo:Int( buf:BBDataBuffer,offset:Int,count:Int,address:BBSocketAddress )
  34. Method ReceiveFrom:Int( buf:BBDataBuffer,offset:Int,count:Int,address:BBSocketAddress )
  35. Method GetLocalAddress:Void( address:BBSocketAddress )
  36. Method GetRemoteAddress:Void( address:BBSocketAddress )
  37. End
  38. Private
  39. Class AsyncOp
  40. 'Careful...called by background thread
  41. Method Execute__UNSAFE__:Void( source:Socket ) Abstract
  42. 'Relax...called by main thread
  43. Method Complete:Void( source:Socket ) Abstract
  44. End
  45. Class AsyncQueue Extends Thread Implements IAsyncEventSource
  46. Method New( source:Socket )
  47. Self.source=source
  48. End
  49. Method IsBusy:Bool() Property
  50. Return get<>put
  51. End
  52. Method Enqueue:Void( op:AsyncOp )
  53. queue[put]=op
  54. put=(put+1) Mod QUEUE_SIZE
  55. If put=get Error "AsyncQueue queue overflow!"
  56. Start 'NOP if already running. Race condition alert! This will fail if thread is in the process of exiting!
  57. End
  58. Method UpdateAsyncEvents:Void()
  59. If nxt<>put
  60. If Not IsRunning() Print "RACE!"
  61. Start 'NOP if already running. This is a kludge for the above race condition...
  62. Endif
  63. While get<>nxt
  64. Local op:=queue[get]
  65. get=(get+1) Mod QUEUE_SIZE
  66. op.Complete source
  67. Wend
  68. End
  69. Private
  70. Method Run__UNSAFE__:Void()
  71. While nxt<>put
  72. queue[nxt].Execute__UNSAFE__ source
  73. nxt=(nxt+1) Mod QUEUE_SIZE
  74. Wend
  75. End
  76. Private
  77. Const QUEUE_SIZE:=256 'how many ops can be queued. Overflow this and yer hosed.
  78. Const QUEUE_MASK:=QUEUE_SIZE-1
  79. Field source:Socket
  80. Field queue:AsyncOp[QUEUE_SIZE]
  81. Field put:Int 'only written by Enqueue
  82. Field get:Int 'only written by Update
  83. Field nxt:Int 'only written by thread
  84. End
  85. Class AsyncConnectOp Extends AsyncOp
  86. Method New( socket:BBSocket,host:String,port:Int,onComplete:IOnConnectComplete )
  87. _socket=socket
  88. _host=host
  89. _port=port
  90. _onComplete=onComplete
  91. End
  92. Private
  93. Field _socket:BBSocket
  94. Field _host:String
  95. Field _port:Int
  96. Field _onComplete:IOnConnectComplete
  97. Field _result:Bool
  98. Method Execute__UNSAFE__:Void( source:Socket )
  99. _result=_socket.Connect( Thread.Strdup(_host),_port )
  100. End
  101. Method Complete:Void( source:Socket )
  102. If _result Socket( source ).OnConnectComplete()
  103. _onComplete.OnConnectComplete( _result,source )
  104. End
  105. End
  106. Class AsyncBindOp Extends AsyncOp
  107. Method New( socket:BBSocket,host:String,port:Int,onComplete:IOnBindComplete )
  108. _socket=socket
  109. _host=host
  110. _port=port
  111. _onComplete=onComplete
  112. End
  113. Private
  114. Field _socket:BBSocket
  115. Field _host:String
  116. Field _port:Int
  117. Field _onComplete:IOnBindComplete
  118. Field _result:Bool
  119. Method Execute__UNSAFE__:Void( source:Socket )
  120. _result=_socket.Bind( Thread.Strdup(_host),_port )
  121. End
  122. Method Complete:Void( source:Socket )
  123. If _result Socket( source ).OnBindComplete()
  124. _onComplete.OnBindComplete( _result,source )
  125. End
  126. End
  127. Class AsyncAcceptOp Extends AsyncOp
  128. Method New( socket:BBSocket,onComplete:IOnAcceptComplete )
  129. _socket=socket
  130. _onComplete=onComplete
  131. End
  132. Private
  133. Field _socket:BBSocket
  134. Field _onComplete:IOnAcceptComplete
  135. Field _result:Bool
  136. Method Execute__UNSAFE__:Void( source:Socket )
  137. _result=_socket.Accept()
  138. End
  139. Method Complete:Void( source:Socket )
  140. Local sock:Socket
  141. If _result sock=Socket( source ).OnAcceptComplete()
  142. _onComplete.OnAcceptComplete( sock,source )
  143. End
  144. End
  145. Class AsyncSocketIoOp Extends AsyncOp
  146. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int )
  147. _socket=socket
  148. _data=data
  149. _offset=offset
  150. _count=count
  151. End
  152. Private
  153. Field _socket:BBSocket
  154. Field _data:DataBuffer
  155. Field _offset:Int
  156. Field _count:Int
  157. End
  158. Class AsyncSendOp Extends AsyncSocketIoOp
  159. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int,onComplete:IOnSendComplete )
  160. Super.New( socket,data,offset,count )
  161. _onComplete=onComplete
  162. End
  163. Private
  164. Field _onComplete:IOnSendComplete
  165. Method Execute__UNSAFE__:Void( source:Socket )
  166. _count=_socket.Send( _data,_offset,_count )
  167. End
  168. Method Complete:Void( source:Socket )
  169. _onComplete.OnSendComplete( _data,_offset,_count,source )
  170. End
  171. End
  172. Class AsyncSendToOp Extends AsyncSocketIoOp
  173. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int,address:SocketAddress,onComplete:IOnSendToComplete )
  174. Super.New( socket,data,offset,count )
  175. _address=address
  176. _onComplete=onComplete
  177. End
  178. Private
  179. Field _address:SocketAddress
  180. Field _onComplete:IOnSendToComplete
  181. Method Execute__UNSAFE__:Void( source:Socket )
  182. _count=_socket.SendTo( _data,_offset,_count,_address )
  183. End
  184. Method Complete:Void( source:Socket )
  185. _onComplete.OnSendToComplete( _data,_offset,_count,_address,source )
  186. End
  187. End
  188. Class AsyncReceiveOp Extends AsyncSocketIoOp
  189. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int,onComplete:IOnReceiveComplete )
  190. Super.New( socket,data,offset,count )
  191. _onComplete=onComplete
  192. End
  193. Private
  194. Field _onComplete:IOnReceiveComplete
  195. Method Execute__UNSAFE__:Void( source:Socket )
  196. _count=_socket.Receive( _data,_offset,_count )
  197. End
  198. Method Complete:Void( source:Socket )
  199. _onComplete.OnReceiveComplete( _data,_offset,_count,source )
  200. End
  201. End
  202. Class AsyncReceiveAllOp Extends AsyncSocketIoOp
  203. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int,onComplete:IOnReceiveComplete )
  204. Super.New( socket,data,offset,count )
  205. _onComplete=onComplete
  206. End
  207. Private
  208. Field _onComplete:IOnReceiveComplete
  209. Method Execute__UNSAFE__:Void( source:Socket )
  210. Local i:=0
  211. While i<_count
  212. Local n:=_socket.Receive( _data,_offset+i,_count-i )
  213. If n>0 i+=n Else Exit
  214. Wend
  215. _count=i
  216. End
  217. Method Complete:Void( source:Socket )
  218. _onComplete.OnReceiveComplete( _data,_offset,_count,source )
  219. End
  220. End
  221. Class AsyncReceiveFromOp Extends AsyncSocketIoOp
  222. Method New( socket:BBSocket,data:DataBuffer,offset:Int,count:Int,address:SocketAddress,onComplete:IOnReceiveFromComplete )
  223. Super.New( socket,data,offset,count )
  224. _address=address
  225. _onComplete=onComplete
  226. End
  227. Private
  228. Field _address:SocketAddress
  229. Field _onComplete:IOnReceiveFromComplete
  230. Method Execute__UNSAFE__:Void( source:Socket )
  231. _count=_socket.ReceiveFrom( _data,_offset,_count,_address )
  232. End
  233. Method Complete:Void( source:Socket )
  234. _onComplete.OnReceiveFromComplete( _data,_offset,_count,_address,source )
  235. End
  236. End
  237. Public
  238. Interface IOnConnectComplete
  239. Method OnConnectComplete:Void( connected:Bool,source:Socket )
  240. End
  241. Interface IOnBindComplete
  242. Method OnBindComplete:Void( bound:Bool,source:Socket )
  243. End
  244. Interface IOnAcceptComplete
  245. Method OnAcceptComplete:Void( socket:Socket,source:Socket )
  246. End
  247. Interface IOnSendComplete
  248. Method OnSendComplete:Void( data:DataBuffer,offset:Int,count:Int,source:Socket )
  249. End
  250. Interface IOnSendToComplete
  251. Method OnSendToComplete:Void( data:DataBuffer,offset:Int,count:Int,address:SocketAddress,source:Socket )
  252. End
  253. Interface IOnReceiveComplete
  254. Method OnReceiveComplete:Void( data:DataBuffer,offset:Int,count:Int,source:Socket )
  255. End
  256. Interface IOnReceiveFromComplete
  257. Method OnReceiveFromComplete:Void( data:DataBuffer,offset:Int,count:Int,address:SocketAddress,source:Socket )
  258. End
  259. Class SocketAddress Extends BBSocketAddress
  260. Method New()
  261. End
  262. Method New( host:String,port:Int )
  263. Set( host,port )
  264. End
  265. Method New( address:SocketAddress )
  266. Set( address )
  267. End
  268. Method Host:String() Property
  269. Return Super.Host()
  270. End
  271. Method Port:Int() Property
  272. Return Super.Port()
  273. End
  274. Method ToString:String() Property
  275. Return Host+":"+Port
  276. End
  277. End
  278. Class Socket Implements IAsyncEventSource
  279. Method New( protocol:String="stream" )
  280. Local proto:Int
  281. Select protocol
  282. Case "stream" proto=STREAM
  283. Case "server" proto=SERVER
  284. Case "datagram" proto=DATAGRAM
  285. Default Error "Illegal socket protocol"
  286. End
  287. _sock=New BBSocket
  288. If Not _sock.Open( proto ) Error "Socket open failed"
  289. _proto=proto
  290. _state=OPEN
  291. Start()
  292. End
  293. Method Close:Void()
  294. _sock.Close()
  295. _state=0
  296. End
  297. Method Bind:Bool( host:String,port:Int )
  298. If Not IsOpen Or IsBound Return False
  299. If Not _sock.Bind( host,port ) Return False
  300. OnBindComplete()
  301. Return True
  302. End
  303. Method BindAsync:Void( host:String,port:Int,onComplete:IOnBindComplete )
  304. If Not IsOpen Or IsBound Return
  305. _rthread.Enqueue New AsyncBindOp( _sock,host,port,onComplete )
  306. End
  307. Method Connect:Bool( host:String,port:Int )
  308. If Not IsOpen Or IsConnected Or IsListening Return False
  309. If Not _sock.Connect( host,port ) Return False
  310. OnConnectComplete()
  311. Return True
  312. End
  313. Method ConnectAsync:Void( host:String,port:Int,onComplete:IOnConnectComplete )
  314. If Not IsOpen Or IsConnected Or IsListening Return
  315. _rthread.Enqueue New AsyncConnectOp( _sock,host,port,onComplete )
  316. End
  317. Method Accept:Socket()
  318. If Not IsListening And (Not IsOpen Or _proto<>SERVER Or Not Bind( "",0 )) Return Null
  319. If Not _sock.Accept() Return Null
  320. Return OnAcceptComplete()
  321. End
  322. Method AcceptAsync:Void( onComplete:IOnAcceptComplete )
  323. If Not IsListening Return
  324. _rthread.Enqueue New AsyncAcceptOp( _sock,onComplete )
  325. End
  326. Method Send:Int( buf:DataBuffer,offset:Int,count:Int )
  327. If Not IsConnected Return 0
  328. Local n:=_sock.Send( buf,offset,count )
  329. If n>=0 Return n
  330. Return 0
  331. End
  332. Method SendAsync:Void( buf:DataBuffer,offset:Int,count:Int,onComplete:IOnSendComplete )
  333. If Not IsConnected Return
  334. _wthread.Enqueue New AsyncSendOp( _sock,buf,offset,count,onComplete )
  335. End
  336. Method SendTo:Int( buf:DataBuffer,offset:Int,count:Int,address:SocketAddress )
  337. Local n:=_sock.SendTo( buf,offset,count,address )
  338. If n>=0 Return n
  339. Return 0
  340. End
  341. Method SendToAsync:Int( buf:DataBuffer,offset:Int,count:Int,address:SocketAddress,onComplete:IOnSendToComplete )
  342. If _proto<>DATAGRAM Or IsConnected Return
  343. _wthread.Enqueue New AsyncSendToOp( _sock,buf,offset,count,address,onComplete )
  344. End
  345. Method Receive:Int( buf:DataBuffer,offset:Int,count:Int )
  346. If Not IsConnected Return 0
  347. Local n:=_sock.Receive( buf,offset,count )
  348. If n>=0 Return n
  349. Return 0
  350. End
  351. Method ReceiveAsync:Void( buf:DataBuffer,offset:Int,count:Int,onComplete:IOnReceiveComplete )
  352. If Not IsConnected Return
  353. _rthread.Enqueue New AsyncReceiveOp( _sock,buf,offset,count,onComplete )
  354. End
  355. Method ReceiveAll:Int( buf:DataBuffer,offset:Int,count:Int )
  356. If Not IsConnected Return 0
  357. Local i:=0
  358. While i<count
  359. Local n:=_sock.Receive( buf,offset+i,count-i )
  360. If n>0 i+=n Else Exit
  361. Wend
  362. Return i
  363. End
  364. Method ReceiveAllAsync:Void( buf:DataBuffer,offset:Int,count:Int,onComplete:IOnReceiveComplete )
  365. If Not IsConnected Return
  366. _rthread.Enqueue New AsyncReceiveAllOp( _sock,buf,offset,count,onComplete )
  367. End
  368. Method ReceiveFrom:Int( buf:DataBuffer,offset:Int,count:Int,address:SocketAddress )
  369. If _proto<>DATAGRAM Or IsConnected Return 0
  370. Local n:=_sock.ReceiveFrom( buf,offset,count,address )
  371. If n>=0 Return n
  372. Return 0
  373. End
  374. Method ReceiveFromAsync:Int( buf:DataBuffer,offset:Int,count:Int,address:SocketAddress,onComplete:IOnReceiveFromComplete )
  375. If _proto<>DATAGRAM Or IsConnected Return
  376. _rthread.Enqueue New AsyncReceiveFromOp( _sock,buf,offset,count,address,onComplete )
  377. End
  378. Method IsOpen:Bool() Property
  379. Return (_state & OPEN)<>0
  380. End
  381. Method IsBound:Bool() Property
  382. Return (_state & BOUND)<>0
  383. End
  384. Method IsConnected:Bool() Property
  385. Return (_state & CONNECTED)<>0
  386. End
  387. Method IsListening:Bool() Property
  388. Return (_state & LISTENING)<>0
  389. End
  390. Method Protocol:String() Property
  391. Select _proto
  392. Case STREAM Return "stream"
  393. Case SERVER Return "server"
  394. Case DATAGRAM Return "datagram"
  395. End
  396. Return "?"
  397. End
  398. Method LocalAddress:SocketAddress() Property
  399. _sock.GetLocalAddress( _localAddress )
  400. Return _localAddress
  401. End
  402. Method RemoteAddress:SocketAddress() Property
  403. _sock.GetRemoteAddress( _remoteAddress )
  404. Return _remoteAddress
  405. End
  406. Private
  407. Const STREAM:=1
  408. Const SERVER:=2
  409. Const DATAGRAM:=3
  410. Const OPEN:=1
  411. Const BOUND:=2
  412. Const CONNECTED:=4
  413. Const LISTENING:=8
  414. Field _sock:BBSocket
  415. Field _proto:Int
  416. Field _state:Int
  417. Field _rthread:AsyncQueue
  418. Field _wthread:AsyncQueue
  419. Field _localAddress:=New SocketAddress
  420. Field _remoteAddress:=New SocketAddress
  421. Method New( sock:BBSocket,proto:Int,state:Int )
  422. _sock=sock
  423. _proto=proto
  424. _state=state
  425. Start()
  426. End
  427. Method Start:Void()
  428. _rthread=New AsyncQueue( Self )
  429. _wthread=New AsyncQueue( Self )
  430. AddAsyncEventSource Self
  431. End
  432. Method UpdateAsyncEvents:Void()
  433. If _rthread _rthread.UpdateAsyncEvents
  434. If _wthread _wthread.UpdateAsyncEvents
  435. End
  436. Method OnConnectComplete:Void()
  437. _state|=Socket.CONNECTED|Socket.BOUND
  438. End
  439. Method OnBindComplete:Void()
  440. _state|=BOUND
  441. If _proto=SERVER
  442. _sock.Listen( 1 )
  443. _state|=LISTENING
  444. Endif
  445. End
  446. Method OnAcceptComplete:Socket()
  447. Return New Socket( _sock.Accepted(),Socket.STREAM,Socket.OPEN|Socket.BOUND|Socket.CONNECTED )
  448. End
  449. End