Hello,
I have been attempting to recreate the basic TCP/IP host functions that ruby has for rmxp (Just the very basic functions)
I am using the win 32 module
The winsock module
The Socket class
The TCP sub class for the Socket class
I created a class of my own called host and created the following method and attempted to create a socket that can be used for the host functions
The sockets family is PF_INET, Type is SOCK_STREAM and Protocol is IPPROTO_TCP
Then I attempted to create a sockaddr_in with the port 80 (Just to test) and the domain of AF_INET
Then I bind the socket to the sockaddr_in
However when I attempt to call this method the game crashes immediately and without any kind of error message.
Does any one have any experience with these scripts that could help me or tell me what I have done wrong?, I plan to continue working on the script after I have passed this bump in the road. If anyone would like to help me with the continued work or with this current problem please let me know, or if there is already a script out there that does what I am trying to do. Please don't post here saying things like "Why would you want your game to be able to host" because that is not what I am here for, I am here for help in writing a script. Also if this script is impossible to make and someone wants to post that kind of information that is fine .
Thank you to anyone who took the time to read this post, below is my attempt at creating the socket I need to begin the rest of the script.
P.S feel free to PM me
I have been attempting to recreate the basic TCP/IP host functions that ruby has for rmxp (Just the very basic functions)
I am using the win 32 module
Code:
#===============================================================================
# ** Module Win32 - Handles numerical based data.
#-------------------------------------------------------------------------------
# Author Ruby
# Version 1.8.1
#===============================================================================
module Win32
#--------------------------------------------------------------------------
# ● Retrieves data from a pointer.
#--------------------------------------------------------------------------
def copymem(len)
buf = "\0" * len
Win32API.new("kernel32", "RtlMoveMemory", "ppl", "").call(buf, self, len)
buf
end
end
# Extends the numeric class.
class Numeric
include Win32
end
# Extends the string class.
class String
include Win32
end
The winsock module
Code:
#===============================================================================
# ** Module Winsock - Maps out the functions held in the Winsock DLL.
#-------------------------------------------------------------------------------
# Author Ruby
# Version 1.8.1
#===============================================================================
module Winsock
DLL = "ws2_32"
#--------------------------------------------------------------------------
# * Accept Connection
#--------------------------------------------------------------------------
def self.accept(*args)
Win32API.new(DLL, "accept", "ppl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Bind
#--------------------------------------------------------------------------
def self.bind(*args)
Win32API.new(DLL, "bind", "ppl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Close Socket
#--------------------------------------------------------------------------
def self.closesocket(*args)
Win32API.new(DLL, "closesocket", "p", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Connect
#--------------------------------------------------------------------------
def self.connect(*args)
Win32API.new(DLL, "connect", "ppl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Get host (Using Adress)
#--------------------------------------------------------------------------
def self.gethostbyaddr(*args)
Win32API.new(DLL, "gethostbyaddr", "pll", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Get host (Using Name)
#--------------------------------------------------------------------------
def self.gethostbyname(*args)
Win32API.new(DLL, "gethostbyname", "p", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Get host's Name
#--------------------------------------------------------------------------
def self.gethostname(*args)
Win32API.new(DLL, "gethostname", "pl", "").call(*args)
end
#--------------------------------------------------------------------------
# * Get Server (Using Name)
#--------------------------------------------------------------------------
def self.getservbyname(*args)
Win32API.new(DLL, "getservbyname", "pp", "p").call(*args)
end
#--------------------------------------------------------------------------
# * HT OnL
#--------------------------------------------------------------------------
def self.htonl(*args)
Win32API.new(DLL, "htonl", "l", "l").call(*args)
end
#--------------------------------------------------------------------------
# * HT OnS
#--------------------------------------------------------------------------
def self.htons(*args)
Win32API.new(DLL, "htons", "l", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Inet Adress
#--------------------------------------------------------------------------
def self.inet_addr(*args)
Win32API.new(DLL, "inet_addr", "p", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Inet NtOA
#--------------------------------------------------------------------------
def self.inet_ntoa(*args)
Win32API.new(DLL, "inet_ntoa", "l", "p").call(*args)
end
#--------------------------------------------------------------------------
# * Listen
#--------------------------------------------------------------------------
def self.listen(*args)
Win32API.new(DLL, "listen", "pl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Recieve
#--------------------------------------------------------------------------
def self.recv(*args)
Win32API.new(DLL, "recv", "ppll", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Select
#--------------------------------------------------------------------------
def self.select(*args)
Win32API.new(DLL, "select", "lpppp", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Send
#--------------------------------------------------------------------------
def self.send(*args)
Win32API.new(DLL, "send", "ppll", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Set Socket Options
#--------------------------------------------------------------------------
def self.setsockopt(*args)
Win32API.new(DLL, "setsockopt", "pllpl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Shutdown
#--------------------------------------------------------------------------
def self.shutdown(*args)
Win32API.new(DLL, "shutdown", "pl", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Socket
#--------------------------------------------------------------------------
def self.socket(*args)
Win32API.new(DLL, "socket", "lll", "l").call(*args)
end
#--------------------------------------------------------------------------
# * Get Last Error
#--------------------------------------------------------------------------
def self.WSAGetLastError(*args)
Win32API.new(DLL, "WSAGetLastError", "", "l").call(*args)
end
end
The Socket class
Code:
#===============================================================================
# ** Socket - Creates and manages sockets.
#-------------------------------------------------------------------------------
# Author Ruby
# Version 1.8.1
#===============================================================================
class Socket
#--------------------------------------------------------------------------
# ● Constants
#--------------------------------------------------------------------------
AF_UNSPEC = 0
AF_UNIX = 1
AF_INET = 2
AF_IPX = 6
AF_APPLETALK = 16
PF_UNSPEC = 0
PF_UNIX = 1
PF_INET = 2
PF_IPX = 6
PF_APPLETALK = 16
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
SOCK_RDM = 4
SOCK_SEQPACKET = 5
IPPROTO_IP = 0
IPPROTO_ICMP = 1
IPPROTO_IGMP = 2
IPPROTO_GGP = 3
IPPROTO_TCP = 6
IPPROTO_PUP = 12
IPPROTO_UDP = 17
IPPROTO_IDP = 22
IPPROTO_ND = 77
IPPROTO_RAW = 255
IPPROTO_MAX = 256
SOL_SOCKET = 65535
SO_DEBUG = 1
SO_REUSEADDR = 4
SO_KEEPALIVE = 8
SO_DONTROUTE = 16
SO_BROADCAST = 32
SO_LINGER = 128
SO_OOBINLINE = 256
SO_RCVLOWAT = 4100
SO_SNDTIMEO = 4101
SO_RCVTIMEO = 4102
SO_ERROR = 4103
SO_TYPE = 4104
SO_SNDBUF = 4097
SO_RCVBUF = 4098
SO_SNDLOWAT = 4099
TCP_NODELAY = 1
MSG_OOB = 1
MSG_PEEK = 2
MSG_DONTROUTE = 4
IP_OPTIONS = 1
IP_DEFAULT_MULTICAST_LOOP = 1
IP_DEFAULT_MULTICAST_TTL = 1
IP_MULTICAST_IF = 2
IP_MULTICAST_TTL = 3
IP_MULTICAST_LOOP = 4
IP_ADD_MEMBERSHIP = 5
IP_DROP_MEMBERSHIP = 6
IP_TTL = 7
IP_TOS = 8
IP_MAX_MEMBERSHIPS = 20
EAI_ADDRFAMILY = 1
EAI_AGAIN = 2
EAI_BADFLAGS = 3
EAI_FAIL = 4
EAI_FAMILY = 5
EAI_MEMORY = 6
EAI_NODATA = 7
EAI_NONAME = 8
EAI_SERVICE = 9
EAI_SOCKTYPE = 10
EAI_SYSTEM = 11
EAI_BADHINTS = 12
EAI_PROTOCOL = 13
EAI_MAX = 14
AI_PASSIVE = 1
AI_CANONNAME = 2
AI_NUMERICHOST = 4
AI_MASK = 7
AI_ALL = 256
AI_V4MAPPED_CFG = 512
AI_ADDRCONFIG = 1024
AI_DEFAULT = 1536
AI_V4MAPPED = 2048
#--------------------------------------------------------------------------
# ● Returns the associated IP address for the given hostname.
#--------------------------------------------------------------------------
def self.getaddress(host)
gethostbyname(host)[3].unpack("C4").join(".")
end
#--------------------------------------------------------------------------
# ● Returns the associated IP address for the given hostname.
#--------------------------------------------------------------------------
def self.getservice(serv)
case serv
when Numeric
return serv
when String
return getservbyname(serv)
else
raise "Please us an interger or string for services."
end
end
#--------------------------------------------------------------------------
# ● Returns information about the given hostname.
#--------------------------------------------------------------------------
def self.gethostbyname(name)
raise SocketError::ENOASSOCHOST if (ptr = Winsock.gethostbyname(name)) == 0
host = ptr.copymem(16).unpack("iissi")
[host[0].copymem(64).split("\0")[0], [], host[2], host[4].copymem(4).unpack("l")[0].copymem(4)]
end
#--------------------------------------------------------------------------
# ● Returns the user's hostname.
#--------------------------------------------------------------------------
def self.gethostname
buf = "\0" * 256
Winsock.gethostname(buf, 256)
buf.strip
end
#--------------------------------------------------------------------------
# ● Returns information about the given service.
#--------------------------------------------------------------------------
def self.getservbyname(name)
case name
when /echo/i
return 7
when /daytime/i
return 13
when /ftp/i
return 21
when /telnet/i
return 23
when /smtp/i
return 25
when /time/i
return 37
when /http/i
return 80
when /pop/i
return 110
else
raise "Service not recognized."
end
end
#--------------------------------------------------------------------------
# ● Creates an INET-sockaddr struct.
#--------------------------------------------------------------------------
def self.sockaddr_in(port, host)
begin
[AF_INET, getservice(port)].pack("sn") + gethostbyname(host)[3] + [].pack("x8")
rescue
nil
end
end
#--------------------------------------------------------------------------
# ● Creates a new socket and connects it to the given host and port.
#--------------------------------------------------------------------------
def self.open(*args)
socket = new(*args)
if block_given?
begin
yield socket
ensure
socket.close
end
end
nil
end
#--------------------------------------------------------------------------
# ● Creates a new socket.
#--------------------------------------------------------------------------
def self.initialize(domain, type, protocol)
SocketError.check if (@fd = Winsock.socket(domain, type, protocol)) == -1
@fd
end
#--------------------------------------------------------------------------
# ● Accepts incoming connections.
#--------------------------------------------------------------------------
def accept(flags = 0)
buf = "\0" * 16
SocketError.check if Winsock.accept(@fd, buf, flags) == -1
buf
end
#--------------------------------------------------------------------------
# ● Binds a socket to the given sockaddr.
#--------------------------------------------------------------------------
def self.bind(sockaddr)
SocketError.check if (ret = Winsock.bind(@fd, sockaddr, sockaddr.size)) == -1
ret
end
#--------------------------------------------------------------------------
# ● Closes a socket.
#--------------------------------------------------------------------------
def close
SocketError.check if (ret = Winsock.closesocket(@fd)) == -1
ret
end
#--------------------------------------------------------------------------
# ● Connects a socket to the given sockaddr.
#--------------------------------------------------------------------------
def connect(sockaddr)
ret = Winsock.connect(@fd, sockaddr, sockaddr.size)
SocketError.check if ret == -1
ret
end
#--------------------------------------------------------------------------
# ● Listens for incoming connections.
#--------------------------------------------------------------------------
def listen(backlog)
SocketError.check if (ret = Winsock.listen(@fd, backlog)) == -1
ret
end
#--------------------------------------------------------------------------
# ● Checks waiting data's status.
#--------------------------------------------------------------------------
def select(timeout)
SocketError.check if (ret = Winsock.select(1, [1, @fd].pack("ll"), 0, 0, [timeout, timeout * 1000000].pack("ll"))) == -1
ret
end
#--------------------------------------------------------------------------
# ● Checks if data is waiting.
#--------------------------------------------------------------------------
def ready?
not select(0) == 0
end
#--------------------------------------------------------------------------
# ● Reads data from socket.
#--------------------------------------------------------------------------
def read(len)
buf = "\0" * len
Win32API.new("msvcrt", "_read", "lpl", "l").call(@fd, buf, len)
buf
end
#--------------------------------------------------------------------------
# ● Returns recieved data.
#--------------------------------------------------------------------------
def recv(len, flags = 0)
buf = "\0" * len
SocketError.check if Winsock.recv(@fd, buf, buf.size, flags) == -1
buf
end
#--------------------------------------------------------------------------
# ● Sends data to a host.
#--------------------------------------------------------------------------
def send(data, flags = 0)
SocketError.check if (ret = Winsock.send(@fd, data, data.size, flags)) == -1
ret
end
#--------------------------------------------------------------------------
# * Gets
#--------------------------------------------------------------------------
def gets
# Create buffer
buffer = ""
# Loop Until "end of line"
while (char = recv(1)) != "\n"
buffer += char
end
# Return recieved data
return buffer
end
#--------------------------------------------------------------------------
# ● Writes data to socket.
#--------------------------------------------------------------------------
def write(data)
Win32API.new("msvcrt", "_write", "lpl", "l").call(@fd, data, 1)
end
end
The TCP sub class for the Socket class
Code:
#===============================================================================
# ** TCPSocket - Creates and manages TCP sockets.
#-------------------------------------------------------------------------------
# Author Ruby
# Version 1.8.1
#===============================================================================
class TCPSocket < Socket
#--------------------------------------------------------------------------
# ● Creates a new socket and connects it to the given host and port.
#--------------------------------------------------------------------------
def self.open(*args)
socket = new(*args)
if block_given?
begin
yield socket
ensure
socket.close
end
end
nil
end
#--------------------------------------------------------------------------
# ● Creates a new socket and connects it to the given host and port.
#--------------------------------------------------------------------------
def initialize(host, port)
super(AF_INET, SOCK_STREAM, IPPROTO_TCP)
connect([AF_INET, Socket.getservice(port), Socket.getaddress(host).split(".").collect { |b| b.to_i }].flatten.pack("snC4x8"))
end
end
#==============================================================================
# ■ SocketError
#------------------------------------------------------------------------------
# Default exception class for sockets.
#==============================================================================
class SocketError < StandardError
ENOASSOCHOST = "getaddrinfo: no address associated with hostname."
def self.check
errno = Winsock.WSAGetLastError
errno = Errno.constants.detect { |c| Errno.const_get(c).new.errno == errno }
if errno != nil
raise Errno.const_get(errno)
end
end
end
I created a class of my own called host and created the following method and attempted to create a socket that can be used for the host functions
The sockets family is PF_INET, Type is SOCK_STREAM and Protocol is IPPROTO_TCP
Then I attempted to create a sockaddr_in with the port 80 (Just to test) and the domain of AF_INET
Then I bind the socket to the sockaddr_in
However when I attempt to call this method the game crashes immediately and without any kind of error message.
Does any one have any experience with these scripts that could help me or tell me what I have done wrong?, I plan to continue working on the script after I have passed this bump in the road. If anyone would like to help me with the continued work or with this current problem please let me know, or if there is already a script out there that does what I am trying to do. Please don't post here saying things like "Why would you want your game to be able to host" because that is not what I am here for, I am here for help in writing a script. Also if this script is impossible to make and someone wants to post that kind of information that is fine .
Thank you to anyone who took the time to read this post, below is my attempt at creating the socket I need to begin the rest of the script.
Code:
class Host
def self.create
#creates a socket with the following family of PF_INET, Type of SOCK_STREAM and Protocol of IPPROTO_TCP
Socket.initialize(2, 1, 6)
# creates a sockaddr_in with the port 80 and the domain of AF_INET
sockaddr_in = Socket.sockaddr_in(80, 2)
# Binds to socket to the above sockaddr_in
Socket.bind()#sockaddr_in)
end
end
P.S feel free to PM me