X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fapp-framework-binder.git;a=blobdiff_plain;f=src%2Fafb-api-ws.c;h=4ea8610e801b19406984e39ada70603e390a6dbf;hp=24ffefefdcb97b59869476ed912e2a6f12c18690;hb=65353dce81a629e042800bb7b86fcd869a76727e;hpb=10aa15afc5bc7321d0049823dd173dda11ff3724 diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c index 24ffefef..4ea8610e 100644 --- a/src/afb-api-ws.c +++ b/src/afb-api-ws.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 "IoT.bzh" + * Copyright (C) 2015-2020 "IoT.bzh" * Author José Bollo * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -38,85 +38,61 @@ #include "verbose.h" #include "fdev.h" -struct api_ws +struct api_ws_server { - char *uri; /* uri of the object for the API */ - char *api; /* api name of the interface */ - struct fdev *fdev; /* fdev handler */ - struct afb_apiset *apiset; + struct afb_apiset *apiset; /* the apiset for calling */ + struct fdev *fdev; /* fdev handler */ + uint16_t offapi; /* api name of the interface */ + char uri[]; /* the uri of the server socket */ }; +/******************************************************************************/ +/*** C L I E N T ***/ /******************************************************************************/ -/* - * create a structure api_ws not connected to the 'uri'. - */ -static struct api_ws *api_ws_make(const char *uri) +static struct fdev *reopen_client(void *closure) { - struct api_ws *api; - size_t length; - - /* allocates the structure */ - length = strlen(uri); - api = calloc(1, sizeof *api + 1 + length); - if (api == NULL) { - errno = ENOMEM; - goto error; - } - - /* uri is copied after the struct */ - api->uri = (char*)(api+1); - memcpy(api->uri, uri, length + 1); - - /* api name is at the end of the uri */ - while (length && uri[length - 1] != '/' && uri[length - 1] != ':') - length = length - 1; - api->api = &api->uri[length]; - if (api->api == NULL || !afb_api_is_valid_name(api->api)) { - errno = EINVAL; - goto error2; - } - - return api; - -error2: - free(api); -error: - return NULL; + const char *uri = closure; + return afb_socket_open_fdev(uri, 0); } -/**********************************************************************************/ - int afb_api_ws_add_client(const char *uri, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong) { - struct api_ws *apiws; struct afb_stub_ws *stubws; + struct fdev *fdev; + const char *api; - /* create the ws client api */ - apiws = api_ws_make(uri); - if (apiws == NULL) + /* check the api name */ + api = afb_socket_api(uri); + if (api == NULL || !afb_api_is_valid_name(api)) { + ERROR("invalid (too long) ws client uri %s", uri); + errno = EINVAL; goto error; - - /* connect to the service */ - apiws->fdev = afb_socket_open(apiws->uri, 0); - if (!apiws->fdev) - goto error2; - - stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, call_set); - if (!stubws) { - ERROR("can't setup client ws service to %s", apiws->uri); - goto error3; } - if (afb_stub_ws_client_add(stubws, declare_set) < 0) { - ERROR("can't add the client to the apiset for service %s", apiws->uri); - goto error3; + + /* open the socket */ + fdev = afb_socket_open_fdev(uri, 0); + if (fdev) { + /* create the client stub */ + stubws = afb_stub_ws_create_client(fdev, api, call_set); + if (!stubws) { + ERROR("can't setup client ws service to %s", uri); + fdev_unref(fdev); + } else { + if (afb_stub_ws_client_add(stubws, declare_set) >= 0) { +#if 1 + /* it is asserted here that uri is never released */ + afb_stub_ws_client_robustify(stubws, reopen_client, (void*)uri, NULL); +#else + /* it is asserted here that uri is released, so use a copy */ + afb_stub_ws_client_robustify(stubws, reopen_client, strdup(uri), free); +#endif + return 0; + } + ERROR("can't add the client to the apiset for service %s", uri); + afb_stub_ws_unref(stubws); + } } - free(apiws); - return 0; -error3: - afb_stub_ws_unref(stubws); -error2: - free(apiws); error: return -!!strong; } @@ -131,17 +107,17 @@ int afb_api_ws_add_client_weak(const char *uri, struct afb_apiset *declare_set, return afb_api_ws_add_client(uri, declare_set, call_set, 0); } -static int api_ws_server_accept_client(struct api_ws *apiws, struct fdev *fdev) -{ - return -!afb_stub_ws_create_server(fdev, apiws->api, apiws->apiset); -} +/*****************************************************************************/ +/*** S E R V E R ***/ +/******************************************************************************/ -static void api_ws_server_accept(struct api_ws *apiws) +static void api_ws_server_accept(struct api_ws_server *apiws) { - int rc, fd; + int fd; struct sockaddr addr; socklen_t lenaddr; struct fdev *fdev; + struct afb_stub_ws *server; lenaddr = (socklen_t)sizeof addr; fd = accept(fdev_fd(apiws->fdev), &addr, &lenaddr); @@ -153,38 +129,40 @@ static void api_ws_server_accept(struct api_ws *apiws) ERROR("can't hold accepted connection to %s: %m", apiws->uri); close(fd); } else { - rc = api_ws_server_accept_client(apiws, fdev); - if (rc < 0) + server = afb_stub_ws_create_server(fdev, &apiws->uri[apiws->offapi], apiws->apiset); + if (server) + afb_stub_ws_set_on_hangup(server, afb_stub_ws_unref); + else ERROR("can't serve accepted connection to %s: %m", apiws->uri); } } } -static int api_ws_server_connect(struct api_ws *apiws); +static int api_ws_server_connect(struct api_ws_server *apiws); static void api_ws_server_listen_callback(void *closure, uint32_t revents, struct fdev *fdev) { - struct api_ws *apiws = closure; + struct api_ws_server *apiws = closure; - if ((revents & EPOLLIN) != 0) - api_ws_server_accept(apiws); if ((revents & EPOLLHUP) != 0) api_ws_server_connect(apiws); + else if ((revents & EPOLLIN) != 0) + api_ws_server_accept(apiws); } -static void api_ws_server_disconnect(struct api_ws *apiws) +static void api_ws_server_disconnect(struct api_ws_server *apiws) { fdev_unref(apiws->fdev); apiws->fdev = 0; } -static int api_ws_server_connect(struct api_ws *apiws) +static int api_ws_server_connect(struct api_ws_server *apiws) { /* ensure disconnected */ api_ws_server_disconnect(apiws); /* request the service object name */ - apiws->fdev = afb_socket_open(apiws->uri, 1); + apiws->fdev = afb_socket_open_fdev(apiws->uri, 1); if (!apiws->fdev) ERROR("can't create socket %s", apiws->uri); else { @@ -200,28 +178,59 @@ static int api_ws_server_connect(struct api_ws *apiws) int afb_api_ws_add_server(const char *uri, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; - struct api_ws *apiws; + const char *api; + struct api_ws_server *apiws; + size_t luri, lapi, extra; + + /* check the size */ + luri = strlen(uri); + if (luri > 4000) { + ERROR("can't create socket %s", uri); + errno = E2BIG; + return -1; + } - /* creates the ws api object */ - apiws = api_ws_make(uri); - if (apiws == NULL) + /* check the api name */ + api = afb_socket_api(uri); + if (api == NULL || !afb_api_is_valid_name(api)) { + ERROR("invalid api name in ws uri %s", uri); + errno = EINVAL; goto error; + } /* check api name */ - if (!afb_apiset_lookup(call_set, apiws->api, 1)) { - ERROR("Can't provide ws-server for %s: API %s doesn't exist", uri, apiws->api); - goto error2; + if (!afb_apiset_lookup(call_set, api, 1)) { + ERROR("Can't provide ws-server for URI %s: API %s doesn't exist", uri, api); + errno = ENOENT; + goto error; } - /* connect for serving */ - rc = api_ws_server_connect(apiws); - if (rc < 0) - goto error2; + /* make the structure */ + lapi = strlen(api); + extra = luri == (api - uri) + lapi ? 0 : lapi + 1; + apiws = malloc(sizeof * apiws + 1 + luri + extra); + if (!apiws) { + ERROR("out of memory"); + errno = ENOMEM; + goto error; + } apiws->apiset = afb_apiset_addref(call_set); - return 0; + apiws->fdev = 0; + strcpy(apiws->uri, uri); + if (!extra) + apiws->offapi = (uint16_t)(api - uri); + else { + apiws->offapi = (uint16_t)(luri + 1); + strcpy(&apiws->uri[apiws->offapi], api); + } + + /* connect for serving */ + rc = api_ws_server_connect(apiws); + if (rc >= 0) + return 0; -error2: + afb_apiset_unref(apiws->apiset); free(apiws); error: return -1;