}
/* on call, propagate it to the dbus service */
-static void api_dbus_client_call(struct api_dbus *api, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb)
+static void api_dbus_client_call(void *closure, struct afb_req req, struct afb_context *context, const char *verb)
{
+ struct api_dbus *api = closure;
size_t size;
int rc;
- char *method = strndupa(verb, lenverb);
struct dbus_memo *memo;
struct sd_bus_message *msg;
/* creates the message */
msg = NULL;
- rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, method);
+ rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, verb);
if (rc < 0)
goto error;
sd_bus_message_unref(msg);
}
-static int api_dbus_service_start(struct api_dbus *api, int share_session, int onneed)
+static int api_dbus_service_start(void *closure, int share_session, int onneed)
{
+ struct api_dbus *api = closure;
+
/* not an error when onneed */
if (onneed != 0)
return 0;
/* record it as an API */
afb_api.closure = api;
- afb_api.call = (void*)api_dbus_client_call;
- afb_api.service_start = (void*)api_dbus_service_start;
+ afb_api.call = api_dbus_client_call;
+ afb_api.service_start = api_dbus_service_start;
if (afb_apis_add(api->api, afb_api) < 0)
goto error2;
dreq->refcount = 1;
areq.itf = &afb_api_dbus_req_itf;
areq.closure = dreq;
- afb_apis_call_(areq, &dreq->context, api->api, method);
+ afb_apis_call(areq, &dreq->context, api->api, method);
dbus_req_unref(dreq);
return 1;
return 1;
}
-static void call_cb(void *closure, struct afb_req req, struct afb_context *context, const char *strverb, size_t lenverb)
+static void call_cb(void *closure, struct afb_req req, struct afb_context *context, const char *strverb)
{
const struct afb_verb_desc_v1 *verb;
struct api_so_desc *desc = closure;
verb = desc->binding->v1.verbs;
- while (verb->name && (strncasecmp(verb->name, strverb, lenverb) || verb->name[lenverb]))
+ while (verb->name && strcasecmp(verb->name, strverb))
verb++;
if (!verb->name)
- afb_req_fail_f(req, "unknown-verb", "verb %.*s unknown within api %s", (int)lenverb, strverb, desc->binding->v1.prefix);
+ afb_req_fail_f(req, "unknown-verb", "verb %s unknown within api %s", strverb, desc->binding->v1.prefix);
else if (call_check(req, context, verb)) {
afb_thread_req_call(req, verb->callback, api_timeout, desc);
}
return 1;
}
-static int api_ws_write_string_nz(struct writebuf *wb, const char *value, size_t length)
-{
- uint32_t len = (uint32_t)length;
- return (size_t)len == length && ++len && api_ws_write_uint32(wb, len) && api_ws_write_put(wb, value, length) && api_ws_write_char(wb, '\0');
-}
-
static int api_ws_write_string_length(struct writebuf *wb, const char *value, size_t length)
{
uint32_t len = (uint32_t)++length;
}
/* on call, propagate it to the ws service */
-static void api_ws_client_call_cb(void * closure, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb)
+static void api_ws_client_call_cb(void * closure, struct afb_req req, struct afb_context *context, const char *verb)
{
int rc;
struct api_ws_memo *memo;
goto internal_error;
if (!api_ws_write_uint32(&wb, memo->msgid)
|| !api_ws_write_uint32(&wb, (uint32_t)context->flags)
- || !api_ws_write_string_nz(&wb, verb, lenverb)
+ || !api_ws_write_string(&wb, verb)
|| !api_ws_write_string(&wb, afb_session_uuid(context->session))
|| !api_ws_write_string_length(&wb, raw, szraw))
goto overflow;
/* makes the call */
areq.itf = &afb_api_ws_req_itf;
areq.closure = wreq;
- afb_apis_call_(areq, &wreq->context, client->api, verb);
+ afb_apis_call(areq, &wreq->context, client->api, verb);
api_ws_server_req_unref(wreq);
return;
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <errno.h>
#include "afb-session.h"
#include "verbose.h"
struct api_desc {
struct afb_api api;
const char *name;
- size_t namelen;
};
static struct api_desc *apis_array = NULL;
static int apis_count = 0;
+/**
+ * Returns the current count of APIs
+ */
int afb_apis_count()
{
return apis_count;
}
+/**
+ * Checks wether 'name' is a valid API name.
+ * @return 1 if valid, 0 otherwise
+ */
int afb_apis_is_valid_api_name(const char *name)
{
unsigned char c;
c = (unsigned char)*name;
if (c == 0)
+ /* empty names aren't valid */
return 0;
+
do {
if (c < (unsigned char)'\x80') {
switch(c) {
return 1;
}
+/**
+ * Adds the api of 'name' described by 'api'.
+ * @param name the name of the api to add
+ * @param api the api
+ * @returns 0 in case of success or -1 in case
+ * of error with errno set:
+ * - EINVAL if name isn't valid
+ * - EEXIST if name already registered
+ * - ENOMEM when out of memory
+ */
int afb_apis_add(const char *name, struct afb_api api)
{
struct api_desc *apis;
/* Checks the api name */
if (!afb_apis_is_valid_api_name(name)) {
ERROR("invalid api name forbidden (name is '%s')", name);
+ errno = EINVAL;
goto error;
}
for (i = 0 ; i < apis_count ; i++) {
if (!strcasecmp(apis_array[i].name, name)) {
ERROR("api of name %s already exists", name);
+ errno = EEXIST;
goto error;
}
}
apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis);
if (apis == NULL) {
ERROR("out of memory");
+ errno = ENOMEM;
goto error;
}
apis_array = apis;
/* record the plugin */
apis = &apis_array[apis_count];
apis->api = api;
- apis->namelen = strlen(name);
apis->name = name;
apis_count++;
return -1;
}
-void afb_apis_call_(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
-{
- afb_apis_call(req, context, api, strlen(api), verb, strlen(verb));
-}
-
-void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
{
int i;
const struct api_desc *a;
- req = afb_hook_req_call(req, context, api, lenapi, verb, lenverb);
+ req = afb_hook_req_call(req, context, api, verb);
a = apis_array;
for (i = 0 ; i < apis_count ; i++, a++) {
- if (a->namelen == lenapi && !strncasecmp(a->name, api, lenapi)) {
+ if (!strcasecmp(a->name, api)) {
context->api_index = i;
- a->api.call(a->api.closure, req, context, verb, lenverb);
+ a->api.call(a->api.closure, req, context, verb);
return;
}
}
struct afb_api
{
void *closure;
- void (*call)(void *closure, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb);
+ void (*call)(void *closure, struct afb_req req, struct afb_context *context, const char *verb);
int (*service_start)(void *closure, int share_session, int onneed);
};
extern int afb_apis_start_all_services(int share_session);
extern int afb_apis_start_service(const char *name, int share_session, int onneed);
-extern void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
-extern void afb_apis_call_(struct afb_req req, struct afb_context *context, const char *api, const char *verb);
+extern void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, const char *verb);
}
}
-static struct afb_hook_req *hook_req_create(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+static struct afb_hook_req *hook_req_create(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
{
+ int len;
+ char name[257];
unsigned id;
struct afb_hook_req *tr;
- tr = malloc(sizeof *tr + 8 + lenapi + lenverb);
- if (tr != NULL) {
- /* get the call id */
- id = ++hook_count;
- if (id == 1000000)
- id = hook_count = 1;
-
- /* init hook */
- tr->observers = NULL;
- tr->refcount = 1;
- tr->context = context;
- tr->req = req;
- afb_req_addref(req);
- snprintf(tr->name, 9 + lenapi + lenverb, "%06d:%.*s/%.*s", id, (int)lenapi, api, (int)lenverb, verb);
+ /* get the call id */
+ id = ++hook_count;
+ if (id == 1000000)
+ id = hook_count = 1;
+
+ /* creates the name */
+ len = snprintf(name, sizeof name, "%06d:%s/%s", id, api, verb);
+ if (len < 0 || (size_t)len >= sizeof name) {
+ tr = NULL;
+ } else {
+ tr = malloc(sizeof *tr + (size_t)len);
+ if (tr != NULL) {
+ /* init hook */
+ tr->observers = NULL;
+ tr->refcount = 1;
+ tr->context = context;
+ tr->req = req;
+ afb_req_addref(req);
+ memcpy(tr->name, name, (size_t)(len + 1));
+ }
}
return tr;
}
* section:
*****************************************************************************/
-struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
{
int add;
struct afb_hook_req *tr;
do {
add = (hook->flags & afb_hook_flags_req_all) != 0
&& (!hook->session || hook->session == context->session)
- && (!hook->api || !(memcmp(hook->api, api, lenapi) || hook->api[lenapi]))
- && (!hook->verb || !(memcmp(hook->verb, verb, lenverb) || hook->verb[lenverb]));
+ && (!hook->api || !strcasecmp(hook->api, api))
+ && (!hook->verb || !strcasecmp(hook->verb, verb));
if (add) {
if (!tr)
- tr = hook_req_create(req, context, api, lenapi, verb, lenverb);
+ tr = hook_req_create(req, context, api, verb);
if (tr)
hook_req_add_observer(tr, hook);
}
void (*hook_req_subcall_result)(void * closure, const struct afb_hook_req *tr, int status, struct json_object *result);
};
-extern struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
+extern struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, const char *verb);
extern struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct afb_session *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure);
extern struct afb_hook *afb_hook_addref(struct afb_hook *spec);
}
afb_context_disconnect(&hreq->context);
json_object_put(hreq->json);
+ free(hreq->api);
+ free(hreq->verb);
free(hreq);
}
afb_subcall(&hreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_hreq_req_itf, .closure = hreq });
}
+int afb_hreq_init_req_call(struct afb_hreq *hreq, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+{
+ free(hreq->api);
+ free(hreq->verb);
+ hreq->api = strndup(api, lenapi);
+ hreq->verb = strndup(verb, lenverb);
+ if (hreq->api == NULL || hreq->verb == NULL) {
+ ERROR("Out of memory");
+ errno = ENOMEM;
+ return -1;
+ }
+ return afb_hreq_init_context(hreq);
+}
+
int afb_hreq_init_context(struct afb_hreq *hreq)
{
const char *uuid;
struct hreq_data *data;
struct json_object *json;
int upgrade;
+ char *api;
+ char *verb;
};
extern int afb_hreq_unprefix(struct afb_hreq *request, const char *prefix, size_t length);
extern struct afb_req afb_hreq_to_req(struct afb_hreq *hreq);
+extern int afb_hreq_init_req_call(struct afb_hreq *hreq, const char *api, size_t lenapi, const char *verb, size_t lenverb);
+
extern int afb_hreq_init_context(struct afb_hreq *hreq);
extern int afb_hreq_init_cookie(int port, const char *path, int maxage);
if (!(*api && *verb && lenapi && lenverb))
return 0;
- if (afb_hreq_init_context(hreq) < 0)
+ if (afb_hreq_init_req_call(hreq, api, lenapi, verb, lenverb) < 0)
afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
else
- afb_apis_call(afb_hreq_to_req(hreq), &hreq->context, api, lenapi, verb, lenverb);
+ afb_apis_call(afb_hreq_to_req(hreq), &hreq->context, hreq->api, hreq->verb);
return 1;
}
subcall->closure = closure;
subcall->context = *context;
afb_req_addref(req);
- afb_apis_call_((struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall }, &subcall->context, api, verb);
+ afb_apis_call((struct afb_req){ .itf = &afb_subcall_req_itf, .closure = subcall }, &subcall->context, api, verb);
subcall_unref(subcall);
}
};
/* functions for services */
-static void svc_on_event(struct afb_svc *svc, const char *event, int eventid, struct json_object *object);
-static void svc_call(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args,
- void (*callback)(void*, int, struct json_object*), void *closure);
+static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object);
+static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args,
+ void (*callback)(void*, int, struct json_object*), void *cbclosure);
/* the interface for services */
static const struct afb_service_itf service_itf = {
- .call = (void*)svc_call
+ .call = svc_call
};
/* the interface for events */
static const struct afb_evt_itf evt_itf = {
- .broadcast = (void*)svc_on_event,
- .push = (void*)svc_on_event
+ .broadcast = svc_on_event,
+ .push = svc_on_event
};
/* functions for requests of services */
/*
* Propagates the event to the service
*/
-static void svc_on_event(struct afb_svc *svc, const char *event, int eventid, struct json_object *object)
+static void svc_on_event(void *closure, const char *event, int eventid, struct json_object *object)
{
+ struct afb_svc *svc = closure;
svc->on_event(event, object);
json_object_put(object);
}
/*
* Initiates a call for the service
*/
-static void svc_call(struct afb_svc *svc, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure)
+static void svc_call(void *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cbclosure)
{
+ struct afb_svc *svc = closure;
struct svc_req *svcreq;
/* allocates the request */
svcreq = malloc(sizeof *svcreq);
if (svcreq == NULL)
- return afb_subcall_internal_error(callback, closure);
+ return afb_subcall_internal_error(callback, cbclosure);
/* initialises the request */
afb_context_init(&svcreq->context, svc->session, NULL);
svcreq->refcount = 1;
/* makes the call */
- afb_subcall(&svcreq->context, api, verb, args, callback, closure, (struct afb_req){ .itf = &afb_svc_req_itf, .closure = svcreq });
+ afb_subcall(&svcreq->context, api, verb, args, callback, cbclosure, (struct afb_req){ .itf = &afb_svc_req_itf, .closure = svcreq });
/* terminates and frees ressources if needed */
svcreq_unref(svcreq);
/* emits the call */
r.closure = wsreq;
r.itf = &afb_ws_json1_req_itf;
- afb_apis_call_(r, &wsreq->context, api, verb);
+ afb_apis_call(r, &wsreq->context, api, verb);
wsreq_unref(wsreq);
}