Pygame webcam streaming client can't execute with python 3.4 - python-3.x

I'm using pygame and python3.4 for stream a webcam in a Odroid board. The server is this (extracted of this post: using pygame to stream over sockets in python error ):
import socket
import pygame
import pygame.camera
import sys
import time
port = 5000
pygame.init()
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serversocket.bind(("",port))
serversocket.listen(1)
pygame.camera.init()
webcam = pygame.camera.Camera("/dev/video1",(320,240))
webcam.start()
while True:
connection, address = serversocket.accept()
image = webcam.get_image() # capture image
data = pygame.image.tostring(image,"RGB") # convert captured image to string, use RGB color scheme
connection.sendall(data)
time.sleep(0.1)
connection.close()
The server works Ok in python and python 3.4.
But when I execute the client with python 3.4 I get the following error:
Traceback (most recent call last):
File "client.py", line 30, in
image = pygame.image.fromstring(dataset,(320,240),"RGB") # convert received image from string
TypeError: must be bytes, not str
The client is the following:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import socket
import pygame
import sys
host = "192.168.45.103"
port=5000
screen = pygame.display.set_mode((320,240),0)
while True:
clientsocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
clientsocket.connect((host, port))
received = []
# loop .recv, it returns empty string when done, then transmitted data is completely received
while True:
#print("esperando receber dado")
recvd_data = clientsocket.recv(230400)
if not recvd_data:
break
else:
received.append(recvd_data)
#dataset = ''.join(received)
dataset = ','.join(str(v) for v in received)
image = pygame.image.fromstring(dataset,(320,240),"RGB") # convert received image from string
screen.blit(image,(0,0)) # "show image" on the screen
pygame.display.update()
# check for quit events
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
I changed the line dataset = ''.join(received) for dataset = ','.join(str(v) for v in received) because I read somwhere that in python3.x it mst be this.
The error line now is: image = pygame.image.fromstring(dataset,(320,240),"RGB")
Thanks!

These 2 lines appear to be plain wrong:
dataset = ','.join(received)
image = pygame.image.fromstring(dataset,(320,240),"RGB") # convert received
If dataset is to contain the binary pxel data, you should not be concatenating the bytes you receive with ",": it would simply add a lost of extraneous "," (decimal 44) bytes as garbage in your pixel data - the previous line, using "join" with an empty string would work (in Python 2.x) becuase called upon an empty string, join simply concatenates the various piece of data, which is what you want.
In Python3, handling of binary data (such as the pixel data you are receiving) has been separated from text handling - and the '""' empty string you where using is an object representing empty text - which is different from empty bytes from Python 2.x - but you can simply prefix it with a b for denoting a bytes-string (which is what you want).
All in all, try just using:
dataset = b''.join(str(v) for v in received)
image = pygame.image.fromstring(dataset,(320,240),"RGB")

Related

Python3 OpenCV - LIBTDB ERROR: data is not tagged properly

I'm getting this error by running this python script (converted into .exe) I found on github on my Acer Tablet with Windows 8.1:
LIBTDB ERROR: data is not tagged properly
(the script continues after printing the error)
import cv2
import numpy as np
import socket
import struct
from io import BytesIO
IP = '192.168.1.8'
# Capture frame
cap = cv2.VideoCapture(0) ## here the error
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((IP, 8080))
while cap.isOpened():
_, frame = cap.read()
memfile = BytesIO()
np.save(memfile, frame)
memfile.seek(0)
data = memfile.read()
# Send form byte array: frame size + frame content
client_socket.sendall(struct.pack("L", len(data)) + data)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
It works fine on my windows 10 pc, but I wanted to try it on two different devices.

Sending Mouse and keyboard inputs from server to client over socket in Python?

I have my desktop stream working the server can see the client desktop, what I basically do is grab screenshots from client and send it to server continuously and displaying it using cv2.imshow().
Now I want a way to send mouse and keyboards inputs from server to the client so that it can control the client remotely. I know pyautogui module could be used to simulate moving, click and dragging mouse as well as pressing keys.
One way I thought is to send the coordinates in fractions of the resolution.
Example:
If your picturebox is 800x600 and you click at location (200, 300), send (0.25, 0.5).
On the other machine, you receive (0.25, 0.5) and you multiply them by the resolution. On a 1024x768, you move the mouse pointer to location (256, 384).
But I need a method to get the mouse and keyboard input from the opencv window and send it to the client over the socket and then simulate it on client side.
Any other method instead of using opencv to display the frames on server would be accepted as well, as long as I am able to work with keyboard and mouse inputs and improves the performance.
Note: I am also not able to get the screenshot of the UAC prompt using Imagegrab.grab() even if I run the script as an administrator I don't know why
this is happening.
Below is my code for client and server exceptions which are not being handled as I am just trying out that the things work.
Any suggestions to make my stream faster are welcomed as well :)
server.py:
import socket
import struct
import cv2
import numpy
host = "192.168.0.5"
port = 4444
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #create socket
s.bind((host,port))
s.listen(5)
c , addr = s.accept()
print("Connection recieved from {}".format(addr))
cv2.namedWindow("Remote Desktop",cv2.WINDOW_NORMAL)
while True:
bs = c.recv(8)
(length,) = struct.unpack(">Q",bs) # get length of image
data = b''
while(len(data)<length): # get image data
recv_data = length - len(data)
if(recv_data>4096):
data += c.recv(4096)
else:
data += c.recv(recv_data)
with open("demo.jpg","wb") as f:
d = f.write(data)
#print(d)
img = cv2.imread("demo.jpg")
cv2.imshow("Remote Desktop",img)
key = cv2.waitKey(1)
if key == 27:
break
cv2.destroyAllWindows()
s.close()
Here is my client.py:
import socket
import struct
from PIL import ImageGrab
import time
host = "192.168.0.5"
port = 4444
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #create socket
s.connect((host,port)) #connect to server
print("Connection Established")
time.sleep(5)
while True:
img = ImageGrab.grab()
img.save("demo.jpg","JPEG")
with open("demo.jpg","rb") as f:
data = f.read() # read the image
s.sendall(struct.pack(">Q",len(data))) #send the length of image in bytes
s.sendall(data) # send the data
s.close()
So how can I send mouse and keyboard inputs effectively over socket in python? Thanks for your help.
This can help you out....Make it according to you need.
import threading
import mouse
import keyboard
mouse_events = []
mouse.hook(mouse_events.append)
keyboard.start_recording()
keyboard.wait("*")
mouse.unhook(mouse_events.append)
keyboard_events = keyboard.stop_recording()
#Keyboard threadings:
k_thread = threading.Thread(target = lambda :keyboard.play(keyboard_events))
k_thread.start()
#Mouse threadings:
m_thread = threading.Thread(target = lambda :mouse.play(mouse_events))
m_thread.start()
#waiting for both threadings to be completed
k_thread.join()
m_thread.join()

Non-blocking input in python 3 [duplicate]

I'm working on a bot for a competition that receives its input through sys.stdin and uses Python's print() for output. I have the following:
import sys
def main():
while True:
line = sys.stdin.readline()
parts = line.split()
if len(parts) > 0:
# do stuff
The problem is that the input comes in through a stream and using the above, blocks me from printing anything back until the stream is closed. What can I do to make this work?
By turning blocking off you can only read a character at a time. So, there is no way to get readline() to work in a non-blocking context. I assume you just want to read key presses to control the robot.
I have had no luck using select.select() on Linux and created a way with tweaking termios settings. So, this is Linux specific but works for me:
import atexit, termios
import sys, os
import time
old_settings=None
def init_any_key():
global old_settings
old_settings = termios.tcgetattr(sys.stdin)
new_settings = termios.tcgetattr(sys.stdin)
new_settings[3] = new_settings[3] & ~(termios.ECHO | termios.ICANON) # lflags
new_settings[6][termios.VMIN] = 0 # cc
new_settings[6][termios.VTIME] = 0 # cc
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, new_settings)
#atexit.register
def term_any_key():
global old_settings
if old_settings:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_settings)
def any_key():
ch_set = []
ch = os.read(sys.stdin.fileno(), 1)
while ch is not None and len(ch) > 0:
ch_set.append( ord(ch[0]) )
ch = os.read(sys.stdin.fileno(), 1)
return ch_set
init_any_key()
while True:
key = any_key()
if key is not None:
print(key)
else:
time.sleep(0.1)
A better Windows or cross-platform answer is here: Non-blocking console input?
You can use selectors for handle I/O multiplexing:
https://docs.python.org/3/library/selectors.html
Try this out:
#! /usr/bin/python3
import sys
import fcntl
import os
import selectors
# set sys.stdin non-blocking
orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)
# function to be called when enter is pressed
def got_keyboard_data(stdin):
print('Keyboard input: {}'.format(stdin.read()))
# register event
m_selector = selectors.DefaultSelector()
m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)
while True:
sys.stdout.write('Type something and hit enter: ')
sys.stdout.flush()
for k, mask in m_selector.select():
callback = k.data
callback(k.fileobj)
The above code will hold on the line
for k, mask in m_selector.select():
until a registered event occurs, returning a selector_key instance (k) and a mask of monitored events.
In the above example we registered only one event (Enter key press):
m_selector.register(sys.stdin, selectors.EVENT_READ, got_keyboard_data)
The selector key instance is defined as follows:
abstractmethod register(fileobj, events, data=None)
Therefore, the register method sets k.data as our callback function got_keyboard_data, and calls it when the Enter key is pressed:
callback = k.data
callback(k.fileobj)
A more complete example (and hopefully more useful) would be to multiplex stdin data from user with incoming connections from network:
import selectors
import socket
import sys
import os
import fcntl
m_selector = selectors.DefaultSelector()
# set sys.stdin non-blocking
def set_input_nonblocking():
orig_fl = fcntl.fcntl(sys.stdin, fcntl.F_GETFL)
fcntl.fcntl(sys.stdin, fcntl.F_SETFL, orig_fl | os.O_NONBLOCK)
def create_socket(port, max_conn):
server_addr = ('localhost', port)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.setblocking(False)
server.bind(server_addr)
server.listen(max_conn)
return server
def read(conn, mask):
global GO_ON
client_address = conn.getpeername()
data = conn.recv(1024)
print('Got {} from {}'.format(data, client_address))
if not data:
GO_ON = False
def accept(sock, mask):
new_conn, addr = sock.accept()
new_conn.setblocking(False)
print('Accepting connection from {}'.format(addr))
m_selector.register(new_conn, selectors.EVENT_READ, read)
def quit():
global GO_ON
print('Exiting...')
GO_ON = False
def from_keyboard(arg1, arg2):
line = arg1.read()
if line == 'quit\n':
quit()
else:
print('User input: {}'.format(line))
GO_ON = True
set_input_nonblocking()
# listen to port 10000, at most 10 connections
server = create_socket(10000, 10)
m_selector.register(server, selectors.EVENT_READ, accept)
m_selector.register(sys.stdin, selectors.EVENT_READ, from_keyboard)
while GO_ON:
sys.stdout.write('>>> ')
sys.stdout.flush()
for k, mask in m_selector.select():
callback = k.data
callback(k.fileobj, mask)
# unregister events
m_selector.unregister(sys.stdin)
# close connection
server.shutdown()
server.close()
# close select
m_selector.close()
You can test using two terminals.
first terminal:
$ python3 test.py
>>> bla
open another terminal and run:
$ nc localhost 10000
hey!
back to the first
>>> qwerqwer
Result (seen on the main terminal):
$ python3 test.py
>>> bla
User input: bla
>>> Accepting connection from ('127.0.0.1', 39598)
>>> Got b'hey!\n' from ('127.0.0.1', 39598)
>>> qwerqwer
User input: qwerqwer
>>>
#-----------------------------------------------------------------------
# Get a character from the keyboard. If Block is True wait for input,
# else return any available character or throw an exception if none is
# available. Ctrl+C isn't handled and continues to generate the usual
# SIGINT signal, but special keys like the arrows return the expected
# escape sequences.
#
# This requires:
#
# import sys, select
#
# This was tested using python 2.7 on Mac OS X. It will work on any
# Linux system, but will likely fail on Windows due to select/stdin
# limitations.
#-----------------------------------------------------------------------
def get_char(block = True):
if block or select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
return sys.stdin.read(1)
raise error('NoChar')
This is a posix solution, similar to the answer by swdev.
As they stated, you have to play with termios.VMIN and termios.VTIME to catch more than one char without requiring user to press Enter. Trying to only use raw mode will be a problem as special keys like arrows can mess next keypress.
Here we use tty.setcbreak() or tty.setraw() as a shortcut, but they have short internals.
import termios
import tty
import sys
import select
def get_enter_key():
fd = sys.stdin.fileno()
orig_fl = termios.tcgetattr(fd)
try:
tty.setcbreak(fd) # use tty.setraw() instead to catch ^C also
mode = termios.tcgetattr(fd)
CC = 6
mode[CC][termios.VMIN] = 0
mode[CC][termios.VTIME] = 0
termios.tcsetattr(fd, termios.TCSAFLUSH, mode)
keypress, _, _ = select.select([fd], [], [])
if keypress:
return sys.stdin.read(4095)
finally:
termios.tcsetattr(fd, termios.TCSANOW, orig_fl)
try:
while True:
print(get_enter_key())
except KeyboardInterrupt:
print('exiting')
sys.exit()
note that there are two potential timeouts you could add here:
one is adding last parameter to select.select()
another is playing with VMIN and VTIME
Might I suggest nobreak? If'n you are willing to use curses.
https://docs.python.org/3/library/curses.html#curses.window.nodelay
You should be able to get read of a stream with either
sys.stdin.read(1)
to read utf-8 decoded chars or:
sys.stdin.buffer.read(1)
to read raw chars.
I would do this if I wanted to get raw data from the stdin and do something with it in a timely manner, without reading a newline or filling up the internal buffer first. This is suitable for running programs remotely via ssh where tty is not available, see:
ssh me#host '/usr/bin/python -c "import sys; print(sys.stdin.isatty())"'
There are some other things to think about to make programs work as expected in this scenario. You need to flush the output when you're done to avoid buffering delays, and it could be easy to assume a program hasn't read the input, when you've simply not flushed the output.
stdout.write("my data")
stdout.flush()
But usually it's not the input reading that's the problem but that the terminal (or program) supplying the input stream is not handing it over when you expect, or perhaps it's not reading your output when you expect. If you have a tty to start with (see ssh check above) you can put it into raw mode with the tty module.
import sys
import termios
import tty
old = termios.tcgetattr(sys.stdin)
tty.setraw(sys.stdin)
c = None
try:
c = sys.stdin.read(1)[0]
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old)
print(c)
... if using Mac/Linux. If using Windows you could use msvcrt.getch().
Use a generator - thankfully sys.stdin is already a generator!
A generator enables you to work on an infinite stream. Always when you call it, it returns the next element. In order to build a generator you need the yield keyword.
for line in sys.stdin:
print line
if a_certain_situation_happens:
break
Do not forget to place a break statement into the loop if a certain, wished situation happens.
You can find more information about generators on:
http://www.dabeaz.com/generators/index.html
http://linuxgazette.net/100/pramode.html

The Output Window always freezes during uploading or saving files (Open CV on python running on a Raspberry Pi 3)

I made a motion detector solely software-based by referring a few books and then adding my own code. The added code saves a frame of the detected motion locally on the Raspberry Pi and also uploads the same to my Google Drive. Another set of code, sends an email to my email-address informing me of the motion detected.
The problem is that when the file is being saved and uploaded, the Open CV output window freezes until the above processes finish. I tried multiprocessing and multi-threading on python but it didn't help. Is there any way I could improve my logic in a way that it doesn't freeze the output window?
EDIT : The issue was somewhat fixed by removing join() from the two processes. There is a very slight lag but I think that's good enough. Thanks to everyone who replied :)
from pydrive.drive import GoogleDrive
from pydrive.auth import GoogleAuth
import cv2
from multiprocessing import Process
import numpy as np
import datetime
import time
import smtplib
# make count 0
count = 0
def sf(t2):
cv2.imwrite("/home/pi/Desktop/StoredImages/frame%d.jpg" % count, t2)
# 'google drive authentication' stuff
gauth = GoogleAuth()
# try to load saved client credentials
gauth.LoadCredentialsFile("mycreds.txt")
if gauth.credentials is None:
# authenticate if not there
gauth.LocalWebserverAuth()
elif gauth.access_token_expired:
# Refresh them if expired
gauth.Refresh()
else:
# Initialize the saved creds
gauth.Authorize()
# Save the current credentials to a file
gauth.SaveCredentialsFile("mycreds.txt")
drive = GoogleDrive(gauth)
def upload_file():
file1 = drive.CreateFile({'parent':'/home/pi/Desktop/StoredImages/'})
file1.SetContentFile('/home/pi/Desktop/StoredImages/frame%d.jpg' % count)
file1.Upload()
# 'sending an email' stuff
server = smtplib.SMTP('smtp.gmail.com',587)
server.starttls()
server.login("Removed Intentionally","Removed Intentionally")
msg = "Motion Detected! For more details check your Drive."
# capture Video from the camera module
cap = cv2.VideoCapture(0)
# stores the present date and time
lastUploaded = datetime.datetime.now()
# kernel is created for the dilation process
k = np.ones((3,3),np.uint8) # creates a 3X3 Matrix filled with ones and
# has the data type uint8 (unsigned integer)
# which can contain values from 0 to 255
# first two subsequent frames captured
t0 = cap.read()[1]
t1 = cap.read()[1]
# initially motion detected 0 times
motionCounter = 0
while True:
# difference between two subsequent frames
d=cv2.absdiff(t1,t0)
# stores present date and time
timestamp = datetime.datetime.now()
# converting difference to grayscale
grey = cv2.cvtColor(d,cv2.COLOR_BGR2GRAY)
# grayscale converted to gaussian blur
blur = cv2.GaussianBlur(grey,(3,3),0)
# gaussian blur converted to binary image
ret, th = cv2.threshold(blur, 15, 155, cv2.THRESH_BINARY)
# dilating the image before using the contour function
dilated = cv2.dilate(th,k,iterations=2)
# contour function to find edges
_, contours, heierarchy = cv2.findContours(dilated,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# copying the original frame to a temporary frame for display
t2 = t0
# drawing green edges around the area with movement
cv2.drawContours(t2, contours, -1, (0,255,0), 2)
# showing output in a new window
cv2.imshow('Output',t2)
# going through each and every contour in the image
for c in contours:
# if contour is lesser than a threshold size, ignore
if cv2.contourArea(c) < 5000:
continue
# if motion occurred after 2 secs
if (timestamp - lastUploaded).seconds >= 2.0:
motionCounter += 1
# if 8 motions occured in 2 secs
if motionCounter >= 8:
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
# upload the temporary pic to Google drive using threads
new_process = Process(target=upload_file)
new_process.start()
new_process.join()
# sending a mail about motion detected
server.sendmail("Removed Intentionally","Removed Intentionally",msg)
# increasing count by 1 and resetting everything
count=count+1
lastUploaded = timestamp
motionCounter = 0
# making the next frame the previous and reading a new frame
t0 = t1
t1 = cap.read()[1]
# esc key breaks the entire loop
if cv2.waitKey(5) == 27:
break
# stops the video stream and exits the window
cap.release()
cv2.destroyAllWindows()
# stops the email server connection
server.quit()
I think you used the multiprocessing in a wrong way. Your code
# write to a temporary file location using threads
new_process = Process(target=sf, args=(t2,))
new_process.start()
new_process.join()
will actually create and start a process, but then it will also wait for it (new_process.join()) to finish. So basically you want to start a parallel running process, but then you wait for it to finish.
Better would be to create and start the processes at the beginning of your program and wait for them to finish at the very end of your program.
Also create a queue for each process (also in the multiprocessing module).
Each process should run in an endless loop and wait for a queue. In your main thread, you feed each process' queue with what it should do (store a file locally, store file remotely)
At the end of your program, you should send your processes a final indication to leave their endless loop, so your new_process.join() statement in the main thread will pick up the fact, that the processes have ended.

Scapy: Inserting a new layer and logging issues

I am attempting to insert GRErouting layer in between GRE and IP using Scapy. The pcap I am reading contains a single packet stacked as follows: Ethernet/IPv4/GRE/IPv4/ICMP.
What I see is that getLayer returns the current layer + its payload, which may include other layers, and that's not good for me. I would like to only get the current layer. When I do getLayer for each layer, and then write the entire array I get a strange pcap because of the additional payload that each layer has over it.
I am also not able to use a simple 'print' to output any data to console. I understand this is because Scapy adds the logging module, and suppresses system logging, but I'd like to know how to undo that and be able to use the 'print' statement.
import os
import sys
import logging
logging.basicConfig()
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import PcapReader, PcapWriter, fuzz, Packet
from scapy.layers.l2 import GRE, GRErouting
from scapy.layers.inet import IP
logging.getLogger("scapy.runtime").setLevel(logging.DEBUG)
logging.getLogger().setLevel(logging.DEBUG)
def foo(in_filename, out_filename):
f = PcapReader(in_filename)
o = PcapWriter(out_filename)
p = f.read_packet()
while p:
layers = []
counter = 0
while True:
layer = p.getlayer(counter)
if (layer != None):
layers.append(layer)
if (type(layer) is IP):
del layer.chksum
if (type(layer) is GRE):
logging.getLogger().debug("there is a GRE layer")
layer.routing_present = 1
gr = GRErouting()
fuzz(gr)
layers.append(gr)
del layer.chksum
else:
break
counter += 1
logging.getLogger().debug("Layers are: %s\t\t",layers)
for l in layers:
logging.getLogger().debug("%s", l)
o.write(layers)
p = f.read_packet()
f.close()
o.close()
if __name__ == "__main__":
logging.getLogger().debug('Executing main')
if (len(sys.argv) == 3):
in_filename = str(sys.argv[1])
out_filename = str(sys.argv[2])
if os.path.exists(in_filename) == False:
sys.stderr.write("Either {0} does not exist, or you do not have proper permissions\n".format(in_filename))
else:
foo(in_filename, out_filename)
else:
sys.stderr.write("USAGE: {0} <path to input file> <path to output file>\n".format(str(sys.argv[0])))
I was finally able to answer my own two questions. See modified code below:
# importing the os package (see api at http://docs.python.org/2.6/library/io.html)
import os
# import function 'basename' from module os.path
from os.path import basename
# importing the sys package (see api at http://docs.python.org/2.6/library/sys.html)
import sys
# importing the logging package (see api at http://docs.python.org/2.6/library/logging.html)
import logging
# by default Scapy attempts to find ipv6 routing information,
# and if it does not find any it prints out a warning when running the module.
# the following statement changes log level to ERROR so that this warning will not
# occur
effective_level = logging.getLogger("scapy.runtime").getEffectiveLevel()
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
# importing Scapy
from scapy.all import PcapReader, PcapWriter
from scapy.layers.l2 import GRE, GRErouting, NoPayload
# return the log level o be what it was
logging.getLogger("scapy.runtime").setLevel(effective_level)
# unfortunately, somewhere in Scapy sys.stdout is being reset.
# thus, using the 'print' command will not produce output to the console.
# the following two lines place stdout back into sys.
if sys.stdout != sys.__stdout__:
sys.stdout = sys.__stdout__
# this is a function declaration. there is no need for explicit types.
# python can infer an object type from its usage
def foo(in_filename, out_filename):
# open the input file for reading
f = PcapReader(in_filename)
# open the output file for writing
o = PcapWriter(out_filename)
# read the first packet from the input file
p = f.read_packet()
# while we haven't processed the last packet
while p:
# gets the first layer of the current packet
layer = p.firstlayer()
# loop over the layers
while not isinstance(layer, NoPayload):
if layer.default_fields.has_key('chksum'):
del layer.chksum
if layer.default_fields.has_key('len'):
del layer.len
if (type(layer) is GRE):
layer.routing_present = 1
layer.chksum_present = 1
# make sure to delete the checksum field. hopefully scapy will calculate it correctly one day
del layer.chksum
gr = GRErouting()
gr.address_family = 0x0800
gr.SRE_len = 4
gr.SRE_offset = 0
gr.routing_info = "1111"
# the NULL routing field
empty_gr = GRErouting()
empty_gr.address_family = 0x0000
empty_gr.SRE_len = 0
gr.add_payload(empty_gr)
gr.add_payload(layer.payload)
layer.remove_payload()
layer.add_payload(gr)
layer = empty_gr
# advance to the next layer
layer = layer.payload
# write the packet we just dissected into the output file
o.write(p)
# read the next packet
p = f.read_packet()
# close the input file
f.close()
# close the output file
o.close()
# i believe this is needed only if we are running the this module
# as the main module. i don't know if this will get executed if this module
# is imported into some other main module
if __name__ == "__main__":
# letting the user know we are starting.
# sys.argv[0] includes the path to the module, including the module name.
# convert sys.argv[0] into string, and extract the module name only
# (using basename)
print '===> Running', basename(str(sys.argv[0]))
# making sure that two parameters were entered on the command line
if (len(sys.argv) == 3):
# get the path to the input file
in_filename = str(sys.argv[1])
# get the path to the output file
out_filename = str(sys.argv[2])
# make sure the input file actually exists.
# if it doesn't, we print out an error and exit
if os.path.exists(in_filename) == False:
# note the method for entering conversion specifiers ({<ordinal>})
sys.stderr.write("Either {0} does not exist, or you do not have proper permissions\n".format(in_filename))
else:
# if the input file does exist, execute 'foo'
foo(in_filename, out_filename)
# print an end script notification
print basename(str(sys.argv[0])), '===> completed successfully'
else:
# write a USAGE message to the standard output stream
sys.stderr.write("USAGE: {0} <path to input file> <path to output file>\n".format(basename(str(sys.argv[0]))))

Resources