diff --git a/src/google/protobuf-c/protobuf-c-dispatch.c b/src/google/protobuf-c/protobuf-c-dispatch.c index 2c74a62..e5f0c17 100644 --- a/src/google/protobuf-c/protobuf-c-dispatch.c +++ b/src/google/protobuf-c/protobuf-c-dispatch.c @@ -114,6 +114,7 @@ ProtobufCDispatch *protobuf_c_dispatch_new (ProtobufCAllocator *allocator) rv->base.changes = ALLOC (sizeof (ProtobufC_FDNotify) * rv->changes_alloced); rv->fd_map_size = 16; rv->fd_map = ALLOC (sizeof (FDMap) * rv->fd_map_size); + rv->allocator = allocator; memset (rv->fd_map, 255, sizeof (FDMap) * rv->fd_map_size); return &rv->base; } @@ -141,7 +142,7 @@ ProtobufCDispatch *protobuf_c_dispatch_default (void) { static ProtobufCDispatch *def = NULL; if (def == NULL) - def = protobuf_c_dispatch_new (NULL); + def = protobuf_c_dispatch_new (&protobuf_c_default_allocator); return def; } diff --git a/src/google/protobuf-c/protobuf-c-rpc.c b/src/google/protobuf-c/protobuf-c-rpc.c index 78d9b47..b7119e1 100644 --- a/src/google/protobuf-c/protobuf-c-rpc.c +++ b/src/google/protobuf-c/protobuf-c-rpc.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -693,6 +694,21 @@ destroy_client_rpc (ProtobufCService *service) client->allocator->free (client->allocator, client); } +static void +trivial_sync_libc_resolver (ProtobufCDispatch *dispatch, + const char *name, + ProtobufC_NameLookup_Found found_func, + ProtobufC_NameLookup_Failed failed_func, + void *callback_data) +{ + struct hostent *ent; + ent = gethostbyname (name); + if (ent == NULL) + failed_func (hstrerror (h_errno), callback_data); + else + found_func ((const uint8_t *) ent->h_addr_list[0], callback_data); +} + ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type, const char *name, const ProtobufCServiceDescriptor *descriptor, @@ -712,10 +728,32 @@ ProtobufCService *protobuf_c_rpc_client_new (ProtobufC_RPC_AddressType type, rv->name = strcpy (allocator->alloc (allocator, strlen (name) + 1), name); rv->state = PROTOBUF_C_CLIENT_STATE_INIT; rv->fd = -1; + rv->autoretry = 1; + rv->autoretry_millis = 2*1000; + rv->resolver = trivial_sync_libc_resolver; rv->info.init.idle = protobuf_c_dispatch_add_idle (dispatch, handle_init_idle, rv); return &rv->base_service; } +protobuf_c_boolean +protobuf_c_rpc_client_is_connected (ProtobufC_RPC_Client *client) +{ + return client->state == PROTOBUF_C_CLIENT_STATE_CONNECTED; +} + +void +protobuf_c_rpc_client_set_autoretry_period (ProtobufC_RPC_Client *client, + unsigned millis) +{ + client->autoretry = 1; + client->autoretry_millis = millis; +} +void +protobuf_c_rpc_client_disable_autoretry (ProtobufC_RPC_Client *client) +{ + client->autoretry = 0; +} + /* === Server === */ typedef struct _ServerRequest ServerRequest; typedef struct _ServerConnection ServerConnection; @@ -1163,3 +1201,23 @@ protobuf_c_rpc_server_new (ProtobufC_RPC_AddressType type, } return server_new_from_fd (fd, name, service, dispatch); } + +ProtobufCService * +protobuf_c_rpc_server_destroy (ProtobufC_RPC_Server *server, + protobuf_c_boolean destroy_underlying) +{ + ProtobufCService *rv = destroy_underlying ? NULL : server->underlying; + while (server->first_connection != NULL) + server_connection_close (server->first_connection); + server->allocator->free (server->allocator, server->bind_name); + while (server->recycled_requests != NULL) + { + ServerRequest *req = server->recycled_requests; + server->recycled_requests = req->info.recycled.next; + server->allocator->free (server->allocator, req); + } + if (destroy_underlying) + protobuf_c_service_destroy (server->underlying); + server->allocator->free (server->allocator, server); + return rv; +} diff --git a/src/google/protobuf-c/protobuf-c-rpc.h b/src/google/protobuf-c/protobuf-c-rpc.h index a3be368..a0979fa 100644 --- a/src/google/protobuf-c/protobuf-c-rpc.h +++ b/src/google/protobuf-c/protobuf-c-rpc.h @@ -78,6 +78,9 @@ void protobuf_c_rpc_client_disable_autoretry (ProtobufC_RPC_Client *client); void protobuf_c_rpc_client_set_autoretry_period (ProtobufC_RPC_Client *client, unsigned millis); +/* checking the state of the client */ +protobuf_c_boolean protobuf_c_rpc_client_is_connected (ProtobufC_RPC_Client *client); + /* NOTE: we don't actually start connecting til the main-loop runs, so you may configure the client immediately after creation */ diff --git a/src/test/test-rpc.c b/src/test/test-rpc.c index 45f5322..37fd390 100644 --- a/src/test/test-rpc.c +++ b/src/test/test-rpc.c @@ -39,6 +39,7 @@ test__by_name (Foo__DirLookup_Service *service, person.n_phone = 1; person.phone = pns; person.email = email; + person.name = name->name; result.person = &person; } closure (&result, closure_data); @@ -82,6 +83,14 @@ test_not_found_closure (const Foo__LookupResult *result, * (protobuf_c_boolean *) closure_data = 1; } +static void +test_defunct_closure (const Foo__LookupResult *result, + void *closure_data) +{ + assert (result == NULL); + * (protobuf_c_boolean *) closure_data = 1; +} + static void test_service (ProtobufCService *service) @@ -93,28 +102,61 @@ test_service (ProtobufCService *service) is_done = 0; foo__dir_lookup__by_name (service, &name, test_dave_closure, &is_done); while (!is_done) - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); name.name = "joe the plumber"; is_done = 0; foo__dir_lookup__by_name (service, &name, test_joe_the_plumber_closure, &is_done); while (!is_done) - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); name.name = "asdfvcvzxsa"; is_done = 0; foo__dir_lookup__by_name (service, &name, test_not_found_closure, &is_done); while (!is_done) - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); +} +static void +test_defunct_client (ProtobufCService *service) +{ + Foo__Name name = FOO__NAME__INIT; + protobuf_c_boolean is_done; + + name.name = "dave"; + is_done = 0; + foo__dir_lookup__by_name (service, &name, test_defunct_closure, &is_done); + while (!is_done) + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); + + name.name = "joe the plumber"; + is_done = 0; + foo__dir_lookup__by_name (service, &name, test_defunct_closure, &is_done); + while (!is_done) + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); + + name.name = "asdfvcvzxsa"; + is_done = 0; + foo__dir_lookup__by_name (service, &name, test_defunct_closure, &is_done); + while (!is_done) + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); } /* --- main() --- */ +static void +set_boolean_true (ProtobufCDispatch *dispatch, + void *func_data) +{ + (void) dispatch; + * (protobuf_c_boolean *) func_data = 1; +} + int main() { protobuf_c_boolean is_done; ProtobufCService *local_service = (ProtobufCService *) &the_dir_lookup_service; ProtobufCService *remote_service; ProtobufC_RPC_Client *client; + ProtobufC_RPC_Server *server; test_service (local_service); @@ -132,7 +174,7 @@ int main() 250, set_boolean_true, &is_done); while (!is_done) { - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); assert (!protobuf_c_rpc_client_is_connected (client)); } @@ -146,7 +188,7 @@ int main() protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (), 250, set_boolean_true, &is_done); while (!is_done && !protobuf_c_rpc_client_is_connected (client)) - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); /* technically, there's no way to know how long it'll take to connect if the machine is heavily loaded, so the following @@ -156,17 +198,31 @@ int main() /* wait for the timer to elapse, since that's laziest way to handle it. */ while (!is_done) - protobuf_c_dispatch_run_once (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); /* Test the client */ test_service (remote_service); /* Destroy the server and ensure that a request is failed in a timely fashion. */ - ... + protobuf_c_rpc_server_destroy (server, 0); + server = NULL; + test_defunct_client (remote_service); /* Create a server again and wait for the client to reconnect. */ - ... + server = protobuf_c_rpc_server_new (PROTOBUF_C_RPC_ADDRESS_LOCAL, + "test.socket", + local_service, + NULL); + assert (server != NULL); + is_done = 0; + while (!is_done) + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); + protobuf_c_dispatch_add_timer_millis (protobuf_c_dispatch_default (), + 250, set_boolean_true, &is_done); + while (!is_done) + protobuf_c_dispatch_run (protobuf_c_dispatch_default ()); + assert (protobuf_c_rpc_client_is_connected (client)); /* Test the client again, for kicks. */ test_service (remote_service); @@ -175,7 +231,7 @@ int main() protobuf_c_service_destroy (remote_service); /* Destroy the server */ - protobuf_c_rpc_server_destroy (server); + protobuf_c_rpc_server_destroy (server, 0); return 0; }