/* cf_fault_sink_hold * Register but don't activate a sink for faults - return sink object pointer on * success, NULL on failure. Only use at startup when parsing config file. After * all sinks are registered, activate via cf_fault_sink_activate_all_held(). */ cf_fault_sink * cf_fault_sink_hold(char *path) { if (num_held_fault_sinks >= CF_FAULT_SINKS_MAX) { cf_warning(CF_MISC, "too many fault sinks"); return NULL; } cf_fault_sink *s = &cf_fault_sinks[num_held_fault_sinks]; s->path = cf_strdup(path); if (! s->path) { cf_warning(CF_MISC, "failed allocation for sink path"); return NULL; } // If a context is not added, its runtime default will be CF_INFO. for (int i = 0; i < CF_FAULT_CONTEXT_UNDEF; i++) { s->limit[i] = CF_INFO; } num_held_fault_sinks++; return s; }
void cloneIC(icol_t *dic, icol_t *sic) { bzero(dic, sizeof(icol_t)); dic->cmatch = sic->cmatch; dic->nlo = sic->nlo; //printf("cloneIC: cmatch: %d nlo: %d\n", dic->cmatch, dic->nlo); if (dic->nlo) { dic->lo = cf_malloc(sizeof(char *) * dic->nlo); for (uint32 j = 0; j < dic->nlo; j++) { dic->lo[j] = cf_strdup(sic->lo[j]); } } }
int cf_ipaddr_get(int socket, char *nic_id, char **node_ip ) { struct sockaddr_in sin; struct ifreq ifr; in_addr_t ip_addr; memset(&ip_addr, 0, sizeof(in_addr_t)); memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); // copy the nic name (eth0, eth1, eth2, etc.) ifr variable structure strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); // get the ifindex for the adapter... if (ioctl(socket, SIOCGIFINDEX, &ifr) < 0) { cf_debug(CF_MISC, "Can't get ifindex for adapter %s - %d %s\n", nic_id, errno, cf_strerror(errno)); return(-1); } // get the IP address memset(&sin, 0, sizeof(struct sockaddr)); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, nic_id, IFNAMSIZ); ifr.ifr_addr.sa_family = AF_INET; if (ioctl(socket, SIOCGIFADDR, &ifr)< 0) { cf_debug(CF_MISC, "can't get IP address: %d %s", errno, cf_strerror(errno)); return(-1); } memcpy(&sin, &ifr.ifr_addr, sizeof(struct sockaddr)); ip_addr = sin.sin_addr.s_addr; char cpaddr[24]; if (NULL == inet_ntop(AF_INET, &ip_addr, (char *)cpaddr, sizeof(cpaddr))) { cf_warning(CF_MISC, "received suspicious address %s : %s", cpaddr, cf_strerror(errno)); return(-1); } cf_info (CF_MISC, "Node ip: %s", cpaddr); *node_ip = cf_strdup(cpaddr); return(0); }
/* cf_fault_sink_add * Register an sink for faults */ cf_fault_sink * cf_fault_sink_add(char *path) { cf_fault_sink *s; if ((CF_FAULT_SINKS_MAX - 1) == cf_fault_sinks_inuse) return(NULL); s = &cf_fault_sinks[cf_fault_sinks_inuse++]; s->path = cf_strdup(path); if (0 == strncmp(path, "stderr", 6)) s->fd = 2; else { if (-1 == (s->fd = open(path, SINK_OPEN_FLAGS, SINK_OPEN_MODE))) { cf_fault_sinks_inuse--; return(NULL); } } for (int i = 0; i < CF_FAULT_CONTEXT_UNDEF; i++) s->limit[i] = CF_INFO; return(s); }
/* cf_fault_sink_add * Register an sink for faults */ cf_fault_sink * cf_fault_sink_add(char *path) { cf_fault_sink *s; if ((CF_FAULT_SINKS_MAX - 1) == cf_fault_sinks_inuse) return(NULL); s = &cf_fault_sinks[cf_fault_sinks_inuse++]; s->path = cf_strdup(path); if (0 == strncmp(path, "stderr", 6)) s->fd = 2; else { if (-1 == (s->fd = open(path, O_WRONLY|O_CREAT|O_APPEND|O_NONBLOCK, S_IRUSR|S_IWUSR))) { cf_fault_sinks_inuse--; return(NULL); } } for (int i = 0; i < CF_FAULT_CONTEXT_UNDEF; i++) s->limit[i] = CF_INFO; return(s); }
int main(int argc, char **argv) { g_start_sec = cf_get_seconds(); // Initialize cf_thread wrapper. cf_thread_init(); // Initialize memory allocation. cf_alloc_init(); // Initialize fault management framework. cf_fault_init(); // Setup signal handlers. as_signal_setup(); // Initialize TLS library. tls_check_init(); int opt; int opt_i; const char *config_file = DEFAULT_CONFIG_FILE; bool run_in_foreground = false; bool new_style_daemon = false; bool cold_start_cmd = false; uint32_t instance = 0; // Parse command line options. while ((opt = getopt_long(argc, argv, "", CMD_OPTS, &opt_i)) != -1) { switch (opt) { case 'h': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s\n", HELP); return 0; case 'v': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s build %s\n", aerospike_build_type, aerospike_build_id); return 0; case 'f': config_file = cf_strdup(optarg); break; case 'F': // As a "new-style" daemon(*), asd runs in the foreground and // ignores the following configuration items: // - user ('user') // - group ('group') // - PID file ('pidfile') // // If ignoring configuration items, or if the 'console' sink is not // specified, warnings will appear in stderr. // // (*) http://0pointer.de/public/systemd-man/daemon.html#New-Style%20Daemons run_in_foreground = true; new_style_daemon = true; break; case 'd': run_in_foreground = true; break; case 'c': cold_start_cmd = true; break; case 'n': instance = (uint32_t)strtol(optarg, NULL, 0); break; default: // fprintf() since we don't want cf_fault's prefix. fprintf(stderr, "%s\n", USAGE); return 1; } } // Set all fields in the global runtime configuration instance. This parses // the configuration file, and creates as_namespace objects. (Return value // is a shortcut pointer to the global runtime configuration instance.) as_config *c = as_config_init(config_file); // Detect NUMA topology and, if requested, prepare for CPU and NUMA pinning. cf_topo_config(c->auto_pin, (cf_topo_numa_node_index)instance, &c->service.bind); // Perform privilege separation as necessary. If configured user & group // don't have root privileges, all resources created or reopened past this // point must be set up so that they are accessible without root privileges. // If not, the process will self-terminate with (hopefully!) a log message // indicating which resource is not set up properly. cf_process_privsep(c->uid, c->gid); // // All resources such as files, devices, and shared memory must be created // or reopened below this line! (The configuration file is the only thing // that must be opened above, in order to parse the user & group.) //========================================================================== // A "new-style" daemon expects console logging to be configured. (If not, // log messages won't be seen via the standard path.) if (new_style_daemon) { if (! cf_fault_console_is_held()) { cf_warning(AS_AS, "in new-style daemon mode, console logging is not configured"); } } // Activate log sinks. Up to this point, 'cf_' log output goes to stderr, // filtered according to NO_SINKS_LIMIT in fault.c. After this point, 'cf_' // log output will appear in all log file sinks specified in configuration, // with specified filtering. If console sink is specified in configuration, // 'cf_' log output will continue going to stderr, but filtering will switch // from NO_SINKS_LIMIT to that specified in console sink configuration. if (0 != cf_fault_sink_activate_all_held()) { // Specifics of failure are logged in cf_fault_sink_activate_all_held(). cf_crash_nostack(AS_AS, "can't open log sink(s)"); } // Daemonize asd if specified. After daemonization, output to stderr will no // longer appear in terminal. Instead, check /tmp/aerospike-console.<pid> // for console output. if (! run_in_foreground && c->run_as_daemon) { // Don't close any open files when daemonizing. At this point only log // sink files are open - instruct cf_process_daemonize() to ignore them. int open_fds[CF_FAULT_SINKS_MAX]; int num_open_fds = cf_fault_sink_get_fd_list(open_fds); cf_process_daemonize(open_fds, num_open_fds); } // Log which build this is - should be the first line in the log file. cf_info(AS_AS, "<><><><><><><><><><> %s build %s <><><><><><><><><><>", aerospike_build_type, aerospike_build_id); // Includes echoing the configuration file to log. as_config_post_process(c, config_file); xdr_config_post_process(); // If we allocated a non-default config file name, free it. if (config_file != DEFAULT_CONFIG_FILE) { cf_free((void*)config_file); } // Write the pid file, if specified. if (! new_style_daemon) { write_pidfile(c->pidfile); } else { if (c->pidfile) { cf_warning(AS_AS, "will not write PID file in new-style daemon mode"); } } // Check that required directories are set up properly. validate_directory(c->work_directory, "work"); validate_directory(c->mod_lua.user_path, "Lua user"); validate_smd_directory(); // Initialize subsystems. At this point we're allocating local resources, // starting worker threads, etc. (But no communication with other server // nodes or clients yet.) as_json_init(); // Jansson JSON API used by System Metadata as_index_tree_gc_init(); // thread to purge dropped index trees as_sindex_thr_init(); // defrag secondary index (ok during population) as_nsup_init(); // load previous evict-void-time(s) // Initialize namespaces. Each namespace decides here whether it will do a // warm or cold start. Index arenas, partition structures and index tree // structures are initialized. Secondary index system metadata is restored. as_namespaces_init(cold_start_cmd, instance); // Initialize the storage system. For warm and cool restarts, this includes // fully resuming persisted indexes - this may take a few minutes. as_storage_init(); // Migrate memory to correct NUMA node (includes resumed index arenas). cf_topo_migrate_memory(); // Drop capabilities that we kept only for initialization. cf_process_drop_startup_caps(); // Activate the storage system. For cold starts and cool restarts, this // includes full drive scans - this may take several hours. The defrag // subsystem starts operating at the end of this call. as_storage_load(); // Populate all secondary indexes. This may block for a long time. as_sindex_boot_populateall(); cf_info(AS_AS, "initializing services..."); cf_dns_init(); // DNS resolver as_netio_init(); // query responses as_security_init(); // security features as_tsvc_init(); // all transaction handling as_hb_init(); // inter-node heartbeat as_skew_monitor_init(); // clock skew monitor as_fabric_init(); // inter-node communications as_exchange_init(); // initialize the cluster exchange subsystem as_clustering_init(); // clustering-v5 start as_info_init(); // info transaction handling as_migrate_init(); // move data between nodes as_proxy_init(); // do work on behalf of others as_rw_init(); // read & write service as_query_init(); // query transaction handling as_udf_init(); // user-defined functions as_scan_init(); // scan a namespace or set as_batch_init(); // batch transaction handling as_xdr_init(); // cross data-center replication as_mon_init(); // monitor // Wait for enough available storage. We've been defragging all along, but // here we wait until it's enough. This may block for a long time. as_storage_wait_for_defrag(); // Start subsystems. At this point we may begin communicating with other // cluster nodes, and ultimately with clients. as_smd_start(); // enables receiving cluster state change events as_health_start(); // starts before fabric and hb to capture them as_fabric_start(); // may send & receive fabric messages as_xdr_start(); // XDR should start before it joins other nodes as_hb_start(); // start inter-node heartbeat as_exchange_start(); // start the cluster exchange subsystem as_clustering_start(); // clustering-v5 start as_nsup_start(); // may send evict-void-time(s) to other nodes as_service_start(); // server will now receive client transactions as_info_port_start(); // server will now receive info transactions as_ticker_start(); // only after everything else is started // Relevant for enterprise edition only. as_storage_start_tomb_raider(); // Log a service-ready message. cf_info(AS_AS, "service ready: soon there will be cake!"); //-------------------------------------------- // Startup is done. This thread will now wait // quietly for a shutdown signal. // // Stop this thread from finishing. Intentionally deadlocking on a mutex is // a remarkably efficient way to do this. pthread_mutex_lock(&g_main_deadlock); g_startup_complete = true; pthread_mutex_lock(&g_main_deadlock); // When the service is running, you are here (deadlocked) - the signals that // stop the service (yes, these signals always occur in this thread) will // unlock the mutex, allowing us to continue. g_shutdown_started = true; pthread_mutex_unlock(&g_main_deadlock); pthread_mutex_destroy(&g_main_deadlock); //-------------------------------------------- // Received a shutdown signal. // as_storage_shutdown(instance); as_xdr_shutdown(); cf_info(AS_AS, "finished clean shutdown - exiting"); // If shutdown was totally clean (all threads joined) we could just return, // but for now we exit to make sure all threads die. #ifdef DOPROFILE exit(0); // exit(0) so profile build actually dumps gmon.out #else _exit(0); #endif return 0; }
as_geojson *as_geojson_new_strdup(const char * s) { return as_geojson_new(cf_strdup(s), true); }
int main(int argc, char **argv) { #ifdef USE_ASM as_mallocation_t asm_array[MAX_NUM_MALLOCATIONS]; // Zero-out the statically-allocated array of memory allocation locations. memset(asm_array, 0, sizeof(asm_array)); // Set the ASMalloc callback user data. g_my_cb_udata = asm_array; // This must come first to allow initialization of the ASMalloc library. asm_init(); #endif // defined(USE_ASM) #ifdef USE_JEM // Initialize the JEMalloc interface. jem_init(true); #endif // Initialize ref-counting system. cf_rc_init(NULL); // Initialize fault management framework. cf_fault_init(); // Setup signal handlers. as_signal_setup(); // Initialize the Jansson JSON API. as_json_init(); int i; int cmd_optidx; const char *config_file = DEFAULT_CONFIG_FILE; bool run_in_foreground = false; bool cold_start_cmd = false; uint32_t instance = 0; // Parse command line options. while (-1 != (i = getopt_long(argc, argv, "", cmd_opts, &cmd_optidx))) { switch (i) { case 'h': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s\n", HELP); return 0; case 'v': // printf() since we want stdout and don't want cf_fault's prefix. printf("%s build %s\n", aerospike_build_type, aerospike_build_id); return 0; case 'f': config_file = cf_strdup(optarg); cf_assert(config_file, AS_AS, CF_CRITICAL, "config filename cf_strdup failed"); break; case 'd': run_in_foreground = true; break; case 'c': cold_start_cmd = true; break; case 'n': instance = (uint32_t)strtol(optarg, NULL, 0); break; default: // fprintf() since we don't want cf_fault's prefix. fprintf(stderr, "%s\n", USAGE); return 1; } } // Set all fields in the global runtime configuration instance. This parses // the configuration file, and creates as_namespace objects. (Return value // is a shortcut pointer to the global runtime configuration instance.) as_config *c = as_config_init(config_file); #ifdef USE_ASM g_asm_hook_enabled = g_asm_cb_enabled = c->asmalloc_enabled; long initial_tid = syscall(SYS_gettid); #endif #ifdef MEM_COUNT // [Note: This should ideally be at the very start of the "main()" function, // but we need to wait until after the config file has been parsed in // order to support run-time configurability.] mem_count_init(c->memory_accounting ? MEM_COUNT_ENABLE : MEM_COUNT_DISABLE); #endif // Perform privilege separation as necessary. If configured user & group // don't have root privileges, all resources created or reopened past this // point must be set up so that they are accessible without root privileges. // If not, the process will self-terminate with (hopefully!) a log message // indicating which resource is not set up properly. if (0 != c->uid && 0 == geteuid()) { // To see this log, change NO_SINKS_LIMIT in fault.c: cf_info(AS_AS, "privsep to %d %d", c->uid, c->gid); cf_process_privsep(c->uid, c->gid); } // // All resources such as files, devices, and shared memory must be created // or reopened below this line! (The configuration file is the only thing // that must be opened above, in order to parse the user & group.) //========================================================================== // Activate log sinks. Up to this point, 'cf_' log output goes to stderr, // filtered according to NO_SINKS_LIMIT in fault.c. After this point, 'cf_' // log output will appear in all log file sinks specified in configuration, // with specified filtering. If console sink is specified in configuration, // 'cf_' log output will continue going to stderr, but filtering will switch // from NO_SINKS_LIMIT to that specified in console sink configuration. if (0 != cf_fault_sink_activate_all_held()) { // Specifics of failure are logged in cf_fault_sink_activate_all_held(). cf_crash_nostack(AS_AS, "can't open log sink(s)"); } // Daemonize asd if specified. After daemonization, output to stderr will no // longer appear in terminal. Instead, check /tmp/aerospike-console.<pid> // for console output. if (! run_in_foreground && c->run_as_daemon) { // Don't close any open files when daemonizing. At this point only log // sink files are open - instruct cf_process_daemonize() to ignore them. int open_fds[CF_FAULT_SINKS_MAX]; int num_open_fds = cf_fault_sink_get_fd_list(open_fds); cf_process_daemonize(open_fds, num_open_fds); } #ifdef USE_ASM // Log the main thread's Linux Task ID (pre- and post-fork) to the console. fprintf(stderr, "Initial main thread tid: %lu\n", initial_tid); if (! run_in_foreground && c->run_as_daemon) { fprintf(stderr, "Post-daemonize main thread tid: %lu\n", syscall(SYS_gettid)); } #endif // Log which build this is - should be the first line in the log file. cf_info(AS_AS, "<><><><><><><><><><> %s build %s <><><><><><><><><><>", aerospike_build_type, aerospike_build_id); // Includes echoing the configuration file to log. as_config_post_process(c, config_file); // If we allocated a non-default config file name, free it. if (config_file != DEFAULT_CONFIG_FILE) { cf_free((void*)config_file); } // Write the pid file, if specified. write_pidfile(c->pidfile); // Check that required directories are set up properly. validate_directory(c->work_directory, "work"); validate_directory(c->mod_lua.system_path, "Lua system"); validate_directory(c->mod_lua.user_path, "Lua user"); validate_smd_directory(); // Initialize subsystems. At this point we're allocating local resources, // starting worker threads, etc. (But no communication with other server // nodes or clients yet.) as_smd_init(); // System Metadata first - others depend on it ai_init(); // before as_storage_init() populates indexes as_sindex_thr_init(); // defrag secondary index (ok during population) // Initialize namespaces. Each namespace decides here whether it will do a // warm or cold start. Index arenas, partition structures and index tree // structures are initialized. Secondary index system metadata is restored. as_namespaces_init(cold_start_cmd, instance); // Initialize the storage system. For cold starts, this includes reading // all the objects off the drives. This may block for a long time. The // defrag subsystem starts operating at the end of this call. as_storage_init(); // Populate all secondary indexes. This may block for a long time. as_sindex_boot_populateall(); cf_info(AS_AS, "initializing services..."); as_netio_init(); as_security_init(); // security features as_tsvc_init(); // all transaction handling as_hb_init(); // inter-node heartbeat as_fabric_init(); // inter-node communications as_info_init(); // info transaction handling as_paxos_init(); // cluster consensus algorithm as_migrate_init(); // move data between nodes as_proxy_init(); // do work on behalf of others as_write_init(); // write service as_query_init(); // query transaction handling as_udf_init(); // apply user-defined functions as_scan_init(); // scan a namespace or set as_batch_init(); // batch transaction handling as_batch_direct_init(); // low priority transaction handling as_xdr_init(); // cross data-center replication as_mon_init(); // monitor // Wait for enough available storage. We've been defragging all along, but // here we wait until it's enough. This may block for a long time. as_storage_wait_for_defrag(); // Start subsystems. At this point we may begin communicating with other // cluster nodes, and ultimately with clients. as_smd_start(c->smd); // enables receiving paxos state change events as_fabric_start(); // may send & receive fabric messages as_hb_start(); // start inter-node heatbeat as_paxos_start(); // blocks until cluster membership is obtained as_nsup_start(); // may send delete transactions to other nodes as_demarshal_start(); // server will now receive client transactions as_info_port_start(); // server will now receive info transactions info_debug_ticker_start(); // only after everything else is started // Log a service-ready message. cf_info(AS_AS, "service ready: soon there will be cake!"); //-------------------------------------------- // Startup is done. This thread will now wait // quietly for a shutdown signal. // // Stop this thread from finishing. Intentionally deadlocking on a mutex is // a remarkably efficient way to do this. pthread_mutex_init(&g_NONSTOP, NULL); pthread_mutex_lock(&g_NONSTOP); g_startup_complete = true; pthread_mutex_lock(&g_NONSTOP); // When the service is running, you are here (deadlocked) - the signals that // stop the service (yes, these signals always occur in this thread) will // unlock the mutex, allowing us to continue. g_shutdown_started = true; pthread_mutex_unlock(&g_NONSTOP); pthread_mutex_destroy(&g_NONSTOP); //-------------------------------------------- // Received a shutdown signal. // as_storage_shutdown(); as_xdr_shutdown(); as_smd_shutdown(c->smd); cf_info(AS_AS, "finished clean shutdown - exiting"); // If shutdown was totally clean (all threads joined) we could just return, // but for now we exit to make sure all threads die. #ifdef DOPROFILE exit(0); // exit(0) so profile build actually dumps gmon.out #else _exit(0); #endif return 0; }
static void* cert_blacklist_read(const char * path) { FILE* fp = fopen(path, "r"); if (fp == NULL) { as_log_warn("Failed to open cert blacklist '%s': %s", path, strerror(errno)); return NULL; } size_t capacity = 32; size_t sz = sizeof(cert_blacklist) + (capacity * sizeof(cert_spec)); cert_blacklist* cbp = cf_malloc(sz); cbp->ncerts = 0; char buffer[1024]; while (true) { char* line = fgets(buffer, sizeof(buffer), fp); if (! line) { break; } // Lines begining with a '#' are comments. if (line[0] == '#') { continue; } char* saveptr = NULL; char* hex_serial = strtok_r(line, " \t\r\n", &saveptr); if (! hex_serial) { continue; } // Skip all additional whitespace. while (isspace(*saveptr)) { ++saveptr; } // Everything to the end of the line is issuer name. Note we // do not consider whitespace a separator anymore. char* issuer_name = strtok_r(NULL, "\r\n", &saveptr); // Do we need more room? if (cbp->ncerts == capacity) { capacity *= 2; size_t sz = sizeof(cert_blacklist) + (capacity * sizeof(cert_spec)); cbp = cf_realloc(cbp, sz); } cbp->certs[cbp->ncerts].hex_serial = cf_strdup(hex_serial); cbp->certs[cbp->ncerts].issuer_name = issuer_name ? cf_strdup(issuer_name) : NULL; cbp->ncerts++; } qsort(cbp->certs, cbp->ncerts, sizeof(cert_spec), cert_spec_compare); fclose(fp); return cbp; }
int cf_nodeid_get( unsigned short port, cf_node *id, char **node_ipp, hb_mode_enum hb_mode, char **hb_addrp, char **config_interface_names) { int fdesc; struct ifreq req; // The default interface names can be overridden by the interface name passed into config char **interface_names = default_interface_names; bool default_config = true; int jlimit = 11; if (config_interface_names) { interface_names = config_interface_names; default_config = false; jlimit = 1; } if (0 >= (fdesc = socket(AF_INET, SOCK_STREAM, 0))) { cf_warning(CF_MISC, "can't open socket: %d %s", errno, cf_strerror(errno)); return(-1); } int i = 0; bool done = false; while ((interface_names[i]) && (!done)) { int j=0; while ((!done) && (j < jlimit)) { if (default_config) sprintf(req.ifr_name, interface_names[i],j); else sprintf(req.ifr_name, interface_names[i]); if (0 == ioctl(fdesc, SIOCGIFHWADDR, &req)) { if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; break; } } cf_debug(CF_MISC, "can't get physical address of interface %s: %d %s", req.ifr_name, errno, cf_strerror(errno)); j++; } i++; } if (!done) { if (default_config) { struct ifaddrs* interface_addrs = NULL; if (getifaddrs(&interface_addrs) == -1) { cf_warning(CF_MISC, "getifaddrs failed %d %s", errno, cf_strerror(errno)); return -1; } if (!interface_addrs) { cf_warning(CF_MISC, "getifaddrs returned NULL"); return -1; } struct ifaddrs *ifa; for (ifa = interface_addrs; ifa != NULL && (!done); ifa = ifa->ifa_next) { if (ifa->ifa_data != 0) { struct ifreq req; strcpy(req.ifr_name, ifa->ifa_name); /* Get MAC address */ if (ioctl(fdesc, SIOCGIFHWADDR, &req) == 0) { uint8_t* mac = (uint8_t*)req.ifr_ifru.ifru_hwaddr.sa_data; /* MAC address sanity check */ if ((mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0) || (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff && mac[3] == 0xff && mac[4] == 0xff && mac[5] == 0xff )) { continue; } /* Get IP address */ if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; continue; } } else { /* Continue to the next interface if cannot get MAC address */ continue; } } } } else { cf_warning(CF_MISC, "can't get physical address of interface name specfied in config file, tried %s. fatal: %d %s", interface_names[0], errno, cf_strerror(errno)); close(fdesc); return(-1); } } if (!done) { cf_warning(CF_MISC, "Tried eth,bond,wlan and list of all available interfaces on device.Failed to retrieve physical address with errno %d %s\n", errno, cf_strerror(errno)); close(fdesc); return(-1); } close(fdesc); /* * Set the hb_addr to be the same as the ip address if the mode is mesh and the hb_addr parameter is empty * Configuration file overrides the automatic node ip detection * - this gives us a work around in case the node ip is somehow detected wrong in production */ if (hb_mode == AS_HB_MODE_MESH) { if (*hb_addrp == NULL) *hb_addrp = cf_strdup(*node_ipp); cf_info(CF_MISC, "Heartbeat address for mesh: %s", *hb_addrp); } *id = 0; memcpy(id, req.ifr_hwaddr.sa_data, 6); memcpy(((byte *)id) + 6, &port, 2); cf_debug(CF_MISC, "port %d id %"PRIx64, port, *id); return(0); }
char * as_cmp_wildcard_val_tostring(const as_val *v) { return cf_strdup("*"); }
char * as_cmp_inf_val_tostring(const as_val *v) { return cf_strdup("INF"); }
as_string *as_string_new_strdup(const char * s) { return as_string_new(cf_strdup(s), true); }
/* * Gets a unique id for this process instance * Uses the mac address right now * And combine with the unique port number, which is why it needs to be passed in * Needs to be a little more subtle: * Should stash the mac address or something, in case you have to replace a card. * * parameters- * Input params: * port - used in setting Node ID * hb_mode - Controls whether hb_addrp is filled out with the IP address. * config_interface_names - Pointer to an array of interface names if specified in the config file, * NULL if absent. * * Output params: * id - Node ID (address and port) * node_ipp - Pointer wherein the IP address is stored * hb_addrp - Pointer to a string wherein the heartbeat address is stored, as specified by hb_mode */ int cf_nodeid_get(unsigned short port, cf_node *id, char **node_ipp, hb_mode_enum hb_mode, char **hb_addrp, const char **config_interface_names) { // The default interface names can be overridden by the interface name passed into config const char **interface_names = default_interface_names; bool default_config = true; int jlimit = 11; if (config_interface_names) { interface_names = config_interface_names; default_config = false; jlimit = 1; } int fdesc = socket(AF_INET, SOCK_STREAM, 0); if (fdesc <= 0) { cf_warning(CF_MISC, "can't open socket: %d %s", errno, cf_strerror(errno)); return(-1); } struct ifreq req; bool done = false; for (int i = 0; interface_names[i]; i++) { for (int j = 0; j < jlimit; j++) { if (default_config) { sprintf(req.ifr_name, interface_names[i], j); } else { sprintf(req.ifr_name, "%s", interface_names[i]); } if (0 == ioctl(fdesc, SIOCGIFHWADDR, &req)) { if (cf_ipaddr_get(fdesc, req.ifr_name, node_ipp) == 0) { done = true; break; } } cf_debug(CF_MISC, "can't get physical address of interface %s: %d %s", req.ifr_name, errno, cf_strerror(errno)); } if (done) { break; } } if (! done) { if (default_config) { struct ifaddrs *interface_addrs = NULL; if (getifaddrs(&interface_addrs) == -1) { cf_warning(CF_MISC, "getifaddrs failed %d %s", errno, cf_strerror(errno)); return -1; } if (! interface_addrs) { cf_warning(CF_MISC, "getifaddrs returned NULL"); return -1; } struct ifaddrs *ifa; for (ifa = interface_addrs; ifa != NULL; ifa = ifa->ifa_next) { if (! ifa->ifa_data) { continue; } if (! is_biosdevname(ifa->ifa_name)) { continue; } if (check_mac_and_get_ipaddr(fdesc, ifa->ifa_name, &req, node_ipp)) { done = true; break; } } for (ifa = interface_addrs; ifa != NULL && (! done); ifa = ifa->ifa_next) { if (! ifa->ifa_data) { continue; } if (check_mac_and_get_ipaddr(fdesc, ifa->ifa_name, &req, node_ipp)) { done = true; break; } } freeifaddrs(interface_addrs); } else { cf_warning(CF_MISC, "can't get physical address of interface name specified in config file, tried %s. fatal: %d %s", interface_names[0], errno, cf_strerror(errno)); close(fdesc); return(-1); } } close(fdesc); if (! done) { cf_warning(CF_MISC, "Tried eth,bond,wlan,em and list of all available interfaces on device. Failed to retrieve physical address with errno %d %s\n", errno, cf_strerror(errno)); return(-1); } /* * Set the hb_addr to be the same as the ip address if the mode is mesh and the hb_addr parameter is empty * Configuration file overrides the automatic node ip detection * - this gives us a work around in case the node ip is somehow detected wrong in production */ if (hb_mode == AS_HB_MODE_MESH) { if (*hb_addrp == NULL) { *hb_addrp = cf_strdup(*node_ipp); } cf_info(CF_MISC, "Heartbeat address for mesh: %s", *hb_addrp); } *id = 0; memcpy(id, req.ifr_hwaddr.sa_data, 6); memcpy(((byte *)id) + 6, &port, 2); cf_debug(CF_MISC, "port %d id %"PRIx64, port, *id); return(0); }