Workarround pra classe TCPSocket Hitskin_logo Hitskin.com

Isto é uma pré-visualização de um tema em Hitskin.com
Instalar o temaVoltar para a ficha do tema

Aldeia RPG
Gostaria de reagir a esta mensagem? Crie uma conta em poucos cliques ou inicie sessão para continuar.

Workarround pra classe TCPSocket

2 participantes

Ir para baixo

Workarround pra classe TCPSocket Empty Workarround pra classe TCPSocket

Mensagem por Cidiomar Dom Jan 29, 2012 2:57 am

Este script cria a possibilidade de conexão com a internet via TCPSocket pelo RPGMaker VXAce.

Não devo mais precisar desde script, por tanto não devo mais atualiza-lo, então resolvi postar.

Ela possui dependências não supridas pelo RGSS3, ele inclui a extensão dl, mas não os seus arquivos .rb(com exceção do 'Win32API.rb'), então será necessário repor esses scripts:

Código:

#
#      thread.rb - thread support classes
#         by Yukihiro Matsumoto <matz@netlab.co.jp>
#
# Copyright (C) 2001  Yukihiro Matsumoto
# Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
# Copyright (C) 2000  Information-technology Promotion Agency, Japan
#

unless defined? Thread
  raise "Thread not available for this ruby interpreter"
end

unless defined? ThreadError
  class ThreadError < StandardError
  end
end

if $DEBUG
  Thread.abort_on_exception = true
end

#
# ConditionVariable objects augment class Mutex. Using condition variables,
# it is possible to suspend while in the middle of a critical section until a
# resource becomes available.
#
# Example:
#
#  require 'thread'
#
#  mutex = Mutex.new
#  resource = ConditionVariable.new

#  a = Thread.new {
#    mutex.synchronize {
#      # Thread 'a' now needs the resource
#      resource.wait(mutex)
#      # 'a' can now have the resource
#    }
#  }

#  b = Thread.new {
#    mutex.synchronize {
#      # Thread 'b' has finished using the resource
#      resource.signal
#    }
#  }
#
class ConditionVariable
  #
  # Creates a new ConditionVariable
  #
  def initialize
    @waiters = []
    @waiters_mutex = Mutex.new
  end
 
  #
  # Releases the lock held in +mutex+ and waits; reacquires the lock on wakeup.
  #
  def wait(mutex)
    begin
      # TODO: mutex should not be used
      @waiters_mutex.synchronize do
        @waiters.push(Thread.current)
      end
      mutex.sleep
    end
  end
 
  #
  # Wakes up the first thread in line waiting for this lock.
  #
  def signal
    begin
      t = @waiters_mutex.synchronize { @waiters.shift }
      t.run if t
    rescue ThreadError
      retry
    end
  end
   
  #
  # Wakes up all threads waiting for this lock.
  #
  def broadcast
    # TODO: imcomplete
    waiters0 = nil
    @waiters_mutex.synchronize do
      waiters0 = @waiters.dup
      @waiters.clear
    end
    for t in waiters0
      begin
   t.run
      rescue ThreadError
      end
    end
  end
end

#
# This class provides a way to synchronize communication between threads.
#
# Example:
#
#  require 'thread'

#  queue = Queue.new

#  producer = Thread.new do
#    5.times do |i|
#      sleep rand(i) # simulate expense
#      queue << i
#      puts "#{i} produced"
#    end
#  end

#  consumer = Thread.new do
#    5.times do |i|
#      value = queue.pop
#      sleep rand(i/2) # simulate expense
#      puts "consumed #{value}"
#    end
#  end

#  consumer.join
#
class Queue
  #
  # Creates a new queue.
  #
  def initialize
    @que = []
    @waiting = []
    @que.taint      # enable tainted comunication
    @waiting.taint
    self.taint
    @mutex = Mutex.new
  end

  #
  # Pushes +obj+ to the queue.
  #
  def push(obj)
    t = nil
    @mutex.synchronize{
      @que.push obj
      begin
        t = @waiting.shift
        t.wakeup if t
      rescue ThreadError
        retry
      end
    }
    begin
      t.run if t
    rescue ThreadError
    end
  end

  #
  # Alias of push
  #
  alias << push

  #
  # Alias of push
  #
  alias enq push

  #
  # Retrieves data from the queue.  If the queue is empty, the calling thread is
  # suspended until data is pushed onto the queue.  If +non_block+ is true, the
  # thread isn't suspended, and an exception is raised.
  #
  def pop(non_block=false)
    while true
      @mutex.synchronize{
        if @que.empty?
          raise ThreadError, "queue empty" if non_block
          @waiting.push Thread.current
          @mutex.sleep
        else
          return @que.shift
        end
      }
    end
  end

  #
  # Alias of pop
  #
  alias shift pop

  #
  # Alias of pop
  #
  alias deq pop

  #
  # Returns +true+ if the queue is empty.
  #
  def empty?
    @que.empty?
  end

  #
  # Removes all objects from the queue.
  #
  def clear
    @que.clear
  end

  #
  # Returns the length of the queue.
  #
  def length
    @que.length
  end

  #
  # Alias of length.
  #
  alias size length

  #
  # Returns the number of threads waiting on the queue.
  #
  def num_waiting
    @waiting.size
  end
end

