Jump to content

nullschritt
 Share

Recommended Posts

Hello, I am re-releasing hyperzap's Event Driven P2P UDF with some modifications.

Thanks to hyperzap for the original UDF.
 
New Features

  • Dynamic RegEx Headers/Footers
  • Supports Messages of Any Length (Including file transfers) [automatically]
  • Allows use of all symbols/letters in messages*

Pre-Modification Features

  • Relays messages over P2P network
  • Delivers messages to client only machines [that cannot port forward]
  • BootStrapping (optional) [Automatically connect to more peers]
  • Even Driven
  • LAN or WAN Mode
  • FAST (Takes 5-50ms per hop)

Known Limitations

  • Does not relay messages when emulated on linux with WINE. (still receives and sends messages)

* = You CANNOT use the "`" symbol in long range messages. To support this symbol, please replace it with it's html entity, urlencode, or use the INCLUDED _base64encode function on data you want to send long range.
 


How it works:
##################
When you start the UDF, it will start listening and accepting incoming connections. The UDF will, in the backround, continue to manage all your connections and initiate any new ones should you use the _P2P_Connect( IP) function. It will also manage the recieving and sending of data.
As a P2P node should, it will route data destined for others, and it will also maintain a healthy number of connections (the number which you define when you start the node).

This entire system is event driven, so you will register your functions with the UDF and the function will get called when the corresponding event happens. See the comments in the UDF for more information.
This works in the same way as Kip's TCP UDF.


Structure:
##################
The first thing you must do is start the Node:
_P2P_Start_Node( Node Identifier, Port, Max peers, Bootstrap mode, Bootstrap max, local/global, IP)

All the Parameters are pretty self expanatory. The Node identifier is the name of your computer in the network. It must not change across sessions and it must be unique. It is used to identify you in your network.

Bootstrapping means autoconnecting. if Bootstrap mode is 1, It will autoconnect you to others until you reach your Bootstrap Max.

Local/Global - Put 0 if working on a LAN, 1 if over internet.

IP - (Optional). You shouldn't need to change this. It is the IP of the listening port.

The second thing is declare your functions. This tells the UDF which functions to call when something happens. EG:
_P2P_Register_Event($P2P_RECEIVE, "my_recieve_function")
So, this will call the function my_recieve_function when data from a peer is recieved. See the comments at the beginning of the UDF for a complete list of Event values, and the parameters for your functions.

