Sunday, September 1, 2013

XML-RPC Client/Server in Python

This demo shows how to have RPC connection in python.  The server collects CPU information (Linux).

Server-side:

 #!/usr/bin/python
import re
import os
import sys
import xmlrpclib

from SimpleXMLRPCServer import SimpleXMLRPCServer

def is_even(n):
    return n%2 == 0

def get_mhz():
    try:
        #return 0
        f = open("/proc/cpuinfo", 'r')
    except IOError:
        print "Unable to access /proc/cpuinfo"
        exit
    except:
        print "Other unhandled error (why?)"
      
    else:
        f.seek(0)
        line = f.readline()
        while line:
            line = line.strip()
            print "line = %s" % line
            m = re.match("cpu MHz[\t ]+: (.*)", line)
            if m:
                print m.group(1)
                f.close()
                return m.group(1)
            line = f.readline()
      
#    finally:
#        print "Sorry, still fails"


def xmlsrv_exit():
    print "trying to exit now..."
    try:
        print "try sys.exit(0)"
        #sys.exit(0)
    except:
        print "Unable to exit"
  
server = SimpleXMLRPCServer(("localhost", 8000))
print "Listening on port 8000..."
server.register_function(is_even, "xmlsrv_is_even")
server.register_function(get_mhz, "xmlsrv_get_mhz")
server.register_function(xmlsrv_exit, "xmlsrv_exit")
server.serve_forever()





Client side:

#!/usr/bin/python

import xmlrpclib

try:
    proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
    #print proxy.system.listMethods()
    print "3 is even: %s" % str(proxy.xmlsrv_is_even(3))
    print "100 is even: %s" % str(proxy.xmlsrv_is_even(100))

    print "CPU Clock: %s" % str(proxy.xmlsrv_get_mhz())

except xmlrpclib.Fault, err:
    print "A fault occurred"
    print "Fault code: %d" % err.faultCode
    print "Fault string: %s" % err.faultString
   
#proxy.xmlsrv_exit()


 

Multithreaded IGMP Query

Example how to access raw socket in Python:


#!/usr/bin/python

from socket import *
from struct import *
from time import *
import sys
import IN
import threading
import signal


src = '192.168.2.2'
dst = '224.0.0.1'
dev = "eth1.100" + "\0"

if len(sys.argv) > 1:
    dev = sys.argv[1]
    print "device = %s" % dev

src = gethostbyname(gethostname())
                  
def ichecksum(data, sum=0):
    """ Compute the Internet Checksum of the supplied data.  The checksum is
    initialized to zero.  Place the return value in the checksum field of a
    packet.  When the packet is received, check the checksum, by passing
    in the checksum field of the packet and the data.  If the result is zero,
    then the checksum has not detected an error.
    """
    # make 16 bit words out of every two adjacent 8 bit words in the packet
    # and add them up
    for i in range(0,len(data),2):
        if i + 1 >= len(data):
            sum += ord(data[i]) & 0xFF
        else:
            w = ((ord(data[i]) <> 16) > 0)
        sum = (sum & 0xFFFF) + (sum >> 16)

    # one's complement the result
    sum = ~sum

    return sum & 0xFFFF


def dump( data ):
    i = 0
    for x in data:
        if i == 4:
            print ''
            i = 0
        i += 1
        sys.stdout.write( ' %0.2x' % ord(x) )
    print ''


# ip header generation

def create_ip_hdr(id, type):
    ip_ihl = 5
    ip_ver = 4
    ip_tos = 0
    ip_tot_len = 0  # kernel will fill the correct total length
    ip_frag_off = 0
    ip_ttl = 255
    ip_proto = type #IPPROTO_IGMP
    ip_check = 0    # kernel will fill the correct checksum
    isrc = inet_aton( src )
    idst = inet_aton( dst )
    ip_ihl_ver = (ip_ver << 4) + ip_ihl
    router_alert = int( '1001010000000100', 2 ) << 16

    # the ! in the pack format string means network order
    ip_hdr = pack('!BBHHHBBH4s4sI',
        ip_ihl_ver, ip_tos, ip_tot_len, id, ip_frag_off, ip_ttl, ip_proto,
        ip_check,
        isrc, idst,
        router_alert)

    crc = pack( '!H', ichecksum( ip_hdr ) )
    ip_hdr = ip_hdr[:10] + crc + ip_hdr[12:]
    return ip_hdr


# IGMP header:
# type (octet), max resp time (octet), checksum (octet), group (4-octets)
IGMP_QUERY = 0x11
IGMP_REPORT = 0x16
IGMP_LEAVE = 0x17
igmp_type = IGMP_QUERY
IGMP_RESP_TIME = 120


def create_igmp_packet(id, type, group_addr='224.0.0.1'):
    igmp = pack( '!BBH4s', type, IGMP_RESP_TIME, 0, inet_aton(group_addr))
    crc = pack( '!H', ichecksum( igmp ) )
    igmp = igmp[0:2] + crc + igmp[4:]
    packet = create_ip_hdr(id, IPPROTO_IGMP) + igmp
    print 'packet:'
    dump( packet )
    return packet

def create_non_igmp_packet(id, type, group_addr='224.0.0.1'):
    igmp = pack( '!BBH4s', type, IGMP_RESP_TIME, 0, inet_aton(group_addr))
    crc = pack( '!H', ichecksum( igmp ) )
    igmp = igmp[0:2] + crc + igmp[4:]
    packet = create_ip_hdr(id, IPPROTO_UDP) + igmp
    print 'packet:'
    dump( packet )
    return packet


group = '224.0.0.1'
id = 1

s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW )
s.setsockopt( IPPROTO_IP, IP_HDRINCL, 1 )
s.setsockopt( IPPROTO_IP, IP_MULTICAST_TTL, 2)
s.setsockopt( SOL_SOCKET, IN.SO_BINDTODEVICE, dev)

socksema = threading.Semaphore()
stop = False

def signal_handler(signal, frame):
    global stop
    print 'You pressed Ctrl+C!'
    stop = True
    #th1.join()
    #th2.join()
    #sys.exit(0)

class IgmpQueryThread(threading.Thread):
    def run(self):
        global stop,id
        while (not stop):
            socksema.acquire()
            print "Sending IGMP query"
            igmp_q = create_igmp_packet(id, IGMP_QUERY, group)
            print s.sendto( igmp_q, (dst, 0) )
            socksema.release()
            dump( igmp_q)
            id += 1
            sleep(1)


class IgmpReportThread(threading.Thread):       
    def run(self):
        global stop,id
        while (not stop):
            socksema.acquire()
            print "Sending IGMP report"
            igmp_r = create_igmp_packet(id, IGMP_REPORT, group)
            print s.sendto( igmp_r, (dst, 0) )
            id += 1
            socksema.release()
            sleep(1)


i = 0
th1 = IgmpQueryThread()
th2 = IgmpReportThread()

th1.start()
th2.start()

signal.signal(signal.SIGINT, signal_handler)
print 'Press Ctrl+C to quit'
#signal.pause()


while(not stop):
    if (i % 5 == 0):
        print "Sending NON-IGMP (%d)" % i
        false_igmp = create_non_igmp_packet(id, IGMP_QUERY, group)
        print s.sendto( false_igmp, (dst, 0) )
        #stop = True
        id += 1
    sleep( 1 )
    i += 1
   
th1.join()
th2.join()

s.close()