LCOV - code coverage report
Current view: top level - src/plugins/network - network.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 58 80 72.5 %
Date: 2019-09-12 12:28:41 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /**
       2             :  * @file
       3             :  *
       4             :  * @brief
       5             :  *
       6             :  * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
       7             :  */
       8             : 
       9             : #include "network.h"
      10             : 
      11             : #ifndef HAVE_KDBCONFIG
      12             : #include "kdbconfig.h"
      13             : #endif
      14             : 
      15             : /* Obtain address(es) matching host/port */
      16        1053 : int elektraNetworkAddrInfo (Key * toCheck)
      17             : {
      18             :         struct addrinfo * result;
      19             :         int s;
      20             : 
      21        1053 :         const Key * meta = keyGetMeta (toCheck, "check/ipaddr");
      22             : 
      23        1053 :         if (!meta) return 0; /* No check to do */
      24             : 
      25             :         struct addrinfo hints;
      26        1032 :         memset (&hints, 0, sizeof (struct addrinfo));
      27             :         hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
      28        1032 :         if (!strcmp (keyString (meta), "ipv4"))
      29             :         {
      30          19 :                 hints.ai_family = AF_INET;
      31          19 :                 hints.ai_flags = AI_NUMERICHOST; /* Only accept numeric hosts */
      32             :         }
      33        1013 :         else if (!strcmp (keyString (meta), "ipv6"))
      34             :         {
      35         993 :                 hints.ai_family = AF_INET6;
      36         993 :                 hints.ai_flags = AI_NUMERICHOST; /* Only accept numeric hosts */
      37             :         }
      38        1032 :         hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
      39        1032 :         hints.ai_protocol = 0;          /* Any protocol */
      40             : 
      41        1032 :         s = getaddrinfo (keyString (toCheck), NULL, &hints, &result);
      42             : 
      43        1032 :         if (s != 0)
      44             :         {
      45             :                 return s;
      46             :         }
      47             : 
      48         379 :         freeaddrinfo (result);
      49             : 
      50         379 :         return 0;
      51             : }
      52             : 
      53         400 : int elektraPortInfo (Key * toCheck, Key * parentKey)
      54             : {
      55         400 :         const Key * meta = keyGetMeta (toCheck, "check/port");
      56         400 :         const Key * listenMeta = keyGetMeta (toCheck, "check/port/listen");
      57         400 :         if (!meta && !listenMeta) return 0; /* No check to do */
      58          18 :         char * endptr = NULL;
      59          18 :         long portNumber = strtol (keyString (toCheck), &endptr, 10);
      60             :         int portNumberNetworkByteOrder;
      61             : 
      62          18 :         if (*endptr == '\0')
      63             :         {
      64          10 :                 if (portNumber < 0 || portNumber > 65535)
      65             :                 {
      66           4 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Port %ld on key %s was not within 0 - 65535", portNumber,
      67             :                                                                 keyName (toCheck));
      68           4 :                         return -1;
      69             :                 }
      70           6 :                 portNumberNetworkByteOrder = htons (portNumber);
      71             :         }
      72             :         else
      73             :         {
      74             :                 struct servent * service;
      75           8 :                 service = getservbyname (keyString (toCheck), NULL); // NULL means we accept both tcp and udp
      76           8 :                 if (service == NULL)
      77             :                 {
      78           4 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Could not find service with name %s on key %s. Reason: %s",
      79             :                                                                 keyString (toCheck), keyName (toCheck), strerror (errno));
      80           4 :                         return -1;
      81             :                 }
      82           4 :                 portNumberNetworkByteOrder = service->s_port;
      83             :         }
      84             : 
      85          10 :         if (!listenMeta) return 0; /* No check to do */
      86             : 
      87           0 :         char const * hostname = "localhost";
      88             : 
      89             :         int sockfd;
      90             :         struct sockaddr_in serv_addr;
      91             :         struct hostent * server;
      92           0 :         sockfd = socket (AF_INET, SOCK_STREAM, 0);
      93             : 
      94           0 :         if (sockfd < 0)
      95             :         {
      96           0 :                 ELEKTRA_SET_RESOURCE_ERRORF (parentKey, "Could not open a socket. Reason: %s", strerror (errno));
      97             :         }
      98             : 
      99           0 :         server = gethostbyname (hostname);
     100           0 :         if (server == NULL)
     101             :         {
     102           0 :                 if (errno == HOST_NOT_FOUND)
     103             :                 {
     104           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Could not connect to %s: No such host", hostname);
     105           0 :                         return -1;
     106             :                 }
     107             :                 else
     108             :                 {
     109           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "There was an error trying to connect to host '%s'. Reason: %s",
     110             :                                                                 hostname, strerror (errno));
     111           0 :                         return -1;
     112             :                 }
     113             :                 // TODO: Maybe consider errno == TRY_AGAIN separately and try to reconnect
     114             :         }
     115             : 
     116             : 
     117           0 :         bzero ((char *) &serv_addr, sizeof (serv_addr));
     118           0 :         serv_addr.sin_family = AF_INET;
     119           0 :         bcopy ((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length);
     120             : 
     121           0 :         serv_addr.sin_port = (in_port_t) portNumberNetworkByteOrder;
     122           0 :         if (bind (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
     123             :         {
     124           0 :                 close (sockfd);
     125           0 :                 if (errno == EADDRINUSE)
     126             :                 {
     127           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey, "Port %s is already in use which was specified on key %s",
     128             :                                                                 keyString (toCheck), keyName (toCheck));
     129             :                 }
     130             :                 else
     131             :                 {
     132           0 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERRORF (parentKey,
     133             :                                                                 "Could not bind to port %s which was specified on key %s. Reason: %s",
     134             :                                                                 keyString (toCheck), keyName (toCheck), strerror (errno));
     135             :                 }
     136             :                 return -1;
     137             :         }
     138           0 :         close (sockfd);
     139             : 
     140           0 :         return 0;
     141             : }
     142             : 
     143          47 : int elektraNetworkGet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey ELEKTRA_UNUSED)
     144             : {
     145             :         /* configuration only */
     146             :         KeySet * n;
     147          47 :         ksAppend (returned,
     148          47 :                   n = ksNew (30, keyNew ("system/elektra/modules/network", KEY_VALUE, "network plugin waits for your orders", KEY_END),
     149             :                              keyNew ("system/elektra/modules/network/exports", KEY_END),
     150             :                              keyNew ("system/elektra/modules/network/exports/get", KEY_FUNC, elektraNetworkGet, KEY_END),
     151             :                              keyNew ("system/elektra/modules/network/exports/set", KEY_FUNC, elektraNetworkSet, KEY_END),
     152             :                              keyNew ("system/elektra/modules/network/exports/elektraNetworkAddrInfo", KEY_FUNC, elektraNetworkAddrInfo,
     153             :                                      KEY_END),
     154             :                              keyNew ("system/elektra/modules/network/exports/elektraPortInfo", KEY_FUNC, elektraNetworkAddrInfo, KEY_END),
     155             : 
     156             : #include "readme_network.c"
     157             : 
     158             :                              keyNew ("system/elektra/modules/network/infos/version", KEY_VALUE, PLUGINVERSION, KEY_END), KS_END));
     159          47 :         ksDel (n);
     160             : 
     161          47 :         return 1; /* success */
     162             : }
     163             : 
     164        1050 : int elektraNetworkSet (Plugin * handle ELEKTRA_UNUSED, KeySet * returned, Key * parentKey)
     165             : {
     166             :         /* check all keys */
     167             :         Key * cur;
     168        1050 :         ksRewind (returned);
     169        2492 :         while ((cur = ksNext (returned)) != 0)
     170             :         {
     171        1053 :                 int s = elektraNetworkAddrInfo (cur);
     172        1053 :                 if (s != 0)
     173             :                 {
     174         653 :                         const char * gaimsg = gai_strerror (s);
     175         653 :                         char * errmsg = elektraMalloc (strlen (gaimsg) + keyGetNameSize (cur) + keyGetValueSize (cur) +
     176             :                                                        sizeof ("name:  value:  message: "));
     177         653 :                         strcpy (errmsg, "name: ");
     178         653 :                         strcat (errmsg, keyName (cur));
     179         653 :                         strcat (errmsg, " value: ");
     180         653 :                         strcat (errmsg, keyValue (cur));
     181         653 :                         strcat (errmsg, " message: ");
     182         653 :                         strcat (errmsg, gaimsg);
     183         653 :                         ELEKTRA_SET_VALIDATION_SEMANTIC_ERROR (parentKey, errmsg);
     184         653 :                         elektraFree (errmsg);
     185         653 :                         return -1;
     186             :                 }
     187         400 :                 int p = elektraPortInfo (cur, parentKey);
     188         400 :                 if (p != 0)
     189             :                 {
     190             :                         return -1;
     191             :                 }
     192             :         }
     193             : 
     194             :         return 1; /* success */
     195             : }
     196             : 
     197        1169 : Plugin * ELEKTRA_PLUGIN_EXPORT
     198             : {
     199             :         // clang-format off
     200        1169 :         return elektraPluginExport ("network",
     201             :                                     ELEKTRA_PLUGIN_GET, &elektraNetworkGet,
     202             :                                     ELEKTRA_PLUGIN_SET, &elektraNetworkSet,
     203             :                                     ELEKTRA_PLUGIN_END);
     204             : }
     205             : 

Generated by: LCOV version 1.13