Then fire away!
_P2P_Send( $socket, "MY DATA!!)
_P2P_Connect( "127.0.0.1")
_P2P_Broadcast( "My data")

When your done,

_P2P_Stop_Node()

The UDF:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author:         Hyperzap.
 Modified By: NullSchritt (Stormageddon)
                 Design concepts were first coined by Kip in his "Event driven TCP UDF"
                 Zatorg's Asynchronous Sockets UDF is also used.
 Script Function:
 
    This UDF is a re-write of Kip's 'Event driven TCP UDF'. Thx Kip.
    It aims to generate simple TCP, event driven functionality for P2P programs, As
    opposed to client-server oriented communication as in Kip's UDF.
    Evidently, this functionality is not possible in Kips original releases.
    
    Apart from the obvious conponents of such a code, like Recv, Send, Connect,
    Listen, other important P2P routines have been coded. These include things 
    like; Universal identifiers, bootstrapping mechanisms, peers
    discovery, and message routing.
    
    MINOR DRAWBACKS:
    You must replace "`" in messages with it's html entity or some other 
    symbol during long range message routing.
#ce ----------------------------------------------------------------------------

$UDF_Version = "1.33 STABLE"
$console_out = False
$STANDARD_MESSAGE_LIFE = 200
#cs
Functions:

    _P2P_Start_Node( Node Identifier, Port, Max peers, Bootstrap mode, Boostrap max, local/global, IP)
    _P2P_Stop_Node()
    _P2P_Connect( IP)
    _P2P_Send( Socket, Data)
    _P2P_Disconnect_Peer( Socket)
    _P2P_Send_Message( Address, Data)
    
    _P2P_Register_Event($iEvent, $sFunction)


Register event values:

    $P2P_AUX_DATA           ; Function ($hSocket, $DataType, $Data);When things like IP and Node identifier are discovered.
    $P2P_MESSAGE            ; Function ($hSocket, $message, $iError) ;When long distance messages are recieved.
    $P2P_RECEIVE            ; Function ($hSocket, $sReceived, $iError)
    $P2P_CONNECT            ; Function ($hSocket, $iError)                  
    $P2P_DISCONNECT         ; Function ($hSocket, $iError)
    $P2P_NEWCONNECTION      ; Function ($hSocket, $iError) 



   Also, please call the function  peer_broadcast() periodically in your program. Failing to do this will
   Seriously cripple the bootstrapping mechanism (unless you program is ALWAYS recieving data at least once
   every 40 seconds, In which case the mechanism will trigger automatically).
#ce

Global Const $fd_read = 1
Global Const $fd_write = 2
Global Const $fd_oob = 4
Global Const $fd_accept = 8
Global Const $fd_connect = 16
Global Const $fd_close = 32
Global $hws2_32 = -1
Global Const $tcp_send = 1
Global Const $tcp_receive = 2
Global Const $tcp_connect = 4
Global Const $tcp_disconnect = 8
Global Const $tcp_newclient = 16
Global Const $iploc_local = 64
Global Const $iploc_global = 128
Global Const $p2p_message = 256
Global Const $p2p_receive = 512
Global Const $p2p_connect = 1024
Global Const $p2p_disconnect = 2048
Global Const $p2p_newconnection = 4096
Global Const $p2p_aux_data = 8192
Global $total_connected = 0
Global $max_connections
Global $listening_socket
Global $node_ip
Global $node_port
Global $node_identifier
Global $node_ext_ip
Global $bootstrap_mode
Global $bootstrap_max
Global $peer_timer
Global $total_id_known = 0
Global $known_id[200]
Global $connectfunc = ""
Global $recievefunc = ""
Global $disconnectfunc = ""
Global $newconnectionfunc = ""
Global $messagefunc = ""
Global $auxfunc = ""
Global $main_socket_address = ""
TCPStartup()
Global Const $__tcp_window = GUICreate("Async Sockets UDF")

Func _p2p_start_node($node_id, $port, $max_peers, $bootstrapmode, $bootstrapmax, $location, $ip = "0.0.0.0")
    Local $startuptimer = TimerInit()
    $listening_socket = ___asocket()
    $main_socket_address = $listening_socket
    ___asockselect($listening_socket, $__tcp_window, 1024, $fd_accept)
    GUIRegisterMsg(1024, "Listensocket_data_")
    ___asocklisten($listening_socket, $ip, $port)
    If $bootstrapmode = 0 Then $bootstrap_mode = $iploc_local
    If $bootstrapmode = 1 Then $bootstrap_mode = $iploc_global
    $bootstrap_max = $bootstrapmax
    $max_connections = $max_peers
    $node_ip = $ip
    $node_port = $port
    $node_identifier = $node_id
    $peer_timer = TimerInit()
    If $location = 1 Then $node_ext_ip = _get_ip()
    If $location = 0 Then $node_ext_ip = @IPAddress1
    Global $socket_handle_array[$max_peers + 1]
    Global $node_identifier_array[$max_peers + 1]
    Global $node_ip_array[$max_peers + 1]
    Global $node_peer_reachable_list[$max_peers + 1]
    For $x = 0 To $max_peers Step 1
        $socket_handle_array[$x] = -1
        $node_identifier_array[$x] = -1
        $node_ip_array[$x] = -1
        $node_peer_reachable_list[$x] = -1
    Next
    If $console_out = True Then ConsoleWrite(@CRLF & @CRLF & "P2P_: Node started")
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Port: " & $node_port)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Ext IP: " & $node_ext_ip)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Max peers: " & $max_connections)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Identifier: " & $node_identifier)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Engine Version: " & $udf_version)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Startup time: " & TimerDiff($startuptimer) & "ms" & @CRLF)
EndFunc

Func _p2p_stop_node()
    ___asockshutdown($listening_socket)
    TCPCloseSocket($listening_socket)

        $socket_handle_array= -1
        $node_identifier_array= -1
        $node_ip_array= -1
        $node_peer_reachable_list= -1
    $max_connections = 0
    $listening_socket = ""
    $node_ip = ""
    $node_port = ""
    $node_identifier = -1
    $node_ext_ip = ""
    $bootstrap_mode = ""
    $bootstrap_max = 0
    $connectfunc = ""
    $recievefunc = ""
    $disconnectfunc = ""
    $newconnectionfunc = ""
    $messagefunc = ""
    $auxfunc = ""
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Engine shutdown successful.")
EndFunc

Func listensocket_data_($hwnd, $imsgid, $wparam, $lparam)
    Local $socketinquestion = $wparam
    Local $ierror = ___hiword($lparam)
    Local $ievent = ___loword($lparam)
    Abs($hwnd)
    If $imsgid = 1024 Then
        If $ievent = $fd_accept Then
            If NOT $ierror Then
                $arrayslot = findfreearrayslot()
                If $arrayslot = "error" Then
                    $newsocket = TCPAccept($socketinquestion)
                    TCPSend($newsocket, "`" & _generateheader(2) & "`NOSLOT`" & _generateheader(1))
                    TCPCloseSocket($newsocket)
                EndIf
                $newsocket = TCPAccept($socketinquestion)
                ___asockselect($newsocket, $__tcp_window, 1024 + $arrayslot, BitOR($fd_read, $fd_connect, $fd_close))
                GUIRegisterMsg(1024 + $arrayslot, "Opensocket_data_")
                $socket_handle_array[$arrayslot] = $newsocket
                $node_identifier_array[$arrayslot] = -1
                $node_ip_array[$arrayslot] = -1
                TCPSend($newsocket, "`" & "`IP`" & $node_ext_ip & _generateheader(1))
                TCPSend($newsocket, "`" & "`ID`" & $node_identifier & _generateheader(1))
                peer_broadcast_to_peer($newsocket)
                $total_connected += 1
                Call($newconnectionfunc, $newsocket, $ierror)
            Else
                Call($newconnectionfunc, 0, $ierror)
            EndIf
        ElseIf $ievent = $fd_connect Then
            Call($connectfunc, $newsocket, $ierror)
        EndIf
    EndIf
