📄 miniupnpd.c
字号:
v->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 'B': if(i+2<argc) { downstream_bitrate = strtoul(argv[++i], 0, 0); upstream_bitrate = strtoul(argv[++i], 0, 0); } else fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]); break; case 'a': i++; if(i+1 < argc) { int address_already_there = 0; int j; for(j=0; j<v->n_lan_addr; j++) { struct lan_addr_s tmpaddr; parselanaddr(&tmpaddr, argv[i]); /*if(0 == strcmp(v->lan_addr[j], argv[i]))*/ if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } if(address_already_there) break; if(v->n_lan_addr < MAX_LAN_ADDR) { /*v->lan_addr[v->n_lan_addr++] = argv[i];*/ if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0) v->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; default: fprintf(stderr, "Unknown option: %s\n", argv[i]); } } if(!ext_if_name || (v->n_lan_addr==0) || v->port<=0) { fprintf(stderr, "Usage:\n\t" "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n" "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U]\n" /*"[-l logfile] " not functionnal */ "\t\t[-u uuid] [-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n" "\t\t[-B down up] [-w url]\n" "\nNotes:\n\tThere can be one or several listening_ips.\n" "\tNotify interval is in seconds. Default is 30 seconds.\n" "\tDefault pid file is %s.\n" "\tWith -d miniupnpd will run as a standard program.\n" "\t-L sets packet log in pf on.\n" "\t-U causes miniupnpd to report system uptime instead " "of daemon uptime.\n" "\t-B sets bitrates reported by daemon in bits per second.\n" "\t-w sets the presentation url. Default is http address on port 80\n", argv[0], pidfilename); return 1; } if(debug_flag) { pid = getpid(); } else { pid = daemonize(); } openlog_option = LOG_PID|LOG_CONS; if(debug_flag) { openlog_option |= LOG_PERROR; /* also log on stderr */ } openlog("miniupnpd", openlog_option, LOG_MINIUPNPD); if(!debug_flag) { /* speed things up and ignore LOG_INFO and LOG_DEBUG */ setlogmask(LOG_UPTO(LOG_NOTICE)); } if(checkforrunning(pidfilename) < 0) { syslog(LOG_ERR, "MiniUPnPd is already running. EXITING"); return 1; } writepidfile(pidfilename, pid); set_startup_time(sysuptime); /* 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/", v->lan_addr[0].str, 80); } /* set signal handler */ memset(&sa, 0, sizeof(struct sigaction)); sa.sa_handler = sigterm; if (sigaction(SIGTERM, &sa, NULL)) { syslog(LOG_ERR, "Failed to set SIGTERM handler. EXITING"); return 1; } if (sigaction(SIGINT, &sa, NULL)) { syslog(LOG_ERR, "Failed to set SIGINT handler. EXITING"); return 1; } return 0;}/* === main === *//* process HTTP or SSDP requests */intmain(int argc, char * * argv){ int i; int sudp, shttpl;#ifdef ENABLE_NATPMP int snatpmp;#endif int snotify[MAX_LAN_ADDR]; LIST_HEAD(httplisthead, upnphttp) upnphttphead; struct upnphttp * e = 0; struct upnphttp * next; fd_set readset; /* for select() */ struct timeval timeout, timeofday, lasttimeofday = {0, 0};#ifdef USE_MINIUPNPDCTL int sctl; LIST_HEAD(ctlstructhead, ctlelem) ctllisthead; struct ctlelem * ectl; struct ctlelem * ectlnext;#endif struct runtime_vars v; /* variables used for the unused-rule cleanup process */ struct rule_state * rule_list = 0; struct timeval checktime = {0, 0}; if(init(argc, argv, &v) != 0) return 1; LIST_INIT(&upnphttphead);#ifdef USE_MINIUPNPDCTL LIST_INIT(&ctllisthead);#endif /* open socket for SSDP connections */ sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr); if(sudp < 0) { syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING"); return 1; } /* open socket for HTTP connections. Listen on the 1st LAN address */ shttpl = OpenAndConfHTTPSocket(v.port); if(shttpl < 0) { syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING"); return 1; } syslog(LOG_NOTICE, "HTTP listening on port %d", v.port); /* open socket for sending notifications */ if(OpenAndConfSSDPNotifySockets(snotify, v.lan_addr, v.n_lan_addr) < 0) { syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify " "messages. EXITING"); return 1; }#ifdef ENABLE_NATPMP /* open socket for NAT PMP traffic */ snatpmp = OpenAndConfNATPMPSocket(); if(snatpmp<0) { syslog(LOG_ERR, "Failed to open socket for NAT PMP. EXITING"); return 1; } syslog(LOG_NOTICE, "Listening for NAT-PMP traffic on port %u", NATPMP_PORT);#endif /* for miniupnpdctl */#ifdef USE_MINIUPNPDCTL sctl = OpenAndConfCtlUnixSocket("/var/run/miniupnpd.ctl");#endif /* main loop */ while(!quitting) { /* Check if we need to send SSDP NOTIFY messages and do it if * needed */ if(gettimeofday(&timeofday, 0) < 0) { syslog(LOG_ERR, "gettimeofday(): %m"); timeout.tv_sec = v.notify_interval; timeout.tv_usec = 0; } else { /* the comparaison is not very precise but who cares ? */ if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval)) { SendSSDPNotifies2(snotify, v.lan_addr, v.n_lan_addr, (unsigned short)v.port, v.notify_interval << 1); memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval)); timeout.tv_sec = v.notify_interval; timeout.tv_usec = 0; } else { timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval - timeofday.tv_sec; if(timeofday.tv_usec > lasttimeofday.tv_usec) { timeout.tv_usec = 1000000 + lasttimeofday.tv_usec - timeofday.tv_usec; timeout.tv_sec--; } else { timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec; } } } /* remove unused rules */ if( v.clean_ruleset_interval && (timeofday.tv_sec >= checktime.tv_sec + v.clean_ruleset_interval)) { if(rule_list) { remove_unused_rules(rule_list); rule_list = NULL; } else { rule_list = get_upnp_rules_state_list(v.clean_ruleset_threshold); } memcpy(&checktime, &timeofday, sizeof(struct timeval)); } /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); FD_SET(sudp, &readset); FD_SET(shttpl, &readset); i = 0; /* active HTTP connections count */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { if((e->socket >= 0) && (e->state <= 2)) { FD_SET(e->socket, &readset); i++; } } /* for debug */#ifdef DEBUG if(i > 1) { syslog(LOG_DEBUG, "%d active incoming HTTP connections", i); }#endif#ifdef ENABLE_NATPMP if(snatpmp >= 0) FD_SET(snatpmp, &readset);#endif#ifdef USE_MINIUPNPDCTL if(sctl >= 0) FD_SET(sctl, &readset); for(ectl = ctllisthead.lh_first; ectl; ectl = ectl->entries.le_next) { if(ectl->socket >= 0) FD_SET(ectl->socket, &readset); }#endif if(select(FD_SETSIZE, &readset, 0, 0, &timeout) < 0) { if(quitting) goto shutdown; syslog(LOG_ERR, "select(all): %m"); syslog(LOG_ERR, "Failed to select open sockets. EXITING"); return 1; /* very serious cause of error */ }#ifdef USE_MINIUPNPDCTL for(ectl = ctllisthead.lh_first; ectl;) { ectlnext = ectl->entries.le_next; if((ectl->socket >= 0) && FD_ISSET(ectl->socket, &readset)) { char buf[256]; int l; l = read(ectl->socket, buf, sizeof(buf)); if(l > 0) { /*write(ectl->socket, buf, l);*/ write_option_list(ectl->socket); write_permlist(ectl->socket, upnppermlist, num_upnpperm); write_upnphttp_details(ectl->socket, upnphttphead.lh_first); write_ctlsockets_list(ectl->socket, ctllisthead.lh_first); write_ruleset_details(ectl->socket); /* close the socket */ close(ectl->socket); ectl->socket = -1; } else { close(ectl->socket); ectl->socket = -1; } } if(ectl->socket < 0) { LIST_REMOVE(ectl, entries); free(ectl); } ectl = ectlnext; } if((sctl >= 0) && FD_ISSET(sctl, &readset)) { int s; struct sockaddr_un clientname; struct ctlelem * tmp; socklen_t clientnamelen = sizeof(struct sockaddr_un); //syslog(LOG_DEBUG, "sctl!"); s = accept(sctl, (struct sockaddr *)&clientname, &clientnamelen); syslog(LOG_DEBUG, "sctl! : '%s'", clientname.sun_path); tmp = malloc(sizeof(struct ctlelem)); tmp->socket = s; LIST_INSERT_HEAD(&ctllisthead, tmp, entries); }#endif#ifdef ENABLE_NATPMP /* process NAT-PMP packets */ if((snatpmp >= 0) && FD_ISSET(snatpmp, &readset)) { ProcessIncomingNATPMPPacket(snatpmp); }#endif /* process SSDP packets */ if(FD_ISSET(sudp, &readset)) { /*syslog(LOG_INFO, "Received UDP Packet");*/ ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr, (unsigned short)v.port); } /* process active HTTP connections */ /* LIST_FOREACH is not available under linux */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { if( (e->socket >= 0) && (e->state <= 2) &&(FD_ISSET(e->socket, &readset)) ) { Process_upnphttp(e); } } /* process incoming HTTP connections */ if(FD_ISSET(shttpl, &readset)) { int shttp; socklen_t clientnamelen; struct sockaddr_in clientname; clientnamelen = sizeof(struct sockaddr_in); shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); if(shttp<0) { syslog(LOG_ERR, "accept(http): %m"); } else { struct upnphttp * tmp = 0; syslog(LOG_INFO, "HTTP connection from %s:%d", inet_ntoa(clientname.sin_addr), ntohs(clientname.sin_port) ); /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) { syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK"); }*/ /* Create a new upnphttp object and add it to * the active upnphttp object list */ tmp = New_upnphttp(shttp); if(tmp) { LIST_INSERT_HEAD(&upnphttphead, tmp, entries); } else { syslog(LOG_ERR, "New_upnphttp() failed"); close(shttp); } } } /* delete finished HTTP connections */ for(e = upnphttphead.lh_first; e != NULL; ) { next = e->entries.le_next; if(e->state >= 100) { LIST_REMOVE(e, entries); Delete_upnphttp(e); } e = next; } }shutdown: /* close out open sockets */ while(upnphttphead.lh_first != NULL) { e = upnphttphead.lh_first; LIST_REMOVE(e, entries); Delete_upnphttp(e); } close(sudp); close(shttpl);#ifdef ENABLE_NATPMP close(snatpmp);#endif#ifdef USE_MINIUPNPDCTL close(sctl); if(unlink("/var/run/miniupnpd.ctl") < 0) { syslog(LOG_ERR, "unlink() %m"); }#endif if(SendSSDPGoodbye(snotify, v.n_lan_addr) < 0) { syslog(LOG_ERR, "Failed to broadcast good-bye notifications"); } for(i=0; i<v.n_lan_addr; i++) close(snotify[i]); if(unlink(pidfilename) < 0) { syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename); } closelog(); freeoptions(); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -