Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / plugins / zigbee_wrapper / telegesis_wrapper / src / telegesis_socket.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 "telegesis_socket.h"
22
23 #include <unistd.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <signal.h>
27 #include <sys/select.h>
28 #include <time.h>
29
30 #include "twsocketlist.h"
31 #include "oic_string.h"
32 #include "oic_malloc.h"
33 #include "logger.h"
34
35 #define TAG "Telegesis_Socket"
36
37 /**
38  * New thread's main() ftn.
39  */
40 void * readForever(/*PIPlugin_Zigbee */void * plugin);
41 /**
42  * Just grabs the next char in the buffer. Called by readBufferLine() multiple times.
43  */
44 char readBufferChar(int fd, ssize_t * readDataBytes);
45 /**
46  * Calls readBufferChar() until line is formed.
47  */
48 const char * readBufferLine(int fd);
49 /**
50  * Calls readBufferLine() until a full TWEntry is formed.
51  */
52 TWEntry * readEntry(int fd);
53 /**
54  * Posts the TWEntry to the queue.
55  */
56 TWResultCode TWEnqueueEntry(PIPlugin_Zigbee * plugin, TWEntry * entry);
57
58 /**
59  * Defines the mapping relationships between Telegesis AT response/prompt tags and
60  * how many lines we should expect with each following the tag.
61  */
62 typedef struct
63 {
64     const char *resultTxt;
65     uint8_t numLines;
66     TWEntryType entryType;
67 } TWEntryTypePair;
68
69 static TWEntryTypePair TWEntryTypePairArray[] =
70 {
71     {"+N=",             1, TW_NETWORK_INFO},
72     {"JPAN:",           1, TW_JPAN},
73     {"RFD:",            1, TW_RFD},
74     {"FFD:",            1, TW_FFD},
75     {"SED:",            1, TW_SED},
76     {"ZED:",            1, TW_ZED},
77     {"MatchDesc:",      1, TW_MATCHDESC},
78     {"SimpleDesc:",     6, TW_SIMPLEDESC},
79     {"InCluster:",      1, TW_INCLUSTER},
80     {"WRITEATTR:",      1, TW_WRITEATTR},
81     {"RESPATTR:",       1, TW_RESPATTR},
82     {"TEMPERATURE:",    1, TW_RESPATTR},
83     {"DFTREP",          1, TW_DFTREP},
84     {"DRLOCRSP:",       1, TW_DRLOCRSP},
85     {"DRUNLOCKRSP:",    1, TW_DRUNLOCKRSP},
86     {"ACK:",            1, TW_ACK},
87     {"NACK:",           1, TW_NACK},
88     {"SEQ:",            1, TW_SEQ},
89     {"ZENROLLREQ:",     1, TW_ZENROLLREQ},
90     {"ENROLLED:",       1, TW_ENROLLED},
91     {"ZONESTATUS:",     1, TW_ZONESTATUS},
92     {"AddrResp:",       1, TW_ADDRESS_RESPONSE},
93     {"REPORTATTR:",     1, TW_NONE},
94     {"Unknown:",        0, TW_NONE},
95     {"Unknown:",        1, TW_MAX_ENTRY}
96 };
97
98 TWEntry * TWEntryList = NULL;
99
100 TWEntryTypePair getEntryTypePair(const char * bufferLine)
101 {
102     size_t count = sizeof(TWEntryTypePairArray)/sizeof(TWEntryTypePairArray[0]);
103     if (!bufferLine)
104     {
105         return TWEntryTypePairArray[count-1];
106     }
107     size_t bufferLength = strlen(bufferLine);
108     for (size_t i = 0; i < count; i++)
109     {
110         if (!TWEntryTypePairArray[i].resultTxt)
111         {
112             return TWEntryTypePairArray[count-1];
113         }
114         size_t resultTxtLength = strlen(TWEntryTypePairArray[i].resultTxt);
115         if ((bufferLength >= resultTxtLength) &&
116            strncmp(bufferLine, TWEntryTypePairArray[i].resultTxt, resultTxtLength) == 0)
117         {
118             return TWEntryTypePairArray[i];
119         }
120     }
121     return TWEntryTypePairArray[count-1];
122 }
123
124 TWResultCode TWWait(pthread_cond_t * cond, pthread_mutex_t * mutex, uint8_t timeout)
125 {
126     int ret = 0;
127     // This is a blocking call which hold the calling thread until an entry
128     // has been enqueued or until the specified timeout has surpassed.
129     struct timespec abs_time;
130     clock_gettime(CLOCK_REALTIME , &abs_time);
131     abs_time.tv_sec += timeout;
132     ret = pthread_cond_timedwait(cond, mutex, &abs_time);
133
134     switch (ret)
135     {
136         case 0:
137             return TW_RESULT_OK;
138         case ETIMEDOUT:
139             OIC_LOG(INFO, TAG, "Timed out waiting for CV. Non-error. Please try again.");
140             return TW_RESULT_OK;
141         case EINVAL:
142             OIC_LOG(ERROR, TAG, "Cond or Mutex is invalid. OR timeout value for CV is invalid.");
143             break;
144         case EPERM:
145             OIC_LOG(ERROR, TAG, "Cannot use CV because the current thread does not own the CV.");
146             break;
147     }
148
149     return TW_RESULT_ERROR;
150 }
151
152 TWResultCode TWGrabMutex(pthread_mutex_t * mutex)
153 {
154     int ret = pthread_mutex_lock(mutex);
155
156     switch (ret)
157     {
158         case 0:
159             return TW_RESULT_OK;
160         case EINVAL:
161             OIC_LOG(ERROR, TAG, "Mutex was not initialized.");
162             break;
163         case ETIMEDOUT:
164             OIC_LOG(INFO, TAG, "Timed out waiting for mutex. Non-error. Please try again.");
165             return TW_RESULT_OK;
166         case EAGAIN:
167             OIC_LOG(ERROR, TAG, "Maximum number of locks for mutex have been exceeded.");
168             break;
169         case EDEADLK:
170             OIC_LOG(ERROR, TAG, "Deadlock OR this thread already owns the mutex.");
171             break;
172     }
173     return TW_RESULT_ERROR;
174 }
175
176 TWResultCode TWReleaseMutex(pthread_mutex_t * mutex)
177 {
178     int ret = pthread_mutex_unlock(mutex);
179
180     switch (ret)
181     {
182         case 0:
183             return TW_RESULT_OK;
184         case EINVAL:
185             OIC_LOG(ERROR, TAG, "Mutex was not initialized.");
186             break;
187         case EAGAIN:
188             OIC_LOG(ERROR, TAG, "Maximum number of locks for mutex have been exceeded.");
189             break;
190         case EPERM:
191             OIC_LOG(ERROR, TAG, "Cannot unlock because the current thread does not own the mutex.");
192             break;
193     }
194     return TW_RESULT_ERROR;
195 }
196
197 char readBufferChar(int fd, ssize_t * readDataBytes)
198 {
199     // Performs read operation on fd for one character at a time.
200     if(!readDataBytes)
201     {
202         return '\0';
203     }
204     *readDataBytes = 0;
205     char byte = '\0';
206     errno = 0;
207     *readDataBytes = read(fd, &byte, sizeof(byte));
208     if(*readDataBytes < 0)
209     {
210         OIC_LOG_V(ERROR, TAG, "\tCould not read from port. Errno is: %d\n", errno);
211         return '\0';
212     }
213     return byte;
214 }
215
216 bool isLineIgnored(const char * line, size_t length)
217 {
218     if(length >= 4)
219     {
220         if(line[0] == 'N' && line[1] == 'A' && line[2] == 'C' && line[3] == 'K')
221         {
222             return true;
223         }
224     }
225     if(length >= 3)
226     {
227         if(line[0] == 'S' && line[1] == 'E' && line[2] == 'Q')
228         {
229             return true;
230         }
231         else if(line[0] == 'A' && line[1] == 'C' && line[2] == 'K')
232         {
233             return true;
234         }
235     }
236     if(length >= 2)
237     {
238         if(line[0] == 'A' && line[1] == 'T')
239         {
240             // If the line starts with "AT", then this is an echo. We ignore echos.
241             return true;
242         }
243         else if(line[0] == 'O' && line[1] == 'K')
244         {
245             //If this line is "OK", we ignore success codes. But we do end TWEntry's on "OK".
246             // (FYI, error codes are handled in readEntry() which invokes this function.)
247             return true;
248         }
249     }
250     return false;
251 }
252
253 const char * readBufferLine(int fd)
254 {
255     char bufferChar = '\0';
256     size_t bufferLoc = 0;
257     ssize_t readDataBytes = 0;
258     char * bufferLineHold = NULL;
259     char * bufferLine = NULL;
260     bool endOfLine1 = false;
261     bool endOfLine2 = false;
262     bool ignore = false;
263     while(true)
264     {
265         if(!endOfLine1 || !endOfLine2)
266         {
267             bufferChar = readBufferChar(fd, &readDataBytes);
268             if(bufferChar == '\r')
269             {
270                 endOfLine1 = true;
271                 continue;
272             }
273             if(bufferChar == '\n')
274             {
275                 endOfLine2 = true;
276                 continue;
277             }
278         }
279         if(readDataBytes != 0 && (!endOfLine1 && !endOfLine2))
280         {
281             size_t bufferLineSize = sizeof(bufferChar)*(bufferLoc+2);
282             bufferLine = (char *) OICRealloc(bufferLineHold, bufferLineSize);
283             if(!bufferLine)
284             {
285                 OIC_LOG(ERROR, TAG, "Ran out of memory.");
286                 return NULL;
287             }
288             bufferLine[bufferLoc] = '\0';
289             OICStrcat(bufferLine, bufferLineSize+2, &bufferChar);
290             bufferLoc++;
291             bufferLineHold = bufferLine;
292
293             OIC_LOG_V(DEBUG, TAG, "Incoming: %s", bufferLine);
294         }
295         else
296         {
297             if(!bufferLine)
298             {
299                 return NULL;
300             }
301             size_t bufferLineSize = sizeof(bufferChar)*(bufferLoc+2);
302             bufferLine = (char *) OICRealloc(bufferLineHold, bufferLineSize);
303             if(!bufferLine)
304             {
305                 OIC_LOG(ERROR, TAG, "Ran out of memory.");
306                 return NULL;
307             }
308             bufferLine[bufferLoc] = '\0';
309             bufferLoc++;
310             bufferLineHold = bufferLine;
311             ignore = isLineIgnored(bufferLine, strlen(bufferLine));
312             if(ignore)
313             {
314                 OICFree(bufferLine);
315                 return readBufferLine(fd);
316             }
317             if(endOfLine1 && endOfLine2)
318             {
319                 return bufferLine;
320             }
321             else
322             {
323                 return NULL;
324             }
325         }
326     }
327 }
328
329 TWResultCode TWAddLineToEntry(const char * line, TWEntry * entry)
330 {
331     if(!line || !entry)
332     {
333         OIC_LOG(ERROR, TAG, "Invalid/NULL parameter(s) received.");
334         return TW_RESULT_ERROR_INVALID_PARAMS;
335     }
336     TWLine * twLine = (TWLine *) OICCalloc(1, sizeof(TWLine));
337     if(!twLine)
338     {
339         OIC_LOG(ERROR, TAG, "Ran out of memory.");
340         return TW_RESULT_ERROR_NO_MEMORY;
341     }
342     size_t lineLength = strlen(line);
343     twLine->line = line;
344     twLine->length = lineLength;
345     size_t errorLength = strlen(TW_ENDCONTROL_ERROR_STRING);
346     size_t maxLength = (lineLength > errorLength) ? errorLength : lineLength;
347
348     if((errorLength == lineLength) &&
349        strncmp(line, TW_ENDCONTROL_ERROR_STRING, maxLength) == 0)
350     {
351         entry->atErrorCode[0] = line[errorLength];
352         entry->atErrorCode[1] = line[errorLength + 1];
353     }
354     else
355     {
356         entry->atErrorCode[0] = '0';
357         entry->atErrorCode[1] = '0';
358     }
359
360     // Null terminate the string.
361     entry->atErrorCode[2] = '\0';
362
363     if(!entry->lines)
364     {
365         entry->lines = twLine;
366     }
367     else
368     {
369         entry->lines[entry->count] = *twLine;
370     }
371     entry->count++;
372
373     return TW_RESULT_OK;
374 }
375
376 TWEntry * readEntry(int fd)
377 {
378     // Calls readBufferLine().
379     // Forms TWEntry from 1-n lines based on the response type.
380
381     TWEntry * entry = (TWEntry *) OICCalloc(1, sizeof(TWEntry));
382     if(!entry)
383     {
384         OIC_LOG(ERROR, TAG, "Ran out of memory.");
385         return NULL;
386     }
387     entry->count = 0;
388
389     const char * bufferLine = NULL;
390     TWEntryTypePair entryTypePair = { .resultTxt = NULL,
391                                       .numLines  = 0,
392                                       .entryType = TW_NONE };
393     size_t numLines = 0;
394     while(numLines == 0 || bufferLine)
395     {
396         if(numLines == 0)
397         {
398             bufferLine = readBufferLine(fd);
399             if(!bufferLine)
400             {
401                 goto exit;
402             }
403             entryTypePair = getEntryTypePair(bufferLine);
404             if(entryTypePair.entryType == TW_NONE)
405             {
406                 goto exit;
407             }
408         }
409         else
410         {
411             bufferLine = readBufferLine(fd);
412         }
413         if(bufferLine != NULL)
414         {
415             entry->type = entryTypePair.entryType;
416             TWAddLineToEntry(bufferLine, entry);
417             numLines++;
418             entry->count = numLines;
419         }
420
421         if(entryTypePair.numLines != numLines)
422         {
423             entry->resultCode = TW_RESULT_ERROR_LINE_COUNT;
424         }
425         else
426         {
427             entry->resultCode = TW_RESULT_OK;
428         }
429     }
430     return entry;
431 exit:
432     OICFree(entry);
433     return NULL;
434 }
435
436 TWResultCode TWRetrieveEUI(PIPlugin_Zigbee * plugin, TWSock * twSock)
437 {
438     if(!plugin || !twSock)
439     {
440         OIC_LOG(ERROR, TAG, "Invalid param.");
441         return TW_RESULT_ERROR_INVALID_PARAMS;
442     }
443     if(twSock->isActive == false)
444     {
445         OIC_LOG(ERROR, TAG, "Tried to retrieve Zigbee EUI on an uninitialized socket.");
446         return TW_RESULT_ERROR;
447     }
448
449     //Empty buffer
450     char hideBuffer[1] = "";
451     int p = 1;
452     while(p != 0)
453     {
454         errno = 0;
455         p = read(twSock->fd, hideBuffer, 1);
456         if(p < 0)
457         {
458             OIC_LOG_V(ERROR, TAG, "\tCould not read from port. Errno is: %d\n", errno);
459             return TW_RESULT_ERROR;
460         }
461     }
462
463     TWEntry * entry = NULL;
464     TWResultCode deleteResult = TW_RESULT_OK;
465     TWResultCode result = TWIssueATCommand(plugin, AT_CMD_GET_LOCAL_EUI);
466     if(result != TW_RESULT_OK)
467     {
468         return result;
469     }
470     result = TWGrabMutex(&twSock->mutex);
471     if(result != TW_RESULT_OK)
472     {
473         return result;
474     }
475     entry = readEntry(twSock->fd);
476     if(!entry)
477     {
478         result = TWReleaseMutex(&twSock->mutex);
479         if(result != TW_RESULT_OK)
480         {
481             goto exit;
482         }
483     }
484     twSock->eui = (char *) OICMalloc(strlen(entry->lines[0].line)+1);
485     if(!twSock->eui)
486     {
487         result = TWReleaseMutex(&twSock->mutex);
488         if(result != TW_RESULT_OK)
489         {
490             goto exit;
491         }
492         result = TW_RESULT_ERROR_NO_MEMORY;
493         goto exit;
494     }
495
496     if(SIZE_EUI != (strlen(entry->lines[0].line)+1))
497     {
498         result = TWReleaseMutex(&twSock->mutex);
499         if(result != TW_RESULT_OK)
500         {
501             goto exit;
502         }
503         OICFree(twSock->eui);
504         result = TW_RESULT_ERROR;
505         goto exit;
506     }
507
508     OICStrcpy(twSock->eui, SIZE_EUI, entry->lines[0].line);
509
510     result = TWReleaseMutex(&twSock->mutex);
511     if(result != TW_RESULT_OK)
512     {
513         OICFree(twSock->eui);
514         goto exit;
515     }
516 exit:
517     deleteResult = TWDeleteEntry(plugin, entry);
518     if(deleteResult != TW_RESULT_OK)
519     {
520         return deleteResult;
521     }
522     return result;
523 }
524
525 TWResultCode TWStartSock(PIPlugin_Zigbee * plugin, const char * fileLoc)
526 {
527     TWSock * sock = TWGetSock((PIPlugin_Zigbee *)plugin);
528     if(sock && sock->isActive == true)
529     {
530         // Ignore requests to start up the same socket.
531         return TW_RESULT_OK;
532     }
533     if(!sock)
534     {
535         sock = (TWSock *) OICCalloc(1, sizeof(TWSock));
536         if(!sock)
537         {
538             return TW_RESULT_ERROR_NO_MEMORY;
539         }
540     }
541     TWResultCode ret = TWAddTWSock(sock, plugin, fileLoc);
542     if(ret != 0)
543     {
544         goto exit;
545     }
546
547     ret = TWRetrieveEUI((PIPlugin_Zigbee *)plugin, sock);
548     if(ret != TW_RESULT_OK)
549     {
550         OIC_LOG(ERROR, TAG, "Unable to retrieve Zigbee Radio's EUI.");
551         return ret;
552     }
553
554     int result = pthread_create(&(sock->threadHandle),
555                                 NULL,
556                                 readForever,
557                                 (void *) plugin);
558     if(result != 0)
559     {
560         OIC_LOG_V(ERROR, TAG, "Thread start failed with error %d", result);
561         ret = TW_RESULT_ERROR;
562         goto exit;
563     }
564
565     return TW_RESULT_OK;
566
567 exit:
568     TWDeleteTWSock(sock);
569     return ret;
570 }
571
572 static void sigHandler(int signal)
573 {
574     pthread_t tid = pthread_self();
575     (void)tid;
576     (void)signal;
577     OIC_LOG_V(INFO, TAG, "Received signal on thread: %lu\n", tid);
578     OIC_LOG_V(INFO, TAG, "Signal is: %d", signal);
579 }
580
581 void * readForever(/*PIPlugin*/ void * plugin)
582 {
583     TWResultCode result = TW_RESULT_OK;
584     TWEntry * entry = NULL;
585     TWSock * twSock = TWGetSock((PIPlugin_Zigbee *)plugin);
586     if(!twSock)
587     {
588         OIC_LOG(ERROR, TAG, "Unable to retrieve associated socket.");
589         return NULL;
590     }
591
592     pthread_t tid = pthread_self();
593     (void)tid;
594     OIC_LOG_V(INFO, TAG, "ReadForever Telegesis ThreadId: %lu", tid);
595
596     struct sigaction action = { .sa_handler = 0 };
597
598     sigset_t sigmask;
599
600     action.sa_handler = sigHandler;
601     action.sa_flags = 0;
602     sigemptyset(&action.sa_mask);
603     sigaction(EINTR, &action, NULL);
604
605     fd_set readFDS;
606     FD_ZERO(&readFDS);
607     FD_SET(twSock->fd, &readFDS);
608     bool haveMutex = false;
609     while(true)
610     {
611         errno = 0;
612         // 'sigmask' is needed to catch intterupts.
613         // This interrupt happens after call to pthread_exit(..., EINTR).
614         // Once a signal handler is registered, pselect will handle interrupts by returning
615         // with '-1' and setting errno appropriately.
616         int ret = pselect(twSock->fd+1, &readFDS, NULL, NULL, NULL, &sigmask);
617         if(ret < 0)
618         {
619             if(errno == EINTR)
620             {
621                 if(twSock->isActive)
622                 {
623                     continue;
624                     // This EINTR signal is not for us. Do not handle it.
625                 }
626                 // Notify other threads waiting for a response that the stack is going down.
627                 pthread_cond_signal(&twSock->queueCV);
628                 OIC_LOG(DEBUG, TAG, "Thread has been joined. Exiting thread.");
629                 pthread_exit(PTHREAD_CANCELED);
630                 return NULL;
631             }
632             else
633             {
634                 OIC_LOG_V(ERROR, TAG, "Unaccounted error occurred. Exiting thread."
635                                      "Errno is: %d", errno);
636                 return NULL;
637             }
638         }
639         else
640         {
641             ret = FD_ISSET(twSock->fd, &readFDS);
642             if(ret != 0)
643             {
644                 // Valid data on valid socket.
645                 // Grab & parse, then pass up to upper layers.
646                 if(haveMutex != true)
647                 {
648                     result = TWGrabMutex(&twSock->mutex);
649                     if(result != TW_RESULT_OK)
650                     {
651                         OIC_LOG(ERROR, TAG, "Unable to grab mutex.");
652                         return NULL;
653                     }
654                     haveMutex = true;
655                 }
656                 entry = readEntry(twSock->fd);
657                 if(!entry)
658                 {
659                     result = TWReleaseMutex(&twSock->mutex);
660                     if(result != TW_RESULT_OK)
661                     {
662                         OIC_LOG(ERROR, TAG, "Unable to release mutex.");
663                         return NULL;
664                     }
665                     haveMutex = false;
666                     // This is most likely a parsing error of the received
667                     // response. Not necessarily fatal.
668                     continue;
669                 }
670                 result = TWEnqueueEntry((PIPlugin_Zigbee *)plugin, entry);
671                 if(result != TW_RESULT_OK)
672                 {
673                     OIC_LOG_V(ERROR, TAG, "Could not add TWEntry to queue for"
674                                           "consumption by the application"
675                                           "layer. Error is: %d", result);
676                     TWDeleteEntry((PIPlugin_Zigbee *)plugin, entry);
677                     // This is most likely a FATAL error, such as out of memory.
678                     break;
679                 }
680
681                 // Notify other threads waiting for a response that an entry has been enqueued.
682                 pthread_cond_signal(&twSock->queueCV);
683
684                 result = TWReleaseMutex(&twSock->mutex);
685                 haveMutex = false;
686             }
687             else
688             {
689                 // Unrelated data waiting elsewhere. Continue the loop.
690                 continue;
691             }
692         }
693     }
694
695     return NULL;
696 }
697
698 TWResultCode TWIssueATCommand(PIPlugin_Zigbee * plugin, const char * command)
699 {
700     if(!plugin || !command)
701     {
702         return TW_RESULT_ERROR_INVALID_PARAMS;
703     }
704     OIC_LOG_V(INFO, TAG, "Attempt to write %s.", command);
705     TWSock * twSock = TWGetSock(plugin);
706     if(!twSock)
707     {
708         return TW_RESULT_ERROR;
709     }
710
711     if(twSock->isActive == false)
712     {
713         return TW_RESULT_ERROR;
714     }
715
716     TWResultCode result = TW_RESULT_OK;
717     TWResultCode mutexResult = TW_RESULT_OK;
718     mutexResult = TWGrabMutex(&twSock->mutex);
719     if(mutexResult != TW_RESULT_OK)
720     {
721         return mutexResult;
722     }
723     size_t sendCommandSize = (strlen(command) + strlen("\r") + 1) * sizeof(char);
724     char * sendCommand = (char *) OICCalloc(1, sendCommandSize);
725     if(!sendCommand)
726     {
727         return TW_RESULT_ERROR_NO_MEMORY;
728     }
729     char * temp = OICStrcpy(sendCommand, sendCommandSize, command);
730     if(temp != sendCommand)
731     {
732         result = TW_RESULT_ERROR;
733         goto exit;
734     }
735     temp = OICStrcat(sendCommand, sendCommandSize, "\r");
736     if(temp != sendCommand)
737     {
738         result = TW_RESULT_ERROR;
739         goto exit;
740     }
741     size_t expectedWrittenBytes = strlen(sendCommand);
742     errno = 0;
743     size_t actualWrittenBytes = write(twSock->fd, sendCommand, expectedWrittenBytes);
744     if(actualWrittenBytes <= 0)
745     {
746         OIC_LOG_V(ERROR, TAG, "Could not write to port. Errno is: %d\n", errno);
747         result =  TW_RESULT_ERROR;
748         goto exit;
749     }
750     if(actualWrittenBytes != expectedWrittenBytes)
751     {
752         OIC_LOG(ERROR, TAG, "Telegesis Adapter did not receive expected command. Unknown state.");
753         result = TW_RESULT_ERROR;
754     }
755
756 exit:
757     mutexResult = TWReleaseMutex(&twSock->mutex);
758     if(mutexResult != TW_RESULT_OK)
759     {
760         return mutexResult;
761     }
762     OICFree(sendCommand);
763     return result;
764 }
765
766 TWResultCode TWEnqueueEntry(PIPlugin_Zigbee * plugin, TWEntry * entry)
767 {
768     if(!plugin || !entry)
769     {
770         return TW_RESULT_ERROR_INVALID_PARAMS;
771     }
772     TWSock * twSock = TWGetSock(plugin);
773     if(!twSock)
774     {
775         return TW_RESULT_ERROR;
776     }
777
778     if(twSock->isActive == false)
779     {
780         return TW_RESULT_ERROR;
781     }
782     LL_APPEND(twSock->queue, entry);
783     return TW_RESULT_OK;
784 }
785
786 TWResultCode TWDequeueEntry(PIPlugin_Zigbee * plugin, TWEntry ** entry, TWEntryType type)
787 {
788     if(!plugin || !entry)
789     {
790         return TW_RESULT_ERROR_INVALID_PARAMS;
791     }
792     TWSock * twSock = TWGetSock(plugin);
793     if(!twSock)
794     {
795         return TW_RESULT_ERROR;
796     }
797
798     if(twSock->isActive == false)
799     {
800         return TW_RESULT_ERROR;
801     }
802
803     TWResultCode ret = TW_RESULT_OK;
804
805     // If no entry is found, then this code path returns immediately.
806     ret = TWGrabMutex(&twSock->mutex);
807     if(ret != TW_RESULT_OK)
808     {
809         return ret;
810     }
811     *entry = NULL;
812     if(type != TW_NONE)
813     {
814         struct timespec abs_time;
815         clock_gettime(CLOCK_REALTIME , &abs_time);
816         abs_time.tv_sec += TIME_OUT_10_SECONDS;
817         while(!*entry)
818          {
819             // Wait for up to 10 seconds for the entry to put into the queue.
820             ret = TWWait(&twSock->queueCV, &twSock->mutex, TIME_OUT_10_SECONDS);
821             if(ret != TW_RESULT_OK)
822             {
823                 return ret;
824             }
825             if(twSock->isActive == false)
826             {
827                 break;
828             }
829             TWEntry * out = NULL;
830             TWEntry * temp = NULL;
831             LL_FOREACH_SAFE(twSock->queue, out, temp)
832              {
833                 if(out->type == type)
834                 {
835                     *entry = out;
836                     break;
837                 }
838             }
839             struct timespec cur_time;
840             clock_gettime(CLOCK_REALTIME, &cur_time);
841             if(cur_time.tv_sec >= abs_time.tv_sec)
842             {
843                 break;
844             }
845         }
846     }
847     else
848     {
849         *entry = twSock->queue;
850     }
851     if(*entry)
852     {
853         LL_DELETE(twSock->queue, *entry);
854     }
855     return TWReleaseMutex(&twSock->mutex);
856 }
857
858 TWResultCode TWFreeQueue(PIPlugin_Zigbee * plugin)
859 {
860     if(!plugin)
861     {
862         return TW_RESULT_ERROR_INVALID_PARAMS;
863     }
864     TWResultCode ret = TW_RESULT_OK;
865     TWEntry * entry = NULL;
866     while(true)
867     {
868         ret = TWDequeueEntry(plugin, &entry, TW_NONE);
869         if(ret != TW_RESULT_OK)
870         {
871             return ret;
872         }
873         if(entry == NULL)
874         {
875             break;
876         }
877         ret = TWDeleteEntry(plugin, entry);
878         if(ret != TW_RESULT_OK)
879         {
880             return ret;
881         }
882     }
883     return ret;
884 }
885
886 TWResultCode TWDeleteEntry(PIPlugin_Zigbee * plugin, TWEntry * entry)
887 {
888     if(!plugin || !entry)
889     {
890         return TW_RESULT_ERROR_INVALID_PARAMS;
891     }
892
893     TWSock * twSock = TWGetSock(plugin);
894     if(!twSock)
895     {
896         return TW_RESULT_ERROR;
897     }
898
899     if(twSock->isActive == false)
900     {
901         return TW_RESULT_ERROR;
902     }
903
904     TWResultCode ret = TWGrabMutex(&twSock->mutex);
905     if(ret != TW_RESULT_OK)
906     {
907         return ret;
908     }
909     TWEntry * out = NULL;
910     TWEntry * tmp = NULL;
911     LL_FOREACH_SAFE(twSock->queue, out, tmp)
912     {
913         if(out == entry)
914         {
915             OIC_LOG(ERROR, TAG, "Tried to delete an entry that is still in the queue. \
916                                 Please dequeue the entry first.");
917             return TW_RESULT_ERROR;
918         }
919     }
920     ret = TWReleaseMutex(&twSock->mutex);
921
922     OICFree(entry);
923
924     return TW_RESULT_OK;
925 }
926
927 TWResultCode TWGetEUI(PIPlugin_Zigbee * plugin, char ** eui)
928 {
929     if(!plugin || !eui)
930     {
931         return TW_RESULT_ERROR_INVALID_PARAMS;
932     }
933     TWSock * twSock = TWGetSock(plugin);
934     if(!twSock)
935     {
936         return TW_RESULT_ERROR;
937     }
938
939     if(twSock->isActive == false)
940     {
941         return TW_RESULT_ERROR;
942     }
943
944     *eui = OICStrdup(twSock->eui);
945
946     return TW_RESULT_OK;
947
948 }
949
950 TWResultCode TWStopSock(PIPlugin_Zigbee * plugin)
951 {
952     if(!plugin)
953     {
954         return TW_RESULT_ERROR_INVALID_PARAMS;
955     }
956     TWSock * twSock = TWGetSock(plugin);
957     if(!twSock)
958     {
959         return TW_RESULT_ERROR;
960     }
961
962     if(twSock->isActive == false)
963     {
964         return TW_RESULT_ERROR;
965     }
966
967     TWResultCode ret = TWFreeQueue(plugin);
968     if(ret != TW_RESULT_OK)
969     {
970         return ret;
971     }
972
973     twSock->isActive = false;
974
975     void * retVal = NULL;
976     int pthreadRet = pthread_kill(twSock->threadHandle, EINTR);
977     if(pthreadRet != 0)
978     {
979         return TW_RESULT_ERROR;
980     }
981
982     pthreadRet = pthread_join(twSock->threadHandle, &retVal);
983     if(pthreadRet != 0)
984     {
985         switch(pthreadRet)
986         {
987             case EDEADLK:
988                 OIC_LOG(ERROR, TAG, "A deadlock has occurred.");
989                 break;
990             case EINVAL:
991                 OIC_LOG(ERROR, TAG, "Thread is not joinable or another thread has already joined.");
992                 break;
993             case ESRCH:
994                 OIC_LOG(ERROR, TAG, "No thread with the ID could be found.");
995                 break;
996             default:
997                 OIC_LOG_V(ERROR, TAG, "Unknown error occurred when joining thread: %d", pthreadRet);
998         }
999         return TW_RESULT_ERROR;
1000     }
1001     if(retVal != PTHREAD_CANCELED)
1002     {
1003         return TW_RESULT_ERROR;
1004     }
1005     ret = TWDeleteTWSock(twSock);
1006     if(ret != TW_RESULT_OK)
1007     {
1008         return ret;
1009     }
1010
1011     return ret;
1012 }
1013