Skip to content

Commit

Permalink
Added workaround to force new port allocation on SYMSP NATs.
Browse files Browse the repository at this point in the history
  • Loading branch information
mertemba committed Aug 10, 2015
1 parent e2a36ec commit a8021e4
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 0 deletions.
8 changes: 8 additions & 0 deletions src/peer.py
Expand Up @@ -44,6 +44,7 @@
#from peer_lossy import Peer_Lossy
from monitor_lrs import Monitor_LRS
from lossy_peer import Lossy_Peer
from symsp_peer import Symsp_Peer

# }}}

Expand Down Expand Up @@ -75,6 +76,8 @@ def __init__(self):

parser.add_argument('--player_port', help='Port to communicate with the player. Default = {}'.format(Peer_IMS.PLAYER_PORT))

parser.add_argument('--port_step', help='Source port step forced when behind a sequentially port allocating NAT (conflicts with --chunk_loss_period). Default = {}'.format(Symsp_Peer.PORT_STEP))

parser.add_argument('--splitter_addr', help='IP address or hostname of the splitter. Default = {}.'.format(Peer_IMS.SPLITTER_ADDR))

parser.add_argument('--splitter_port', help='Listening port of the splitter. Default = {}.'.format(Peer_IMS.SPLITTER_PORT))
Expand Down Expand Up @@ -131,6 +134,11 @@ def __init__(self):
# {{{ This is an "unicast" peer.

peer = Peer_DBS(peer)
if args.port_step:
Symsp_Peer.PORT_STEP = int(args.port_step)
print('PORT_STEP =', Symsp_Peer.PORT_STEP)
if int(args.port_step) != 0:
peer = Symsp_Peer(peer)
peer.receive_my_endpoint()
peer.receive_the_number_of_peers()
print("===============> number_of_peers =", peer.number_of_peers)
Expand Down
54 changes: 54 additions & 0 deletions src/symsp_peer.py
@@ -0,0 +1,54 @@
# This code is distributed under the GNU General Public License (see
# THE_GENERAL_GNU_PUBLIC_LICENSE.txt for extending this information).
# Copyright (C) 2014, the P2PSP team.
# http://www.p2psp.org

# The P2PSP.org project has been supported by the Junta de Andalucia
# through the Proyecto Motriz "Codificacion de Video Escalable y su
# Streaming sobre Internet" (P10-TIC-6548).

# {{{ Imports
import sys
import socket
from peer_dbs import Peer_DBS
from color import Color
from symsp_socket import symsp_socket
# }}}

# Some useful definitions.
ADDR = 0
PORT = 1

class Symsp_Peer(Peer_DBS):
# {{{

PORT_STEP = 0

def __init__(self, peer):
# {{{

sys.stdout.write(Color.yellow)
sys.stdout.write("Symsp Peer\n")
sys.stdout.write(Color.none)

# }}}

def listen_to_the_team(self):
# {{{ Create "team_socket" (UDP) as a copy of "splitter_socket" (TCP)

self.team_socket = symsp_socket(self.PORT_STEP, socket.AF_INET, socket.SOCK_DGRAM)
try:
# In Windows systems this call doesn't work!
self.team_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except Exception as e:
print ("NTS:", e)
pass
self.team_socket.bind(('', self.splitter_socket.getsockname()[PORT]))

# This is the maximum time the peer will wait for a chunk
# (from the splitter or from another peer).
self.team_socket.settimeout(1)

# }}}

# }}}
50 changes: 50 additions & 0 deletions src/symsp_socket.py
@@ -0,0 +1,50 @@
# -*- coding: iso-8859-15 -*-

# The P2PSP.org project has been supported by the Junta de Andalucía
# through the Proyecto Motriz "Codificación de Vídeo Escalable y su
# Streaming sobre Internet" (P10-TIC-6548).

# Overwrites the "sendto" method of the socket library, in order to
# force sequential source port allocation.

import socket

class symsp_socket():

def __init__(self, port_step, *p):
self._sock = socket.socket(*p)
self.destinations = []
self.port_step = port_step

def sendto(self, message, destination):
# {{{

# For each destination endpoint that was not sent to yet, this socket
# wrapper creates a temporary socket and connects to the destination a
# specified number of times before sending from the original socket.
# This forces the NAT to create a new mapping entry.

if destination not in self.destinations:
for _ in range(self.port_step):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto('', destination)
sock.close()
self.destinations.append(destination)
return self._sock.sendto(message, destination)

# }}}

def bind(self, *p):
return self._sock.bind(*p)

def settimeout(self, *p):
return self._sock.settimeout(*p)

def getsockname(self, *p):
return self._sock.getsockname(*p)

def recvfrom(self, *p):
return self._sock.recvfrom(*p)

def setsockopt(self, *p):
return self._sock.setsockopt(*p)

0 comments on commit a8021e4

Please sign in to comment.