Remote Access base on libstrophe
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / ra_adapter / caraadapter.c
1 //*****************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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 #include "caraadapter.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
27
28 #include "caadapterutils.h"
29 #include "camutex.h"
30 #include "uarraylist.h"
31 #include "logger.h"
32 #include "oic_malloc.h"
33 #include "oic_string.h"
34 #include "caremotehandler.h"
35 #include "cacommon.h"
36
37 #ifdef RA_ADAPTER_IBB
38 #include "caprotocolmessage.h"
39 #include "xmpp_helper.h"
40 #include "xmpp_utils.h"
41 #include "xmpp_ibb.h"
42 #include "xmpp_utils.h"
43 #else
44 #include "ra_xmpp.h"
45 #endif
46
47 #ifdef RA_ADAPTER_IBB
48 /**
49  * Logging tag for module name.
50  */
51 #define RA_ADAPTER_TAG "RA_ADAP_IBB"
52
53 /**
54  * Network Packet Received Callback to CA.
55  */
56 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
57
58 /**
59  * Network Changed Callback to CA.
60  */
61 static CANetworkChangeCallback g_networkChangeCallback = NULL;
62
63 /**
64  * Holds XMPP data information.
65  */
66 #define RA_MAX_HOSTNAME_LENGTH 256
67 #define RA_MAX_PASSWORD_LENGTH 64
68 typedef struct
69 {
70     xmpp_t     *xmpp;
71     int         port;
72     char        hostname[RA_MAX_HOSTNAME_LENGTH];
73     char        password[RA_MAX_PASSWORD_LENGTH];
74     char        jid[CA_RAJABBERID_SIZE];
75     CANetworkStatus_t connection_status;
76 } CARAXmppData_t;
77
78 static ca_mutex g_raadapterMutex = NULL;
79
80 static CARAXmppData_t g_xmppData = {.xmpp = NULL, .port = 5222, .hostname = {0},
81     .password = {0}, .jid = {0}, .connection_status = CA_INTERFACE_DOWN};
82
83 static void CARANotifyNetworkChange(const char *address, CANetworkStatus_t status);
84
85 void CARANotifyNetworkChange(const char *address, CANetworkStatus_t status)
86 {
87     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARANotifyNetworkChange IN");
88
89     g_xmppData.connection_status = status;
90
91     CAEndpoint_t *localEndpoint = CACreateEndpointObject(CA_DEFAULT_FLAGS,
92                                 CA_ADAPTER_REMOTE_ACCESS,
93                                 address, 0);
94     if (!localEndpoint)
95     {
96         OIC_LOG(ERROR, RA_ADAPTER_TAG, "localEndpoint creation failed!");
97         return;
98     }
99     CANetworkChangeCallback networkChangeCallback = g_networkChangeCallback;
100     if (networkChangeCallback)
101     {
102         networkChangeCallback(localEndpoint, status);
103     }
104     else
105     {
106         OIC_LOG(ERROR, RA_ADAPTER_TAG, "g_networkChangeCallback is NULL");
107     }
108
109     CAFreeEndpoint(localEndpoint);
110
111     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARANotifyNetworkChange OUT");
112 }
113
114 #define MAX_IBB_SESSION_ID_LENGTH 32
115 /* Ref. octypes.h */
116 #define OBSERVE_REGISTER    0
117 #define OBSERVE_DEREGISTER  1
118 /* Ref. octypes.h */
119
120 static ilist_t * g_observerList = NULL;
121
122 typedef struct _obs_item_t
123 {
124     char sessid[MAX_IBB_SESSION_ID_LENGTH + 1];
125     int  option;
126 } obs_item_t;
127
128 static bool CARAFindSessID(obs_item_t *item, char *key)
129 {
130     if (item == NULL || key == NULL)
131     {
132         return false;
133     }
134     if (strcmp(item->sessid, key) == 0)
135     {
136         return true;
137     }
138     else
139     {
140         return false;
141     }
142 }
143
144 static bool CARAPDUIsRequest(uint32_t x)
145 {
146     return (x == CA_GET || x == CA_POST || x == CA_PUT || x == CA_DELETE);
147 }
148
149 static void CARAUpdateObsList(int option, char *sid)
150 {
151     if (option == OBSERVE_REGISTER)
152     {
153         obs_item_t *item = (obs_item_t *) OICMalloc(sizeof(*item));
154         OICStrcpy(item->sessid, sizeof(item->sessid), sid);
155         item->option = OBSERVE_REGISTER;
156         ilist_add(g_observerList, item);
157     }
158     else if (option == OBSERVE_DEREGISTER)
159     {
160         obs_item_t *item = ilist_finditem_func(g_observerList, CARAFindSessID, sid);
161         if (item != NULL)
162         {
163             item->option = OBSERVE_DEREGISTER;
164         }
165     }
166 }
167
168 static int CARAGetReqObsOption(coap_pdu_t *pdu)
169 {
170     uint32_t obsopt = -1;
171
172     CARequestInfo_t *reqInfo = (CARequestInfo_t *) OICMalloc(sizeof(*reqInfo));
173     VERIFY_NON_NULL_RET(reqInfo, RA_ADAPTER_TAG, "Memory alloc of CARequestInfo_t failed!", -1);
174
175     CAResult_t result = CAGetRequestInfoFromPDU(pdu, reqInfo);
176     if (CA_STATUS_OK != result)
177     {
178         OICFree(reqInfo);
179         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Get Request Info failed!");
180         return -1;
181     }
182     if (!CARAPDUIsRequest(reqInfo->method))
183     {
184         OICFree(reqInfo);
185         OIC_LOG(DEBUG, RA_ADAPTER_TAG, "It is not a request data.");
186         return -1;
187     }
188
189     uint8_t numOpt = reqInfo->info.numOptions;
190     CAHeaderOption_t *options = reqInfo->info.options;
191     for (uint8_t i = 0; i < numOpt; i++)
192     {
193         if(options[i].protocolID == CA_COAP_ID &&
194                 options[i].optionID == COAP_OPTION_OBSERVE)
195         {
196             obsopt = options[i].optionData[0];
197             break;
198         }
199     }
200     OICFree(reqInfo);
201     return obsopt;
202 }
203
204 static int CARAErrorCB(xmpp_ibb_session_t *sess, xmpperror_t *xerr)
205 {
206     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "%s(): code(%d) tyep'%s' mesg'%s'",
207             __FUNCTION__, xerr->code, xerr->type, xerr->mesg);
208     return 0;
209 }
210
211 static int CARAOpenCB(xmpp_ibb_session_t *sess, char *type)
212 {
213     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "%s(): set type '%s'", __FUNCTION__, type);
214     return 0;
215 }
216
217 static int CARACloseCB(xmpp_ibb_session_t *sess, char *type)
218 {
219     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "%s(): set type '%s'", __FUNCTION__, type);
220     char *sid = xmpp_ibb_get_sid(sess);
221     obs_item_t *item = ilist_finditem_func(g_observerList, CARAFindSessID, sid);
222     if (item != NULL)
223     {
224         ilist_remove(g_observerList, item);
225         OICFree(item);
226     }
227     return 0;
228 }
229
230 static char *CARAGetSIDFromPDU(coap_pdu_t *pdu)
231 {
232     static char s_sid[MAX_IBB_SESSION_ID_LENGTH + 1] = {0};
233
234     VERIFY_NON_NULL_RET(pdu, RA_ADAPTER_TAG, "Invalid parameter!", NULL);
235
236     if (pdu->hdr->token_length * 2 > MAX_IBB_SESSION_ID_LENGTH)
237     {
238         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Token length more than expected!");
239         return NULL;
240     }
241
242     char hex[3] = {0};
243     for (int i = 0; i < pdu->hdr->token_length; i++)
244     {
245         snprintf(hex, 3, "%02x", pdu->hdr->token[i]);
246         OICStrcat(s_sid, sizeof(s_sid), hex);
247     }
248
249     return s_sid;
250 }
251
252 static int CARARecvCB(xmpp_ibb_session_t *sess, xmppdata_t *xdata)
253 {
254     if (xdata == NULL)
255     {
256         /* xdata == NULL, send ack result */
257         return 0;
258     }
259
260     char *msg = xdata->data;
261     char *from = xmpp_ibb_get_remote_jid(sess);
262     if (g_networkPacketCallback)
263     {
264         VERIFY_NON_NULL_RET(from, RA_ADAPTER_TAG, "from sender is NULL", -1);
265         VERIFY_NON_NULL_RET(msg, RA_ADAPTER_TAG, "message is NULL", -1);
266
267         OIC_LOG_V (DEBUG, RA_ADAPTER_TAG, "Message received from %s", from);
268
269         CAEndpoint_t *endPoint = CACreateEndpointObject(CA_DEFAULT_FLAGS,
270                         CA_ADAPTER_REMOTE_ACCESS, from, 0);
271         if (!endPoint)
272         {
273             OIC_LOG(ERROR, RA_ADAPTER_TAG, "EndPoint creation failed!");
274             return -1;
275         }
276         uint32_t code = CA_NOT_FOUND;
277         coap_pdu_t *pdu = (coap_pdu_t *) CAParsePDU(xdata->data, xdata->size, &code);
278         char *sid = CARAGetSIDFromPDU(pdu);
279         int obsopt = CARAGetReqObsOption(pdu);
280         coap_delete_pdu(pdu);
281
282         if (CARAPDUIsRequest(code))
283         {
284             OIC_LOG(DEBUG, RA_ADAPTER_TAG, "this is a request data");
285             if (obsopt == OBSERVE_DEREGISTER || obsopt == OBSERVE_REGISTER)
286             {
287                 CARAUpdateObsList(obsopt, sid);
288             }
289         }
290         else
291         {
292             OIC_LOG(DEBUG, RA_ADAPTER_TAG, "this is a response data");
293             obs_item_t *item = ilist_finditem_func(g_observerList, CARAFindSessID, sid);
294             if (item != NULL)
295             {
296                 if (item->option == OBSERVE_DEREGISTER)
297                 {
298                     xmpp_ibb_close(sess);
299                     ilist_remove(g_observerList, item);
300                     OICFree(item);
301                 }
302             }
303             else
304             {
305                 xmpp_ibb_close(sess);
306             }
307         }
308
309         void *buf = NULL;
310         xmpp_ibb_userdata_alloc(sess, &buf, xdata->size);
311         if (!buf)
312         {
313             OIC_LOG(ERROR, RA_ADAPTER_TAG, "Memory alloc of message failed!");
314             CAFreeEndpoint(endPoint);
315             return -1;
316         }
317         memcpy(buf, xdata->data, xdata->size);
318         g_networkPacketCallback(endPoint, buf, xdata->size);
319
320         CAFreeEndpoint (endPoint);
321     }
322     else
323     {
324         OIC_LOG(ERROR, RA_ADAPTER_TAG, "No callback for RA received message found");
325     }
326     return 0;
327 }
328
329 static int CARAConnHandler(xmpp_t *xmpp, xmppconn_info_t *conninfo, void *udata)
330 {
331     if (conninfo->connevent != 0)
332     {
333         OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, " status(%d) error(%d) errorType(%d) errorText '%s'\n",
334                 conninfo->connevent, conninfo->error, conninfo->errortype,
335                 conninfo->errortext);
336         CARANotifyNetworkChange(g_xmppData.jid, CA_INTERFACE_DOWN);
337         return -1;
338     }
339     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "\n\n  Bound JID: '%s'\n\n\n", xmpphelper_get_bound_jid(xmpp));
340     CARANotifyNetworkChange(xmpphelper_get_bound_jid(xmpp), CA_INTERFACE_UP);
341     return 0;
342 }
343
344 CAResult_t CAInitializeRA(CARegisterConnectivityCallback registerCallback,
345                                 CANetworkPacketReceivedCallback networkPacketCallback,
346                                 CANetworkChangeCallback netCallback, ca_thread_pool_t handle)
347 {
348     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CAInitializeRA IN");
349     if (!registerCallback || !networkPacketCallback || !netCallback || !handle)
350     {
351         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
352         return CA_STATUS_INVALID_PARAM;
353     }
354
355     g_networkChangeCallback = netCallback;
356     g_networkPacketCallback = networkPacketCallback;
357
358     CAConnectivityHandler_t raHandler = {
359         .startAdapter = CAStartRA,
360         .startListenServer = CAStartRAListeningServer,
361         .startDiscoveryServer = CAStartRADiscoveryServer,
362         .sendData = CASendRAUnicastData,
363         .sendDataToAll = CASendRAMulticastData,
364         .GetnetInfo = CAGetRAInterfaceInformation,
365         .readData = CAReadRAData,
366         .stopAdapter = CAStopRA,
367         .terminate = CATerminateRA};
368     registerCallback(raHandler, CA_ADAPTER_REMOTE_ACCESS);
369
370     g_xmppData.xmpp = xmpphelper_new(CARAConnHandler, NULL);
371     xmpphelper_force_tls(g_xmppData.xmpp);
372     g_observerList = ilist_new();
373
374     return CA_STATUS_OK;
375 }
376
377 CAResult_t CASetRAInfo(const CARAInfo_t *caraInfo)
378 {
379     if (!caraInfo)
380     {
381         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
382         return CA_STATUS_INVALID_PARAM;
383     }
384     if (caraInfo->hostname != NULL)
385     {
386         OICStrcpy(g_xmppData.hostname, sizeof(g_xmppData.hostname), caraInfo->hostname);
387     }
388     else
389     {
390         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
391         return CA_STATUS_INVALID_PARAM;
392     }
393     if (caraInfo->username != NULL && strlen(caraInfo->username) != 0)
394     {
395         OICStrcpy(g_xmppData.jid, sizeof(g_xmppData.jid), caraInfo->username);
396     }
397     else
398     {
399         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
400         return CA_STATUS_INVALID_PARAM;
401     }
402     if (caraInfo->xmpp_domain != NULL && strlen(caraInfo->xmpp_domain) != 0)
403     {
404         OICStrcat(g_xmppData.jid, sizeof(g_xmppData.jid), "@");
405         OICStrcat(g_xmppData.jid, sizeof(g_xmppData.jid), caraInfo->xmpp_domain);
406         if (caraInfo->resource != NULL && strlen(caraInfo->resource) != 0)
407         {
408             OICStrcat(g_xmppData.jid, sizeof(g_xmppData.jid), "/");
409             OICStrcat(g_xmppData.jid, sizeof(g_xmppData.jid), caraInfo->resource);
410         }
411     }
412     if (caraInfo->password != NULL)
413     {
414         OICStrcpy(g_xmppData.password, sizeof(g_xmppData.password), caraInfo->password);
415     }
416     g_xmppData.port = caraInfo->port;
417
418     return CA_STATUS_OK;
419 }
420
421 void CATerminateRA()
422 {
423     CAStopRA();
424     ilist_destroy(g_observerList);
425     xmpphelper_join(g_xmppData.xmpp);
426     xmpphelper_release(g_xmppData.xmpp);
427     g_xmppData.xmpp = NULL;
428 }
429
430 CAResult_t CAStartRA()
431 {
432     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Starting RA adapter"));
433
434     if (!g_xmppData.xmpp)
435     {
436         OIC_LOG (ERROR, RA_ADAPTER_TAG, "CAStartRA(): g_xmppData.xmpp == NULL");
437         return CA_STATUS_FAILED;
438     }
439
440     g_raadapterMutex = ca_mutex_new ();
441     if (!g_raadapterMutex)
442     {
443         OIC_LOG (ERROR, RA_ADAPTER_TAG, PCF("Memory allocation for mutex failed."));
444         return CA_MEMORY_ALLOC_FAILED;
445     }
446
447     ca_mutex_lock (g_raadapterMutex);
448
449     xmpphelper_connect(g_xmppData.xmpp, g_xmppData.hostname, g_xmppData.port,
450                     g_xmppData.jid, g_xmppData.password);
451     xmpp_ibb_reg_funcs_t regfuncs;
452     regfuncs.open_cb = CARAOpenCB;
453     regfuncs.close_cb = CARACloseCB;
454     regfuncs.recv_cb = CARARecvCB;
455     regfuncs.error_cb = CARAErrorCB;
456     xmpp_ibb_register(xmpphelper_get_conn(g_xmppData.xmpp), &regfuncs);
457
458     xmpphelper_run(g_xmppData.xmpp);
459
460     ca_mutex_unlock (g_raadapterMutex);
461
462     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "RA adapter started succesfully");
463     return CA_STATUS_OK;
464 }
465
466 CAResult_t CAStopRA()
467 {
468     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Stopping RA adapter"));
469
470     xmpphelper_stop(g_xmppData.xmpp);
471     xmpp_ibb_unregister(xmpphelper_get_conn(g_xmppData.xmpp));
472     if (!g_raadapterMutex)
473     {
474         ca_mutex_free (g_raadapterMutex);
475         g_raadapterMutex = NULL;
476     }
477     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Stopped RA adapter successfully"));
478     return CA_STATUS_OK;
479 }
480
481 int32_t CASendRAUnicastData(const CAEndpoint_t *remoteEndpoint, const void *data,
482                                   uint32_t dataLength)
483 {
484     if (!remoteEndpoint || !data)
485     {
486         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
487         return -1;
488     }
489
490     if (0 == dataLength)
491     {
492         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Data length is 0!");
493         return 0;
494     }
495     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "Sending unicast data to %s", remoteEndpoint->addr);
496
497     uint32_t code = CA_NOT_FOUND;
498     coap_pdu_t *pdu = (coap_pdu_t *) CAParsePDU(data, dataLength, &code);
499     char *sid = CARAGetSIDFromPDU(pdu);
500     int obsopt = CARAGetReqObsOption(pdu);
501     coap_delete_pdu(pdu);
502
503     ca_mutex_lock (g_raadapterMutex);
504     if (CA_INTERFACE_UP != g_xmppData.connection_status)
505     {
506         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Unable to send XMPP message, RA not connected");
507         ca_mutex_unlock (g_raadapterMutex);
508         return -1;
509     }
510
511     xmpp_ibb_session_t *sess = xmpp_ibb_get_session_by_sid(sid);
512     if (sess == NULL)
513     {
514         sess = xmpp_ibb_open(xmpphelper_get_conn(g_xmppData.xmpp), remoteEndpoint->addr, sid);
515         if (sess == NULL)
516         {
517             OIC_LOG(ERROR, RA_ADAPTER_TAG, "IBB session establish failed!");
518             ca_mutex_unlock (g_raadapterMutex);
519             return -1;
520         }
521     }
522     if (CARAPDUIsRequest(code))
523     {
524         if (obsopt == OBSERVE_REGISTER || obsopt == OBSERVE_DEREGISTER)
525         {
526             CARAUpdateObsList(obsopt, sid);
527         }
528     }
529     xmppdata_t xdata = {.data = data, .size = dataLength};
530     int rc = xmpp_ibb_send_data(sess, &xdata);
531     ca_mutex_unlock (g_raadapterMutex);
532     if (rc < 0)
533     {
534         OIC_LOG(ERROR, RA_ADAPTER_TAG, "IBB send data failed!");
535         return -1;
536     }
537
538     OIC_LOG_V(INFO, RA_ADAPTER_TAG, "Successfully dispatched bytes[%d] to addr[%s]",
539             dataLength, remoteEndpoint->addr);
540
541     return dataLength;
542 }
543
544 CAResult_t CAGetRAInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
545 {
546     VERIFY_NON_NULL(info, RA_ADAPTER_TAG, "info is NULL");
547     VERIFY_NON_NULL(size, RA_ADAPTER_TAG, "size is NULL");
548     return CA_STATUS_OK;
549 }
550
551 int32_t CASendRAMulticastData(const CAEndpoint_t *endpoint,
552                     const void *data, uint32_t dataLength)
553 {
554     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support sending multicast data");
555     return 0;
556 }
557
558 CAResult_t CAStartRAListeningServer()
559 {
560     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support listening for multicast data");
561     return CA_NOT_SUPPORTED;
562 }
563
564 CAResult_t CAStartRADiscoveryServer()
565 {
566     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support discovery of multicast servers");
567     return CA_NOT_SUPPORTED;
568 }
569
570 CAResult_t CAReadRAData()
571 {
572     OIC_LOG(INFO, RA_ADAPTER_TAG, "Read data is not implemented for the RA adapter");
573     return CA_NOT_SUPPORTED;
574 }
575
576 #else /* #ifdef RA_ADAPTER_IBB */
577
578 /**
579  * Logging tag for module name.
580  */
581 #define RA_ADAPTER_TAG "RA_ADAP"
582
583 /**
584  * Network Packet Received Callback to CA.
585  */
586 static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
587
588 /**
589  * Network Changed Callback to CA.
590  */
591 static CANetworkChangeCallback g_networkChangeCallback = NULL;
592
593 /**
594  * Holds XMPP data information.
595  */
596 typedef struct
597 {
598     xmpp_context_t context;
599     xmpp_handle_t handle;
600     xmpp_connection_callback_t connection_callback;
601     xmpp_connection_handle_t connection_handle;
602     xmpp_message_context_t message_context;
603     xmpp_message_callback_t message_callback;
604     CANetworkStatus_t connection_status;
605     xmpp_host_t     g_host;
606     xmpp_identity_t g_identity;
607     char jabberID[CA_RAJABBERID_SIZE];
608 } CARAXmppData_t;
609
610 static ca_mutex g_raadapterMutex = NULL;
611
612 static CARAXmppData_t g_xmppData = {};
613
614 static void CARANotifyNetworkChange(const char *address, CANetworkStatus_t status);
615
616 static void CARAXmppConnectedCB(void * const param, xmpp_error_code_t result,
617         const char *const bound_jid,
618         xmpp_connection_handle_t connection);
619
620 static void CARAXmppDisonnectedCB(void * const param, xmpp_error_code_t result,
621         xmpp_connection_handle_t connection);
622
623 static void CARAXmppMessageSentCB(void * const param, xmpp_error_code_t result,
624         const void *const recipient, const void *const msg, size_t messageOctets);
625
626 static void CARAXmppMessageReceivedCB(void * const param, xmpp_error_code_t result,
627         const void *const sender, const void *const msg, size_t messageOctets);
628
629 void CARANotifyNetworkChange(const char *address, CANetworkStatus_t status)
630 {
631     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARANotifyNetworkChange IN");
632
633     CAEndpoint_t *localEndpoint = CACreateEndpointObject(CA_DEFAULT_FLAGS,
634                                 CA_ADAPTER_REMOTE_ACCESS,
635                                 address, 0);
636     if (!localEndpoint)
637     {
638         OIC_LOG(ERROR, RA_ADAPTER_TAG, "localEndpoint creation failed!");
639         return;
640     }
641     CANetworkChangeCallback networkChangeCallback = g_networkChangeCallback;
642     if (networkChangeCallback)
643     {
644         networkChangeCallback(localEndpoint, status);
645     }
646     else
647     {
648         OIC_LOG(ERROR, RA_ADAPTER_TAG, "g_networkChangeCallback is NULL");
649     }
650
651     CAFreeEndpoint(localEndpoint);
652
653     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARANotifyNetworkChange OUT");
654 }
655
656 void CARAXmppConnectedCB(void * const param, xmpp_error_code_t result,
657         const char *const bound_jid,
658         xmpp_connection_handle_t connection)
659 {
660     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARAXmppConnectedCB IN");
661     CANetworkStatus_t connection_status;
662     if (XMPP_ERR_OK == result)
663     {
664         printf("\n\n\t\t===>your jid: %s\n\n", bound_jid);
665
666         ca_mutex_lock (g_raadapterMutex);
667         OICStrcpy (g_xmppData.jabberID, CA_RAJABBERID_SIZE, bound_jid);
668
669         g_xmppData.connection_status = CA_INTERFACE_UP;
670         connection_status = CA_INTERFACE_UP;
671         g_xmppData.connection_handle = connection;
672         g_xmppData.message_callback.on_received = CARAXmppMessageReceivedCB;
673         g_xmppData.message_callback.on_sent = CARAXmppMessageSentCB;
674         g_xmppData.message_context = xmpp_message_context_create(g_xmppData.connection_handle,
675                 g_xmppData.message_callback);
676     }
677     else
678     {
679         g_xmppData.connection_status = CA_INTERFACE_DOWN;
680         connection_status = CA_INTERFACE_DOWN;
681         OIC_LOG_V(ERROR, RA_ADAPTER_TAG, "XMPP connected callback status: %d", result);
682     }
683
684     ca_mutex_unlock (g_raadapterMutex);
685     // Notify network change to CA
686     CARANotifyNetworkChange(bound_jid, connection_status);
687
688     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARAXmppConnectedCB OUT");
689 }
690
691 void CARAXmppDisonnectedCB(void * const param, xmpp_error_code_t result,
692         xmpp_connection_handle_t connection)
693 {
694     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARAXmppDisonnectedCB IN");
695     char jabberID[CA_RAJABBERID_SIZE];
696     ca_mutex_lock (g_raadapterMutex);
697
698     g_xmppData.connection_status = CA_INTERFACE_DOWN;
699     xmpp_message_context_destroy(g_xmppData.message_context);
700     OICStrcpy (jabberID, CA_RAJABBERID_SIZE, g_xmppData.jabberID);
701
702     ca_mutex_unlock (g_raadapterMutex);
703
704     // Notify network change to CA
705     CARANotifyNetworkChange(jabberID, CA_INTERFACE_DOWN);
706
707     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CARAXmppDisonnectedCB OUT");
708 }
709
710 void CARAXmppMessageSentCB(void * const param, xmpp_error_code_t result,
711         const void *const recipient, const void *const msg, size_t messageOctets)
712 {
713     OIC_LOG_V(DEBUG, RA_ADAPTER_TAG, "Sending message to %s has result %d",
714         recipient, result);
715 }
716
717 void CARAXmppMessageReceivedCB(void * const param, xmpp_error_code_t result,
718         const void *const sender, const void *const msg, size_t messageOctets)
719 {
720     if (g_networkPacketCallback)
721     {
722         VERIFY_NON_NULL_VOID(sender, RA_ADAPTER_TAG, "sender is NULL");
723         VERIFY_NON_NULL_VOID(msg,    RA_ADAPTER_TAG, "message is NULL");
724
725         OIC_LOG_V (ERROR, RA_ADAPTER_TAG, "Message received from %s", sender);
726         OIC_LOG_V (ERROR, RA_ADAPTER_TAG, "Message reception result %d", result);
727
728         CAEndpoint_t *endPoint = CACreateEndpointObject(CA_DEFAULT_FLAGS,
729                         CA_ADAPTER_REMOTE_ACCESS, sender, 0);
730         if (!endPoint)
731         {
732             OIC_LOG(ERROR, RA_ADAPTER_TAG, "EndPoint creation failed!");
733             return;
734         }
735
736         void *buf = OICMalloc(messageOctets);
737         if (!buf)
738         {
739             OIC_LOG(ERROR, RA_ADAPTER_TAG, "Memory alloc of message failed!");
740             CAFreeEndpoint(endPoint);
741             return;
742         }
743         memcpy(buf, msg, messageOctets);
744         CANetworkPacketReceivedCallback networkPacketCallback = g_networkPacketCallback;
745         if (networkPacketCallback)
746         {
747             g_networkPacketCallback(endPoint, buf, messageOctets);
748         }
749
750         CAFreeEndpoint (endPoint);
751     }
752     else
753     {
754         OIC_LOG_V (ERROR, RA_ADAPTER_TAG, "No callback for RA  received message found");
755     }
756 }
757
758 CAResult_t CAInitializeRA(CARegisterConnectivityCallback registerCallback,
759                                 CANetworkPacketReceivedCallback networkPacketCallback,
760                                 CANetworkChangeCallback netCallback, ca_thread_pool_t handle)
761 {
762     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "CAInitializeRA IN");
763     if (!registerCallback || !networkPacketCallback || !netCallback || !handle)
764     {
765         return CA_STATUS_INVALID_PARAM;
766     }
767
768     g_networkChangeCallback = netCallback;
769     g_networkPacketCallback = networkPacketCallback;
770
771     CAConnectivityHandler_t raHandler = {};
772     raHandler.startAdapter = CAStartRA;
773     raHandler.startListenServer = CAStartRAListeningServer;
774     raHandler.startDiscoveryServer = CAStartRADiscoveryServer;
775     raHandler.sendData = CASendRAUnicastData;
776     raHandler.sendDataToAll = CASendRAMulticastData;
777     raHandler.GetnetInfo = CAGetRAInterfaceInformation;
778     raHandler.readData = CAReadRAData;
779     raHandler.stopAdapter = CAStopRA;
780     raHandler.terminate = CATerminateRA;
781     registerCallback(raHandler, CA_ADAPTER_REMOTE_ACCESS);
782
783     return CA_STATUS_OK;
784 }
785
786 CAResult_t CASetRAInfo(const CARAInfo_t *caraInfo)
787 {
788     if (!caraInfo)
789     {
790         return CA_STATUS_INVALID_PARAM;
791     }
792     xmpp_identity_init(&g_xmppData.g_identity, caraInfo->username, caraInfo->password,
793             caraInfo->user_jid, XMPP_TRY_IN_BAND_REGISTER);
794     xmpp_host_init(&g_xmppData.g_host, caraInfo->hostname, caraInfo->port,
795             caraInfo->xmpp_domain, XMPP_PROTOCOL_XMPP);
796     return CA_STATUS_OK;
797 }
798
799 void CATerminateRA()
800 {
801     CAStopRA();
802 }
803
804 CAResult_t CAStartRA()
805 {
806     if (g_xmppData.handle.abstract_handle)
807     {
808         OIC_LOG(WARNING, RA_ADAPTER_TAG, "RA adapter already started");
809         return CA_STATUS_OK;
810     }
811
812     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Starting RA adapter"));
813
814     g_raadapterMutex = ca_mutex_new ();
815     if (!g_raadapterMutex)
816     {
817         OIC_LOG (ERROR, RA_ADAPTER_TAG, PCF("Memory allocation for mutex failed."));
818         return CA_MEMORY_ALLOC_FAILED;
819     }
820
821     ca_mutex_lock (g_raadapterMutex);
822
823     xmpp_context_init(&g_xmppData.context);
824     g_xmppData.handle = xmpp_startup(&g_xmppData.context);
825
826     // Wire up connection callbacks and call API to connect to XMPP server
827     g_xmppData.connection_callback.on_connected = CARAXmppConnectedCB;
828     g_xmppData.connection_callback.on_disconnected = CARAXmppDisonnectedCB;
829
830     xmpp_error_code_t ret = xmpp_connect(g_xmppData.handle, &g_xmppData.g_host,
831             &g_xmppData.g_identity, g_xmppData.connection_callback);
832
833     // Destroy host and identity structures as they are only
834     // required to establish initial connection
835     xmpp_identity_destroy(&g_xmppData.g_identity);
836     xmpp_host_destroy(&g_xmppData.g_host);
837
838     ca_mutex_unlock (g_raadapterMutex);
839
840     if (XMPP_ERR_OK != ret)
841     {
842         OIC_LOG_V(ERROR, RA_ADAPTER_TAG, "Failed to init XMPP connection status: %d",
843             ret);
844         return CA_STATUS_FAILED;
845     }
846
847     OIC_LOG(DEBUG, RA_ADAPTER_TAG, "RA adapter started succesfully");
848     return CA_STATUS_OK;
849 }
850
851 CAResult_t CAStopRA()
852 {
853     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Stopping RA adapter"));
854
855     xmpp_error_code_t ret = xmpp_close(g_xmppData.connection_handle);
856     if (XMPP_ERR_OK != ret)
857     {
858         OIC_LOG_V(ERROR, RA_ADAPTER_TAG, "Failed to close XMPP connection, status: %d",
859             ret);
860         return CA_STATUS_FAILED;
861     }
862
863     xmpp_shutdown_xmpp(g_xmppData.handle);
864     xmpp_context_destroy(&g_xmppData.context);
865     ca_mutex_free (g_raadapterMutex);
866     g_raadapterMutex = NULL;
867
868     OIC_LOG(DEBUG, RA_ADAPTER_TAG, PCF("Stopped RA adapter successfully"));
869     return CA_STATUS_OK;
870 }
871
872 int32_t CASendRAUnicastData(const CAEndpoint_t *remoteEndpoint, const void *data,
873                                   uint32_t dataLength)
874 {
875     if (!remoteEndpoint || !data)
876     {
877         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Invalid parameter!");
878         return -1;
879     }
880
881     if (0 == dataLength)
882     {
883         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Data length is 0!");
884         return 0;
885     }
886
887     OIC_LOG_V(ERROR, RA_ADAPTER_TAG, "Sending unicast data to %s", remoteEndpoint->addr);
888     ca_mutex_lock (g_raadapterMutex);
889
890     if (CA_INTERFACE_UP != g_xmppData.connection_status)
891     {
892         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Unable to send XMPP message, RA not connected");
893         ca_mutex_unlock (g_raadapterMutex);
894         return -1;
895     }
896
897     xmpp_error_code_t res = xmpp_send_message(g_xmppData.message_context,
898             remoteEndpoint->addr, data, dataLength,
899             XMPP_MESSAGE_TRANSMIT_DEFAULT);
900     if (XMPP_ERR_OK != res)
901     {
902         OIC_LOG_V(ERROR, RA_ADAPTER_TAG, "Unable to send XMPP message, status: %d", res);
903         ca_mutex_unlock (g_raadapterMutex);
904         return -1;
905     }
906     ca_mutex_unlock (g_raadapterMutex);
907
908     OIC_LOG_V(INFO, RA_ADAPTER_TAG, "Successfully dispatched bytes[%d] to addr[%s]",
909             dataLength, remoteEndpoint->addr);
910
911     return dataLength;
912 }
913
914 CAResult_t CAGetRAInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
915 {
916     VERIFY_NON_NULL(info, RA_ADAPTER_TAG, "info is NULL");
917     VERIFY_NON_NULL(size, RA_ADAPTER_TAG, "size is NULL");
918
919     ca_mutex_lock (g_raadapterMutex);
920
921     if (CA_INTERFACE_UP != g_xmppData.connection_status)
922     {
923         OIC_LOG(ERROR, RA_ADAPTER_TAG, "Failed to get interface info, RA not Connected");
924         ca_mutex_unlock (g_raadapterMutex);
925         return CA_ADAPTER_NOT_ENABLED;
926     }
927
928     ca_mutex_unlock (g_raadapterMutex);
929
930     CAEndpoint_t *localEndpoint = CACreateEndpointObject(CA_DEFAULT_FLAGS,
931                                  CA_ADAPTER_REMOTE_ACCESS,
932                                  g_xmppData.jabberID, 0);
933
934     *size = 1;
935     *info = localEndpoint;
936
937     return CA_STATUS_OK;
938 }
939
940 int32_t CASendRAMulticastData(const CAEndpoint_t *endpoint,
941                     const void *data, uint32_t dataLength)
942 {
943     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support sending multicast data");
944     return 0;
945 }
946
947 CAResult_t CAStartRAListeningServer()
948 {
949     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support listening for multicast data");
950     return CA_NOT_SUPPORTED;
951 }
952
953 CAResult_t CAStartRADiscoveryServer()
954 {
955     OIC_LOG(INFO, RA_ADAPTER_TAG, "RA adapter does not support discovery of multicast servers");
956     return CA_NOT_SUPPORTED;
957 }
958
959 CAResult_t CAReadRAData()
960 {
961     OIC_LOG(INFO, RA_ADAPTER_TAG, "Read data is not implemented for the RA adapter");
962     return CA_NOT_SUPPORTED;
963 }
964 #endif