#
# This class represents queues of specified size capacity.  The push operation
# may be blocked if the capacity is full.
#
# See Queue for an example of how a SizedQueue works.
#
class SizedQueue < Queue
  #
  # Creates a fixed-length queue with a maximum size of +max+.
  #
  def initialize(max)
    raise ArgumentError, "queue size must be positive" unless max > 0
    @max = max
    @queue_wait = []
    @queue_wait.taint      # enable tainted comunication
    super()
  end

  #
  # Returns the maximum size of the queue.
  #
  def max
    @max
  end

  #
  # Sets the maximum size of the queue.
  #
  def max=(max)
    diff = nil
    @mutex.synchronize {
      if max <= @max
        @max = max
      else
        diff = max - @max
        @max = max
      end
    }
    if diff
      diff.times do
   begin
     t = @queue_wait.shift
     t.run if t
   rescue ThreadError
     retry
   end
      end
    end
    max
  end

  #
  # Pushes +obj+ to the queue.  If there is no space left in the queue, waits
  # until space becomes available.
  #
  def push(obj)
    t = nil
    @mutex.synchronize{
      while true
        break if @que.length < @max
        @queue_wait.push Thread.current
        @mutex.sleep
      end
   
      @que.push obj
      begin
        t = @waiting.shift
        t.wakeup if t
      rescue ThreadError
        retry
      end
    }
   
    begin
      t.run if t
    rescue ThreadError
    end
  end

  #
  # Alias of push
  #
  alias << push

  #
  # Alias of push
  #
  alias enq push

  #
  # Retrieves data from the queue and runs a waiting thread, if any.
  #
  def pop(*args)
    retval = super
    t = nil
    @mutex.synchronize {
      if @que.length < @max
        begin
          t = @queue_wait.shift
          t.wakeup if t
        rescue ThreadError
          retry
        end
      end
    }
    begin
      t.run if t
    rescue ThreadError
    end
    retval
  end

  #
  # Alias of pop
  #
  alias shift pop

  #
  # Alias of pop
  #
  alias deq pop

  #
  # Returns the number of threads waiting on the queue.
  #
  def num_waiting
    @waiting.size + @queue_wait.size
  end
end

# Documentation comments:
#  - How do you make RDoc inherit documentation from superclass?
#require 'dl'
#require 'thread'

module DL
  SEM = Mutex.new

  def set_callback_internal(proc_entry, addr_entry, argc, ty, &cbp)
    if( argc < 0 )
      raise(ArgumentError, "arity should not be less than 0.")
    end
    addr = nil
    SEM.synchronize{
      ary = proc_entry[ty]
      (0...MAX_CALLBACK).each{|n|
        idx = (n * DLSTACK_SIZE) + argc
        if( ary[idx].nil? )
          ary[idx] = cbp
          addr = addr_entry[ty][idx]
          break
        end
      }
    }
    addr
  end

  def set_cdecl_callback(ty, argc, &cbp)
    set_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, argc, ty, &cbp)
  end

  def set_stdcall_callback(ty, argc, &cbp)
    set_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, argc, ty, &cbp)
  end

  def remove_callback_internal(proc_entry, addr_entry, addr, ctype = nil)
    index = nil
    if( ctype )
      addr_entry[ctype].each_with_index{|xaddr, idx|
        if( xaddr == addr )
          index = idx
        end
      }
    else
      addr_entry.each{|ty,entry|
        entry.each_with_index{|xaddr, idx|
          if( xaddr == addr )
            index = idx
          end
        }
      }
    end
    if( index and proc_entry[ctype][index] )
      proc_entry[ctype][index] = nil
      return true
    else
      return false
    end
  end

  def remove_cdecl_callback(addr, ctype = nil)
    remove_callback_internal(CdeclCallbackProcs, CdeclCallbackAddrs, addr, ctype)
  end

  def remove_stdcall_callback(addr, ctype = nil)
    remove_callback_internal(StdcallCallbackProcs, StdcallCallbackAddrs, addr, ctype)
  end

  alias set_callback set_cdecl_callback
  alias remove_callback remove_cdecl_callback
