static int parse_ip6_port(struct in6_addr *ip6, u_int16_t *port, char *s) { u_int32_t ip; char *p; if (!parse_ip_port(&ip, port, s)) { if (ip) in4_to_6(ip6, ip); else *ip6 = in6addr_any; return 0; } if (*s != '[') return -1; p = strstr(s, "]:"); if (!p) return -1; *p = '\0'; if (inet_pton(AF_INET6, s+1, ip6) != 1) goto fail; *p = ']'; *port = atoi(p+2); if (!*port) return -1; return 0; fail: *p = ']'; return -1; }
int last_forwarded_ip(t_http_header *http_headers, t_ip_addr *ip_addr) { char *forwarded, *search, ip_str[MAX_IP_STR_LEN + 1], *begin, *end; size_t len; int port; if ((forwarded = get_http_header(hs_forwarded, http_headers)) != NULL) { /* Forwarded header */ begin = NULL; while ((forwarded = strcasestr(forwarded, "for=")) == NULL) { begin = forwarded; forwarded++; } if (begin == NULL) { return -1; } end = begin; while ((*end != '\0') && (*end != ',') && (*end != ';')) { end++; } if (*begin == '"') { begin++; end--; if (*end != '"') { return -1; } } len = end - begin; if (len > MAX_IP_STR_LEN) { return -1; } memcpy(ip_str, begin, len); *(ip_str + len) = '\0'; forwarded = ip_str; } else if ((forwarded = get_http_header(hs_x_forwarded_for, http_headers)) != NULL) { /* X-Forwarded-For header */ if ((search = strrchr(forwarded, ',')) != NULL) { forwarded = search + 1; while (*forwarded == ' ') { forwarded++; } } } else { return -1; } if (parse_ip(forwarded, ip_addr) == -1) { if (parse_ip_port(forwarded, ip_addr, &port) == -1) { return -1; } } return 0; }
static void options(int *argc, char ***argv) { char **if_a = NULL; char **iter; struct interface_address *ifa; char *listenps = NULL; char *listenudps = NULL; char *listenngs = NULL; char *redisps = NULL; char *log_facility_s = NULL; int version = 0; int sip_source = 0; GOptionEntry e[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL }, { "table", 't', 0, G_OPTION_ARG_INT, &table, "Kernel table to use", "INT" }, { "no-fallback",'F', 0, G_OPTION_ARG_NONE, &no_fallback, "Only start when kernel module is available", NULL }, { "interface", 'i', 0, G_OPTION_ARG_STRING_ARRAY,&if_a, "Local interface for RTP", "[NAME/]IP[!IP]"}, { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" }, { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" }, { "timeout", 'o', 0, G_OPTION_ARG_INT, &timeout, "RTP timeout", "SECS" }, { "silent-timeout",'s',0,G_OPTION_ARG_INT, &silent_timeout,"RTP timeout for muted", "SECS" }, { "pidfile", 'p', 0, G_OPTION_ARG_FILENAME, &pidfile, "Write PID to file", "FILE" }, { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Don't fork to background", NULL }, { "port-min", 'm', 0, G_OPTION_ARG_INT, &port_min, "Lowest port to use for RTP", "INT" }, { "port-max", 'M', 0, G_OPTION_ARG_INT, &port_max, "Highest port to use for RTP", "INT" }, { "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "IP:PORT" }, { "redis-db", 'R', 0, G_OPTION_ARG_INT, &redis_db, "Which Redis DB to use", "INT" }, { "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" }, { "log-level", 'L', 0, G_OPTION_ARG_INT, (void *)&log_level,"Mask log priorities above this level","INT" }, { "log-facility",0, 0, G_OPTION_ARG_STRING, &log_facility_s, "Syslog facility to use for logging", "daemon|local0|...|local7"}, { "log-stderr", 'E', 0, G_OPTION_ARG_NONE, &_log_stderr, "Log on stderr instead of syslog", NULL }, { "xmlrpc-format",'x', 0, G_OPTION_ARG_INT, &xmlrpc_fmt, "XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only", "INT" }, { "num-threads", 0, 0, G_OPTION_ARG_INT, &num_threads, "Number of worker threads to create", "INT" }, { "sip-source", 0, 0, G_OPTION_ARG_NONE, &sip_source, "Use SIP source address by default", NULL }, { "dtls-passive", 0, 0, G_OPTION_ARG_NONE, &dtls_passive_def,"Always prefer DTLS passive role", NULL }, { NULL, } }; GOptionContext *c; GError *er = NULL; c = g_option_context_new(" - next-generation media proxy"); g_option_context_add_main_entries(c, e, NULL); if (!g_option_context_parse(c, argc, argv, &er)) die("Bad command line: %s", er->message); if (version) die("%s", RTPENGINE_VERSION); if (!if_a) die("Missing option --interface"); if (!listenps && !listenudps && !listenngs) die("Missing option --listen-tcp, --listen-udp or --listen-ng"); for (iter = if_a; *iter; iter++) { ifa = if_addr_parse(*iter); if (!ifa) die("Invalid interface specification: %s", *iter); g_queue_push_tail(&interfaces, ifa); } if (listenps) { if (parse_ip_port(&listenp, &listenport, listenps)) die("Invalid IP or port (--listen-tcp)"); } if (listenudps) { if (parse_ip6_port(&udp_listenp, &udp_listenport, listenudps)) die("Invalid IP or port (--listen-udp)"); } if (listenngs) { if (parse_ip6_port(&ng_listenp, &ng_listenport, listenngs)) die("Invalid IP or port (--listen-ng)"); } if (tos < 0 || tos > 255) die("Invalid TOS value"); if (timeout <= 0) timeout = 60; if (silent_timeout <= 0) silent_timeout = 3600; if (redisps) { if (parse_ip_port(&redis_ip, &redis_port, redisps) || !redis_ip) die("Invalid IP or port (--redis)"); if (redis_db < 0) die("Must specify Redis DB number (--redis-db) when using Redis"); } if (xmlrpc_fmt > 1) die("Invalid XMLRPC format"); if ((log_level < LOG_EMERG) || (log_level > LOG_DEBUG)) die("Invalid log level (--log_level)"); setlogmask(LOG_UPTO(log_level)); if (log_facility_s) { if (!parse_log_facility(log_facility_s, &_log_facility)) { print_available_log_facilities(); die ("Invalid log facility '%s' (--log-facility)\n", log_facility_s); } } if (_log_stderr) { write_log = log_to_stderr; max_log_line_length = 0; } if (!sip_source) trust_address_def = 1; }
int main(int argc, char* argv[]) { welcome(); init(argc, argv); ServerConfig::max_channels = conf->get_num("front.max_channels"); ServerConfig::max_subscribers_per_channel = conf->get_num("front.max_subscribers_per_channel"); ServerConfig::channel_buffer_size = conf->get_num("front.channel_buffer_size"); ServerConfig::channel_timeout = conf->get_num("front.channel_timeout"); ServerConfig::polling_timeout = conf->get_num("front.polling_timeout"); if (ServerConfig::polling_timeout <= 0){ log_fatal("Invalid polling_timeout!"); exit(0); } if (ServerConfig::channel_timeout <= 0){ ServerConfig::channel_timeout = (int)(0.5 * ServerConfig::polling_timeout); } ServerConfig::polling_idles = ServerConfig::polling_timeout / CHANNEL_CHECK_INTERVAL; ServerConfig::channel_idles = ServerConfig::channel_timeout / CHANNEL_CHECK_INTERVAL; log_info("ServerConfig::max_channels =%d", ServerConfig::max_channels); log_info("ServerConfig::max_subscribers_per_channel=%d", ServerConfig::max_subscribers_per_channel); log_info("ServerConfig::polling_timeout=%d", ServerConfig::polling_timeout); log_info("ServerConfig::polling_idles =%d", ServerConfig::polling_idles); log_info("ServerConfig::channel_buffer_size=%d", ServerConfig::channel_buffer_size); log_info("ServerConfig::channel_timeout=%d", ServerConfig::channel_timeout); log_info("ServerConfig::channel_idles =%d", ServerConfig::channel_idles); serv = new Server(); ip_filter = new IpFilter(); { // /pub?cname=abc&content=hi // content must be json encoded string without leading quote and trailing quote // TODO: multi_pub evhttp_set_cb(admin_http, "/pub", pub_handler, NULL); // pub raw content(not json encoded) evhttp_set_cb(admin_http, "/push", push_handler, NULL); // 分配通道, 返回通道的id和token // /sign?cname=abc[&expires=60] // wait 60 seconds to expire before any sub evhttp_set_cb(admin_http, "/sign", sign_handler, NULL); // 销毁通道 // /close?cname=abc evhttp_set_cb(admin_http, "/close", close_handler, NULL); // 销毁通道 // /clear?cname=abc evhttp_set_cb(admin_http, "/clear", clear_handler, NULL); // 获取通道的信息 // /info?[cname=abc], or TODO: /info?cname=a,b,c evhttp_set_cb(admin_http, "/info", info_handler, NULL); // 判断通道是否处于被订阅状态(所有订阅者断开连接一定时间后, 通道才转为空闲状态) // /check?cname=abc, or TODO: /check?cname=a,b,c evhttp_set_cb(admin_http, "/check", check_handler, NULL); // 订阅通道的状态变化信息, 如创建通道(第一个订阅者连接时), 关闭通道. // 通过 endless chunk 返回. evhttp_set_cb(admin_http, "/psub", psub_handler, NULL); std::string admin_ip; int admin_port = 0; parse_ip_port(conf->get_str("admin.listen"), &admin_ip, &admin_port); struct evhttp_bound_socket *handle; handle = evhttp_bind_socket_with_handle(admin_http, admin_ip.c_str(), admin_port); if (!handle){ log_fatal("bind admin_port %d error! %s", admin_port, strerror(errno)); exit(0); } log_info("admin server listen on %s:%d", admin_ip.c_str(), admin_port); struct evconnlistener *listener = evhttp_bound_socket_get_listener(handle); evconnlistener_set_error_cb(listener, accept_error_cb); // TODO: modify libevent, add evhttp_set_accept_cb() } // init admin ip_filter { Config *cc = (Config *)conf->get("admin"); if (cc != NULL){ std::vector<Config *> *children = &cc->children; std::vector<Config *>::iterator it; for (it = children->begin(); it != children->end(); it++){ if ((*it)->key != "allow"){ continue; } const char *ip = (*it)->str(); log_info(" allow %s", ip); ip_filter->add_allow(ip); } } } { Config *cc = (Config *)conf->get("admin"); if (cc != NULL){ std::vector<Config *> *children = &cc->children; std::vector<Config *>::iterator it; for (it = children->begin(); it != children->end(); it++){ if ((*it)->key != "deny"){ continue; } const char *ip = (*it)->str(); log_info(" deny %s", ip); ip_filter->add_deny(ip); } } } { // /sub?cname=abc&cb=jsonp&token=&seq=123&noop=123 evhttp_set_cb(front_http, "/sub", poll_handler, NULL); evhttp_set_cb(front_http, "/poll", poll_handler, NULL); // forever iframe evhttp_set_cb(front_http, "/iframe", iframe_handler, NULL); // http endless chunk evhttp_set_cb(front_http, "/stream", stream_handler, NULL); // /ping?cb=jsonp evhttp_set_cb(front_http, "/ping", ping_handler, NULL); std::string front_ip; int front_port = 0; parse_ip_port(conf->get_str("front.listen"), &front_ip, &front_port); for (int i = 0; i < MAX_BIND_PORTS; i++){ int port = front_port + i; struct evhttp_bound_socket *handle; handle = evhttp_bind_socket_with_handle(front_http, front_ip.c_str(), port); if (!handle){ log_fatal("bind front_port %d error! %s", port, strerror(errno)); exit(0); } log_info("front server listen on %s:%d", front_ip.c_str(), port); struct evconnlistener *listener = evhttp_bound_socket_get_listener(handle); evconnlistener_set_error_cb(listener, accept_error_cb); } std::string auth = conf->get_str("front.auth"); log_info(" auth %s", auth.c_str()); log_info(" max_channels %d", ServerConfig::max_channels); log_info(" max_subscribers_per_channel %d", ServerConfig::max_subscribers_per_channel); log_info(" channel_buffer_size %d", ServerConfig::channel_buffer_size); log_info(" channel_timeout %d", ServerConfig::channel_timeout); log_info(" polling_timeout %d", ServerConfig::polling_timeout); if (auth == "token"){ serv->auth = Server::AUTH_TOKEN; } } //write_pidfile(); log_info("chatserv started"); event_base_dispatch(evbase); //remove_pidfile(); event_free(timer_event); event_free(sigint_event); event_free(sigterm_event); evhttp_free(admin_http); evhttp_free(front_http); event_base_free(evbase); delete serv; delete conf; log_info("chatserv exit"); return 0; }
static void options(int *argc, char ***argv) { char *ipv4s = NULL; char *adv_ipv4s = NULL; char *ipv6s = NULL; char *adv_ipv6s = NULL; char *listenps = NULL; char *listenudps = NULL; char *listenngs = NULL; char *redisps = NULL; char *log_facility_s = NULL; int version = 0; GOptionEntry e[] = { { "version", 'v', 0, G_OPTION_ARG_NONE, &version, "Print build time and exit", NULL }, { "table", 't', 0, G_OPTION_ARG_INT, &table, "Kernel table to use", "INT" }, { "no-fallback",'F', 0, G_OPTION_ARG_NONE, &no_fallback, "Only start when kernel module is available", NULL }, { "ip", 'i', 0, G_OPTION_ARG_STRING, &ipv4s, "Local IPv4 address for RTP", "IP" }, { "advertised-ip", 'a', 0, G_OPTION_ARG_STRING, &adv_ipv4s, "IPv4 address to advertise", "IP" }, { "ip6", 'I', 0, G_OPTION_ARG_STRING, &ipv6s, "Local IPv6 address for RTP", "IP6" }, { "advertised-ip6",'A',0,G_OPTION_ARG_STRING, &adv_ipv6s, "IPv6 address to advertise", "IP6" }, { "listen-tcp", 'l', 0, G_OPTION_ARG_STRING, &listenps, "TCP port to listen on", "[IP:]PORT" }, { "listen-udp", 'u', 0, G_OPTION_ARG_STRING, &listenudps, "UDP port to listen on", "[IP46:]PORT" }, { "listen-ng", 'n', 0, G_OPTION_ARG_STRING, &listenngs, "UDP port to listen on, NG protocol", "[IP46:]PORT" }, { "tos", 'T', 0, G_OPTION_ARG_INT, &tos, "Default TOS value to set on streams", "INT" }, { "timeout", 'o', 0, G_OPTION_ARG_INT, &timeout, "RTP timeout", "SECS" }, { "silent-timeout",'s',0,G_OPTION_ARG_INT, &silent_timeout,"RTP timeout for muted", "SECS" }, { "pidfile", 'p', 0, G_OPTION_ARG_STRING, &pidfile, "Write PID to file", "FILE" }, { "foreground", 'f', 0, G_OPTION_ARG_NONE, &foreground, "Don't fork to background", NULL }, { "port-min", 'm', 0, G_OPTION_ARG_INT, &port_min, "Lowest port to use for RTP", "INT" }, { "port-max", 'M', 0, G_OPTION_ARG_INT, &port_max, "Highest port to use for RTP", "INT" }, { "redis", 'r', 0, G_OPTION_ARG_STRING, &redisps, "Connect to Redis database", "IP:PORT" }, { "redis-db", 'R', 0, G_OPTION_ARG_INT, &redis_db, "Which Redis DB to use", "INT" }, { "b2b-url", 'b', 0, G_OPTION_ARG_STRING, &b2b_url, "XMLRPC URL of B2B UA" , "STRING" }, { "log-level", 'L', 0, G_OPTION_ARG_INT, (void *)&log_level, "Mask log priorities above this level", "INT" }, { "log-facility", 0, 0, G_OPTION_ARG_STRING, &log_facility_s, "Syslog facility to use for logging", "daemon|local0|...|local7"}, { "log-stderr", 'E', 0, G_OPTION_ARG_NONE, &_log_stderr, "Log on stderr instead of syslog", NULL }, { "xmlrpc-format", 'x', 0, G_OPTION_ARG_INT, &xmlrpc_fmt, "XMLRPC timeout request format to use. 0: SEMS DI, 1: call-id only", "INT" }, { NULL, } }; GOptionContext *c; GError *er = NULL; c = g_option_context_new(" - next-generation media proxy"); g_option_context_add_main_entries(c, e, NULL); if (!g_option_context_parse(c, argc, argv, &er)) die("Bad command line: %s\n", er->message); if (version) die("%s\n", RTPENGINE_VERSION); if (!ipv4s) die("Missing option --ip\n"); if (!listenps && !listenudps && !listenngs) die("Missing option --listen-tcp, --listen-udp or --listen-ng\n"); ipv4 = inet_addr(ipv4s); if (ipv4 == -1) die("Invalid IPv4 address (--ip)\n"); if (adv_ipv4s) { adv_ipv4 = inet_addr(adv_ipv4s); if (adv_ipv4 == -1) die("Invalid IPv4 address (--advertised-ip)\n"); } if (ipv6s) { if (smart_pton(AF_INET6, ipv6s, &ipv6) != 1) die("Invalid IPv6 address (--ip6)\n"); } if (adv_ipv6s) { if (smart_pton(AF_INET6, adv_ipv6s, &adv_ipv6) != 1) die("Invalid IPv6 address (--advertised-ip6)\n"); } if (listenps) { if (parse_ip_port(&listenp, &listenport, listenps)) die("Invalid IP or port (--listen-tcp)\n"); } if (listenudps) { if (parse_ip6_port(&udp_listenp, &udp_listenport, listenudps)) die("Invalid IP or port (--listen-udp)\n"); } if (listenngs) { if (parse_ip6_port(&ng_listenp, &ng_listenport, listenngs)) die("Invalid IP or port (--listen-ng)\n"); } if (tos < 0 || tos > 255) die("Invalid TOS value\n"); if (timeout <= 0) timeout = 60; if (silent_timeout <= 0) silent_timeout = 3600; if (redisps) { if (parse_ip_port(&redis_ip, &redis_port, redisps) || !redis_ip) die("Invalid IP or port (--redis)\n"); if (redis_db < 0) die("Must specify Redis DB number (--redis-db) when using Redis\n"); } if (xmlrpc_fmt < 0 || xmlrpc_fmt > 1) { die("Invalid XMLRPC format\n"); } if ((log_level < LOG_EMERG) || (log_level > LOG_DEBUG)) die("Invalid log level (--log_level)\n"); setlogmask(LOG_UPTO(log_level)); if (log_facility_s) { if (!parse_log_facility(log_facility_s, &_log_facility)) { print_available_log_facilities(); die ("Invalid log facility '%s' (--log-facility)\n", log_facility_s); } } if (_log_stderr) { write_log = log_to_stderr; } }
void open_socket_inet(device_dev_t* if_device, options_t *options) { // TODO: not yet ready !!! ip_port_t srv_addr; // address to connect the probe to struct addrinfo* a_res; // address results struct addrinfo a_hint; // address results // parse address input string '<ip>:<port>' srv_addr = parse_ip_port(if_device->device_name); LOGGER_info("INET socket: '%s:%s'", srv_addr.ip, srv_addr.port); // TODO: IPv4 support IPv6 is added later memset( &a_hint, 0, sizeof(a_hint) ); a_hint.ai_family = options->ai_family; //AF_INET; // AF_INET6; //a_hint.ai_socktype = SOCK_STREAM; //SOCK_DGRAM; a_hint.ai_socktype = SOCK_DGRAM; //SOCK_STREAM; a_hint.ai_flags = AI_PASSIVE; // server socket //a_hint.ai_flags |= AI_ADDRCONFIG; //a_hint.ai_flags |= AI_V4MAPPED; a_hint.ai_protocol = IPPROTO_UDP; // udp protocol // get all availabe address for the given ip port //int rv = getaddrinfo(srv_addr.ip, srv_addr.port, &a_hint, &a_res); int rv = getaddrinfo(NULL, srv_addr.port, &a_hint, &a_res); if( 0 != rv ) { perror( "Socket error in getaddrinfo()" ); perror( gai_strerror(rv) ); exit(1); } // print the return addresses print_addrinfo( a_res ); if( NULL != a_res ) { //LOGGER_info( "connect" ); LOGGER_info( "bind" ); int socket = -1; // create a socket for the returned service //if_device->device_handle.socket = create_connect( a_res ); socket = create_bind( a_res ); if(-1 == socket ) { //perror("socket create_connect error"); perror("socket create_bind error"); exit(1); } if_device->device_handle.socket = socket; if_device->dh.fd = socket; if_device->dispatch = socket_dispatch_inet; // send 'hello' TODO: for test only //write( if_device->device_handle.socket, "HELLO!", 6 ); //write( if_device->device_handle.socket, "", 1 ); // TODO: some rework is still needed // register read handling to ev_handler LOGGER_debug("Register io handling for interface: %s", if_device->device_name); setNONBlocking(if_device); int fd = get_file_desc(if_device); LOGGER_debug("File Descriptor: %d", fd); /* storing a reference of packet device to be passed via watcher on a packet event so we know which device to read the packet from */ // TODO: implement an own packet watcher callback LOGGER_info("register event io: read inet socket interface (%s)", if_device->device_name); ev_watcher* watcher = event_register_io_r(EV_DEFAULT_ packet_watcher_cb, fd); watcher->data = (device_dev_t *) if_device; } // TODO: for UDP send initial message ? return; }