RDK Documentation (Open Sourced RDK Components)
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
http_server.cpp
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 2018 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 #include <glib.h>
21 #include <cJSON.h>
22 #include <stdlib.h>
23 #include <fstream>
24 
25 #ifdef __cplusplus
26 extern "C"
27 {
28 #endif
29 #include <wdmp-c.h>
30 #include <wdmp_internal.h>
31 #ifdef __cplusplus
32 }
33 #endif
34 
35 #include "hostIf_main.h"
36 #include "hostIf_utils.h"
37 #include "http_server.h"
38 #include "waldb.h"
39 #include "request_handler.h"
40 #include "libsoup/soup.h"
41 #include <mutex>
42 #include <condition_variable>
43 
44 extern std::mutex mtx_httpServerThreadDone;
45 extern std::condition_variable cv_httpServerThreadDone;
46 extern bool httpServerThreadDone;
47 
48 extern T_ARGLIST argList;
49 static SoupServer *http_server = NULL;
50 
51 static void HTTPRequestHandler(
52  SoupServer *server,
53  SoupMessage *msg,
54  const char *path,
55  GHashTable *query,
56  SoupClientContext *client,
57  void *user_data)
58 {
59  cJSON *jsonRequest = NULL;
60  cJSON *jsonResponse = NULL;
61  req_struct *reqSt = NULL;
62  res_struct *respSt = NULL;
63 
64  struct timespec start,end,*startPtr,*endPtr;
65  startPtr = &start;
66  endPtr = &end;
67 
68  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
69  getCurrentTime(startPtr);
70  if (!msg->request_body ||
71  !msg->request_body->data ||
72  !msg->request_body->length)
73  {
74  soup_message_set_status_full (msg, SOUP_STATUS_BAD_REQUEST, "No request data.");
75  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Failed due to no message data.\n", __FUNCTION__, __FILE__);
76  return;
77  }
78 
79  const char *pcCallerID = (char *)soup_message_headers_get_one(msg->request_headers, "CallerID");
80 
81  jsonRequest = cJSON_Parse((const char *) msg->request_body->data);
82 
83  if(jsonRequest)
84  {
85  reqSt = (req_struct *)malloc(sizeof(req_struct));
86  if(reqSt == NULL)
87  {
88  soup_message_set_status_full (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "Cannot create return object");
89  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Failed to create req_struct\n", __FUNCTION__, __FILE__);
90  return;
91  }
92  memset(reqSt, 0, sizeof(req_struct));
93 
94  if(!strcmp(msg->method, "GET"))
95  {
96  if(!pcCallerID || !strlen(pcCallerID))
97  {
98  pcCallerID = "Unknown";
99  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF, "[%s:%s] Unknown Caller ID, GET is allowed by default\n", __FUNCTION__, __FILE__);
100  }
101  else
102  RDK_LOG(RDK_LOG_DEBUG, LOG_TR69HOSTIF,"[%s:%s] GET with CallerID : %s..\n", __FUNCTION__, __FILE__, pcCallerID);
103  parse_get_request(jsonRequest, &reqSt, WDMP_TR181);
104  respSt = handleRequest(pcCallerID, reqSt);
105  if(respSt)
106  {
107  jsonResponse = cJSON_CreateObject();
108  wdmp_form_get_response(respSt, jsonResponse);
109 
110  // WDMP Code sets a generic statusCode, the following lines replace it with an actual error code.
111  int new_st_code = 0;
112 
113  for(int paramIndex = 0; paramIndex < respSt->paramCnt; paramIndex++)
114  {
115  if(respSt->retStatus[paramIndex] != 0 || paramIndex == respSt->paramCnt-1)
116  {
117  new_st_code = respSt->retStatus[paramIndex];
118  break;
119  }
120  }
121  cJSON * stcode = cJSON_GetObjectItem(jsonResponse, "statusCode");
122  if( NULL != stcode)
123  {
124  cJSON_SetIntValue(stcode, new_st_code);
125  }
126  }
127  else
128  {
129  soup_message_set_status_full (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "Invalid request format");
130  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Request couldn't be processed\n", __FUNCTION__, __FILE__);
131  return;
132  }
133  }
134  else if(!strcmp(msg->method, "POST"))
135  {
136  if(!pcCallerID || !strlen(pcCallerID))
137  {
138  soup_message_set_status_full (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "POST Not Allowed without CallerID");
139  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. POST operation not allowed with unknown CallerID\n", __FUNCTION__, __FILE__);
140  wdmp_free_req_struct(reqSt);
141  reqSt = NULL;
142  return;
143  }
144  else
145  RDK_LOG(RDK_LOG_DEBUG, LOG_TR69HOSTIF,"[%s:%s] POST with CallerID : %s..\n", __FUNCTION__, __FILE__, pcCallerID);
146 
147  parse_set_request(jsonRequest, &reqSt, WDMP_TR181);
148  RDK_LOG(RDK_LOG_DEBUG, LOG_TR69HOSTIF,"Calling handleRequest...\n");
149  respSt = handleRequest(pcCallerID, reqSt);
150  if(respSt)
151  {
152  jsonResponse = cJSON_CreateObject();
153  wdmp_form_set_response(respSt, jsonResponse);
154  // WDMP Code sets a generic statusCode, the following lines replace it with an actual error code.
155  int new_st_code = 0;
156 
157  for(int paramIndex = 0; paramIndex < respSt->paramCnt; paramIndex++)
158  {
159  if(respSt->retStatus[paramIndex] != 0 || paramIndex == respSt->paramCnt-1)
160  {
161  new_st_code = respSt->retStatus[paramIndex];
162  break;
163  }
164  }
165  cJSON * stcode = cJSON_GetObjectItem(jsonResponse, "statusCode");
166  if( NULL != stcode)
167  {
168  cJSON_SetIntValue(stcode, new_st_code);
169  }
170  }
171  else
172  {
173  soup_message_set_status_full (msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, "Invalid request format");
174  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Request couldn't be processed\n", __FUNCTION__, __FILE__);
175  wdmp_free_req_struct(reqSt);
176  reqSt = NULL;
177  return;
178  }
179  }
180  else
181  {
182  soup_message_set_status_full (msg, SOUP_STATUS_NOT_IMPLEMENTED, "Method not implemented");
183  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Unsupported operation \n", __FUNCTION__, __FILE__);
184  wdmp_free_req_struct(reqSt);
185  reqSt = NULL;
186  return;
187  }
188 
189  char *buf = cJSON_Print(jsonResponse);
190 
191  if(buf) {
192  soup_message_set_response(msg, (const char *) "application/json", SOUP_MEMORY_COPY, buf, strlen(buf));
193  soup_message_set_status (msg, SOUP_STATUS_OK);
194  }
195 
196  wdmp_free_req_struct(reqSt);
197  reqSt = NULL;
198  cJSON_Delete(jsonRequest);
199  cJSON_Delete(jsonResponse);
200  wdmp_free_res_struct(respSt);
201  respSt = NULL;
202 
203  if(buf != NULL) {
204  free(buf);
205  buf = NULL;
206  }
207  }
208  else
209  {
210  soup_message_set_status_full (msg, SOUP_STATUS_BAD_REQUEST, "Bad Request");
211  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"[%s:%s] Exiting.. Failed to parse JSON Message \n", __FUNCTION__, __FILE__);
212  return;
213  }
214 
215  getCurrentTime(endPtr);
216  RDK_LOG(RDK_LOG_DEBUG,LOG_TR69HOSTIF,"Curl Request Processing Time : %lu ms\n", timeValDiff(startPtr, endPtr));
217  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
218  return;
219 }
220 
221 
222 void *HTTPServerStartThread(void *msg)
223 {
224  /*Start HTTP server */
225  GError *error = NULL;
226  int status =-1;
227  guint httpServerPort = argList.httpServerPort;
228 
229  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"[%s:%s] Entering..\n", __FUNCTION__, __FILE__);
230 
231 #ifndef GLIB_VERSION_2_36
232  g_type_init ();
233 #endif
234 
235  status = checkDataModelStatus();
236  if(status != 0)
237  {
238  RDK_LOG(RDK_LOG_ERROR,LOG_TR69HOSTIF,"Error in Data Model Initialization\n");
239  return NULL;
240  }
241 
242  if(http_server == NULL)
243  http_server = soup_server_new (SOUP_SERVER_SERVER_HEADER, "HTTPServer", NULL);
244 
245  if (!http_server)
246  {
247  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"SERVER: Could not create server.\n");
248  return NULL;
249  }
250  else
251  {
252  soup_server_add_handler (http_server, (const char*)"/", HTTPRequestHandler, NULL, NULL);
253 
254  if(FALSE == soup_server_listen_local (http_server, httpServerPort, SOUP_SERVER_LISTEN_IPV4_ONLY, &error))
255  {
256  RDK_LOG(RDK_LOG_ERROR, LOG_TR69HOSTIF,"SERVER: failed in soup_server_listen_local. (%s).\n", error->message);
257  }
258 
259  //Create a .http_server_ready file in /tmp for RFC to check whether http server is ready to accept requests
260  ofstream ofs("/tmp/.tr69hostif_http_server_ready", ios::trunc | ios::out);
261  if(!ofs.is_open())
262  RDK_LOG (RDK_LOG_ERROR, LOG_TR69HOSTIF, "Failed to open : /tmp/.tr69hostif_http_server_ready \n");
263  else
264  ofs.close();
265 
266  RDK_LOG(RDK_LOG_DEBUG, LOG_TR69HOSTIF,"SERVER: Started server successfully.\n");
267  }
268 
269  {
270  std::unique_lock<std::mutex> lck(mtx_httpServerThreadDone);
271  httpServerThreadDone = true;
272  cv_httpServerThreadDone.notify_all();
273  }
274 
275  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"[%s:%s] Exiting..\n", __FUNCTION__, __FILE__);
276  return NULL;
277 }
278 
279 void HttpServerStop()
280 {
281  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"SERVER: Stopping HTTP Server....\n");
282  if(http_server) {
283  std::unique_lock<std::mutex> lck(mtx_httpServerThreadDone);
284  httpServerThreadDone = false;
285  soup_server_disconnect(http_server);
286  RDK_LOG(RDK_LOG_TRACE1, LOG_TR69HOSTIF,"SERVER: Stopped server successfully.\n");
287  }
288 }
289 
request_handler.h
API to handle single multiple and wild card parameters in HTTP JSON Interface.
getCurrentTime
void getCurrentTime(struct timespec *timer)
Get Current time.
Definition: hostIf_utils.cpp:466
hostIf_main.h
hostIf_main API.
RDK_LOG
#define RDK_LOG
Definition: rdk_debug.h:258
argsList
Definition: hostIf_main.h:126