First steps to crude AMQP listener
This commit is contained in:
parent
4c36800ab3
commit
c5a665adb2
214
amqp_codegen.py
214
amqp_codegen.py
|
@ -15,9 +15,12 @@ def kids(e,t): return [k for k in e.getElementsByTagName(t) if k.parentNode is e
|
|||
##########################################################################
|
||||
# Identifier utils
|
||||
|
||||
keywords = set('type'.split())
|
||||
|
||||
def mlify(s):
|
||||
s = s.replace('-', '_')
|
||||
s = s.replace(' ', '_')
|
||||
if s in keywords: s = s + '_'
|
||||
return s
|
||||
|
||||
def ctor(s):
|
||||
|
@ -56,16 +59,36 @@ def resolve(typename):
|
|||
if typename in domains:
|
||||
typename = domains[typename]
|
||||
|
||||
class AccessibleFieldsMixin:
|
||||
class DatalikeMixin:
|
||||
@property
|
||||
def accessible_fields(self):
|
||||
return [f for f in self.fields if not f.reserved]
|
||||
|
||||
class Class(AccessibleFieldsMixin,
|
||||
namedtuple('Class', 'index name fields methods'.split())):
|
||||
pass
|
||||
def pattern(self, is_type = False, need_some = False):
|
||||
if not self.accessible_fields:
|
||||
return ctor(self.full_name)
|
||||
elif is_type:
|
||||
if need_some:
|
||||
types = [(tname(f.type)+' option' if f.type != 'bit' else 'bit_t')
|
||||
for f in self.accessible_fields]
|
||||
else:
|
||||
types = [tname(f.type) for f in self.accessible_fields]
|
||||
return '%s of (%s)' % (ctor(self.full_name), ' * '.join(types))
|
||||
else:
|
||||
return '%s (%s)' % (ctor(self.full_name),
|
||||
', '.join((mlify(f.name) for f in self.accessible_fields)))
|
||||
|
||||
class Method(AccessibleFieldsMixin,
|
||||
@property
|
||||
def match_clause(self):
|
||||
return ' | ' + self.pattern() + ' ->'
|
||||
|
||||
class Class(DatalikeMixin,
|
||||
namedtuple('Class', 'index name fields methods'.split())):
|
||||
@property
|
||||
def full_name(self):
|
||||
return self.name + '-properties'
|
||||
|
||||
class Method(DatalikeMixin,
|
||||
namedtuple('Method', ['class_name',
|
||||
'class_index',
|
||||
'has_content',
|
||||
|
@ -109,6 +132,30 @@ for c in classes:
|
|||
methods.append(m)
|
||||
|
||||
###########################################################################
|
||||
# Implementation restrictions
|
||||
|
||||
for c in classes:
|
||||
if len(c.fields) > 15:
|
||||
# We'd need to deal with more than one flags word
|
||||
raise Exception("Having more than 15 fields in a class is not supported")
|
||||
|
||||
###########################################################################
|
||||
|
||||
class BitAccumulator:
|
||||
def __init__(self):
|
||||
self.acc = []
|
||||
|
||||
@property
|
||||
def count(self):
|
||||
return len(self.acc)
|
||||
|
||||
def add(self, x):
|
||||
self.acc.append(x)
|
||||
|
||||
def flush(self):
|
||||
if self.acc:
|
||||
print ' write_octet output_buf (%s);' % (' lor '.join(self.acc),)
|
||||
self.acc = []
|
||||
|
||||
def print_codec():
|
||||
print copyright_stmt
|
||||
|
@ -118,93 +165,138 @@ def print_codec():
|
|||
print 'open Sexp'
|
||||
print
|
||||
print 'let version = (%d, %d, %d)' % (major, minor, revision)
|
||||
print 'let port = %d' % (port,)
|
||||
print
|
||||
for (n, v) in constants():
|
||||
print 'let %s = %s' % (mlify(n), v)
|
||||
print
|
||||
print 'type method_t ='
|
||||
for m in methods:
|
||||
print ' | %s' % (ctor(m.full_name),),
|
||||
if m.accessible_fields:
|
||||
print 'of (' + ', '.join((tname(f.type) for f in m.accessible_fields)) + ')'
|
||||
else:
|
||||
print
|
||||
print ' | ' + m.pattern(True)
|
||||
print
|
||||
print 'let has_content m = match m with '
|
||||
for m in methods:
|
||||
if m.has_content:
|
||||
if m.accessible_fields:
|
||||
print (' | %s (' + ', '.join(('_' for f in m.accessible_fields)) + ') = true') % \
|
||||
(ctor(m.full_name),)
|
||||
else:
|
||||
print ' | %s = true' % (ctor(m.full_name),)
|
||||
print ' | _ = false'
|
||||
print m.match_clause + ' true'
|
||||
print ' | _ -> false'
|
||||
print
|
||||
print 'type properties_t ='
|
||||
for c in classes:
|
||||
if c.fields:
|
||||
if c.accessible_fields:
|
||||
print (' | %s_properties of (' + ', '.join((tname(f.type) for f in c.accessible_fields)) + ')') % (ctor(c.name),)
|
||||
else:
|
||||
print ' | %s_properties' % (ctor(c.name),)
|
||||
print ' | ' + c.pattern(True, True)
|
||||
print
|
||||
print 'let is_synchronous m = match m with '
|
||||
for m in methods:
|
||||
if not m.synchronous:
|
||||
if m.accessible_fields:
|
||||
print (' | %s (' + ', '.join(('_' for f in m.accessible_fields)) + ') = false') % \
|
||||
(ctor(m.full_name),)
|
||||
else:
|
||||
print ' | %s = false' % (ctor(m.full_name),)
|
||||
print ' | _ = true'
|
||||
print m.match_clause + ' false'
|
||||
print ' | _ -> true'
|
||||
print
|
||||
print 'let sexp_of_method m = match m with '
|
||||
for m in methods:
|
||||
print ' | %s' % (ctor(m.full_name),),
|
||||
print m.match_clause
|
||||
if m.accessible_fields:
|
||||
print 'of (' + ', '.join((mlify(f.name) for f in m.accessible_fields)) + ') ->'
|
||||
print ' Arr ["%s"; "%s"; %s]' % (
|
||||
m.class_name,
|
||||
m.name,
|
||||
'; '.join(('Arr [Str "%s"; sexp_of_%s(%s)]' % \
|
||||
(f.name, mlify(f.type), mlify(f.name)) for f in m.accessible_fields))
|
||||
)
|
||||
print ' Arr [Str "%s"; Str "%s"' % (m.class_name, m.name)
|
||||
for f in m.accessible_fields:
|
||||
print ' ; Arr [Str "%s"; sexp_of_%s(%s)]' % \
|
||||
(f.name, mlify(f.type), mlify(f.name))
|
||||
print ' ]'
|
||||
else:
|
||||
print '->'
|
||||
print ' Arr ["%s"; "%s"]' % (m.class_name, m.name)
|
||||
print ' Arr [Str "%s"; Str "%s"]' % (m.class_name, m.name)
|
||||
print
|
||||
print 'let read_method class_index method_index ch = match (class_index, method_index) with'
|
||||
print 'let method_name class_index method_index = match (class_index, method_index) with'
|
||||
for m in methods:
|
||||
print ' | (%d, %d) -> "%s"' % (m.class_index, m.index, ctor(m.full_name))
|
||||
print ' | _ -> "??unknownmethod??"'
|
||||
print
|
||||
print 'let read_method class_index method_index input_buf = match (class_index, method_index) with'
|
||||
for m in methods:
|
||||
print ' | (%d, %d) ->' % (m.class_index, m.index)
|
||||
bits_remaining = 0
|
||||
for f in m.fields:
|
||||
if f.reserved:
|
||||
print ' let _ = read_%s ch in' % (mlify(f.type))
|
||||
target = '_' if f.reserved else mlify(f.name)
|
||||
if f.type == 'bit':
|
||||
if bits_remaining < 1:
|
||||
print ' let bit_buffer = read_octet input_buf in'
|
||||
bits_remaining = 8
|
||||
print ' let %s = (bit_buffer land %d) <> 0 in' % \
|
||||
(target, 1 << (8 - bits_remaining))
|
||||
bits_remaining = bits_remaining - 1
|
||||
else:
|
||||
print ' let %s = read_%s ch in' % (mlify(f.name), mlify(f.type))
|
||||
if m.accessible_fields:
|
||||
print ' %s (%s)' % (ctor(m.full_name),
|
||||
', '.join((mlify(f.name) for f in m.accessible_fields)))
|
||||
else:
|
||||
print ' %s' % (ctor(m.full_name),)
|
||||
print ' let %s = read_%s input_buf in' % (target, mlify(f.type))
|
||||
print ' ' + m.pattern()
|
||||
print ' | _ -> raise (Amqp_exception (frame_error,'
|
||||
print ' Printf.sprintf "Unknown method number %d/%d"'
|
||||
print ' class_index method_index))'
|
||||
print
|
||||
print 'let method_index m = match m with'
|
||||
for m in methods:
|
||||
if m.accessible_fields:
|
||||
print (' | %s (' + ', '.join(('_' for f in m.accessible_fields)) + ') = (%d, %d)') % \
|
||||
(ctor(m.full_name), m.class_index, m.index)
|
||||
else:
|
||||
print ' | %s = (%d, %d)' % (ctor(m.full_name), m.class_index, m.index)
|
||||
print m.match_clause + ' (%d, %d)' % (m.class_index, m.index)
|
||||
print
|
||||
print 'let write_method m ch = match m with'
|
||||
print 'let write_method m output_buf = match m with'
|
||||
for m in methods:
|
||||
print ' | %s' % (ctor(m.full_name),),
|
||||
if m.accessible_fields:
|
||||
print 'of (' + ', '.join((mlify(f.name) for f in m.accessible_fields)) + ') ->'
|
||||
for f in m.fields:
|
||||
if f.reserved:
|
||||
print ' write_%s ch reserved_value_%s;' % (mlify(f.type), mlify(f.type))
|
||||
else:
|
||||
print ' write_%s ch %s;' % (mlify(f.type), mlify(f.name))
|
||||
else:
|
||||
print '->'
|
||||
print m.match_clause
|
||||
acc = BitAccumulator()
|
||||
for f in m.fields:
|
||||
source = 'reserved_value_'+mlify(f.type) if f.reserved else mlify(f.name)
|
||||
if f.type == 'bit':
|
||||
if acc.count >= 8:
|
||||
acc.flush()
|
||||
acc.add('(if %s then %d else 0)' % (source, 1 << acc.count))
|
||||
else:
|
||||
acc.flush()
|
||||
print ' write_%s output_buf %s;' % (mlify(f.type), source)
|
||||
print ' ()'
|
||||
print
|
||||
print 'let read_properties class_index input_buf = match class_index with'
|
||||
for c in classes:
|
||||
if c.fields:
|
||||
print ' | %d ->' % (c.index,)
|
||||
print ' let flags__ = read_short input_buf in'
|
||||
property_bit = 15
|
||||
for f in c.fields:
|
||||
target = '_' if f.reserved else mlify(f.name)
|
||||
if f.type == 'bit':
|
||||
print ' let %s = if (flags__ land %d) <> 0 in' % \
|
||||
(target, 1 << property_bit)
|
||||
else:
|
||||
print (' let %s = if (flags__ land %d) <> 0 then '+
|
||||
'Some (read_%s input_buf) else None in') % \
|
||||
(target, 1 << property_bit, mlify(f.type))
|
||||
property_bit = property_bit - 1
|
||||
print ' ' + c.pattern()
|
||||
print ' | _ -> raise (Amqp_exception (frame_error, Printf.sprintf "Unknown class number %d"'
|
||||
print ' class_index))'
|
||||
print
|
||||
print 'let class_index p = match p with'
|
||||
for c in classes:
|
||||
if c.fields:
|
||||
print c.match_clause + ' ' + str(c.index)
|
||||
print
|
||||
print 'let write_properties p output_buf = match p with'
|
||||
for c in classes:
|
||||
if c.fields:
|
||||
print c.match_clause
|
||||
print ' let flags__ = 0'
|
||||
property_bit = 15
|
||||
for f in c.fields:
|
||||
if not f.reserved:
|
||||
if f.type == 'bit':
|
||||
print ' lor (if %s then %d else 0)' % \
|
||||
(mlify(f.name), 1 << property_bit)
|
||||
else:
|
||||
print ' lor (match %s with Some _ -> %d | None -> 0)' % \
|
||||
(mlify(f.name), 1 << property_bit)
|
||||
property_bit = property_bit - 1
|
||||
print ' in'
|
||||
print ' write_short output_buf flags__;'
|
||||
for f in c.fields:
|
||||
source = 'reserved_value_%s' if f.reserved else mlify(f.name)
|
||||
if f.type != 'bit':
|
||||
print (' (match %s with Some v_ -> write_%s output_buf v_'+
|
||||
' | None -> ());') % \
|
||||
(source, mlify(f.type))
|
||||
print ' ()'
|
||||
print
|
||||
|
||||
if __name__ == '__main__':
|
||||
print_codec()
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
open Unix
|
||||
open Printf
|
||||
open Thread
|
||||
open Amqp_spec
|
||||
|
||||
type connection_t = {
|
||||
n: Node.t;
|
||||
mtx: Mutex.t;
|
||||
cin: in_channel;
|
||||
cout: out_channel;
|
||||
mutable input_buf: string;
|
||||
mutable output_buf: Buffer.t;
|
||||
mutable frame_max: int;
|
||||
mutable connection_closed: bool
|
||||
}
|
||||
|
||||
let read_frame conn =
|
||||
let frame_type = input_byte conn.cin in
|
||||
let channel_hi = input_byte conn.cin in
|
||||
let channel_lo = input_byte conn.cin in
|
||||
let channel = (channel_hi lsr 8) lor channel_lo in
|
||||
let length = input_binary_int conn.cin in
|
||||
printf "Length %d\n%!" length;
|
||||
if length > conn.frame_max
|
||||
then raise (Amqp_wireformat.Amqp_exception (frame_error, "Frame longer than current frame_max"))
|
||||
else
|
||||
(really_input conn.cin conn.input_buf 0 length;
|
||||
if input_byte conn.cin <> frame_end
|
||||
then raise (Amqp_wireformat.Amqp_exception (frame_error, "Missing frame_end octet"))
|
||||
else (frame_type, channel, length))
|
||||
|
||||
let write_frame conn frame_type channel =
|
||||
output_byte conn.cout frame_type;
|
||||
output_byte conn.cout ((channel lsr 8) land 255);
|
||||
output_byte conn.cout (channel land 255);
|
||||
output_binary_int conn.cout (Buffer.length conn.output_buf);
|
||||
Buffer.output_buffer conn.cout conn.output_buf;
|
||||
Buffer.reset conn.output_buf;
|
||||
output_byte conn.cout frame_end
|
||||
|
||||
let serialize_method buf m =
|
||||
let (class_id, method_id) = method_index m in
|
||||
Amqp_wireformat.write_short buf class_id;
|
||||
Amqp_wireformat.write_short buf method_id;
|
||||
write_method m buf
|
||||
|
||||
let deserialize_method buf =
|
||||
let class_id = Amqp_wireformat.read_short buf in
|
||||
let method_id = Amqp_wireformat.read_short buf in
|
||||
read_method class_id method_id buf
|
||||
|
||||
let serialize_header buf body_size p =
|
||||
let class_id = class_index p in
|
||||
Amqp_wireformat.write_short buf class_id;
|
||||
Amqp_wireformat.write_short buf 0;
|
||||
Amqp_wireformat.write_longlong buf (Int64.of_int body_size);
|
||||
write_properties p buf
|
||||
|
||||
let send_content_body conn channel body =
|
||||
let offset = ref 0 in
|
||||
let len = String.length body in
|
||||
while (!offset) < len do
|
||||
let snip_len = min conn.frame_max (len - !offset) in
|
||||
Buffer.add_substring conn.output_buf body (!offset) snip_len;
|
||||
write_frame conn frame_body channel;
|
||||
offset := !offset + snip_len
|
||||
done
|
||||
|
||||
let next_method conn =
|
||||
let (frame_type, channel, length) = read_frame conn in
|
||||
if frame_type <> frame_method
|
||||
then raise (Amqp_wireformat.Amqp_exception
|
||||
(command_invalid,
|
||||
(Printf.sprintf "Unexpected frame type %d" frame_type)))
|
||||
else
|
||||
let buf = Ibuffer.create conn.input_buf 0 length in
|
||||
(channel, deserialize_method buf)
|
||||
|
||||
let with_conn_mutex conn thunk = Util.with_mutex0 conn.mtx thunk
|
||||
|
||||
let send_method conn m =
|
||||
with_conn_mutex conn (fun () ->
|
||||
serialize_method conn.output_buf m;
|
||||
write_frame conn frame_method 0;
|
||||
flush conn.cout)
|
||||
|
||||
let send_error conn code message =
|
||||
if conn.connection_closed
|
||||
then
|
||||
()
|
||||
else
|
||||
let m = Connection_close (code, message, 0, 0) in
|
||||
Log.warn "Sending error" [sexp_of_method m];
|
||||
send_method conn m
|
||||
|
||||
let issue_banner cin cout =
|
||||
let handshake = String.create 8 in
|
||||
try
|
||||
really_input cin handshake 0 8;
|
||||
if String.sub handshake 0 4 <> "AMQP"
|
||||
then (output_string cout "AMQP\000\000\009\001"; false)
|
||||
else true
|
||||
with End_of_file -> false
|
||||
|
||||
let amqp_handler mtx cin cout n m =
|
||||
raise (Amqp_wireformat.Amqp_exception (not_implemented, "TODO"))
|
||||
|
||||
let handle_method conn m =
|
||||
match m with
|
||||
| _ ->
|
||||
let (cid, mid) = method_index m in
|
||||
raise (Amqp_wireformat.Amqp_exception (not_implemented,
|
||||
Printf.sprintf "Unsupported method %s (%d/%d)"
|
||||
(method_name cid mid) cid mid))
|
||||
|
||||
let initial_frame_size = frame_min_size
|
||||
|
||||
let amqp_mainloop peername mtx cin cout n =
|
||||
let conn = {
|
||||
n = n;
|
||||
mtx = mtx;
|
||||
cin = cin;
|
||||
cout = cout;
|
||||
input_buf = String.create initial_frame_size;
|
||||
output_buf = Buffer.create initial_frame_size;
|
||||
frame_max = initial_frame_size;
|
||||
connection_closed = false
|
||||
} in
|
||||
(try
|
||||
let (major_version, minor_version, revision) = version in
|
||||
send_method conn (Connection_start (major_version, minor_version,
|
||||
Amqp_wireformat.table_of_list [],
|
||||
"", ""));
|
||||
let (_, Connection_start_ok (client_properties, mechanism, response, locale))
|
||||
= next_method conn in
|
||||
while true do
|
||||
let (channel, m) = next_method conn in
|
||||
handle_method conn m
|
||||
done
|
||||
with
|
||||
| Amqp_wireformat.Amqp_exception (code, message) ->
|
||||
send_error conn code message
|
||||
)
|
||||
|
||||
let start (s, peername) =
|
||||
Connections.start_connection "amqp" issue_banner amqp_handler amqp_mainloop (s, peername)
|
|
@ -0,0 +1,254 @@
|
|||
open Sexp
|
||||
|
||||
exception Amqp_exception of (int * string)
|
||||
|
||||
type octet_t = int
|
||||
type short_t = int
|
||||
type long_t = int32
|
||||
type longlong_t = int64
|
||||
type shortstr_t = string
|
||||
type longstr_t = string
|
||||
type bit_t = bool
|
||||
type timestamp_t = int64
|
||||
|
||||
type table_t = { mutable table_body: table_body_t }
|
||||
and table_body_t =
|
||||
| Encoded_table of string
|
||||
| Decoded_table of (string * table_value_t) list
|
||||
| Both_table of (string * (string * table_value_t) list)
|
||||
and table_value_t =
|
||||
| Table_bool of bool (* t *)
|
||||
| Table_signed_byte of int (* b *)
|
||||
| Table_unsigned_byte of int (* B *)
|
||||
| Table_signed_short of int (* U *)
|
||||
| Table_unsigned_short of int (* u *)
|
||||
| Table_signed_long of int32 (* I *)
|
||||
| Table_unsigned_long of int32 (* i *)
|
||||
| Table_signed_longlong of int64 (* L *)
|
||||
| Table_unsigned_longlong of int64 (* l *)
|
||||
| Table_float of string (* f -- there seems to be no I/O for binary floats? *)
|
||||
| Table_double of string (* d -- there seems to be no I/O for binary floats? *)
|
||||
| Table_decimal of (int * int32) (* D *)
|
||||
| Table_short_string of string (* s *)
|
||||
| Table_string of string (* S *)
|
||||
| Table_array of table_value_t list (* A *)
|
||||
| Table_timestamp of int64 (* T *)
|
||||
| Table_table of table_t (* F *)
|
||||
| Table_void (* V *)
|
||||
|
||||
let read_octet input_buf = Ibuffer.next_byte input_buf
|
||||
let read_short input_buf =
|
||||
let hi = read_octet input_buf in
|
||||
let lo = read_octet input_buf in
|
||||
(hi lsl 8) lor lo
|
||||
let read_long input_buf =
|
||||
let hi = Int32.of_int (read_short input_buf) in
|
||||
let lo = Int32.of_int (read_short input_buf) in
|
||||
Int32.logor (Int32.shift_left hi 16) lo
|
||||
let read_longlong input_buf =
|
||||
let s0 = Int64.of_int (read_short input_buf) in
|
||||
let s1 = Int64.of_int (read_short input_buf) in
|
||||
let s2 = Int64.of_int (read_short input_buf) in
|
||||
let s3 = Int64.of_int (read_short input_buf) in
|
||||
Int64.logor
|
||||
(Int64.logor (Int64.shift_left s0 48) (Int64.shift_left s1 32))
|
||||
(Int64.logor (Int64.shift_left s2 16) s3)
|
||||
let read_shortstr input_buf =
|
||||
let len = read_octet input_buf in
|
||||
Ibuffer.next_chars input_buf len
|
||||
let read_longstr input_buf =
|
||||
let len = Int32.to_int (read_long input_buf) in
|
||||
Ibuffer.next_chars input_buf len
|
||||
let read_timestamp input_buf = read_longlong input_buf
|
||||
let read_table input_buf =
|
||||
{ table_body = Encoded_table (read_longstr input_buf) }
|
||||
|
||||
let
|
||||
rec decode_named_fields input_buf =
|
||||
if Ibuffer.remaining input_buf = 0
|
||||
then []
|
||||
else
|
||||
let s = read_shortstr input_buf in
|
||||
let f = read_table_value input_buf in
|
||||
(s, f) :: decode_named_fields input_buf
|
||||
|
||||
and decode_unnamed_fields input_buf =
|
||||
if Ibuffer.remaining input_buf = 0
|
||||
then []
|
||||
else
|
||||
let f = read_table_value input_buf in
|
||||
f :: decode_unnamed_fields input_buf
|
||||
|
||||
and read_table_value input_buf =
|
||||
match Ibuffer.next_char input_buf with
|
||||
| 't' -> Table_bool (read_octet input_buf <> 0)
|
||||
| 'b' ->
|
||||
let v = read_octet input_buf in
|
||||
Table_signed_byte (if v >= 128 then v - 256 else v)
|
||||
| 'B' -> Table_unsigned_byte (read_octet input_buf)
|
||||
| 'U' ->
|
||||
let v = read_short input_buf in
|
||||
Table_signed_short (if v >= 32768 then v - 65536 else v)
|
||||
| 'u' -> Table_unsigned_short (read_short input_buf)
|
||||
| 'I' -> Table_signed_long (read_long input_buf)
|
||||
| 'i' -> Table_unsigned_long (read_long input_buf)
|
||||
| 'L' -> Table_signed_longlong (read_longlong input_buf)
|
||||
| 'l' -> Table_unsigned_longlong (read_longlong input_buf)
|
||||
| 'f' -> Table_float (Ibuffer.next_chars input_buf 4)
|
||||
| 'd' -> Table_double (Ibuffer.next_chars input_buf 8)
|
||||
| 'D' ->
|
||||
let scale = read_octet input_buf in
|
||||
let v = read_long input_buf in
|
||||
Table_decimal (scale, v)
|
||||
| 's' -> Table_short_string (read_shortstr input_buf)
|
||||
| 'S' -> Table_string (read_longstr input_buf)
|
||||
| 'A' ->
|
||||
let n = Int32.to_int (read_long input_buf) in
|
||||
Table_array (decode_unnamed_fields (Ibuffer.next_sub input_buf n))
|
||||
| 'T' -> Table_timestamp (read_longlong input_buf)
|
||||
| 'F' -> Table_table { table_body = Encoded_table (read_longstr input_buf) }
|
||||
| 'V' -> Table_void
|
||||
| c -> raise (Amqp_exception (502 (*syntax-error*),
|
||||
Printf.sprintf "Unknown table field type code '%c'" c))
|
||||
|
||||
and decoded_table t =
|
||||
match t.table_body with
|
||||
| Encoded_table s ->
|
||||
let fs = decode_named_fields (Ibuffer.create s 0 (String.length s)) in
|
||||
t.table_body <- Both_table (s, fs);
|
||||
fs
|
||||
| Decoded_table fs -> fs
|
||||
| Both_table (_, fs) -> fs
|
||||
|
||||
let write_octet output_buf x = Buffer.add_char output_buf (char_of_int x)
|
||||
let write_char output_buf x = write_octet output_buf (int_of_char x)
|
||||
let write_short output_buf x =
|
||||
write_octet output_buf ((x lsr 8) land 255);
|
||||
write_octet output_buf (x land 255)
|
||||
let write_long output_buf x =
|
||||
write_octet output_buf ((Int32.to_int (Int32.shift_right_logical x 24)) land 255);
|
||||
write_octet output_buf ((Int32.to_int (Int32.shift_right_logical x 16)) land 255);
|
||||
write_octet output_buf ((Int32.to_int (Int32.shift_right_logical x 8)) land 255);
|
||||
write_octet output_buf ((Int32.to_int x) land 255)
|
||||
let write_longlong output_buf x =
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 56)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 48)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 40)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 32)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 24)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 16)) land 255);
|
||||
write_octet output_buf ((Int64.to_int (Int64.shift_right_logical x 8)) land 255);
|
||||
write_octet output_buf ((Int64.to_int x) land 255)
|
||||
let write_shortstr output_buf x =
|
||||
let len = String.length x in
|
||||
write_octet output_buf len;
|
||||
Buffer.add_string output_buf x
|
||||
let write_longstr output_buf x =
|
||||
write_long output_buf (Int32.of_int (String.length x));
|
||||
Buffer.add_string output_buf x
|
||||
let write_timestamp output_buf x = write_longlong output_buf x
|
||||
|
||||
let
|
||||
rec encode_named_fields output_buf fs =
|
||||
match fs with
|
||||
[] -> ()
|
||||
| (s, f) :: rest ->
|
||||
write_shortstr output_buf s;
|
||||
write_table_value output_buf f;
|
||||
encode_named_fields output_buf rest
|
||||
|
||||
and encode_unnamed_fields output_buf fs =
|
||||
match fs with
|
||||
[] -> ()
|
||||
| f :: rest ->
|
||||
write_table_value output_buf f;
|
||||
encode_unnamed_fields output_buf rest
|
||||
|
||||
and write_table_value output_buf f =
|
||||
let wcode c = write_char output_buf c in
|
||||
match f with
|
||||
| Table_bool true -> wcode 't'; write_octet output_buf 1
|
||||
| Table_bool false -> wcode 't'; write_octet output_buf 0
|
||||
| Table_signed_byte v -> wcode 'b'; write_octet output_buf (if v < 0 then v + 256 else v)
|
||||
| Table_unsigned_byte v -> wcode 'B'; write_octet output_buf v
|
||||
| Table_signed_short v -> wcode 'U'; write_short output_buf (if v < 0 then v + 65536 else v)
|
||||
| Table_unsigned_short v -> wcode 'u'; write_short output_buf v
|
||||
| Table_signed_long v -> wcode 'I'; write_long output_buf v
|
||||
| Table_unsigned_long v -> wcode 'i'; write_long output_buf v
|
||||
| Table_signed_longlong v -> wcode 'L'; write_longlong output_buf v
|
||||
| Table_unsigned_longlong v -> wcode 'l'; write_longlong output_buf v
|
||||
| Table_float v -> wcode 'f'; Buffer.add_string output_buf v
|
||||
| Table_double v -> wcode 'd'; Buffer.add_string output_buf v
|
||||
| Table_decimal (scale, v) -> wcode 'D'; write_octet output_buf scale; write_long output_buf v
|
||||
| Table_short_string v -> wcode 's'; write_shortstr output_buf v
|
||||
| Table_string v -> wcode 'S'; write_longstr output_buf v
|
||||
| Table_array vs ->
|
||||
wcode 'A';
|
||||
let buf = Buffer.create 1024 in
|
||||
encode_unnamed_fields buf vs;
|
||||
write_longstr output_buf (Buffer.contents buf)
|
||||
| Table_timestamp v -> wcode 'T'; write_longlong output_buf v
|
||||
| Table_table t -> wcode 'F'; write_longstr output_buf (encoded_table t)
|
||||
| Table_void -> wcode 'V'
|
||||
|
||||
and encoded_table t =
|
||||
match t.table_body with
|
||||
| Encoded_table s -> s
|
||||
| Decoded_table fs ->
|
||||
let buf = Buffer.create 1024 in
|
||||
encode_named_fields buf fs;
|
||||
let s = Buffer.contents buf in
|
||||
t.table_body <- Both_table (s, fs);
|
||||
s
|
||||
| Both_table (s, _) -> s
|
||||
|
||||
and write_table output_buf x = write_longstr output_buf (encoded_table x)
|
||||
|
||||
let sexp_of_octet x = Str (string_of_int x)
|
||||
let sexp_of_short x = Str (string_of_int x)
|
||||
let sexp_of_long x = Str (Int32.to_string x)
|
||||
let sexp_of_longlong x = Str (Int64.to_string x)
|
||||
let sexp_of_shortstr x = Str x
|
||||
let sexp_of_longstr x = Str x
|
||||
let sexp_of_bit x = if x then Str "1" else Str "0"
|
||||
let sexp_of_timestamp x = Str (Int64.to_string x)
|
||||
|
||||
let rec
|
||||
sexp_of_table x = Hint {hint = Str "table";
|
||||
body = Arr (List.map sexp_of_named_field (decoded_table x))}
|
||||
and sexp_of_named_field (s, f) = Arr [Str s; sexp_of_unnamed_field f]
|
||||
and sexp_of_unnamed_field f =
|
||||
match f with
|
||||
| Table_bool true -> Str "1"
|
||||
| Table_bool false -> Str "0"
|
||||
| Table_signed_byte v -> sexp_of_octet (if v < 0 then v + 256 else v)
|
||||
| Table_unsigned_byte v -> sexp_of_octet v
|
||||
| Table_signed_short v -> sexp_of_short (if v < 0 then v + 65536 else v)
|
||||
| Table_unsigned_short v -> sexp_of_short v
|
||||
| Table_signed_long v -> sexp_of_long v
|
||||
| Table_unsigned_long v -> Hint {hint = Str "unsigned"; body = sexp_of_long v}
|
||||
| Table_signed_longlong v -> sexp_of_longlong v
|
||||
| Table_unsigned_longlong v -> Hint {hint = Str "unsigned"; body = sexp_of_longlong v}
|
||||
| Table_float v -> Hint {hint = Str "float"; body = Str v}
|
||||
| Table_double v -> Hint {hint = Str "double"; body = Str v}
|
||||
| Table_decimal (scale, v) -> Hint {hint = Str "decimal";
|
||||
body = Arr [Arr [Str "scale"; sexp_of_octet scale];
|
||||
Arr [Str "value"; sexp_of_long v]]}
|
||||
| Table_short_string v -> Str v
|
||||
| Table_string v -> Str v
|
||||
| Table_array vs -> Hint {hint = Str "array"; body = Arr (List.map sexp_of_unnamed_field vs)}
|
||||
| Table_timestamp v -> Hint {hint = Str "timestamp"; body = sexp_of_longlong v}
|
||||
| Table_table t -> sexp_of_table t
|
||||
| Table_void -> Arr []
|
||||
|
||||
let table_of_list fs = { table_body = Decoded_table fs }
|
||||
|
||||
let reserved_value_octet = 0
|
||||
let reserved_value_short = 0
|
||||
let reserved_value_long = Int32.zero
|
||||
let reserved_value_longlong = Int64.zero
|
||||
let reserved_value_shortstr = ""
|
||||
let reserved_value_longstr = ""
|
||||
let reserved_value_bit = false
|
||||
let reserved_value_timestamp = Int64.zero
|
||||
let reserved_value_table = { table_body = Encoded_table "" }
|
|
@ -0,0 +1,48 @@
|
|||
type t = {
|
||||
mutable pos: int;
|
||||
limit: int;
|
||||
buf: string;
|
||||
}
|
||||
|
||||
let create s ofs len = {
|
||||
pos = ofs;
|
||||
limit = ofs + len;
|
||||
buf = s
|
||||
}
|
||||
|
||||
let sub b ofs len =
|
||||
if b.pos + ofs + len > b.limit
|
||||
then
|
||||
raise End_of_file
|
||||
else
|
||||
{ pos = b.pos + ofs;
|
||||
limit = b.pos + ofs + len;
|
||||
buf = b.buf }
|
||||
|
||||
let remaining b = b.limit - b.pos
|
||||
|
||||
let next_char b =
|
||||
if b.pos < b.limit
|
||||
then
|
||||
let v = String.get b.buf b.pos in
|
||||
b.pos <- b.pos + 1;
|
||||
v
|
||||
else
|
||||
raise End_of_file
|
||||
|
||||
let next_byte b = int_of_char (next_char b)
|
||||
|
||||
let next_chars b n =
|
||||
if remaining b < n
|
||||
then
|
||||
raise End_of_file
|
||||
else
|
||||
let dst = String.create n in
|
||||
String.blit b.buf b.pos dst 0 n;
|
||||
b.pos <- b.pos + n;
|
||||
dst
|
||||
|
||||
let next_sub b n =
|
||||
let v = sub b 0 n in
|
||||
b.pos <- b.pos + n;
|
||||
v
|
13
ocamlmsg.ml
13
ocamlmsg.ml
|
@ -2,19 +2,19 @@ open Unix
|
|||
open Printf
|
||||
open Thread
|
||||
|
||||
let rec accept_loop sock =
|
||||
let rec accept_loop sock connection_start_fn =
|
||||
let (s, peername) = accept sock in
|
||||
setsockopt s TCP_NODELAY true;
|
||||
ignore (Relay.start_relay (s, peername));
|
||||
accept_loop sock
|
||||
ignore (connection_start_fn (s, peername));
|
||||
accept_loop sock connection_start_fn
|
||||
|
||||
let start_net port_number =
|
||||
let start_net port_number connection_start_fn =
|
||||
let sock = socket PF_INET SOCK_STREAM 0 in
|
||||
setsockopt sock SO_REUSEADDR true;
|
||||
bind sock (ADDR_INET (inet_addr_of_string "0.0.0.0", port_number));
|
||||
listen sock 5;
|
||||
Log.info "Accepting connections" [Sexp.Str (string_of_int port_number)];
|
||||
accept_loop sock
|
||||
accept_loop sock connection_start_fn
|
||||
|
||||
let hook_log () =
|
||||
let old_hook = !Log.hook in
|
||||
|
@ -31,4 +31,5 @@ let _ =
|
|||
Factory.init ();
|
||||
Queuenode.init ();
|
||||
hook_log ();
|
||||
start_net 5671
|
||||
ignore (Util.create_thread "AMQP listener" None (start_net Amqp_spec.port) Amqp_relay.start);
|
||||
start_net 5671 Relay.start
|
||||
|
|
Loading…
Reference in New Issue