/* process command within a request */ static int process_command( int new_sockfd, struct server_ctx* ctx, const char* param, size_t plen ) { int rc = 0; const int STAT_OPTIONS = 0; const int RESTART_OPTIONS = MSO_SKIP_CLIENTS | MSO_RESTART; assert( (new_sockfd > 0) && ctx && param ); if( 0 == strncmp( ctx->cmd, CMD_UDP, sizeof(ctx->cmd) ) || 0 == strncmp( ctx->cmd, CMD_RTP, sizeof(ctx->cmd) ) ) { if( ctx->clfree ) { rc = udp_relay( new_sockfd, param, plen, &(ctx->mcast_inaddr), ctx ); } else { send_http_response( new_sockfd, 401, "Bad request" ); (void)tmfprintf( g_flog, "Client limit [%d] has been reached.\n", ctx->clmax); } } else if( 0 == strncmp( ctx->cmd, CMD_STATUS, sizeof(ctx->cmd) ) ) { rc = report_status( new_sockfd, ctx, STAT_OPTIONS ); } else if( 0 == strncmp( ctx->cmd, CMD_RESTART, sizeof(ctx->cmd) ) ) { (void) report_status( new_sockfd, ctx, RESTART_OPTIONS ); terminate_all_clients( ctx ); wait_all( ctx ); } else { TRACE( (void)tmfprintf( g_flog, "Unrecognized command [%s]" " - ignoring.\n", ctx->cmd) ); send_http_response( new_sockfd, 401, "Unrecognized request" ); } return rc; }
int serv_loop(void) { int cs, ss = 0; struct sockaddr_storage cl, udp; fd_set readable; int i, n, len; char cl_addr[NI_MAXHOST]; char cl_name[NI_MAXHOST]; int error; pid_t pid; #ifdef USE_THREAD if (threading) { blocksignal(SIGHUP); blocksignal(SIGINT); blocksignal(SIGUSR1); } #endif for (;;) { readable = allsock; MUTEX_LOCK(mutex_select); n = select(maxsock+1, &readable, 0, 0, 0); if (n <= 0) { if (n < 0 && errno != EINTR) msg_out(warn, "select: %m"); MUTEX_UNLOCK(mutex_select); continue; } #ifdef USE_THREAD if ( ! threading ) { #endif /* handle any queued signal flags */ if (FD_ISSET(sig_queue[0], &readable)) { if (ioctl(sig_queue[0], FIONREAD, &i) != 0) { msg_out(crit, "ioctl: %m"); exit(-1); } while (--i >= 0) { char c; if (read(sig_queue[0], &c, 1) != 1) { msg_out(crit, "read: %m"); exit(-1); } switch(c) { case 'H': /* sighup */ reload(); break; case 'C': /* sigchld */ reapchild(); break; case 'T': /* sigterm */ cleanup(); break; default: break; } } } #ifdef USE_THREAD } #endif for ( i = 0; i < serv_sock_ind; i++ ) { if (FD_ISSET(serv_sock[i], &readable)) { n--; break; } } if ( n < 0 || i >= serv_sock_ind ) { MUTEX_UNLOCK(mutex_select); continue; } len = sizeof(struct sockaddr_storage); cs = accept(serv_sock[i], (struct sockaddr *)&cl, &len); if (cs < 0) { if (errno == EINTR #ifdef SOLARIS || errno == EPROTO #endif || errno == EWOULDBLOCK || errno == ECONNABORTED) { ; /* ignore */ } else /* real accept error */ msg_out(warn, "accept: %m"); MUTEX_UNLOCK(mutex_select); continue; } MUTEX_UNLOCK(mutex_select); #ifdef USE_THREAD if ( !threading ) { #endif if (max_child > 0 && cur_child >= max_child) { msg_out(warn, "child: cur %d; exeedeing max(%d)\n", cur_child, max_child); close(cs); continue; } #ifdef USE_THREAD } #endif error = getnameinfo((struct sockaddr *)&cl, len, cl_addr, sizeof(cl_addr), NULL, 0, NI_NUMERICHOST); if (resolv_client) { error = getnameinfo((struct sockaddr *)&cl, len, cl_name, sizeof(cl_name), NULL, 0, 0); msg_out(norm, "%s[%s] connected\n", cl_name, cl_addr); } else { msg_out(norm, "%s connected\n", cl_addr); strncpy(cl_name, cl_addr, sizeof(cl_name)); } i = validate_access(cl_addr, cl_name); if (i < 1) { /* access denied */ close(cs); continue; } set_blocking(cs); #ifdef USE_THREAD if (!threading ) { #endif blocksignal(SIGHUP); blocksignal(SIGCHLD); pid = fork(); switch (pid) { case -1: /* fork child failed */ break; case 0: /* i am child */ for ( i = 0; i < serv_sock_ind; i++ ) close(serv_sock[i]); setsignal(SIGCHLD, SIG_DFL); setsignal(SIGHUP, SIG_DFL); releasesignal(SIGCHLD); releasesignal(SIGHUP); #ifdef IPHONE_OS iphone_app_check_connection(); #endif bzero(&udp, sizeof(struct sockaddr_storage)); udp.ss_family = AF_UNSPEC; ss = proto_socks(cs, &udp); if ( ss == -1 ) { close(cs); /* may already be closed */ exit(1); } if (udp.ss_family == AF_UNSPEC) { errno = 0; perror("start udp_relay()\n"); udp_relay(cs, ss, &udp); } else { errno = 0; perror("start relay()\n"); relay(cs, ss); } exit(0); default: /* may be parent */ proclist_add(pid); break; } close(cs); releasesignal(SIGHUP); releasesignal(SIGCHLD); #ifdef USE_THREAD } else { #ifdef IPHONE_OS iphone_app_check_connection(); #endif bzero(&udp, sizeof(struct sockaddr_storage)); udp.ss_family = AF_UNSPEC; ss = proto_socks(cs, &udp); if ( ss == -1 ) { close(cs); /* may already be closed */ continue; } if (udp.ss_family != AF_UNSPEC) { errno = 0; udp_relay(cs, ss, &udp); } else { errno = 0; relay(cs, ss); } } #endif } }
int service_udprelay(Connection *Conn) { udp_relay(Conn,FromC); return 0; }