TCP P2P, Event driven!


SUBMITTED BY: Guest

DATE: May 30, 2013, 7:49 a.m.

FORMAT: Text only

SIZE: 39.4 kB

HITS: 2127

  1. #cs ----------------------------------------------------------------------------
  2. AutoIt Version: 3.3.0.0
  3. Author: Hyperzap.
  4. Design concepts were first coined by Kip in his "Event driven TCP UDF"
  5. Zatorg's Asynchronous Sockets UDF is also used.
  6. Script Function:
  7. This UDF is a re-write of Kip's 'Event driven TCP UDF'. Thx Kip.
  8. It aims to generate simple TCP, event driven functionality for P2P programs, As
  9. opposed to client-server oriented communication as in Kip's UDF.
  10. Evidently, this functionality is not possible in Kips original releases.
  11. Apart from the obvious conponents of such a code, like Recv, Send, Connect,
  12. Listen, other important P2P routines have been coded. These include things
  13. like; Universal identifiers, bootstrapping mechanisms, peers
  14. discovery, and message routing.
  15. MINOR DRAWBACKS:
  16. You can never use the string #8i8# or #8i8TERMINATE# in your communicatons.
  17. You cannot use the # (hash) symbol in either your Node ID or any part of a
  18. long range message.
  19. #ce ----------------------------------------------------------------------------
  20. $UDF_Version = "1.31 STABLE"
  21. $console_out = True
  22. $STANDARD_MESSAGE_LIFE = 6
  23. #cs
  24. Functions:
  25. _P2P_Start_Node( Node Identifier, Port, Max peers, Bootstrap mode, Boostrap max, local/global, IP)
  26. _P2P_Stop_Node()
  27. _P2P_Connect( IP)
  28. _P2P_Send( Socket, Data)
  29. _P2P_Disconnect_Peer( Socket)
  30. _P2P_Send_Message( Address, Data)
  31. _P2P_Register_Event($iEvent, $sFunction)
  32. Register event values:
  33. $P2P_AUX_DATA ; Function ($hSocket, $DataType, $Data);When things like IP and Node identifier are discovered.
  34. $P2P_MESSAGE ; Function ($hSocket, $message, $iError) ;When long distance messages are recieved.
  35. $P2P_RECEIVE ; Function ($hSocket, $sReceived, $iError)
  36. $P2P_CONNECT ; Function ($hSocket, $iError)
  37. $P2P_DISCONNECT ; Function ($hSocket, $iError)
  38. $P2P_NEWCONNECTION ; Function ($hSocket, $iError)
  39. Also, please call the function peer_broadcast() periodically in your program. Failing to do this will
  40. Seriously cripple the bootstrapping mechanism (unless you program is ALWAYS recieving data at least once
  41. every 40 seconds, In which case the mechanism will trigger automatically).
  42. #ce
  43. Global Const $FD_READ = 1
  44. Global Const $FD_WRITE = 2
  45. Global Const $FD_OOB = 4
  46. Global Const $FD_ACCEPT = 8
  47. Global Const $FD_CONNECT = 16
  48. Global Const $FD_CLOSE = 32
  49. Global $hWs2_32 = -1 ;Kip, What is this? (I left it in case it was something important)
  50. Global Const $TCP_SEND = 1
  51. Global Const $TCP_RECEIVE = 2
  52. Global Const $TCP_CONNECT = 4
  53. Global Const $TCP_DISCONNECT = 8
  54. Global Const $TCP_NEWCLIENT = 16
  55. Global Const $IPLOC_LOCAL = 64
  56. Global Const $IPLOC_GLOBAL = 128
  57. Global Const $P2P_MESSAGE = 256
  58. Global Const $P2P_RECEIVE = 512
  59. Global Const $P2P_CONNECT = 1024
  60. Global Const $P2P_DISCONNECT = 2048
  61. Global Const $P2P_NEWCONNECTION = 4096
  62. Global Const $P2P_AUX_DATA = 8192
  63. ;NOTE - SOCKET ARRAYS & OTHER ARRAYS WILL BE DECLARED IN THE '_P2P_START_NODE' FUNCTION.
  64. ; THIS IS BECAUSE I DO NOT KNOW HOW TO DECLARE AN ARRAY AT THE BEGINNING WITHOUT
  65. ; DEFINING A DIMENSION RANGE(I do not know max peers at this stage).
  66. ; I'M SURE THERE IS A WAY. WHEN I FIND IT OUT, I WILL PUT IT IN THE NEXT RELEASE.
  67. Global $total_connected = 0
  68. Global $max_connections
  69. Global $Listening_Socket
  70. Global $node_IP
  71. Global $node_Port
  72. Global $node_Identifier
  73. Global $node_ext_IP
  74. Global $Bootstrap_mode
  75. Global $Bootstrap_max
  76. Global $peer_timer
  77. Global $total_ID_known = 0
  78. Global $Known_ID[200]
  79. Global $connectfunc = ""
  80. Global $recievefunc = ""
  81. Global $disconnectfunc = ""
  82. Global $newconnectionfunc = ""
  83. Global $messagefunc = ""
  84. global $auxfunc = ""
  85. Global $Main_Socket_Address = ""
  86. TCPStartup()
  87. Global Const $__TCP_WINDOW = GUICreate("Async Sockets UDF") ;I know, Copy paste.
  88. ; #FUNCTION# ;===============================================================================================================
  89. ;
  90. ; Name...........: _P2P_Start_Node
  91. ; Description ...: Initializes the P2P Node. Starts listening for connections.
  92. ; Syntax.........: _P2P_Start_Node( $node_id, $Port, $Max_peers, $Bootstrapmode, $bootstrapmax, $location, $IP="0.0.0.0")
  93. ; Parameters ....: $node_id - The Unique Identifier assigned to you, as a user of the program. Should not change
  94. ; between excutions for a specific user. This ID is used as an address for long range messages.
  95. ; $Port - The port to listen for incoming connections on.
  96. ; $Max_peers - The maximum number of peers that can be connected to your node at any one time.
  97. ; $bootstrapmode - Either 0 or 1. If 0, this UDF will not automatically connect you to other nodes.
  98. ; $bootstrapmax - The number of peers connected before the UDF will stop bootstrapping. (autoconnecting)
  99. ; $location - Either 0 or 1. Put 0 if working on a LAN or WLAN. Put 1 if your node works over the
  100. ; Internet.
  101. ; $IP - (Optional) The IP address to host the node on. Really, the default value will work 99%
  102. ; of the time. You shouldn't change it unless you know exactly what your doing.
  103. ; Return values .: Err...Nothing.
  104. ; Author ........: Hyperzap and Kip.
  105. ; Modified.......:
  106. ; Remarks .......: Only 1 P2P node can be created per script. By why on earth would you need another?
  107. ; Related .......:
  108. ; Link ..........;
  109. ; Example .......; See my 'example scripts' post. (If applicable)
  110. ;
  111. ; ;==========================================================================================================================
  112. Func _P2P_Start_Node( $node_id, $Port, $Max_peers, $Bootstrapmode, $bootstrapmax, $location, $IP="0.0.0.0")
  113. local $startuptimer = TimerInit()
  114. $Listening_Socket = ___ASocket()
  115. $Main_Socket_Address = $Listening_Socket
  116. ___ASockSelect( $Listening_Socket, $__TCP_WINDOW, 0x0400, $FD_ACCEPT)
  117. GUIRegisterMsg( 0x0400, "Listensocket_data_" )
  118. ___ASockListen( $Listening_Socket, $IP, $Port )
  119. if $Bootstrapmode = 0 then $Bootstrap_mode = $IPLOC_LOCAL
  120. if $Bootstrapmode = 1 then $Bootstrap_mode = $IPLOC_GLOBAL
  121. $bootstrap_max = $bootstrapmax
  122. $max_connections = $Max_peers
  123. $node_IP = $IP
  124. $node_Port = $Port
  125. $node_Identifier = $node_id
  126. $peer_timer = TimerInit()
  127. if $location = 1 then $node_ext_IP = _Get_IP() ;GetIP command.
  128. if $location = 0 then $node_ext_IP = @IPAddress1
  129. Global $Socket_Handle_array[$Max_peers + 1]
  130. Global $Node_Identifier_array[$Max_peers + 1]
  131. Global $Node_IP_array[$Max_peers + 1]
  132. Global $Node_Peer_Reachable_list[$Max_peers + 1]
  133. For $x = 0 to $Max_peers step 1
  134. $Socket_Handle_array[$x] = -1
  135. $Node_Identifier_array[$x] = -1
  136. $Node_IP_array[$x] = -1
  137. $Node_Peer_Reachable_list[$x] = -1
  138. Next
  139. if $console_out = True then ConsoleWrite( @CRLF & @CRLF & "P2P_: Node started")
  140. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Port: " & $node_Port)
  141. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Ext IP: " & $node_ext_IP)
  142. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Max peers: " & $max_connections)
  143. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Identifier: " & $node_Identifier)
  144. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Engine Version: " & $UDF_version)
  145. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Startup time: " & TimerDiff( $startuptimer) & "ms" & @CRLF)
  146. EndFunc
  147. ; #FUNCTION# ;===============================================================================
  148. ;
  149. ; Name...........: _P2P_Stop_Node
  150. ; Description ...: Stops the node, and closes all connections.
  151. ; Syntax.........: _P2P_Stop_Node()
  152. ; Parameters ....:
  153. ; Return values .: None.
  154. ; Author ........: Hyperzap
  155. ; Modified.......:
  156. ; Remarks .......:
  157. ; Related .......:
  158. ; Link ..........;
  159. ; Example .......;
  160. ;
  161. ; ;==========================================================================================
  162. Func _P2P_Stop_Node()
  163. ___ASockShutdown($Listening_Socket)
  164. TCPCloseSocket($Listening_Socket)
  165. For $x = 0 to $max_connections step 1
  166. $Socket_Handle_array[$x] = -1
  167. $Node_Identifier_array[$x] = -1
  168. $Node_IP_array[$x] = -1
  169. $Node_Peer_Reachable_list[$x] = -1
  170. Next
  171. $max_connections = 0
  172. $Listening_Socket = ""
  173. $node_IP = ""
  174. $node_Port = ""
  175. $node_Identifier = -1
  176. $node_ext_IP = ""
  177. $Bootstrap_mode = ""
  178. $Bootstrap_max = 0
  179. $connectfunc = ""
  180. $recievefunc = ""
  181. $disconnectfunc = ""
  182. $newconnectionfunc = ""
  183. $messagefunc = ""
  184. $auxfunc = ""
  185. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Engine shutdown successful.")
  186. EndFunc
  187. Func Listensocket_data_($hWnd, $iMsgID, $WParam, $LParam)
  188. Local $Socketinquestion = $WParam
  189. Local $iError = ___HiWord( $LParam )
  190. Local $iEvent = ___LoWord( $LParam )
  191. Abs($hWnd) ; Stupid AU3Check...
  192. If $iMsgID = 0x400 Then
  193. If $iEvent = $FD_ACCEPT Then
  194. If Not $iError Then
  195. $arrayslot = Findfreearrayslot()
  196. if $arrayslot = "error" then ;No more spots for new peers. Connection dropped.
  197. $newsocket = TCPAccept($Socketinquestion)
  198. TCPSend( $newsocket, "#8i8#NOSLOT#8i8TERMINATE#")
  199. TCPCloseSocket( $newsocket)
  200. EndIf
  201. $newsocket = TCPAccept($Socketinquestion)
  202. ___ASockSelect($newsocket, $__TCP_WINDOW, 0x0400 + $arrayslot, BitOR($FD_READ, $FD_CONNECT, $FD_CLOSE))
  203. GUIRegisterMsg( 0x0400 + $arrayslot, "Opensocket_data_" )
  204. $Socket_Handle_array[$arrayslot] = $newsocket
  205. $Node_Identifier_array[$arrayslot] = -1
  206. $Node_IP_array[$arrayslot] = -1
  207. TCPSend( $newsocket, "#8i8#IP#" & $node_ext_IP & "#8i8TERMINATE#")
  208. TCPSend( $newsocket, "#8i8#ID#" & $node_Identifier & "#8i8TERMINATE#")
  209. peer_broadcast_to_peer( $newsocket)
  210. $total_connected += 1
  211. Call( $newconnectionfunc, $newsocket, $iError)
  212. Else
  213. Call( $newconnectionfunc, 0, $iError)
  214. EndIf
  215. ElseIf $iEvent = $FD_CONNECT Then
  216. Call( $connectfunc, $newsocket, $iError)
  217. EndIf
  218. EndIf
  219. EndFunc
  220. Func Findfreearrayslot()
  221. $newConnNum = -1
  222. For $x = 1 To $max_connections
  223. If $Socket_Handle_array[$x] = -1 Then
  224. $newConnNum = $x
  225. ExitLoop
  226. EndIf
  227. Next
  228. If $newConnNum = -1 Then Return "error";Didn't want it to be a number.
  229. Return $newConnNum
  230. EndFunc
  231. Func Opensocket_data_( $hWnd, $iMsgID, $WParam, $LParam )
  232. Local $iError = ___HiWord( $LParam )
  233. Local $iEvent = ___LoWord( $LParam )
  234. Abs($hWnd)
  235. local $Array_Slot = $iMsgID-0x400 ;No more loops to slow down message delievery!
  236. local $SocketID = $Socket_Handle_array[$Array_Slot]
  237. if $SocketID = -1 then return 0
  238. Switch $iEvent
  239. Case $FD_READ
  240. $rawrecv = TCPRecv($SocketID, 1024*5)
  241. recvprocess( $rawrecv, $SocketID, $Array_Slot, $iError)
  242. Case $FD_CLOSE
  243. ___ASockShutdown($SocketID)
  244. TCPCloseSocket($SocketID)
  245. Call( $disconnectfunc, $SocketID, $iError)
  246. $Socket_Handle_array[$Array_Slot] = -1
  247. $Node_Identifier_array[$Array_Slot] = -1
  248. $Node_IP_array[$Array_Slot] = -1
  249. $Node_Peer_Reachable_list[$Array_Slot] = -1
  250. $total_connected -= 1
  251. if TimerDiff( $peer_timer) > 40000 Then
  252. peer_broadcast()
  253. EndIf
  254. Case $FD_CONNECT
  255. If $iError Then
  256. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Connection failed: " & $SocketID)
  257. $Socket_Handle_array[$Array_Slot] = -1
  258. $Node_Identifier_array[$Array_Slot] = -1
  259. $Node_IP_array[$Array_Slot] = -1
  260. $Node_Peer_Reachable_list[$Array_Slot] = -1
  261. $total_connected -= 1
  262. Call( $connectfunc, $SocketID, $iError)
  263. Else
  264. Call( $connectfunc, $SocketID, $iError)
  265. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Connection established: " & $SocketID)
  266. TCPSend( $Socket_Handle_array[$Array_Slot], "#8i8#IP#" & $node_ext_IP & "#8i8TERMINATE#")
  267. TCPSend( $Socket_Handle_array[$Array_Slot], "#8i8#ID#" & $node_Identifier & "#8i8TERMINATE#")
  268. peer_broadcast_to_peer( $Socket_Handle_array[$Array_Slot])
  269. EndIf
  270. if TimerDiff( $peer_timer) > 40000 Then
  271. peer_broadcast()
  272. EndIf
  273. EndSwitch
  274. EndFunc
  275. Func recvprocess( $rawrecv, $SocketID, $Array_Slot, $iError)
  276. if stringlen($rawrecv) < 1 then return 0
  277. local $Single_Data = StringSplit( $rawrecv, "#8i8TERMINATE#", 1)
  278. for $k = 1 to $Single_Data[0] step 1
  279. if $Single_Data[$k] = "" then ContinueLoop ;Probably isn't nessesary.
  280. if $Single_Data[$k] = " " then ContinueLoop ;Disregard noise and crappy coders.
  281. if StringInStr( $Single_Data[$k], "#8i8#", 1) > 0 Then
  282. node_data_process( $SocketID, $Single_Data[$k], $Array_Slot, $iError);must be node info to process.
  283. Else
  284. Call( $recievefunc, $SocketID, $Single_Data[$k], $iError) ;Sends to user script
  285. EndIf
  286. Next
  287. if TimerDiff( $peer_timer) > 40000 Then
  288. peer_broadcast()
  289. EndIf
  290. EndFunc
  291. Func node_data_process( $SocketID, $Data, $Array_Slot, $iError)
  292. local $split = StringSplit( $Data, "#")
  293. if $split[3] = "IP" then
  294. $Node_IP_array[$Array_Slot] = $split[4]
  295. Call( $auxfunc, $SocketID, "IP", $split[4])
  296. EndIf
  297. if $split[3] = "ID" then
  298. $Node_Identifier_array[$Array_Slot] = $split[4]
  299. Call( $auxfunc, $SocketID, "ID", $split[4])
  300. EndIf
  301. if $split[3] = "PEER" then bootstrap( $SocketID, $split[4], $Array_Slot, $iError)
  302. if $split[3] = "IDLIST" then
  303. $Node_Peer_Reachable_list[$Array_Slot] = $split[4]
  304. Call( $auxfunc, $SocketID, "NODE-REACHABLE", $split[4])
  305. EndIf
  306. if $split[3] = "MESSAGE" then ;#8i8#MESSAGE
  307. Route_Message( $SocketID, $Data, $Array_Slot)
  308. EndIf
  309. EndFunc
  310. Func bootstrap( $SocketID, $split, $Array_Slot, $iError)
  311. if $Bootstrap_mode = $IPLOC_LOCAL then return 9;Bootstrapping disabled.
  312. if $total_connected >= $Bootstrap_max then return 8;Already connected to enough peers.
  313. local $connectpeers = Round( ($Bootstrap_max/$total_connected/2), 0) ;calculate how many peers we should attempt to connect to.
  314. if $connectpeers < $Bootstrap_max and $connectpeers = 0 then $connectpeers = 1
  315. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Bootstrap stats: " & $connectpeers & ":" & $total_connected & "/" & $Bootstrap_max)
  316. $peers = StringSplit( $split, ";")
  317. For $d = 1 to $connectpeers step 1
  318. $error = False
  319. $rndarray = Random( 1, $peers[0], 1)
  320. if $peers[$rndarray] = "" or $peers[$rndarray] = " " then ContinueLoop
  321. For $u = 0 to $max_connections step 1 ;checks to see if already connected
  322. if $peers[$rndarray] = $Node_IP_array[$u] then
  323. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Bootstrap: connectee already connected! reselecting...")
  324. $error = True
  325. ExitLoop
  326. EndIf
  327. Next
  328. if $error = True then ContinueLoop
  329. _P2P_Connect( $peers[$rndarray])
  330. Next
  331. EndFunc
  332. Func peer_broadcast()
  333. $peer_timer = TimerInit()
  334. local $peers = ""
  335. local $IDLIST = ""
  336. For $a = 0 to $max_connections step 1
  337. if $Node_IP_array[$a] <> -1 then $peers &= $Node_IP_array[$a] & ";"
  338. if $Node_Identifier_array[$a] <> -1 then $IDLIST &= $Node_Identifier_array[$a] & ";"
  339. Next
  340. _P2P_Broadcast( "#8i8#PEER#" & $peers)
  341. _P2P_Broadcast( "#8i8#IDLIST#" & $IDLIST)
  342. EndFunc
  343. Func peer_broadcast_to_peer( $socket)
  344. local $peers = ""
  345. local $IDLIST = ""
  346. For $a = 0 to $max_connections step 1
  347. if $Node_IP_array[$a] <> -1 then $peers &= $Node_IP_array[$a] & ";"
  348. if $Node_Identifier_array[$a] <> -1 then $IDLIST &= $Node_Identifier_array[$a] & ";"
  349. Next
  350. TCPSend( $socket, "#8i8#PEER#" & $peers & "#8i8TERMINATE#")
  351. TCPSend( $socket, "#8i8#IDLIST#" & $IDLIST & "#8i8TERMINATE#")
  352. EndFunc
  353. Func Route_Message( $Socket, $Message, $array_slot) ;process long distance messages
  354. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing started")
  355. local $timer = TimerInit()
  356. local $split = StringSplit( $Message, "#")
  357. if $split[0] < 6 then return 1
  358. Local $ttl = $split[4]
  359. Local $address = $split[5]
  360. Local $identifier = $split[6]
  361. Local $begin = "#8i8#MESSAGE#" & $ttl & "#" & $address & "#" & $identifier & "#"
  362. Local $cutlen = StringLen( $Message) - StringLen( $begin)
  363. if idknown( $split[6]) = True then ;Have we seen it before? if yes-Terminate.
  364. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message-ID known.")
  365. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  366. return 1
  367. EndIf
  368. if $address = $node_Identifier then ;Is it for us? if yes-deliever.
  369. local $messagetrim = StringRight( $Message, $cutlen)
  370. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message-Inbound")
  371. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  372. call( $messagefunc, $Socket, $messagetrim, 0)
  373. return 1
  374. EndIf
  375. if $ttl = 0 then ;Is it too old? if yes-Terminate.
  376. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message-TTL Exceeded.")
  377. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  378. return 1
  379. EndIf
  380. ;Time to route the message.
  381. $messagefull = "#8i8#MESSAGE#" & ($ttl-1) & "#" & $address & "#" & $identifier & "#" & StringRight( $Message, $cutlen)
  382. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Starting First level Routing: " & $total_connected)
  383. For $qwe = 0 to $max_connections step 1 ;Send if we are directly connected to the destination.
  384. if $address = $Node_Identifier_array[$qwe] then
  385. _P2P_Send( $Socket_Handle_array[$qwe], $messagefull)
  386. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message-Destination located.")
  387. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  388. return 1
  389. EndIf
  390. Next
  391. if $Socket = -1 Then ;If we created the message: Flood to all peers
  392. _P2P_Broadcast( $messagefull)
  393. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  394. return 1
  395. Else ;Or check every peer to see if it is connected to destination.
  396. For $qwe = 0 to $max_connections step 1 ;See if our peers are connected to the destination.
  397. if $Socket_Handle_array[$qwe] = -1 then ContinueLoop
  398. if StringInStr( $Node_Peer_Reachable_List[$qwe], $address) > 0 Then
  399. _P2P_Send( $Socket_Handle_array[$qwe], $messagefull)
  400. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message-2nd Level destination located. ")
  401. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  402. return 1
  403. EndIf
  404. Next
  405. EndIf
  406. For $qwe = 0 to $max_connections step 1 ;So the destination is not reachable within two levels. Time to pass it on. Don't pass it on to sender or sender's peers.
  407. if $Socket_Handle_array[$qwe] = -1 then ContinueLoop
  408. if $node_Identifier_array[$qwe] = $node_Identifier_array[$array_slot] then ContinueLoop
  409. if StringInStr( $Node_Peer_Reachable_List[$array_slot], $node_Identifier_array[$qwe]) > 0 Then ContinueLoop
  410. _P2P_Send( $Socket_Handle_array[$qwe], $messagefull)
  411. Next
  412. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message##########Routing Finished: " & Round( TimerDiff( $timer), 1))
  413. EndFunc
  414. ; #FUNCTION# ;===============================================================================
  415. ;
  416. ; Name...........: _P2P_Send_Message
  417. ; Description ...: Sends a long range message to a peer somewhere in the network.
  418. ; Syntax.........: _P2P_Send_Message( $Identifier, $data)
  419. ; Parameters ....: $Identifier - The node Identifier/ID/Address of the destination.
  420. ; $Data - Data/Message to send.
  421. ; Return values .:
  422. ; Author ........: Hyperzap
  423. ; Modified.......:
  424. ; Remarks .......: This, as opposed to the _P2P_Send function, will send a message to the
  425. ; destination regardless of whether they are connected or not, That is, you need
  426. ; not be directly TCP connected to someone for the message to reach them. This
  427. ; System works making your message 'hop' from node to node until one knows where
  428. ; your destination is. At that point, it is sent directly to the destination To
  429. ; be unpacked and processed.Please note that there is no way to know if the message
  430. ; reached it's destination, but if it is in range and online it will reach it
  431. ; 99.5% of the time.
  432. ; Related .......:
  433. ; Link ..........;
  434. ; Example .......;
  435. ;
  436. ; ;==========================================================================================
  437. Func _P2P_Send_Message( $IDaddress, $INdata)
  438. local $messageID = Round( ((Random( 0, 99999999999, 1)*@YDAY)/@MIN)*(Random(5, 1376, 1)/(@SEC*100)), 0) ;As random as it'l ever get.
  439. local $ttl = $STANDARD_MESSAGE_LIFE
  440. local $fullmessage = "#8i8#MESSAGE#" & $ttl & "#" & $IDaddress & "#" & $messageID & "#" & $INdata & "#8i8TERMINATE#"
  441. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Message generated: " & $messageID)
  442. Route_Message( -1, $fullmessage, -1)
  443. EndFunc
  444. Func idknown ($ID)
  445. for $IDcount = 0 to $total_ID_known step 1
  446. if $Known_ID[$IDcount] = $ID then Return True
  447. Next
  448. $total_ID_known += 1
  449. if $total_ID_known > 198 then $total_ID_known = 0
  450. $Known_ID[$total_ID_known] = $ID
  451. return False
  452. EndFunc
  453. ; #FUNCTION# ;===============================================================================
  454. ;
  455. ; Name...........: _P2P_Send
  456. ; Description ...: Sends data to a peer.
  457. ; Syntax.........: _P2P_Send( $Socket, $Data)
  458. ; Parameters ....: $Socket - peer socket handle.
  459. ; $Data - Data to send.
  460. ; Return values .:
  461. ; Author ........: Hyperzap
  462. ; Modified.......:
  463. ; Remarks .......: This UDF will automatically keep your individual messages separate, So
  464. ; Don't worry about adding delays or message-split-buffer systems.
  465. ; Related .......:
  466. ; Link ..........;
  467. ; Example .......;
  468. ;
  469. ; ;==========================================================================================
  470. Func _P2P_Send( $Socket, $Data)
  471. TCPSend( $Socket, $Data & "#8i8TERMINATE#")
  472. EndFunc
  473. ; #FUNCTION# ;===============================================================================
  474. ;
  475. ; Name...........: _P2P_Disconnect_Peer
  476. ; Description ...: Disconnects a peer (someone your connected to) from the system.
  477. ; Syntax.........: _P2P_Disconnect_Peer($Socket)
  478. ; Parameters ....: $Socket - Socket of peer.
  479. ; Return values .: Success - True
  480. ; Failure - False
  481. ; Author ........: Hyperzap
  482. ; Modified.......:
  483. ; Remarks .......: The peer socket ($Socket) is the socket handler of ANY peer connected.
  484. ; Related .......:
  485. ; Link ..........;
  486. ; Example .......;
  487. ;
  488. ; ;==========================================================================================
  489. Func _P2P_Disconnect_Peer( $socket)
  490. local $it_socket = ""
  491. local $array_slot = ""
  492. For $count = 0 to $max_connections step 1
  493. if $Socket_Handle_array[$count] = $socket then
  494. $it_socket = $socket
  495. $array_slot = $count
  496. ExitLoop
  497. EndIf
  498. Next
  499. if $it_socket = "" then return False
  500. ___ASockShutdown($it_socket)
  501. TCPCloseSocket($it_socket)
  502. $Socket_Handle_array[$Array_Slot] = -1
  503. $Node_Identifier_array[$Array_Slot] = -1
  504. $Node_IP_array[$Array_Slot] = -1
  505. $Node_Peer_Reachable_list[$Array_Slot] = -1
  506. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Peer " & $it_socket & " closed.")
  507. return true
  508. EndFunc
  509. ; #FUNCTION# ;===============================================================================
  510. ;
  511. ; Name...........: _P2P_Connect
  512. ; Description ...: Initiates a new connection to another node.
  513. ; Syntax.........: __P2P_Connect( $Conn_IP)
  514. ; Parameters ....: $Conn_IP - The IP address to connect to.
  515. ; Return values .: 0, 1, 2, 3 indicate failure due to criteria. Listen to the
  516. ; _P2P_Register_Event( $P2P_CONNECT etc to determine if it connected or not.
  517. ; Author ........: Hyperzap
  518. ; Modified.......:
  519. ; Remarks .......:
  520. ; Related .......:
  521. ; Link ..........;
  522. ; Example .......;
  523. ;
  524. ; ;==========================================================================================
  525. Func _P2P_Connect( $Conn_IP)
  526. For $u = 0 to $max_connections step 1 ;checks to see if already connected
  527. if $Conn_IP = $Node_IP_array[$u] then
  528. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Unable to connect-IP is already connected!")
  529. return 1
  530. EndIf
  531. Next
  532. if $Conn_IP = "" then Return 0
  533. if $Conn_IP = " " then Return 0
  534. if $Conn_IP = "0" then Return 0
  535. if $Conn_IP = ";" then Return 0
  536. if $Conn_IP = @CRLF then Return 0
  537. $arrayslot = Findfreearrayslot()
  538. if $arrayslot = "error" then
  539. if $Listening_Socket = "" Then
  540. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Unable to connect-node services offline!")
  541. Return 3
  542. EndIf
  543. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Unable to connect-peer limit reached!")
  544. return 2 ;no free slots to put your new connection!
  545. EndIf
  546. if $console_out = True then ConsoleWrite( @CRLF & "P2P_: Attempting Connection: " & $Conn_IP)
  547. local $SocketID = ___ASocket()
  548. ___ASockSelect( $SocketID, $__TCP_WINDOW, 0x400 + $arrayslot, BitOR( $FD_CONNECT, $FD_READ, $FD_CLOSE))
  549. GUIRegisterMsg( 0x400 + $arrayslot, "Opensocket_data_" )
  550. $Socket_Handle_array[$arrayslot] = $SocketID
  551. $Node_Identifier_array[$arrayslot] = -1
  552. $Node_IP_array[$arrayslot] = $Conn_IP
  553. $return = ___ASockConnect( $SocketID, $Conn_IP, $node_Port )
  554. $total_connected += 1
  555. If @extended Then
  556. if $console_out = True then ConsoleWrite( @CRLF & "_P2P: Connection Established.")
  557. Call( $connectfunc, $SocketID, 0);connected immediately!
  558. EndIf
  559. EndFunc
  560. ; #FUNCTION# ;===============================================================================
  561. ;
  562. ; Name...........: _P2P_Broadcast
  563. ; Description ...: Sends data to all connected peers.
  564. ; Syntax.........: _P2P_Broadcast($Data)
  565. ; Parameters ....: $Data - The data to send.
  566. ; Return values .: True
  567. ; Author ........: Hyperzap
  568. ; Modified.......:
  569. ; Remarks .......:
  570. ; Related .......:
  571. ; Link ..........;
  572. ; Example .......;
  573. ;
  574. ; ;==========================================================================================
  575. Func _P2P_Broadcast($Data)
  576. Local $i
  577. For $i = 0 to $max_connections step 1
  578. If $Socket_Handle_array[$i] <> -1 Then TCPSend($Socket_Handle_array[$i], $Data & "#8i8TERMINATE#")
  579. Next
  580. Return True
  581. EndFunc
  582. ; #FUNCTION# ;===============================================================================
  583. ;
  584. ; Name...........: _P2P_Peerlist
  585. ; Description ...: Returns the sockets, IDs, and IPs of all connected peers.
  586. ; Syntax.........: _P2P_Peerlist()
  587. ; Parameters ....:
  588. ; Return values .: A 3 dimensional array of all connected peers. The first spot in the array,
  589. ; AKA [0][0] defines the number of connected peers. The remaining spots
  590. ; In the array are the actual peers in the format of dimension [0] socket
  591. ; handle, [1] ID, and [2] IP. So the first peer will be [1][0], [1][1]. [1][2]
  592. ; and the second [2][0], [2][1], [2][2] etc.
  593. ; Author ........: Hyperzap
  594. ; Modified.......:
  595. ; Remarks .......:
  596. ; Related .......:
  597. ; Link ..........;
  598. ; Example .......;
  599. ;
  600. ; ;==========================================================================================
  601. Func _P2P_Peerlist()
  602. Local $aList[$max_connections+1][3], $alist_count = 1
  603. For $i = 1 to $max_connections
  604. If $Socket_Handle_array[$i] <> -1 Then
  605. $aList[$alist_count][0] = $Socket_Handle_array[$i]
  606. $aList[$alist_count][1] = $Node_Identifier_array[$i]
  607. $aList[$alist_count][2] = $Node_IP_array[$i]
  608. $alist_count += 1
  609. EndIf
  610. Next
  611. $aList[0][0] = $alist_count
  612. Return $alist
  613. EndFunc
  614. ; #FUNCTION# ;===============================================================================
  615. ;
  616. ; Name...........: _P2P_Register_Event
  617. ; Description ...: Registers an event.So, if I register my function "ant" with the event
  618. ; $P2P_RECEIVE, it will look like: _P2P_Register_Event($P2P_RECEIVE, "ant").
  619. ; It will mean my function 'ant' will get called with the specified parameters
  620. ; (see below) when data is recieved.
  621. ; Syntax.........: _P2P_Register_Event($iEvent, $sFunction)
  622. ; Parameters ....: $iEvent - Event number. It can be any these values:
  623. ; Event number This is the required syntax of YOUR called function
  624. ; $P2P_AUX_DATA ; Function ($hSocket, $DataType, $Data)
  625. ;When things like IP and Node identifier are discovered.
  626. ; $P2P_MESSAGE ; Function ($hSocket, $message, $from, $iError)
  627. ;When long distance messages are recieved.
  628. ; $P2P_RECEIVE ; Function ($hSocket, $sReceived, $iError)
  629. ;When data is recieved directly from a connected peer.
  630. ; $P2P_CONNECT ; Function ($hSocket, $iError)
  631. ;This is called when an attempted connection is successful or unsuccessful.
  632. ; $P2P_DISCONNECT ; Function ($hSocket, $iError)
  633. ;This is called whenever a peer disconnects from you.
  634. ; $P2P_NEWCONNECTION ; Function ($hSocket, $iError)
  635. ;This is called whenever a peer connects to you.
  636. ; Return values .: Success - True
  637. ; Failure - False
  638. ; Author ........: Kip
  639. ; Modified.......: Hyperzap
  640. ; Remarks .......:
  641. ; Related .......:
  642. ; Link ..........;
  643. ; Example .......;
  644. ;
  645. ; ;==========================================================================================
  646. Func _P2P_Register_Event($iEvent, $sFunction)
  647. if $iEvent = $P2P_AUX_DATA then $auxfunc = $sFunction
  648. if $iEvent = $P2P_RECEIVE then $recievefunc = $sFunction
  649. if $iEvent = $P2P_CONNECT then $connectfunc = $sFunction
  650. if $iEvent = $P2P_DISCONNECT then $disconnectfunc = $sFunction
  651. if $iEvent = $P2P_NEWCONNECTION then $newconnectionfunc = $sFunction
  652. if $iEvent = $P2P_MESSAGE then $messagefunc = $sFunction
  653. EndFunc
  654. ;==================================================================================================================
  655. ;
  656. ; Zatorg's Asynchronous Sockets UDF Starts from here.
  657. ;
  658. ;==================================================================================================================
  659. Func ___ASocket($iAddressFamily = 2, $iType = 1, $iProtocol = 6)
  660. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  661. Local $hSocket = DllCall($hWs2_32, "uint", "socket", "int", $iAddressFamily, "int", $iType, "int", $iProtocol)
  662. If @error Then
  663. SetError(1, @error)
  664. Return -1
  665. EndIf
  666. If $hSocket[ 0 ] = -1 Then
  667. SetError(2, ___WSAGetLastError())
  668. Return -1
  669. EndIf
  670. Return $hSocket[ 0 ]
  671. EndFunc ;==>_ASocket
  672. Func ___ASockShutdown($hSocket)
  673. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  674. Local $iRet = DllCall($hWs2_32, "int", "shutdown", "uint", $hSocket, "int", 2)
  675. If @error Then
  676. SetError(1, @error)
  677. Return False
  678. EndIf
  679. If $iRet[ 0 ] <> 0 Then
  680. SetError(2, ___WSAGetLastError())
  681. Return False
  682. EndIf
  683. Return True
  684. EndFunc ;==>_ASockShutdown
  685. Func ___ASockClose($hSocket)
  686. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  687. Local $iRet = DllCall($hWs2_32, "int", "closesocket", "uint", $hSocket)
  688. If @error Then
  689. SetError(1, @error)
  690. Return False
  691. EndIf
  692. If $iRet[ 0 ] <> 0 Then
  693. SetError(2, ___WSAGetLastError())
  694. Return False
  695. EndIf
  696. Return True
  697. EndFunc ;==>_ASockClose
  698. Func ___ASockSelect($hSocket, $hWnd, $uiMsg, $iEvent)
  699. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  700. Local $iRet = DllCall( _
  701. $hWs2_32, _
  702. "int", "WSAAsyncSelect", _
  703. "uint", $hSocket, _
  704. "hwnd", $hWnd, _
  705. "uint", $uiMsg, _
  706. "int", $iEvent _
  707. )
  708. If @error Then
  709. SetError(1, @error)
  710. Return False
  711. EndIf
  712. If $iRet[ 0 ] <> 0 Then
  713. SetError(2, ___WSAGetLastError())
  714. Return False
  715. EndIf
  716. Return True
  717. EndFunc ;==>_ASockSelect
  718. ; Note: you can see that $iMaxPending is set to 5 by default.
  719. ; IT DOES NOT MEAN THAT DEFAULT = 5 PENDING CONNECTIONS
  720. ; 5 == SOMAXCONN, so don't worry be happy
  721. Func ___ASockListen($hSocket, $sIP, $uiPort, $iMaxPending = 5); 5 == SOMAXCONN => No need to change it.
  722. Local $iRet
  723. Local $stAddress
  724. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  725. $stAddress = ___SockAddr($sIP, $uiPort)
  726. If @error Then
  727. SetError(@error, @extended)
  728. Return False
  729. EndIf
  730. $iRet = DllCall($hWs2_32, "int", "bind", "uint", $hSocket, "ptr", DllStructGetPtr($stAddress), "int", DllStructGetSize($stAddress))
  731. If @error Then
  732. SetError(3, @error)
  733. Return False
  734. EndIf
  735. If $iRet[ 0 ] <> 0 Then
  736. $stAddress = 0; Deallocate
  737. SetError(4, ___WSAGetLastError())
  738. Return False
  739. EndIf
  740. $iRet = DllCall($hWs2_32, "int", "listen", "uint", $hSocket, "int", $iMaxPending)
  741. If @error Then
  742. SetError(5, @error)
  743. Return False
  744. EndIf
  745. If $iRet[ 0 ] <> 0 Then
  746. $stAddress = 0; Deallocate
  747. SetError(6, ___WSAGetLastError())
  748. Return False
  749. EndIf
  750. Return True
  751. EndFunc ;==>_ASockListen
  752. Func ___ASockConnect($hSocket, $sIP, $uiPort)
  753. Local $iRet
  754. Local $stAddress
  755. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  756. $stAddress = ___SockAddr($sIP, $uiPort)
  757. If @error Then
  758. SetError(@error, @extended)
  759. Return False
  760. EndIf
  761. $iRet = DllCall($hWs2_32, "int", "connect", "uint", $hSocket, "ptr", DllStructGetPtr($stAddress), "int", DllStructGetSize($stAddress))
  762. If @error Then
  763. SetError(3, @error)
  764. Return False
  765. EndIf
  766. $iRet = ___WSAGetLastError()
  767. If $iRet = 10035 Then; WSAEWOULDBLOCK
  768. Return True; Asynchronous connect attempt has been started.
  769. EndIf
  770. SetExtended(1); Connected immediately
  771. Return True
  772. EndFunc ;==>_ASockConnect
  773. ; A wrapper function to ease all the pain in creating and filling the sockaddr struct
  774. Func ___SockAddr($sIP, $iPort, $iAddressFamily = 2)
  775. Local $iRet
  776. Local $stAddress
  777. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  778. $stAddress = DllStructCreate("short; ushort; uint; char[8]")
  779. If @error Then
  780. SetError(1, @error)
  781. Return False
  782. EndIf
  783. DllStructSetData($stAddress, 1, $iAddressFamily)
  784. $iRet = DllCall($hWs2_32, "ushort", "htons", "ushort", $iPort)
  785. DllStructSetData($stAddress, 2, $iRet[ 0 ])
  786. $iRet = DllCall($hWs2_32, "uint", "inet_addr", "str", $sIP)
  787. If $iRet[ 0 ] = 0xffffffff Then; INADDR_NONE
  788. $stAddress = 0; Deallocate
  789. SetError(2, ___WSAGetLastError())
  790. Return False
  791. EndIf
  792. DllStructSetData($stAddress, 3, $iRet[ 0 ])
  793. Return $stAddress
  794. EndFunc ;==>__SockAddr
  795. Func ___WSAGetLastError()
  796. If $hWs2_32 = -1 Then $hWs2_32 = DllOpen( "Ws2_32.dll" )
  797. Local $iRet = DllCall($hWs2_32, "int", "WSAGetLastError")
  798. If @error Then
  799. ;if $console_out = True then ConsoleWrite("+> _WSAGetLastError(): WSAGetLastError() failed. Script line number: " & @ScriptLineNumber & @CRLF)
  800. SetExtended(1)
  801. Return 0
  802. EndIf
  803. Return $iRet[ 0 ]
  804. EndFunc ;==>_WSAGetLastError
  805. ; Got these here:
  806. ; http://www.autoitscript.com/forum/index.php?showtopic=5620&hl=MAKELONG
  807. Func ___MakeLong($LoWord, $HiWord)
  808. Return BitOR($HiWord * 0x10000, BitAND($LoWord, 0xFFFF)); Thanks Larry
  809. EndFunc ;==>_MakeLong
  810. Func ___HiWord($Long)
  811. Return BitShift($Long, 16); Thanks Valik
  812. EndFunc ;==>_HiWord
  813. Func ___LoWord($Long)
  814. Return BitAND($Long, 0xFFFF); Thanks Valik
  815. EndFunc ;==>_LoWord
  816. ;----------------------------------OTHER AUTOIT INBUILT FUNCS----##
  817. ;===============================================================================
  818. ;
  819. ; Function Name: _GetIP()
  820. ; Description: Get public IP address of a network/computer.
  821. ; Parameter(s): None
  822. ; Requirement(s): Internet access.
  823. ; Return Value(s): On Success - Returns the public IP Address
  824. ; On Failure - -1 and sets @ERROR = 1
  825. ; Author(s): Larry/Ezzetabi & Jarvis Stubblefield
  826. ;
  827. ;===============================================================================
  828. Func _Get_IP()
  829. Local $ip, $t_ip
  830. If InetGet("http://checkip.dyndns.org/?rnd1=" & Random(1, 65536) & "&rnd2=" & Random(1, 65536), @TempDir & "\~ip.tmp") Then
  831. $ip = FileRead(@TempDir & "\~ip.tmp", FileGetSize(@TempDir & "\~ip.tmp"))
  832. FileDelete(@TempDir & "\~ip.tmp")
  833. $ip = StringTrimLeft($ip, StringInStr($ip, ":") + 1)
  834. $ip = StringTrimRight($ip, StringLen($ip) - StringInStr($ip, "/") + 2)
  835. $t_ip = StringSplit($ip, '.')
  836. If $t_ip[0] = 4 And StringIsDigit($t_ip[1]) And StringIsDigit($t_ip[2]) And StringIsDigit($t_ip[3]) And StringIsDigit($t_ip[4]) Then
  837. Return $ip
  838. EndIf
  839. EndIf
  840. If InetGet("http://www.whatismyip.com/?rnd1=" & Random(1, 65536) & "&rnd2=" & Random(1, 65536), @TempDir & "\~ip.tmp") Then
  841. $ip = FileRead(@TempDir & "\~ip.tmp", FileGetSize(@TempDir & "\~ip.tmp"))
  842. FileDelete(@TempDir & "\~ip.tmp")
  843. $ip = StringTrimLeft($ip, StringInStr($ip, "Your ip is") + 10)
  844. $ip = StringLeft($ip, StringInStr($ip, " ") - 1)
  845. $ip = StringStripWS($ip, 8)
  846. $t_ip = StringSplit($ip, '.')
  847. If $t_ip[0] = 4 And StringIsDigit($t_ip[1]) And StringIsDigit($t_ip[2]) And StringIsDigit($t_ip[3]) And StringIsDigit($t_ip[4]) Then
  848. Return $ip
  849. EndIf
  850. EndIf
  851. SetError(1)
  852. Return -1
  853. EndFunc ;==>_Get_IP

comments powered by Disqus