filetransfer sending is finished, only proxies remain

master
Stefan Krulj 14 years ago
parent 104cc5166a
commit 1db64fe052
  1. 1
      .gitignore
  2. 36
      brathuhn.py
  3. 4
      config.py
  4. 67
      jingle_ft.py
  5. 11
      main.py
  6. 52
      s5b.py
  7. 164
      stream_ft.py
  8. 39
      util.py

1
.gitignore vendored

@ -1 +1,2 @@
*~ *~
*.pyc

@ -1,4 +1,4 @@
import xmpp, os, sys, time, traceback import xmpp, os, sys, time, traceback, stream_ft
import threading import threading
from config import * from config import *
@ -20,6 +20,7 @@ join_time = time.time()+60*60*24*365 #1 year in the future
users = dict() users = dict()
STATUS_JOIN, STATUS_ONLINE, STATUS_OFFLINE, STATUS_RENAME, STATUS_XAWAY, STATUS_AWAY, STATUS_UNKNOWN = range(7) STATUS_JOIN, STATUS_ONLINE, STATUS_OFFLINE, STATUS_RENAME, STATUS_XAWAY, STATUS_AWAY, STATUS_UNKNOWN = range(7)
SI, JINGLE = range(2)
def getUsers(): def getUsers():
"""Return a dictionary of every user in the group, the values are status codes.""" """Return a dictionary of every user in the group, the values are status codes."""
@ -232,6 +233,7 @@ def connect_and_join():
cl.RegisterHandler('message',__ignore_first) cl.RegisterHandler('message',__ignore_first)
cl.RegisterHandler('presence',__presenceCB) cl.RegisterHandler('presence',__presenceCB)
cl.RegisterHandler('iq',stream_ft.ft_listener)
#authenticate #authenticate
auth=cl.auth(NAME,PWD,resource=jid.getResource()) auth=cl.auth(NAME,PWD,resource=jid.getResource())
@ -312,3 +314,35 @@ def cancelCall(cid):
if cid in call_ats: if cid in call_ats:
del call_ats[cid] del call_ats[cid]
def sendFile(to,path,method=SI):
"""Send a file using method specified
@param to -- Reciever of the file
@param path -- Path to the file
@param method -- Initiation method, currently only stream initiation is supported
"""
size = os.path.getsize(path)
name = os.path.basename(path)
fd = open(path,'rb')
if method==SI:
cim = stream_ft.create_init_message(room_nick,to,name,size,fd)
cl.send(cim)
else:
fd.close()
def sendFileStream(to,size,name,fd,method=SI):
"""Send a file using method specified
@param to -- Reciever of the file
@param size -- Number of bytes to send
@param name -- The name of the file the user will see
@param fd -- A file like object
@param method -- Initiation method, currently only stream initiation is supported
"""
if method==SI:
cim = stream_ft.create_init_message(room_nick,to,name,size,fd)
cl.send(cim)
else:
fd.close()

@ -11,6 +11,10 @@ try:
RESOURCE = cp.get("Account","RESOURCE") RESOURCE = cp.get("Account","RESOURCE")
except: except:
RESOURCE = 'bot' RESOURCE = 'bot'
try:
S5B_PROXY = cp.get("General","RESOURCE")
except:
S5B_PROXY = 'proxy.jabbim.cz'
ROOM = cp.get("Conference","ROOM") ROOM = cp.get("Conference","ROOM")
PWD_ROOM = cp.get("Conference","PWD_ROOM") PWD_ROOM = cp.get("Conference","PWD_ROOM")

