📄 main.c
字号:
/* * Copyright (c) 2004-2006 Maxim Sobolev <sobomax@FreeBSD.org> * Copyright (c) 2006-2007 Sippy Software, Inc., http://www.sippysoft.com * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id: main.c,v 1.71 2008/04/03 20:51:45 sobomax Exp $ * */#include <sys/types.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <sys/resource.h>#include <sys/un.h>#include <sys/uio.h>#include <ctype.h>#include <sys/select.h>#include <sys/stat.h>#include <assert.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <netdb.h>#include <poll.h>#include <sched.h>#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <string.h>#include <strings.h>#include <unistd.h>#include "rtp.h"#include "rtp_resizer.h"#include "rtp_server.h"#include "rtpp_defines.h"#include "rtpp_command.h"#include "rtpp_log.h"#include "rtpp_record.h"#include "rtpp_session.h"#include "rtpp_util.h"static const char *cmd_sock = CMD_SOCK;static const char *pid_file = PID_FILE;static rtpp_log_t glog;static void setbindhost(struct sockaddr *, int, const char *, const char *);static void usage(void);static void send_packet(struct cfg *, struct rtpp_session *, int, struct rtp_packet *);static voidsetbindhost(struct sockaddr *ia, int pf, const char *bindhost, const char *servname){ int n; /* * If user specified * then change it to NULL, * that will make getaddrinfo to return addr_any socket */ if (bindhost && (strcmp(bindhost, "*") == 0)) bindhost = NULL; if ((n = resolve(ia, pf, bindhost, servname, AI_PASSIVE)) != 0) errx(1, "setbindhost: %s", gai_strerror(n));}static voidusage(void){ fprintf(stderr, "usage: rtpproxy [-2fvF] [-l addr1[/addr2]] " "[-6 addr1[/addr2]] [-s path]\n\t[-t tos] [-r rdir [-S sdir]] [-T ttl] " "[-L nfiles] [-m port_min]\n\t[-M port_max] [-u uname[:gname]]\n"); exit(1);}static voidfatsignal(int sig){ rtpp_log_write(RTPP_LOG_INFO, glog, "got signal %d", sig); exit(0);}static voidehandler(void){ unlink(cmd_sock); unlink(pid_file); rtpp_log_write(RTPP_LOG_INFO, glog, "rtpproxy ended"); rtpp_log_close(glog);}static void init_config(struct cfg *cf, int argc, char **argv){ int ch, i; char *bh[2], *bh6[2], *cp; bh[0] = bh[1] = bh6[0] = bh6[1] = NULL; cf->port_min = PORT_MIN; cf->port_max = PORT_MAX; cf->max_ttl = SESSION_TIMEOUT; cf->tos = TOS; cf->rrtcp = 1; if (getrlimit(RLIMIT_NOFILE, &(cf->nofile_limit)) != 0) err(1, "getrlimit"); while ((ch = getopt(argc, argv, "vf2Rl:6:s:S:t:r:p:T:L:m:M:u:F")) != -1) switch (ch) { case 'f': cf->nodaemon = 1; break; case 'l': bh[0] = optarg; bh[1] = strchr(bh[0], '/'); if (bh[1] != NULL) { *bh[1] = '\0'; bh[1]++; cf->bmode = 1; } break; case '6': bh6[0] = optarg; bh6[1] = strchr(bh6[0], '/'); if (bh6[1] != NULL) { *bh6[1] = '\0'; bh6[1]++; cf->bmode = 1; } break; case 's': if (strncmp("udp:", optarg, 4) == 0) { cf->umode = 1; optarg += 4; } else if (strncmp("udp6:", optarg, 5) == 0) { cf->umode = 6; optarg += 5; } else if (strncmp("unix:", optarg, 5) == 0) { cf->umode = 0; optarg += 5; } cmd_sock = optarg; break; case 't': cf->tos = atoi(optarg); break; case '2': cf->dmode = 1; break; case 'v': printf("Basic version: %d\n", CPROTOVER); for (i = 1; proto_caps[i].pc_id != NULL; ++i) { printf("Extension %s: %s\n", proto_caps[i].pc_id, proto_caps[i].pc_description); } exit(0); break; case 'r': cf->rdir = optarg; break; case 'S': cf->sdir = optarg; break; case 'R': cf->rrtcp = 0; break; case 'p': pid_file = optarg; break; case 'T': cf->max_ttl = atoi(optarg); break; case 'L': cf->nofile_limit.rlim_cur = cf->nofile_limit.rlim_max = atoi(optarg); if (setrlimit(RLIMIT_NOFILE, &(cf->nofile_limit)) != 0) err(1, "setrlimit"); if (getrlimit(RLIMIT_NOFILE, &(cf->nofile_limit)) != 0) err(1, "getrlimit"); if (cf->nofile_limit.rlim_max < atoi(optarg)) warnx("limit allocated by setrlimit (%d) is less than " "requested (%d)", (int) cf->nofile_limit.rlim_max, atoi(optarg)); break; case 'm': cf->port_min = atoi(optarg); break; case 'M': cf->port_max = atoi(optarg); break; case 'u': cf->run_uname = optarg; cp = strchr(optarg, ':'); if (cp != NULL) { if (cp == optarg) cf->run_uname = NULL; cp[0] = '\0'; cp++; } cf->run_gname = cp; break; case 'F': cf->no_check = 1; break; case '?': default: usage(); } if (cf->rdir == NULL && cf->sdir != NULL) errx(1, "-S switch requires -r switch"); if (cf->no_check == 0 && getuid() == 0 && cf->run_uname == NULL) { if (cf->umode != 0) { errx(1, "running this program as superuser in a remote control " "mode is strongly not recommended, as it poses serious security " "threat to your system. Use -u option to run as an unprivileged " "user or -F is you want to run as a superuser anyway."); } else { warnx("WARNING!!! Running this program as superuser is strongly " "not recommended, as it may pose serious security threat to " "your system. Use -u option to run as an unprivileged user " "or -F to surpress this warning."); } } if (cf->port_min <= 0 || cf->port_min > 65535) errx(1, "invalid value of the port_min argument, " "not in the range 1-65535"); if (cf->port_max <= 0 || cf->port_max > 65535) errx(1, "invalid value of the port_max argument, " "not in the range 1-65535"); if (cf->port_min > cf->port_max) errx(1, "port_min should be less than port_max"); /* make sure that port_min and port_max are even */ if ((cf->port_min % 2) != 0) cf->port_min++; if ((cf->port_max % 2) != 0) cf->port_max--; cf->nextport[0] = cf->nextport[1] = cf->port_min; cf->sessions = malloc((sizeof cf->sessions[0]) * (((cf->port_max - cf->port_min + 1) * 2) + 1)); cf->rtp_servers = malloc((sizeof cf->rtp_servers[0]) * (((cf->port_max - cf->port_min + 1) * 2) + 1)); cf->pfds = malloc((sizeof cf->pfds[0]) * (((cf->port_max - cf->port_min + 1) * 2) + 1)); if (bh[0] == NULL && bh[1] == NULL && bh6[0] == NULL && bh6[1] == NULL) { if (cf->umode != 0) errx(1, "explicit binding address has to be specified in UDP " "command mode"); bh[0] = "*"; } for (i = 0; i < 2; i++) { if (bh[i] != NULL && *bh[i] == '\0') bh[i] = NULL; if (bh6[i] != NULL && *bh6[i] == '\0') bh6[i] = NULL; } i = ((bh[0] == NULL) ? 0 : 1) + ((bh[1] == NULL) ? 0 : 1) + ((bh6[0] == NULL) ? 0 : 1) + ((bh6[1] == NULL) ? 0 : 1); if (cf->bmode != 0) { if (bh[0] != NULL && bh6[0] != NULL) errx(1, "either IPv4 or IPv6 should be configured for external " "interface in bridging mode, not both"); if (bh[1] != NULL && bh6[1] != NULL) errx(1, "either IPv4 or IPv6 should be configured for internal " "interface in bridging mode, not both"); if (i != 2) errx(1, "incomplete configuration of the bridging mode - exactly " "2 listen addresses required, %d provided", i); } else if (i != 1) { errx(1, "exactly 1 listen addresses required, %d provided", i); } for (i = 0; i < 2; i++) { cf->bindaddr[i] = NULL; if (bh[i] != NULL) { cf->bindaddr[i] = malloc(sizeof(struct sockaddr_storage)); setbindhost(cf->bindaddr[i], AF_INET, bh[i], SERVICE); continue; } if (bh6[i] != NULL) { cf->bindaddr[i] = malloc(sizeof(struct sockaddr_storage)); setbindhost(cf->bindaddr[i], AF_INET6, bh6[i], SERVICE); continue; } } if (cf->bindaddr[0] == NULL) { cf->bindaddr[0] = cf->bindaddr[1]; cf->bindaddr[1] = NULL; }}static intinit_controlfd(struct cfg *cf){ struct sockaddr_un ifsun; struct sockaddr_storage ifsin; char *cp; int i, controlfd, flags; if (cf->umode == 0) { unlink(cmd_sock); memset(&ifsun, '\0', sizeof ifsun);#if !defined(__linux__) && !defined(__solaris__) ifsun.sun_len = strlen(cmd_sock);#endif ifsun.sun_family = AF_LOCAL; strcpy(ifsun.sun_path, cmd_sock); controlfd = socket(PF_LOCAL, SOCK_STREAM, 0); if (controlfd == -1) err(1, "can't create socket"); setsockopt(controlfd, SOL_SOCKET, SO_REUSEADDR, &controlfd, sizeof controlfd); if (bind(controlfd, sstosa(&ifsun), sizeof ifsun) < 0) err(1, "can't bind to a socket"); if (listen(controlfd, 32) != 0) err(1, "can't listen on a socket"); } else { cp = strrchr(cmd_sock, ':'); if (cp != NULL) { *cp = '\0'; cp++; } if (cp == NULL || *cp == '\0') cp = CPORT; i = (cf->umode == 6) ? AF_INET6 : AF_INET; setbindhost(sstosa(&ifsin), i, cmd_sock, cp); controlfd = socket(i, SOCK_DGRAM, 0); if (controlfd == -1) err(1, "can't create socket"); if (bind(controlfd, sstosa(&ifsin), SS_LEN(&ifsin)) < 0) err(1, "can't bind to a socket"); } flags = fcntl(controlfd, F_GETFL); fcntl(controlfd, F_SETFL, flags | O_NONBLOCK);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -