/* subscribe to the (configured) multicast channel */ static int subscribe( int* sockfd, struct in_addr* mcast_inaddr ) { struct sockaddr_in sa; const char* ipaddr = g_recopt.rec_channel; size_t rcvbuf_len = 0; int rc = 0; assert( sockfd && mcast_inaddr ); if( 1 != inet_aton( ipaddr, &sa.sin_addr ) ) { mperror( g_flog, errno, "%s: Invalid subscription [%s:%d]: inet_aton", __func__, ipaddr, g_recopt.rec_port ); return -1; } sa.sin_family = AF_INET; sa.sin_port = htons( (uint16_t)g_recopt.rec_port ); if( 1 != inet_aton( g_recopt.mcast_addr, mcast_inaddr ) ) { mperror( g_flog, errno, "%s: Invalid multicast interface: [%s]: inet_aton", __func__, g_recopt.mcast_addr ); return -1; } rc = calc_buf_settings( NULL, &rcvbuf_len ); if (0 != rc) return rc; return setup_mcast_listener( &sa, mcast_inaddr, sockfd, (g_recopt.nosync_sbuf ? 0 : rcvbuf_len) ); }
/* process command to relay udp traffic * */ static int udp_relay( int sockfd, const char* param, size_t plen, const struct in_addr* mifaddr, struct server_ctx* ctx ) { char mcast_addr[ IPADDR_STR_SIZE ]; struct sockaddr_in addr; uint16_t port; pid_t new_pid; int rc = 0, flags; int msockfd = -1, sfilefd = -1, dfilefd = -1, srcfd = -1; char dfile_name[ MAXPATHLEN ]; size_t rcvbuf_len = 0; assert( (sockfd > 0) && param && plen && ctx ); TRACE( (void)tmfprintf( g_flog, "udp_relay : new_socket=[%d] param=[%s]\n", sockfd, param) ); do { rc = parse_udprelay( param, plen, mcast_addr, IPADDR_STR_SIZE, &port ); if( 0 != rc ) { (void) tmfprintf( g_flog, "Error [%d] parsing parameters [%s]\n", rc, param ); break; } if( 1 != inet_aton(mcast_addr, &addr.sin_addr) ) { (void) tmfprintf( g_flog, "Invalid address: [%s]\n", mcast_addr ); rc = ERR_INTERNAL; break; } addr.sin_family = AF_INET; addr.sin_port = htons( (short)port ); } while(0); if( 0 != rc ) { (void) send_http_response( sockfd, 500, "Service error" ); return rc; } /* start the (new) process to relay traffic */ if( 0 != (new_pid = fork()) ) { rc = add_client( ctx, new_pid, mcast_addr, port, sockfd ); return rc; /* parent returns */ } /* child process: */ TRACE( (void)tmfprintf( g_flog, "Client process=[%d] started " "for socket=[%d]\n", getpid(), sockfd) ); (void) get_pidstr( PID_RESET, "c" ); (void)close( ctx->lsockfd ); /* close the reading end of the comm. pipe */ (void)close( ctx->cpipe[0] ); ctx->cpipe[0] = -1; do { /* make write end of pipe non-blocking (we don't want to * block on pipe write while relaying traffic) */ if( -1 == (flags = fcntl( ctx->cpipe[1], F_GETFL )) || -1 == fcntl( ctx->cpipe[1], F_SETFL, flags | O_NONBLOCK ) ) { mperror( g_flog, errno, "%s: fcntl", __func__ ); rc = -1; break; } if( NULL != g_uopt.dstfile ) { (void) snprintf( dfile_name, MAXPATHLEN - 1, "%s.%d", g_uopt.dstfile, getpid() ); dfilefd = creat( dfile_name, S_IRUSR | S_IWUSR | S_IRGRP ); if( -1 == dfilefd ) { mperror( g_flog, errno, "%s: g_uopt.dstfile open", __func__ ); rc = -1; break; } TRACE( (void)tmfprintf( g_flog, "Dest file [%s] opened as fd=[%d]\n", dfile_name, dfilefd ) ); } else dfilefd = -1; if( NULL != g_uopt.srcfile ) { sfilefd = open( g_uopt.srcfile, O_RDONLY | O_NOCTTY ); if( -1 == sfilefd ) { mperror( g_flog, errno, "%s: g_uopt.srcfile open", __func__ ); rc = -1; } else { TRACE( (void) tmfprintf( g_flog, "Source file [%s] opened\n", g_uopt.srcfile ) ); srcfd = sfilefd; } } else { rc = calc_buf_settings( NULL, &rcvbuf_len ); if (0 == rc ) { rc = setup_mcast_listener( &addr, mifaddr, &msockfd, (g_uopt.nosync_sbuf ? 0 : rcvbuf_len) ); srcfd = msockfd; } } if( 0 != rc ) break; rc = relay_traffic( srcfd, sockfd, ctx, dfilefd, mifaddr ); if( 0 != rc ) break; } while(0); if( msockfd > 0 ) { close_mcast_listener( msockfd, mifaddr ); } if( sfilefd > 0 ) { (void) close( sfilefd ); TRACE( (void) tmfprintf( g_flog, "Source file [%s] closed\n", g_uopt.srcfile ) ); } if( dfilefd > 0 ) { (void) close( dfilefd ); TRACE( (void) tmfprintf( g_flog, "Dest file [%s] closed\n", dfile_name ) ); } if( 0 != rc ) { (void) send_http_response( sockfd, 500, "Service error" ); } (void) close( sockfd ); free_server_ctx( ctx ); closelog(); TRACE( (void)tmfprintf( g_flog, "Child process=[%d] exits with rc=[%d]\n", getpid(), rc) ); if( g_flog && (stderr != g_flog) ) { (void) fclose(g_flog); } free_uopt( &g_uopt ); rc = ( 0 != rc ) ? ERR_INTERNAL : rc; exit(rc); /* child exits */ return rc; }