EndFunc

Func _generateheader($type = 1)
    $alpha = StringSplit("PRODY", "", 3)
    $str = ""
    If $type = 1 Then
        $str = "--P2P:"
        For $i = 1 To 5
            $str &= Random(0, 9, 1) & $alpha[Random(0, 4, 1)]
        Next
        Return $str
    EndIf
    If $type = 2 Then
        $str = "--P2P:"
        For $i = 1 To 5
            $str &= $alpha[Random(0, 4, 1)] & Random(0, 9, 1)
        Next
        Return $str
    EndIf
EndFunc

Func findfreearrayslot()
    $newconnnum = -1
    For $x = 1 To $max_connections
        If $socket_handle_array[$x] = -1 Then
            $newconnnum = $x
            ExitLoop
        EndIf
    Next
    If $newconnnum = -1 Then Return "error"
    Return $newconnnum
EndFunc

Func opensocket_data_($hwnd, $imsgid, $wparam, $lparam)
    Local $ierror = ___hiword($lparam)
    Local $ievent = ___loword($lparam)
    Abs($hwnd)
    Local $array_slot = $imsgid - 1024
    Local $socketid = $socket_handle_array[$array_slot]
    If $socketid = -1 Then Return 0
    Switch $ievent
        Case $fd_read
            $rawrecv = TCPRecv($socketid, 2048)
            If $rawrecv <> "" Then
                $regex = StringRegExp($rawrecv, "--P2P:([0-9](.*?)[PRODY]){5}", 2)
                If IsArray($regex) Then
                    $rawrecv = StringReplace($rawrecv, $regex[0], "")
                    recvprocess($rawrecv, $socketid, $array_slot, $ierror)
                Else
                    $dre = 0
                    Do
                        $recvtmp = TCPRecv($socketid, 2048)
                        If $recvtmp = "" Then
                            ExitLoop
                        EndIf
                        $rawrecv &= $recvtmp
                        $regex = StringRegExp($rawrecv, "--P2P:([0-9](.*?)[PRODY]){5}", 2)
                        Sleep(1)
                    Until IsArray($regex)
                    If IsArray($regex) Then
                        $rawrecv = StringReplace($rawrecv, $regex[0], "")
                        recvprocess($rawrecv, $socketid, $array_slot, $ierror)
                    EndIf
                EndIf
            EndIf
        Case $fd_close
            ___asockshutdown($socketid)
            TCPCloseSocket($socketid)
            Call($disconnectfunc, $socketid, $ierror)
            $socket_handle_array[$array_slot] = -1
            $node_identifier_array[$array_slot] = -1
            $node_ip_array[$array_slot] = -1
            $node_peer_reachable_list[$array_slot] = -1
            $total_connected -= 1
            If TimerDiff($peer_timer) > 40000 Then
                peer_broadcast()
            EndIf
        Case $fd_connect
            If $ierror Then
                If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Connection failed: " & $socketid)
                $socket_handle_array[$array_slot] = -1
                $node_identifier_array[$array_slot] = -1
                $node_ip_array[$array_slot] = -1
                $node_peer_reachable_list[$array_slot] = -1
                $total_connected -= 1
                Call($connectfunc, $socketid, $ierror)
            Else
                Call($connectfunc, $socketid, $ierror)
                If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Connection established: " & $socketid)
                TCPSend($socket_handle_array[$array_slot], "`" & "`IP`" & $node_ext_ip & _generateheader(1))
                TCPSend($socket_handle_array[$array_slot], "`" & "`ID`" & $node_identifier & _generateheader(1))
                peer_broadcast_to_peer($socket_handle_array[$array_slot])
            EndIf
            If TimerDiff($peer_timer) > 40000 Then
                peer_broadcast()
            EndIf
    EndSwitch
EndFunc

