mirror of
https://github.com/protobuf-c/protobuf-c.git
synced 2024-12-28 14:48:18 +08:00
initial commit. this is NOT WORKING by a long shot.
git-svn-id: https://protobuf-c.googlecode.com/svn/trunk@104 00440858-1255-0410-a3e6-75ea37f81c3a
This commit is contained in:
parent
ddb111cab3
commit
27aed0b2ac
98
src/sctp-rpc/example-client.c
Normal file
98
src/sctp-rpc/example-client.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include "example-word-funcs-service.h"
|
||||
|
||||
static void
|
||||
word_closure_to_ptr_word (const Example__Word *message,
|
||||
void *closure_data)
|
||||
{
|
||||
const char *rv = message == NULL || message->word == NULL
|
||||
? "*error*" : message->word;
|
||||
* (char **) closure_data = strdup (rv);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
Example__WordFuncs_Service *service = NULL;
|
||||
const char *name = "word_funcs";
|
||||
const char *addr = NULL;
|
||||
|
||||
dispatch = protobuf_c_sctp_dispatch_new ();
|
||||
|
||||
/* Create service (either local or remote) */
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strcmp (argv[i], "--local") == 0)
|
||||
{
|
||||
example_word_funcs_service_init ();
|
||||
service = example_word_funcs_service;
|
||||
name = "<local word_funcs>";
|
||||
}
|
||||
else if (strncmp (argv[i], "--addr=", 7) == 0)
|
||||
addr = argv[i] + 7;
|
||||
else if (strncmp (argv[i], "--name=", 7) == 0)
|
||||
name = argv[i] + 7;
|
||||
else
|
||||
usage (argv[0]);
|
||||
}
|
||||
if (service == NULL && addr == NULL)
|
||||
die ("missing --addr=");
|
||||
if (service == NULL && addr != NULL)
|
||||
{
|
||||
channel = protobuf_c_sctp_channel_ipv4_connect_by_hostport (addr, dispatch);
|
||||
service = protobuf_c_sctp_channel_add_remote_service (channel,
|
||||
name,
|
||||
&example__word_funcs__descriptor);
|
||||
}
|
||||
|
||||
/* main loop: invoke service methods (either local or remote) */
|
||||
for (;;)
|
||||
{
|
||||
fprintf (stderr, "%s >> ", name);
|
||||
if (fgets (buf, sizeof (buf), stdin) == NULL)
|
||||
break;
|
||||
/* parse command */
|
||||
at = buf;
|
||||
while (*at && isspace (*at))
|
||||
at++;
|
||||
if (*at == 0)
|
||||
continue;
|
||||
cmd = at;
|
||||
while (*at && !isspace (*at))
|
||||
at++;
|
||||
if (*at != 0)
|
||||
{
|
||||
*at++ = 0;
|
||||
while (*at && *isspace (*at))
|
||||
at++;
|
||||
}
|
||||
|
||||
if (strcmp (cmd, "uppercase") == 0
|
||||
|| strcmp (cmd, "lowercase") == 0)
|
||||
{
|
||||
/* functions mapping string => string can be handled via this
|
||||
mechanism */
|
||||
char *rv = NULL;
|
||||
Example__Word input = EXAMPLE__WORD__INIT;
|
||||
input.word = at;
|
||||
if (strcmp (cmd, "uppercase") == 0)
|
||||
example__word_funcs__uppercase (service,
|
||||
&input,
|
||||
word_closure_to_ptr_word,
|
||||
&rv);
|
||||
else if (strcmp (cmd, "lowercase") == 0)
|
||||
example__word_funcs__lowercase (service,
|
||||
&input,
|
||||
word_closure_to_ptr_word,
|
||||
&rv);
|
||||
else
|
||||
assert (0);
|
||||
while (rv == NULL)
|
||||
protobuf_c_sctp_dispatch_run (dispatch);
|
||||
|
||||
printf ("%s\n", rv);
|
||||
fflush (stdout);
|
||||
free (rv);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
33
src/sctp-rpc/example-server-2.c
Normal file
33
src/sctp-rpc/example-server-2.c
Normal file
@ -0,0 +1,33 @@
|
||||
#include "protobuf-c-sctp.h"
|
||||
|
||||
void usage (const char *prog_name)
|
||||
{
|
||||
die ("usage: %s --port=PORT [--name=NAME]\n"
|
||||
"Run an example word-funcs service.\n", prog_name);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int port = 0;
|
||||
ProtobufC_SCTP_LocalService local_services[1] = { { "word_funcs", NULL } };
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strncmp (argv[i], "--port=", 7) == 0)
|
||||
port = atoi (argv[i] + 7);
|
||||
else if (strncmp (argv[i], "--name=", 7) == 0)
|
||||
local_services[0].name = argv[i] + 7;
|
||||
else
|
||||
usage (argv[0]);
|
||||
}
|
||||
if (port == 0)
|
||||
die ("--port=PORT is required");
|
||||
|
||||
/* initialize our our actual service implementation */
|
||||
example_word_funcs_service_init ();
|
||||
local_services[0].service = example_word_funcs_service;
|
||||
|
||||
/* run the server */
|
||||
protobuf_c_sctp_server_run (1, local_services, 0, NULL, port);
|
||||
|
||||
return 0;
|
||||
}
|
60
src/sctp-rpc/example-server.c
Normal file
60
src/sctp-rpc/example-server.c
Normal file
@ -0,0 +1,60 @@
|
||||
#include "protobuf-c-sctp.h"
|
||||
|
||||
typedef struct _StringFuncsImpl StringFuncsImpl;
|
||||
struct _StringFuncsImpl
|
||||
{
|
||||
Example__WordFuncs_Service base_service;
|
||||
};
|
||||
|
||||
void usage (const char *prog_name)
|
||||
{
|
||||
die ("usage: %s --port=PORT [--name=NAME]\n"
|
||||
"Run an example word-funcs service.\n", prog_name);
|
||||
}
|
||||
|
||||
typedef struct _ChannelConfigData ChannelConfigData;
|
||||
struct _ChannelConfigData
|
||||
{
|
||||
const char *name;
|
||||
ProtobufCService *service;
|
||||
};
|
||||
|
||||
/* Set up newly-accepted connection */
|
||||
static void
|
||||
init_channel (ProtobufC_SCTP_Channel *channel,
|
||||
void *data)
|
||||
{
|
||||
ChannelConfigData *config = data;
|
||||
protobuf_c_sctp_channel_add_local_service (channel,
|
||||
config->name,
|
||||
config->service);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int port = 0;
|
||||
StringFuncsImpl impl;
|
||||
ChannelConfigData config = { "word_funcs", &impl.base_service.base };
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
if (strncmp (argv[i], "--port=", 7) == 0)
|
||||
port = atoi (argv[i] + 7);
|
||||
else if (strncmp (argv[i], "--name=", 7) == 0)
|
||||
config.name = argv[i] + 7;
|
||||
else
|
||||
usage (argv[0]);
|
||||
}
|
||||
if (port == 0)
|
||||
die ("--port=PORT is required");
|
||||
|
||||
/* initialize our our actual service implementation */
|
||||
example__word_funcs__init (&impl.base_service);
|
||||
impl.base_service.uppercase = implement_uppercase;
|
||||
|
||||
listener = protobuf_c_sctp_listener_new_ipv4 (NULL, port, dispatch,
|
||||
init_channel, &config);
|
||||
for (;;)
|
||||
protobuf_c_sctp_dispatch_run (dispatch, -1);
|
||||
|
||||
return 0;
|
||||
}
|
61
src/sctp-rpc/example-word-funcs-service.c
Normal file
61
src/sctp-rpc/example-word-funcs-service.c
Normal file
@ -0,0 +1,61 @@
|
||||
#include "example-word-funcs-service.h"
|
||||
|
||||
/* note: the implementations here only handle ascii characters--
|
||||
this is a tutorial about RPC,
|
||||
not utf8 encoding or unicode normalization */
|
||||
|
||||
Example__WordFuncs_Service *example_word_funcs_service;
|
||||
|
||||
static Example__WordFuncs_Service word_funcs_service;
|
||||
|
||||
static void
|
||||
implement_uppercase (Example__WordFuncs_Service *service,
|
||||
const Example__Word *input,
|
||||
Example__Word_Closure closure,
|
||||
void *closure_data)
|
||||
{
|
||||
char *rv = strdup (input->word);
|
||||
Example__Word output = EXAMPLE__WORD__INIT;
|
||||
char *at;
|
||||
for (at = rv; *at; at++)
|
||||
if ('a' <= *at && *at <= 'z')
|
||||
*at -= ('a' - 'A');
|
||||
output.word = rv;
|
||||
closure (&output, closure_data);
|
||||
free (rv);
|
||||
}
|
||||
|
||||
static void
|
||||
implement_lowercase (Example__WordFuncs_Service *service,
|
||||
const Example__Word *input,
|
||||
Example__Word_Closure closure,
|
||||
void *closure_data)
|
||||
{
|
||||
char *rv = strdup (input->word);
|
||||
Example__Word output = EXAMPLE__WORD__INIT;
|
||||
char *at;
|
||||
for (at = rv; *at; at++)
|
||||
if ('A' <= *at && *at <= 'Z')
|
||||
*at += ('a' - 'A');
|
||||
output.word = rv;
|
||||
closure (&output, closure_data);
|
||||
free (rv);
|
||||
}
|
||||
|
||||
#if 0 /* you could consider an init function like this instead */
|
||||
void example_word_funcs_service_init (void)
|
||||
{
|
||||
example_word_funcs_service = &word_funcs_service;
|
||||
example__word_funcs__init (&word_funcs_service);
|
||||
word_funcs_service.uppercase = implement_uppercase;
|
||||
word_funcs_service.lowercase = implement_lowercase;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO: provide a c99 example */
|
||||
Example__WordFuncs_Service example__word_funcs__service__global =
|
||||
{
|
||||
EXAMPLE__WORD_FUNCS__SERVICE__BASE_INIT,
|
||||
implement_uppercase,
|
||||
implement_lowercase
|
||||
};
|
8
src/sctp-rpc/example-word-funcs-service.h
Normal file
8
src/sctp-rpc/example-word-funcs-service.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include "generated/example.pb-c.h"
|
||||
|
||||
extern Example__WordFuncs_Service example__word_funcs__service__global;
|
||||
|
||||
/* extern ProtobufCService *example__word_funcs__service; */
|
||||
#define example__word_funcs__service \
|
||||
((ProtobufCService *) (&example__word_funcs__service__global))
|
||||
|
11
src/sctp-rpc/example.proto
Normal file
11
src/sctp-rpc/example.proto
Normal file
@ -0,0 +1,11 @@
|
||||
package example;
|
||||
|
||||
message Word
|
||||
{
|
||||
required string word = 1;
|
||||
};
|
||||
|
||||
service WordFuncs {
|
||||
rpc Uppercase (Word) returns (Word);
|
||||
rpc Lowercase (Word) returns (Word);
|
||||
}
|
65
src/sctp-rpc/protobuf-c-sctp.h
Normal file
65
src/sctp-rpc/protobuf-c-sctp.h
Normal file
@ -0,0 +1,65 @@
|
||||
#include "../google/protobuf-c/protobuf-c.h"
|
||||
|
||||
typedef struct _ProtobufC_SCTP_Dispatch ProtobufC_SCTP_Dispatch;
|
||||
typedef struct _ProtobufC_SCTP_Channel ProtobufC_SCTP_Channel;
|
||||
typedef struct _ProtobufC_SCTP_Listener ProtobufC_SCTP_Listener;
|
||||
|
||||
/* For servers and clients, you can get at the array of
|
||||
remote service objects from the closure-data of your local-service's
|
||||
invocation method. */
|
||||
ProtobufCService **
|
||||
protobuf_c_sctp_closure_data_get_remote_services (void *closure_data);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
ProtobufCService *service;
|
||||
} ProtobufC_SCTP_LocalService;
|
||||
typedef struct {
|
||||
const char *name;
|
||||
ProtobufCServiceDescriptor *descriptor;
|
||||
} ProtobufC_SCTP_RemoteService;
|
||||
|
||||
ProtobufC_SCTP_Config *
|
||||
protobuf_c_sctp_config_new (size_t n_local_services,
|
||||
ProtobufC_SCTP_LocalService *local_services,
|
||||
size_t n_remote_services,
|
||||
ProtobufC_SCTP_RemoteService *remote_services);
|
||||
|
||||
/* a channel: an sctp association (technically sctp allows multiple
|
||||
streams within a single association (unlike tcp), but we do not
|
||||
use that ability. when created as a client, this does automatic
|
||||
reconnecting. */
|
||||
ProtobufC_SCTP_Channel *
|
||||
protobuf_c_sctp_client_new_ipv4(const uint8_t *addr,
|
||||
uint16_t port,
|
||||
ProtobufC_SCTP_Config *config,
|
||||
ProtobufC_Dispatch *dispatch);
|
||||
ProtobufC_SCTP_Channel *
|
||||
protobuf_c_sctp_client_new_ipv4_dns (const char *host,
|
||||
uint16_t port,
|
||||
ProtobufC_SCTP_Config *config,
|
||||
ProtobufC_Dispatch *dispatch);
|
||||
ProtobufC_SCTP_Channel *
|
||||
protobuf_c_sctp_client_new_ipv4_hostport(const char *host_port,
|
||||
ProtobufC_SCTP_Config *config,
|
||||
ProtobufC_SCTP_Dispatch *dispatch);
|
||||
void protobuf_c_sctp_channel_set_error_handler (ProtobufC_SCTP_Channel *channel,
|
||||
ProtobufC_SCTP_ErrorFunc func,
|
||||
void *data,
|
||||
ProtobufC_SCTP_Destroy destroy);
|
||||
ProtobufCService *
|
||||
protobuf_c_sctp_channel_peek_remote_service(ProtobufC_SCTP_Channel *channel,
|
||||
unsigned index);
|
||||
void protobuf_c_sctp_channel_shutdown (ProtobufC_SCTP_Channel *channel);
|
||||
void protobuf_c_sctp_channel_destroy (ProtobufC_SCTP_Channel *channel);
|
||||
|
||||
|
||||
|
||||
/* a listener: a passive sctp socket awaiting new connections */
|
||||
ProtobufC_SCTP_Server *
|
||||
protobuf_c_sctp_server_new_ipv4 (const uint8_t *bind_addr,
|
||||
uint16_t port,
|
||||
ProtobufC_SCTP_Config *config);
|
||||
void protobuf_c_sctp_server_destroy (ProtobufC_SCTP_Server *server);
|
||||
|
||||
|
12
src/sctp-rpc/render-rfc
Executable file
12
src/sctp-rpc/render-rfc
Executable file
@ -0,0 +1,12 @@
|
||||
#! /bin/sh
|
||||
|
||||
nroff -t -ms rfc-protobuf-sctp.ms |
|
||||
perl -e '
|
||||
undef $/; # Read whole files in a single gulp.
|
||||
while (<>) { # Read the entire input file.
|
||||
s/FORMFEED(\[Page\s+\d+\])\s+/ \1\n\f\n/sg;
|
||||
s/\f\n$//; # Want no formfeed at end?
|
||||
print; # Print the resultant file.
|
||||
}' > rfc-protobuf-sctp.txt
|
||||
|
||||
groff -t -ms rfc-protobuf-sctp.ms > rfc-protobuf-sctp.ps
|
371
src/sctp-rpc/rfc-protobuf-sctp.ms
Normal file
371
src/sctp-rpc/rfc-protobuf-sctp.ms
Normal file
@ -0,0 +1,371 @@
|
||||
.pl 10.0i
|
||||
.po 0
|
||||
.ll 7.2i
|
||||
.lt 7.2i
|
||||
.nr LL 7.2i
|
||||
.nr LT 7.2i
|
||||
.ds LF Benson
|
||||
.ds RF FORMFEED[Page %]
|
||||
.ds CF
|
||||
.ds LH PROPOSAL
|
||||
.ds RH 7 December 2008
|
||||
.ds CH Protobuf over SCTP
|
||||
.hy 0
|
||||
.ad l
|
||||
.in 0
|
||||
.ce
|
||||
Proposal for Implementing Protocol-Buffer RPC over SCTP
|
||||
|
||||
.ti 0
|
||||
Status of this Memo
|
||||
|
||||
.fi
|
||||
.in 3
|
||||
This memo describes a proposed method for the encapsulation of
|
||||
Protocol-Buffer Datagrams via the Stream Control Transmission Protocol.
|
||||
This is an experimental, not recommended standard.
|
||||
Distribution of this memo is unlimited.
|
||||
|
||||
.ti 0
|
||||
Overview and Rationale
|
||||
|
||||
Google's Protobuf Buffer package (or "protobuf", for short)
|
||||
provides a language for
|
||||
specifying the format binary-data. In that language, a "message"
|
||||
in that language defines a specific binary-data format.
|
||||
The language also defines a "service": a service has
|
||||
an array of named "methods", each of which takes a specific
|
||||
type of message as input, and gives a specific
|
||||
type of message as output.
|
||||
|
||||
SCTP is a reliable datagram-oriented protocol,
|
||||
parallel to UDP or TCP, and riding atop the IP layer
|
||||
(either IPv4 or IPv6).
|
||||
|
||||
Protocol-Buffer RPC over SCTP (or protobuf-sctp for short),
|
||||
defines a way of implementing RPCs to one of a set of named services.
|
||||
|
||||
The general inplementation of the server and client
|
||||
is very similar, since both the server and client can
|
||||
implement local services and invoke remote services.
|
||||
Usually, a server provides a local service and the client
|
||||
accesses it, but we provide a more symmetric model.
|
||||
|
||||
.ti 0
|
||||
Why Services and not Messages?
|
||||
|
||||
One possible alternate scheme for using protobuf is to encapsulate messages
|
||||
without any regard to the request/response cycle.
|
||||
This could be quite beneficial at times, especially when the RPC does not
|
||||
need to get a response message. Despite the possibility of eliminating
|
||||
many round-trips, we do not offer any protocol but the rpc-method technique.
|
||||
|
||||
Services are the fundamental unit of RPC in protocol buffers,
|
||||
so it makes sense to use them as the basis of a protocol.
|
||||
It is possible that a string name is not the most efficient way
|
||||
to identify the service, but many languages are well-optimized
|
||||
for string handling, so it's unclear if base-128 encoding is really
|
||||
better. In any event, strings are sent on every request for both
|
||||
the name of the service, and the name of the method.
|
||||
|
||||
.ti 0
|
||||
Why SCTP and not a generalized reliable datagram layer?
|
||||
|
||||
In principle, this specification could be generalized
|
||||
to cover any reliable datagram passing mechanism.
|
||||
We chose to limit our attention to SCTP for
|
||||
the following reasons:
|
||||
.IP
|
||||
.RS
|
||||
.IP *
|
||||
We can analyze the performance of our design choices.
|
||||
.RE
|
||||
.RS
|
||||
.IP *
|
||||
SCTP boasts a rich set of features, like the ability to
|
||||
specify ordered or unordered delivery.
|
||||
.RE
|
||||
|
||||
.ti 0
|
||||
Definitions
|
||||
|
||||
.KS
|
||||
.IP
|
||||
Datagram
|
||||
.RS
|
||||
.IP
|
||||
a piece of binary-data, an array of bytes.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.IP
|
||||
SCTP Connection
|
||||
.RS
|
||||
.IP
|
||||
a single stream of datagrams.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.IP
|
||||
Handshake
|
||||
.RS
|
||||
.IP
|
||||
the sequence of datagrams to establish client/server validity.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.IP
|
||||
Uninitialized Connection
|
||||
.RS
|
||||
.IP
|
||||
an SCTP connection before the handshake has completed.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.IP
|
||||
Request ID
|
||||
.RS
|
||||
.IP
|
||||
a 64-bit number allocated by the end that begins an RPC request.
|
||||
It is recommend that the allocation strategy simply use an incrementing 64-bit
|
||||
counter.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.IP
|
||||
Datagram Type
|
||||
.RS
|
||||
.IP
|
||||
is a single byte that is the first byte in every message.
|
||||
It can be used to distinguish the type of message.
|
||||
.RE
|
||||
.KE
|
||||
|
||||
.ti 0
|
||||
Overview of the Protocol
|
||||
|
||||
The session always begins with ordered delivery of three
|
||||
messages, the handshake. Only after the handshake is completed
|
||||
may unordered messages be sent.
|
||||
|
||||
For each remote-procedure call, the caller must allocate a request_id.
|
||||
The request_id is necessary because we want
|
||||
to support unordered delivery and because we would like to support
|
||||
concurrent backend service invocations.
|
||||
|
||||
.ti 0
|
||||
Initial handshake
|
||||
|
||||
The first packet is sent by the client,
|
||||
the active end of the connection.
|
||||
|
||||
.KS
|
||||
.TS
|
||||
tab(:);
|
||||
l s
|
||||
| c | c |
|
||||
| l | l | .
|
||||
HANDSHAKE_REQUEST
|
||||
=
|
||||
format:name
|
||||
_
|
||||
byte:datagram_type (HANDSHAKE_REQUEST=1)
|
||||
HandshakeRequest:request
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
|
||||
The HandshakeRequest message format is defined
|
||||
by the following protobuf file fragment:
|
||||
.DS L
|
||||
message HandshakeService
|
||||
{
|
||||
required string name = 1;
|
||||
optional string service_type_name = 2;
|
||||
}
|
||||
message HandshakeRequest
|
||||
{
|
||||
// lists the services provided by the client to the server
|
||||
repeated HandshakeService services = 1;
|
||||
}
|
||||
.DE
|
||||
|
||||
Once the request has been received,
|
||||
the server should respond with a message
|
||||
.KS
|
||||
.TS
|
||||
tab(:);
|
||||
l s
|
||||
| c | c |
|
||||
| l | l | .
|
||||
HANDSHAKE_RESPONSE
|
||||
=
|
||||
format:name
|
||||
_
|
||||
byte:datagram_type (HANDSHAKE_RESPONSE=2)
|
||||
HandshakeResponse:request
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
where HandshakeResponse is defined by the
|
||||
following fragment, which uses the definition of
|
||||
HandshakeService above:
|
||||
.DS L
|
||||
message HandshakeResponse
|
||||
{
|
||||
// lists the services provided by the client to the server
|
||||
repeated HandshakeService services = 1;
|
||||
}
|
||||
.DE
|
||||
This message gives a list of services provided by the
|
||||
server (which can be called by the client).
|
||||
|
||||
Once the response has been received,
|
||||
the client should respond with the final handshake message:
|
||||
.KS
|
||||
.TS
|
||||
tab(:);
|
||||
l s
|
||||
| c | c |
|
||||
| l | l | .
|
||||
HANDSHAKE_COMPLETED
|
||||
=
|
||||
format:name
|
||||
_
|
||||
byte:datagram_type (HANDSHAKE_COMPLETED=3)
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
|
||||
As far as the client is concerned, the handshake is completed
|
||||
when it received the HandshakeRespond message;
|
||||
for the server, the handshake is completed slightly later:
|
||||
once the HandshakeCompleted message is received.
|
||||
|
||||
For pipelineing purposes, it is nice to be able to send
|
||||
requests before completing the handshake.
|
||||
But until the handshake is complete, all packets
|
||||
must be sent in ordered fashion, to ensure that the handshake
|
||||
is the first packet processed. (This is the point of the HandshakeCompleted
|
||||
message: to ensure that all sends will be ordered until
|
||||
the client has received the respond.)
|
||||
|
||||
|
||||
.ti 0
|
||||
The RPC Protocol
|
||||
|
||||
The format of a remote-procedure call (RPC) transaction
|
||||
is that a request is sent from the caller to
|
||||
the caller. Eventually, the called resource
|
||||
trasmits a response packet. The protocol specified here
|
||||
permits responses to be received out of order.
|
||||
|
||||
Out-of-order receipt is implemented by requiring the caller
|
||||
(or, more precisely, its RPC implementation)
|
||||
to allocate a request_id for each request.
|
||||
The caller which has multiple outstanding requests must then
|
||||
match the request id to the appropriate response.
|
||||
The caller may throw an error if a response with an invalid request_id
|
||||
is encountered.
|
||||
|
||||
The remaining sections will describe the wire-format of the messages
|
||||
sent for a request/response pair.
|
||||
|
||||
.ti 0
|
||||
Request Format
|
||||
|
||||
.KS
|
||||
.TS
|
||||
tab(:);
|
||||
l s
|
||||
| c | c |
|
||||
| l | l | .
|
||||
REQUEST
|
||||
=
|
||||
format:name
|
||||
_
|
||||
byte:datagram_type (REQUEST=4)
|
||||
uint64:request_id
|
||||
NUL-terminated string:service_name
|
||||
NUL-terminated string:method_name
|
||||
protobuf:request
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
|
||||
The format of "request" is specified by the service-definition.
|
||||
|
||||
.ti 0
|
||||
Response Format
|
||||
|
||||
.KS
|
||||
.TS
|
||||
tab(:);
|
||||
l s
|
||||
| c | c |
|
||||
| l | l | .
|
||||
RESPONSE
|
||||
=
|
||||
format:name
|
||||
_
|
||||
byte:datagram_type (RESPONSE=5)
|
||||
uint64:request_id
|
||||
protobuf:response
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
|
||||
|
||||
.ti 0
|
||||
Discussion
|
||||
|
||||
Multiple types of service can be provided with a prioritized pecking
|
||||
order. An additional property is built-in worm detection and
|
||||
eradication. Because IP only guarantees best effort delivery, loss of
|
||||
a carrier can be tolerated. With time, the carriers are
|
||||
self-regenerating. While broadcasting is not specified, storms can
|
||||
cause data loss. There is persistent delivery retry, until the
|
||||
carrier drops. Audit trails are automatically generated, and can
|
||||
often be found on logs and cable trays.
|
||||
|
||||
.ti 0
|
||||
Security Considerations
|
||||
|
||||
.in 3
|
||||
Messages are sent unencrypted, so this encapsulation cannot
|
||||
be used safely on the broader internet.
|
||||
|
||||
.KS
|
||||
.ti 0
|
||||
Author's Address
|
||||
|
||||
.nf
|
||||
David Benson
|
||||
|
||||
EMail: daveb@ffem.org
|
||||
.KE
|
||||
|
||||
.KS
|
||||
.ti 0
|
||||
Appendix: table of datagram types
|
||||
|
||||
.TS
|
||||
tab(:);
|
||||
c | c
|
||||
| l | l | .
|
||||
value:datagram type
|
||||
=
|
||||
1:HANDSHAKE_REQUEST
|
||||
2:HANDSHAKE_RESPONSE
|
||||
3:HANDSHAKE_COMPLETED
|
||||
4:REQUEST
|
||||
5:RESPONSE
|
||||
_
|
||||
.TE
|
||||
.KE
|
||||
|
8
src/sctp-rpc/sctp-channel.c
Normal file
8
src/sctp-rpc/sctp-channel.c
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
struct _ProtobufC_SCTP_Channel
|
||||
{
|
||||
int fd;
|
||||
protobuf_c_boolean is_passive; /* ie the server */
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user