Move to subdirectory in preparation for repo merge.

This commit is contained in:
Tony Garnock-Jones 2012-05-11 08:53:27 -04:00
parent c539cfd526
commit eeece41b83
54 changed files with 9 additions and 1928 deletions

10
.gitignore vendored
View File

@ -1,10 +0,0 @@
scratch/
*.o
server/messages.h
server/messages.c
server/cmsg
server/test1
server/test3
server/test1_latency
server/test3_latency
depend.mk

View File

@ -1,459 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2009 AMQP Working Group.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<amqp major="0" minor="9" revision="1" port="5672">
<constant name="frame-method" value="1"/>
<constant name="frame-header" value="2"/>
<constant name="frame-body" value="3"/>
<constant name="frame-heartbeat" value="8"/>
<constant name="frame-min-size" value="4096"/>
<constant name="frame-end" value="206"/>
<constant name="reply-success" value="200"/>
<constant name="content-too-large" value="311" class="soft-error"/>
<constant name="no-consumers" value="313" class="soft-error"/>
<constant name="connection-forced" value="320" class="hard-error"/>
<constant name="invalid-path" value="402" class="hard-error"/>
<constant name="access-refused" value="403" class="soft-error"/>
<constant name="not-found" value="404" class="soft-error"/>
<constant name="resource-locked" value="405" class="soft-error"/>
<constant name="precondition-failed" value="406" class="soft-error"/>
<constant name="frame-error" value="501" class="hard-error"/>
<constant name="syntax-error" value="502" class="hard-error"/>
<constant name="command-invalid" value="503" class="hard-error"/>
<constant name="channel-error" value="504" class="hard-error"/>
<constant name="unexpected-frame" value="505" class="hard-error"/>
<constant name="resource-error" value="506" class="hard-error"/>
<constant name="not-allowed" value="530" class="hard-error"/>
<constant name="not-implemented" value="540" class="hard-error"/>
<constant name="internal-error" value="541" class="hard-error"/>
<domain name="class-id" type="short"/>
<domain name="consumer-tag" type="shortstr"/>
<domain name="delivery-tag" type="longlong"/>
<domain name="exchange-name" type="shortstr">
<assert check="length" value="127"/>
<assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/>
</domain>
<domain name="method-id" type="short"/>
<domain name="no-ack" type="bit"/>
<domain name="no-local" type="bit"/>
<domain name="no-wait" type="bit"/>
<domain name="path" type="shortstr">
<assert check="notnull"/>
<assert check="length" value="127"/>
</domain>
<domain name="peer-properties" type="table"/>
<domain name="queue-name" type="shortstr">
<assert check="length" value="127"/>
<assert check="regexp" value="^[a-zA-Z0-9-_.:]*$"/>
</domain>
<domain name="redelivered" type="bit"/>
<domain name="message-count" type="long"/>
<domain name="reply-code" type="short">
<assert check="notnull"/>
</domain>
<domain name="reply-text" type="shortstr">
<assert check="notnull"/>
</domain>
<domain name="bit" type="bit"/>
<domain name="octet" type="octet"/>
<domain name="short" type="short"/>
<domain name="long" type="long"/>
<domain name="longlong" type="longlong"/>
<domain name="shortstr" type="shortstr"/>
<domain name="longstr" type="longstr"/>
<domain name="timestamp" type="timestamp"/>
<domain name="table" type="table"/>
<class name="connection" handler="connection" index="10">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<method name="start" synchronous="1" index="10">
<chassis name="client" implement="MUST"/>
<response name="start-ok"/>
<field name="version-major" domain="octet"/>
<field name="version-minor" domain="octet"/>
<field name="server-properties" domain="peer-properties"/>
<field name="mechanisms" domain="longstr">
<assert check="notnull"/>
</field>
<field name="locales" domain="longstr">
<assert check="notnull"/>
</field>
</method>
<method name="start-ok" synchronous="1" index="11">
<chassis name="server" implement="MUST"/>
<field name="client-properties" domain="peer-properties"/>
<field name="mechanism" domain="shortstr">
<assert check="notnull"/>
</field>
<field name="response" domain="longstr">
<assert check="notnull"/>
</field>
<field name="locale" domain="shortstr">
<assert check="notnull"/>
</field>
</method>
<method name="secure" synchronous="1" index="20">
<chassis name="client" implement="MUST"/>
<response name="secure-ok"/>
<field name="challenge" domain="longstr"/>
</method>
<method name="secure-ok" synchronous="1" index="21">
<chassis name="server" implement="MUST"/>
<field name="response" domain="longstr">
<assert check="notnull"/>
</field>
</method>
<method name="tune" synchronous="1" index="30">
<chassis name="client" implement="MUST"/>
<response name="tune-ok"/>
<field name="channel-max" domain="short"/>
<field name="frame-max" domain="long"/>
<field name="heartbeat" domain="short"/>
</method>
<method name="tune-ok" synchronous="1" index="31">
<chassis name="server" implement="MUST"/>
<field name="channel-max" domain="short">
<assert check="notnull"/>
<assert check="le" method="tune" field="channel-max"/>
</field>
<field name="frame-max" domain="long"/>
<field name="heartbeat" domain="short"/>
</method>
<method name="open" synchronous="1" index="40">
<chassis name="server" implement="MUST"/>
<response name="open-ok"/>
<field name="virtual-host" domain="path"/>
<field name="reserved-1" type="shortstr" reserved="1"/>
<field name="reserved-2" type="bit" reserved="1"/>
</method>
<method name="open-ok" synchronous="1" index="41">
<chassis name="client" implement="MUST"/>
<field name="reserved-1" type="shortstr" reserved="1"/>
</method>
<method name="close" synchronous="1" index="50">
<chassis name="client" implement="MUST"/>
<chassis name="server" implement="MUST"/>
<response name="close-ok"/>
<field name="reply-code" domain="reply-code"/>
<field name="reply-text" domain="reply-text"/>
<field name="class-id" domain="class-id"/>
<field name="method-id" domain="method-id"/>
</method>
<method name="close-ok" synchronous="1" index="51">
<chassis name="client" implement="MUST"/>
<chassis name="server" implement="MUST"/>
</method>
</class>
<class name="channel" handler="channel" index="20">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<method name="open" synchronous="1" index="10">
<chassis name="server" implement="MUST"/>
<response name="open-ok"/>
<field name="reserved-1" type="shortstr" reserved="1"/>
</method>
<method name="open-ok" synchronous="1" index="11">
<chassis name="client" implement="MUST"/>
<field name="reserved-1" type="longstr" reserved="1"/>
</method>
<method name="flow" synchronous="1" index="20">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<response name="flow-ok"/>
<field name="active" domain="bit"/>
</method>
<method name="flow-ok" index="21">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<field name="active" domain="bit"/>
</method>
<method name="close" synchronous="1" index="40">
<chassis name="client" implement="MUST"/>
<chassis name="server" implement="MUST"/>
<response name="close-ok"/>
<field name="reply-code" domain="reply-code"/>
<field name="reply-text" domain="reply-text"/>
<field name="class-id" domain="class-id"/>
<field name="method-id" domain="method-id"/>
</method>
<method name="close-ok" synchronous="1" index="41">
<chassis name="client" implement="MUST"/>
<chassis name="server" implement="MUST"/>
</method>
</class>
<class name="exchange" handler="channel" index="40">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<method name="declare" synchronous="1" index="10">
<chassis name="server" implement="MUST"/>
<response name="declare-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="exchange" domain="exchange-name">
<assert check="notnull"/>
</field>
<field name="type" domain="shortstr"/>
<field name="passive" domain="bit"/>
<field name="durable" domain="bit"/>
<field name="reserved-2" type="bit" reserved="1"/>
<field name="reserved-3" type="bit" reserved="1"/>
<field name="no-wait" domain="no-wait"/>
<field name="arguments" domain="table"/>
</method>
<method name="declare-ok" synchronous="1" index="11">
<chassis name="client" implement="MUST"/>
</method>
<method name="delete" synchronous="1" index="20">
<chassis name="server" implement="MUST"/>
<response name="delete-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="exchange" domain="exchange-name">
<assert check="notnull"/>
</field>
<field name="if-unused" domain="bit"/>
<field name="no-wait" domain="no-wait"/>
</method>
<method name="delete-ok" synchronous="1" index="21">
<chassis name="client" implement="MUST"/>
</method>
</class>
<class name="queue" handler="channel" index="50">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MUST"/>
<method name="declare" synchronous="1" index="10">
<chassis name="server" implement="MUST"/>
<response name="declare-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="passive" domain="bit"/>
<field name="durable" domain="bit"/>
<field name="exclusive" domain="bit"/>
<field name="auto-delete" domain="bit"/>
<field name="no-wait" domain="no-wait"/>
<field name="arguments" domain="table"/>
</method>
<method name="declare-ok" synchronous="1" index="11">
<chassis name="client" implement="MUST"/>
<field name="queue" domain="queue-name">
<assert check="notnull"/>
</field>
<field name="message-count" domain="message-count"/>
<field name="consumer-count" domain="long"/>
</method>
<method name="bind" synchronous="1" index="20">
<chassis name="server" implement="MUST"/>
<response name="bind-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
<field name="no-wait" domain="no-wait"/>
<field name="arguments" domain="table"/>
</method>
<method name="bind-ok" synchronous="1" index="21">
<chassis name="client" implement="MUST"/>
</method>
<method name="unbind" synchronous="1" index="50">
<chassis name="server" implement="MUST"/>
<response name="unbind-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
<field name="arguments" domain="table"/>
</method>
<method name="unbind-ok" synchronous="1" index="51">
<chassis name="client" implement="MUST"/>
</method>
<method name="purge" synchronous="1" index="30">
<chassis name="server" implement="MUST"/>
<response name="purge-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="no-wait" domain="no-wait"/>
</method>
<method name="purge-ok" synchronous="1" index="31">
<chassis name="client" implement="MUST"/>
<field name="message-count" domain="message-count"/>
</method>
<method name="delete" synchronous="1" index="40">
<chassis name="server" implement="MUST"/>
<response name="delete-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="if-unused" domain="bit"/>
<field name="if-empty" domain="bit"/>
<field name="no-wait" domain="no-wait"/>
</method>
<method name="delete-ok" synchronous="1" index="41">
<chassis name="client" implement="MUST"/>
<field name="message-count" domain="message-count"/>
</method>
</class>
<class name="basic" handler="channel" index="60">
<chassis name="server" implement="MUST"/>
<chassis name="client" implement="MAY"/>
<field name="content-type" domain="shortstr"/>
<field name="content-encoding" domain="shortstr"/>
<field name="headers" domain="table"/>
<field name="delivery-mode" domain="octet"/>
<field name="priority" domain="octet"/>
<field name="correlation-id" domain="shortstr"/>
<field name="reply-to" domain="shortstr"/>
<field name="expiration" domain="shortstr"/>
<field name="message-id" domain="shortstr"/>
<field name="timestamp" domain="timestamp"/>
<field name="type" domain="shortstr"/>
<field name="user-id" domain="shortstr"/>
<field name="app-id" domain="shortstr"/>
<field name="reserved" domain="shortstr"/>
<method name="qos" synchronous="1" index="10">
<chassis name="server" implement="MUST"/>
<response name="qos-ok"/>
<field name="prefetch-size" domain="long"/>
<field name="prefetch-count" domain="short"/>
<field name="global" domain="bit"/>
</method>
<method name="qos-ok" synchronous="1" index="11">
<chassis name="client" implement="MUST"/>
</method>
<method name="consume" synchronous="1" index="20">
<chassis name="server" implement="MUST"/>
<response name="consume-ok"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="consumer-tag" domain="consumer-tag"/>
<field name="no-local" domain="no-local"/>
<field name="no-ack" domain="no-ack"/>
<field name="exclusive" domain="bit"/>
<field name="no-wait" domain="no-wait"/>
<field name="arguments" domain="table"/>
</method>
<method name="consume-ok" synchronous="1" index="21">
<chassis name="client" implement="MUST"/>
<field name="consumer-tag" domain="consumer-tag"/>
</method>
<method name="cancel" synchronous="1" index="30">
<chassis name="server" implement="MUST"/>
<response name="cancel-ok"/>
<field name="consumer-tag" domain="consumer-tag"/>
<field name="no-wait" domain="no-wait"/>
</method>
<method name="cancel-ok" synchronous="1" index="31">
<chassis name="client" implement="MUST"/>
<field name="consumer-tag" domain="consumer-tag"/>
</method>
<method name="publish" content="1" index="40">
<chassis name="server" implement="MUST"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
<field name="mandatory" domain="bit"/>
<field name="immediate" domain="bit"/>
</method>
<method name="return" content="1" index="50">
<chassis name="client" implement="MUST"/>
<field name="reply-code" domain="reply-code"/>
<field name="reply-text" domain="reply-text"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
</method>
<method name="deliver" content="1" index="60">
<chassis name="client" implement="MUST"/>
<field name="consumer-tag" domain="consumer-tag"/>
<field name="delivery-tag" domain="delivery-tag"/>
<field name="redelivered" domain="redelivered"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
</method>
<method name="get" synchronous="1" index="70">
<response name="get-ok"/>
<response name="get-empty"/>
<chassis name="server" implement="MUST"/>
<field name="reserved-1" type="short" reserved="1"/>
<field name="queue" domain="queue-name"/>
<field name="no-ack" domain="no-ack"/>
</method>
<method name="get-ok" synchronous="1" content="1" index="71">
<chassis name="client" implement="MAY"/>
<field name="delivery-tag" domain="delivery-tag"/>
<field name="redelivered" domain="redelivered"/>
<field name="exchange" domain="exchange-name"/>
<field name="routing-key" domain="shortstr"/>
<field name="message-count" domain="message-count"/>
</method>
<method name="get-empty" synchronous="1" index="72">
<chassis name="client" implement="MAY"/>
<field name="reserved-1" type="shortstr" reserved="1"/>
</method>
<method name="ack" index="80">
<chassis name="server" implement="MUST"/>
<field name="delivery-tag" domain="delivery-tag"/>
<field name="multiple" domain="bit"/>
</method>
<method name="reject" index="90">
<chassis name="server" implement="MUST"/>
<field name="delivery-tag" domain="delivery-tag"/>
<field name="requeue" domain="bit"/>
</method>
<method name="recover-async" index="100" deprecated="1">
<chassis name="server" implement="MAY"/>
<field name="requeue" domain="bit"/>
</method>
<method name="recover" index="110">
<chassis name="server" implement="MUST"/>
<field name="requeue" domain="bit"/>
</method>
<method name="recover-ok" synchronous="1" index="111">
<chassis name="client" implement="MUST"/>
</method>
</class>
<class name="tx" handler="channel" index="90">
<chassis name="server" implement="SHOULD"/>
<chassis name="client" implement="MAY"/>
<method name="select" synchronous="1" index="10">
<chassis name="server" implement="MUST"/>
<response name="select-ok"/>
</method>
<method name="select-ok" synchronous="1" index="11">
<chassis name="client" implement="MUST"/>
</method>
<method name="commit" synchronous="1" index="20">
<chassis name="server" implement="MUST"/>
<response name="commit-ok"/>
</method>
<method name="commit-ok" synchronous="1" index="21">
<chassis name="client" implement="MUST"/>
</method>
<method name="rollback" synchronous="1" index="30">
<chassis name="server" implement="MUST"/>
<response name="rollback-ok"/>
</method>
<method name="rollback-ok" synchronous="1" index="31">
<chassis name="client" implement="MUST"/>
</method>
</class>
</amqp>