Func recvprocess($rawrecv, $socketid, $array_slot, $ierror)
    If StringLen($rawrecv) < 1 Then Return 0
    $regex = StringRegExp($rawrecv, "--P2P:([0-9](.*?)[PRODY]){5}", 2)
    If IsArray($regex) Then
        Local $single_data = StringSplit($rawrecv, $regex[0], 1)
    Else
        Local $single_data = $rawrecv
    EndIf
    If UBound($single_data) < 1 Then Return 
    For $k = 1 To $single_data[0] Step 1
        If $single_data[$k] = "" Then ContinueLoop
        If $single_data[$k] = " " Then ContinueLoop
        If StringRegExp($single_data[$k], "--P2P:([PRODY](.*?)[0-9]){5}") Then
            node_data_process($socketid, $single_data[$k], $array_slot, $ierror)
        Else
            Call($recievefunc, $socketid, $single_data[$k], $ierror)
        EndIf
    Next
    If TimerDiff($peer_timer) > 40000 Then
        peer_broadcast()
    EndIf
EndFunc

Func node_data_process($socketid, $data, $array_slot, $ierror)
    Local $split = StringSplit($data, "`")
    If $split[3] = "IP" Then
        $node_ip_array[$array_slot] = $split[4]
        Call($auxfunc, $socketid, "IP", $split[4])
    EndIf
    If $split[3] = "ID" Then
        $node_identifier_array[$array_slot] = $split[4]
        Call($auxfunc, $socketid, "ID", $split[4])
    EndIf
    If $split[3] = "PEER" Then bootstrap($socketid, $split[4], $array_slot, $ierror)
    If $split[3] = "IDLIST" Then
        $node_peer_reachable_list[$array_slot] = $split[4]
        Call($auxfunc, $socketid, "NODE-REACHABLE", $split[4])
    EndIf
    If $split[3] = "MESSAGE" Then
        route_message($socketid, $data, $array_slot)
    EndIf
EndFunc

Func bootstrap($socketid, $split, $array_slot, $ierror)
    If $bootstrap_mode = $iploc_local Then Return 9
    If $total_connected >= $bootstrap_max Then Return 8
    Local $connectpeers = Round(($bootstrap_max / $total_connected / 2), 0)
    If $connectpeers < $bootstrap_max AND $connectpeers = 0 Then $connectpeers = 1
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Bootstrap stats: " & $connectpeers & ":" & $total_connected & "/" & $bootstrap_max)
    $peers = StringSplit($split, ";")
    For $d = 1 To $connectpeers Step 1
        $error = False
        $rndarray = Random(1, $peers[0], 1)
        If $peers[$rndarray] = "" OR $peers[$rndarray] = " " Then ContinueLoop
        For $u = 0 To $max_connections Step 1
            If $peers[$rndarray] = $node_ip_array[$u] Then
                If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Bootstrap: connectee already connected! reselecting...")
                $error = True
                ExitLoop
            EndIf
        Next
        If $error = True Then ContinueLoop
        _p2p_connect($peers[$rndarray])
    Next
EndFunc

Func peer_broadcast()
    $peer_timer = TimerInit()
    Local $peers = ""
    Local $idlist = ""
    For $a = 0 To $max_connections Step 1
        If $node_ip_array[$a] <> -1 Then $peers &= $node_ip_array[$a] & ";"
        If $node_identifier_array[$a] <> -1 Then $idlist &= $node_identifier_array[$a] & ";"
    Next
    _p2p_broadcast("`" & _generateheader(2) & "`PEER`" & $peers)
    _p2p_broadcast("`" & _generateheader(2) & "`IDLIST`" & $idlist)
EndFunc

Func peer_broadcast_to_peer($socket)
    Local $peers = ""
    Local $idlist = ""
    For $a = 0 To $max_connections Step 1
        If $node_ip_array[$a] <> -1 Then $peers &= $node_ip_array[$a] & ";"
        If $node_identifier_array[$a] <> -1 Then $idlist &= $node_identifier_array[$a] & ";"
    Next
    TCPSend($socket, "`" & _generateheader(2) & "`PEER`" & $peers & _generateheader(1))
    TCPSend($socket, "`" & _generateheader(2) & "`IDLIST`" & $idlist & _generateheader(1))
EndFunc

Func route_message($socket, $message, $array_slot)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: MessageRouting started")
    Local $timer = TimerInit()
    Local $split = StringSplit($message, "`")
    If $split[0] < 6 Then Return 1
    Local $ttl = $split[4]
    Local $from = $split[5]
    Local $address = $split[6]
    Local $identifier = $split[7]
    Local $begin = "`" & _generateheader(2) & "`MESSAGE`" & $ttl & "`" & $from & "`" & $address & "`" & $identifier & "`"
    Local $cutlen = StringLen($message) - StringLen($begin)
    If idknown($split[7]) = True Then
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message-ID known.")
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
        Return 1
    EndIf
    If $address = $node_identifier Then
        Local $messagetrim = StringRight($message, $cutlen)
        Local $messagetrim = StringRight($message, $cutlen)
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message-Inbound")
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
        Call($messagefunc, $socket, $messagetrim, $from, 0)
        Return 1
    EndIf
    If $ttl = 0 Then
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message-TTL Exceeded.")
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
        Return 1
    EndIf
    $messagefull = "`" & _generateheader(2) & "`MESSAGE`" & ($ttl - 1) & "`" & $from & "`" & $address & "`" & $identifier & "`" & StringRight($message, $cutlen)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Starting First level Routing: " & $total_connected)
    For $qwe = 0 To $max_connections Step 1
        If $address = $node_identifier_array[$qwe] Then
            _p2p_send($socket_handle_array[$qwe], $messagefull)
            If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message-Destination located.")
            If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
            Return 1
        EndIf
    Next
    If $socket = -1 Then
        _p2p_broadcast($messagefull)
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
        Return 1
    Else
        For $qwe = 0 To $max_connections Step 1
            If $socket_handle_array[$qwe] = -1 Then ContinueLoop
            If StringInStr($node_peer_reachable_list[$qwe], $address) > 0 Then
                _p2p_send($socket_handle_array[$qwe], $messagefull)
                If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message-2nd Level destination located. ")
                If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
                Return 1
            EndIf
        Next
    EndIf
    For $qwe = 0 To $max_connections Step 1
        If $socket_handle_array[$qwe] = -1 Then ContinueLoop
        If $node_identifier_array[$qwe] = $node_identifier_array[$array_slot] Then ContinueLoop
        If StringInStr($node_peer_reachable_list[$array_slot], $node_identifier_array[$qwe]) > 0 Then ContinueLoop
        _p2p_send($socket_handle_array[$qwe], $messagefull)
    Next
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message Routing Finished: " & Round(TimerDiff($timer), 1))
EndFunc

Func _p2p_send_message($idaddress, $indata, $from = "Null")
    Local $messageid = Round(((Random(0, 99999999999, 1) * @YDAY) / @MIN) * (Random(5, 1376, 1) / (@SEC * 100)), 0)
    Local $ttl = $standard_message_life
    Local $fullmessage = "`" & _generateheader(2) & "`MESSAGE`" & $ttl & "`" & $from & "`" & $idaddress & "`" & $messageid & "`" & $indata & _generateheader(1)
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Message generated: " & $messageid)
    route_message(-1, $fullmessage, -1)
EndFunc

Func idknown($id)
    For $idcount = 0 To $total_id_known Step 1
        If $known_id[$idcount] = $id Then Return True
    Next
    $total_id_known += 1
    If $total_id_known > 198 Then $total_id_known = 0
    $known_id[$total_id_known] = $id
    Return False
EndFunc

Func _p2p_send($socket, $data)
    TCPSend($socket, $data & _generateheader(1))
EndFunc

Func _p2p_disconnect_peer($socket)
    Local $it_socket = ""
    Local $array_slot = ""
    For $count = 0 To $max_connections Step 1
        If $socket_handle_array[$count] = $socket Then
            $it_socket = $socket
            $array_slot = $count
            ExitLoop
        EndIf
    Next
    If $it_socket = "" Then Return False
    ___asockshutdown($it_socket)
    TCPCloseSocket($it_socket)
    $socket_handle_array[$array_slot] = -1
    $node_identifier_array[$array_slot] = -1
    $node_ip_array[$array_slot] = -1
    $node_peer_reachable_list[$array_slot] = -1
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Peer " & $it_socket & " closed.")
    Return True
EndFunc

Func _p2p_connect($conn_ip)
    For $u = 0 To $max_connections Step 1
        If $conn_ip = $node_ip_array[$u] Then
            If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Unable to connect-IP is already connected!")
            Return 1
        EndIf
    Next
    If $conn_ip = "" Then Return 0
    If $conn_ip = " " Then Return 0
    If $conn_ip = "0" Then Return 0
    If $conn_ip = ";" Then Return 0
    If $conn_ip = @CRLF Then Return 0
    $arrayslot = findfreearrayslot()
    If $arrayslot = "error" Then
        If $listening_socket = "" Then
            If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Unable to connect-node services offline!")
            Return 3
        EndIf
        If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Unable to connect-peer limit reached!")
        Return 2
    EndIf
    If $console_out = True Then ConsoleWrite(@CRLF & "P2P_: Attempting Connection: " & $conn_ip)
    Local $socketid = ___asocket()
    ___asockselect($socketid, $__tcp_window, 1024 + $arrayslot, BitOR($fd_connect, $fd_read, $fd_close))
    GUIRegisterMsg(1024 + $arrayslot, "Opensocket_data_")
    $socket_handle_array[$arrayslot] = $socketid
    $node_identifier_array[$arrayslot] = -1
    $node_ip_array[$arrayslot] = $conn_ip
    $return = ___asockconnect($socketid, $conn_ip, $node_port)
    $total_connected += 1
    If @extended Then
        If $console_out = True Then ConsoleWrite(@CRLF & "_P2P: Connection Established.")
        Call($connectfunc, $socketid, 0)
    EndIf
