Presence Code Python

From Second Life Wiki
Revision as of 02:07, 9 March 2010 by New Spore (talk | contribs)
Jump to navigation Jump to search

Extremely incomplete example of how to log an avatar in and establish a presence. So far it only sends enough to temporarily show in-world. More to come....

N.B.: the packet ID number of a zero encoded pack is encoded and must be decoded before you can know what packet you are actually dealing with (Thanks John Hurliman/Eddy Stryker).

(based on a sample login script found at libsl login.)

<python>from struct import * from zerocode import * import md5 import xmlrpclib import sys

import re import httplib, urllib from urlparse import urlparse import socket, sys, time import uuid from makepacketdict import makepacketdict


from datetime import datetime


mypacketdictionary = {} outputstring = ack_need_list = []

logoutputflag = False

if logoutputflag:

   temp = sys.stdout
   sys.stdout =open('alog.txt','w')

def login(first, last, passwd, mac):

 passwd_md5 = '$1$' + md5.new(passwd).hexdigest()

 uri = 'http://127.0.0.1'
 uri = 'https://login.agni.lindenlab.com/cgi-bin/login.cgi'
 s = xmlrpclib.ServerProxy(uri)

 login_details = {
   'first': first,
   'last': last,
   'passwd': passwd_md5,
   'start': 'last',
   'major': '1',
   'minor': '18',
   'patch': '5',
   'build': '3',
   'platform': 'Win',
   'mac': mac,
   'options': [],
   'user-agent': 'sl.py 0.1',
   'id0': ,
   'agree_to_tos': ,
   'viewer_digest': '09d93740-8f37-c418-fbf2-2a78c7b0d1ea'
 }
 results = s.login_to_simulator(login_details)
 print results
 
 return results



def get_caps(results,cap_key, request_keys):

 _, netloc, path, _, _, _ = urlparse(results[cap_key])
 params = "<llsd><array><string>"+ request_keys[0]+"</string></array></llsd>"
 headers = {"content-type": "application/xml"}
 conn = httplib.HTTPSConnection(netloc)
 conn.request("POST", path, params, headers)
 response = conn.getresponse()


 data = response.read()
 conn.close()
 return data
 

def ExtractCap(cap_result):

 trim_xml = re.compile(r"<key>([a-zA-Z_]+)</key><string>([a-zA-Z_:/0-9-.]+)</string>")
 new_key = trim_xml.search(cap_result).group(1)
 new_cap = trim_xml.search(cap_result).group(2)
 return new_key, new_cap
 


def scheduleacknowledgemessage(data):

   if not ord(data[0])&0x40:
       print "OOOPS! Got asked to ack a message that shouldn't be acked"
       
       return
   else:
       ID = data[1:5]
       if (ord(data[0])&0x40) & 0x80: ID = zero_decode_ID(ID) #impossible
       ack_need_list.append(unpack(">L",ID)[0])
       #ack_need_list.append(unpack(">L",data[1:5])[0])
       #print "ack needed","insdie schedule ack_need_list", ack_need_list
       
   return

def packacks():

   acksequence = ""
   for msgnum in ack_need_list:
       acksequence += pack("<L", msgnum)
   
   
   return acksequence
       
  1. def sendacks():
#   if len(ack_need_list)>0:


  1. ===============================================================================
  2. {
  3. UUIDNameRequest Low NotTrusted Unencoded
  4. {
  5. UUIDNameBlock Variable
  6. { ID LLUUID }
  7. }
  8. }
  9. ===============================================================================

def sendUUIDNameRequest(sock, port, host, currentsequence,aUUID):

   packed_data = ""
   fix_ID = int("ffff0000",16)+ 235
   data_header = pack('>BLB', 0x00,currentsequence,0x00) 
   
   
   for x in aUUID:
       packed_data += uuid.UUID(x).bytes
       
   packed_data += pack("L",fix_ID) + pack(">B",len(aUUID)) + packed_data
       
   sock.sendto(packed_data, (host, port)) 
   return              
  

def sendRegionHandshakeReply(sock, port, host, currentsequence,agentUUID,sessionUUID):

   packed_data = ""
   
   low_ID = "ffff00%2x" % 149
   data_header = pack('>BLB', 0x00,currentsequence,0x00)
   packed_data += uuid.UUID(agentUUID).bytes+uuid.UUID(sessionUUID).bytes+ pack(">L",0x00)
   packed_data = data_header + pack(">L",int(low_ID,16))+packed_data
   sock.sendto(packed_data, (host, port)) 
   #print "RegionHandshakeReply", ByteToHex(packed_data)
   return
   
  
       

def sendAgentUpdate(sock, port, host, currentsequence, result):

  1. AgentUpdate
   tempacks = packacks()
   del ack_need_list[:]
   if tempacks == "": 
       flags = 0x00
   else:
       flags = 0x10
   #print "tempacks is:", ByteToHex(tempacks)  
       
   data_header = pack('>BLB', flags,currentsequence,0x00)
   packed_data_message_ID = pack('>B',0x04)
   packed_data_ID = uuid.UUID(result["agent_id"]).bytes + uuid.UUID(result["session_id"]).bytes
   packed_data_QuatRots = pack('<ffff', 0.0,0.0,0.0,0.0)+pack('<ffff', 0.0,0.0,0.0,0.0)  
   packed_data_State = pack('<B', 0x00)
   packed_data_Camera = pack('<fff', 0.0,0.0,0.0)+pack('<fff', 0.0,0.0,0.0)+pack('<fff', 0.0,0.0,0.0)+pack('<fff', 0.0,0.0,0.0)
   packed_data_Flags = pack('<fLB', 0.0,0x00,0x00)
   encoded_packed_data = zero_encode(packed_data_message_ID+packed_data_ID+packed_data_QuatRots+packed_data_State+packed_data_Camera+packed_data_Flags)
   packed_data = data_header + encoded_packed_data+tempacks
  # print "sending AgentUpdate to server",ByteToHex(packed_data_header+zero_decode(encoded_packed_data)+ tempacks)
   
   sock.sendto(packed_data, (host, port))
   return

def sendCompletePingCheck(sock, port, host, currentsequence,data,lastPingSent):

  1. print "data from PingCHeck", ByteToHex(data)
   data_header = pack('>BLB', 0x00,currentsequence,0x00)
   packed_data_message_ID = pack('>B',0x02)
   packed_data = data_header + packed_data_message_ID+pack('>B', lastPingSent)
   print "CompletePingCheck packet sent:", ByteToHex(packed_data)
   sock.sendto(packed_data, (host, port))
   
   return
   

def sendPacketAck(sock, port, host,currentsequence):

   tempacks = packacks()
   templen = len(ack_need_list)
   del ack_need_list[:]
   data_header = pack('>BLB',0x00,currentsequence,0x00) 
   packed_data_message_ID = pack('>L',0xFFFFFFFB)
   packed_ack_len = pack('>B',templen)
   
   packed_data = data_header + packed_data_message_ID + packed_ack_len + tempacks
  1. ===============================================================================
  2. t = datetime.now()
  3. t.strftime("%H:%M:%S")
  4. ti = "%02d:%02d:%02d.%06d" % (t.hour,t.minute,t.second,t.microsecond)
  5. print ti, "PacketAck packet sent:", ByteToHex(packed_data)
  6. ===============================================================================
   sock.sendto(packed_data, (host, port))
   return

def sendLogoutRequest(sock, port, host,seqnum,aUUID,sUUID):

   packed_data = ""
   packed_data_message_ID = pack('>L',0xffff00fc)
   data_header = pack('>BLB', 0x00,seqnum,0x00)
   packed_data += uuid.UUID(aUUID).bytes+uuid.UUID(sUUID).bytes+ pack(">L",0x00)
   
   packed_data = data_header + packed_data_message_ID + packed_data
   sock.sendto(packed_data, (host, port))
   return