end
module DL
  module CParser
    def parse_struct_signature(signature, tymap=nil)
      if( signature.is_a?(String) )
        signature = signature.split(/\s*,\s*/)
      end
      mems = []
      tys  = []
      signature.each{|msig|
        tks = msig.split(/\s+(\*)?/)
        ty = tks[0..-2].join(" ")
        member = tks[-1]

        case ty
        when /\[(\d+)\]/
          n = $1.to_i
          ty.gsub!(/\s*\[\d+\]/,"")
          ty = [ty, n]
        when /\[\]/
          ty.gsub!(/\s*\[\]/, "*")
        end

        case member
        when /\[(\d+)\]/
          ty = [ty, $1.to_i]
          member.gsub!(/\s*\[\d+\]/,"")
        when /\[\]/
          ty = ty + "*"
          member.gsub!(/\s*\[\]/, "")
        end

        mems.push(member)
        tys.push(parse_ctype(ty,tymap))
      }
      return tys, mems
    end

    def parse_signature(signature, tymap=nil)
      tymap ||= {}
      signature = signature.gsub(/\s+/, " ").strip
      case signature
      when /^([\d\w@\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
        ret = $1
        (args = $2).strip!
        ret = ret.split(/\s+/)
        args = args.split(/\s*,\s*/)
        func = ret.pop
        if( func =~ /^\*/ )
          func.gsub!(/^\*+/,"")
          ret.push("*")
        end
        ret  = ret.join(" ")
        return [func, parse_ctype(ret, tymap), args.collect{|arg| parse_ctype(arg, tymap)}]
      else
        raise(RuntimeError,"can't parse the function prototype: #{proto}")
      end
    end

    def parse_ctype(ty, tymap=nil)
      tymap ||= {}
      case ty
      when Array
        return [parse_ctype(ty[0], tymap), ty[1]]
      when "void"
        return TYPE_VOID
      when "char"
        return TYPE_CHAR
      when "unsigned char"
        return  -TYPE_CHAR
      when "short"
        return TYPE_SHORT
      when "unsigned short"
        return -TYPE_SHORT
      when "int"
        return TYPE_INT
      when "unsigned int"
        return -TYPE_INT
      when "long"
        return TYPE_LONG
      when "unsigned long"
        return -TYPE_LONG
      when "long long"
        if( defined?(TYPE_LONG_LONG) )
          return TYPE_LONG_LONG
        else
          raise(RuntimeError, "unsupported type: #{ty}")
        end
      when "unsigned long long"
        if( defined?(TYPE_LONG_LONG) )
          return -TYPE_LONG_LONG
        else
          raise(RuntimeError, "unsupported type: #{ty}")
        end
      when "float"
        return TYPE_FLOAT
      when "double"
        return TYPE_DOUBLE
      when /\*/, /\[\s*\]/
        return TYPE_VOIDP
      else
        if( tymap[ty] )
          return parse_ctype(tymap[ty], tymap)
        else
          raise(DLError, "unknown type: #{ty}", caller(1))
        end
      end
    end
  end
end
#require 'dl'

module DL
  module PackInfo
    if( defined?(TYPE_LONG_LONG) )
    ALIGN_MAP = {
      TYPE_VOIDP => ALIGN_VOIDP,
      TYPE_CHAR  => ALIGN_CHAR,
      TYPE_SHORT => ALIGN_SHORT,
      TYPE_INT  => ALIGN_INT,
      TYPE_LONG  => ALIGN_LONG,
      TYPE_LONG_LONG => ALIGN_LONG_LONG,
      TYPE_FLOAT => ALIGN_FLOAT,
      TYPE_DOUBLE => ALIGN_DOUBLE,
      -TYPE_CHAR  => ALIGN_CHAR,
      -TYPE_SHORT => ALIGN_SHORT,
      -TYPE_INT  => ALIGN_INT,
      -TYPE_LONG  => ALIGN_LONG,
      -TYPE_LONG_LONG => ALIGN_LONG_LONG,
    }

    PACK_MAP = {
      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
      TYPE_CHAR  => "c",
      TYPE_SHORT => "s!",
      TYPE_INT  => "i!",
      TYPE_LONG  => "l!",
      TYPE_LONG_LONG => "q",
      TYPE_FLOAT => "f",
      TYPE_DOUBLE => "d",
      -TYPE_CHAR  => "c",
      -TYPE_SHORT => "s!",
      -TYPE_INT  => "i!",
      -TYPE_LONG  => "l!",
      -TYPE_LONG_LONG => "q",
    }

    SIZE_MAP = {
      TYPE_VOIDP => SIZEOF_VOIDP,
      TYPE_CHAR  => SIZEOF_CHAR,
      TYPE_SHORT => SIZEOF_SHORT,
      TYPE_INT  => SIZEOF_INT,
      TYPE_LONG  => SIZEOF_LONG,
      TYPE_LONG_LONG => SIZEOF_LONG_LONG,
      TYPE_FLOAT => SIZEOF_FLOAT,
      TYPE_DOUBLE => SIZEOF_DOUBLE,
      -TYPE_CHAR  => SIZEOF_CHAR,
      -TYPE_SHORT => SIZEOF_SHORT,
      -TYPE_INT  => SIZEOF_INT,
      -TYPE_LONG  => SIZEOF_LONG,
      -TYPE_LONG_LONG => SIZEOF_LONG_LONG,
    }
    else
    ALIGN_MAP = {
      TYPE_VOIDP => ALIGN_VOIDP,
      TYPE_CHAR  => ALIGN_CHAR,
      TYPE_SHORT => ALIGN_SHORT,
      TYPE_INT  => ALIGN_INT,
      TYPE_LONG  => ALIGN_LONG,
      TYPE_FLOAT => ALIGN_FLOAT,
      TYPE_DOUBLE => ALIGN_DOUBLE,
      -TYPE_CHAR  => ALIGN_CHAR,
      -TYPE_SHORT => ALIGN_SHORT,
      -TYPE_INT  => ALIGN_INT,
      -TYPE_LONG  => ALIGN_LONG,
    }

    PACK_MAP = {
      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG) ? "q" : "l!"),
      TYPE_CHAR  => "c",
      TYPE_SHORT => "s!",
      TYPE_INT  => "i!",
      TYPE_LONG  => "l!",
      TYPE_FLOAT => "f",
      TYPE_DOUBLE => "d",
      -TYPE_CHAR  => "c",
      -TYPE_SHORT => "s!",
      -TYPE_INT  => "i!",
      -TYPE_LONG  => "l!",
    }

    SIZE_MAP = {
      TYPE_VOIDP => SIZEOF_VOIDP,
      TYPE_CHAR  => SIZEOF_CHAR,
      TYPE_SHORT => SIZEOF_SHORT,
      TYPE_INT  => SIZEOF_INT,
      TYPE_LONG  => SIZEOF_LONG,
      TYPE_FLOAT => SIZEOF_FLOAT,
      TYPE_DOUBLE => SIZEOF_DOUBLE,
      -TYPE_CHAR  => SIZEOF_CHAR,
      -TYPE_SHORT => SIZEOF_SHORT,
      -TYPE_INT  => SIZEOF_INT,
      -TYPE_LONG  => SIZEOF_LONG,
    }
    end

    def align(addr, align)
      d = addr % align
      if( d == 0 )
        addr
      else
        addr + (align - d)
      end
    end
    module_function :align
  end

  class Packer
    include PackInfo

    def Packer.[](*types)
      Packer.new(types)
    end

    def initialize(types)
      parse_types(types)
    end

    def size()
      @size
    end
   
    def pack(ary)
      case SIZEOF_VOIDP
      when SIZEOF_LONG
        ary.pack(@template)
      when SIZEOF_LONG
        ary.pack(@template)
      else
        raise(RuntimeError, "sizeof(void*)?")
      end
    end

    def unpack(ary)
      case SIZEOF_VOIDP
      when SIZEOF_LONG
        ary.join().unpack(@template)
      when SIZEOF_LONG_LONG
        ary.join().unpack(@template)
      else
        raise(RuntimeError, "sizeof(void*)?")
      end
    end
   
    private
   
    def parse_types(types)
      @template = ""
      addr    = 0
      types.each{|t|
        orig_addr = addr
        if( t.is_a?(Array) )
          addr = align(orig_addr, ALIGN_MAP[TYPE_VOIDP])
        else
          addr = align(orig_addr, ALIGN_MAP[t])
        end
        d = addr - orig_addr
        if( d > 0 )
          @template << "x#{d}"
        end
        if( t.is_a?(Array) )
          @template << (PACK_MAP[t[0]] * t[1])
          addr += (SIZE_MAP[t[0]] * t[1])
        else
          @template << PACK_MAP[t]
          addr += SIZE_MAP[t]
        end
      }
      addr = align(addr, ALIGN_MAP[TYPE_VOIDP])
      @size = addr
    end
  end
end
#require 'dl'

module DL
  class Stack
    def Stack.[](*types)
      Stack.new(types)
    end

    def initialize(types)
      parse_types(types)
    end

    def size()
      @size
    end

    def types()
      @types
    end

    def pack(ary)
      case SIZEOF_VOIDP
      when SIZEOF_LONG
        ary.pack(@template).unpack('l!*')
      when SIZEOF_LONG_LONG
        ary.pack(@template).unpack('q*')
      else
        raise(RuntimeError, "sizeof(void*)?")
      end
    end

    def unpack(ary)
      case SIZEOF_VOIDP
      when SIZEOF_LONG
        ary.pack('l!*').unpack(@template)
      when SIZEOF_LONG_LONG
        ary.pack('q*').unpack(@template)
      else
        raise(RuntimeError, "sizeof(void*)?")
      end
    end
   
    private
   
    def align(addr, align)
      d = addr % align
      if( d == 0 )
        addr
      else
        addr + (align - d)
      end
    end