@ -0,0 +1,67 @@
#!/usr/bin/python
import xmpp, os, hashlib, time
from datetime import datetime
ID=0
JINGLE_NS = 'urn:xmpp:jingle:1'
JINGLE_FT_NS = 'urn:xmpp:jingle:apps:file-transfer:3'
JINGLE_TRANSPORT_S5B_NS = 'urn:xmpp:jingle:transports:s5b:1'
HASHES_NS = 'urn:xmpp:hashes:1'
def create_init_message(mfrom,to,path,desc,host,port):
global ID
ID+=1
iq=xmpp.Iq(xmlns=None,
attrs={'to':to,'id':"jin_ft_iq_%d" % ID,'type':'set'})
jingle=__create_jingle_node(mfrom,'session-initiate',"jin_ft_%d" % ID)
iq.getChildren().append(jingle)
cont=__create_content_node('initiator',time.time(),path,desc)
jingle.getChildren().append(cont)
tr = __create_transport_tcp_direct(mfrom,host,port,126<<8+127,ID)
cont.getChildren().append(tr)
return iq
def __create_jingle_node(initiator,action,sid):
return xmpp.Protocol(name="jingle",xmlns=JINGLE_NS,
attrs={'initiator':initiator,'action':action,'sid':sid})
def __create_content_node(creator,date,path,txt):
mfile=open(path,"r")
datefmt = datetime.fromtimestamp(date).strftime("%Y-%m-%dT%H:%M:%SZ")
name=os.path.basename(path)
size=os.path.getsize(path)
mhash=hashlib.sha1()
mhash.update(mfile.read())
mfile.close()
cont= xmpp.Protocol(name="content",attrs={'creator':creator,'name':name})
desc = cont.addChild(name="description",namespace=JINGLE_FT_NS)
offer = desc.addChild(name="offer")
mfile = offer.addChild(name="file")
mfile.addChild(name="date",payload=[datefmt])
mfile.addChild(name="desc",payload=[txt])
mfile.addChild(name="name",payload=[name])
mfile.addChild(name="size",payload=[size])
mfile.addChild(name="hash",payload=[mhash.hexdigest()],
attrs={'algo':'sha-1'},namespace=HASHES_NS)
return cont
def __create_transport_tcp_direct(mfrom,host,port,priority,id):
tr = xmpp.Protocol(name="transport",
attrs={'mode':'tcp','sid':"jin_ft_tr_%d" % id})
tr.addChild(name="candidate",attrs={
'cid':"jin_ft_cd_%d" % id,
'host':host,
'jid':mfrom,
'port':port,
'priority':priority,
'type':'direct'})
return tr

@ -1,7 +1,7 @@
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import brathuhn import brathuhn, os
import stream_ft,xmpp import stream_ft,xmpp
@ -13,16 +13,9 @@ import choose
import tantrum import tantrum
import tell import tell
import last_active import last_active
import pen
def foo(msg,args):
cim = stream_ft.create_init_message(brathuhn.room_nick,msg.getFrom(),"brathuhn.py")
brathuhn.cl.send(cim)
brathuhn.addPrivateCommand("foo","asdasdasd",foo)
brathuhn.connect_and_join() brathuhn.connect_and_join()
brathuhn.cl.RegisterHandler('iq',stream_ft.ft_listener)
brathuhn.loop() brathuhn.loop()

@ -0,0 +1,52 @@
import socket, random
def s5b_prepare():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
port = None
while True:
port = random.randint(10000,2**16-1)
try:
s.bind(('', port))
s.listen(1)
break
except socket.error:
pass
return (s,port)
def s5b_write_file(s,fd,size):
s.settimeout(20)
conn, addr = s.accept()
data = conn.recv(3)
assert data[0]=='\x05' #SOCKS version not 5
assert data[1]=='\x01' #not a connect command
assert data[2]=='\x00' #does not support other connection method
#send VER=5 METHOD=NO_AUTH
conn.sendall('\x05\x00')
data = conn.recv(47)
assert data[0]=='\x05' # SOCKS version not 5
assert data[1]=='\x01' # not a connect command
# data[2] is reserved
assert data[3]=='\x03' # addr type is name
assert data[4]=='('
name = data[5:45]
assert data[45]=='\x00'
assert data[46]=='\x00'
#ACK
conn.sendall('\x05\x00\x00'+'\x03('+name+'\x00\x00')
#send file
data = fd.read(min(size,1024))
size -= len(data)
while data!='':
conn.sendall(data)
data = fd.read(min(size,1024))
size -= len(data)
conn.close()
fd.close()