def establishpresence(host, port, circuit_code):


   sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  1. Sending packet UseCircuitCode <-- Inits the connection to the sim.
   data = pack('>BLBL',0x00,0x01,00,0xffff0003) + pack('<L',circuit_code) + uuid.UUID(result["session_id"]).bytes+uuid.UUID(result["agent_id"]).bytes
   sock.sendto(data, (host, port))
  1. ISending packet CompleteAgentMovement <-- establishes the agent's presence
   data = pack('>BLBL',0x00,0x02,00,0xffff00f9) + uuid.UUID(result["agent_id"]).bytes + uuid.UUID(result["session_id"]).bytes + pack('<L', circuit_code)
   sock.sendto(data, (host, port))
   sendAgentUpdate(sock, port, host, 3, result)
   aUUID = [result["agent_id"]]
   sendUUIDNameRequest(sock, port, host, 4,aUUID)
   buf = 100
   i = 0
   trusted_count = 0
   ackable = 0
   trusted_and_ackable = 0
   ack_need_list_changed = False
   seqnum = 5
   lastPingSent = 0 
   trusted = 0
   while True:
       if ack_need_list_changed:
           ack_need_list_changed = False
           seqnum += 1
           sendPacketAck(sock, port, host,seqnum)
           #sendAgentUpdate(sock, port, host, seqnum, result)
           seqnum += 1
       #sendacks()
       i += 1
       data,addr = sock.recvfrom(buf)
       t = datetime.now()
       t.strftime("%H:%M:%S")


       if not data:
           print "Client has exited!"
           
           break
       else:
           test =  ByteToHex(data).split()
           #print test
           ID = data[6:12]
           #print "ID =", ByteToHex(ID) 
           if ord(data[0])&0x80: 
               ID = zero_decode_ID(data[6:12])
               
           if ord(data[0])&0x40: 
               scheduleacknowledgemessage(data); 
               ack_need_list_changed = True
           #print "ID =", ByteToHex(ID) 
           #print "ID =", unpack(">L", ID[:4])
           if ID[0] == '\xFF':
               if ID[1] == '\xFF':
                   if ID[2] == '\xFF':
                       myentry = mypacketdictionary[("Fixed" , "0x"+ByteToHex(ID[0:4]).replace(' ', ))]
                       if myentry[1] == "Trusted":
                           trusted += 1;
                       ti = "%02d:%02d:%02d.%06d" % (t.hour,t.minute,t.second,t.microsecond)
                       print ti, "Message #", i, "trusted count is", trusted,"Flags: 0x" + test[0], myentry,  "sequence #", unpack(">L",data[1:5])
                           
                       #if myentry[1] == "Trusted": trusted_count += 1;print "number of trusted messages =", trusted_count
                       #if ord(data[0])&0x40 and myentry[1] == "Trusted": trusted_and_ackable += 1; print "trusted_and_ackable =", trusted_and_ackable
                       #if ord(data[0])&0x40: ackable += 1; print "number of ackable messages = ", ackable
                   else:
                       myentry = mypacketdictionary[("Low",int(ByteToHex(ID[2:4]).replace(' ', ),16))]
                       if myentry[1] == "Trusted":
                           trusted += 1;
                       ti = "%02d:%02d:%02d.%06d" % (t.hour,t.minute,t.second,t.microsecond)
                       print ti, "Message #", i,"trusted count is", trusted,"Flags: 0x" + test[0], myentry,   "sequence #", unpack(">L",data[1:5])
                       if myentry[0] == "UUIDNameReply":
                           pass
                           #print ByteToHex(data)
                           #print data[:28]
                           #print data[28:36],data[38:45]
                       elif myentry[0] == "RegionHandshake":
                           sendRegionHandshakeReply(sock, port, host, seqnum,result["agent_id"],result["session_id"])
                           seqnum += 1
                       
                       #if myentry[1] == "Trusted": trusted_count += 1;print "number of trusted messages =", trusted_count
                       #if ord(data[0])&0x40 and myentry[1] == "Trusted": trusted_and_ackable += 1; print "trusted_and_ackable =", trusted_and_ackable
                       #if ord(data[0])&0x40: ackable += 1; print "number of ackable messages = ", ackable
               else:
                   myentry = mypacketdictionary[("Medium", int(ByteToHex(ID[1:2]).replace(' ', ),16))]
                   if myentry[1] == "Trusted":
                       trusted += 1;
                   ti = "%02d:%02d:%02d.%06d" % (t.hour,t.minute,t.second,t.microsecond)
                   print ti, "Message #", i,"trusted count is", trusted,"Flags: 0x" + test[0], myentry,  "sequence #", unpack(">L",data[1:5])
                   
                   
                   #if myentry[1] == "Trusted": trusted_count += 1;print "number of trusted messages =", trusted_count
                   #if ord(data[0])&0x40 and myentry[1] == "Trusted": trusted_and_ackable += 1; print "trusted_and_ackable =", trusted_and_ackable
                   #if ord(data[0])&0x40: ackable += 1; print "number of ackable messages = ", ackable
           else:
               myentry = mypacketdictionary[("High", int(ByteToHex(ID[0]), 16))]
               if myentry[0] == "StartPingCheck": 
                   print "data from StartPingCheck", test
                   sendCompletePingCheck(sock, port, host, seqnum,data,lastPingSent)
                   lastPingSent += 1
                   seqnum += 1
                   
               if myentry[1] == "Trusted":
                   trusted += 1;   
               ti = "%02d:%02d:%02d.%06d" % (t.hour,t.minute,t.second,t.microsecond)
               
               print ti, "Message #", i,"trusted count is", trusted,"Flags: 0x" + test[0], myentry,   "sequence #", unpack(">L",data[1:5])
               
               #if myentry[1] == "Trusted": trusted_count += 1;print "number of trusted messages =", trusted_count
               #if ord(data[0])&0x40 and myentry[1] == "Trusted": trusted_and_ackable += 1; print "trusted_and_ackable =",  trusted_and_ackable
               #if ord(data[0])&0x40: ackable += 1; print "number of ackable messages = ", ackable
   sendLogoutRequest(sock, port, host,seqnum,myAgentID,mySessionID)
   sock.close()
   print "final number of trusted messages =", trusted_count
   
   return



result = login("first", "last", "password", MAC)

mypacketdictionary = makepacketdict()

myhost = result["sim_ip"] myport = result["sim_port"] mycircuit_code = result["circuit_code"]

establishpresence(myhost, myport, mycircuit_code)

  1. cap_out = get_caps(result,"seed_capability", ["ChatSessionRequest"])




</python>