github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/p2p/handshake.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package p2p
    18  
    19  import "fmt"
    20  import "bytes"
    21  
    22  //import "net"
    23  import "sync/atomic"
    24  import "time"
    25  
    26  //import "container/list"
    27  
    28  //import log "github.com/sirupsen/logrus"
    29  //import "github.com/allegro/bigcache"
    30  import "github.com/romana/rlog"
    31  import "github.com/vmihailenco/msgpack"
    32  
    33  import "github.com/deroproject/derosuite/config"
    34  import "github.com/deroproject/derosuite/globals"
    35  
    36  //import "github.com/deroproject/derosuite/blockchain"
    37  
    38  // reads our data, length prefix blocks
    39  func (connection *Connection) Send_Handshake(request bool) {
    40  
    41  	var handshake Handshake_Struct
    42  
    43  	fill_common(&handshake.Common) // fill common info
    44  	handshake.Command = V2_COMMAND_HANDSHAKE
    45  	handshake.Request = request
    46  
    47  	// TODO these version strings should be setup during build
    48  	// original protocol in c daemon should be called version 1
    49  	// the new version is version 2
    50  	handshake.ProtocolVersion = "1.0.0"
    51  	handshake.DaemonVersion = config.Version.String()
    52  	handshake.Tag = node_tag
    53  	handshake.UTC_Time = int64(time.Now().UTC().Unix()) // send our UTC time
    54  	handshake.Local_Port = uint32(P2P_Port)             // export requested or default port
    55  	handshake.Peer_ID = GetPeerID()                     // give our randomly generated peer id
    56  	if globals.Arguments["--lowcpuram"].(bool) == false {
    57  		handshake.Flags = append(handshake.Flags, FLAG_LOWCPURAM) // add low cpu ram flag
    58  	}
    59  
    60  	//scan our peer list and send peers which have been recently communicated
    61  	handshake.PeerList = get_peer_list()
    62  	copy(handshake.Network_ID[:], globals.Config.Network_ID[:])
    63  
    64  	// serialize and send
    65  	serialized, err := msgpack.Marshal(&handshake)
    66  	if err != nil {
    67  		panic(err)
    68  	}
    69  
    70  	rlog.Tracef(2, "handshake sent  %s", globals.CTXString(connection.logger))
    71  	connection.Send_Message(serialized)
    72  }
    73  
    74  // verify incoming handshake for number of checks such as mainnet/testnet etc etc
    75  func (connection *Connection) Verify_Handshake(handshake *Handshake_Struct) bool {
    76  	return bytes.Equal(handshake.Network_ID[:], globals.Config.Network_ID[:])
    77  }
    78  
    79  // handles both server and client connections
    80  func (connection *Connection) Handle_Handshake(buf []byte) {
    81  
    82  	var handshake Handshake_Struct
    83  
    84  	err := msgpack.Unmarshal(buf, &handshake)
    85  	if err != nil {
    86  		rlog.Warnf("Error while decoding incoming handshake request err %s %s", err, globals.CTXString(connection.logger))
    87  		connection.Exit()
    88  		return
    89  	}
    90  
    91  	if !connection.Verify_Handshake(&handshake) { // if not same network boot off
    92  		connection.logger.Debugf("kill connection network id mismatch peer network id %x", handshake.Network_ID)
    93  		connection.Exit()
    94  		return
    95  	}
    96  
    97  	rlog.Tracef(2, "handshake response received %+v  %s", handshake, globals.CTXString(connection.logger))
    98          
    99          // check if self connection exit
   100          if connection.Incoming && handshake.Peer_ID == GetPeerID(){
   101              rlog.Tracef(1,"Same peer ID, probably self connection, disconnecting from this client")
   102              connection.Exit()
   103              return
   104          }
   105          
   106  
   107  	if handshake.Request {
   108  		connection.Send_Handshake(false) // send it as response
   109  	}
   110  	if !connection.Incoming { // setup success
   111  		Peer_SetSuccess(connection.Addr.String())
   112  	}
   113  
   114  	connection.Update(&handshake.Common) // update common information
   115  
   116  	if atomic.LoadUint32(&connection.State) == HANDSHAKE_PENDING { // some of the fields are processed only while initial handshake
   117  		connection.Lock()
   118  		if len(handshake.ProtocolVersion) < 128 {
   119  			connection.ProtocolVersion = handshake.ProtocolVersion
   120  		}
   121  
   122  		if len(handshake.DaemonVersion) < 128 {
   123  			connection.DaemonVersion = handshake.DaemonVersion
   124  		}
   125  		connection.Port = handshake.Local_Port
   126  		connection.Peer_ID = handshake.Peer_ID
   127  		if len(handshake.Tag) < 128 {
   128  			connection.Tag = handshake.Tag
   129  		}
   130  
   131  		// TODO we must also add the peer to our list
   132  		// which can be distributed to other peers
   133  		if connection.Port != 0 && connection.Port <= 65535 { // peer is saying it has an open port, handshake is success so add peer
   134  
   135  			var p Peer
   136  			if connection.Addr.IP.To4() != nil { // if ipv4
   137                              p.Address = fmt.Sprintf("%s:%d", connection.Addr.IP.String(), connection.Port)
   138                          }else{ // if ipv6
   139                              p.Address = fmt.Sprintf("[%s]:%d", connection.Addr.IP.String(), connection.Port)
   140                          }
   141  			p.ID = connection.Peer_ID
   142  
   143  			p.LastConnected = 0 // uint64(time.Now().UTC().Unix())
   144  
   145  			/* TODO we should add any flags here if necessary, but they are not
   146  			   required, since a peer can only be used if connected and if connected
   147  			   we already have a truly synced view
   148  			 for _, k := range handshake.Flags {
   149  				switch k {
   150  				case FLAG_MINER:
   151  					p.Miner = true
   152  				}
   153  			}*/
   154  
   155  			Peer_Add(&p)
   156  		}
   157  
   158  		for _, k := range handshake.Flags {
   159  			switch k {
   160  			case FLAG_LOWCPURAM:
   161  				connection.Lowcpuram = true
   162  
   163  				//connection.logger.Debugf("Miner flag \"%s\" from peer", k)
   164  			default:
   165  				connection.logger.Debugf("Unknown flag \"%s\" from peer, ignoring", k)
   166  
   167  			}
   168  
   169  		}
   170  
   171  		// do NOT build TX cache, if we are runnin in lowcpu mode
   172  		if globals.Arguments["--lowcpuram"].(bool) == true { // if connection is not running in low cpu mode and we are also same, activate transaction cache
   173  			connection.TXpool_cache = nil
   174  		} else { // we do not have any limitation, activate per peer cache
   175  			connection.TXpool_cache = map[uint64]uint32{}
   176  
   177  		}
   178  		connection.Unlock()
   179  	}
   180  
   181  	// parse delivered peer list as grey list
   182  	rlog.Debugf("Peer provides %d peers", len(handshake.PeerList))
   183  	for i := range handshake.PeerList {
   184  		Peer_Add(&Peer{Address: handshake.PeerList[i].Addr})
   185  	}
   186  
   187  	atomic.StoreUint32(&connection.State, ACTIVE)
   188  	if connection.Incoming {
   189  		Connection_Add(connection)
   190  	}
   191  }