title: PYTHON - socket management
body: <p>I'm trying to implement a multi-ping code in python, but the problem is that in the following code both the sockets I defined seems to receive the SAME PACKET from the SAME DESTINATION! Why does it happen? O.o</p>
  
  <p>------------------- UPDATE -------------------</p>
  
  <p>I noticed that the received packet is always the "most fast" one [that is the one with the smaller RTT]! For example:</p>
  
  <pre><code>dests_list = ['173.194.41.70','213.92.16.101'] -&gt; DEST: 173.194.41.70
  dests_list = ['213.92.16.101','173.194.41.70'] -&gt; DEST: 173.194.41.70
  dests_list = ['213.92.16.191','95.141.47.7'] -&gt; DEST: 213.92.16.191
  </code></pre>
  
  <p>with:</p>
  
  <pre><code>RTT_213.92.16.191=20ms  RTT_173.194.41.70=8ms  RTT_95.141.47.7=28ms
  </code></pre>
  
  <p>------------------- UPDATE -------------------</p>
  
  <p>CODE --> [at the end of the post there's a downloadable version to avoid formatting issues]</p>
  
  <pre><code>#!/usr/bin/python
  # -*- coding: utf-8 -*-
  
  from exceptions import Exception
  import random
  import select
  import socket
  import struct
  import sys
  import time
  
  ICMP_ECHO_REQUEST = 8  # Seems to be the same on Solaris.
  PACKET_SIZE = 32
  IS_WIN = False
  my_socket_list = []
  dests_list = ['173.194.41.70','213.92.16.101']
  N_DESTS = 2
  seq_num = 1
  
  #----------------------------------------------------------------------------------------#
  #----&gt; CHECKSUM: calculate checksum
  #----------------------------------------------------------------------------------------#
  
  def checksum(source_string):
      """
      I'm not too confident that this is right but testing seems
      to suggest that it gives the same answers as in_cksum in ping.c
      """
  
      sum = 0
      countTo = len(source_string) / 2 * 2
      count = 0
      while count &lt; countTo:
          thisVal = ord(source_string[count + 1]) * 256 + ord(source_string[count])
          sum = sum + thisVal
          sum = sum &amp; 0xffffffff  # Necessary?
          count = count + 2
  
      if countTo &lt; len(source_string):
          sum = sum + ord(source_string[len(source_string) - 1])
          sum = sum &amp; 0xffffffff  # Necessary?
  
      sum = (sum &gt;&gt; 16) + (sum &amp; 65535)
      sum = sum + (sum &gt;&gt; 16)
      answer = ~sum
      answer = answer &amp; 65535
  
      # Swap bytes. Bugger me if I know why.
  
      answer = answer &gt;&gt; 8 | answer &lt;&lt; 8 &amp; 0xff00
  
      return answer
  
  
  #----------------------------------------------------------------------------------------#
  #----&gt; RECEIVE PINGS: polling on all open sockets
  #----------------------------------------------------------------------------------------#
  
  def receive_pings():
      """
      Receive the ping from the socket.
      """
  
      whatReady = select.select(my_socket_list, [], [], 1000)
  
          if whatReady[0] != []:
          print whatReady[0]
          for skt in whatReady[0]:
  
              # time evaluation 
              if IS_WIN:
                  timeReceived = time.clock()
              else:
                  timeReceived = time.time()
  
              # get datas
              (recPacket, addr) = skt.recvfrom(PACKET_SIZE + 64)
              icmpHeader = recPacket[20:28]
              (type, code, checksum, packetID, sequence) = struct.unpack('bbHHh', icmpHeader)
              print addr
              if type == 0:
              bytesInDouble = struct.calcsize('d')
              timeSent = struct.unpack('d', recPacket[28:28 + bytesInDouble])[0]
              print "DEST: %s - RTT: %s"%(addr[0],str(timeReceived-timeSent))
             elif type == 3:
              codes = {
                          0: 'Net Unreachable',
                      1: 'Host Unreachable',
                      2: 'Protocol Unreachable',
                  3: 'Port Unreachable',
                  }
              raise Exception(codes[code])
              break
  
  
  #----------------------------------------------------------------------------------------#
  #----&gt; SEND PING
  #----------------------------------------------------------------------------------------#
  
  def send_one_ping(my_socket, dest_addr, ID):
  
      # Header is type (8bit), code (8bit), checksum (16bit), id (16bit), sequence (16bit)
  
      my_checksum = 0
  
      # Make a dummy heder with a 0 checksum.
  
      header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, my_checksum, ID, 1)
      bytesInDouble = struct.calcsize('d')
      data = (PACKET_SIZE - len(header) - bytesInDouble) * 'x'
  
      if IS_WIN:
          start = time.clock()
      else:
          start = time.time()
  
      data = struct.pack('d', start) + data
  
      # Calculate the checksum on the data and the dummy header.
  
      my_checksum = checksum(header + data)
  
      # Now that we have the right checksum, we put that in. It's just easier
      # to make up a new header than to stuff it into the dummy.
  
      header = struct.pack('bbHHh', ICMP_ECHO_REQUEST, 0, socket.htons(my_checksum), ID, 1)
      packet = header + data
      print my_socket 
      while packet:
          sent = my_socket.sendto(packet, (dest_addr, 1))  # Don't know about the 1
          packet = packet[sent:]      
          print "PING SENT TO %s"%dest_addr 
  
  
  #----------------------------------------------------------------------------------------#
  #----&gt; DO ONE: socket creation and ping sending
  #----------------------------------------------------------------------------------------#
  
  def send_pings():
  
      i = 1
      for skt in my_socket_list:
          print i
          send_one_ping(skt, dests_list[i-1], i)
          i+=1
  
      seq_num=+1
  
  
  #----------------------------------------------------------------------------------------#
  #----&gt; SCHEDULE PING: open socket towards a specific destination
  #----------------------------------------------------------------------------------------#
  
  def sockets_opening(Ndests):
      try:
  
          if sys.platform[0:-2] == 'win':
                  IS_WIN = True
          else:
                  IS_WIN = False
  
          for i in range(0,Ndests):
              icmp = socket.getprotobyname('icmp')
              my_socket_list.append(socket.socket(socket.AF_INET, socket.SOCK_RAW,icmp))
              print "O2: %s"%my_socket_list[i]
  
      except socket.error, (errno, msg):
          if errno == 1:      # operation not permitted
              msg = msg + ' - Note that ICMP messages can only be sent from processes running as root.'
                  raise socket.error(msg)
              raise   # raise the original error
  
  def sockets_closing():
      try:
          for skt in my_socket_list:
              print "C2: %s"%skt      
              skt.close()
      except socket.error, (errno, msg):
          print "ERR:%d -&gt; %s"%(errno,msg)        
          raise
  
  #----------------------------------------------------------------------------------------#
  #----&gt; MAIN
  #----------------------------------------------------------------------------------------#
  
  if __name__ == '__main__':
      print
      sockets_opening(N_DESTS)
      send_pings()
      #time.sleep(3)
      receive_pings()
      sockets_closing()
  </code></pre>
  
  <p>OUTPUT--></p>
  
  <pre><code>CREATED-SOCKETS:[&lt;socket._socketobject object at 0xb7267df4&gt;, &lt;socket._socketobject object at 0xb7267e2c&gt;]
  
  PING SENT TO 173.194.41.70
  PING SENT TO 213.92.16.101
  
  READY-SOCKETS:[&lt;socket._socketobject object at 0xb7267df4&gt;, &lt;socket._socketobject object at 0xb7267e2c&gt;]
  DEST: 173.194.41.70 - RTT: 0.00797414779663
  DEST: 173.194.41.70 - RTT: 0.00811314582825
  
  C2: &lt;socket._socketobject object at 0xb7267df4&gt;
  C2: &lt;socket._socketobject object at 0xb7267e2c&gt;
  </code></pre>
  
  <p>CODE LINK: <a href="https://www.dropbox.com/s/90wjfd3saz4xurj/PingSKT.py" rel="nofollow">PingSKT.py</a></p>