if( defined?(TYPE_LONG_LONG) )
    ALIGN_MAP = {
      TYPE_VOIDP => ALIGN_VOIDP,
      TYPE_CHAR  => ALIGN_VOIDP,
      TYPE_SHORT => ALIGN_VOIDP,
      TYPE_INT  => ALIGN_VOIDP,
      TYPE_LONG  => ALIGN_VOIDP,
      TYPE_LONG_LONG => ALIGN_LONG_LONG,
      TYPE_FLOAT => ALIGN_FLOAT,
      TYPE_DOUBLE => ALIGN_DOUBLE,
    }

    PACK_MAP = {
      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
      TYPE_CHAR  => "c",
      TYPE_SHORT => "s!",
      TYPE_INT  => "i!",
      TYPE_LONG  => "l!",
      TYPE_LONG_LONG => "q",
      TYPE_FLOAT => "f",
      TYPE_DOUBLE => "d",
    }

    SIZE_MAP = {
      TYPE_VOIDP => SIZEOF_VOIDP,
      TYPE_CHAR  => SIZEOF_CHAR,
      TYPE_SHORT => SIZEOF_SHORT,
      TYPE_INT  => SIZEOF_INT,
      TYPE_LONG  => SIZEOF_LONG,
      TYPE_LONG_LONG => SIZEOF_LONG_LONG,
      TYPE_FLOAT => SIZEOF_FLOAT,
      TYPE_DOUBLE => SIZEOF_DOUBLE,
    }
else
    ALIGN_MAP = {
      TYPE_VOIDP => ALIGN_VOIDP,
      TYPE_CHAR  => ALIGN_VOIDP,
      TYPE_SHORT => ALIGN_VOIDP,
      TYPE_INT  => ALIGN_VOIDP,
      TYPE_LONG  => ALIGN_VOIDP,
      TYPE_FLOAT => ALIGN_FLOAT,
      TYPE_DOUBLE => ALIGN_DOUBLE,
    }

    PACK_MAP = {
      TYPE_VOIDP => ((SIZEOF_VOIDP == SIZEOF_LONG_LONG)? "q" : "l!"),
      TYPE_CHAR  => "c",
      TYPE_SHORT => "s!",
      TYPE_INT  => "i!",
      TYPE_LONG  => "l!",
      TYPE_FLOAT => "f",
      TYPE_DOUBLE => "d",
    }

    SIZE_MAP = {
      TYPE_VOIDP => SIZEOF_VOIDP,
      TYPE_CHAR  => SIZEOF_CHAR,
      TYPE_SHORT => SIZEOF_SHORT,
      TYPE_INT  => SIZEOF_INT,
      TYPE_LONG  => SIZEOF_LONG,
      TYPE_FLOAT => SIZEOF_FLOAT,
      TYPE_DOUBLE => SIZEOF_DOUBLE,
    }
end

    def parse_types(types)
      @types = types
      @template = ""
      addr      = 0
      types.each{|t|
        addr = add_padding(addr, ALIGN_MAP[t])
        @template << PACK_MAP[t]
        addr += SIZE_MAP[t]
      }
      addr = add_padding(addr, ALIGN_MAP[SIZEOF_VOIDP])
      if( addr % SIZEOF_VOIDP == 0 )
        @size = addr / SIZEOF_VOIDP
      else
        @size = (addr / SIZEOF_VOIDP) + 1
      end
    end

    def add_padding(addr, align)
      orig_addr = addr
      addr = align(orig_addr, align)
      d = addr - orig_addr
      if( d > 0 )
        @template << "x#{d}"
      end
      addr
    end
  end
end
#require 'dl'

module DL
  module ValueUtil
    def unsigned_value(val, ty)
      case ty.abs
      when TYPE_CHAR
        [val].pack("c").unpack("C")[0]
      when TYPE_SHORT
        [val].pack("s!").unpack("S!")[0]
      when TYPE_INT
        [val].pack("i!").unpack("I!")[0]
      when TYPE_LONG
        [val].pack("l!").unpack("L!")[0]
      when TYPE_LONG_LONG
        [val].pack("q!").unpack("Q!")[0]
      else
        val
      end
    end

    def signed_value(val, ty)
      case ty.abs
      when TYPE_CHAR
        [val].pack("C").unpack("c")[0]
      when TYPE_SHORT
        [val].pack("S!").unpack("s!")[0]
      when TYPE_INT
        [val].pack("I!").unpack("i!")[0]
      when TYPE_LONG
        [val].pack("L!").unpack("l!")[0]
      when TYPE_LONG_LONG
        [val].pack("Q!").unpack("q!")[0]
      else
        val
      end
    end

    def wrap_args(args, tys, funcs, &block)
      result = []
      tys ||= []
      args.each_with_index{|arg, idx|
        result.push(wrap_arg(arg, tys[idx], funcs, &block))
      }
      result
    end

    def wrap_arg(arg, ty, funcs, &block)
        funcs ||= []
        case arg
        when nil
          return 0
        when CPtr
          return arg.to_i
        when IO
          case ty
          when TYPE_VOIDP
            return CPtr[arg].to_i
          else
            return arg.to_i
          end
        when Function
          if( block )
            arg.bind_at_call(&block)
            funcs.push(arg)
          elsif !arg.bound?
            raise(RuntimeError, "block must be given.")
          end
          return arg.to_i
        when String
          if( ty.is_a?(Array) )
            return arg.unpack('C*')
          else
            case SIZEOF_VOIDP
            when SIZEOF_LONG
              return [arg].pack("p").unpack("l!")[0]
            when SIZEOF_LONG_LONG
              return [arg].pack("p").unpack("q")[0]
            else
              raise(RuntimeError, "sizeof(void*)?")
            end
          end
        when Float, Integer
          return arg
        when Array
          if( ty.is_a?(Array) ) # used only by struct
            case ty[0]
            when TYPE_VOIDP
              return arg.collect{|v| Integer(v)}
            when TYPE_CHAR
              if( arg.is_a?(String) )
                return val.unpack('C*')
              end
            end
            return arg
          else
            return arg
          end
        else
          if( arg.respond_to?(:to_ptr) )
            return arg.to_ptr.to_i
          else
            begin
              return Integer(arg)
            rescue
              raise(ArgumentError, "unknown argument type: #{arg.class}")
            end
          end
        end
    end
  end
