Search code examples
pythonpingicmp

"Test Failed: unsupported operand type(s) for +: 'int' and 'tuple'"


i keep having a problem in my code coming back as Test Failed: unsupported operand type(s) for +: 'int' and 'tuple'.

i am a super beginner who is not very good at coding, so i cannot figure out what the issue is.

here is the full code.

i am making a simple icmp pinger program.

thanks everyone for your help!!! (this is my first question here so please let me know if i need to edit anything)

from socket import *
import os
import sys
import struct
import time
import select
import statistics
import binascii

# Should use stdev

ICMP_ECHO_REQUEST = 8


def checksum(string):
   csum = 0
   countTo = (len(string) // 2) * 2
   count = 0

   while count < countTo:
       thisVal = (string[count + 1]) * 256 + (string[count])
       csum += thisVal
       csum &= 0xffffffff
       count += 2

   if countTo < len(string):
       csum += (string[len(string) - 1])
       csum &= 0xffffffff

   csum = (csum >> 16) + (csum & 0xffff)
   csum = csum + (csum >> 16)
   answer = ~csum
   answer = answer & 0xffff
   answer = answer >> 8 | (answer << 8 & 0xff00)
   return answer



def receiveOnePing(mySocket, ID, timeout, destAddr):
   timeLeft = timeout

   while 1:
       startedSelect = time.time()
       whatReady = select.select([mySocket], [], [], timeLeft)
       howLongInSelect = (time.time() - startedSelect)
       if whatReady[0] == []:  # Timeout
           return "Request timed out."

       timeReceived = time.time()
       recPacket, addr = mySocket.recvfrom(1024)

       # Fetch the ICMP header from the IP packet

       header = recPacket[20:28]
       type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
       if type == 0 and packID == ID:
          bytesInDouble = struct.calcsize("d")
          timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
          ttls = struct.unpack("c", recPacket[8:9])[0]  
          rtt = timeReceived - timeSent
          return (rtt, ttls)

       timeLeft = timeLeft - howLongInSelect
       if timeLeft <= 0:
           return "Request timed out."


def sendOnePing(mySocket, destAddr, ID):
   # Header is type (8), code (8), checksum (16), id (16), sequence (16)

   myChecksum = 0
   # Make a dummy header with a 0 checksum
   # struct -- Interpret strings as packed binary data
   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   data = struct.pack("d", time.time())
   # Calculate the checksum on the data and the dummy header.
   myChecksum = checksum(header + data)

   # Get the right checksum, and put in the header

   if sys.platform == 'darwin':
       # Convert 16-bit integers from host to network  byte order
       myChecksum = htons(myChecksum) & 0xffff
   else:
       myChecksum = htons(myChecksum)


   header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
   packet = header + data

   mySocket.sendto(packet, (destAddr, 1))  # AF_INET address must be tuple, not str


   # Both LISTS and TUPLES consist of a number of objects
   # which can be referenced by their position number within the object.

def doOnePing(destAddr, timeout):
   icmp = getprotobyname("icmp")


   # SOCK_RAW is a powerful socket type. For more details:   http://sockraw.org/papers/sock_raw
   mySocket = socket(AF_INET, SOCK_RAW, icmp)

   myID = os.getpid() & 0xFFFF  # Return the current process i
   sendOnePing(mySocket, destAddr, myID)
   delay = receiveOnePing(mySocket, myID, timeout, destAddr)
   mySocket.close()
   return delay


def ping(host, timeout=1):
  # timeout=1 means: If one second goes by without a reply from the server,      # the client assumes that either the client's ping or the server's pong is lost
   dest = gethostbyname(host)
  # print("Pinging " + dest + " using Python:")
  # print("")
  # Calculate vars values and return them
   count = 0
   val = []
  # Send ping requests to a server separated by approximately one second
   for i in range(0,4):
       delay = doOnePing(dest, timeout)
       val.append(delay)
      # print(delay)
       time.sleep(1)  # one second
         
   if len(val) > 0:      
       packet_min = min(val) * 1000
       packet_avg = sum(val) / len(val) * 1000
       packet_max = max(val) * 1000
       stdev_var =  list(val) * 1000
       vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(stdev(stdev_var), 2))]
   else:
        vars = ['0', '0.0', '0', '0.0']
   return vars

if __name__ == '__main__':
   ping("google.co.il")