EndFunc

Func _p2p_broadcast($data)
    Local $i
    For $i = 0 To $max_connections Step 1
        If $socket_handle_array[$i] <> -1 Then TCPSend($socket_handle_array[$i], $data & _generateheader(1))
    Next
    Return True
EndFunc

Func _p2p_peerlist()
    Local $alist[$max_connections + 1][3], $alist_count = 1
    For $i = 1 To $max_connections
        If $socket_handle_array[$i] <> -1 Then
            $alist[$alist_count][0] = $socket_handle_array[$i]
            $alist[$alist_count][1] = $node_identifier_array[$i]
            $alist[$alist_count][2] = $node_ip_array[$i]
            $alist_count += 1
        EndIf
    Next
    $alist[0][0] = $alist_count
    Return $alist
EndFunc

Func _p2p_register_event($ievent, $sfunction)
    If $ievent = $p2p_aux_data Then $auxfunc = $sfunction
    If $ievent = $p2p_receive Then $recievefunc = $sfunction
    If $ievent = $p2p_connect Then $connectfunc = $sfunction
    If $ievent = $p2p_disconnect Then $disconnectfunc = $sfunction
    If $ievent = $p2p_newconnection Then $newconnectionfunc = $sfunction
    If $ievent = $p2p_message Then $messagefunc = $sfunction
EndFunc

Func ___asocket($iaddressfamily = 2, $itype = 1, $iprotocol = 6)
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    Local $hsocket = DllCall($hws2_32, "uint", "socket", "int", $iaddressfamily, "int", $itype, "int", $iprotocol)
    If @error Then
        SetError(1, @error)
        Return -1
    EndIf
    If $hsocket[0] = -1 Then
        SetError(2, ___wsagetlasterror())
        Return -1
    EndIf
    Return $hsocket[0]
EndFunc

Func ___asockshutdown($hsocket)
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    Local $iret = DllCall($hws2_32, "int", "shutdown", "uint", $hsocket, "int", 2)
    If @error Then
        SetError(1, @error)
        Return False
    EndIf
    If $iret[0] <> 0 Then
        SetError(2, ___wsagetlasterror())
        Return False
    EndIf
    Return True
EndFunc

Func ___asockclose($hsocket)
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    Local $iret = DllCall($hws2_32, "int", "closesocket", "uint", $hsocket)
    If @error Then
        SetError(1, @error)
        Return False
    EndIf
    If $iret[0] <> 0 Then
        SetError(2, ___wsagetlasterror())
        Return False
    EndIf
    Return True
EndFunc

Func ___asockselect($hsocket, $hwnd, $uimsg, $ievent)
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    Local $iret = DllCall($hws2_32, "int", "WSAAsyncSelect", "uint", $hsocket, "hwnd", $hwnd, "uint", $uimsg, "int", $ievent)
    If @error Then
        SetError(1, @error)
        Return False
    EndIf
    If $iret[0] <> 0 Then
        SetError(2, ___wsagetlasterror())
        Return False
    EndIf
    Return True
EndFunc

Func ___asocklisten($hsocket, $sip, $uiport, $imaxpending = 5)
    Local $iret
    Local $staddress
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    $staddress = ___sockaddr($sip, $uiport)
    If @error Then
        SetError(@error, @extended)
        Return False
    EndIf
    $iret = DllCall($hws2_32, "int", "bind", "uint", $hsocket, "ptr", DllStructGetPtr($staddress), "int", DllStructGetSize($staddress))
    If @error Then
        SetError(3, @error)
        Return False
    EndIf
    If $iret[0] <> 0 Then
        $staddress = 0
        SetError(4, ___wsagetlasterror())
        Return False
    EndIf
    $iret = DllCall($hws2_32, "int", "listen", "uint", $hsocket, "int", $imaxpending)
    If @error Then
        SetError(5, @error)
        Return False
    EndIf
    If $iret[0] <> 0 Then
        $staddress = 0
        SetError(6, ___wsagetlasterror())
        Return False
    EndIf
    Return True
EndFunc

Func ___asockconnect($hsocket, $sip, $uiport)
    Local $iret
    Local $staddress
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    $staddress = ___sockaddr($sip, $uiport)
    If @error Then
        SetError(@error, @extended)
        Return False
    EndIf
    $iret = DllCall($hws2_32, "int", "connect", "uint", $hsocket, "ptr", DllStructGetPtr($staddress), "int", DllStructGetSize($staddress))
    If @error Then
        SetError(3, @error)
        Return False
    EndIf
    $iret = ___wsagetlasterror()
    If $iret = 10035 Then
        Return True
    EndIf
    SetExtended(1)
    Return True