@ -0,0 +1,164 @@
import xmpp, os, hashlib, time, brathuhn
import socket, subprocess, random, s5b, util
import config
from threading import Thread
from datetime import datetime
GET_IP_CMD = ["dig", "myip.opendns.com", "@resolver1.opendns.com", "+short"]
PROXY = config.S5B_PROXY
ID=random.randint(0,1000000)
BSTREAM_NS = "http://jabber.org/protocol/bytestreams"
SI_NS = 'http://jabber.org/protocol/si'
FILE_NS = 'http://jabber.org/protocol/si/profile/file-transfer'
FEATURE_NS = 'http://jabber.org/protocol/feature-neg'
X_DATA_NS = 'jabber:x:data'
JABBER_NS = 'jabber:client'
BYTESTREAM = 'http://jabber.org/protocol/bytestreams'
IBB = 'http://jabber.org/protocol/ibb'
transfer_ids = dict()
queries = dict()
LOCAL_IP = util.get_local_ip()
def create_init_message(mfrom,to,name,size,fd):
global ID
global transfer_ids
ID+=1
transfer_ids[unicode("si_%d"%ID)]=[fd,ID,size]
iq=xmpp.Iq(xmlns=JABBER_NS,
attrs={'from':unicode(mfrom),'to':to,'id':"si_%d" % ID,'type':'set'})
si=iq.addChild(name="si",namespace=SI_NS, attrs={'id':"si_%d" % ID, 'profile':FILE_NS})
si.addChild(name="file", namespace=FILE_NS, attrs={'name':name,'size':size})
fr=si.addChild(name="feature", namespace=FEATURE_NS)
x=fr.addChild(name="x", namespace=X_DATA_NS, attrs={'type':'form'})
fd=x.addChild(name="field",attrs={'type':'list-single','var':'stream-method'})
opt=fd.addChild(name="option")
val=opt.addChild(name="value")
val.addData(BYTESTREAM)
opt=fd.addChild(name="option")
val=opt.addChild(name="value")
val.addData(IBB)
return iq
def create_bytestream_query_message(mfrom,to,port,cid):
global queries
sid = "si_%d" % cid
queries[sid] = cid
iq=xmpp.Iq(xmlns=JABBER_NS,
attrs={'from':unicode(mfrom),'to':to,'id':sid,'type':'set'})
q = iq.addChild(name="query",namespace=BSTREAM_NS, attrs={'sid':sid})
hosts = []
p=subprocess.Popen(GET_IP_CMD,stdout=subprocess.PIPE)
p.wait()
hosts.append(p.stdout.read())
hosts.append(LOCAL_IP)
for host in hosts:
q.addChild(name="streamhost",attrs={'jid':unicode(mfrom),'port':str(port),'host':host})
#print "<!--out-->\n",q
return iq
def start_ibb(cid,mfrom,fd):
print "IBB"
stream = xmpp.filetransfer.IBB()
stream.PlugIn(brathuhn.cl)
stream.OpenStream("si_%d" % cid, mfrom, fd, blocksize=4096)
def ft_query(conn,msg):
global queries
global transfer_ids
sid = msg.attrs['id']
cid = queries[sid]
assert sid in transfer_ids
fd = transfer_ids[ sid ][0]
if msg.attrs['type']=='error':
start_ibb(cid, unicode(msg.getFrom()), fd)
del transfer_ids[ sid ]
del queries[ sid ]
def ft_init(conn,msg):
global ID
sid = msg.attrs['id']
if msg.attrs['type']=='result':
fd = transfer_ids[ sid ][0]
size = transfer_ids[ sid ][2]
current_id = transfer_ids[ sid ][1]
else:
del transfer_ids[ sid ]
return
si=msg.getChildren()[0]
# check if cancel message
if si.name!='si':
return
fr=si.getChildren()[0]
# some clients send a profile name
# we will ignore it i.e take the next child
if fr.name=='file':
fr=si.getChildren()[1]
if fr.name!='feature':
return
x=fr.getChildren()[0]
if x.name!='x' and x.attrs['type']!='submit':
return
fi=x.getChildren()[0]
if fi.name!='field':
return
val=fi.getChildren()[0]
if val.name!='value':
return
if val.data[0]==BYTESTREAM:
print "BYTESTREAM"
s,port=s5b.s5b_prepare()
q = create_bytestream_query_message(brathuhn.room_nick,msg.getFrom(),port,current_id)
brathuhn.cl.send(q)
def __run():
s5b.s5b_write_file(s,fd,size)
Thread(target=__run()).start()
ID += 1
elif val.data[0]==IBB:
start_ibb(current_id, unicode(msg.getFrom()), fd)
def ft_listener(conn,msg):
global transfer_ids
global queries
assert msg.name=='iq'
sid = msg.attrs['id']
if sid in transfer_ids and not sid in queries:
print "init"
ft_init(conn,msg)
return
if sid in queries:
ft_query(conn,msg)
return

@ -0,0 +1,39 @@
import select
import socket
import threading
import random
from Queue import Queue, Empty
MAGIC_PACKET = ""
for i in xrange(50):
MAGIC_PACKET += chr(random.randrange(ord('a'),ord('z')))
def get_local_ip():
def udp_listening_server():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(('<broadcast>', 8888))
s.setblocking(0)
while True:
result = select.select([s],[],[])
msg, address = result[0][0].recvfrom(1024)
msg = unicode(msg)
if msg == MAGIC_PACKET:
break
queue.put(address)
queue = Queue()
thread = threading.Thread(target=udp_listening_server)
thread.queue = queue
thread.start()
s2 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s2.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
waiting = True
while waiting:
s2.sendto(bytes(MAGIC_PACKET), ('<broadcast>', 8888))
try:
address = queue.get(False)
except Empty:
pass
else:
waiting = False
return address[0]
Loading…
Cancel
Save