class P3

Constants

P3_END
P3_ESC
P3_START

Public Class Methods

new(hash={},&block) click to toggle source
# File lib/p3.rb, line 13
def initialize(hash={},&block)
  @p3mode=false
  @p3start=0
  @p3buf=[]
  @p3esc=false
  @clients={}
  @block=block
end

Public Instance Methods

inchar(ch) click to toggle source
# File lib/p3.rb, line 153
def inchar ch
  #puts "got:#{ch}"
  if ch==P3_START and not @p3esc and not @p3mode
    @p3mode=true
    @p3start=Time.now
    @p3buf=[]
  elsif ch==P3_END and not @p3esc and @p3mode
    @p3mode=false
    p3_packet_in @p3buf
    @p3buf=[]
  else
    if not @p3mode
      return false #not done, please process .. show to user
    else
      if @p3esc
        @p3esc=false
      elsif ch==P3_ESC
        @p3esc=true
        return
      end
      @p3buf<<ch
    end
  end
  return true #char was done -- do not process
end
p3_packet_in(buf) click to toggle source
# File lib/p3.rb, line 89
def p3_packet_in buf
  #puts "packet in #{buf}"
  pac= unpack buf
  return if not pac
  pp pac
  pp @clients
  if pac[:proto]=="U"
    if not @clients[pac[:mac]]
      puts "new client #{pac[:mac]}"
      @clients[pac[:mac]]={socket: UDPSocket.new,created:Time.now,count_r:0, count_s:0}
      @clients[pac[:mac]][:thread]=Thread.new(pac[:mac]) do |my_mac|
        loop do
          begin
            r,stuff=@clients[my_mac][:socket].recvfrom(2000) #get_packet --high level func!
            ip=stuff[2]
            port=stuff[1]
            #puts "got reply '#{r}' from server #{ip}:#{port} to our mac #{my_mac}"
            pac={
              proto:'U',
              mac: my_mac,
              ip: ip,
              port:port,
              data:r,
            }
            #pp pac
            # received return packet from server!
            if @block
              @block.call pac
            end
            #$sp.write pack pac
            @clients[my_mac][:last_r]=Time.now
            @clients[my_mac][:count_r]+=1
           rescue => e
            puts "thread dies..."
            p e
            p e.backtrace
          end
        end
      end
      pp @clients
    end
    @clients[pac[:mac]][:socket].send(pac[:data].pack("C*"), 0, pac[:ip], pac[:port])
    _,port,_,_ = @clients[pac[:mac]][:socket].addr
    @clients[pac[:mac]][:gw_port]=port
    @clients[pac[:mac]][:last_s]=Time.now
    @clients[pac[:mac]][:count_s]+=1
    pp @clients
  end
end
pack(pac) click to toggle source
# File lib/p3.rb, line 55
def pack pac #builds p3 packet from  pac object
  #pp pac
  begin
    buf=[]
    buf<<pac[:proto].ord
    macs=pac[:mac].split(":")
    buf<<macs[0].to_i(16)
    buf<<macs[1].to_i(16)
    buf<<0
    buf<<0
    ips=pac[:ip].split(".")
    buf<<ips[3].to_i
    buf<<ips[2].to_i
    buf<<ips[1].to_i
    buf<<ips[0].to_i
    buf<<pac[:port]/0x100
    buf<<(pac[:port]&0xff)
    buf<<pac[:data].size
    buf+=pac[:data].unpack("C*")
    check=0
    buf.each do |b|
      check^=b
    end
    buf<<check
    #pp buf
    #pp "~#{buf.pack("C*")}~"
    return "~#{buf.pack("C*")}~"
  rescue => e
    p e
    p e.backtrace
  end
  return nil
end
shutdown() click to toggle source
# File lib/p3.rb, line 139
def shutdown
  @clients.each do |k,c|
    if c[:socket]
      c[:socket].close
      puts "closed #{k}: #{c[:socket]}"
    end
    if c[:thread]
      c[:thread].kill
      puts "killed #{k}: #{c[:thread]}"
    end
  end
  @clients={}
end
unpack(buf) click to toggle source
# File lib/p3.rb, line 22
def unpack buf #buils object from packet byte array
  blen=buf.size
  #puts "GOT: buf<#{buf}> buflen=#{buf.size}"
  return if blen<4
  check2=0
  buf[0...blen-1].each do |b|
    check2^=b
  end
  i=0
  proto=buf[i].chr
  i+=1
  mac=sprintf "%02X:%02X",buf[i],buf[i+1]
  i+=4
  ip=sprintf "%d.%d.%d.%d",buf[i+3],buf[i+2],buf[i+1],buf[i]
  i+=4
  port=buf[i]*0x100+buf[i+1]
  i+=2
  len=buf[i]
  i+=1
  check=buf[i+len]
  data=buf[i...i+len]
  pac={
    proto:proto,
    mac: mac,
    ip: ip,
    port:port,
    data:data,
  }
  #puts "proto=#{proto},mac=#{mac},ip=#{ip},socket=#{socket},len=#{len},check=#{check}==#{check2},data='#{data.pack("C*")}'"
end