diff --git a/TODO b/TODO index c0a7fb5..8085cd0 100644 --- a/TODO +++ b/TODO @@ -1,15 +1,16 @@ -- check over documentation again -- make services derive from ProtobufCService; be usable with a cast. - provide example rpc +- at least include extensions in Descriptor -- To document: +- Documentations: - __INIT macro + - service __init function + - get rid of docs for create-service; update generally + - check over documentation again - support Group (whatever it is) - almost no code generator options are obeyed - ISSUE: strings may not contain NULs - generate Init functions / handle default values -- at least include extensions in Descriptor - proper support for extensions (not sure i get what's needed) - get rid of kThick/ThinSeparator if we decide not to use them diff --git a/src/google/protobuf-c/protobuf-c.c b/src/google/protobuf-c/protobuf-c.c index cb61e44..9391171 100644 --- a/src/google/protobuf-c/protobuf-c.c +++ b/src/google/protobuf-c/protobuf-c.c @@ -1534,14 +1534,12 @@ struct _ServiceMachgen typedef void (*DestroyHandler)(void *service); typedef void (*GenericHandler)(void *service, const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); + ProtobufCClosure *closure); static void service_machgen_invoke(ProtobufCService *service, unsigned method_index, const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data) + ProtobufCClosure *closure) { GenericHandler *handlers; GenericHandler handler; @@ -1549,7 +1547,7 @@ service_machgen_invoke(ProtobufCService *service, PROTOBUF_C_ASSERT (method_index < service->descriptor->n_methods); handlers = (GenericHandler *) machgen->service; handler = handlers[method_index]; - (*handler) (machgen->service, input, closure, closure_data); + (*handler) (machgen->service, input, closure); } void @@ -1564,6 +1562,55 @@ protobuf_c_service_generated_init (ProtobufCService *service, memset (service + 1, 0, descriptor->n_methods * sizeof (GenericHandler)); } +ProtobufCClosure * +protobuf_c_closure_new (const ProtobufCMessageDescriptor *descriptor, + ProtobufCClosureFunc func, + void *closure_data, + ProtobufCDestroyFunc destroy) +{ + ProtobufCClosure *rv; + rv = protobuf_c_default_allocator.alloc (&protobuf_c_default_allocator, + sizeof (ProtobufCClosure)); + rv->descriptor = descriptor; + rv->handle_message = func; + rv->handle_error = NULL; + rv->closure_data = closure_data; + rv->destroy_data = destroy; + return rv; +} +#undef protobuf_c_closure_set_error_handler +void +protobuf_c_closure_set_error_handler (ProtobufCClosure *closure, + ProtobufCClosureErrorFunc func) +{ + closure->handle_error = func; +} + +static inline void free_closure (ProtobufCClosure *closure) +{ + if (closure->destroy_data) + closure->destroy_data (closure->closure_data); + protobuf_c_default_allocator.free (&protobuf_c_default_allocator, closure); +} + +void protobuf_c_closure_run (ProtobufCClosure *closure, + const ProtobufCMessage *message) +{ + PROTOBUF_C_ASSERT (closure->descriptor == message->descriptor); + closure->handle_message (message, closure->closure_data); + free_closure (closure); +} + +void +protobuf_c_closure_error (ProtobufCClosure *closure, + const ProtobufCError *error) +{ + if (closure->handle_error != NULL) + closure->handle_error (error, closure->closure_data); + free_closure (closure); +} + + void protobuf_c_service_destroy (ProtobufCService *service) { service->destroy (service); diff --git a/src/google/protobuf-c/protobuf-c.h b/src/google/protobuf-c/protobuf-c.h index 6062d82..24d05b2 100644 --- a/src/google/protobuf-c/protobuf-c.h +++ b/src/google/protobuf-c/protobuf-c.h @@ -173,6 +173,23 @@ void protobuf_c_message_free_unpacked (ProtobufCMessage *message, typedef struct _ProtobufCMethodDescriptor ProtobufCMethodDescriptor; typedef struct _ProtobufCServiceDescriptor ProtobufCServiceDescriptor; +typedef struct _ProtobufCError ProtobufCError; +struct _ProtobufCError +{ + const char *domain; /* must be static string */ + unsigned code; + char *message; +}; +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +#define PROTOBUF_C_PRINTF_ATTR( format_idx, arg_idx ) \ + __attribute__((__format__ (__printf__, format_idx, arg_idx))) +#endif +ProtobufCError *protobuf_c_error_new (const char *domain, + unsigned code, + const char *message_format, + ...) PROTOBUF_C_PRINTF_ATTR(3,4); + + struct _ProtobufCMethodDescriptor { const char *name; @@ -192,16 +209,45 @@ struct _ProtobufCServiceDescriptor }; typedef struct _ProtobufCService ProtobufCService; -typedef void (*ProtobufCClosure)(const ProtobufCMessage *message, - void *closure_data); +typedef void (*ProtobufCClosureFunc) (const ProtobufCMessage *message, + void *closure_data); +typedef void (*ProtobufCClosureErrorFunc)(const ProtobufCError *error, + void *closure_data); +typedef void (*ProtobufCDestroyFunc) (void *closure_data); + +typedef struct _ProtobufCClosure ProtobufCClosure; +struct _ProtobufCClosure +{ + const ProtobufCMessageDescriptor *descriptor; + ProtobufCClosureFunc handle_message; + ProtobufCClosureErrorFunc handle_error; + void *closure_data; + ProtobufCDestroyFunc destroy_data; +}; + +ProtobufCClosure *protobuf_c_closure_new (const ProtobufCMessageDescriptor *, + ProtobufCClosureFunc func, + void *closure_data, + ProtobufCDestroyFunc destroy); +void protobuf_c_closure_set_error_handler + (ProtobufCClosure *closure, + ProtobufCClosureErrorFunc func); +#define protobuf_c_closure_set_error_handler(closure, func) \ + do { ((closure)->handle_error) = (func); } while(0) + +/* these functions destroy the closure */ +void protobuf_c_closure_run (ProtobufCClosure *closure, + const ProtobufCMessage *message); +void protobuf_c_closure_error(ProtobufCClosure *closure, + const ProtobufCError *error); + struct _ProtobufCService { const ProtobufCServiceDescriptor *descriptor; void (*invoke)(ProtobufCService *service, unsigned method_index, const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); + ProtobufCClosure *closure); void (*destroy) (ProtobufCService *service); }; diff --git a/src/google/protobuf/compiler/c/c_message.cc b/src/google/protobuf/compiler/c/c_message.cc index c5de3bc..2a42652 100644 --- a/src/google/protobuf/compiler/c/c_message.cc +++ b/src/google/protobuf/compiler/c/c_message.cc @@ -120,16 +120,16 @@ GenerateStructDefinition(io::Printer* printer) { } printer->Outdent(); - printer->Print(vars, "};\n\n"); + printer->Print(vars, "};\n"); printer->Print(vars, "#define $ucclassname$__INIT \\\n" - " { PROTOBUF_C_MESSAGE_INIT (&$lcclassname$__descriptor)"); + " { PROTOBUF_C_MESSAGE_INIT (&$lcclassname$__descriptor) \\\n "); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor *field = descriptor_->field(i); printer->Print(", "); field_generators_.get(field).GenerateStaticInit(printer); } - printer->Print(" }\n"); + printer->Print(" }\n\n\n"); } @@ -180,10 +180,16 @@ void MessageGenerator::GenerateClosureTypedef(io::Printer* printer) } std::map vars; vars["name"] = FullNameToC(descriptor_->full_name()); + vars["lcclassname"] = FullNameToLower(descriptor_->full_name()); printer->Print(vars, - "typedef void (*$name$_Closure)\n" + "typedef void (*$name$__ClosureFunc)\n" " (const $name$ *message,\n" - " void *closure_data);\n"); + " void *closure_data);\n" + "ProtobufCClosure *$lcclassname$__closure_new\n" + " ($name$__ClosureFunc func,\n" + " void *closure_data,\n" + " ProtobufCDestroyFunc destroy);\n" + ); } static int @@ -240,6 +246,15 @@ GenerateHelperFunctionDefinitions(io::Printer* printer) " PROTOBUF_C_ASSERT (message->base.descriptor == &$lcclassname$__descriptor);\n" " protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);\n" "}\n" + "ProtobufCClosure *$lcclassname$__closure_new\n" + " ($classname$__ClosureFunc func,\n" + " void *closure_data,\n" + " ProtobufCDestroyFunc destroy)\n" + "{\n" + " return protobuf_c_closure_new (&$lcclassname$__descriptor,\n" + " (ProtobufCClosureFunc) func,\n" + " closure_data, destroy);\n" + "}\n" ); } diff --git a/src/google/protobuf/compiler/c/c_service.cc b/src/google/protobuf/compiler/c/c_service.cc index f8a67b9..b01070f 100644 --- a/src/google/protobuf/compiler/c/c_service.cc +++ b/src/google/protobuf/compiler/c/c_service.cc @@ -71,8 +71,7 @@ void ServiceGenerator::GenerateVfuncs(io::Printer* printer) printer->Print(vars_, " void (*$method$)($cname$_Service *service,\n" " $metpad$ const $input_typename$ *input,\n" - " $metpad$ $output_typename$_Closure closure,\n" - " $metpad$ void *closure_data);\n"); + " $metpad$ ProtobufCClosure *closure);\n"); } printer->Print(vars_, "};\n"); @@ -95,8 +94,7 @@ void ServiceGenerator::GenerateCallersDeclarations(io::Printer* printer) printer->Print(vars_, "void $lcfullname$__$method$(ProtobufCService *service,\n" " $padddddddddddddddddd$ const $input_typename$ *input,\n" - " $padddddddddddddddddd$ $output_typename$_Closure closure,\n" - " $padddddddddddddddddd$ void *closure_data);\n"); + " $padddddddddddddddddd$ ProtobufCClosure *closure);\n"); } } @@ -167,17 +165,18 @@ void ServiceGenerator::GenerateCallersImplementations(io::Printer* printer) vars_["metpad"] = ConvertToSpaces(lcname); vars_["input_typename"] = FullNameToC(method->input_type()->full_name()); vars_["output_typename"] = FullNameToC(method->output_type()->full_name()); + vars_["lc_output_typename"] = FullNameToLower(method->output_type()->full_name()); vars_["padddddddddddddddddd"] = ConvertToSpaces(lcfullname + "__" + lcname); vars_["index"] = SimpleItoa(i); printer->Print(vars_, "void $lcfullname$__$method$(ProtobufCService *service,\n" " $padddddddddddddddddd$ const $input_typename$ *input,\n" - " $padddddddddddddddddd$ $output_typename$_Closure closure,\n" - " $padddddddddddddddddd$ void *closure_data)\n" + " $padddddddddddddddddd$ ProtobufCClosure *closure)\n" "{\n" " PROTOBUF_C_ASSERT (service->descriptor == &$lcfullname$__descriptor);\n" - " service->invoke(service, $index$, (const ProtobufCMessage *) input, (ProtobufCClosure) closure, closure_data);\n" + " PROTOBUF_C_ASSERT (closure->descriptor == &$lc_output_typename$__descriptor);\n" + " service->invoke(service, $index$, (const ProtobufCMessage *) input, closure);\n" "}\n"); } } diff --git a/src/simplerpc/simplerpc.c b/src/simplerpc/simplerpc.c index 751617c..430fcdd 100644 --- a/src/simplerpc/simplerpc.c +++ b/src/simplerpc/simplerpc.c @@ -1,4 +1,7 @@ #include +#include "generated/simplerpc.pb-c.h" + +/* === server === */ struct _SimplerpcServerStream { @@ -7,20 +10,24 @@ struct _SimplerpcServerStream GskBuffer incoming, outgoing; }; -struct _SimplerpcServer +struct _SimplerpcContext { - GskStreamListener *listener; GHashTable *domain_to_service; guint ref_count; }; +struct _SimplerpcServer +{ + GskStreamListener *listener; + SimplerpcContext *context; +}; static SimplerpcServer * -simplerpc_server_from_listener (GskStreamListener *listener) +simplerpc_server_from_listener (GskStreamListener *listener, + SimplerpcContext *context) { SimplerpcServer *rv = g_slice_new (SimplerpcServer); rv->listener = listener; - rv->ref_count = 1; rv->domain_to_service = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, protobuf_c_server_destroy); @@ -30,9 +37,10 @@ simplerpc_server_from_listener (GskStreamListener *listener) } SimplerpcServer * -simplerpc_bind_ipv4 (int tcp_port, - SimplerpcBindIpv4Flags flags, - ProtobufCError **error) +simplerpc_server_bind_ipv4 (int tcp_port, + SimplerpcBindIpv4Flags flags, + SimplerpcContext *context, + ProtobufCError **error) { GskStreamListener *listener; GskSocketAddress *addr; @@ -46,33 +54,111 @@ simplerpc_bind_ipv4 (int tcp_port, set_protobuf_c_error_from_gerror (error, ge); return NULL; } - return simplerpc_server_from_listener (listener); + return simplerpc_server_from_listener (listener, context); } SimplerpcServer * -simplerpc_bind_local (const char *path, - ProtobufCError **error) +simplerpc_server_bind_local (const char *path, + SimplerpcContext *context, + ProtobufCError **error) +{ + GskStreamListener *listener; + GskSocketAddress *addr; + addr = gsk_socket_address_new_local (path); + listener = gsk_stream_listener_socket_new_bind (addr, &ge); + if (listener == NULL) + { + set_protobuf_c_error_from_gerror (error, ge); + return NULL; + } + return simplerpc_server_from_listener (listener, context); +} + + +typedef struct _BuiltinService BuiltinService; +struct _BuiltinService +{ + Simplerpc__Builtin_Service base; + SimplerpcContext *context; +}; + +static void +builtin_service_list_domains (Simplerpc__Builtin_Service *service, + const Simplerpc__DomainListRequest *input, + ProtobufCClosure *closure) { ... - return simplerpc_server_from_listener (listener); } + +static void +builtin_service_destroy (Simplerpc__Builtin_Service *ser) +{ + BuiltinService *bs = (BuiltinService *) ser; + g_slice_free (BuiltinService, bs); +} + +SimplerpcContext * +simplerpc_context_new (void) +{ + SimplerpcContext *context = g_slice_new (SimplerpcContext); + BuiltinService *service; + context->domain_to_service + = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, + (GDestroyNotify) protobuf_c_server_destroy); + context->ref_count = 1; + + service = g_slice_new (BuiltinService); + simplerpc__builtin__init (&service->base); + service->base.list_domains = builtin_service_list_domains; + service->base.base.destroy = builtin_service_free; + service->context = context; + simplerpc_context_add_service (context, "simplerpc.builtin", + (ProtobufCService *) service); + return context; +} + + void -simplerpc_add_service (SimplerpcServer *server, - const char *domain, - ProtobufCService *service) +simplerpc_context_add_service (SimplerpcContext *context, + const char *domain, + ProtobufCService *service) { - ... + g_hash_table_insert (context, g_strdup (domain), service); } + void simplerpc_server_destroy (SimplerpcServer *server) { ... } +/* === client === */ +typedef struct _SimplerpcClientRequest SimplerpcClientRequest; +typedef struct _SimplerpcClient SimplerpcClient; +struct _SimplerpcClientRequest +{ + guint64 request_id; + gsize request_len; + guint8 *request_data; + ProtobufCClosure *closure; + SimplerpcClientRequest *prev, *next; +}; + +struct _SimplerpcClient +{ + GskStream *transport; + GskBuffer incoming; + GskBuffer outgoing; + GHashTable *request_id_to_request; + + guint ref_count; + SimplerpcClientRequest *first, *last; +}; SimplerpcClient * -simplerpc_client_new_ipv4 (const uint8_t *ip_addr, +simplerpc_client_new_ipv4 (const char *hostname, uint16_t port, ProtobufCError **error) { diff --git a/src/simplerpc/simplerpc.h b/src/simplerpc/simplerpc.h index 6bf839f..21fe45c 100644 --- a/src/simplerpc/simplerpc.h +++ b/src/simplerpc/simplerpc.h @@ -3,14 +3,19 @@ #include -SimplerpcServer * simplerpc_bind_ipv4 (int tcp_port, - SimplerpcBindIpv4Flags flags, - ProtobufCError **error); -SimplerpcServer * simplerpc_bind_local (const char *path, - ProtobufCError **error); -void simplerpc_add_service (SimplerpcServer *server, +SimplerpcContext *simplerpc_context_new (void); +void simplerpc_context_add_service + (SimplerpcServer *server, const char *domain, ProtobufCService *service); + +SimplerpcServer * simplerpc_bind_ipv4 (int tcp_port, + SimplerpcBindIpv4Flags flags, + SimplerpcContext *context, + ProtobufCError **error); +SimplerpcServer * simplerpc_bind_local (const char *path, + SimplerpcContext *context, + ProtobufCError **error); void simplerpc_server_destroy (SimplerpcServer *server); diff --git a/src/simplerpc/simplerpc.proto b/src/simplerpc/simplerpc.proto new file mode 100644 index 0000000..22bdf87 --- /dev/null +++ b/src/simplerpc/simplerpc.proto @@ -0,0 +1,37 @@ +package simplerpc; + +message RequestPreamble +{ + required uint32 size = 1; + required string domain = 2; + required uint64 request_id = 3; +} + +message ResponsePreamble +{ + required uint32 size = 1; + required uint64 request_id = 2; +} + +// builtin services (domain=simplerpc.builtin) +message DomainListRequest +{ + required bool get_service_defs = 1; +} + +message DomainInfo +{ + required string domain = 1; + optional string service = 2; + optional bytes service_defs = 3; +} + +message DomainListResponse +{ + repeated DomainInfo info = 1; +} + +service Builtin +{ + rpc ListDomains(DomainListRequest) returns (DomainListResponse); +}