6bc4277960799c994f08cd2d78d6fb5fa1484468
[src/app-framework-binder.git] / src / afb-apis.c
1 /*
2  * Copyright (C) 2016, 2017 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  * Author José Bollo <jose.bollo@iot.bzh>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define _GNU_SOURCE
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include "session.h"
26 #include "verbose.h"
27 #include "afb-apis.h"
28 #include "afb-context.h"
29 #include "afb-hook.h"
30 #include <afb/afb-req-itf.h>
31
32 struct api_desc {
33         struct afb_api api;
34         const char *name;
35         size_t namelen;
36 };
37
38 static struct api_desc *apis_array = NULL;
39 static int apis_count = 0;
40
41 int afb_apis_count()
42 {
43         return apis_count;
44 }
45
46 int afb_apis_is_valid_api_name(const char *name)
47 {
48         unsigned char c;
49
50         c = (unsigned char)*name;
51         if (c == 0)
52                 return 0;
53         do {
54                 if (c < (unsigned char)'\x80') {
55                         switch(c) {
56                         default:
57                                 if (c > ' ')
58                                         break;
59                         case '"':
60                         case '#':
61                         case '%':
62                         case '&':
63                         case '\'':
64                         case '/':
65                         case '?':
66                         case '`':
67                         case '\\':
68                         case '\x7f':
69                                 return 0;
70                         }
71                 }
72                 c = (unsigned char)*++name;
73         } while(c != 0);
74         return 1;
75 }
76
77 int afb_apis_add(const char *name, struct afb_api api)
78 {
79         struct api_desc *apis;
80         int i;
81
82         /* Checks the api name */
83         if (!afb_apis_is_valid_api_name(name)) {
84                 ERROR("invalid api name forbidden (name is '%s')", name);
85                 goto error;
86         }
87
88         /* check previously existing plugin */
89         for (i = 0 ; i < apis_count ; i++) {
90                 if (!strcasecmp(apis_array[i].name, name)) {
91                         ERROR("api of name %s already exists", name);
92                         goto error;
93                 }
94         }
95
96         /* allocates enough memory */
97         apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis);
98         if (apis == NULL) {
99                 ERROR("out of memory");
100                 goto error;
101         }
102         apis_array = apis;
103
104         /* record the plugin */
105         apis = &apis_array[apis_count];
106         apis->api = api;
107         apis->namelen = strlen(name);
108         apis->name = name;
109         apis_count++;
110
111         return 0;
112
113 error:
114         return -1;
115 }
116
117 void afb_apis_call_(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
118 {
119         afb_apis_call(req, context, api, strlen(api), verb, strlen(verb));
120 }
121
122 void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
123 {
124         int i;
125         const struct api_desc *a;
126
127         req = afb_hook_req_call(req, context, api, lenapi, verb, lenverb);
128         a = apis_array;
129         for (i = 0 ; i < apis_count ; i++, a++) {
130                 if (a->namelen == lenapi && !strncasecmp(a->name, api, lenapi)) {
131                         context->api_index = i;
132                         a->api.call(a->api.closure, req, context, verb, lenverb);
133                         return;
134                 }
135         }
136         afb_req_fail(req, "fail", "api not found");
137 }
138
139 int afb_apis_start_service(const char *api, int share_session, int onneed)
140 {
141         int i;
142
143         for (i = 0 ; i < apis_count ; i++) {
144                 if (!strcasecmp(apis_array[i].name, api))
145                         return apis_array[i].api.service_start(apis_array[i].api.closure, share_session, onneed);
146         }
147         ERROR("can't find service %s", api);
148         return -1;
149 }
150
151 int afb_apis_start_all_services(int share_session)
152 {
153         int i, rc;
154
155         for (i = 0 ; i < apis_count ; i++) {
156                 rc = apis_array[i].api.service_start(apis_array[i].api.closure, share_session, 1);
157                 if (rc < 0)
158                         return rc;
159         }
160         return 0;
161 }
162