EndFunc

Func ___sockaddr($sip, $iport, $iaddressfamily = 2)
    Local $iret
    Local $staddress
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    $staddress = DllStructCreate("short; ushort; uint; char[8]")
    If @error Then
        SetError(1, @error)
        Return False
    EndIf
    DllStructSetData($staddress, 1, $iaddressfamily)
    $iret = DllCall($hws2_32, "ushort", "htons", "ushort", $iport)
    DllStructSetData($staddress, 2, $iret[0])
    $iret = DllCall($hws2_32, "uint", "inet_addr", "str", $sip)
    If $iret[0] = -1 Then
        $staddress = 0
        SetError(2, ___wsagetlasterror())
        Return False
    EndIf
    DllStructSetData($staddress, 3, $iret[0])
    Return $staddress
EndFunc

Func ___wsagetlasterror()
    If $hws2_32 = -1 Then $hws2_32 = DllOpen("Ws2_32.dll")
    Local $iret = DllCall($hws2_32, "int", "WSAGetLastError")
    If @error Then
        SetExtended(1)
        Return 0
    EndIf
    Return $iret[0]
EndFunc

Func ___makelong($loword, $hiword)
    Return BitOR($hiword * 65536, BitAND($loword, 65535))
EndFunc

Func ___hiword($long)
    Return BitShift($long, 16)
EndFunc

Func ___loword($long)
    Return BitAND($long, 65535)
EndFunc

Func _get_ip()
    Local $ip, $t_ip
    If InetGet("http://checkip.dyndns.org/?rnd1=" & Random(1, 65536) & "&rnd2=" & Random(1, 65536), @TempDir & "\~ip.tmp") Then
        $ip = FileRead(@TempDir & "\~ip.tmp", FileGetSize(@TempDir & "\~ip.tmp"))
        FileDelete(@TempDir & "\~ip.tmp")
        $ip = StringTrimLeft($ip, StringInStr($ip, ":") + 1)
        $ip = StringTrimRight($ip, StringLen($ip) - StringInStr($ip, "/") + 2)
        $t_ip = StringSplit($ip, ".")
        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
            Return $ip
        EndIf
    EndIf
    If InetGet("http://www.whatismyip.com/?rnd1=" & Random(1, 65536) & "&rnd2=" & Random(1, 65536), @TempDir & "\~ip.tmp") Then
        $ip = FileRead(@TempDir & "\~ip.tmp", FileGetSize(@TempDir & "\~ip.tmp"))
        FileDelete(@TempDir & "\~ip.tmp")
        $ip = StringTrimLeft($ip, StringInStr($ip, "Your ip is") + 10)
        $ip = StringLeft($ip, StringInStr($ip, " ") - 1)
        $ip = StringStripWS($ip, 8)
        $t_ip = StringSplit($ip, ".")
        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
            Return $ip
        EndIf
    EndIf
    SetError(1)
    Return -1
EndFunc

Func _base64decode($data)
    Local $opcode = "0xC81000005356578365F800E8500000003EFFFFFF3F3435363738393A3B3C3DFFFFFF00FFFFFF000102030405060708090A0B0C0D0E0F10111213141516171819FFFFFFFFFFFF1A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132338F45F08B7D0C8B5D0831D2E9910000008365FC00837DFC047D548A034384C0750383EA033C3D75094A803B3D75014AB00084C0751A837DFC047D0D8B75FCC64435F400FF45FCEBED6A018F45F8EB1F3C2B72193C7A77150FB6F083EE2B0375F08A068B75FC884435F4FF45FCEBA68D75F4668B06C0E002C0EC0408E08807668B4601C0E004C0EC0208E08847018A4602C0E00624C00A46038847028D7F038D5203837DF8000F8465FFFFFF89D05F5E5BC9C21000"
    Local $codebuffer = DllStructCreate("byte[" & BinaryLen($opcode) & "]")
    DllStructSetData($codebuffer, 1, $opcode)
    Local $ouput = DllStructCreate("byte[" & BinaryLen($data) & "]")
    Local $ret = DllCall("user32.dll", "int", "CallWindowProc", "ptr", DllStructGetPtr($codebuffer), "str", $data, "ptr", DllStructGetPtr($ouput), "int", 0, "int", 0)
    Return BinaryMid(DllStructGetData($ouput, 1), 1, $ret[0])
EndFunc

