]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - apps/tidep0084.git/blob - tutorials/generic_sensor_tutorial/final/SensorToCloud/components/common/src/stream_socket_private.c
Added Support for Generic Sensor Tutorial which provides instructions on how to add...
[apps/tidep0084.git] / tutorials / generic_sensor_tutorial / final / SensorToCloud / components / common / src / stream_socket_private.c
1 /******************************************************************************
2  @file stream_socket_private.c
4  @brief TIMAC 2.0 API Socket abstraction shared code (server & client)
6  Group: WCS LPC
7  $Target Devices: Linux: AM335x, Embedded Devices: CC1310, CC1350$
9  ******************************************************************************
10  $License: BSD3 2016 $
11   
12    Copyright (c) 2015, Texas Instruments Incorporated
13    All rights reserved.
14   
15    Redistribution and use in source and binary forms, with or without
16    modification, are permitted provided that the following conditions
17    are met:
18   
19    *  Redistributions of source code must retain the above copyright
20       notice, this list of conditions and the following disclaimer.
21   
22    *  Redistributions in binary form must reproduce the above copyright
23       notice, this list of conditions and the following disclaimer in the
24       documentation and/or other materials provided with the distribution.
25   
26    *  Neither the name of Texas Instruments Incorporated nor the names of
27       its contributors may be used to endorse or promote products derived
28       from this software without specific prior written permission.
29   
30    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
32    THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33    PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
36    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
37    OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
38    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
39    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
40    EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41  ******************************************************************************
42  $Release Name: TI-15.4Stack Linux x64 SDK$
43  $Release Date: Jun 28, 2017 (2.02.00.03)$
44  *****************************************************************************/
46 #include "compiler.h"
47 #include "stream.h"
48 #include "stream_socket.h"
49 #include "log.h"
50 #include "timer.h"
51 #include "void_ptr.h"
52 #include "unix_fdrw.h"
54 #include <sys/types.h>
55 #if defined(__linux__)
56 #include <sys/socket.h>
57 #include <netdb.h>
58 #include <unistd.h>
59 #include <arpa/inet.h>
60 #include <unistd.h>
61 #endif
62 #if defined(_MSC_VER)
63 #include "winsock2.h"
64 #include "ws2tcpip.h"
65 #endif
67 #define _STREAM_SOCKET_PRIVATE 1450384394
68 #include "stream_socket_private.h"
70 #include "errno.h"
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include "hlos_specific.h"
76 int _socket_errno(void)
77 {
78     int e;
79 #if defined(__linux__)
80     e = errno;
81 #endif
82 #if defined(_MSC_VER)
83     e = WSAGetLastError();
84 #endif
85     return (e);
86 }
88 /*!
89  * @var socket_test
90  * @brief [private] Used to verify a linux socket pointer
91  * Also answer to live, universe, and everything..
92  */
93 static const int socket_test = 42;
95 /*!
96  * @brief Release memory in the 'cfg' structure.
97  */
98 static void _stream_socket_cfg_free(struct linux_socket *pS)
99 {
100     /* release what we got */
101     if(pS->cfg.host)
102     {
103         free_const((const void *)(pS->cfg.host));
104     }
105     if(pS->cfg.service)
106     {
107         free_const((const void *)(pS->cfg.service));
108     }
109     if(pS->cfg.device_binding)
110     {
111         free_const((const void *)(pS->cfg.device_binding));
112     }
114     /* clear pointers */
115     pS->cfg.host           = NULL;
116     pS->cfg.service        = NULL;
117     pS->cfg.device_binding = NULL;
120 /*!
121  * @brief Copy (and reallocate as needed) a socket configuration structure.
122  */
123 static int _stream_socket_cfg_copy(struct linux_socket *pS,
124                                     const struct socket_cfg *pCFG)
126     int r;
128     /* assume success */
129     r = 0;
131     /* Bulk copy */
132     pS->cfg = *pCFG;
134     /* If host was specified, make our own copy */
135     if(pS->cfg.host)
136     {
137         pS->cfg.host = strdup(pS->cfg.host);
138         if(pS->cfg.host == NULL)
139         {
140             r = -1;
141         }
142     }
144     /* same for service */
145     if(pS->cfg.service)
146     {
147         pS->cfg.service = strdup(pS->cfg.service);
148         if(pS->cfg.service == NULL)
149         {
150             r = -1;
151         }
152     }
154     /* same for finding */
155     if(pS->cfg.device_binding)
156     {
157         pS->cfg.device_binding = strdup(pS->cfg.device_binding);
158         if(pS->cfg.device_binding == NULL)
159         {
160             r = -1;
161         }
162     }
164     /* if something went wrong... cleanup allocation */
165     if(r < 0)
166     {
167         /* something is wrong... something failed */
168         LOG_printf(LOG_ERROR, "socket-cfg-copy no memory\n");
170         _stream_socket_cfg_free(pS);
171     }
172     /* return Great Success */
173     return (r);
176 /*
177  * pseudo-private function to create a linux socket structure
178  * Used by both client and server sockets.
179  *
180  * Pseudo-private function defined in stream_socket_private.h
181  */
182 struct linux_socket *_stream_socket_create(const struct socket_cfg *pCFG,
183                                             const struct io_stream_funcs *pFuncs)
185     /* this is the source of our connection ids it must be static. */
186     static int connection_counter;
188     struct linux_socket *pS;
189     int r;
191     switch (pCFG->inet_4or6)
192     {
193     case 0: /* pick randomly */
194     case 4: /* specifically inet4 */
195     case 6: /* specifically inet6 */
196         break;
197     default:
198         LOG_printf(LOG_ERROR, "invalid inet_4or6\n");
199         return (0);
200     }
202     pS = calloc(1, sizeof(*pS));
203     if(pS == NULL)
204     {
205         LOG_printf(LOG_ERROR, "socket-client no memory\n");
206         return (pS);
207     }
209     _ATOMIC_global_lock();
210     connection_counter++;
211     pS->connection_id = connection_counter;
212     _ATOMIC_global_unlock();
214     pS->test_ptr     = &(socket_test);
215     pS->pParent      = STREAM_createPrivate(pFuncs, (intptr_t)(pS));
216     if(pS->pParent == NULL)
217     {
218         memset((void *)(pS), 0, sizeof(*pS));
219         return (NULL);
220     }
222     pS->h            = -1;
223     r = _stream_socket_cfg_copy(pS, pCFG);
224     if(r < 0)
225     {
226         STREAM_destroyPrivate(pS->pParent);
227         free((void *)(pS));
228         pS = NULL;
229     }
230     else
231     {
232         /* UPDATE internal pointers */
233         pS->is_connected = false;
234         pS->err_action   = "client-create";
235     }
237     return (pS);
240 /*
241  * Determine if a socket is connected or not.
242  *
243  * Public function defined in stream_socket.h
244  */
245 bool STREAM_SOCKET_isConnected(intptr_t h)
247     struct linux_socket *pS;
248     bool answer;
250     answer = false;
251     pS = _stream_socket_h2ps(h,0);
252     if(pS)
253     {
254         answer = pS->is_connected;
255     }
256     return (answer);
259 /*
260  * Destroy a socket created by various SOCKET_<name>_create() calls
261  *
262  * Public function defined in stream_socket.h
263  */
264 void SOCKET_destroy(intptr_t h)
266     if(h)
267     {
268         _stream_socket_destroy(_stream_socket_h2ps(h,0));
269     }
272 /*
273  * Pseudo-private destroy function for sockets
274  * Shared by both client and server socket code.
275  *
276  * Pseudo-private function defined in stream_socket_private.h
277  */
278 void _stream_socket_destroy(struct linux_socket *pS)
280     if(pS == NULL)
281     {
282         return;
283     }
284     if(pS->h > 0)
285     {
286         _stream_socket_close(pS);
287     }
288     if(pS->pParent)
289     {
290         STREAM_destroyPrivate(pS->pParent);
291         pS->pParent = NULL;
292     }
293     _stream_socket_cfg_free(pS);
295     memset((void *)(pS), 0, sizeof(*pS));
298 /*
299  * Mark a socket as a reusable socket  (avoids address in use errors)
300  * Pseudo-private function shared across socket types
301  *
302  * Pseudo-private function defined in stream_socket_private
303  */
304 int _stream_socket_reuse(struct linux_socket *pS)
306     int r,f,v;
308     /* Mark as reuseable, avoid EADDRINUSE errors */
309     /* http://linux.die.net/man/7/socket */
310     /* http://linux.die.net/man/2/setsockopt */
311     f = SO_REUSEADDR;
312 #if defined(SO_REUSEPORT)
313     /* http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t */
314     /* post Linux 3.9 */
315     f |= SO_REUSEPORT;
316 #endif
317     v = 1;
318     r = setsockopt(pS->h, SOL_SOCKET, f, (const void *)(&v), sizeof(v));
319     if(r < 0)
320     {
321         _stream_socket_error(pS, "setsocketopt(SO_REUSEADDR)", errno, NULL);
322     }
323     return (r);
326 /*
327  * Bind this socket to a specific device, ie: 'eth0' vrs 'eth1'
328  * Pseudo-private to socket implimentations.
329  *
330  * Pseudo-private function defined in stream_socket_private
331  */
332 int _stream_socket_bind_to_device(struct linux_socket *pS)
334     size_t l;
335     int r;
337     /* accept *NO* binding */
338     if(pS->cfg.device_binding == NULL)
339     {
340         return (0);
341     }
342     /* or blank binding */
343     l = strlen(pS->cfg.device_binding);
344     if(l == 0)
345     {
346         return (0);
347     }
348 #if defined(_MSC_VER)
349     /* not supported on windows */
350     r = 0;
351 #else
352     /* http://linux.die.net/man/7/socket */
353     /* http://linux.die.net/man/2/setsockopt */
354     r = setsockopt(pS->h,
355                     SOL_SOCKET,
356                     SO_BINDTODEVICE,
357                     ((const void *)(pS->cfg.device_binding)),
358                     strlen(pS->cfg.device_binding));
359 #endif
360     if(r < 0)
361     {
362         _stream_socket_error(pS, "bind()", _socket_errno(),NULL);
363     }
364     return (r);
367 /*
368  * Print an error message with this socket and mark the stream as in error
369  *
370  * Pseudo-private function defined in stream_socket_private.h
371  */
372 void _stream_socket_error(struct linux_socket *pS,
373                           const char *msg1,
374                           int errnum,
375                           const char *msg2)
377     const char *host;
379     host = pS->cfg.host;
380     if(host == NULL)
381     {
382         host = "(null-host)";
383     }
384     pS->pParent->is_error = true;
385     if(msg2 == NULL)
386     {
387         msg2 = "";
388         if(errnum != 0)
389         {
390 #if defined(__linux__)
391             msg2 = strerror(errnum);
392 #endif
393 #if defined(_MSC_VER)
394             msg2 = gai_strerrorA(errnum);
395 #endif
396         }
397     }
398     LOG_printf(LOG_ERROR, "socket(%c,%s:%s) %s %s %d %s\n",
399                 pS->cfg.ascp,
400                 host,
401                 pS->cfg.service,
402                 pS->err_action,
403                 msg1,
404                 errnum,
405                 msg2);
408 /*
409  * Pseudo-private socket function that converts a stream handle
410  * into a socket structure pointer
411  *
412  * Pseudo-private function defined in stream_socket_private.h
413  */
414 struct linux_socket *_stream_socket_io2ps(struct io_stream *pIO, int typecode)
416     struct linux_socket *pS;
417     pS = (struct linux_socket *)(pIO->opaque_ptr);
419     if(pS == NULL)
420     {
421     bad:
422         LOG_printf(LOG_ERROR, "not a socket handle: %p (it is a: %s)\n",
423                     (void *)(pIO), pIO->pFuncs->name );
424         return (NULL);
425     }
427     if(pS->test_ptr != &(socket_test))
428     {
429         goto bad;
430     }
432     if(typecode)
433     {
434         if(pS->cfg.ascp != typecode)
435         {
436             pS->err_action = "get-type";
437             _stream_socket_error(pS, "wrong-socket-type", 0, "");
438             /* return failure */
439             pS = NULL;
440         }
441     }
442     return (pS);
445 /*
446  * convert a handle into a linux socket pointer
447  * Shared by both client and server socket code
448  *
449  * Pseudo-private function defined in stream_socket_private.h
450  */
451 struct linux_socket *_stream_socket_h2ps(intptr_t h, int typecode)
453     struct io_stream *pIO;
455     pIO = STREAM_hToStruct(h);
456     if(pIO == NULL)
457     {
458         return (NULL);
459     }
461     return (_stream_socket_io2ps(pIO, typecode));
464 /*
465  * Return true if this handle is a socket handle
466  *
467  * Public function defined in stream_socket.h
468  */
469 bool STREAM_isSocket(intptr_t h)
471     struct io_stream *pIO;
472     struct linux_socket *pS;
474     pIO = STREAM_hToStruct(h);
475     if(pIO == NULL)
476     {
477         return (false);
478     }
479     pS = (struct linux_socket *)(pIO->opaque_ptr);
481     if(pS->test_ptr == &(socket_test))
482     {
483         return (true);
484     }
485     else
486     {
487         return (false);
488     }
491 /*
492  * Psuedo-private function to close a socket.
493  * Shared between client and server sockets
494  *
495  * Pseudo-private function defined in stream_socket_private.h
496  */
497 void _stream_socket_close(struct linux_socket *pS)
499     pS->is_connected = false;
500     /* clear the error because we closed the connection */
501     pS->pParent->is_error = false;
503     /* close it */
504     if(pS->h >= 0)
505     {
506         LOG_printf(LOG_DBG_SOCKET, "socket_close(%c,%s:%s)\n",
507                     pS->cfg.ascp,
508                     pS->cfg.host ? pS->cfg.host : "server",
509                     pS->cfg.service);
510 #if defined(_MSC_VER)
511         closesocket(pS->h);
512 #endif
513 #if defined(__linux__)
514         close(pS->h);
515 #endif
516         pS->h = -1;
517         if(pS->h != -1)
518         {
519             BUG_HERE("need to close this\n");
520         }
521     }
524 /*
525  * Pseudo private function to poll (read) a socket
526  * Shared between client and server sockets.
527  *
528  * Pseudo-private function defined in stream_socket_private.h
529  */
530 bool _stream_socket_poll(struct linux_socket *pS, int mSecs_timeout)
532     int r;
534     /* assume ok to poll */
535     r = 0;
537     pS->err_action = "poll";
538     switch(pS->cfg.ascp)
539     {
540     default:
541         _stream_socket_error(pS, "not-valid-poll-state", 0, "");
542         r = -1;
543         break;
544     case 'c':
545         if(!(pS->is_connected))
546         {
547             r = -1;
548             _stream_socket_error(pS, "not connected", 0, "");
549         }
550         break;
551     case 's':
552         _stream_socket_error(pS, "not-listen-state", 0, "");
553         r = -1;
554         break;
555     case 'l':
556         /* we can poll */
557         break;
558     case 'a':
559         /* yes we can poll! */
560         break;
561     }
562     if(r < 0)
563     {
564         _stream_socket_error(pS, "poll bad socket type", 0, "");
565         r = -1;
566     }
567     if(r >= 0)
568     {
569         struct unix_fdrw rw;
570         memset(&rw, 0, sizeof(rw));
571         rw.is_connected  = true;
572         rw.fd            = pS->h;
573         rw.rw            = 'r';
574         rw.log_prefix    = "socket-poll";
575         rw.log_why       = LOG_DBG_SOCKET;
576         rw.mSecs_timeout = mSecs_timeout;
577         rw.type          = 's';
578         r = POLL_readable(&rw);
579         if(r < 0)
580         {
581             _stream_socket_error(pS,"poll error", 0, "");
582         }
583     }
585     if(r > 0)
586     {
587         return (true);
588     }
589     else
590     {
591         return (false);
592     }
595 /*
596  *  ========================================
597  *  Texas Instruments Micro Controller Style
598  *  ========================================
599  *  Local Variables:
600  *  mode: c
601  *  c-file-style: "bsd"
602  *  tab-width: 4
603  *  c-basic-offset: 4
604  *  indent-tabs-mode: nil
605  *  End:
606  *  vim:set  filetype=c tabstop=4 shiftwidth=4 expandtab=true
607  */