1 /*
2  *
3   ***** BEGIN LICENSE BLOCK *****
4 
5   Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
6   Copyright (C) 2017-2019 Olof Hagsand
7   Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
8 
9   This file is part of CLIXON.
10 
11   Licensed under the Apache License, Version 2.0 (the "License");
12   you may not use this file except in compliance with the License.
13   You may obtain a copy of the License at
14 
15     http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22 
23   Alternatively, the contents of this file may be used under the terms of
24   the GNU General Public License Version 3 or later (the "GPL"),
25   in which case the provisions of the GPL are applicable instead
26   of those above. If you wish to allow use of your version of this file only
27   under the terms of the GPL, and not to allow others to
28   use your version of this file under the terms of Apache License version 2,
29   indicate your decision by deleting the provisions above and replace them with
30   the  notice and other provisions required by the GPL. If you do not delete
31   the provisions above, a recipient may use your version of this file under
32   the terms of any one of the Apache License version 2 or the GPL.
33 
34   ***** END LICENSE BLOCK *****
35 
36  *
37  */
38 #ifdef HAVE_CONFIG_H
39 #include "clixon_config.h"
40 #endif
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdint.h>
45 #include <errno.h>
46 #include <string.h>
47 #include <assert.h>
48 #include <sys/time.h>
49 
50 #include <cligen/cligen.h>
51 
52 /* clicon */
53 #include "clixon_queue.h"
54 #include "clixon_hash.h"
55 #include "clixon_handle.h"
56 #include "clixon_log.h"
57 #include "clixon_err.h"
58 #include "clixon_yang.h"
59 #include "clixon_xml.h"
60 #include "clixon_stream.h"
61 #include "clixon_data.h"
62 #include "clixon_options.h"
63 
64 #define CLICON_MAGIC 0x99aafabe
65 
66 #define handle(h) (assert(clicon_handle_check(h)==0),(struct clicon_handle *)(h))
67 
68 /*! Internal structure of basic handle. Also header of all other handles.
69  * @note If you change here, you must also change the structs below:
70  * This is the internal definition of a "Clixon handle" which in its external
71  * form is "clicon_handle" and is used in most Clixon API calls.
72  * Some details:
73  * 1) the internal structure contains a header (defined here) whereas higher
74  *    order libs (eg cli and backend) introduce more fields appended to this
75  *    struct.
76  * 2) ch_options accessed via clicon_options() are clixon config options are
77  *    string values appearing in the XML configfile accessed with -f.
78  *    Alternatively, these could be accessed via clicon_conf_xml()
79  * 3) ch_data accessed via clicon_data() is more general purpose for any data.
80  *    that is, not only strings. And has separate namespace from options.
81  * 4) ch_db_elmnt. Only reason it is not in ch_data is its own namespace and
82  *    need to dump all hashes
83  * XXX: put ch_stream under ch_data
84  * @see struct cli_handle
85  * @see struct backend_handle
86  * @see struct restconf_handle
87  */
88 struct clicon_handle {
89     int               ch_magic;    /* magic (HDR) */
90     clicon_hash_t    *ch_copt;     /* clicon option list (HDR) */
91     clicon_hash_t    *ch_data;     /* internal clicon data (HDR) */
92     clicon_hash_t    *ch_db_elmnt; /* xml datastore element cache data */
93     event_stream_t   *ch_stream;   /* notification streams, see clixon_stream.[ch] */
94 };
95 
96 /*! Internal call to allocate a CLICON handle.
97  *
98  * @param[in]  size  Size of handle (internal) struct.
99  * @retval   h   Clicon handle
100  *
101  * There may be different variants of handles with some common options.
102  * So far the only common options is a MAGIC cookie for sanity checks and
103  * CLICON options
104  */
105 clicon_handle
clicon_handle_init0(int size)106 clicon_handle_init0(int size)
107 {
108     struct clicon_handle *ch;
109     clicon_handle         h = NULL;
110 
111     if ((ch = malloc(size)) == NULL){
112 	clicon_err(OE_UNIX, errno, "malloc");
113 	goto done;
114     }
115     memset(ch, 0, size);
116     ch->ch_magic = CLICON_MAGIC;
117     if ((ch->ch_copt = clicon_hash_init()) == NULL){
118 	clicon_handle_exit((clicon_handle)ch);
119 	goto done;
120     }
121     if ((ch->ch_data = clicon_hash_init()) == NULL){
122 	clicon_handle_exit((clicon_handle)ch);
123 	goto done;
124     }
125     if ((ch->ch_db_elmnt = clicon_hash_init()) == NULL){
126 	clicon_handle_exit((clicon_handle)ch);
127 	goto done;
128     }
129     h = (clicon_handle)ch;
130   done:
131     return h;
132 }
133 
134 /*! Basic CLICON init functions returning a handle for API access.
135  *
136  * @retval   h   Clicon handle
137  * This is the first call to CLICON basic API which returns a handle to be
138  * used in the API functions. There are other clicon_init functions for more
139  * elaborate applications (cli/backend/netconf). This should be used by the most
140  * basic applications that use CLICON lib directly.
141  */
142 clicon_handle
clicon_handle_init(void)143 clicon_handle_init(void)
144 {
145     return clicon_handle_init0(sizeof(struct clicon_handle));
146 }
147 
148 /*! Deallocate clicon handle, including freeing handle data.
149  * @param[in]  h   Clicon handle
150  * @Note: handle 'h' cannot be used in calls after this
151  */
152 int
clicon_handle_exit(clicon_handle h)153 clicon_handle_exit(clicon_handle h)
154 {
155     int                   retval = -1;
156     struct clicon_handle *ch = handle(h);
157     clicon_hash_t        *ha;
158 
159     if ((ha = clicon_options(h)) != NULL)
160 	clicon_hash_free(ha);
161     if ((ha = clicon_data(h)) != NULL)
162 	clicon_hash_free(ha);
163     if ((ha = clicon_db_elmnt(h)) != NULL)
164 	clicon_hash_free(ha);
165     stream_delete_all(h, 1);
166     free(ch);
167     retval = 0;
168     return retval;
169 }
170 
171 /*! Check struct magic number for sanity checks
172  * @param[in]  h   Clicon handle
173  * @retval     0   Sanity check OK
174  * @retval    -1   Sanity check failed
175  */
176 int
clicon_handle_check(clicon_handle h)177 clicon_handle_check(clicon_handle h)
178 {
179     /* Dont use handle macro to avoid recursion */
180     struct clicon_handle *ch = (struct clicon_handle *)(h);
181 
182     return ch->ch_magic == CLICON_MAGIC ? 0 : -1;
183 }
184 
185 /*! Return clicon options (hash-array) given a handle.
186  * @param[in]  h        Clicon handle
187  */
188 clicon_hash_t *
clicon_options(clicon_handle h)189 clicon_options(clicon_handle h)
190 {
191     struct clicon_handle *ch = handle(h);
192 
193     return ch->ch_copt;
194 }
195 
196 /*! Return clicon data (hash-array) given a handle.
197  * @param[in]  h        Clicon handle
198  */
199 clicon_hash_t *
clicon_data(clicon_handle h)200 clicon_data(clicon_handle h)
201 {
202     struct clicon_handle *ch = handle(h);
203 
204     return ch->ch_data;
205 }
206 
207 /*! Return clicon db_elmnt (hash-array) given a handle.
208  * @param[in]  h        Clicon handle
209  */
210 clicon_hash_t *
clicon_db_elmnt(clicon_handle h)211 clicon_db_elmnt(clicon_handle h)
212 {
213     struct clicon_handle *ch = handle(h);
214 
215     return ch->ch_db_elmnt;
216 }
217 
218 /*! Return stream hash-array given a clicon handle.
219  * @param[in]  h        Clicon handle
220  */
221 event_stream_t *
clicon_stream(clicon_handle h)222 clicon_stream(clicon_handle h)
223 {
224     struct clicon_handle *ch = handle(h);
225 
226     return ch->ch_stream;
227 }
228 
229 int
clicon_stream_set(clicon_handle h,event_stream_t * es)230 clicon_stream_set(clicon_handle   h,
231 		  event_stream_t *es)
232 {
233     struct clicon_handle *ch = handle(h);
234 
235     ch->ch_stream = es;
236     return 0;
237 }
238 
239 int
clicon_stream_append(clicon_handle h,event_stream_t * es)240 clicon_stream_append(clicon_handle h,
241 		     event_stream_t *es)
242 {
243     struct clicon_handle *ch = handle(h);
244 
245     ADDQ(es, ch->ch_stream);
246     return 0;
247 }
248