RDK Documentation (Open Sourced RDK Components)
hostIf_jsonReqHandlerThread.cpp
Go to the documentation of this file.
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 /**
21  * @file hostIf_jsonReqHandlerThread.cpp
22  * @brief The header file provides HostIf IP json request handler information APIs.
23  */
24 
25 /**
26 * @defgroup tr69hostif
27 * @{
28 * @defgroup hostif
29 * @{
30 **/
31 
32 
33 #include "hostIf_jsonReqHandler.h"
34 #include "hostIf_msgHandler.h"
35 #include "hostIf_utils.h"
36 #include <glib.h>
37 #include "libsoup-2.4/libsoup/soup.h"
38 #include <yajl/yajl_parse.h>
39 #include <yajl/yajl_gen.h>
40 extern T_ARGLIST argList;
41 
42 typedef enum { STATE_BEFORE = 0, STATE_PARAM, STATE_PROCESSING, STATE_DONE } state_t;
43 
44 typedef struct {
45  GList *list;
46  state_t state;
47  gboolean grabString;
49 
50 SoupServer *server = NULL;
51 
52 
53 /*
54  * YAJL Parsing functions
55  */
56 
57 /* First, a couple nop's. We don't care about these values. Just proceed */
58 static int process_null(void * ctx) {
59  return 1;
60 }
61 static int process_boolean(void * ctx, int boolVal) {
62  return 1;
63 }
64 static int process_integer(void * ctx, long long integerVal) {
65  return 1;
66 }
67 static int process_double(void * ctx, double doubleVal) {
68  return 1;
69 }
70 static int process_number(void * ctx, const char * numberVal, size_t numberLen) {
71  return 1;
72 }
73 
74 /*
75  * Grab a string, assuming we're in the right mode.
76  */
77 static int process_string(void * ctx, const unsigned char * stringVal, size_t stringLen)
78 {
79  parser_state_t *context = (parser_state_t *) ctx;
80 
81  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"Process string: %d\n", context->state);
82  if ((context->state == STATE_PROCESSING) && (context->grabString) && (stringLen<TR69HOSTIFMGR_MAX_PARAM_LEN-1))
83  {
84  char *string = strndup((const char *)stringVal, stringLen);
85  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"Adding string %s\n", string);
86  context->list = g_list_append(context->list, string);
87  context->grabString = FALSE;
88  }
89 
90  return 1;
91 }
92 
93 static int process_start_map(void * ctx)
94 {
95  return 1;
96 }
97 
98 static int process_map_key(void * ctx, const unsigned char * key, size_t stringLen)
99 {
100  parser_state_t *context = (parser_state_t *) ctx;
101  char buffer[256];
102 
103  //RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"Process Map Key: %d %s\n", context->state, strof(key, stringLen));
104  if ((context->state == STATE_BEFORE) &&
105  (stringLen == strlen("paramList")) &&
106  (strncmp("paramList", (const char *) key, stringLen) == 0))
107  {
108  context->state = STATE_PARAM;
109  }
110  else if ((context->state == STATE_PROCESSING) &&
111  (stringLen == 4) &&
112  (strncmp("name", (const char *) key, stringLen) == 0))
113  {
114  context->grabString = TRUE;
115  }
116  else
117  {
118  context->grabString = FALSE;
119  }
120  return 1;
121 }
122 
123 static int process_end_map(void * ctx)
124 {
125  // Do nothing right now
126  return 1;
127 }
128 
129 static int process_start_array(void * ctx)
130 {
131  parser_state_t *context = (parser_state_t *) ctx;
132  if (context->state == STATE_PARAM)
133  {
134  context->state = STATE_PROCESSING;
135  }
136  return 1;
137 }
138 
139 static int process_end_array(void * ctx)
140 {
141  parser_state_t *context = (parser_state_t *) ctx;
142  if ((context->state == STATE_PROCESSING) || (context->state == STATE_PARAM))
143  {
144  context->state = STATE_DONE;
145  }
146  return 1;
147 }
148 
149 static yajl_callbacks callbacks = {
150  process_null,
151  process_boolean,
152  process_integer,
153  process_double,
154  process_number,
155  process_string,
156  process_start_map,
157  process_map_key,
158  process_end_map,
159  process_start_array,
160  process_end_array,
161 };
162 
163 // Specify that we use the GLib memory allocation primitives.
164 /*
165 static yajl_alloc_funcs allocFuncs = {
166  g_malloc,
167  g_realloc,
168  g_free
169 };
170 */
171 
172 void *jsonIfHandlerThread(void *msg)
173 {
174  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
175 
176  /*Start HTTP server */
178 
179  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
180  return NULL;
181 }
182 
183 
184 GList *
185 hostIf_HTTPJsonParse(const unsigned char *message, int length)
186 {
187  parser_state_t context = { NULL, STATE_BEFORE, FALSE };
188  yajl_status stat;
189 
190  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
191 #ifndef YAJL_V2
192  yajl_handle parser = yajl_alloc(&callbacks, NULL, /* &allocFuncs */ NULL, (void *) (&context));
193 #else
194  yajl_handle parser = yajl_alloc(&callbacks, /* &allocFuncs */ NULL, (void *) (&context));
195 #endif
196  //yajl_handle parser = yajl_alloc(&callbacks, NULL, NULL);
197  stat = yajl_parse(parser, message, length);
198  if (stat != yajl_status_ok)
199  {
200  RDK_LOG(RDK_LOG_ERROR,LOG_TR69HOSTIF,"[%s:%s] Failed to parse in yajl_parse()\n", __FUNCTION__, __FILE__);
201  } else {
202 #ifndef YAJL_V2
203  stat = yajl_parse_complete(parser);
204 #else
205  stat = yajl_complete_parse(parser);
206 #endif
207  if (stat != yajl_status_ok)
208  {
209  RDK_LOG(RDK_LOG_ERROR,LOG_TR69HOSTIF,"[%s:%s] Failed to parse in yajl_parse_complete()\n", __FUNCTION__, __FILE__);
210  }
211  }
212  if (parser) {
213  yajl_free(parser);
214  }
215  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
216  return context.list;
217 }
218 
219 
221  SoupServer *server,
222  SoupMessage *msg,
223  const gchar *path,
224  GHashTable *query,
225  SoupClientContext *client,
226  gpointer user_data)
227 {
228  GList *params;
229  GList *requestList = NULL;
230 
231  bool ret = true;
232  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
233 
234  if (!msg->request_body ||
235  !msg->request_body->data ||
236  !msg->request_body->length)
237  {
238  soup_message_set_status_full (msg, SOUP_STATUS_BAD_REQUEST, "No request data.");
239  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting.. Failed due to no message data.\n", __FUNCTION__, __FILE__);
240  return;
241  }
242 
243  params = hostIf_HTTPJsonParse((const unsigned char *) msg->request_body->data, msg->request_body->length);
244  if (!params)
245  {
246  soup_message_set_status_full (msg, SOUP_STATUS_BAD_REQUEST, "No request data.");
247  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting... Failed due to Parse HTTP Json messages. \n", __FUNCTION__, __FILE__);
248  return;
249  }
250 
251  yajl_gen json;
252 #ifndef YAJL_V2
253  json = yajl_gen_alloc(/* &allocFuncs */ NULL, NULL);
254 #else
255  json = yajl_gen_alloc(NULL);
256 #endif
257  if (!json)
258  {
259  soup_message_set_status_full (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "Cannot create return object");
260  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting.. Failed to create json object\n", __FUNCTION__, __FILE__);
261  return;
262  }
263 
264  yajl_gen_map_open(json);
265  yajl_gen_string(json, (const unsigned char *) "paramList", 9);
266  yajl_gen_array_open(json);
267 
268  GList *l = params;
269  while (l)
270  {
271  HOSTIF_MsgData_t *param = (HOSTIF_MsgData_t *) g_malloc0(sizeof(HOSTIF_MsgData_t));
272  strncpy( param->paramName,(char *) l->data,TR69HOSTIFMGR_MAX_PARAM_LEN );
273  // requestList = g_list_append(requestList, param);
274 
275  if (hostIf_GetMsgHandler(param) == OK) //We are expecting on Get call from JSON
276  {
277  yajl_gen_map_open(json);
278  yajl_gen_string(json, (const unsigned char *) "name", 4);
279  yajl_gen_string(json, (const unsigned char *) param->paramName, strlen(param->paramName));
280 
281  yajl_gen_string(json, (const unsigned char *) "value", 5);
282  switch (param->paramtype) {
283  case hostIf_StringType:
284  yajl_gen_string(json, (const unsigned char*) param->paramValue, strlen((char*)param->paramValue));
285  break;
286  case hostIf_IntegerType:
287  case hostIf_UnsignedIntType:
288  yajl_gen_integer(json, get_int(param->paramValue));
289  break;
290  case hostIf_UnsignedLongType:
291  yajl_gen_integer(json, get_ulong(param->paramValue));
292  break;
293  case hostIf_BooleanType:
294  yajl_gen_bool(json, get_boolean(param->paramValue));
295  break;
296  case hostIf_DateTimeType:
297  // TODO: What to do here? What is the actual data representation?
298  yajl_gen_string(json, (const unsigned char *) "Unknown", 7);
299  break;
300  default:
301  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"Unknown data type: %d", param->paramtype);
302  break;
303  }
304 
305  yajl_gen_map_close(json);
306  }
307  hostIf_Free_stMsgData(param);
308 
309 
310  l = l->next;
311  }
312  // Free the list, but do NOT deallocate the strings. They're now in the requestList
313  g_list_free_full(params, g_free);
314  params = NULL;
315 
316  // Close out the structures
317  yajl_gen_array_close(json);
318  yajl_gen_map_close(json);
319 
320  // Get the string
321  const unsigned char *buf;
322  size_t len;
323  yajl_gen_get_buf(json, &buf, &len);
324 
325  // TODO: What is the correct MIME type?
326  soup_message_set_response(msg, (const char *) "application/json", SOUP_MEMORY_COPY, (const char *) buf, len);
327  soup_message_set_status (msg, SOUP_STATUS_OK);
328 
329  yajl_gen_free(json);
330 
331  //json_t* incommingReq = NULL;
332  //json_t* outRes = NULL;
333  // ret = hostIf_JsonReqResHandler (incommingReq, outRes);
334  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
335  return;
336 }
337 
338 /**
339  * @brief This API is used to initialize and start the HTTP server process. It use to serve the
340  * http json client request.
341  * @ingroup TR-069HOSTIF_JSON_REQHANDLER_API
342  */
344 {
345  GError *error = NULL;
346  guint port = argList.httpPort;
347  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
348 
349  g_type_init();
350 
351  if(server == NULL)
352  //server = soup_server_new (SOUP_SERVER_PORT, port, NULL);
353  server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "hostif", NULL);
354 
355  if (!server)
356  {
357  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"SERVER: Could not create server.\n");
358  // TODO: Return code
359  return;
360  }
361  else
362  {
363  soup_server_add_handler (server, "/", hostIf_HTTPJsonMsgHandler, NULL, NULL);
364 
365  if(FALSE == soup_server_listen_local (server, port, SOUP_SERVER_LISTEN_IPV4_ONLY, &error))
366  {
367  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "SERVER: failed in soup_server_listen_local. (%s).\n", error->message);
368  }
369 
370  //soup_server_run(server);
371  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"SERVER: Started server successfully.\n");
372  }
373 
374  RDK_LOG(RDK_LOG_TRACE1,LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
375 }
376 
377 /**
378  * @brief This function is used to stop the http server. To stop the server
379  * it disconnects the soup server with the server handle.
380  * @ingroup TR-069HOSTIF_JSON_REQHANDLER_API
381  */
383 {
384  if(server) {
385  soup_server_disconnect(server);
386  RDK_LOG(RDK_LOG_INFO,LOG_TR69HOSTIF,"SERVER: Stopped server successfully.\n");
387  }
388 }
389 
390 
391 
392 /** @} */
393 /** @} */
_HostIf_MsgData_t
Definition: hostIf_tr69ReqHandler.h:170
hostIf_HttpServerStart
void hostIf_HttpServerStart()
This API is used to initialize and start the HTTP server process. It use to serve the http json clien...
Definition: hostIf_jsonReqHandlerThread.cpp:343
_HostIf_MsgData_t::paramtype
HostIf_ParamType_t paramtype
Definition: hostIf_tr69ReqHandler.h:177
RDK_LOG
#define RDK_LOG
Definition: rdk_debug.h:258
_HostIf_MsgData_t::paramName
char paramName[(4 *1024)]
Definition: hostIf_tr69ReqHandler.h:171
hostIf_HttpServerStop
void hostIf_HttpServerStop()
It handles the request and response IARM member processes.
Definition: hostIf_jsonReqHandlerThread.cpp:382
hostIf_jsonReqHandler.h
The header file provides HostIf IP json request handler information APIs.
hostIf_HTTPJsonMsgHandler
bool hostIf_HTTPJsonMsgHandler()
Handle the Post message from HTTP Json client.
_HostIf_MsgData_t::paramValue
char paramValue[(4 *1024)]
Definition: hostIf_tr69ReqHandler.h:172
argsList
Definition: hostIf_main.h:126
parser_state_t
Definition: hostIf_jsonReqHandlerThread.cpp:44
hostIf_msgHandler.h
The header file provides HostIf message handler information APIs.
TRUE
#define TRUE
Defines for TRUE/FALSE/ENABLE flags.
Definition: wifi_common_hal.h:199