| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | #ifndef NETDATA_SYSTEM_SERVICES_H |
| 4 | #define NETDATA_SYSTEM_SERVICES_H |
| 5 | |
| 6 | #include "libnetdata/libnetdata.h" |
| 7 | #include <netdb.h> |
| 8 | |
| 9 | // -------------------------------------------------------------------------------------------------------------------- |
| 10 | // hashtable for caching port and protocol to service name mappings |
| 11 | // key is the combination of protocol and port packed into an uint64_t, value is service name (STRING) |
| 12 | |
| 13 | #define SIMPLE_HASHTABLE_VALUE_TYPE STRING * |
| 14 | #define SIMPLE_HASHTABLE_NAME _SERVICENAMES_CACHE |
| 15 | #include "libnetdata/simple_hashtable/simple_hashtable.h" |
| 16 | |
| 17 | typedef struct servicenames_cache { |
| 18 | SPINLOCK spinlock; |
| 19 | SIMPLE_HASHTABLE_SERVICENAMES_CACHE ht; |
| 20 | } SERVICENAMES_CACHE; |
| 21 | |
| 22 | static inline const char *system_servicenames_ipproto2str(uint16_t ipproto) { |
| 23 | return (ipproto == IPPROTO_TCP) ? "tcp" : "udp"; |
| 24 | } |
| 25 | |
| 26 | static inline const char *static_portnames(uint16_t port, uint16_t ipproto) { |
| 27 | if(port == 19999 && ipproto == IPPROTO_TCP) |
| 28 | return "netdata"; |
| 29 | |
| 30 | if(port == 8125) |
| 31 | return "statsd"; |
| 32 | |
| 33 | return NULL; |
| 34 | } |
| 35 | |
| 36 | static inline STRING *system_servicenames_cache_lookup(SERVICENAMES_CACHE *sc, uint16_t port, uint16_t ipproto) { |
| 37 | struct { |
| 38 | uint16_t ipproto; |
| 39 | uint16_t port; |
| 40 | } key = { |
| 41 | .ipproto = ipproto, |
| 42 | .port = port, |
| 43 | }; |
| 44 | XXH64_hash_t hash = XXH3_64bits(&key, sizeof(key)); |
| 45 | |
| 46 | spinlock_lock(&sc->spinlock); |
| 47 | |
| 48 | SIMPLE_HASHTABLE_SLOT_SERVICENAMES_CACHE *sl = simple_hashtable_get_slot_SERVICENAMES_CACHE(&sc->ht, hash, &key, true); |
| 49 | STRING *s = SIMPLE_HASHTABLE_SLOT_DATA(sl); |
| 50 | if (!s) { |
| 51 | const char *st = static_portnames(port, ipproto); |
| 52 | if(st) { |
| 53 | s = string_strdupz(st); |
| 54 | } |
| 55 | else { |
| 56 | struct servent *se = getservbyport(htons(port), system_servicenames_ipproto2str(ipproto)); |
| 57 | |
| 58 | if (!se || !se->s_name) { |
| 59 | char name[50]; |
| 60 | snprintfz(name, sizeof(name), "%u/%s", port, system_servicenames_ipproto2str(ipproto)); |
| 61 | s = string_strdupz(name); |
| 62 | } |
| 63 | else |
| 64 | s = string_strdupz(se->s_name); |
| 65 | } |
| 66 | |
| 67 | simple_hashtable_set_slot_SERVICENAMES_CACHE(&sc->ht, sl, hash, s); |
| 68 | } |
| 69 | |
| 70 | s = string_dup(s); |
| 71 | spinlock_unlock(&sc->spinlock); |
| 72 | return s; |
| 73 | } |
| 74 | |
| 75 | static inline SERVICENAMES_CACHE *system_servicenames_cache_init(void) { |
| 76 | SERVICENAMES_CACHE *sc = callocz(1, sizeof(*sc)); |
| 77 | spinlock_init(&sc->spinlock); |
| 78 | simple_hashtable_init_SERVICENAMES_CACHE(&sc->ht, 100); |
| 79 | return sc; |
| 80 | } |
| 81 | |
| 82 | static inline void system_servicenames_cache_destroy(SERVICENAMES_CACHE *sc) { |
| 83 | spinlock_lock(&sc->spinlock); |
| 84 | |
| 85 | for (SIMPLE_HASHTABLE_SLOT_SERVICENAMES_CACHE *sl = simple_hashtable_first_read_only_SERVICENAMES_CACHE(&sc->ht); |
| 86 | sl; |
| 87 | sl = simple_hashtable_next_read_only_SERVICENAMES_CACHE(&sc->ht, sl)) { |
| 88 | STRING *s = SIMPLE_HASHTABLE_SLOT_DATA(sl); |
| 89 | string_freez(s); |
| 90 | } |
| 91 | |
| 92 | simple_hashtable_destroy_SERVICENAMES_CACHE(&sc->ht); |
| 93 | freez(sc); |
| 94 | } |
| 95 | |
| 96 | #endif //NETDATA_SYSTEM_SERVICES_H |