end
#require 'dl'
#require 'dl/pack.rb'

module DL
  class CStruct
    def CStruct.entity_class()
      CStructEntity
    end
  end

  class CUnion
    def CUnion.entity_class()
      CUnionEntity
    end
  end

  module CStructBuilder
    def create(klass, types, members)
      new_class = Class.new(klass){
        define_method(:initialize){|addr|
          @entity = klass.entity_class.new(addr, types)
          @entity.assign_names(members)
        }
        define_method(:to_ptr){ @entity }
        define_method(:to_i){ @entity.to_i }
        members.each{|name|
          define_method(name){ @entity[name] }
          define_method(name + "="){|val| @entity[name] = val }
        }
      }
      size = klass.entity_class.size(types)
      new_class.module_eval(<<-EOS)
        def new_class.size()
          #{size}
        end
        def new_class.malloc()
          addr = DL.malloc(#{size})
          new(addr)
        end
      EOS
      return new_class
    end
    module_function :create
  end
 
  class CStructEntity < CPtr
    include PackInfo
    include ValueUtil

    def CStructEntity.malloc(types, func = nil)
      addr = DL.malloc(CStructEntity.size(types))
      CStructEntity.new(addr, types, func)
    end

    def CStructEntity.size(types)
      offset = 0
      max_align = 0
      types.each_with_index{|t,i|
        orig_offset = offset
        if( t.is_a?(Array) )
          align = PackInfo::ALIGN_MAP[t[0]]
          offset = PackInfo.align(orig_offset, align)
          size = offset - orig_offset
          offset += (PackInfo::SIZE_MAP[t[0]] * t[1])
        else
          align = PackInfo::ALIGN_MAP[t]
          offset = PackInfo.align(orig_offset, align)
          size = offset - orig_offset
          offset += PackInfo::SIZE_MAP[t]
        end
        if (max_align < align)
          max_align = align
        end
      }
      offset = PackInfo.align(offset, max_align)
      offset
    end

    def initialize(addr, types, func = nil)
      set_ctypes(types)
      super(addr, @size, func)
    end

    def assign_names(members)
      @members = members
    end

    def set_ctypes(types)
      @ctypes = types
      @offset = []
      offset = 0
      max_align = 0
      types.each_with_index{|t,i|
        orig_offset = offset
        if( t.is_a?(Array) )
          align = ALIGN_MAP[t[0]]
        else
          align = ALIGN_MAP[t]
        end
        offset = PackInfo.align(orig_offset, align)
        size = offset - orig_offset
        @offset[i] = offset
        if( t.is_a?(Array) )
          offset += (SIZE_MAP[t[0]] * t[1])
        else
          offset += SIZE_MAP[t]
        end
        if (max_align < align)
          max_align = align
        end
      }
      offset = PackInfo.align(offset, max_align)
      @size = offset
    end

    def [](name)
      idx = @members.index(name)
      if( idx.nil? )
        raise(ArgumentError, "no such member: #{name}")
      end
      ty = @ctypes[idx]
      if( ty.is_a?(Array) )
        r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1])
      else
        r = super(@offset[idx], SIZE_MAP[ty.abs])
      end
      packer = Packer.new([ty])
      val = packer.unpack([r])
      case ty
      when Array
        case ty[0]
        when TYPE_VOIDP
          val = val.collect{|v| CPtr.new(v)}
        end
      when TYPE_VOIDP
        val = CPtr.new(val[0])
      else
        val = val[0]
      end
      if( ty.is_a?(Integer) && (ty < 0) )
        return unsigned_value(val, ty)
      elsif( ty.is_a?(Array) && (ty[0] < 0) )
        return val.collect{|v| unsigned_value(v,ty[0])}
      else
        return val
      end
    end

    def []=(name, val)
      idx = @members.index(name)
      if( idx.nil? )
        raise(ArgumentError, "no such member: #{name}")
      end
      ty  = @ctypes[idx]
      packer = Packer.new([ty])
      val = wrap_arg(val, ty, [])
      buff = packer.pack([val].flatten())
      super(@offset[idx], buff.size, buff)
      if( ty.is_a?(Integer) && (ty < 0) )
        return unsigned_value(val, ty)
      elsif( ty.is_a?(Array) && (ty[0] < 0) )
        return val.collect{|v| unsigned_value(v,ty[0])}
      else
        return val
      end
    end

    def to_s()
      super(@size)
    end
  end

  class CUnionEntity < CStructEntity
    include PackInfo

    def CUnionEntity.malloc(types, func=nil)
      addr = DL.malloc(CUnionEntity.size(types))
      CUnionEntity.new(addr, types, func)
    end

    def CUnionEntity.size(types)
      size  = 0
      types.each_with_index{|t,i|
        if( t.is_a?(Array) )
          tsize = PackInfo::SIZE_MAP[t[0]] * t[1]
        else
          tsize = PackInfo::SIZE_MAP[t]
        end
        if( tsize > size )
          size = tsize
        end
      }
    end

    def set_ctypes(types)
      @ctypes = types
      @offset = []
      @size  = 0
      types.each_with_index{|t,i|
        @offset[i] = 0
        if( t.is_a?(Array) )
          size = SIZE_MAP[t[0]] * t[1]
        else
          size = SIZE_MAP[t]
        end
        if( size > @size )
          @size = size
        end
      }
    end
  end
end

