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