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