module DL
  module Win32Types
    def included(m)
      m.module_eval{
        typealias "DWORD", "unsigned long"
        typealias "PDWORD", "unsigned long *"
        typealias "WORD", "unsigned short"
        typealias "PWORD", "unsigned short *"
        typealias "BOOL", "int"
        typealias "ATOM", "int"
        typealias "BYTE", "unsigned char"
        typealias "PBYTE", "unsigned char *"
        typealias "UINT", "unsigned int"
        typealias "ULONG", "unsigned long"
        typealias "UCHAR", "unsigned char"
        typealias "HANDLE", "unsigned long"
        typealias "PHANDLE", "void*"
        typealias "PVOID", "void*"
        typealias "LPCSTR", "char*"
        typealias "LPSTR", "char*"
        typealias "HINSTANCE", "unsigned int"
        typealias "HDC", "unsigned int"
        typealias "HWND", "unsigned int"
      }
    end
    module_function :included
  end

  module BasicTypes
    def included(m)
      m.module_eval{
        typealias "uint", "unsigned int"
        typealias "u_int", "unsigned int"
        typealias "ulong", "unsigned long"
        typealias "u_long", "unsigned long"
      }
    end
    module_function :included
  end
end
#require 'dl'
#require 'dl/callback'
#require 'dl/stack'
#require 'dl/value'
#require 'thread'

module DL
  class Function
    include DL
    include ValueUtil

    def initialize(cfunc, argtypes, &proc)
      @cfunc = cfunc
      @stack = Stack.new(argtypes.collect{|ty| ty.abs})
      if( @cfunc.ctype < 0 )
        @cfunc.ctype = @cfunc.ctype.abs
        @unsigned = true
      end
      if( proc )
        bind(&proc)
      end
    end

    def to_i()
      @cfunc.to_i
    end

    def check_safe_obj(val)
      if $SAFE > 0 and val.tainted?
        raise SecurityError, 'Insecure operation'
      end
    end

    def call(*args, &block)
      funcs = []
      args.each{|e| check_safe_obj(e) }
      check_safe_obj(block)
      args = wrap_args(args, @stack.types, funcs, &block)
      r = @cfunc.call(@stack.pack(args))
      funcs.each{|f| f.unbind_at_call()}
      return wrap_result(r)
    end

    def wrap_result(r)
      case @cfunc.ctype
      when TYPE_VOIDP
        r = CPtr.new(r)
      else
        if( @unsigned )
          r = unsigned_value(r, @cfunc.ctype)
        end
      end
      r
    end

    def bind(&block)
      if( !block )
        raise(RuntimeError, "block must be given.")
      end
      if( @cfunc.ptr == 0 )
        cb = Proc.new{|*args|
          ary = @stack.unpack(args)
          @stack.types.each_with_index{|ty, idx|
            case ty
            when TYPE_VOIDP
              ary[idx] = CPtr.new(ary[idx])
            end
          }
          r = block.call(*ary)
          wrap_arg(r, @cfunc.ctype, [])
        }
        case @cfunc.calltype
        when :cdecl
          @cfunc.ptr = set_cdecl_callback(@cfunc.ctype, @stack.size, &cb)
        when :stdcall
          @cfunc.ptr = set_stdcall_callback(@cfunc.ctype, @stack.size, &cb)
        else
          raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
        end
        if( @cfunc.ptr == 0 )
          raise(RuntimeException, "can't bind C function.")
        end
      end
    end

    def unbind()
      if( @cfunc.ptr != 0 )
        case @cfunc.calltype
        when :cdecl
          remove_cdecl_callback(@cfunc.ptr, @cfunc.ctype)
        when :stdcall
          remove_stdcall_callback(@cfunc.ptr, @cfunc.ctype)
        else
          raise(RuntimeError, "unsupported calltype: #{@cfunc.calltype}")
        end
        @cfunc.ptr = 0
      end
    end

    def bound?()
      @cfunc.ptr != 0
    end

    def bind_at_call(&block)
      bind(&block)
    end

    def unbind_at_call()
    end
  end

  class TempFunction < Function
    def bind_at_call(&block)
      bind(&block)
    end

    def unbind_at_call()
      unbind()
    end
  end

  class CarriedFunction < Function
    def initialize(cfunc, argtypes, n)
      super(cfunc, argtypes)
      @carrier = []
      @index = n
      @mutex = Mutex.new
    end

    def create_carrier(data)
      ary = []
      userdata = [ary, data]
      @mutex.lock()
      @carrier.push(userdata)
      return dlwrap(userdata)
    end

    def bind_at_call(&block)
      userdata = @carrier[-1]
      userdata[0].push(block)
      bind{|*args|
        ptr = args[@index]
        if( !ptr )
          raise(RuntimeError, "The index of userdata should be lower than #{args.size}.")
        end
        userdata = dlunwrap(Integer(ptr))
        args[@index] = userdata[1]
        userdata[0][0].call(*args)
      }
      @mutex.unlock()
    end
  end
end
#require 'dl'
#require 'dl/func.rb'
#require 'dl/struct.rb'
#require 'dl/cparser.rb'

