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