Last active
April 3, 2017 03:09
-
-
Save film42/ed9844b39df6f8a59a95dcf6791cb6bb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "socket" | |
class Client | |
def initialize(addr, port, user, db) | |
@user = user | |
@db = db | |
@socket = TCPSocket.new(addr, port) | |
end | |
def login_packet | |
null = "\x0" | |
packet = [ | |
[0].pack("N"), [0x30000].pack("N"), | |
"user", null, | |
@user, null, | |
"database", null, | |
@database, null, | |
null | |
] | |
# Set the packet size at pos 0. The null was a placeholder. | |
packet_size = packet.join.size | |
packet[0] = [packet_size].pack("N") | |
packet.join | |
end | |
def parse_uint32(buffer) | |
num = buffer[0..3].unpack("N").first | |
buffer = buffer[4..-1] | |
[num, buffer] | |
end | |
def parse_string(buffer) | |
null = "\x0" | |
pos = buffer.index(null) | |
fail "no valid string to parse" if pos.nil? | |
str = buffer[0...pos] | |
buffer = buffer[(pos+1)..-1] | |
[str, buffer] | |
end | |
def parse_message(buffer) | |
type = buffer[0] | |
size = buffer[1..4].unpack("N").first - 4 | |
message = buffer[5...(5+size)] | |
buffer = buffer[(5 + size)..-1] | |
[type, message, buffer] | |
end | |
def connect | |
@socket.write(login_packet) | |
buffer = @socket.recv(1024) | |
loop do | |
type, message, buffer = parse_message(buffer) | |
case type | |
when "Z" then return :ok | |
when "R" then auth(message) | |
when "S" then params(message) | |
when "K" then backend_key_data(message) | |
else fail "Idk what this message is: #{type}" | |
end | |
end | |
ensure | |
@socket.close rescue nil | |
end | |
def backend_key_data(message) | |
process_id, message = parse_uint32(message) | |
puts "process_id: #{process_id}" | |
secret_key, message = parse_uint32(message) | |
puts "secret_key: #{secret_key}" | |
end | |
def params(message) | |
key, message = parse_string(message) | |
value, message = parse_string(message) | |
puts "param: #{key}" | |
puts "value: #{value}" | |
end | |
def auth(message) | |
code, _ = parse_uint32(message) | |
case code | |
when 0 | |
puts "auth: ok" | |
else | |
fail "New auth code #{code}" | |
end | |
nil | |
end | |
end | |
host = "localhost" | |
port = 5432 | |
user = "postgres" | |
database = "some_db" | |
client = Client.new(host, port, user, database) | |
puts client.connect | |
# $ ruby pg.rb | |
# auth: ok | |
# param: application_name | |
# value: | |
# param: client_encoding | |
# value: UTF8 | |
# param: DateStyle | |
# value: ISO, MDY | |
# param: integer_datetimes | |
# value: on | |
# param: IntervalStyle | |
# value: postgres | |
# param: is_superuser | |
# value: on | |
# param: server_encoding | |
# value: UTF8 | |
# param: server_version | |
# value: 9.6.1 | |
# param: session_authorization | |
# value: postgres | |
# param: standard_conforming_strings | |
# value: on | |
# param: TimeZone | |
# value: US/Eastern | |
# process_id: 26819 | |
# secret_key: 1782894957 | |
# ok |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment