socket.monkey2 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. Namespace std.socket
  2. #If __TARGET__="windows"
  3. #Import "<libWs2_32.a>"
  4. #Endif
  5. #Import "native/socket.cpp"
  6. #Import "native/socket.h"
  7. Extern private
  8. #rem monkeydoc @hidden
  9. #end
  10. Function socket_init:int()="bbSocket::init"
  11. #rem monkeydoc @hidden
  12. #end
  13. Function socket_connect:Int( hostname:CString,service:CString,type:Int,flags:int )="bbSocket::connect"
  14. #rem monkeydoc @hidden
  15. #end
  16. Function socket_bind:Int( hostname:CString,service:CString,flags:int )="bbSocket::bind"
  17. #rem monkeydoc @hidden
  18. #end
  19. Function socket_listen:Int( hostname:CString,service:CString,backlog:Int,flags:int )="bbSocket::listen"
  20. #rem monkeydoc @hidden
  21. #end
  22. Function socket_accept:Int( socket:Int )="bbSocket::accept"
  23. #rem monkeydoc @hidden
  24. #end
  25. Function socket_close( socket:Int )="bbSocket::close"
  26. #rem monkeydoc @hidden
  27. #end
  28. Function socket_send:Int( socket:Int,data:Void Ptr,size:Int )="bbSocket::send"
  29. #rem monkeydoc @hidden
  30. #end
  31. Function socket_recv:Int( socket:Int,data:Void Ptr,size:Int )="bbSocket::recv"
  32. #rem monkeydoc @hidden
  33. #end
  34. Function socket_sendto:Int( socket:Int,data:Void Ptr,size:Int,addr:Void ptr,addrlen:Int )="bbSocket::sendto"
  35. #rem monkeydoc @hidden
  36. #end
  37. Function socket_recvfrom:Int( socket:Int,data:Void Ptr,size:Int,addr:Void ptr,addrlen:Int Ptr )="bbSocket::recvfrom"
  38. #rem monkeydoc @hidden
  39. #end
  40. Function socket_setopt( socket:Int,opt:String,value:Int )="bbSocket::setopt"
  41. #rem monkeydoc @hidden
  42. #end
  43. Function socket_getopt:Int( socket:Int,opt:String )="bbSocket::getopt"
  44. #rem monkeydoc @hidden
  45. #end
  46. Function socket_cansend:Int( socket:Int )="bbSocket::cansend"
  47. #rem monkeydoc @hidden
  48. #end
  49. Function socket_canrecv:Int( socket:Int )="bbSocket::canrecv"
  50. #rem monkeydoc @hidden
  51. #end
  52. Function socket_getsockaddr:Int( socket:Int,addr:Void Ptr,addrlen:Int Ptr )="bbSocket::getsockaddr"
  53. #rem monkeydoc @hidden
  54. #end
  55. Function socket_getpeeraddr:Int( socket:Int,addr:Void Ptr,addrlen:Int Ptr )="bbSocket::getpeeraddr"
  56. #rem monkeydoc @hidden
  57. #end
  58. Function socket_sockaddrname:Int( addr:Void Ptr,addrlen:Int,host:libc.char_t Ptr,service:libc.char_t Ptr )="bbSocket::sockaddrname"
  59. #rem monkeydoc @hidden
  60. #end
  61. Function socket_select:Int( n_read:Int,r_socks:Int ptr,n_write:Int,w_socks:Int Ptr,n_except:Int,e_socks:Int Ptr,millis:Int )="bbSocket::select"
  62. Private
  63. Global _init:=socket_init()
  64. Public
  65. #rem monkeydoc The SocketType enum.
  66. | SocketType | Description
  67. |:--------------|:-----------
  68. | `Stream` | Reliable stream, eg: TCP.
  69. | `Datagram` | Unreliable datagrams, eg: UDP.
  70. #end
  71. Enum SocketType
  72. Stream=0
  73. Datagram=1
  74. End
  75. #rem monkeydoc The SocketFlags enum.
  76. | SocketFlags | Description
  77. |:--------------|:-----------
  78. | `Passive` | for Bind and Listen. Indicates socket accepts connections from any address. If not set, socket accepts loopback connections only.
  79. | `Ipv4` | for Connect, Bind and Listen. Socket can be an ip4 socket.
  80. | `Ipv6` | for Connect, Bind and Listen. Socket can be an ip6 socket.
  81. #end
  82. Enum SocketFlags
  83. Passive=1
  84. Ipv4=2
  85. Ipv6=4
  86. End
  87. #rem monkeydoc The SocketAddress class.
  88. A socket address encapsulates the hostname and service of a socket.
  89. Socket address objects are returned by the [[Socket.Address]] and [[Socket.PeerAddress]] properties, and indirectly returned by [[Socket.ReceiveFrom]].
  90. #end
  91. Class SocketAddress
  92. #rem monkeydoc Creates a new empty socket address.
  93. The new socket address can be used with [[Socket.ReceiveFrom]].
  94. #end
  95. Method New()
  96. End
  97. #rem monkeydoc Creates a copy of an existing socket address.
  98. Creates and returns a copy of `address`.
  99. #end
  100. Method New( address:SocketAddress )
  101. _addr=address._addr.Slice( 0 )
  102. _addrlen=address._addrlen
  103. _host=address._host
  104. _service=address._service
  105. _dirty=address._dirty
  106. End
  107. #rem monkeydoc The hostname represented by the address.
  108. Returns an empty string if the address is invalid.
  109. #end
  110. Property Host:String()
  111. Validate()
  112. Return _host
  113. End
  114. #rem monkeydoc The service represented by the address.
  115. Returns an empty string if the address is invalid.
  116. #end
  117. Property Service:String()
  118. Validate()
  119. Return _service
  120. End
  121. #rem monkeydoc Comparison operator.
  122. #end
  123. Operator<=>:Int( address:SocketAddress )
  124. Local n:=libc.memcmp( _addr.Data,address._addr.Data,Min( _addrlen,address._addrlen ) )
  125. If Not n Return _addrlen-address._addrlen
  126. Return n
  127. End
  128. #rem monkeydoc Converts the address to a string.
  129. #end
  130. Method To:String()
  131. Return Host+":"+Service
  132. End
  133. Private
  134. Field _addr:=New Byte[128]
  135. Field _addrlen:Int=0
  136. Field _host:String=""
  137. Field _service:String=""
  138. Field _dirty:Bool=False
  139. Method Validate()
  140. If Not _dirty Return
  141. Local host:=New libc.char_t[1024]
  142. Local service:=New libc.char_t[80]
  143. If socket_sockaddrname( _addr.Data,_addrlen,host.Data,service.Data )>=0
  144. _host=String.FromCString( host.Data )
  145. _service=String.FromCString( service.Data )
  146. Else
  147. _host=""
  148. _service=""
  149. Endif
  150. _dirty=False
  151. End
  152. Property Addr:Void Ptr()
  153. Return _addr.Data
  154. End
  155. Property Addrlen:Int()
  156. Return _addrlen
  157. End
  158. Method Update( addrlen:Int )
  159. _addrlen=addrlen
  160. If _addrlen
  161. _dirty=True
  162. Return
  163. Endif
  164. _host=""
  165. _service=""
  166. _dirty=False
  167. End
  168. End
  169. #rem monkeydoc The Socket class.
  170. The socket class provides a thin wrapper around native Winsock and BSD sockets.
  171. Sockets support asynchronous programming through the use of fibers. To connect, send or receive asynchronously, simply run the relevant socket code on its own fiber. Control will be returned to the 'main' gui fiber will the operation is busy.
  172. Sockets are ipv4/ipv6 compatible.
  173. #end
  174. Class Socket Extends std.resource.Resource
  175. #rem Not on Windows...
  176. #rem monkeydoc The number of bytes that be sent to the socket without it blocking.
  177. #end
  178. Property CanSend:Int()
  179. If _socket=-1 Return 0
  180. Return socket_cansend( _socket )
  181. End
  182. #end
  183. #rem monkeydoc True if socket has been closed.
  184. #end
  185. Property Closed:Bool()
  186. Return _socket=-1
  187. End
  188. #rem monkeydoc True if socket is connected to peer.
  189. #end
  190. Property Connected:bool()
  191. If _socket=-1 Return False
  192. Local read:=_socket
  193. Local r:=socket_select( 1,Varptr read,0,Null,0,Null,0 )
  194. If r=1 Return socket_canrecv( _socket )<>0
  195. Return r=0
  196. End
  197. #rem monkeydoc The number of bytes that can be received from the socket without blocking.
  198. #end
  199. Property CanReceive:Int()
  200. If _socket=-1 Return 0
  201. Return socket_canrecv( _socket )
  202. End
  203. #rem monkeydoc The address of the socket.
  204. #end
  205. Property Address:SocketAddress()
  206. If _socket=-1 Return Null
  207. If Not _addr
  208. Local addrlen:Int=128
  209. _addr=New SocketAddress
  210. Local n:=socket_getsockaddr( _socket,_addr.Addr,Varptr addrlen )
  211. _addr.Update( n>=0 ? addrlen Else 0 )
  212. Endif
  213. Return _addr
  214. End
  215. #rem monkeydoc The address of the socket peer.
  216. #end
  217. Property PeerAddress:SocketAddress()
  218. If _socket=-1 Return Null
  219. If Not _peer
  220. Local addrlen:Int=128
  221. _peer=New SocketAddress
  222. Local n:=socket_getpeeraddr( _socket,_peer.Addr,Varptr addrlen )
  223. _peer.Update( n>=0 ? addrlen Else 0 )
  224. Endif
  225. Return _peer
  226. End
  227. #rem monkeydoc Accepts a new incoming connection on a listening socket.
  228. Returns null if there was an error, otherwise blocks until an incoming connection has been made.
  229. @return new incomnig connection or null if there was an error.
  230. #end
  231. Method Accept:Socket()
  232. If _socket=-1 Return Null
  233. Local socket:=socket_accept( _socket )
  234. If socket=-1 Return Null
  235. Return New Socket( socket )
  236. End
  237. #rem monkeydoc Closes a socket.
  238. Once closed, a socket should not be used anymore.
  239. #end
  240. Method Close()
  241. Discard()
  242. End
  243. #rem monkeydoc Sends data on a connected socket.
  244. Writes `size` bytes to the socket.
  245. Returns the number of bytes actually written.
  246. Can return less than `size` if the socket has been closed by the peer or if an error occured.
  247. @param buf The memory buffer to write data from.
  248. @param size The number of bytes to write to the socket.
  249. @return The number of bytes actually written.
  250. #end
  251. Method Send:Int( data:Void Ptr,size:Int )
  252. If _socket=-1 Return 0
  253. Return socket_send( _socket,data,size )
  254. End
  255. Method SendTo:Int( data:Void Ptr,size:Int,address:SocketAddress )
  256. If _socket=-1 Return 0
  257. DebugAssert( address.Addrlen,"SocketAddress is invalid" )
  258. Return socket_sendto( _socket,data,size,address.Addr,address.Addrlen )
  259. End
  260. #rem monkeydoc Receives data on a connected socket.
  261. Reads at most `size` bytes from the socket.
  262. Returns 0 if the socket has been closed by the peer.
  263. Can return less than `size`, in which case you may have to read again if you know there's more data coming.
  264. @param buf The memory buffer to read data into.
  265. @param size The number of bytes to read from the socket.
  266. @return The number of bytes actually read.
  267. #end
  268. Method Receive:Int( data:Void Ptr,size:Int )
  269. If _socket=-1 Return 0
  270. Return socket_recv( _socket,data,size )
  271. End
  272. Method ReceiveFrom:Int( data:Void Ptr,size:Int,address:SocketAddress )
  273. If _socket=-1 Return 0
  274. Local addrlen:Int=128
  275. Local n:=socket_recvfrom( _socket,data,size,address.Addr,Varptr addrlen )
  276. address.Update( n>=0 ? addrlen Else 0 )
  277. Return n
  278. End
  279. #rem monkeydoc Sets a socket option.
  280. Currently, only "TCP_NODELAY" is supported, which should be 1 to enable, 0 to disable.
  281. #end
  282. Method SetOption( opt:String,value:Int )
  283. If _socket=-1 Return
  284. socket_setopt( _socket,opt,value )
  285. End
  286. #rem monkeydoc Gets a socket option.
  287. #end
  288. Method GetOption:Int( opt:String )
  289. If _socket=-1 Return -1
  290. Return socket_getopt( _socket,opt )
  291. End
  292. #rem monkeydoc Creates a connected socket.
  293. Attempts to connect to the host at `hostname` and service at `service` and returns a new connected socket if successful.
  294. The socket `type` should be SocketType.Stream (the default) is connecting to stream server, or SocketType.DataGram if connecting to a datagram server.
  295. Returns null upon failure.
  296. @return A new socket.
  297. #end
  298. Function Connect:Socket( hostname:String,service:String,type:SocketType=SocketType.Stream,flags:SocketFlags=Null )
  299. Local socket:=socket_connect( hostname,service,type,flags )
  300. If socket=-1 Return Null
  301. Return New Socket( socket )
  302. End
  303. #rem monkeydoc Creates a datagram server socket.
  304. Returns a new datagram server socket bound to 'service' if successful.
  305. `service` can also be an integer port number.
  306. Returns null upon failure.
  307. @return A new socket.
  308. #end
  309. Function Bind:Socket( service:String,flags:SocketFlags=SocketFlags.Passive )
  310. Local socket:=socket_bind( "",service,flags )
  311. If socket=-1 Return Null
  312. Return New Socket( socket )
  313. End
  314. #rem monkey @deprecated
  315. #end
  316. Function Bind:Socket( hostname:String,service:String )
  317. Local socket:=socket_bind( "",service,1 )
  318. If socket=-1 Return Null
  319. Return New Socket( socket )
  320. End
  321. #rem monkeydoc Creates a stream server socket and listens on it.
  322. Returns a new stream server socket listening at `service` if successful.
  323. `service` can also be an integer port number.
  324. Returns null upon failure.
  325. @return A new socket.
  326. #end
  327. Function Listen:Socket( service:String,backlog:Int=32,flags:SocketFlags=SocketFlags.Passive )
  328. Local socket:=socket_listen( "",service,backlog,flags )
  329. If socket=-1 Return Null
  330. Return New Socket( socket )
  331. End
  332. #rem monkey @deprecated
  333. #end
  334. Function Listen:Socket( hostname:String,service:String,backlog:Int=128 )
  335. Local socket:=socket_listen( "",service,backlog,1 )
  336. If socket=-1 Return Null
  337. Return New Socket( socket )
  338. End
  339. Protected
  340. #rem monkeydoc @hidden
  341. #end
  342. Method OnDiscard() Override
  343. socket_close( _socket )
  344. _socket=-1
  345. _addr=Null
  346. _peer=null
  347. End
  348. #rem monkeydoc @hidden
  349. #end
  350. Method OnFinalize() Override
  351. socket_close( _socket )
  352. End
  353. Private
  354. Field _socket:Int=-1
  355. Field _addr:SocketAddress
  356. Field _peer:SocketAddress
  357. Method New( socket:Int )
  358. _socket=socket
  359. End
  360. End