Solution

  • You have return (rtt, ttls) in function receiveOnePing and then you return the same tuple from function doOnePing. After that, you append this tuple to list and are trying to sum this list of tuples. This leads to the error you mentioned. You need val.append(delay[0]) in ping function (line 122).

    You also use undefined function stdev. Should be statistics.stdev.

    Please note that your script will crash in case of timeout because you return a string in this. Also the code is runnable only by root.

    UPD Below is fixed code.

    rom socket import *
    import os
    import sys
    import struct
    import time
    import select
    import statistics
    import binascii
    
    # Should use stdev
    
    ICMP_ECHO_REQUEST = 8
    
    
    def checksum(string):
       csum = 0
       countTo = (len(string) // 2) * 2
       count = 0
    
       while count < countTo:
           thisVal = (string[count + 1]) * 256 + (string[count])
           csum += thisVal
           csum &= 0xffffffff
           count += 2
    
       if countTo < len(string):
           csum += (string[len(string) - 1])
           csum &= 0xffffffff
    
       csum = (csum >> 16) + (csum & 0xffff)
       csum = csum + (csum >> 16)
       answer = ~csum
       answer = answer & 0xffff
       answer = answer >> 8 | (answer << 8 & 0xff00)
       return answer
    
    
    
    def receiveOnePing(mySocket, ID, timeout, destAddr):
       timeLeft = timeout
    
       while 1:
           startedSelect = time.time()
           whatReady = select.select([mySocket], [], [], timeLeft)
           howLongInSelect = (time.time() - startedSelect)
           if whatReady[0] == []:  # Timeout
               return "Request timed out."
    
           timeReceived = time.time()
           recPacket, addr = mySocket.recvfrom(1024)
    
           # Fetch the ICMP header from the IP packet
    
           header = recPacket[20:28]
           type, code, checksum, packID, seqNo = struct.unpack("bbHHh", header)
           if type == 0 and packID == ID:
              bytesInDouble = struct.calcsize("d")
              timeSent = struct.unpack("d", recPacket[28:28 + bytesInDouble])[0]
              ttls = struct.unpack("c", recPacket[8:9])[0]  
              rtt = timeReceived - timeSent
              return (rtt, ttls)
    
           timeLeft = timeLeft - howLongInSelect
           if timeLeft <= 0:
               return "Request timed out."
    
    
    def sendOnePing(mySocket, destAddr, ID):
       # Header is type (8), code (8), checksum (16), id (16), sequence (16)
    
       myChecksum = 0
       # Make a dummy header with a 0 checksum
       # struct -- Interpret strings as packed binary data
       header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
       data = struct.pack("d", time.time())
       # Calculate the checksum on the data and the dummy header.
       myChecksum = checksum(header + data)
    
       # Get the right checksum, and put in the header
    
       if sys.platform == 'darwin':
           # Convert 16-bit integers from host to network  byte order
           myChecksum = htons(myChecksum) & 0xffff
       else:
           myChecksum = htons(myChecksum)
    
    
       header = struct.pack("bbHHh", ICMP_ECHO_REQUEST, 0, myChecksum, ID, 1)
       packet = header + data
    
       mySocket.sendto(packet, (destAddr, 1))  # AF_INET address must be tuple, not str
    
    
       # Both LISTS and TUPLES consist of a number of objects
       # which can be referenced by their position number within the object.
    
    def doOnePing(destAddr, timeout):
       icmp = getprotobyname("icmp")
    
    
       # SOCK_RAW is a powerful socket type. For more details:   http://sockraw.org/papers/sock_raw
       mySocket = socket(AF_INET, SOCK_RAW, icmp)
    
       myID = os.getpid() & 0xFFFF  # Return the current process i
       sendOnePing(mySocket, destAddr, myID)
       delay = receiveOnePing(mySocket, myID, timeout, destAddr)
       mySocket.close()
       return delay
    
    
    def ping(host, timeout=1):
      # timeout=1 means: If one second goes by without a reply from the server,      # the client assumes that either the client's ping or the server's pong is lost
       dest = gethostbyname(host)
      # print("Pinging " + dest + " using Python:")
      # print("")
      # Calculate vars values and return them
       count = 0
       val = []
      # Send ping requests to a server separated by approximately one second
       for i in range(0,4):
           delay = doOnePing(dest, timeout)
           val.append(delay[0])
          # print(delay)
           time.sleep(1)  # one second
             
       print(val)
       if len(val) > 0:      
           packet_min = min(val) * 1000
           packet_avg = sum(val) / len(val) * 1000
           packet_max = max(val) * 1000
           stdev_var =  list(val) * 1000
           vars = [str(round(packet_min, 2)), str(round(packet_avg, 2)), str(round(packet_max, 2)),str(round(statistics.stdev(stdev_var), 2))]
       else:
            vars = ['0', '0.0', '0', '0.0']
       return vars
    
    if __name__ == '__main__':
       ping("google.co.il")
    
    >sudo python3 ping.py
    [0.0778355598449707, 0.07866811752319336, 0.07798004150390625, 0.07628297805786133]