diff --git a/include/App/appclient.h b/include/App/appclient.h index 6cfe086..398d4c5 100644 --- a/include/App/appclient.h +++ b/include/App/appclient.h @@ -18,6 +18,7 @@ #ifndef LIBAPP_APP_APPCLIENT_H # define LIBAPP_APP_APPCLIENT_H +# include # include # include # include @@ -42,7 +43,13 @@ AppStatus * appclient_get_status(AppClient * appclient); /* useful */ int appclient_call(AppClient * appclient, void ** result, char const * method, ...); +int appclient_callv(AppClient * appclient, + void ** result, char const * method, va_list args); int appclient_call_variable(AppClient * appclient, Variable * result, char const * method, ...); +int appclient_call_variables(AppClient * appclient, + Variable * result, char const * method, Variable ** args); +int appclient_call_variablev(AppClient * appclient, + Variable * result, char const * method, va_list args); #endif /* !LIBAPP_APP_APPCLIENT_H */ diff --git a/src/appclient.c b/src/appclient.c index 5b7a5eb..4d14f4c 100644 --- a/src/appclient.c +++ b/src/appclient.c @@ -83,6 +83,9 @@ AppClient * appclient_new_event(App * self, char const * app, || appclient->event == NULL) { appclient_delete(appclient); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() => NULL\n", __func__); +#endif return NULL; } #ifdef DEBUG @@ -131,34 +134,73 @@ int appclient_call(AppClient * appclient, va_list ap; va_start(ap, method); - ret = appinterface_callv(appclient->interface, appclient->app, result, - method, ap); + ret = appclient_callv(appclient, result, method, ap); va_end(ap); return ret; } +/* appclient_callv */ +int appclient_callv(AppClient * appclient, + void ** result, char const * method, va_list args) +{ + int ret; + AppMessage * message; + + if((message = appinterface_messagev(appclient->interface, method, args)) + == NULL) + return -1; + /* FIXME obtain the answer (AICD_{,IN}OUT) */ + ret = apptransport_client_send(appclient->transport, message, 1); + appmessage_delete(message); + return ret; +} + + /* appclient_call_variable */ int appclient_call_variable(AppClient * appclient, Variable * result, char const * method, ...) { int ret; - size_t cnt; - size_t i; va_list ap; - Variable ** argv; - if(appinterface_get_args_count(appclient->interface, &cnt, method) != 0) - return -1; - if((argv = malloc(sizeof(*argv) * cnt)) == NULL) - return error_set_code(-errno, "%s", strerror(errno)); va_start(ap, method); - for(i = 0; i < cnt; i++) - argv[i] = va_arg(ap, Variable *); + ret = appclient_call_variablev(appclient, result, method, ap); va_end(ap); - ret = appinterface_call_variablev(appclient->interface, appclient->app, - result, method, cnt, argv); - free(argv); + return ret; +} + + +/* appclient_call_variables */ +int appclient_call_variables(AppClient * appclient, + Variable * result, char const * method, Variable ** args) +{ + int ret; + AppMessage * message; + + if((message = appinterface_message_variables(appclient->interface, + method, args)) == NULL) + return -1; + /* FIXME obtain the answer (AICD_{,IN}OUT) */ + ret = apptransport_client_send(appclient->transport, message, 1); + appmessage_delete(message); + return ret; +} + + +/* appclient_call_variablev */ +int appclient_call_variablev(AppClient * appclient, + Variable * result, char const * method, va_list args) +{ + int ret; + AppMessage * message; + + if((message = appinterface_message_variablev(appclient->interface, + method, args)) == NULL) + return -1; + /* FIXME obtain the answer (AICD_{,IN}OUT) */ + ret = apptransport_client_send(appclient->transport, message, 1); + appmessage_delete(message); return ret; } diff --git a/src/appinterface.c b/src/appinterface.c index 5a47cc0..e2905a7 100644 --- a/src/appinterface.c +++ b/src/appinterface.c @@ -26,6 +26,7 @@ #include #include #include +#include "App/appmessage.h" #include "App/appserver.h" #include "appstatus.h" #include "appinterface.h" @@ -161,8 +162,12 @@ static AppInterfaceCall * _appinterface_get_call(AppInterface * appinterface, char const * method); /* useful */ +static Variable ** _appinterface_argv(AppInterfaceCall * call, va_list args); +static void _appinterface_argv_free(Variable ** argv, size_t argc); static int _appinterface_call(App * app, Variable * result, AppInterfaceCall * call, size_t argc, Variable ** argv); +static AppMessage * _appinterface_message(AppInterfaceCall * call, + size_t argc, Variable ** argv); /* functions */ @@ -513,8 +518,125 @@ int appinterface_callv(AppInterface * appinterface, App * app, void ** result, int ret = 0; AppInterfaceCall * call; Variable * r; - size_t argc; Variable ** argv; + + if((call = _appinterface_get_call(appinterface, method)) == NULL) + return -1; + if(call->type.type == VT_NULL) + r = NULL; + else if((r = variable_new(call->type.type, NULL)) == NULL) + return -1; + if((argv = _appinterface_argv(call, args)) == NULL) + { + if(r != NULL) + variable_delete(r); + return -1; + } + if(ret == 0) + ret = _appinterface_call(app, r, call, call->args_cnt, argv); + if(r != NULL) + { + if(ret == 0 && result != NULL) + /* XXX return 0 anyway? */ + ret = variable_get_as(r, call->type.type, *result); + variable_delete(r); + } + /* FIXME also implement AICD_{,IN}OUT */ + _appinterface_argv_free(argv, call->args_cnt); + return ret; +} + + +/* appinterface_call_variablev */ +int appinterface_call_variablev(AppInterface * appinterface, App * app, + Variable * result, char const * method, + size_t argc, Variable ** argv) +{ + AppInterfaceCall * call; + + if((call = _appinterface_get_call(appinterface, method)) == NULL) + return -1; + return _appinterface_call(app, result, call, argc, argv); +} + + +/* appinterface_messagev */ +AppMessage * appinterface_messagev(AppInterface * appinterface, + char const * method, va_list args) +{ + AppInterfaceCall * call; + Variable ** argv; + AppMessage * message; + + if((call = _appinterface_get_call(appinterface, method)) == NULL) + return NULL; + if((argv = _appinterface_argv(call, args)) == NULL) + return NULL; + message = _appinterface_message(call, call->args_cnt, argv); + _appinterface_argv_free(argv, call->args_cnt); + return message; +} + + +/* appinterface_message_variables */ +AppMessage * appinterface_message_variables(AppInterface * appinterface, + char const * method, Variable ** args) +{ + AppInterfaceCall * call; + + if((call = _appinterface_get_call(appinterface, method)) == NULL) + return NULL; + return _appinterface_message(call, call->args_cnt, args); +} + + +/* appinterface_message_variablev */ +AppMessage * appinterface_message_variablev(AppInterface * appinterface, + char const * method, va_list args) +{ + AppInterfaceCall * call; + Variable ** argv; + size_t i; + AppMessage * message; + + if((call = _appinterface_get_call(appinterface, method)) == NULL) + return NULL; + if(call->args_cnt == 0) + argv = NULL; + else if((argv = malloc(sizeof(*argv) * call->args_cnt)) == NULL) + /* XXX report error */ + return NULL; + for(i = 0; i < call->args_cnt; i++) + argv[i] = va_arg(args, Variable *); + message = _appinterface_message(call, call->args_cnt, argv); + free(argv); + return message; +} + + +/* private */ +/* accessors */ +/* appinterface_get_call */ +static AppInterfaceCall * _appinterface_get_call(AppInterface * appinterface, + String const * method) +{ + size_t i; + + for(i = 0; i < appinterface->calls_cnt; i++) + if(string_compare(appinterface->calls[i].name, method) == 0) + return &appinterface->calls[i]; + error_set_code(1, "%s%s%s%s", "Unknown call \"", method, + "\" for interface ", appinterface->name); + return NULL; +} + + +/* useful */ +/* appinterface_argv */ +static Variable ** _appinterface_argv(AppInterfaceCall * call, va_list args) +{ + Variable ** argv; + size_t argc; union { bool b; @@ -533,18 +655,9 @@ int appinterface_callv(AppInterface * appinterface, App * app, void ** result, } u; void * p; - if((call = _appinterface_get_call(appinterface, method)) == NULL) - return -1; - if(call->type.type == VT_NULL) - r = NULL; - else if((r = variable_new(call->type.type, NULL)) == NULL) - return -1; if((argv = malloc(sizeof(*argv) * (call->args_cnt))) == NULL) - { - if(r != NULL) - variable_delete(r); - return -1; - } + /* XXX set the error */ + return NULL; for(argc = 0; argc < call->args_cnt; argc++) { /* FIXME also implement AICD_{,IN}OUT */ @@ -610,50 +723,26 @@ int appinterface_callv(AppInterface * appinterface, App * app, void ** result, argv[argc] = (p != NULL) ? variable_new(call->args[argc].type, p) : NULL; if(p == NULL || argv[argc] == NULL) - ret = -1; + { + _appinterface_argv_free(argv, argc); + return NULL; + } } - if(ret == 0) - ret = _appinterface_call(app, r, call, argc, argv); - if(ret == 0 && result != NULL) - /* XXX return 0 anyway? */ - ret = variable_get_as(r, call->type.type, *result); - if(r != NULL) - variable_delete(r); - return ret; + return argv; } -/* appinterface_call_variablev */ -int appinterface_call_variablev(AppInterface * appinterface, App * app, - Variable * result, char const * method, - size_t argc, Variable ** argv) -{ - AppInterfaceCall * call; - - if((call = _appinterface_get_call(appinterface, method)) == NULL) - return -1; - return _appinterface_call(app, result, call, argc, argv); -} - - -/* private */ -/* accessors */ -/* appinterface_get_call */ -static AppInterfaceCall * _appinterface_get_call(AppInterface * appinterface, - String const * method) +/* appinterface_argv_free */ +static void _appinterface_argv_free(Variable ** argv, size_t argc) { size_t i; - for(i = 0; i < appinterface->calls_cnt; i++) - if(string_compare(appinterface->calls[i].name, method) == 0) - return &appinterface->calls[i]; - error_set_code(1, "%s%s%s%s", "Unknown call \"", method, - "\" for interface ", appinterface->name); - return NULL; + for(i = 0; i < argc; i++) + variable_delete(argv[argc]); + free(argv); } -/* useful */ /* appinterface_call */ static int _appinterface_call(App * app, Variable * result, AppInterfaceCall * call, size_t argc, Variable ** argv) @@ -663,8 +752,10 @@ static int _appinterface_call(App * app, Variable * result, size_t i; if(argc != call->args_cnt) + /* XXX set the error */ return -1; if((p = malloc(sizeof(*p) * (argc + 1))) == NULL) + /* XXX set the error */ return -1; /* XXX really is a VT_POINTER (void *) */ if((p[0] = variable_new(VT_BUFFER, app)) == NULL) @@ -679,3 +770,31 @@ static int _appinterface_call(App * app, Variable * result, free(p); return ret; } + + +/* appinterface_message */ +static AppMessage * _appinterface_message(AppInterfaceCall * call, + size_t argc, Variable ** argv) +{ + AppMessage * message; + AppMessageCallArgument * args; + size_t i; + + if(argc != call->args_cnt) + /* XXX set the error */ + return NULL; + if(argc == 0) + args = NULL; + else if((args = malloc(sizeof(*args) * argc)) == NULL) + /* XXX set the error */ + return NULL; + else + for(i = 0; i < argc; i++) + { + args[i].direction = call->args[i].direction; + args[i].arg = argv[i]; + } + message = appmessage_new_call(call->name, args, argc); + free(args); + return message; +} diff --git a/src/appinterface.h b/src/appinterface.h index 493e286..672d6d1 100644 --- a/src/appinterface.h +++ b/src/appinterface.h @@ -51,4 +51,11 @@ int appinterface_call_variablev(AppInterface * appinterface, App * app, Variable * result, char const * method, size_t argc, Variable ** argv); +AppMessage * appinterface_messagev(AppInterface * appinterface, + char const * method, va_list args); +AppMessage * appinterface_message_variables(AppInterface * appinterface, + char const * method, Variable ** args); +AppMessage * appinterface_message_variablev(AppInterface * appinterface, + char const * method, va_list args); + #endif /* !LIBAPP_APPINTERFACE_H */ diff --git a/src/apptransport.c b/src/apptransport.c index ba9932e..0fc65c5 100644 --- a/src/apptransport.c +++ b/src/apptransport.c @@ -408,7 +408,16 @@ static AppTransportClient * _apptransport_helper_client_new( if((client = object_new(sizeof(*client))) == NULL) return NULL; client->transport = transport; - client->name = (name != NULL) ? string_new(name) : NULL; + if(name != NULL) + { + if((client->name = string_new(name)) == NULL) + { + object_delete(client); + return NULL; + } + } + else + client->name = NULL; return client; } diff --git a/src/transport/tcp.c b/src/transport/tcp.c index 4e1d6af..631cf07 100644 --- a/src/transport/tcp.c +++ b/src/transport/tcp.c @@ -109,9 +109,9 @@ static TCP * _tcp_init(AppTransportPluginHelper * helper, AppTransportMode mode, char const * name); static void _tcp_destroy(TCP * tcp); -static int _tcp_client_send(TCP * tcp, AppTransportClient * client, +static int _tcp_client_send(TCP * tcp, AppMessage * message); +static int _tcp_server_send(TCP * tcp, AppTransportClient * client, AppMessage * message); -static int _tcp_send(TCP * tcp, AppMessage * message); /* useful */ static int _tcp_error(char const * message); @@ -120,7 +120,8 @@ static int _tcp_error(char const * message); static int _tcp_server_add_client(TCP * tcp, TCPSocket * client); /* sockets */ -static int _tcp_socket_init(TCPSocket * tcpsocket, int domain, TCP * tcp); +static int _tcp_socket_init(TCPSocket * tcpsocket, int domain, int flags, + TCP * tcp); static void _tcp_socket_init_fd(TCPSocket * tcpsocket, TCP * tcp, int fd, struct sockaddr * sa, socklen_t sa_len); static TCPSocket * _tcp_socket_new_fd(TCP * tcp, int fd, struct sockaddr * sa, @@ -146,8 +147,8 @@ AppTransportPluginDefinition transport = NULL, _tcp_init, _tcp_destroy, - _tcp_send, - _tcp_client_send + _tcp_client_send, + _tcp_server_send }; @@ -214,19 +215,20 @@ static int _init_client(TCP * tcp, char const * name, int domain) { tcp->u.client.fd = -1; /* initialize the client socket */ - if(_tcp_socket_init(&tcp->u.client, aip->ai_family, tcp) != 0) + if(_tcp_socket_init(&tcp->u.client, aip->ai_family, O_NONBLOCK, + tcp) != 0) continue; #ifdef DEBUG if(aip->ai_family == AF_INET) { sa = (struct sockaddr_in *)aip->ai_addr; - fprintf(stderr, "DEBUG: %s() %s (%s:%u)\n", __func__, - "connect()", inet_ntoa(sa->sin_addr), + fprintf(stderr, "DEBUG: %s() connect(%s:%u)\n", __func__, + inet_ntoa(sa->sin_addr), ntohs(sa->sin_port)); } else - fprintf(stderr, "DEBUG: %s() %s %d\n", __func__, - "connect()", aip->ai_family); + fprintf(stderr, "DEBUG: %s() connect(%d)\n", __func__, + aip->ai_family); #endif if(connect(tcp->u.client.fd, aip->ai_addr, aip->ai_addrlen) != 0) @@ -242,14 +244,25 @@ static int _init_client(TCP * tcp, char const * name, int domain) tcp->u.client.fd, (EventIOFunc)_tcp_callback_connect, tcp); + event_loop(tcp->helper->event); } - else - /* listen for any incoming message */ - event_register_io_read(tcp->helper->event, - tcp->u.client.fd, - (EventIOFunc)_tcp_socket_callback_read, - &tcp->u.client); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() connect() => 0\n", __func__); +#endif tcp->ai_addrlen = aip->ai_addrlen; + /* listen for any incoming message */ + event_register_io_read(tcp->helper->event, tcp->u.client.fd, + (EventIOFunc)_tcp_socket_callback_read, + &tcp->u.client); + /* write pending messages if any */ + if(tcp->u.client.bufout_cnt > 0) + { + event_register_io_write(tcp->helper->event, + tcp->u.client.fd, + (EventIOFunc)_tcp_socket_callback_write, + &tcp->u.client); + event_loop(tcp->helper->event); + } break; } freeaddrinfo(tcp->ai); @@ -272,7 +285,8 @@ static int _init_server(TCP * tcp, char const * name, int domain) for(aip = tcp->ai; aip != NULL; aip = aip->ai_next) { /* create the socket */ - if(_tcp_socket_init(&tcpsocket, aip->ai_family, tcp) != 0) + if(_tcp_socket_init(&tcpsocket, aip->ai_family, O_NONBLOCK, + tcp) != 0) continue; /* XXX ugly */ tcp->u.server.fd = tcpsocket.fd; @@ -358,7 +372,26 @@ static void _destroy_server(TCP * tcp) /* tcp_client_send */ -static int _tcp_client_send(TCP * tcp, AppTransportClient * client, +static int _tcp_client_send(TCP * tcp, AppMessage * message) +{ + int ret; + Buffer * buffer; + + if(tcp->mode != ATM_CLIENT) + return -error_set_code(1, "%s", "Not a client"); + /* send the message */ + if((buffer = buffer_new(0, NULL)) == NULL) + return -1; + if((ret = appmessage_serialize(message, buffer)) == 0 + && (ret = _tcp_socket_queue(&tcp->u.client, buffer)) == 0) + event_loop(tcp->helper->event); + buffer_delete(buffer); + return ret; +} + + +/* tcp_server_send */ +static int _tcp_server_send(TCP * tcp, AppTransportClient * client, AppMessage * message) { size_t i; @@ -389,27 +422,6 @@ static int _tcp_client_send(TCP * tcp, AppTransportClient * client, } -/* tcp_send */ -static int _tcp_send(TCP * tcp, AppMessage * message) -{ - Buffer * buffer; - - if(tcp->mode != ATM_CLIENT) - return -error_set_code(1, "%s", "Not a client"); - /* send the message */ - if((buffer = buffer_new(0, NULL)) == NULL) - return -1; - if(appmessage_serialize(message, buffer) != 0 - || _tcp_socket_queue(&tcp->u.client, buffer) != 0) - { - buffer_delete(buffer); - return -1; - } - buffer_delete(buffer); - return 0; -} - - /* useful */ /* tcp_error */ static int _tcp_error(char const * message) @@ -457,23 +469,27 @@ static int _tcp_server_add_client(TCP * tcp, TCPSocket * client) /* sockets */ /* tcp_socket_init */ -static int _tcp_socket_init(TCPSocket * tcpsocket, int domain, TCP * tcp) +static int _tcp_socket_init(TCPSocket * tcpsocket, int domain, int flags, + TCP * tcp) { - int flags; + int f; if((tcpsocket->fd = socket(domain, SOCK_STREAM, 0)) < 0) return -_tcp_error("socket"); _tcp_socket_init_fd(tcpsocket, tcp, tcpsocket->fd, NULL, 0); - /* set the socket as non-blocking */ - if((flags = fcntl(tcpsocket->fd, F_GETFL)) == -1) - return -_tcp_error("fcntl"); - if((flags & O_NONBLOCK) == 0) - if(fcntl(tcpsocket->fd, F_SETFL, flags | O_NONBLOCK) == -1) + /* set the socket flags */ + if(flags != 0) + { + if((f = fcntl(tcpsocket->fd, F_GETFL)) == -1) return -_tcp_error("fcntl"); + if((f & flags) != flags) + if(fcntl(tcpsocket->fd, F_SETFL, f | flags) == -1) + return -_tcp_error("fcntl"); + } #ifdef TCP_NODELAY /* do not wait before sending any traffic */ - flags = 1; - setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &flags, sizeof(flags)); + f = 1; + setsockopt(fd, SOL_SOCKET, TCP_NODELAY, &f, sizeof(f)); #endif return 0; } @@ -652,8 +668,8 @@ static int _accept_client(TCP * tcp, int fd, struct sockaddr * sa, /* tcp_callback_connect */ static int _tcp_callback_connect(int fd, TCP * tcp) { - int res; - socklen_t s = sizeof(res); + int ret; + socklen_t s = sizeof(ret); #ifdef DEBUG fprintf(stderr, "DEBUG: %s(%d)\n", __func__, fd); @@ -662,7 +678,7 @@ static int _tcp_callback_connect(int fd, TCP * tcp) if(tcp->u.client.fd != fd) return -1; /* obtain the connection status */ - if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &res, &s) != 0) + if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &s) != 0) { error_set_code(-errno, "%s: %s", "getsockopt", strerror(errno)); close(fd); @@ -671,33 +687,28 @@ static int _tcp_callback_connect(int fd, TCP * tcp) #ifdef DEBUG fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(errno)); #endif - return -1; + ret = -1; } - if(res != 0) + else if(ret != 0) { /* the connection failed */ - error_set_code(-res, "%s: %s", "connect", strerror(res)); + error_set_code(-ret, "%s: %s", "connect", strerror(ret)); close(fd); tcp->u.client.fd = -1; /* FIXME report error */ #ifdef DEBUG - fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(res)); + fprintf(stderr, "DEBUG: %s() %s\n", __func__, strerror(ret)); #endif - return -1; + ret = -1; } - /* listen for any incoming message */ - event_register_io_read(tcp->helper->event, fd, - (EventIOFunc)_tcp_socket_callback_read, - &tcp->u.client); - /* write pending messages if any */ - if(tcp->u.client.bufout_cnt > 0) - { - event_register_io_write(tcp->helper->event, fd, - (EventIOFunc)_tcp_socket_callback_write, - &tcp->u.client); - return 0; - } - return 1; + else + /* deregister this callback */ + ret = 1; + event_loop_quit(tcp->helper->event); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() => %d\n", __func__, ret); +#endif + return ret; } @@ -850,6 +861,9 @@ static int _tcp_socket_callback_write(int fd, TCPSocket * tcpsocket) tcpsocket->bufout_cnt -= ssize; /* unregister the callback if there is nothing left to write */ if(tcpsocket->bufout_cnt == 0) + { + event_loop_quit(tcpsocket->tcp->helper->event); return 1; + } return 0; }