module DL
  class CompositeHandler
    def initialize(handlers)
      @handlers = handlers
    end

    def handlers()
      @handlers
    end

    def sym(symbol)
      @handlers.each{|handle|
        if( handle )
          begin
            addr = handle.sym(symbol)
            return addr
          rescue DLError
          end
        end
      }
      return nil
    end

    def [](symbol)
      sym(symbol)
    end
  end

  module Importer
    include DL
    include CParser
    extend Importer

    def dlload(*libs)
      handles = libs.collect{|lib|
        case lib
        when nil
          nil
        when Handle
          lib
        when Importer
          lib.handlers
        else
          begin
            DL.dlopen(lib)
          rescue DLError
            raise(DLError, "can't load #{lib}")
          end
        end
      }.flatten()
      @handler = CompositeHandler.new(handles)
      @func_map = {}
      @type_alias = {}
    end

    def typealias(alias_type, orig_type)
      @type_alias[alias_type] = orig_type
    end

    def sizeof(ty)
      case ty
      when String
        ty = parse_ctype(ty, @type_alias).abs()
        case ty
        when TYPE_CHAR
          return SIZEOF_CHAR
        when TYPE_SHORT
          return SIZEOF_SHORT
        when TYPE_INT
          return SIZEOF_INT
        when TYPE_LONG
          return SIZEOF_LONG
        when TYPE_LONG_LONG
          return SIZEOF_LONG_LON
        when TYPE_FLOAT
          return SIZEOF_FLOAT
        when TYPE_DOUBLE
          return SIZEOF_DOUBLE
        when TYPE_VOIDP
          return SIZEOF_VOIDP
        else
          raise(DLError, "unknown type: #{ty}")
        end
      when Class
        if( ty.instance_methods().include?(:to_ptr) )
          return ty.size()
        end
      end
      return CPtr[ty].size()
    end

    def parse_bind_options(opts)
      h = {}
      prekey = nil
      while( opt = opts.shift() )
        case opt
        when :stdcall, :cdecl
          h[:call_type] = opt
        when :carried, :temp, :temporal, :bind
          h[:callback_type] = opt
          h[:carrier] = opts.shift()
        else
          h[opt] = true
        end
      end
      h
    end
    private :parse_bind_options

    def extern(signature, *opts)
      symname, ctype, argtype = parse_signature(signature, @type_alias)
      opt = parse_bind_options(opts)
      f = import_function(symname, ctype, argtype, opt[:call_type])
      name = symname.gsub(/@.+/,'')
      @func_map[name] = f
      # define_method(name){|*args,&block| f.call(*args,&block)}
      module_eval(<<-EOS)
        def #{name}(*args, &block)
          @func_map['#{name}'].call(*args,&block)
        end
      EOS
      module_function(name)
      f
    end

    def bind(signature, *opts, &blk)
      name, ctype, argtype = parse_signature(signature, @type_alias)
      h = parse_bind_options(opts)
      case h[:callback_type]
      when :bind, nil
        f = bind_function(name, ctype, argtype, h[:call_type], &blk)
      when :temp, :temporal
        f = create_temp_function(name, ctype, argtype, h[:call_type])
      when :carried
        f = create_carried_function(name, ctype, argtype, h[:call_type], h[:carrier])
      else
        raise(RuntimeError, "unknown callback type: #{h[:callback_type]}")
      end
      @func_map[name] = f
      #define_method(name){|*args,&block| f.call(*args,&block)}
      module_eval(<<-EOS)
        def #{name}(*args,&block)
          @func_map['#{name}'].call(*args,&block)
        end
      EOS
      module_function(name)
      f
    end

    def struct(signature)
      tys, mems = parse_struct_signature(signature, @type_alias)
      DL::CStructBuilder.create(CStruct, tys, mems)
    end

    def union(signature)
      tys, mems = parse_struct_signature(signature, @type_alias)
      DL::CStructBuilder.create(CUnion, tys, mems)
    end

    def [](name)
      @func_map[name]
    end

    def create_value(ty, val=nil)
      s = struct([ty + " value"])
      ptr = s.malloc()
      if( val )
        ptr.value = val
      end
      return ptr
    end
    alias value create_value

    def import_value(ty, addr)
      s = struct([ty + " value"])
      ptr = s.new(addr)
      return ptr
    end

    def import_symbol(name)
      addr = @handler.sym(name)
      if( !addr )
        raise(DLError, "cannot find the symbol: #{name}")
      end
      CPtr.new(addr)
    end

    def import_function(name, ctype, argtype, call_type = nil)
      addr = @handler.sym(name)
      if( !addr )
        raise(DLError, "cannot find the function: #{name}()")
      end
      Function.new(CFunc.new(addr, ctype, name, call_type || :cdecl), argtype)
    end

    def bind_function(name, ctype, argtype, call_type = nil, &block)
      f = Function.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
      f.bind(&block)
      f
    end

    def create_temp_function(name, ctype, argtype, call_type = nil)
      TempFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype)
    end

    def create_carried_function(name, ctype, argtype, call_type = nil, n = 0)
      CarriedFunction.new(CFunc.new(0, ctype, name, call_type || :cdecl), argtype, n)
    end
  end
end


Nessa grande código há 10 scripts diferentes, o thread.rb foi criado por Yukihiro Matsumoto (criador do Ruby e é licenciado pela Ruby License (Compatível com GPL))
Os outros não possuem header com os autores, apenas tem algumas RCS IDs com nomes que prefiro não citar aqui, mas de qualquer mode estão sob a Ruby License do mesmo modo.


E por fim, as funções de socket:
Código:

#--------------------
#require "dl"
#require "dl/import"
#require "dl/struct"
#--------------------
# Created by Cidiomar
#--------------------
module DL::Importer
  #----------
  def typedef(string)
    args = string.split(' ')
    alias_type = args.pop
    typealias(alias_type, args.join(' '))
  end
  #-----
  module_function :typedef
  #----------