View File

@ -1,699 +0,0 @@
Network Working Group R. Rivest
Internet Draft May 4, 1997
Expires November 4, 1997
S-Expressions
draft-rivest-sexp-00.txt
Status of this Memo
Distribution of this memo is unlimited.
This document is an Internet-Draft. Internet Drafts are working
documents of the Internet Engineering Task Force (IETF), its Areas,
and its Working Groups. Note that other groups may also distribute
working documents as Internet Drafts.
Internet Drafts are draft documents valid for a maximum of six
months, and may be updated, replaced, or obsoleted by other documents
at any time. It is not appropriate to use Internet Drafts as
reference material, or to cite them other than as a ``working draft''
or ``work in progress.''
To learn the current status of any Internet-Draft, please check the
``1id-abstracts.txt'' listing contained in the internet-drafts Shadow
Directories on: ftp.is.co.za (Africa), nic.nordu.net (Europe),
ds.internic.net (US East Coast), ftp.isi.edu (US West Coast),
or munnari.oz.au (Pacific Rim)
Abstract
This memo describes a data structure called "S-expressions" that are
suitable for representing arbitrary complex data structures. We make
precise the encodings of S-expressions: we give a "canonical form" for
S-expressions, described two "transport" representations, and also
describe an "advanced" format for display to people.
1. Introduction
S-expressions are data structures for representing complex data. They
are either byte-strings ("octet-strings") or lists of simpler
S-expressions. Here is a sample S-expression:
(snicker "abc" (#03# |YWJj|))
It is a list of length three:
-- the octet-string "snicker"
-- the octet-string "abc"
-- a sub-list containing two elements:
- the hexadecimal constant #03#
- the base-64 constant |YWJj| (which is the same as "abc")
This note gives a specific proposal for constructing and utilizing
S-expressions. The proposal is independent of any particular application.
Here are the design goals for S-expressions:
-- generality: S-expressions should be good at representing arbitrary
data.
-- readability: it should be easy for someone to examine and
understand the structure of an S-expression.
-- economy: S-expressions should represent data compactly.
-- tranportability: S-expressions should be easy to transport
over communication media (such as email) that are known to be
less than perfect.
-- flexibility: S-expressions should make it relatively simple to
modify and extend data structures.
-- canonicalization: it should be easy to produce a unique
"canonical" form of an S-expression, for digital signature purposes.
-- efficiency: S-expressions should admit in-memory representations
that allow efficient processing.
Section 2 gives an introduction to S-expressions.
Section 3 discusses the character sets used.
Section 4 presents the various representations of octet-strings.
Section 5 describes how to represent lists.
Section 6 discusses how S-expressions are represented for various uses.
Section 7 gives a BNF syntax for S-expressions.
Section 8 talks about how S-expressions might be represented in memory.
Section 9 briefly describes implementations for handling S-expressions.
Section 10 discusses how applications might utilize S-expressions.
Section 11 gives historical notes on S-expressions.
Section 12 gives references.
2. S-expressions -- informal introduction
Informally, an S-expression is either:
-- an octet-string, or
-- a finite list of simpler S-expressions.
An octet-string is a finite sequence of eight-bit octets. There may be
many different but equivalent ways of representing an octet-string
abc -- as a token
"abc" -- as a quoted string
#616263# -- as a hexadecimal string
3:abc -- as a length-prefixed "verbatim" encoding
{MzphYmM=} -- as a base-64 encoding of the verbatim encoding
(that is, an encoding of "3:abc")
|YWJj| -- as a base-64 encoding of the octet-string "abc"
These encodings are all equivalent; they all denote the same octet string.
We will give details of these encodings later on, and also describe how to
give a "display type" to a byte string.
A list is a finite sequence of zero or more simpler S-expressions. A list
may be represented by using parentheses to surround the sequence of encodings
of its elements, as in:
(abc (de #6667#) "ghi jkl")
As we see, there is variability possible in the encoding of an
S-expression. In some cases, it is desirable to standardize or
restrict the encodings; in other cases it is desirable to have no
restrictions. The following are the target cases we aim to handle:
-- a "transport" encoding for transporting the S-expression between
computers.
-- a "canonical" encoding, used when signing the S-expression.
-- an "advanced" encoding used for input/output to people.
-- an "in-memory" encoding used for processing the S-expression in
the computer.
These need not be different; in this proposal the canonical encoding
is the same as the transport encoding, for example. In this note we
propose (related) encoding techniques for each of these uses.
3. Character set
We will be describing encodings of S-expressions. Except when giving
"verbatim" encodings, the character set used is limited to the following
characters in US-ASCII:
Alphabetic: A B ... Z a b ... z
numeric: 0 1 ... 9
whitespace: space, horizontal tab, vertical tab, form-feed
carriage-return, line-feed
The following graphics characters, which we call "pseudo-alphabetic":
- hyphen or minus
. period
/ slash
_ underscore
: colon
* asterisk
+ plus
= equal
The following graphics characters, which are "reserved punctuation":
( left parenthesis
) right parenthesis
[ left bracket
] right bracket
{ left brace
} right brace
| vertical bar
# number sign
" double quote
& ampersand
\ backslash
The following characters are unused and unavailable, except in
"verbatim" encodings:
! exclamation point
% percent
^ circumflex
~ tilde
; semicolon
' apostrophe
, comma
< less than
> greater than
? question mark
4. Octet string representations
This section describes in detail the ways in which an octet-string may
be represented.
We recall that an octet-string is any finite sequence of octets, and
that the octet-string may have length zero.
4.1 Verbatim representation
A verbatim encoding of an octet string consists of four parts:
-- the length (number of octets) of the octet-string,
given in decimal most significant digit first, with
no leading zeros.
-- a colon ":"
-- the octet string itself, verbatim.
There are no blanks or whitespace separating the parts. No "escape
sequences" are interpreted in the octet string. This encoding is also
called a "binary" or "raw" encoding.
Here are some sample verbatim encodings:
3:abc
7:subject
4:::::
12:hello world!
10:abcdefghij
0:
4.2 Quoted-string representation
The quoted-string representation of an octet-string consists of:
-- an optional decimal length field
-- an initial double-quote (")
-- the octet string with "C" escape conventions (\n,etc)
-- a final double-quote (")
The specified length is the length of the resulting string after any
escape sequences have been handled. The string does not have any
"terminating NULL" that C includes, and the length does not count such
a character.
The length is optional.
The escape conventions within the quoted string are as follows (these follow
the "C" programming language conventions, with an extension for
ignoring line terminators of just LF or CRLF):
\b -- backspace
\t -- horizontal tab
\v -- vertical tab
\n -- new-line
\f -- form-feed
\r -- carriage-return
\" -- double-quote
\' -- single-quote
\\ -- back-slash
\ooo -- character with octal value ooo (all three digits
must be present)
\xhh -- character with hexadecimal value hh (both digits
must be present)
\<carriage-return> -- causes carriage-return to be ignored.
\<line-feed> -- causes linefeed to be ignored
\<carriage-return><line-feed> -- causes CRLF to be ignored.
\<line-feed><carriage-return> -- causes LFCR to be ignored.
Here are some examples of quoted-string encodings:
"subject"
"hi there"
7"subject"
3"\n\n\n"
"This has\n two lines."
"This has\
one."
""
4.3 Token representation
An octet string that meets the following conditions may be given
directly as a "token".
-- it does not begin with a digit
-- it contains only characters that are
-- alphabetic (upper or lower case),
-- numeric, or
-- one of the eight "pseudo-alphabetic" punctuation marks:
- . / _ : * + =
(Note: upper and lower case are not equivalent.)
(Note: A token may begin with punctuation, including ":").
Here are some examples of token representations:
subject
not-before
class-of-1997
//microsoft.com/names/smith
*
4.4 Hexadecimal representation
An octet-string may be represented with a hexadecimal encoding consisting of:
-- an (optional) decimal length of the octet string
-- a sharp-sign "#"
-- a hexadecimal encoding of the octet string, with each octet
represented with two hexadecimal digits, most significant
digit first.
-- a sharp-sign "#"
There may be whitespace inserted in the midst of the hexadecimal
encoding arbitrarily; it is ignored. It is an error to have
characters other than whitespace and hexadecimal digits.
Here are some examples of hexadecimal encodings:
#616263# -- represents "abc"
3#616263# -- also represents "abc"
# 616
263 # -- also represents "abc"
4.5 Base-64 representation
An octet-string may be represented in a base-64 coding consisting of:
-- an (optional) decimal length of the octet string
-- a vertical bar "|"
-- the rfc 1521 base-64 encoding of the octet string.
-- a final vertical bar "|"
The base-64 encoding uses only the characters
A-Z a-z 0-9 + / =
It produces four characters of output for each three octets of input.
If the input has one or two left-over octets of input, it produces an
output block of length four ending in two or one equals signs, respectively.
Output routines compliant with this standard MUST output the equals signs
as specified. Input routines MAY accept inputs where the equals signs are
dropped.
There may be whitespace inserted in the midst of the base-64 encoding
arbitrarily; it is ignored. It is an error to have characters other
than whitespace and base-64 characters.
Here are some examples of base-64 encodings:
|YWJj| -- represents "abc"
| Y W
J j | -- also represents "abc"
3|YWJj| -- also represents "abc"
|YWJjZA==| -- represents "abcd"
|YWJjZA| -- also represents "abcd"
4.6 Display hint
Any octet string may be preceded by a single "display hint".
The purposes of the display hint is to provide information on how
to display the octet string to a user. It has no other function.
Many of the MIME types work here.
A display-hint is an octet string surrounded by square brackets.
There may be whitespace separating the octet string from the
surrounding brackets. Any of the legal formats may be used for the
octet string.
Here are some examples of display-hints:
[image/gif]
[URI]
[charset=unicode-1-1]
[text/richtext]
[application/postscript]
[audio/basic]
["http://abc.com/display-types/funky.html"]
In applications an octet-string that is untyped may be considered to have
a pre-specified "default" mime type. The mime type
"text/plain; charset=iso-8859-1"
is the standard default.
4.7 Equality of octet-strings
Two octet strings are considered to be "equal" if and only if they
have the same display hint and the same data octet strings.
Note that octet-strings are "case-sensitive"; the octet-string "abc"
is not equal to the octet-string "ABC".
An untyped octet-string can be compared to another octet-string (typed
or not) by considering it as a typed octet-string with the default
mime-type.
5. Lists
Just as with octet-strings, there are several ways to represent an
S-expression. Whitespace may be used to separate list elements, but
they are only required to separate two octet strings when otherwise
the two octet strings might be interpreted as one, as when one token
follows another. Also, whitespace may follow the initial left
parenthesis, or precede the final right parenthesis.
Here are some examples of encodings of lists:
(a b c)
( a ( b c ) ( ( d e ) ( e f ) ) )
(11:certificate(6:issuer3:bob)(7:subject5:alice))
({3Rt=} "1997" murphy 3:{XC++})
6. Representation types
There are three "types" of representations:
-- canonical
-- basic transport
-- advanced transport
The first two MUST be supported by any implementation; the last is
optional.
6.1 Canonical representation
This canonical representation is used for digital signature purposes,
transmission, etc. It is uniquely defined for each S-expression. It
is not particularly readable, but that is not the point. It is
intended to be very easy to parse, to be reasonably economical, and to
be unique for any S-expression.
The "canonical" form of an S-expression represents each octet-string
in verbatim mode, and represents each list with no blanks separating
elements from each other or from the surrounding parentheses.
Here are some examples of canonical representations of S-expressions:
(6:issuer3:bob)
(4:icon[12:image/bitmap]9:xxxxxxxxx)
(7:subject(3:ref5:alice6:mother))
6.2 Basic transport representation
There are two forms of the "basic transport" representation:
-- the canonical representation
-- an rfc-2045 base-64 representation of the canonical representation,
surrounded by braces.
The transport mechanism is intended to provide a universal means of
representing S-expressions for transport from one machine to another.
Here are some examples of an S-expression represented in basic
transport mode:
(1:a1:b1:c)
{KDE6YTE6YjE6YykA}
(this is the same S-expression encoded in base-64)
There is a difference between the brace notation for base-64 used here
and the || notation for base-64'd octet-strings described above. Here
the base-64 contents are converted to octets, and then re-scanned as
if they were given originally as octets. With the || notation, the
contents are just turned into an octet-string.
6.3 Advanced transport representation
The "advanced transport" representation is intended to provide more
flexible and readable notations for documentation, design, debugging,
and (in some cases) user interface.
The advanced transport representation allows all of the representation
forms described above, include quoted strings, base-64 and hexadecimal
representation of strings, tokens, representations of strings with
omitted lengths, and so on.
7. BNF for syntax
We give separate BNF's for canonical and advanced forms of S-expressions.
We use the following notation:
<x>* means 0 or more occurrences of <x>
<x>+ means 1 or more occurrences of <x>
<x>? means 0 or 1 occurrences of <x>
parentheses are used for grouping, as in (<x> | <y>)*
For canonical and basic transport:
<sexpr> :: <string> | <list>
<string> :: <display>? <simple-string> ;
<simple-string> :: <raw> ;
<display> :: "[" <simple-string> "]" ;
<raw> :: <decimal> ":" <bytes> ;
<decimal> :: <decimal-digit>+ ;
-- decimal numbers should have no unnecessary leading zeros
<bytes> -- any string of bytes, of the indicated length
<list> :: "(" <sexp>* ")" ;
<decimal-digit> :: "0" | ... | "9" ;
For advanced transport:
<sexpr> :: <string> | <list>
<string> :: <display>? <simple-string> ;
<simple-string> :: <raw> | <token> | <base-64> | <hexadecimal> |
<quoted-string> ;
<display> :: "[" <simple-string> "]" ;
<raw> :: <decimal> ":" <bytes> ;
<decimal> :: <decimal-digit>+ ;
-- decimal numbers should have no unnecessary leading zeros
<bytes> -- any string of bytes, of the indicated length
<token> :: <tokenchar>+ ;
<base-64> :: <decimal>? "|" ( <base-64-char> | <whitespace> )* "|" ;
<hexadecimal> :: "#" ( <hex-digit> | <white-space> )* "#" ;
<quoted-string> :: <decimal>? <quoted-string-body>
<quoted-string-body> :: "\"" <bytes> "\""
<list> :: "(" ( <sexp> | <whitespace> )* ")" ;
<whitespace> :: <whitespace-char>* ;
<token-char> :: <alpha> | <decimal-digit> | <simple-punc> ;
<alpha> :: <upper-case> | <lower-case> | <digit> ;
<lower-case> :: "a" | ... | "z" ;
<upper-case> :: "A" | ... | "Z" ;
<decimal-digit> :: "0" | ... | "9" ;
<hex-digit> :: <decimal-digit> | "A" | ... | "F" | "a" | ... | "f" ;
<simple-punc> :: "-" | "." | "/" | "_" | ":" | "*" | "+" | "=" ;
<whitespace-char> :: " " | "\t" | "\r" | "\n" ;
<base-64-char> :: <alpha> | <decimal-digit> | "+" | "/" | "=" ;
<null> :: "" ;
8. In-memory representations
For processing, the S-expression would typically be parsed and represented
in memory in a more more amenable to efficient processing. We suggest
two alternatives:
-- "list-structure"
-- "array-layout"
We only sketch these here, as they are only suggestive. The code referenced
below illustrates these styles in more detail.
8.1. List-structure memory representation
Here there are separate records for simple-strings, strings, and
lists. An S-expression of the form ("abc" "de") would require two
records for the simple strings, two for the strings, and two for the
list elements. This is a fairly conventional representation, and
details are omitted here.
8.2 Array-layout memory representation
Here each S-expression is represented as a contiguous array of bytes.
The first byte codes the "type" of the S-expression:
01 octet-string
02 octet-string with display-hint
03 beginning of list (and 00 is used for "end of list")
Each of the three types is immediately followed by a k-byte integer
indicating the size (in bytes) of the following representation. Here
k is an integer that depends on the implementation, it might be
anywhere from 2 to 8, but would be fixed for a given implementation;
it determines the size of the objects that can be handled. The transport
and canonical representations are independent of the choice of k made by
the implementation.
Although the length of lists are not given in the usual S-expression
notations, it is easy to fill them in when parsing; when you reach a
right-parenthesis you know how long the list representation was, and
where to go back to fill in the missing length.
8.2.1 Octet string
This is represented as follows:
01 <length> <octet-string>
For example (here k = 2)
01 0003 a b c
8.2.2 Octet-string with display-hint
This is represented as follows:
02 <length>
01 <length> <octet-string> /* for display-type */
01 <length> <octet-string> /* for octet-string */
For example, the S-expression
[gif] #61626364#
would be represented as (with k = 2)
02 000d
01 0003 g i f
01 0004 61 62 63 64
8.2.3 List
This is represented as
03 <length> <item1> <item2> <item3> ... <itemn> 00
For example, the list (abc [d]ef (g)) is represented in memory as (with k=2)
03 001b
01 0003 a b c
02 0009
01 0001 d
01 0002 e f
03 0005
01 0001 g
00
00
9. Code
There is code available for reading and parsing the various
S-expression formats proposed here.
See http://theory.lcs.mit.edu/~rivest/sexp.html
10. Utilization of S-expressions
This note has described S-expressions in general form. Application writers
may wish to restrict their use of S-expressions in various ways. Here are
some possible restrictions that might be considered:
-- no display-hints
-- no lengths on hexadecimal, quoted-strings, or base-64 encodings
-- no empty lists
-- no empty octet-strings
-- no lists having another list as its first element
-- no base-64 or hexadecimal encodings
-- fixed limits on the size of octet-strings
11. Historical note
The S-expression technology described here was originally developed
for ``SDSI'' (the Simple Distributed Security Infrastructure by
Lampson and Rivest [SDSI]) in 1996, although the origins clearly date
back to McCarthy's LISP programming language. It was further refined
and improved during the merger of SDSI and SPKI [SPKI] during the
first half of 1997. S-expressions are similar to, but more readable
and flexible than, Bernstein's "net-strings" [BERN].
12. References
[SDSI] "A Simple Distributed Security Architecture", by
Butler Lampson, and Ronald L. Rivest
http://theory.lcs.mit.edu/~cis/sdsi.html
[SPKI] <a href="http://www.clark.net/pub/cme/html/spki.html">SPKI--A
Simple Public Key Infrastructure</a>
[BERN] Dan Bernstein's "net-strings"; Internet Draft
draft-bernstein-netstrings-02.txt
Author's Address
Ronald L. Rivest
Room 324, 545 Technology Square
MIT Laboratory for Computer Science
Cambridge, MA 02139
rivest@theory.lcs.mit.edu

5
experiments/cmsg/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.o
messages.h
messages.c
cmsg
depend.mk

View File

@ -25,10 +25,10 @@ $(TARGET): $(OBJECTS)
%.o: %.c
$(CC) $(CFLAGS) -c $<
messages.c: messages.json codegen.py
messages.c: ../../protocol/messages.json codegen.py
python codegen.py body > $@
messages.h: messages.json codegen.py
messages.h: ../../protocol/messages.json codegen.py
python codegen.py header > $@
clean:
@ -36,7 +36,6 @@ clean:
rm -f $(OBJECTS)
rm -rf *.dSYM
rm -f depend.mk messages.c messages.h
rm -f test1 test3 test1.o test3.o test1_latency test3_latency test1_latency.o test3_latency.o
depend.mk:
touch messages.h

View File

@ -21,8 +21,8 @@ class MessageType:
def format_args(self, template, separator = ', '):
return separator.join([template % (x,) for x in self.argnames])
with file("messages.json") as f:
spec = map(MessageType, json.load(f))
with file("../../protocol/messages.json") as f:
spec = map(MessageType, json.load(f)['definitions'])
def entrypoint_header():
print copyright_stmt

View File

@ -1,42 +0,0 @@
[
{
"selector": "create",
"args": ["classname", "arg", "reply-sink", "reply-name"]
},
{
"selector": "create-ok",
"args": ["info"]
},
{
"selector": "create-failed",
"args": ["reason"]
},
{
"selector": "subscribed",
"args": ["source", "filter", "sink", "name"]
},
{
"selector": "unsubscribed",
"args": ["source", "filter", "sink", "name"]
},
{
"selector": "post",
"args": ["name", "body", "token"]
},
{
"selector": "subscribe",
"args": ["filter", "sink", "name", "reply_sink", "reply_name"]
},
{
"selector": "subscribe-ok",
"args": ["token"]
},
{
"selector": "unsubscribe",
"args": ["token"]
},
{
"selector": "error",
"args": ["message", "details"]
}
]

View File

@ -1,93 +0,0 @@
/* Copyright (C) 2010, 2011 Tony Garnock-Jones. All rights reserved. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
int main(int argc, char *argv[]) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s;
FILE *f;
struct timeval start_time;
long bytecount = -1;
long last_report_bytecount = 0;
if (argc < 2) {
fprintf(stderr, "Usage: test1 <serverhostname>\n");
exit(1);
}
{
struct hostent *h = gethostbyname(argv[1]);
if (h == NULL) {
fprintf(stderr, "serverhostname lookup: %d\n", h_errno);
exit(1);
}
s.sin_family = AF_INET;
s.sin_addr.s_addr = * (uint32_t *) h->h_addr_list[0];
s.sin_port = htons(5671);
}
if (connect(fd, (struct sockaddr *) &s, sizeof(s)) < 0) return 1;
{
int i = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
}
f = fdopen(fd, "a+");
fprintf(f, "(9:subscribe5:test10:0:5:test15:login)(4:post7:factory(6:create5:queue(2:q1)5:test11:k)0:)(4:post2:q1(9:subscribe0:5:test18:consumer5:test11:k)0:)\n");
fflush(f);
#define MESSAGESIZE 65
while (1) {
char buf[1024];
size_t n = read(fd, buf, sizeof(buf));
if (n == 0) break;
if (n >= 16) {
if (!memcmp(buf, "(4:post8:consumer", 16)) {
if (bytecount == -1) {
printf("Buffer at start: <<%.*s>>\n", (int) n, buf);
printf("Starting.\n");
bytecount = 0;
gettimeofday(&start_time, NULL);
}
}
}
if (bytecount >= 0) {
bytecount += n;
if ((bytecount - last_report_bytecount) > (100000 * MESSAGESIZE)) {
struct timeval now;
double delta;
gettimeofday(&now, NULL);
delta = (now.tv_sec - start_time.tv_sec) + (now.tv_usec - start_time.tv_usec) / 1000000.0;
printf("So far received %ld bytes in %g seconds = %g bytes/sec and %g msgs/sec\n",
bytecount,
delta,
bytecount / delta,
bytecount / (delta * MESSAGESIZE));
fflush(stdout);
last_report_bytecount = bytecount;
}
}
}
return 0;
}

View File

@ -1,150 +0,0 @@
/* Copyright (C) 2010, 2011 Tony Garnock-Jones. All rights reserved. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
#define EXPECTEDPREFIX "(4:post8:consumer8:"
static size_t hunt_for_latencies_in(char *buf, size_t count) {
struct timeval now;
char *pos = buf;
char *sentinel = buf + count;
size_t msgsize = 0;
gettimeofday(&now, NULL);
while (1) {
char *openptr = memchr(pos, '(', sentinel - pos);
char *closeptr;
uint32_t s, us;
if (openptr == NULL) break;
closeptr = memchr(openptr + 1, ')', sentinel - (openptr + 1));
if (closeptr == NULL) break;
memcpy(&s, openptr + strlen(EXPECTEDPREFIX), sizeof(uint32_t));
memcpy(&us, openptr + strlen(EXPECTEDPREFIX) + sizeof(uint32_t), sizeof(uint32_t));
s = ntohl(s);
us = ntohl(us);
if (s != 0 || us != 0) {
double delta = (now.tv_sec - s) * 1000000.0 + (now.tv_usec - us);
printf("Latency %g microseconds (%g milliseconds)\n", delta, delta / 1000.0);
}
msgsize = closeptr + 1 - openptr;
pos = closeptr + 1;
}
return msgsize;
}
int main(int argc, char *argv[]) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s;
FILE *f;
struct timeval start_time;
long bytecount = -1;
size_t message_size = 0;
long last_report_bytecount = 0;
char idchar = '1';
char *qclass = "queue";
if (argc < 2) {
fprintf(stderr, "Usage: test1 <serverhostname> [<idchar> [<qclass>]]\n");
exit(1);
}
if (argc > 2) {
idchar = argv[2][0];
}
printf("Idchar: '%c'\n", idchar);
if (argc > 3) {
qclass = argv[3];
}
printf("Qclass: %s\n", qclass);
{
struct hostent *h = gethostbyname(argv[1]);
if (h == NULL) {
fprintf(stderr, "serverhostname lookup: %d\n", h_errno);
exit(1);
}
s.sin_family = AF_INET;
s.sin_addr.s_addr = * (uint32_t *) h->h_addr_list[0];
s.sin_port = htons(5671);
}
if (connect(fd, (struct sockaddr *) &s, sizeof(s)) < 0) return 1;
{
int i = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
}
f = fdopen(fd, "a+");
fprintf(f, "(9:subscribe5:test%c0:0:5:test%c5:login)(4:post7:factory(6:create%d:%s(2:q1)5:test%c1:k)0:)(4:post2:q1(9:subscribe0:5:test%c8:consumer5:test%c1:k)0:)\n",
idchar, idchar, (int) strlen(qclass), qclass, idchar, idchar, idchar);
fflush(f);
while (1) {
char buf[1024];
size_t n = read(fd, buf, sizeof(buf));
if (n == 0) break;
if (n >= strlen(EXPECTEDPREFIX)) {
if (!memcmp(buf, EXPECTEDPREFIX, strlen(EXPECTEDPREFIX))) {
if (bytecount == -1) {
printf("Buffer at start: <<%.*s>>\n", (int) n, buf);
printf("Starting.\n");
bytecount = 0;
gettimeofday(&start_time, NULL);
}
}
}
if (bytecount >= 0) {
size_t detected_msgsize = hunt_for_latencies_in(buf, n);
bytecount += n;
if (detected_msgsize != 0 && message_size == 0) {
message_size = detected_msgsize;
printf("message_size = %lu\n", message_size);
}
if (message_size != 0) {
if ((bytecount - last_report_bytecount) > (100000 * message_size)) {
struct timeval now;
double delta;
gettimeofday(&now, NULL);
delta = (now.tv_sec - start_time.tv_sec) + (now.tv_usec - start_time.tv_usec) / 1000000.0;
printf("So far received %ld bytes in %g seconds = %g bytes/sec and %g msgs/sec\n",
bytecount,
delta,
bytecount / delta,
bytecount / (delta * message_size));
fflush(stdout);
last_report_bytecount = bytecount;
}
}
}
}
return 0;
}

View File

@ -1,92 +0,0 @@
/* Copyright (C) 2010, 2011 Tony Garnock-Jones. All rights reserved. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
int main(int argc, char *argv[]) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s;
FILE *f;
struct timeval start_time;
long bytecount = 0;
char const *msg = "(4:post2:q1(4:post0:6:XXXXXX0:)0:)";
size_t msglen = strlen(msg);
int i;
if (argc < 2) {
fprintf(stderr, "Usage: test1 <serverhostname>\n");
exit(1);
}
{
struct hostent *h = gethostbyname(argv[1]);
if (h == NULL) {
fprintf(stderr, "serverhostname lookup: %d\n", h_errno);
exit(1);
}
s.sin_family = AF_INET;
s.sin_addr.s_addr = * (uint32_t *) h->h_addr_list[0];
s.sin_port = htons(5671);
}
if (connect(fd, (struct sockaddr *) &s, sizeof(s)) < 0) return 1;
{
int i = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
}
f = fdopen(fd, "a+");
fprintf(f, "(9:subscribe5:test30:0:5:test35:login)");
fflush(f);
usleep(100000);
{
char buf[4096];
size_t n = read(fd, buf, sizeof(buf));
printf("Received: <<%.*s>>\n", (int) n, buf);
}
gettimeofday(&start_time, NULL);
for (i = 0; i < 10000000; i++) {
fwrite(msg, msglen, 1, f);
bytecount += msglen;
if ((bytecount % 100000) < msglen) {
struct timeval now;
double delta;
gettimeofday(&now, NULL);
delta = (now.tv_sec - start_time.tv_sec) + (now.tv_usec - start_time.tv_usec) / 1000000.0;
printf("So far sent %ld bytes in %g seconds = %g bytes/sec and %g msgs/sec\n",
bytecount,
delta,
bytecount / delta,
bytecount / (delta * msglen));
fflush(stdout);
}
}
fprintf(f, "(11:unsubscribe5:test3)");
fflush(f);
fclose(f);
return 0;
}

View File

@ -1,149 +0,0 @@
/* Copyright (C) 2010, 2011 Tony Garnock-Jones. All rights reserved. */
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <assert.h>
static size_t build_message(char *message, uint32_t s, uint32_t us) {
char const *msg_prefix = "(4:post2:q1(4:post0:8:";
char const *msg_suffix = "0:)0:)";
size_t prefix_len = strlen(msg_prefix);
size_t suffix_len = strlen(msg_suffix);
uint32_t v;
size_t total_len = 0;
memcpy(message + total_len, msg_prefix, prefix_len);
total_len += prefix_len;
v = htonl(s);
memcpy(message + total_len, &v, sizeof(uint32_t));
total_len += sizeof(uint32_t);
v = htonl(us);
memcpy(message + total_len, &v, sizeof(uint32_t));
total_len += sizeof(uint32_t);
memcpy(message + total_len, msg_suffix, suffix_len);
total_len += suffix_len;
/*
printf("%d<<", total_len);
fwrite(message, total_len, 1, stdout);
printf(">>\n");
*/
return total_len;
}
int main(int argc, char *argv[]) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s;
FILE *f;
struct timeval start_time;
long bytecount = 0;
int i;
unsigned long hz_limit = 1000000;
unsigned long msgcount = 10000000;
assert(sizeof(uint32_t) == 4);
if (argc < 2) {
fprintf(stderr, "Usage: test1 <serverhostname> [<hz_limit> [<msgcount>]]\n");
exit(1);
}
if (argc > 2) {
hz_limit = strtoul(argv[2], NULL, 0);
}
printf("hz_limit = %lu\n", hz_limit);
if (argc > 3) {
msgcount = strtoul(argv[3], NULL, 0);
}
printf("msgcount = %lu\n", msgcount);
{
struct hostent *h = gethostbyname(argv[1]);
if (h == NULL) {
fprintf(stderr, "serverhostname lookup: %d\n", h_errno);
exit(1);
}
s.sin_family = AF_INET;
s.sin_addr.s_addr = * (uint32_t *) h->h_addr_list[0];
s.sin_port = htons(5671);
}
if (connect(fd, (struct sockaddr *) &s, sizeof(s)) < 0) return 1;
{
int i = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i));
}
f = fdopen(fd, "a+");
fprintf(f, "(9:subscribe5:test30:0:5:test35:login)");
fflush(f);
usleep(100000);
{
char buf[4096];
size_t n = read(fd, buf, sizeof(buf));
printf("Received: <<%.*s>>\n", (int) n, buf);
}
gettimeofday(&start_time, NULL);
for (i = 0; i < msgcount; i++) {
char message[1024];
size_t msglen;
while (1) {
struct timeval now;
double delta;
gettimeofday(&now, NULL);
delta = (now.tv_sec - start_time.tv_sec) + (now.tv_usec - start_time.tv_usec) / 1000000.0;
if (i / delta <= hz_limit) break;
fflush(f);
usleep(1000);
}
if ((i % (hz_limit / 4)) == 0) {
struct timeval now;
gettimeofday(&now, NULL);
msglen = build_message(message, now.tv_sec, now.tv_usec);
} else {
msglen = build_message(message, 0, 0);
}
fwrite(message, msglen, 1, f);
bytecount += msglen;
if ((bytecount % 100000) < msglen) {
struct timeval now;
double delta;
gettimeofday(&now, NULL);
delta = (now.tv_sec - start_time.tv_sec) + (now.tv_usec - start_time.tv_usec) / 1000000.0;
printf("So far sent %ld bytes in %g seconds = %g bytes/sec and %g msgs/sec\n",
bytecount,
delta,
bytecount / delta,
bytecount / (delta * msglen));
fflush(stdout);
}
}
fprintf(f, "(11:unsubscribe5:test3)");
fflush(f);
fclose(f);
return 0;
}

View File

@ -1,229 +0,0 @@
import xml.dom.minidom
def constify(s):
s = s.replace('-', '_')
s = s.replace(' ', '_')
s = s.upper()
return s
def cify(s):
s = constify(s)
s = s.lower()
return s
def camelify(s):
s = constify(s)
s = s.split('_')
s = [s[0].lower()] + [w.capitalize() for w in s[1:]]
s = ''.join(s)
return s
ctypemap = {
'shortstr': 'cmsg_bytes_t',
'longstr': 'cmsg_bytes_t',
'table': 'cmsg_bytes_t', # TODO fix
'octet': 'uint8_t',
'short': 'uint16_t',
'long': 'uint32_t',
'longlong': 'uint64_t',
'bit': 'uint8_t',
'timestamp': 'uint64_t',
}
class Constant:
def __init__(self, e):
self.name = e.getAttribute('name')
self.value = e.getAttribute('value')
self.class_ = e.getAttribute('class') or None
def getName(self):
if self.class_:
return 'CMSG_AMQP_ERROR_' + constify(self.name)
else:
return 'CMSG_AMQP_' + constify(self.name)
def getValue(self):
return self.value
class Field:
def __init__(self, e):
self.name = e.getAttribute('name')
self.domain = e.getAttribute('domain') or e.getAttribute('type')
# self.reserved = bool(e.getAttribute('reserved'))
self.type = resolveDomain(self.domain)
def getName(self):
return cify(self.name)
def ctype(self):
return ctypemap[str(self.type)]
class Entity:
def __init__(self, parent, e):
self.parent = parent
self.name = e.getAttribute('name')
self.index = int(e.getAttribute('index'))
self.fields = [Field(ee) \
for ee in e.getElementsByTagName('field') \
if ee.parentNode is e]
def getName(self):
if self.parent:
return self.parent.getName() + '_' + cify(self.name)
else:
return cify(self.name)
def printStructDefExtras(self):
pass
def printStructDef(self, suffix):
if self.fields:
print
print 'typedef struct cmsg_amqp_%s_%s_t_ {' % (self.getName(), suffix)
self.printStructDefExtras()
for f in self.fields:
print ' %s %s;' % (f.ctype(), f.getName())
print '} cmsg_amqp_%s_%s_t;' % (self.getName(), suffix)
class BitWriter:
def __init__(self):
self.bit_offset = 0
def flush(self):
if self.bit_offset:
print ' write_amqp_octet(bit_buffer);'
self.bit_offset = 0
def emit(self, valueExpr):
if self.bit_offset == 0:
print ' bit_buffer = 0;'
print ' if (%s) bit_buffer |= 0x%02x;' % (valueExpr, 1 << self.bit_offset)
self.bit_offset += 1
if self.bit_offset == 8:
self.flush()
class Method(Entity):
def __init__(self, parent, e):
Entity.__init__(self, parent, e)
self.has_content = bool(e.getAttribute('content'))
self.synchronous = bool(e.getAttribute('synchronous'))
self.responses = [ee.getAttribute('name') for ee in e.getElementsByTagName('response')]
def methodId(self):
return self.parent.index << 16 | self.index
def printParseClause(self):
bit_offset = 0
print ' case 0x%08x: /* %s */ ' % (self.methodId(), self.getName())
for f in self.fields:
if f.type == 'bit':
if bit_offset == 0:
print ' if (!parse_amqp_octet(&bit_buffer, &input, &offset))'
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
print ' output->body.%s.%s = (bit_buffer & 0x%02x) != 0;' % \
(self.getName(), f.getName(), 1 << bit_offset)
bit_offset += 1
if bit_offset == 8: bit_offset = 0
else:
print ' if (!parse_amqp_%s(&output->body.%s.%s, &input, &offset))' % \
(f.type, self.getName(), f.getName())
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
print ' return 0;'
def printWriteClause(self):
bw = BitWriter()
print ' case 0x%08x: /* %s */ ' % (self.methodId(), self.getName())
for f in self.fields:
if f.type == 'bit':
bw.emit('output->body.%s.%s' % (self.getName(), f.getName()))
else:
bw.flush()
print ' write_amqp_%s(output->body.%s.%s);' % \
(f.type, self.getName(), f.getName())
bw.flush()
print ' break;'
class Class(Entity):
def __init__(self, e):
Entity.__init__(self, None, e)
self.methods = [Method(self, ee) for ee in e.getElementsByTagName('method')]
def printStructDefExtras(self):
print ' uint32_t _flags;'
def resolveDomain(n):
while n in domainmap and domainmap[n] != n:
n = domainmap[n]
return n
specxml = xml.dom.minidom.parse("amqp0-9-1.stripped.xml")
constants = [Constant(e) for e in specxml.getElementsByTagName('constant')]
domainmap = dict((e.getAttribute('name'), e.getAttribute('type')) \
for e in specxml.getElementsByTagName('domain'))
classes = [Class(e) for e in specxml.getElementsByTagName('class')]
classmap = dict((c.name, c) for c in classes)
def header():
print '/* TODO: put copyright etc */'
print '/* Generated from AMQP spec version %s.%s.%s */' % \
(specxml.documentElement.getAttribute('major'),
specxml.documentElement.getAttribute('minor'),
specxml.documentElement.getAttribute('revision'))
print
for c in constants:
print '#define %s %s' % (c.getName(), c.getValue())
for c in classes:
c.printStructDef('properties')
for c in classes:
for m in c.methods:
m.printStructDef('method')
print
print 'typedef struct cmsg_amqp_method_t_ {'
print ' uint32_t id;'
print ' union {'
for c in classes:
for m in c.methods:
if m.fields:
print ' cmsg_amqp_%s_method_t %s;' % (m.getName(), m.getName())
print ' } body;'
print '} cmsg_amqp_method_t;'
print
print 'int parse_amqp_method('
print ' cmsg_bytes_t input,'
print ' cmsg_amqp_method_t *output) {'
print ' size_t offset = 0;'
print ' uint8_t bit_buffer = 0;'
print ' if (!parse_amqp_long(&output->id, &input, &offset))'
print ' return -CMSG_AMQP_ERROR_FRAME_ERROR;'
print ' switch (output->id) {'
for c in classes:
for m in c.methods:
m.printParseClause()
print ' default:'
print ' warn("Invalid AMQP method number 0x%%08x", output->id);'
print ' return -CMSG_AMQP_ERROR_NOT_IMPLEMENTED;'
print ' }'
print '}'
print
print 'void write_amqp_method('
print ' IOHandle *h,'
print ' cmsg_amqp_method_t *m) {'
print ' uint8_t bit_buffer = 0;'
print ' write_amqp_long(&m->id);'
print ' switch (m->id) {'
for c in classes:
for m in c.methods:
m.printWriteClause()
print ' default:'
print ' die("Invalid AMQP method number 0x%%08x", m->id);'
print ' }'
print '}'
header()