Update copyright dates
[src/app-framework-binder.git] / src / afb-token.c
1 /*
2  * Copyright (C) 2015-2020 "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 <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <pthread.h>
25 #include <errno.h>
26
27 #include "afb-token.h"
28
29 /**
30  * structure for recording a token
31  */
32 struct afb_token
33 {
34         /** link to the next token of the list */
35         struct afb_token *next;
36
37         /** reference of the token */
38         uint16_t refcount;
39
40         /** local numeric id of the token */
41         uint16_t id;
42
43         /** string value of the token */
44         char text[];
45 };
46
47 struct tokenset
48 {
49         struct afb_token *first;
50         pthread_mutex_t mutex;
51         uint16_t idgen;
52 };
53
54 static struct tokenset tokenset = {
55         .first = 0,
56         .mutex = PTHREAD_MUTEX_INITIALIZER,
57         .idgen = 0
58 };
59
60 static struct afb_token *searchid(uint16_t id)
61 {
62         struct afb_token *r = tokenset.first;
63         while (r && r->id != id)
64                 r = r->next;
65         return r;
66 }
67
68 /**
69  * Get a token for the given value
70  *
71  * @param token address to return the pointer to the gotten token
72  * @param tokenstring string value of the token to get
73  * @return 0 in case of success or a -errno like negative code
74  */
75 int afb_token_get(struct afb_token **token, const char *tokenstring)
76 {
77         int rc;
78         struct afb_token *tok;
79         size_t length;
80
81         /* get length of the token string */
82         length =  + strlen(tokenstring);
83
84         /* concurrency */
85         pthread_mutex_lock(&tokenset.mutex);
86
87         /* search the token */
88         tok = tokenset.first;
89         while (tok && (memcmp(tokenstring, tok->text, length) || tokenstring[length]))
90                 tok = tok->next;
91
92         /* search done */
93         if (tok) {
94                 /* found */
95                 tok = afb_token_addref(tok);
96                 rc = 0;
97         } else {
98                 /* not found, create */
99                 tok = malloc(length + 1 + sizeof *tok);
100                 if (!tok)
101                         /* creation failed */
102                         rc = -ENOMEM;
103                 else {
104                         while(!++tokenset.idgen || searchid(tokenset.idgen));
105                         tok->next = tokenset.first;
106                         tokenset.first = tok;
107                         tok->id = tokenset.idgen;
108                         tok->refcount = 1;
109                         memcpy(tok->text, tokenstring, length + 1);
110                         rc = 0;
111                 }
112         }
113         pthread_mutex_unlock(&tokenset.mutex);
114         *token = tok;
115         return rc;
116 }
117
118 /**
119  * Add a reference count to the given token
120  *
121  * @param token the token to reference
122  * @return the token with the reference added
123  */
124 struct afb_token *afb_token_addref(struct afb_token *token)
125 {
126         if (token)
127                 __atomic_add_fetch(&token->refcount, 1, __ATOMIC_RELAXED);
128         return token;
129 }
130
131 /**
132  * Remove a reference to the given token and clean the memory if needed
133  *
134  * @param token the token that is unreferenced
135  */
136 void afb_token_unref(struct afb_token *token)
137 {
138         struct afb_token **pt;
139         if (token && !__atomic_sub_fetch(&token->refcount, 1, __ATOMIC_RELAXED)) {
140                 pthread_mutex_lock(&tokenset.mutex);
141                 pt = &tokenset.first;
142                 while (*pt && *pt != token)
143                         pt = &(*pt)->next;
144                 if (*pt)
145                         *pt = token->next;
146                 pthread_mutex_unlock(&tokenset.mutex);
147                 free(token);
148         }
149 }
150
151 /**
152  * Get the string value of the token
153  *
154  * @param token the token whose string value is queried
155  * @return the string value of the token
156  */
157 const char *afb_token_string(const struct afb_token *token)
158 {
159         return token->text;
160 }
161
162 /**
163  * Get the "local" numeric id of the token
164  *
165  * @param token the token whose id is queried
166  * @return the numeric id of the token
167  */
168 uint16_t afb_token_id(const struct afb_token *token)
169 {
170         return token->id;
171 }