mirror of
https://github.com/protobuf-c/protobuf-c.git
synced 2024-12-29 23:42:12 +08:00
188 lines
4.9 KiB
C
188 lines
4.9 KiB
C
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include "generated-code/test.pb-c.h"
|
|
#include <google/protobuf-c/protobuf-c-rpc.h>
|
|
|
|
static void
|
|
die (const char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start (args, format);
|
|
vfprintf (stderr, format, args);
|
|
va_end (args);
|
|
fprintf (stderr, "\n");
|
|
exit (1);
|
|
}
|
|
|
|
static void
|
|
usage (void)
|
|
{
|
|
die ("usage: example-client [--tcp=HOST:PORT | --unix=PATH]\n"
|
|
"\n"
|
|
"Run a protobuf client as specified by the DirLookup service\n"
|
|
"in the test.proto file in the protobuf-c distribution.\n"
|
|
"\n"
|
|
"Options:\n"
|
|
" --tcp=HOST:PORT Port to listen on for RPC clients.\n"
|
|
" --unix=PATH Unix-domain socket to listen on.\n"
|
|
" --autoreconnect=MILLIS Try to reconnect to the client if it fails.\n"
|
|
);
|
|
}
|
|
|
|
static void *xmalloc (size_t size)
|
|
{
|
|
void *rv;
|
|
if (size == 0)
|
|
return NULL;
|
|
rv = malloc (size);
|
|
if (rv == NULL)
|
|
die ("out-of-memory allocating %u bytes", (unsigned) size);
|
|
return rv;
|
|
}
|
|
|
|
static protobuf_c_boolean is_whitespace (const char *text)
|
|
{
|
|
while (*text != 0)
|
|
{
|
|
if (!isspace (*text))
|
|
return 0;
|
|
text++;
|
|
}
|
|
return 1;
|
|
}
|
|
static void chomp_trailing_whitespace (char *buf)
|
|
{
|
|
unsigned len = strlen (buf);
|
|
while (len > 0)
|
|
{
|
|
if (!isspace (buf[len-1]))
|
|
break;
|
|
len--;
|
|
}
|
|
buf[len] = 0;
|
|
}
|
|
static protobuf_c_boolean starts_with (const char *str, const char *prefix)
|
|
{
|
|
return memcmp (str, prefix, strlen (prefix)) == 0;
|
|
}
|
|
|
|
static void
|
|
handle_query_response (const Foo__LookupResult *result,
|
|
void *closure_data)
|
|
{
|
|
if (result == NULL)
|
|
printf ("Error processing request.\n");
|
|
else if (result->person == NULL)
|
|
printf ("Not found.\n");
|
|
else
|
|
{
|
|
Foo__Person *person = result->person;
|
|
unsigned i;
|
|
printf ("%s\n"
|
|
" %u\n", person->name, person->id);
|
|
if (person->email)
|
|
printf (" %s\n", person->email);
|
|
for (i = 0; i < person->n_phone; i++)
|
|
{
|
|
const ProtobufCEnumValue *ev;
|
|
ev = protobuf_c_enum_descriptor_get_value (&foo__person__phone_type__descriptor, person->phone[i]->type);
|
|
printf (" %s %s\n",
|
|
ev ? ev->name : "???",
|
|
person->phone[i]->number);
|
|
}
|
|
}
|
|
|
|
* (protobuf_c_boolean *) closure_data = 1;
|
|
}
|
|
|
|
/* Run the main-loop without blocking. It would be nice
|
|
if there was a simple API for this (protobuf_c_dispatch_run_with_timeout?),
|
|
but there isn't for now. */
|
|
static void
|
|
do_nothing (ProtobufCDispatch *dispatch, void *unused)
|
|
{
|
|
}
|
|
static void
|
|
run_main_loop_without_blocking (ProtobufCDispatch *dispatch)
|
|
{
|
|
protobuf_c_dispatch_add_idle (dispatch, do_nothing, NULL);
|
|
protobuf_c_dispatch_run (dispatch);
|
|
}
|
|
|
|
int main(int argc, char**argv)
|
|
{
|
|
ProtobufCService *service;
|
|
ProtobufC_RPC_Client *client;
|
|
ProtobufC_RPC_AddressType address_type=0;
|
|
const char *name = NULL;
|
|
unsigned i;
|
|
int autoreconnect_millis = -1;
|
|
|
|
for (i = 1; i < (unsigned) argc; i++)
|
|
{
|
|
if (starts_with (argv[i], "--tcp="))
|
|
{
|
|
address_type = PROTOBUF_C_RPC_ADDRESS_TCP;
|
|
name = strchr (argv[i], '=') + 1;
|
|
}
|
|
else if (starts_with (argv[i], "--unix="))
|
|
{
|
|
address_type = PROTOBUF_C_RPC_ADDRESS_LOCAL;
|
|
name = strchr (argv[i], '=') + 1;
|
|
}
|
|
else if (starts_with (argv[i], "--autoreconnect="))
|
|
{
|
|
autoreconnect_millis = atoi (strchr (argv[i], '=') + 1);
|
|
}
|
|
else
|
|
usage ();
|
|
}
|
|
|
|
if (name == NULL)
|
|
die ("missing --tcp=HOST:PORT or --unix=PATH");
|
|
|
|
signal (SIGPIPE, SIG_IGN);
|
|
|
|
service = protobuf_c_rpc_client_new (address_type, name, &foo__dir_lookup__descriptor, NULL);
|
|
if (service == NULL)
|
|
die ("error creating client");
|
|
client = (ProtobufC_RPC_Client *) service;
|
|
|
|
if (autoreconnect_millis >= 0)
|
|
protobuf_c_rpc_client_set_autoreconnect_period (client, autoreconnect_millis);
|
|
|
|
fprintf (stderr, "Connecting... ");
|
|
while (!protobuf_c_rpc_client_is_connected (client))
|
|
protobuf_c_dispatch_run (protobuf_c_dispatch_default ());
|
|
fprintf (stderr, "done.\n");
|
|
|
|
for (;;)
|
|
{
|
|
char buf[1024];
|
|
Foo__Name query = FOO__NAME__INIT;
|
|
protobuf_c_boolean is_done = 0;
|
|
fprintf (stderr, ">> ");
|
|
if (fgets (buf, sizeof (buf), stdin) == NULL)
|
|
break;
|
|
|
|
/* In order to prevent having the client get unduly stuck
|
|
in an error state, exercise the main-loop, which will
|
|
give the connection process time to run. */
|
|
run_main_loop_without_blocking (protobuf_c_dispatch_default ());
|
|
|
|
if (is_whitespace (buf))
|
|
continue;
|
|
chomp_trailing_whitespace (buf);
|
|
query.name = buf;
|
|
foo__dir_lookup__by_name (service, &query, handle_query_response, &is_done);
|
|
while (!is_done)
|
|
protobuf_c_dispatch_run (protobuf_c_dispatch_default ());
|
|
}
|
|
return 0;
|
|
}
|