socket.bmx 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. Strict
  2. Rem
  3. bbdoc: Networking/Sockets
  4. End Rem
  5. Module BRL.Socket
  6. ModuleInfo "Version: 1.04"
  7. ModuleInfo "Author: Mark Sibly and Bruce A Henderson"
  8. ModuleInfo "License: zlib/libpng"
  9. ModuleInfo "Copyright: Blitz Research Ltd"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.04"
  12. ModuleInfo "History: Fixed for Android."
  13. ModuleInfo "History: 1.03"
  14. ModuleInfo "History: Added IPV6 support."
  15. ModuleInfo "History: 1.02 Release"
  16. ModuleInfo "History: Fixed socket name 0 failing"
  17. Import Pub.StdC
  18. Private
  19. Extern "os"
  20. ?Win32
  21. Const FIONREAD=$4004667F
  22. Function ioctl_( socket,opt,buf:Byte Ptr )="int ioctlsocket(SOCKET ,long ,u_long *)!"
  23. ?MacOS
  24. Const FIONREAD=$4004667F
  25. Function ioctl_( socket,opt,buf:Byte Ptr )="ioctl"
  26. ?Linux And Not android
  27. Const FIONREAD=$541b
  28. Function ioctl_( socket,opt,buf:Byte Ptr )="ioctl"
  29. ?android
  30. Const FIONREAD=$541b
  31. Function ioctl_( socket,opt,buf:Byte Ptr )="int ioctl(int, int, BBBYTE*)!"
  32. ?emscripten
  33. Const FIONREAD=$541b
  34. Function ioctl_( socket,opt,buf:Byte Ptr )="ioctl"
  35. ?nx
  36. Const FIONREAD=$4004667F
  37. Function ioctl_( socket,opt,buf:Byte Ptr )="ioctl"
  38. ?haiku
  39. Const FIONREAD=$be000001
  40. Function ioctl_( socket,opt,buf:Byte Ptr )="int ioctl(int, unsigned long, BBBYTE*)!"
  41. ?
  42. End Extern
  43. Public
  44. Type TSocketException
  45. Method ToString$() Override
  46. Return "Internal socket error"
  47. End Method
  48. End Type
  49. Type TSocket
  50. ?Ptr64
  51. Method Send:Long( buf:Byte Ptr, count:Size_T, flags:Int = 0 )
  52. Local n:Long=send_( _socket,buf,count,flags )
  53. ?Not ptr64
  54. Method Send:Int( buf:Byte Ptr, count:Size_T, flags:Int = 0 )
  55. Local n:Int=send_( _socket,buf,count,flags )
  56. ?
  57. Return n
  58. End Method
  59. ?ptr64
  60. Method Recv:Long( buf:Byte Ptr, count:Size_T, flags:Int = 0 )
  61. Local n:Long=recv_( _socket,buf,count,flags )
  62. ?Not ptr64
  63. Method Recv:Int( buf:Byte Ptr, count:Size_T, flags:Int = 0 )
  64. Local n:Int=recv_( _socket,buf,count,flags )
  65. ?
  66. Return n
  67. End Method
  68. Method Close()
  69. If _socket<0 Return
  70. If _autoClose closesocket_ _socket
  71. _socket=-1
  72. _localIp=""
  73. _localPort=-1
  74. _remoteIp=""
  75. _remotePort=-1
  76. End Method
  77. Method Connected()
  78. If _socket<0 Return False
  79. Local Read=_socket
  80. If select_( 1,Varptr Read,0,Null,0,Null,0 )<>1 Or ReadAvail()<>0 Return True
  81. Close
  82. Return False
  83. End Method
  84. Method Bind:Int( localPort:Int, family:Int = AF_INET_ )
  85. If bind_( _socket,family,localPort )<0 Return False
  86. UpdateLocalName
  87. Return True
  88. End Method
  89. Method Bind:Int( info:TAddrInfo )
  90. If bmx_stdc_bind_info( _socket, info.infoPtr ) < 0 Then
  91. Return False
  92. End If
  93. UpdateLocalName
  94. Return True
  95. End Method
  96. Method Connect:Int( AddrInfo:TAddrInfo )
  97. If connect_( _socket, AddrInfo.infoPtr )<0 Return False
  98. UpdateLocalName
  99. UpdateRemoteName
  100. Return True
  101. End Method
  102. Method Listen:Int( backlog:Int )
  103. Return listen_( _socket,backlog )>=0
  104. End Method
  105. Method Accept:TSocket( timeout:Int = -1, storage:TSockaddrStorage = Null )
  106. If timeout >= 0 Then
  107. Local Read:Int = _socket
  108. If select_( 1,Varptr Read,0,Null,0,Null,timeout )<>1 Then
  109. Return
  110. End If
  111. End If
  112. Local client:Int
  113. If storage Then
  114. client = bmx_stdc_accept_(_socket, storage.storagePtr)
  115. Else
  116. client = bmx_stdc_accept_(_socket, Null)
  117. End If
  118. If client > 0 Then
  119. Return Create( client )
  120. End If
  121. End Method
  122. Method ReadAvail:Int()
  123. Local n
  124. Local t=ioctl_( _socket,FIONREAD,Varptr n )
  125. If t<0 Return 0
  126. Return n
  127. End Method
  128. Method SetTCPNoDelay( enable )
  129. Local flag=enable
  130. setsockopt_( _socket,IPPROTO_TCP,TCP_NODELAY,Varptr flag,4 )
  131. End Method
  132. Method SetSockOpt:Int(level:Int, optname:Int, enable:Int)
  133. Local flag:Int = enable
  134. If setsockopt_(_socket, level, optname, Varptr flag, 4) < 0 Then
  135. Return False
  136. End If
  137. Return True
  138. End Method
  139. Method Socket:Int()
  140. Return _socket
  141. End Method
  142. Method LocalIp:String()
  143. Return _localIp
  144. End Method
  145. Method LocalPort:Int()
  146. Return _localPort
  147. End Method
  148. Method RemoteIp:String()
  149. Return _remoteIp
  150. End Method
  151. Method RemotePort:Int()
  152. Return _remotePort
  153. End Method
  154. Method UpdateLocalName:Int()
  155. If bmx_stdc_getsockname(_socket, _localPort, _localIp) < 0 Then
  156. Return False
  157. End If
  158. Return True
  159. End Method
  160. Method UpdateRemoteName:Int()
  161. If bmx_stdc_getpeername(_socket, _remotePort, _remoteIp) < 0 Then
  162. Return False
  163. End If
  164. Return True
  165. End Method
  166. Function Create:TSocket( socket:Int, autoClose:Int = True )
  167. If socket < 0 Then
  168. Return
  169. End If
  170. Local addr:Byte[16],size:Int
  171. Local t:TSocket = New TSocket
  172. t._socket = socket
  173. t._autoClose = autoClose
  174. t.UpdateLocalName
  175. t.UpdateRemoteName
  176. Return t
  177. End Function
  178. Function CreateUDP:TSocket(family:Int = AF_INET_)
  179. Local socket=socket_( family,SOCK_DGRAM_,0 )
  180. If socket>=0 Return Create( socket,True )
  181. End Function
  182. Function CreateTCP:TSocket(family:Int = AF_INET_)
  183. Local socket=socket_( family,SOCK_STREAM_,0 )
  184. If socket>=0 Return Create( socket,True )
  185. End Function
  186. Rem
  187. bbdoc:
  188. End Rem
  189. Function Create:TSocket(info:TAddrInfo)
  190. Local socket:Int = socket_( info.family(),info.sockType(),info.protocol() )
  191. If socket >= 0 Then
  192. Return Create( socket, True )
  193. End If
  194. End Function
  195. Field _socket:Int,_autoClose:Int
  196. Field _localIp:String,_localPort:Int
  197. Field _remoteIp:String,_remotePort:Int
  198. End Type
  199. Rem
  200. bbdoc: Create a UDP socket
  201. returns: A new socket
  202. about:
  203. The new socket is not bound to any local or remote address.
  204. End Rem
  205. Function CreateUDPSocket:TSocket()
  206. Return TSocket.CreateUDP()
  207. End Function
  208. Rem
  209. bbdoc: Create a TCP socket
  210. returns: A new socket
  211. about:
  212. The new socket is not bound to any local or remote address.
  213. End Rem
  214. Function CreateTCPSocket:TSocket()
  215. Return TSocket.CreateTCP()
  216. End Function
  217. Rem
  218. bbdoc: Close a socket
  219. about:
  220. All sockets should eventually be closed. Once closed, a socket can no longer
  221. be used.
  222. End Rem
  223. Function CloseSocket( socket:TSocket )
  224. socket.Close
  225. End Function
  226. Rem
  227. bbdoc: Bind a socket to a local port
  228. returns: True if successful, otherwise false
  229. about:
  230. If @localPort is 0, a new local port will be allocated. If @localPort is not 0,
  231. #BindSocket will fail if there is already an application bound to @localPort.
  232. End Rem
  233. Function BindSocket( socket:TSocket, localPort, family:Int = AF_INET_)
  234. Return socket.Bind( localPort, family )
  235. End Function
  236. Rem
  237. bbdoc: Connect a socket to a remote ip and port
  238. returns: True if successful, otherwise false
  239. about:
  240. For both UDP and TCP sockets, #ConnectSocket will fail if the specified
  241. ip address could not be reached.
  242. In the case of TCP sockets, #ConnectSocket will also fail if there is
  243. no application listening at the remote port.
  244. End Rem
  245. Function ConnectSocket( socket:TSocket, AddrInfo:TAddrInfo )
  246. Return socket.Connect( AddrInfo )
  247. End Function
  248. Rem
  249. bbdoc: Start listening at a socket
  250. about:
  251. The specified socket must be a TCP socket, and must already be bound to a local port.
  252. End Rem
  253. Function SocketListen( socket:TSocket,backlog=0 )
  254. Return socket.Listen( backlog )
  255. End Function
  256. Rem
  257. bbdoc: Accept new connections on a listening socket
  258. returns: A new socket, or Null if no connection was made in the specified timeout
  259. about:
  260. The specified socket must be a TCP socket, and must be listening.
  261. End Rem
  262. Function SocketAccept:TSocket( socket:TSocket,timeout=0 )
  263. Return socket.Accept( timeout )
  264. End Function
  265. Rem
  266. bbdoc: Get socket connection status
  267. returns: True if socket is connected
  268. about:
  269. #SocketConnected allows you to determine if a TCP connection is still
  270. alive or has been remotely closed.
  271. #SocketConnected should only be used with TCP sockets that have already
  272. connected via #ConnectSocket or #SocketAccept.
  273. End Rem
  274. Function SocketConnected( socket:TSocket )
  275. Return socket.Connected()
  276. End Function
  277. Rem
  278. bbdoc: Get number of bytes available for reading from a socket
  279. returns: Number of bytes that may be read without causing the socket to block
  280. End Rem
  281. Function SocketReadAvail( socket:TSocket )
  282. Return socket.ReadAvail()
  283. End Function
  284. Rem
  285. bbdoc: Get local ip of a socket
  286. End Rem
  287. Function SocketLocalIP:String( socket:TSocket )
  288. Return socket.LocalIP()
  289. End Function
  290. Rem
  291. bbdoc: Get local port of a socket
  292. End Rem
  293. Function SocketLocalPort( socket:TSocket )
  294. Return socket.LocalPort()
  295. End Function
  296. Rem
  297. bbdoc: Get remote ip of a socket
  298. End Rem
  299. Function SocketRemoteIP:String( socket:TSocket )
  300. Return socket.RemoteIP()
  301. End Function
  302. Rem
  303. bbdoc: Get remote port of a socket
  304. End Rem
  305. Function SocketRemotePort( socket:TSocket )
  306. Return socket.RemotePort()
  307. End Function
  308. Rem
  309. bbdoc: Convert an ip address to a dotted string
  310. returns: Dotted string version of ip address
  311. End Rem
  312. Function DottedIP$( ip:Int )
  313. Return (ip Shr 24)+"."+(ip Shr 16 & 255)+"."+(ip Shr 8 & 255 )+"."+(ip & 255)
  314. End Function
  315. Rem
  316. bbdoc: Converts a dotted IPv4 string to an ip address.
  317. returns: An integer version of an ip address.
  318. End Rem
  319. Function DottedIPToInt:Int(addr:String)
  320. Local parts:String[] = addr.Split(".")
  321. Local num:Long
  322. For Local i:Int = 0 Until parts.length
  323. Local power:Int = 3 - i
  324. num :+ (parts[i].ToInt() Mod 256) * (256 ^ power)
  325. Next
  326. Return num
  327. End Function
  328. Rem
  329. bbdoc: Converts an IP address string into a binary representation.
  330. about: For AF_INET_, @dst should be an Int or 32-bit (4 bytes) in size.
  331. For AF_INET6_, @dst should be 128-bits (16 bytes) in size.
  332. End Rem
  333. Function InetPton:Int(family:Int, src:String, dst:Byte Ptr)
  334. Return inet_pton_(family, src, dst)
  335. End Function
  336. Rem
  337. bbdoc: Convert a host name to an ip address
  338. returns: Host ip address, or 0 if host not found
  339. End Rem
  340. Function HostIp:String( HostName$, index:Int=0, family:Int = AF_UNSPEC_ )
  341. If index<0 Return
  342. Local ips:String[]=HostIps( HostName, family )
  343. If index < ips.length Then
  344. Return ips[index]
  345. End If
  346. End Function
  347. Rem
  348. bbdoc: Get all ip addresses for a host name
  349. returns: Array of host ips, or Null if host not found
  350. End Rem
  351. Function HostIps:String[]( HostName$, family:Int = AF_UNSPEC_ )
  352. Local addr:TAddrInfo[] = AddrInfo(HostName, , family)
  353. Local ips:String[] = New String[addr.length]
  354. For Local i:Int = 0 Until addr.length
  355. ips[i] = addr[i].HostIp()
  356. Next
  357. Return ips
  358. End Function
  359. Rem
  360. bbdoc: Convert a host ip address to a name
  361. returns: Name of host, or Null if host not found
  362. End Rem
  363. Function HostName$( HostIp:String, family:Int = AF_UNSPEC_ )
  364. Local addr:TAddrInfo[] = AddrInfo(HostIp, , family)
  365. If addr Then
  366. Return addr[0].HostName()
  367. End If
  368. End Function
  369. Rem
  370. bbdoc: Returns an array of TAddrInfo objects.
  371. End Rem
  372. Function AddrInfo:TAddrInfo[](host:String, service:String = "http", family:Int = AF_UNSPEC_)
  373. Return getaddrinfo_(host, service, family)
  374. End Function
  375. Rem
  376. bbdoc: Returns an array of TAddrInfo objects.
  377. End Rem
  378. Function AddrInfo:TAddrInfo[](host:String, service:String, hints:TAddrInfo)
  379. Return getaddrinfo_hints(host, service, hints.infoPtr)
  380. End Function