Attempt to really re-implement the AppClient

This is still very messy... :(
This commit is contained in:
Pierre Pronchery 2020-03-25 09:33:20 +01:00
parent 607c9b00f3
commit 688d40c1ad
6 changed files with 328 additions and 130 deletions

View File

@ -18,6 +18,7 @@
#ifndef LIBAPP_APP_APPCLIENT_H
# define LIBAPP_APP_APPCLIENT_H
# include <stdarg.h>
# include <stdint.h>
# include <System/event.h>
# include <System/variable.h>
@ -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 */

View File

@ -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;
}

View File

@ -26,6 +26,7 @@
#include <errno.h>
#include <System.h>
#include <System/Marshall.h>
#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;
}

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
}