end
#---------------
module CIDI_DK
  #---------------
  Timeval = DL::Importer.struct [
    "long tv_sec",
    "long tv_usec",
  ]
  #---------------
  module Winsock2
    #----------
    extend DL::Importer
    #----------
    dlload 'ws2_32.dll'
    #----------
    SOCK_STREAM  = 1
    AF_INET      = 2
    IPPROTO_TCP  = 6
    INADDR_NONE     = 0xffffffff
    #----------
    typedef 'unsigned char   u_char'
    typedef 'unsigned short   u_short'
    typedef 'unsigned int     u_int'
    typedef 'unsigned long   u_long'
    #-----
    typedef 'u_int           SOCKET'
    #----------
    Fd_set = struct [
      'u_int  fd_count',
      'SOCKET  fd_array[2]'
    ]
    #----------
    Fd_set1 = struct [
      'u_int  fd_count',
      'SOCKET  fd_array'
    ]
    #----------
    Sockaddr = struct [
      'u_short sa_family',
      'char     sa_data[14]'
    ]
    #----------
    Sockaddr2 = struct [
      'u_short sa_family',
      'u_short s_port',
      'u_long  s_host',
      'char     sa_data[8]'
    ]
    #----------
    Hostent = struct [
      'char     *  h_name',
      'char     **  h_aliases',
      'short       h_addrtype',
      'short      h_length',
      'char     **  h_addr_list',
    ]
    #----------
    extern 'int closesocket(SOCKET)'
    extern 'int connect(SOCKET,const struct sockaddr*,int)'
    extern 'hostent *  gethostbyname(const char*)'
    extern 'int recv(SOCKET,char*,int,int)'
    extern 'int send(SOCKET,const char*,int,int)'
    extern 'SOCKET socket(int,int,int)'
    extern 'int select(int,fd_set*,fd_set*,fd_set*,const struct timeval*)'
    extern 'int WSAGetLastError()'
    #----------
  end
  #---------------
  class TCPSocket
    #----------
    attr_reader :host, :port
    #----------
    def initialize(host, port)
      @host, @port      = host, port
      @recv_back_buffer = ""
      connect
    end
    #----------
    def connect
      #-----
      @sock_io_id = Winsock2.socket(Winsock2::AF_INET, Winsock2::SOCK_STREAM, Winsock2::IPPROTO_TCP)
      #-----
      unless (_host = Winsock2.gethostbyname(@host)).null?
        hostent    = Winsock2::Hostent.new(Winsock2.gethostbyname(@host))
      else
        SocketError.raise_no_assoc_host
      end
      #-----
      zeros = i = 0
      ip_addr = []
      loop do
        now = hostent.h_addr_list[i]
        if zeros == 5
          now += 256 if now < 0
          ip_addr << now
          break if ip_addr.size == 4
        elsif now == 0
          zeros += 1
        else
          zeros = 0
        end
        i += 1
      end
      #-----
      sock_addr          = Winsock2::Sockaddr2.malloc
      sock_addr.sa_family = Winsock2::AF_INET
      sock_addr.s_port    = [@port].pack("n").unpack("S")[0]
      sock_addr.s_host    = ip_addr.pack("C4").unpack("L")[0]
      #-----
      if Winsock2.connect(@sock_io_id, sock_addr, Winsock2::Sockaddr2.size) == -1 or sock_addr.s_host == 0
        SocketError.raise
      end
      #-----
      nil
    end
    #----------
    def close
      SocketError.raise if Winsock2.closesocket(@sock_io_id) == -1
      nil
    end
    #----------
    def recv(len)
      if @recv_back_buffer.size != 0
        if @recv_back_buffer.size > len
          buffer = @recv_back_buffer[0 ... len]
          @recv_back_buffer[0 ... len] = ''
        elsif @recv_back_buffer.size == len
          buffer = @recv_back_buffer
          @recv_back_buffer = ""
        else
          len -= @recv_back_buffer.size
          buffer    = "\0" * len
          SocketError.raise if (recv_size = Winsock2.recv(@sock_io_id, buffer, len, 0)) == -1
          buffer = @recv_back_buffer + buffer[0 ... recv_size]
          @recv_back_buffer = ""
        end
      else
        buffer    = "\0" * len
        SocketError.raise if (recv_size = Winsock2.recv(@sock_io_id, buffer, len, 0)) == -1
        buffer = buffer[0 ... recv_size]
      end
      return buffer
    end
    #----------
    def gets(end_sequence = "\n")
      end_sequence_size = end_sequence.size
      return nil if end_sequence_size == 0
      ret_buffer = ""
      buffer    = "\0"
      result    = -1
      #-----
      while not ret_buffer[ret_buffer.size - end_sequence_size ... ret_buffer.size] == end_sequence
        if @recv_back_buffer.size != 0
          buffer = @recv_back_buffer[0]
          @recv_back_buffer[0] = ''
        else
          SocketError.raise if (result = Winsock2.recv(@sock_io_id, buffer, 1, 0)) == -1
        end
        ret_buffer << buffer unless result == 0
      end
      #-----
      return ret_buffer
    end
    #----------
    def send(*args)
      string = args.join
      SocketError.raise if Winsock2.send(@sock_io_id, string, string.size, 0) == -1
      string
    end
    #----------
    def eof?
      #-----
      timeval = Timeval.malloc
      timeval.tv_sec  = 0
      timeval.tv_usec = 0
      #-----
      readfds          = Winsock2::Fd_set1.malloc
      readfds.fd_count  = 1
      readfds.fd_array  = @sock_io_id
      #-----
      result = Winsock2.select(2, readfds, 0, 0, timeval)
      #-----
      if result == 1
        buffer = "\0"
        if Winsock2.recv(@sock_io_id, buffer, 1, 0) == 0
          result = 0
        else
          @recv_back_buffer << buffer
        end
      end
      #-----
      SocketError.raise if result == -1
      return !(result > 0)
    end
    #----------
    protected :connect
    #----------
  end
  #---------------
  class SocketError < StandardError
    #----------
    ENOASSOCHOST = 'getaddrinfo: no address associated with hostname.'
    #----------
    def self.raise(errno = Winsock2.WSAGetLastError)
      _caller = caller()
      _caller.pop
      Kernel.raise Errno.const_get(Errno.constants.detect { |c| Errno.const_get(c).new.errno == errno }), '', _caller
    end
    #----------
    def self.raise_no_assoc_host
      _caller = caller()
      _caller.pop
      Kernel.raise 'getaddrinfo: no address associated with hostname.', '', _caller
    end
    #----------
  end
end
#--------------------
TCPSocket = CIDI_DK::TCPSocket






Pergunta: Por que não usar Win32API ao invés de dl?o código ficaria 36.5KB mais leve!
Resposta: Prefiro usar dl, Win32API não deve mais ser usada, esta em ativa apenas por compatibilidade, será removida do Ruby em breve.

Cidiomar
Semi-Experiente
Semi-Experiente

Mensagens : 115
Créditos : 51

Ir para o topo Ir para baixo

Workarround pra classe TCPSocket Empty Re: Workarround pra classe TCPSocket

Mensagem por Komuro Takashi Sex Fev 15, 2013 10:57 pm

Sei que tópico é antigo mais não poderia deixar de agradecer...eu estava desesperado por isso e estava aqui á mais de 1 ano e eu não havia visto....já consegui conectar com os server de NP existentes, o seu em Ruby o em Java o do Master para RMXP e RMVX o script é totalmente funcional, só que peguei ele de outro site e lá vc falou que era nescessário inportar as funcões em .rb e foi o que fiz direcionei para minha lib dl e deu certo.....Obrigado novamente.

Atenciosamente : KOmuro Takashi

_________________
Workarround pra classe TCPSocket Takashi_komuro_by_minato8-d51g9o4

Paga um café? Patreon
Komuro Takashi
Komuro Takashi
Colaborador
Colaborador

Mensagens : 1047
Créditos : 130

Ir para o topo Ir para baixo

Ir para o topo

- Tópicos semelhantes

 
Permissões neste sub-fórum
Não podes responder a tópicos