Func _base64encode($data, $linebreak = 76)
    Local $opcode = "0x5589E5FF7514535657E8410000004142434445464748494A4B4C4D4E4F505152535455565758595A6162636465666768696A6B6C6D6E6F707172737475767778797A303132333435363738392B2F005A8B5D088B7D108B4D0CE98F0000000FB633C1EE0201D68A06880731C083F901760C0FB6430125F0000000C1E8040FB63383E603C1E60409C601D68A0688470183F90176210FB6430225C0000000C1E8060FB6730183E60FC1E60209C601D68A06884702EB04C647023D83F90276100FB6730283E63F01D68A06884703EB04C647033D8D5B038D7F0483E903836DFC04750C8B45148945FC66B80D0A66AB85C90F8F69FFFFFFC607005F5E5BC9C21000"
    Local $codebuffer = DllStructCreate("byte[" & BinaryLen($opcode) & "]")
    DllStructSetData($codebuffer, 1, $opcode)
    $data = Binary($data)
    Local $input = DllStructCreate("byte[" & BinaryLen($data) & "]")
    DllStructSetData($input, 1, $data)
    $linebreak = Floor($linebreak / 4) * 4
    Local $oputputsize = Ceiling(BinaryLen($data) * 4 / 3)
    $oputputsize = $oputputsize + Ceiling($oputputsize / $linebreak) * 2 + 4
    Local $ouput = DllStructCreate("char[" & $oputputsize & "]")
    DllCall("user32.dll", "none", "CallWindowProc", "ptr", DllStructGetPtr($codebuffer), "ptr", DllStructGetPtr($input), "int", BinaryLen($data), "ptr", DllStructGetPtr($ouput), "uint", $linebreak)
    Return DllStructGetData($ouput, 1)
EndFunc 

 
Usage Example:
P2Ptest.au3

Edited by nullschritt
Link to comment
Share on other sites

Hi this looks interesting.

Can you aid me a boost in the right direction?

Is lets say I develop a app for voting (poll) 

Do I setup my client as the destination and then give out my WAN and PORT to the peers and this way they build a list of peers?

Also I plan on using SQLite for the voting so I guess the peers need to build a voting list?

?

All nodes act as both a server and a client. You can easily build a simple server node though. The server node needs to simply be running on the same port as the node in your program. In your program enable bootstrapping. Whenever a new pc connects to this server, it will notify all connected clients of the new peer, and they will all try to connect.

You can always resolve a hostname to an ip address, and attempt to connect to it automatically with your code. You could also ask the user for an ip if that fails, or try a pre-generated list of other ip addresses.

If you want to make a pure peer-to-peer voting system, and want each node to store the votes in a sqlite file you will need to do two things.

1)Make a way to verify votes. This is to ensure a user doesnt send false votes into the network, or edit it into the file.

2)Make an update system for clients who have not been online. (Allow these clients to ask any other clients for any vote info they dont already have)

Link to comment
Share on other sites

  • 2 months later...

Hi!

i have a problem :/

if i try to run P2PTest.au3, it throws me "Problem connection attempt: " and a number, every time i connect (press d)

if i turn on the debug on the UDF, it says: "P2P_: Connection failed: " and the same number.

The twitchyliquid64's udf works fine in my computer.

What can i do to fix the problem?

Link to comment
Share on other sites

  • 3 months later...

Hi!

i have a problem :/

if i try to run P2PTest.au3, it throws me "Problem connection attempt: " and a number, every time i connect (press d)

if i turn on the debug on the UDF, it says: "P2P_: Connection failed: " and the same number.

The twitchyliquid64's udf works fine in my computer.

What can i do to fix the problem?

It's probably because the bootstrapper has already connected you in this case.

Try pressing e to send some data. (with console out on)

Edited by nullschritt
Link to comment
Share on other sites

  • 2 weeks later...

Just for the general public, I would put the bug you are having into the first post of this UDF -- >link

"I am having this same problem with the Event Driven P2P script based off this script, it's not sendign the data as packets, it's simply cutting off the string when it's send over a network connection, locally there is no limit for TCPSend, but it seems that over a network connection, only so many bytes can be transferred at once."

As I'm seeing people looking for the same thing, this could save someone a lot of time testing your code.. :)

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

  • 2 months later...

Can you use _P2P_Connect($ip) to connect to some peers also? If so would you call it for each one or can you only call the _P2P_Connect($ip) function 1 time?

Thanks in advance for any informatin on this.

 

Every time you are trying to make a connection you call the connect function. But, please see the below quote as this could create errors; This whole library is based off a library that the author said not to use, just FYI :)>link

 

"I am having this same problem with the Event Driven P2P script based off this script, it's not sendign the data as packets, it's simply cutting off the string when it's send over a network connection, locally there is no limit for TCPSend, but it seems that over a network connection, only so many bytes can be transferred at once."

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

My pleasure ;)

What were you doing before?

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

Have you had a look at Kealper's TCP server example by chance? >link

very nice way of doing a TCP server.

Snips & Scripts


My Snips: graphCPUTemp ~ getENVvars
My Scripts: Short-Order Encrypter - message and file encryption V1.6.1 ~ AuPad - Notepad written entirely in AutoIt V1.9.4

Feel free to use any of my code for your own use.                                                                                                                                                           Forum FAQ

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...