socket.monkey2 9.8 KB

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