/***************************************************************************** 函数名称 : add_pcp_rule 功能描述 : 对参数进行封装,并发送到pcp client 输入参数 : 见函数声明 lifetime目前没有意义,赋0即可。在没有收到delete mapping之前,pcp client 一直refresh,将lifetime当作无限长处理。lifetime只在miniupnpd中维护,超期后 删除,删除的时候确保通知给pcp client即可。 输出参数 : No 返 回 值 : No *****************************************************************************/ void add_pcp_rule(unsigned short eport, int proto, unsigned int lifetime, int enabled, const char *local_ip, unsigned short iport) { PARA_TO_PCP_PROC_ST pcp_para; char wan_ip[IPV4_ADDRESS_LEN] = {0}; NP_UPNP_DEBUG("add_pcp_rule entered: eport:%d, proto:%d, iport:%d", eport, proto, iport); if (NULL == local_ip) { NP_UPNP_ERROR("local ip is NULL, be carefully.\n"); } memset(&pcp_para, 0, sizeof(pcp_para)); // wanip作为inip,eport作为iport if ((getifaddr(ext_if_name, wan_ip, sizeof(wan_ip)) < 0) || (0 == strlen(wan_ip))) { NP_UPNP_ERROR("Failed to get wan ip.\n"); } else { //eport作为iport fill_pcp_process_para(&pcp_para, iport, wan_ip, eport, proto, lifetime, enabled, local_ip); send_msg_to_pcp_client(ATP_MSG_PCP_ADD_PORTMAP, &pcp_para); } }
static bool parse_listen_faces(char str[], ccarray_t * faces) { static const char delims[] = " \t\n,;"; char * tok; tok = strtok(str, delims); while ( tok && ccarray_size(faces) < ccarray_capacity(faces) ) { uint32_t address = 0; uint16_t port = 0; if ( getifaddr(tok, &address, &port) == -1 ) { fprintf(stderr, "FATAL: Can't get address for '%s': %s\n", tok, strerror(errno)); fprintf(stderr, "Check if device name is valid and device is up\n"); return false; } if ( !port ) { fprintf(stderr, "No port specified in '%s'\n", tok); return false; } ccarray_push_back(faces, &(struct sockaddr_in ) { .sin_family = AF_INET, .sin_addr.s_addr = htonl(address), .sin_port = htons(port), .sin_zero = { 0 } }); tok = strtok(NULL, delims); }
int ip6up_main(int argc, char **argv) { char *wan_ifname = safe_getenv("IFNAME"); char *llremote = safe_getenv("LLREMOTE"); if (!wan_ifname || strlen(wan_ifname) <= 0) return 0; nvram_set("ipv6_ll_remote", llremote); switch (get_ipv6_service()) { case IPV6_NATIVE: case IPV6_NATIVE_DHCP: wait_ppp_count = 10; while ((!is_intf_up(wan_ifname) || !getifaddr(wan_ifname, AF_INET6, 0)) && (wait_ppp_count-- > 0)) sleep(1); break; default: wait_ppp_count = 0; break; } if (wait_ppp_count != -2) { wan6_up(wan_ifname); start_firewall(0, 0); } return 0; }
static void FillPublicAddressResponse(unsigned char * resp, in_addr_t senderaddr) { #ifndef MULTIPLE_EXTERNAL_IP char tmp[16]; UNUSED(senderaddr); if(use_ext_ip_addr) { inet_pton(AF_INET, use_ext_ip_addr, resp+8); } else { if(!ext_if_name || ext_if_name[0]=='\0') { resp[3] = 3; /* Network Failure (e.g. NAT box itself * has not obtained a DHCP lease) */ } else if(getifaddr(ext_if_name, tmp, INET_ADDRSTRLEN) < 0) { syslog(LOG_ERR, "Failed to get IP for interface %s", ext_if_name); resp[3] = 3; /* Network Failure (e.g. NAT box itself * has not obtained a DHCP lease) */ } else { inet_pton(AF_INET, tmp, resp+8); /* ok */ } } #else struct lan_addr_s * lan_addr; for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if( (senderaddr & lan_addr->mask.s_addr) == (lan_addr->addr.s_addr & lan_addr->mask.s_addr)) { memcpy(resp+8, &lan_addr->ext_ip_addr, sizeof(lan_addr->ext_ip_addr)); break; } } #endif }
/* Set address by interface name, ip address or hostname */ int generic_addr(struct sockaddr_in *addr, struct vtun_addr *vaddr) { struct hostent *hent; memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; switch (vaddr->type) { case VTUN_ADDR_IFACE: if (!(addr->sin_addr.s_addr = getifaddr(vaddr->name))) { vtun_syslog(LOG_ERR, "Can't get address of interface %s", vaddr->name); return -1; } break; case VTUN_ADDR_NAME: if (!(hent = gethostbyname(vaddr->name))) { vtun_syslog(LOG_ERR, "Can't resolv local address %s", vaddr->name); return -1; } addr->sin_addr.s_addr = *(unsigned long *) hent->h_addr; break; default: addr->sin_addr.s_addr = INADDR_ANY; break; } if (vaddr->port) addr->sin_port = htons(vaddr->port); return 0; }
static bool set_ipv4_multicast_leave( int socket, struct in_addr maddr, char *ifname ) { assert( ifname != NULL ); if ( !IN_MULTICAST( ntohl( maddr.s_addr ) ) ) { return false; } unsigned int n_users = 0; delete_user_from_multicast_group( maddr, &n_users ); if ( n_users > 0 ) { // Still used. return true; } struct ip_mreq mreq; memset( &mreq, 0, sizeof( mreq ) ); mreq.imr_multiaddr = maddr; if ( !getifaddr( ifname, &mreq.imr_interface ) ) { return false; } int ret = setsockopt( socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, ( char * ) &mreq, sizeof( mreq ) ); if ( ret < 0 ) { char buf[ 256 ]; char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) ); error( "Failed to send a leave group ( socket = %d, ret = %d, errno = %s [%d] ).", socket, ret, error_string, errno ); return false; } return true; }
VALUE netif_get_addr(VALUE self) { VALUE ifname = rb_iv_get(self, "@ifname"); char buf[128]; getifaddr(StringValuePtr(ifname), buf, sizeof(buf)); return rb_str_new2(buf); }
/** * get the connection status * return values : * 0 - Unconfigured * 1 - Connecting * 2 - Connected * 3 - PendingDisconnect * 4 - Disconnecting * 5 - Disconnected */ int get_wan_connection_status(const char * ifname) { char addr[INET_ADDRSTRLEN]; int r; /* we need a better implementation here. * I'm afraid it should be device specific */ r = getifaddr(ifname, addr, INET_ADDRSTRLEN); return (r < 0) ? STATUS_DISCONNECTED : STATUS_CONNECTED; }
int get_local_address(const std::string ð_name, std::string &local_address) { // get local address uint32_t ip; if (getifaddr(AF_INET, 0, eth_name.c_str(), &ip) != 0){ return -1; } char ip_str[INET_ADDRSTRLEN]; if(inet_ntop(AF_INET, &ip, ip_str, sizeof (ip_str)) == NULL){ return -1; } local_address = ip_str; return 0; }
int main(int argc, char * * argv) { char addr[64]; if(argc < 2) { fprintf(stderr, "Usage:\t%s interface_name\n", argv[0]); return 1; } openlog("testgetifaddr", LOG_CONS|LOG_PERROR, LOG_USER); if(getifaddr(argv[1], addr, sizeof(addr)) < 0) { fprintf(stderr, "Cannot get address for interface %s.\n", argv[1]); return 1; } printf("Interface %s has IP address %s.\n", argv[1], addr); return 0; }
bool update_interface_state() { assert( vxlan != NULL ); struct in_addr addr; if ( getifaddr( vxlan->ifname, &addr ) ) { vxlan->active = true; } else { vxlan->active = false; } return true; }
static bool set_ipv4_multicast_join_and_iface( int socket, struct in_addr maddr, char *ifname ) { assert( ifname != NULL ); if ( !IN_MULTICAST( ntohl( maddr.s_addr ) ) ) { return false; } unsigned int n_users = 0; add_user_into_multicast_group( maddr, &n_users ); if ( n_users > 1 ) { // Already joined. return true; } else if ( n_users != 1 ) { return false; } struct ip_mreq mreq; memset( &mreq, 0, sizeof( mreq ) ); mreq.imr_multiaddr = maddr; if ( !getifaddr( ifname, &mreq.imr_interface ) ) { return false; } char buf[ 256 ]; int ret = setsockopt( socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, ( char * ) &mreq, sizeof( mreq ) ); if ( ret < 0 ) { char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) ); error( "Failed to send a membership report ( socket = %d, ret = %d, errno = %s [%d] ).", socket, ret, error_string, errno ); return false; } ret = setsockopt( socket, IPPROTO_IP, IP_MULTICAST_IF, ( char * ) &mreq.imr_interface, sizeof( mreq.imr_interface ) ); if ( ret < 0 ) { char *error_string = safe_strerror_r( errno, buf, sizeof( buf ) ); error( "Failed to set a network interface ( socket = %d, ret = %d, errno = %s [%d] ).", socket, ret, error_string, errno ); return false; } return true; }
static void check_and_set_comm_if(void) { #ifndef RTCONFIG_RALINK const char *ipaddr; char buf_ip[32]; ipaddr = getifaddr("vlan2", AF_INET, GIF_PREFIXLEN); //_dprintf("%s: %s\n", __func__, ipaddr); if(!ipaddr || (ipaddr && strncmp("169.254", ipaddr, 7))) { pick_a_random_ipv4(buf_ip); ifconfig("vlan2", IFUP, buf_ip, "255.255.0.0"); } if(!check_if_route_exist("vlan2", "169.254.0.1", "255.255.255.255")) route_add("vlan2", 0, "169.254.0.1", "0.0.0.0", "255.255.255.255"); #endif }
int main(void) { char *status; /*char *avgs;*/ char *tmcentral; char *cpu; char *battery; char *ifaddr; char *temp; int i = 0; if (!(dpy = XOpenDisplay(NULL))) { fprintf(stderr, "dwmstatus: cannot open display.\n"); return 1; } /* Clear old_stats for cpu usage*/ for(i = 0; i < 10; ++i) old_stats[i] = 0; for (;;sleep(1)) { /*avgs = loadavg();*/ cpu = cpu_usage(); tmcentral = mktimes("%Y-%m-%d %H:%M:%S", tzcentral); battery = getbattery(); ifaddr = getifaddr(); temp = gettemp(); status = smprintf("%s | %s BAT %s | CPU %s | %s", temp, ifaddr, battery, cpu, tmcentral); setstatus(status); /*free(avgs);*/ free(tmcentral); free(status); free(ifaddr); } XCloseDisplay(dpy); return 0; }
/* init phase : * 1) read configuration file * 2) read command line arguments * 3) daemonize * 4) check and write pid file * 5) set startup time stamp * 6) compute presentation URL * 7) set signal handlers */ static int init(int argc, char * * argv) { int i; int pid; int debug_flag = 0; int verbose_flag = 0; int options_flag = 0; struct sigaction sa; const char * presurl = NULL; const char * optionsfile = "/etc/minidlna.conf"; char mac_str[13]; char * string, * word; enum media_types type; char * path; char buf[PATH_MAX]; char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; char log_str[72] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"; char *log_level = NULL; /* first check if "-f" option is used */ for(i=2; i<argc; i++) { if(0 == strcmp(argv[i-1], "-f")) { optionsfile = argv[i]; options_flag = 1; break; } } /* set up uuid based on mac address */ if( getsyshwaddr(mac_str, sizeof(mac_str)) < 0 ) { DPRINTF(E_OFF, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n"); strcpy(mac_str, "554e4b4e4f57"); } strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-"); strncat(uuidvalue, mac_str, 12); getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN); runtime_vars.port = -1; runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ runtime_vars.root_container = NULL; /* read options file first since * command line arguments have final say */ if(readoptionsfile(optionsfile) < 0) { /* only error if file exists or using -f */ if(access(optionsfile, F_OK) == 0 || options_flag) DPRINTF(E_ERROR, L_GENERAL, "Error reading configuration file %s\n", optionsfile); } else { for(i=0; i<num_options; i++) { switch(ary_options[i].id) { case UPNPIFNAME: for( string = ary_options[i].value; (word = strtok(string, ",")); string = NULL ) { if(n_lan_addr < MAX_LAN_ADDR) { if(getifaddr(word, ip_addr, sizeof(ip_addr)) >= 0) { if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) if(n_lan_addr < MAX_LAN_ADDR) n_lan_addr++; } } else { DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, word); } } break; case UPNPLISTENING_IP: if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ary_options[i].value) == 0) n_lan_addr++; } else { DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, ary_options[i].value); } break; case UPNPPORT: runtime_vars.port = atoi(ary_options[i].value); break; case UPNPPRESENTATIONURL: presurl = ary_options[i].value; break; case UPNPNOTIFY_INTERVAL: runtime_vars.notify_interval = atoi(ary_options[i].value); break; case UPNPSERIAL: strncpyt(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); break; case UPNPMODEL_NAME: strncpyt(modelname, ary_options[i].value, MODELNAME_MAX_LEN); break; case UPNPMODEL_NUMBER: strncpyt(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); break; case UPNPFRIENDLYNAME: strncpyt(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN); break; case UPNPMEDIADIR: type = ALL_MEDIA; char * myval = NULL; switch( ary_options[i].value[0] ) { case 'A': case 'a': if( ary_options[i].value[0] == 'A' || ary_options[i].value[0] == 'a' ) type = AUDIO_ONLY; case 'V': case 'v': if( ary_options[i].value[0] == 'V' || ary_options[i].value[0] == 'v' ) type = VIDEO_ONLY; case 'P': case 'p': if( ary_options[i].value[0] == 'P' || ary_options[i].value[0] == 'p' ) type = IMAGES_ONLY; myval = index(ary_options[i].value, '/'); case '/': path = realpath(myval ? myval:ary_options[i].value, buf); if( !path ) path = (myval ? myval:ary_options[i].value); if( access(path, F_OK) != 0 ) { DPRINTF(E_ERROR, L_GENERAL, "Media directory \"%s\" not accessible! [%s]\n", path, strerror(errno)); break; } struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s)); this_dir->path = strdup(path); this_dir->type = type; if( !media_dirs ) { media_dirs = this_dir; } else { struct media_dir_s * all_dirs = media_dirs; while( all_dirs->next ) all_dirs = all_dirs->next; all_dirs->next = this_dir; } break; default: DPRINTF(E_ERROR, L_GENERAL, "Media directory entry not understood! [%s]\n", ary_options[i].value); break; } break; case UPNPALBUMART_NAMES: for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) { struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s)); int len = strlen(word); if( word[len-1] == '*' ) { word[len-1] = '\0'; this_name->wildcard = 1; } this_name->name = strdup(word); if( !album_art_names ) { album_art_names = this_name; } else { struct album_art_name_s * all_names = album_art_names; while( all_names->next ) all_names = all_names->next; all_names->next = this_name; } } break; case UPNPDBDIR: path = realpath(ary_options[i].value, buf); if( !path ) path = (ary_options[i].value); make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); if( access(path, F_OK) != 0 ) { DPRINTF(E_FATAL, L_GENERAL, "Database path not accessible! [%s]\n", path); break; } strncpyt(db_path, path, PATH_MAX); break; case UPNPLOGDIR: path = realpath(ary_options[i].value, buf); if( !path ) path = (ary_options[i].value); make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); if( access(path, F_OK) != 0 ) { DPRINTF(E_FATAL, L_GENERAL, "Log path not accessible! [%s]\n", path); break; } strncpyt(log_path, path, PATH_MAX); break; case UPNPLOGLEVEL: log_level = ary_options[i].value; break; case UPNPINOTIFY: if( (strcmp(ary_options[i].value, "yes") != 0) && !atoi(ary_options[i].value) ) CLEARFLAG(INOTIFY_MASK); break; case ENABLE_TIVO: if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) SETFLAG(TIVO_MASK); break; case ENABLE_DLNA_STRICT: if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) SETFLAG(DLNA_STRICT_MASK); break; case ROOT_CONTAINER: switch( ary_options[i].value[0] ) { case '.': runtime_vars.root_container = NULL; break; case 'B': case 'b': runtime_vars.root_container = BROWSEDIR_ID; break; case 'M': case 'm': runtime_vars.root_container = MUSIC_ID; break; case 'V': case 'v': runtime_vars.root_container = VIDEO_ID; break; case 'P': case 'p': runtime_vars.root_container = IMAGE_ID; break; default: DPRINTF(E_ERROR, L_GENERAL, "Invalid root container! [%s]\n", ary_options[i].value); break; } break; case UPNPMINISSDPDSOCKET: minissdpdsocketpath = ary_options[i].value; break; default: DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n", optionsfile); } } } if( log_path[0] == '\0' ) { if( db_path[0] == '\0' ) strncpyt(log_path, DEFAULT_LOG_PATH, PATH_MAX); else strncpyt(log_path, db_path, PATH_MAX); } if( db_path[0] == '\0' ) strncpyt(db_path, DEFAULT_DB_PATH, PATH_MAX); /* command line arguments processing */ for(i=1; i<argc; i++) { if(argv[i][0]!='-') { DPRINTF(E_ERROR, L_GENERAL, "Unknown option: %s\n", argv[i]); } else if(strcmp(argv[i], "--help")==0) { runtime_vars.port = 0; break; } else switch(argv[i][1]) { case 't': if(i+1 < argc) runtime_vars.notify_interval = atoi(argv[++i]); else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 's': if(i+1 < argc) strncpyt(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'm': if(i+1 < argc) strncpyt(modelnumber, argv[++i], MODELNUMBER_MAX_LEN); else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'p': if(i+1 < argc) runtime_vars.port = atoi(argv[++i]); else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'P': if(i+1 < argc) pidfilename = argv[++i]; else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'd': debug_flag = 1; case 'v': verbose_flag = 1; break; case 'L': SETFLAG(NO_PLAYLIST_MASK); break; case 'w': if(i+1 < argc) presurl = argv[++i]; else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'a': if(i+1 < argc) { int address_already_there = 0; int j; i++; for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, argv[i]); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) n_lan_addr++; } else { DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'i': if(i+1 < argc) { int address_already_there = 0; int j; i++; if( getifaddr(argv[i], ip_addr, sizeof(ip_addr)) < 0 ) { DPRINTF(E_FATAL, L_GENERAL, "Required network interface '%s' not found.\n", argv[i]); } for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, ip_addr); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0) n_lan_addr++; } else { DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else DPRINTF(E_ERROR, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); break; case 'f': i++; /* discarding, the config file is already read */ break; case 'h': runtime_vars.port = 0; // triggers help display break; case 'R': snprintf(buf, sizeof(buf), "rm -rf %s/files.db %s/art_cache", db_path, db_path); if( system(buf) != 0 ) DPRINTF(E_WARN, L_GENERAL, "Failed to clean old file cache.\n"); break; case 'V': printf("Version " MINIDLNA_VERSION "\n"); exit(0); break; default: DPRINTF(E_ERROR, L_GENERAL, "Unknown option: %s\n", argv[i]); } } /* If no IP was specified, try to detect one */ if( n_lan_addr < 1 ) { if( (getsysaddr(ip_addr, sizeof(ip_addr)) < 0) && (getifaddr("eth0", ip_addr, sizeof(ip_addr)) < 0) && (getifaddr("eth1", ip_addr, sizeof(ip_addr)) < 0) ) { DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); } if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) { n_lan_addr++; } } if( (n_lan_addr==0) || (runtime_vars.port<=0) ) { DPRINTF(E_ERROR, L_GENERAL, "Usage:\n\t" "%s [-d] [-v] [-f config_file]\n" "\t\t[-a listening_ip] [-p port]\n" /*"[-l logfile] " not functionnal */ "\t\t[-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n" "\t\t[-w url] [-R] [-V] [-h]\n" "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" "\tDefault pid file is %s.\n" "\tWith -d minidlna will run in debug mode (not daemonize).\n" "\t-w sets the presentation url. Default is http address on port 80\n" "\t-h displays this text\n" "\t-R forces a full rescan\n" "\t-L do note create playlists\n" "\t-V print the version number\n", argv[0], pidfilename); return 1; } if( verbose_flag ) { strcpy(log_str+65, "debug"); log_level = log_str; } else if( !log_level ) { log_level = log_str; } if(debug_flag) { pid = getpid(); log_init(NULL, log_level); } else { pid = daemonize(); #ifdef READYNAS log_init("/var/log/upnp-av.log", log_level); #else if( access(db_path, F_OK) != 0 ) make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); sprintf(buf, "%s/minidlna.log", log_path); log_init(buf, log_level); #endif } if(checkforrunning(pidfilename) < 0) { DPRINTF(E_ERROR, L_GENERAL, "MiniDLNA is already running. EXITING.\n"); return 1; } set_startup_time(); /* presentation url */ if(presurl) strncpyt(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); else strcpy(presentationurl, "/"); /* set signal handler */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; if (sigaction(SIGTERM, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n"); } if (sigaction(SIGINT, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n"); } if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n"); } writepidfile(pidfilename, pid); return 0; }
int getifaddr_in6(const char * ifname, int af, struct in6_addr * addr) { #if defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) struct ifaddrs * ifap; struct ifaddrs * ife; #ifdef ENABLE_IPV6 const struct sockaddr_in6 * tmpaddr; #endif /* ENABLE_IPV6 */ int found = 0; if(!ifname || ifname[0]=='\0') return -1; if(getifaddrs(&ifap)<0) { syslog(LOG_ERR, "getifaddrs: %m"); return -1; } for(ife = ifap; ife && !found; ife = ife->ifa_next) { /* skip other interfaces if one was specified */ if(ifname && (0 != strcmp(ifname, ife->ifa_name))) continue; if(ife->ifa_addr == NULL) continue; if (ife->ifa_addr->sa_family != af) continue; switch(ife->ifa_addr->sa_family) { case AF_INET: /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ memset(addr->s6_addr, 0, 10); addr->s6_addr[10] = 0xff; addr->s6_addr[11] = 0xff; memcpy(addr->s6_addr + 12, &(((struct sockaddr_in *)ife->ifa_addr)->sin_addr.s_addr), 4); found = 1; break; #ifdef ENABLE_IPV6 case AF_INET6: tmpaddr = (const struct sockaddr_in6 *)ife->ifa_addr; if(!IN6_IS_ADDR_LOOPBACK(&tmpaddr->sin6_addr) && !IN6_IS_ADDR_LINKLOCAL(&tmpaddr->sin6_addr)) { memcpy(addr->s6_addr, &tmpaddr->sin6_addr, 16); found = 1; } break; #endif /* ENABLE_IPV6 */ } } freeifaddrs(ifap); return (found ? 0 : -1); #else /* defined(ENABLE_IPV6) || defined(USE_GETIFADDRS) */ /* IPv4 only */ struct in_addr addr4; if(af != AF_INET) return -1; if(getifaddr(ifname, NULL, 0, &addr4, NULL) < 0) return -1; /* IPv4-mapped IPv6 address ::ffff:1.2.3.4 */ memset(addr->s6_addr, 0, 10); addr->s6_addr[10] = 0xff; addr->s6_addr[11] = 0xff; memcpy(addr->s6_addr + 12, &addr4.s_addr, 4); return 0; #endif }
/* init phase : * 1) read configuration file * 2) read command line arguments * 3) daemonize * 4) check and write pid file * 5) set startup time stamp * 6) set signal handlers */ static int init(int argc, char * * argv) { int i; int pid; int debug_flag = 0; int options_flag = 0; struct sigaction sa; /*const char * logfilename = 0;*/ const char * presurl = 0; const char * optionsfile = "/etc/dlnaproxy.conf"; char mac_str[13]; char * string, * word; char * path; char real_path[PATH_MAX]; char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; /* first check if "-f" option is used */ for(i=2; i<argc; i++) { if(0 == strcmp(argv[i-1], "-f")) { optionsfile = argv[i]; options_flag = 1; break; } } /* set up uuid based on mac address */ if( getsyshwaddr(mac_str, sizeof(mac_str)) < 0 ) { DPRINTF(E_OFF, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n"); strcpy(mac_str, "554e4b4e4f57"); } strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-"); strncat(uuidvalue, mac_str, 12); getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN); runtime_vars.port = -1; runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ runtime_vars.rport = 50001; runtime_vars.rhost = "192.168.1.1"; /* read options file first since * command line arguments have final say */ if(readoptionsfile(optionsfile) < 0) { /* only error if file exists or using -f */ if(access(optionsfile, F_OK) == 0 || options_flag) fprintf(stderr, "Error reading configuration file %s\n", optionsfile); } else { for(i=0; i<num_options; i++) { switch(ary_options[i].id) { case UPNPIFNAME: for( string = ary_options[i].value; (word = strtok(string, ",")); string = NULL ) { if(n_lan_addr < MAX_LAN_ADDR) { if(getifaddr(word, ip_addr, sizeof(ip_addr)) >= 0) { if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) if(n_lan_addr < MAX_LAN_ADDR) n_lan_addr++; } else fprintf(stderr, "Interface %s not found, ignoring.\n", word); } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, word); } } break; case UPNPLISTENING_IP: if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ary_options[i].value) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, ary_options[i].value); } break; case UPNPPORT: runtime_vars.port = atoi(ary_options[i].value); break; case UPNPNOTIFY_INTERVAL: runtime_vars.notify_interval = atoi(ary_options[i].value); break; case UPNPSERIAL: strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; break; case UPNPMODEL_NAME: strncpy(modelname, ary_options[i].value, MODELNAME_MAX_LEN); modelname[MODELNAME_MAX_LEN-1] = '\0'; break; case UPNPMODEL_NUMBER: strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; break; case UPNPLOGDIR: path = realpath(ary_options[i].value, real_path); if( !path ) path = (ary_options[i].value); make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); if( access(path, F_OK) != 0 ) { DPRINTF(E_FATAL, L_GENERAL, "Log path not accessible! [%s]\n", path); break; } strncpy(log_path, path, PATH_MAX); break; case UPNPMINISSDPDSOCKET: minissdpdsocketpath = ary_options[i].value; break; case UPNPREMOTEUUID: runtime_vars.ruuid = ary_options[i].value; strcpy(uuidvalue+5, runtime_vars.ruuid); break; case UPNPREMOTEPORT: runtime_vars.rport = atoi(ary_options[i].value); break; case UPNPREMOTEHOST: runtime_vars.rhost = ary_options[i].value; break; case UPNPDESCPATH: runtime_vars.path = ary_options[i].value; break; default: fprintf(stderr, "Unknown option with value %s in file %s\n", ary_options[i].value, optionsfile); } } } if( log_path[0] == '\0' ) { strncpy(log_path, DEFAULT_LOG_PATH, PATH_MAX); } /* command line arguments processing */ for(i=1; i<argc; i++) { if(argv[i][0]!='-') { fprintf(stderr, "Unknown option: %s\n", argv[i]); } else if(strcmp(argv[i], "--help")==0) { runtime_vars.port = 0; break; } else switch(argv[i][1]) { case 't': if(i+1 < argc) runtime_vars.notify_interval = atoi(argv[++i]); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; /*case 'l': logfilename = argv[++i]; break;*/ case 'p': if(i+1 < argc) runtime_vars.port = atoi(argv[++i]); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'P': if(i+1 < argc) pidfilename = argv[++i]; else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'd': debug_flag = 1; break; case 'a': if(i+1 < argc) { int address_already_there = 0; int j; i++; for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, argv[i]); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'i': if(i+1 < argc) { int address_already_there = 0; int j; i++; if( getifaddr(argv[i], ip_addr, sizeof(ip_addr)) < 0 ) { fprintf(stderr, "Network interface '%s' not found.\n", argv[i]); exit(-1); } for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, ip_addr); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'f': i++; /* discarding, the config file is already read */ break; case 'h': runtime_vars.port = 0; // triggers help display break; case 'V': printf("Version " DLNAPROXY_VERSION "\n"); exit(0); break; default: fprintf(stderr, "Unknown option: %s\n", argv[i]); } } /* If no IP was specified, try to detect one */ if( n_lan_addr < 1 ) { if( (getsysaddr(ip_addr, sizeof(ip_addr)) < 0) && (getifaddr("eth0", ip_addr, sizeof(ip_addr)) < 0) && (getifaddr("eth1", ip_addr, sizeof(ip_addr)) < 0) ) { DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); } if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) { n_lan_addr++; } } if( (n_lan_addr==0) || (runtime_vars.port<=0) ) { fprintf(stderr, "Usage:\n\t" "%s [-d] [-f config_file]\n" "\t\t[-a listening_ip] [-p port]\n" /*"[-l logfile] " not functionnal */ "\t\t[-t notify_interval] [-P pid_filename]\n" "\t\t[-V] [-h]\n" "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" "\tDefault pid file is %s.\n" "\tWith -d dlnaproxy will run in debug mode (not daemonize).\n" "\t-h displays this text\n" "\t-V print the version number\n", argv[0], pidfilename); return 1; } if(debug_flag) { pid = getpid(); log_init(NULL, "general,inotify,http,ssdp=debug"); } else { #ifdef USE_DAEMON if(daemon(0, 0)<0) { perror("daemon()"); } pid = getpid(); #else pid = daemonize(); #endif if( access(log_path, F_OK) != 0 ) make_dir(log_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); sprintf(real_path, "%s/dlnaproxy.log", log_path); log_init(real_path, "general,inotify,http,ssdp=warn"); } if(checkforrunning(pidfilename) < 0) { DPRINTF(E_ERROR, L_GENERAL, "DLNAProxy is already running. EXITING.\n"); return 1; } set_startup_time(); /* presentation url */ if(presurl) { strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0'; } else { snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, "http://%s:%d/", lan_addr[0].str, runtime_vars.port); } /* set signal handler */ signal(SIGCLD, SIG_IGN); memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; if (sigaction(SIGTERM, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n"); } if (sigaction(SIGINT, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n"); } if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n"); } writepidfile(pidfilename, pid); return 0; }
/* init phase : * 1) read configuration file * 2) read command line arguments * 3) daemonize * 4) check and write pid file * 5) set startup time stamp * 6) compute presentation URL * 7) set signal handlers */ static int init(int argc, char * * argv) { int i; int pid; int debug_flag = 0; int options_flag = 0; struct sigaction sa; /*const char * logfilename = 0;*/ const char * presurl = 0; #if 1 const char * optionsfile = "/system/etc/minidlna.conf"; #else const char * optionsfile = "/etc/minidlna.conf"; #endif char mac_str[13]; char * string, * word; enum media_types type; char * path; char real_path[PATH_MAX]; char ext_ip_addr[INET_ADDRSTRLEN] = {'\0'}; /* first check if "-f" option is used */ for(i=2; i<argc; i++) { if(0 == strcmp(argv[i-1], "-f")) { optionsfile = argv[i]; options_flag = 1; break; } } /* set up uuid based on mac address */ if( getsyshwaddr(mac_str, sizeof(mac_str)) < 0 ) { DPRINTF(E_OFF, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n"); strcpy(mac_str, "554e4b4e4f57"); } strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-"); strncat(uuidvalue, mac_str, 12); getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN); runtime_vars.port = -1; runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ /* read options file first since * command line arguments have final say */ if(readoptionsfile(optionsfile) < 0) { /* only error if file exists or using -f */ if(access(optionsfile, F_OK) == 0 || options_flag) fprintf(stderr, "Error reading configuration file %s\n", optionsfile); } else { for(i=0; i<num_options; i++) { switch(ary_options[i].id) { case UPNPIFNAME: if(getifaddr(ary_options[i].value, ext_ip_addr, INET_ADDRSTRLEN) >= 0) { if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) n_lan_addr++; } else fprintf(stderr, "Interface %s not found, ignoring.\n", ary_options[i].value); break; case UPNPLISTENING_IP: if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ary_options[i].value) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, ary_options[i].value); } break; case UPNPPORT: runtime_vars.port = atoi(ary_options[i].value); break; case UPNPPRESENTATIONURL: presurl = ary_options[i].value; break; case UPNPNOTIFY_INTERVAL: runtime_vars.notify_interval = atoi(ary_options[i].value); break; case UPNPSERIAL: strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; break; case UPNPMODEL_NUMBER: strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; break; case UPNPFRIENDLYNAME: strncpy(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN); friendly_name[FRIENDLYNAME_MAX_LEN-1] = '\0'; break; case UPNPMEDIADIR: type = ALL_MEDIA; char * myval = NULL; switch( ary_options[i].value[0] ) { case 'A': case 'a': if( ary_options[i].value[0] == 'A' || ary_options[i].value[0] == 'a' ) type = AUDIO_ONLY; case 'V': case 'v': if( ary_options[i].value[0] == 'V' || ary_options[i].value[0] == 'v' ) type = VIDEO_ONLY; case 'P': case 'p': if( ary_options[i].value[0] == 'P' || ary_options[i].value[0] == 'p' ) type = IMAGES_ONLY; myval = index(ary_options[i].value, '/'); case '/': path = realpath(myval ? myval:ary_options[i].value, real_path); if( !path ) path = (myval ? myval:ary_options[i].value); if( access(path, F_OK) != 0 ) { fprintf(stderr, "Media directory not accessible! [%s]\n", path); break; } struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s)); this_dir->path = strdup(path); this_dir->type = type; if( !media_dirs ) { media_dirs = this_dir; } else { struct media_dir_s * all_dirs = media_dirs; while( all_dirs->next ) all_dirs = all_dirs->next; all_dirs->next = this_dir; } break; default: fprintf(stderr, "Media directory entry not understood! [%s]\n", ary_options[i].value); break; } break; case UPNPALBUMART_NAMES: for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) { struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s)); this_name->name = strdup(word); if( !album_art_names ) { album_art_names = this_name; } else { struct album_art_name_s * all_names = album_art_names; while( all_names->next ) all_names = all_names->next; all_names->next = this_name; } } break; case UPNPINOTIFY: if( (strcmp(ary_options[i].value, "yes") != 0) && !atoi(ary_options[i].value) ) CLEARFLAG(INOTIFY_MASK); break; case ENABLE_TIVO: if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) SETFLAG(TIVO_MASK); break; case ENABLE_DLNA_STRICT: if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) SETFLAG(DLNA_STRICT_MASK); break; default: fprintf(stderr, "Unknown option in file %s\n", optionsfile); } } } /* command line arguments processing */ for(i=1; i<argc; i++) { if(argv[i][0]!='-') { fprintf(stderr, "Unknown option: %s\n", argv[i]); } else if(strcmp(argv[i], "--help")==0) { runtime_vars.port = 0; break; } else switch(argv[i][1]) { case 't': if(i+1 < argc) runtime_vars.notify_interval = atoi(argv[++i]); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 's': if(i+1 < argc) strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; break; case 'm': if(i+1 < argc) strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; break; /*case 'l': logfilename = argv[++i]; break;*/ case 'p': if(i+1 < argc) runtime_vars.port = atoi(argv[++i]); else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'P': if(i+1 < argc) pidfilename = argv[++i]; else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'd': debug_flag = 1; break; case 'w': if(i+1 < argc) presurl = argv[++i]; else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'a': if(i+1 < argc) { int address_already_there = 0; int j; i++; for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, argv[i]); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'i': if(i+1 < argc) { int address_already_there = 0; int j; i++; if( getifaddr(argv[i], ext_ip_addr, INET_ADDRSTRLEN) < 0 ) { fprintf(stderr, "Network interface '%s' not found.\n", argv[i]); exit(-1); } for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, ext_ip_addr); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(n_lan_addr < MAX_LAN_ADDR) { if(parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0) n_lan_addr++; } else { fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", MAX_LAN_ADDR, argv[i]); } } else fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); break; case 'f': i++; /* discarding, the config file is already read */ break; case 'h': runtime_vars.port = 0; // triggers help display break; case 'R': system("rm -rf " DB_PATH); // triggers a full rescan break; case 'V': printf("Version " MINIDLNA_VERSION "\n"); exit(0); break; default: fprintf(stderr, "Unknown option: %s\n", argv[i]); } } /* If no IP was specified, try to detect one */ if( n_lan_addr < 1 ) { if( (getsysaddr(ext_ip_addr, INET_ADDRSTRLEN) < 0) && (getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) && (getifaddr("eth1", ext_ip_addr, INET_ADDRSTRLEN) < 0) ) { DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); } if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) { n_lan_addr++; } } if( (n_lan_addr==0) || (runtime_vars.port<=0) ) { fprintf(stderr, "Usage:\n\t" "%s [-d] [-f config_file]\n" "\t\t[-a listening_ip] [-p port]\n" /*"[-l logfile] " not functionnal */ "\t\t[-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n" "\t\t[-w url] [-R] [-V] [-h]\n" "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" "\tDefault pid file is %s.\n" "\tWith -d minidlna will run in debug mode (not daemonize).\n" "\t-w sets the presentation url. Default is http address on port 80\n" "\t-h displays this text\n" "\t-R forces a full rescan\n" "\t-V print the version number\n", argv[0], pidfilename); return 1; } if(debug_flag) { pid = getpid(); log_init(NULL, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug"); } else { #ifdef USE_DAEMON if(daemon(0, 0)<0) { perror("daemon()"); } pid = getpid(); #else pid = daemonize(); #endif #ifdef READYNAS log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); #else log_init(DB_PATH "/minidlna.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); #endif } if(checkforrunning(pidfilename) < 0) { DPRINTF(E_ERROR, L_GENERAL, "MiniDLNA is already running. EXITING.\n"); return 1; } set_startup_time(); /* presentation url */ if(presurl) { strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0'; } else { #ifdef READYNAS snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, "https://%s/admin/", lan_addr[0].str); #else snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, "http://%s:%d/", lan_addr[0].str, runtime_vars.port); #endif } /* set signal handler */ //signal(SIGCLD, SIG_IGN); signal(SIGCHLD, SIG_IGN); memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; if (sigaction(SIGTERM, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n"); } if (sigaction(SIGINT, &sa, NULL)) { DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n"); } if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n"); } writepidfile(pidfilename, pid); return 0; }
/* disabled at the moment */ int ProcessInterfaceUp(struct ifinfomsg *ifi) { struct lan_iface_s * lan_iface; struct lan_iface_s * lan_iface2; struct lan_addr_s * lan_addr; char ifname[IFNAMSIZ]; char ifstraddr[16]; struct in_addr ifaddr; /* check if we already have this iface */ for(lan_iface = lan_ifaces.lh_first; lan_iface != NULL; lan_iface = lan_iface->list.le_next) if (lan_iface->iface.index == ifi->ifi_index) break; if (lan_iface != NULL) return 0; if (if_indextoname(ifi->ifi_index, ifname) == NULL) { syslog(LOG_ERR, "if_indextoname(%d, ifname) failed", ifi->ifi_index); return -1; } if (getifaddr(ifname, ifstraddr, 16) < 0) { syslog(LOG_DEBUG, "getifaddr(%s, ifaddr, 16) failed", ifname); return 1; } if (inet_pton(AF_INET, ifstraddr, &ifaddr) != 1) { syslog(LOG_ERR, "inet_pton(AF_INET, \"%s\", &ifaddr) failed", ifstraddr); return -1; } /* check if this new interface has address which we need to listen to */ for(lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next) { if (lan_addr->addr.s_addr != ifaddr.s_addr) continue; syslog(LOG_INFO, "Interface up: %s (%s)", ifname, ifstraddr); /* adding new lan_iface entry */ lan_iface = (struct lan_iface_s *) malloc(sizeof(struct lan_iface_s)); if (lan_iface == NULL) { syslog(LOG_ERR, "malloc(sizeof(struct lan_iface_s): %m"); continue; } lan_iface->lan_addr = lan_addr; strncpy(lan_iface->iface.name, ifname, IFNAMSIZ); lan_iface->iface.index = ifi->ifi_index; lan_iface->iface.addr = ifaddr; lan_iface->snotify = -1; #ifdef ENABLE_NATPMP lan_iface->snatpmp = -1; #endif LIST_INSERT_HEAD(&lan_ifaces, lan_iface, list); /* adding multicast membership for SSDP */ if(AddMulticastMembership(sudp, ifaddr.s_addr, ifi->ifi_index) < 0) syslog(LOG_WARNING, "Failed to add multicast membership for interface %s (%s)", ifname, ifstraddr); else syslog(LOG_INFO, "Multicast membership added for %s (%s)", ifname, ifstraddr); /* create SSDP notify socket */ if (OpenAndConfSSDPNotifySocket(lan_iface) < 0) syslog(LOG_WARNING, "Failed to open SSDP notify socket for interface %s (%s)", ifname, ifstraddr); #ifdef ENABLE_NATPMP /* create NAT-PMP socket */ for(lan_iface2 = lan_ifaces.lh_first; lan_iface2 != NULL; lan_iface2 = lan_iface2->list.le_next) if (lan_iface2->lan_addr->addr.s_addr == lan_iface->lan_addr->addr.s_addr && lan_iface2->snatpmp >= 0) lan_iface->snatpmp = lan_iface2->snatpmp; if (lan_iface->snatpmp < 0) { lan_iface->snatpmp = OpenAndConfNATPMPSocket(ifaddr.s_addr); if (lan_iface->snatpmp < 0) syslog(LOG_ERR, "OpenAndConfNATPMPSocket(ifaddr.s_addr) failed for %s (%s)", ifname, ifstraddr); else syslog(LOG_INFO, "Listening for NAT-PMP connection on %s:%d", ifstraddr, NATPMP_PORT); } #endif } return 0; }
int port_in_use(const char *if_name, unsigned eport, int proto, const char *iaddr, unsigned iport) { int found = 0; char ip_addr_str[INET_ADDRSTRLEN]; struct in_addr ip_addr; #ifdef __linux__ /* linux code */ char line[256]; FILE *f; const char * tcpfile = "/proc/net/tcp"; const char * udpfile = "/proc/net/udp"; #endif if(getifaddr(if_name, ip_addr_str, INET_ADDRSTRLEN, &ip_addr, NULL) < 0) { ip_addr.s_addr = 0; ip_addr_str[0] = '\0'; } syslog(LOG_DEBUG, "Check protocol %s for port %d on ext_if %s %s, %08X", (proto==IPPROTO_TCP)?"tcp":"udp", eport, if_name, ip_addr_str, (unsigned)ip_addr.s_addr); /* Phase 1 : check for local sockets (would be listed by netstat) */ #if defined(__linux__) f = fopen((proto==IPPROTO_TCP)?tcpfile:udpfile, "r"); if (!f) { syslog(LOG_ERR, "cannot open %s", (proto==IPPROTO_TCP)?tcpfile:udpfile); return -1; } while (fgets(line, 255, f)) { char eaddr[68]; unsigned tmp_port; if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " "%*x:%*x %*x %*d %*d %*llu", eaddr, &tmp_port) == 2 ) { /* TODO add IPV6 support if enabled * Presently assumes IPV4 */ #ifdef DEBUG syslog(LOG_DEBUG, "port_in_use check port %d and address %s", tmp_port, eaddr); #endif if (tmp_port == eport) { char tmp_addr[4]; struct in_addr *tmp_ip_addr = (struct in_addr *)tmp_addr; if (sscanf(eaddr,"%2hhx%2hhx%2hhx%2hhx", &tmp_addr[3],&tmp_addr[2],&tmp_addr[1],&tmp_addr[0]) == 4) { if (tmp_ip_addr->s_addr == 0 || tmp_ip_addr->s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } } } fclose(f); #elif defined(__OpenBSD__) static struct nlist list[] = { #if 0 {"_tcpstat", 0, 0, 0, 0}, {"_udpstat", 0, 0, 0, 0}, {"_tcbinfo", 0, 0, 0, 0}, {"_udbinfo", 0, 0, 0, 0}, #endif {"_tcbtable", 0, 0, 0, 0}, {"_udbtable", 0, 0, 0, 0}, {NULL,0, 0, 0, 0} }; char errstr[_POSIX2_LINE_MAX]; kvm_t *kd; ssize_t n; struct inpcbtable table; struct inpcb *next; struct inpcb inpcb; kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr); if(!kd) { syslog(LOG_ERR, "%s: kvm_openfiles(): %s", "portinuse()", errstr); return -1; } if(kvm_nlist(kd, list) < 0) { syslog(LOG_ERR, "%s: kvm_nlist(): %s", "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } n = kvm_read(kd, list[(proto==IPPROTO_TCP)?0:1].n_value, &table, sizeof(table)); if(n < 0) { syslog(LOG_ERR, "%s: kvm_read(): %s", "portinuse()", kvm_geterr(kd)); kvm_close(kd); return -1; } next = CIRCLEQ_FIRST(&table.inpt_queue); /*TAILQ_FIRST(&table.inpt_queue);*/ while(next != NULL) { if(((u_long)next & 3) != 0) break; n = kvm_read(kd, (u_long)next, &inpcb, sizeof(inpcb)); if(n < 0) { syslog(LOG_ERR, "kvm_read(): %s", kvm_geterr(kd)); break; } next = CIRCLEQ_NEXT(&inpcb, inp_queue); /*TAILQ_NEXT(&inpcb, inp_queue);*/ /* skip IPv6 sockets */ if((inpcb.inp_flags & INP_IPV6) != 0) continue; #ifdef DEBUG syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu", (u_long)inpcb.inp_laddr.s_addr, ntohs(inpcb.inp_lport), (u_long)inpcb.inp_faddr.s_addr, ntohs(inpcb.inp_fport)); #endif if(eport == (unsigned)ntohs(inpcb.inp_lport)) { if(inpcb.inp_laddr.s_addr == INADDR_ANY || inpcb.inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } kvm_close(kd); #elif defined(__DragonFly__) const char *varname; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; void *buf = NULL; void *so_begin, *so_end; size_t len; switch (proto) { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: varname = "net.inet.udp.pcblist"; break; default: syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); return -1; } if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); return -1; } buf = malloc(len); if (buf == NULL) { syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); return -1; } if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); free(buf); return -1; } so_begin = buf; so_end = (uint8_t *)buf + len; for (so_begin = buf, so_end = (uint8_t *)so_begin + len; (uint8_t *)so_begin + sizeof(size_t) < (uint8_t *)so_end && (uint8_t *)so_begin + *(size_t *)so_begin <= (uint8_t *)so_end; so_begin = (uint8_t *)so_begin + *(size_t *)so_begin) { switch (proto) { case IPPROTO_TCP: xtp = (struct xtcpcb *)so_begin; if (xtp->xt_len != sizeof *xtp) { syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", (long)xtp->xt_len, sizeof *xtp); free(buf); return -1; } inp = &xtp->xt_inp; break; case IPPROTO_UDP: xip = (struct xinpcb *)so_begin; if (xip->xi_len != sizeof *xip) { syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", (long)xip->xi_len, sizeof *xip); free(buf); return -1; } inp = &xip->xi_inp; break; default: abort(); } /* no support for IPv6 */ if ((inp->inp_vflag & INP_IPV6) != 0) continue; syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), eport, (u_long)ip_addr.s_addr, iport ); if (eport == (unsigned)ntohs(inp->inp_lport)) { if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } if(buf) { free(buf); buf = NULL; } #elif defined(__FreeBSD__) const char *varname; struct xinpgen *xig, *exig; struct xinpcb *xip; struct xtcpcb *xtp; struct inpcb *inp; void *buf = NULL; size_t len; switch (proto) { case IPPROTO_TCP: varname = "net.inet.tcp.pcblist"; break; case IPPROTO_UDP: varname = "net.inet.udp.pcblist"; break; default: syslog(LOG_ERR, "port_in_use() unknown proto=%d", proto); return -1; } if (sysctlbyname(varname, NULL, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, NULL, ...): %m", varname); return -1; } buf = malloc(len); if (buf == NULL) { syslog(LOG_ERR, "malloc(%u) failed", (unsigned)len); return -1; } if (sysctlbyname(varname, buf, &len, NULL, 0) < 0) { syslog(LOG_ERR, "sysctlbyname(%s, buf, ...): %m", varname); free(buf); return -1; } xig = (struct xinpgen *)buf; exig = (struct xinpgen *)(void *)((char *)buf + len - sizeof *exig); if (xig->xig_len != sizeof *xig) { syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", (long)xig->xig_len, sizeof *xig); free(buf); return -1; } if (exig->xig_len != sizeof *exig) { syslog(LOG_WARNING, "struct xinpgen size mismatch; %ld vs %ld", (long)exig->xig_len, sizeof *exig); free(buf); return -1; } while (1) { xig = (struct xinpgen *)(void *)((char *)xig + xig->xig_len); if (xig >= exig) break; switch (proto) { case IPPROTO_TCP: xtp = (struct xtcpcb *)xig; if (xtp->xt_len != sizeof *xtp) { syslog(LOG_WARNING, "struct xtcpcb size mismatch; %ld vs %ld", (long)xtp->xt_len, sizeof *xtp); free(buf); return -1; } inp = &xtp->xt_inp; break; case IPPROTO_UDP: xip = (struct xinpcb *)xig; if (xip->xi_len != sizeof *xip) { syslog(LOG_WARNING, "struct xinpcb size mismatch : %ld vs %ld", (long)xip->xi_len, sizeof *xip); free(buf); return -1; } inp = &xip->xi_inp; break; default: abort(); } /* no support for IPv6 */ if ((inp->inp_vflag & INP_IPV6) != 0) continue; syslog(LOG_DEBUG, "%08lx:%hu %08lx:%hu <=> %hu %08lx:%hu", (u_long)inp->inp_laddr.s_addr, ntohs(inp->inp_lport), (u_long)inp->inp_faddr.s_addr, ntohs(inp->inp_fport), eport, (u_long)ip_addr.s_addr, iport ); if (eport == (unsigned)ntohs(inp->inp_lport)) { if (inp->inp_laddr.s_addr == INADDR_ANY || inp->inp_laddr.s_addr == ip_addr.s_addr) { found++; break; /* don't care how many, just that we found at least one */ } } } if (buf) { free(buf); buf = NULL; } /* #elif __NetBSD__ */ #else /* TODO : NetBSD / Darwin (OS X) / Solaris code */ #error "No port_in_use() implementation available for this OS" #endif /* Phase 2 : check existing mappings * TODO : implement for pf/ipfw/etc. */ #if defined(USE_NETFILTER) if (!found) { char iaddr_old[16]; unsigned short iport_old; int i; for (i = 0; chains_to_check[i]; i++) { if (get_nat_redirect_rule(chains_to_check[i], if_name, eport, proto, iaddr_old, sizeof(iaddr_old), &iport_old, 0, 0, 0, 0, 0, 0, 0) == 0) { syslog(LOG_DEBUG, "port_in_use check port %d on nat chain %s redirected to %s port %d", eport, chains_to_check[i], iaddr_old, iport_old); if (!(strcmp(iaddr, iaddr_old)==0 && iport==iport_old)) { /* only "in use" if redirected to somewhere else */ found++; break; /* don't care how many, just that we found at least one */ } } } } #else /* USE_NETFILTER */ UNUSED(iport); UNUSED(iaddr); #endif /* USE_NETFILTER */ return found; }
/* parselanaddr() * parse address with mask * ex: 192.168.1.1/24 or 192.168.1.1/255.255.255.0 * When MULTIPLE_EXTERNAL_IP is enabled, the ip address of the * external interface associated with the lan subnet follows. * ex : 192.168.1.1/24 81.21.41.11 * * Can also use the interface name (ie eth0) * * return value : * 0 : ok * -1 : error */ static int parselanaddr(struct lan_addr_s * lan_addr, const char * str) { const char * p; int n; char tmp[16]; memset(lan_addr, 0, sizeof(struct lan_addr_s)); p = str; while(*p && *p != '/' && !isspace(*p)) p++; n = p - str; if(!isdigit(str[0]) && n < (int)sizeof(lan_addr->ifname)) { /* not starting with a digit : suppose it is an interface name */ memcpy(lan_addr->ifname, str, n); lan_addr->ifname[n] = '\0'; if(getifaddr(lan_addr->ifname, lan_addr->str, sizeof(lan_addr->str)) < 0) goto parselan_error; } else { if(n>15) goto parselan_error; memcpy(lan_addr->str, str, n); lan_addr->str[n] = '\0'; } if(!inet_aton(lan_addr->str, &lan_addr->addr)) goto parselan_error; if(*p == '/') { const char * q = ++p; while(*p && isdigit(*p)) p++; if(*p=='.') { while(*p && (*p=='.' || isdigit(*p))) p++; n = p - q; if(n>15) goto parselan_error; memcpy(tmp, q, n); tmp[n] = '\0'; if(!inet_aton(tmp, &lan_addr->mask)) goto parselan_error; } else { int nbits = atoi(q); if(nbits > 32 || nbits < 0) goto parselan_error; lan_addr->mask.s_addr = htonl(nbits ? (0xffffffffu << (32 - nbits)) : 0); } } else { /* by default, networks are /24 */ lan_addr->mask.s_addr = htonl(0xffffff00u); } #ifdef MULTIPLE_EXTERNAL_IP /* skip spaces */ while(*p && isspace(*p)) p++; if(*p) { /* parse the exteral ip address to associate with this subnet */ n = 0; while(p[n] && !isspace(*p)) n++; if(n<=15) { memcpy(lan_addr->ext_ip_str, p, n); lan_addr->ext_ip_str[n] = '\0'; if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) { /* error */ fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str); } } } #endif #ifdef ENABLE_IPV6 if(lan_addr->ifname[0] != '\0') { lan_addr->index = if_nametoindex(lan_addr->ifname); if(lan_addr->index == 0) fprintf(stderr, "Cannot get index for network interface %s", lan_addr->ifname); } #endif return 0; parselan_error: fprintf(stderr, "Error parsing address/mask (or interface name) : %s\n", str); return -1; }