/** * \brief Verse server main function * \param argc The number of options and arguments. * \param argv The array of options and arguments. * \return Function returns 0, when it is ended successfully and non-zero * value, when there some error occurs. This function never reach the end, * because it is server. */ int main(int argc, char *argv[]) { VS_CTX vs_ctx; int opt; char *config_file=NULL; int debug_level_set = 0; void *res; /* Set up initial state */ vs_ctx.state = SERVER_STATE_CONF; /* Default debug prints of verse server */ v_init_print_log(VRS_PRINT_WARNING, stdout); /* When server received some arguments */ if(argc>1) { while( (opt = getopt(argc, argv, "c:hd:")) != -1) { switch(opt) { case 'c': config_file = strdup(optarg); break; case 'd': debug_level_set = vs_set_debug_level(optarg); break; case 'h': vs_print_help(argv[0]); exit(EXIT_SUCCESS); case ':': exit(EXIT_FAILURE); case '?': exit(EXIT_FAILURE); } } } /* Initialize default values first */ vs_init(&vs_ctx); /* Try to load Verse server configuration file */ vs_load_config_file(&vs_ctx, config_file); /* When debug level wasn't specified as option at command line, then use * configuration from file */ if(debug_level_set == 1) { uint8 log_level = v_log_level(); v_init_print_log(log_level, vs_ctx.log_file); } else { v_init_print_log(vs_ctx.print_log_level, vs_ctx.log_file); } /* Add superuser account to the list of users */ vs_add_superuser_account(&vs_ctx); /* Add fake account for other users to the list of users*/ vs_add_other_users_account(&vs_ctx); /* Load user accounts and save them in the linked list of verse server * context */ switch (vs_ctx.auth_type) { case AUTH_METHOD_CSV_FILE: if(vs_load_user_accounts(&vs_ctx) != 1) { v_print_log(VRS_PRINT_ERROR, "vs_load_user_accounts(): failed\n"); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } break; case AUTH_METHOD_PAM: /* TODO: read list of supported usernames and their uids somehow */ exit(EXIT_FAILURE); case AUTH_METHOD_LDAP: /* TODO: not implemented yet */ exit(EXIT_FAILURE); default: /* Not supported method */ v_print_log(VRS_PRINT_ERROR, "unsupported auth method: %d\n", vs_ctx.auth_type); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Initialize data mutex */ if( pthread_mutex_init(&vs_ctx.data.mutex, NULL) != 0) { v_print_log(VRS_PRINT_ERROR, "pthread_mutex_init(): failed\n"); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Create basic node structure of node tree */ if(vs_nodes_init(&vs_ctx) == -1) { v_print_log(VRS_PRINT_ERROR, "vs_nodes_init(): failed\n"); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } if(vs_ctx.stream_protocol == TCP) { /* Initialize Verse server context */ if(vs_init_stream_ctx(&vs_ctx) == -1) { v_print_log(VRS_PRINT_ERROR, "vs_init_stream_ctx(): failed\n"); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } } else { vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } if(vs_ctx.flag & SERVER_DEBUG_MODE) { /* Set up signal handlers (only for debug mode, real server should ignore most of signals) */ if(vs_config_signal_handling() == -1 ) { vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } } else { #if 0 /* Make from verse server real verse application: * - detach from standard file descriptors, terminals, PPID process etc. */ if(vs_init_server(&vs_ctx) == -1) { vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } #endif } /* Initialize data semaphore */ if( (vs_ctx.data.sem = sem_open(DATA_SEMAPHORE_NAME, O_CREAT, 0644, 1)) == SEM_FAILED) { v_print_log(VRS_PRINT_ERROR, "sem_init(): %s\n", strerror(errno)); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Try to create new data thread */ if(pthread_create(&vs_ctx.data_thread, NULL, vs_data_loop, (void*)&vs_ctx) != 0) { v_print_log(VRS_PRINT_ERROR, "pthread_create(): %s\n", strerror(errno)); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Try to create cli thread */ if(pthread_create(&vs_ctx.cli_thread, NULL, vs_server_cli, (void*)&vs_ctx) != 0) { v_print_log(VRS_PRINT_ERROR, "pthread_create(): %s\n", strerror(errno)); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Set up pointer to local server CTX -> server server could be terminated * with signal now. */ local_vs_ctx = &vs_ctx; vs_ctx.state = SERVER_STATE_READY; if(vs_ctx.stream_protocol == TCP) { if(vs_main_listen_loop(&vs_ctx) == -1) { v_print_log(VRS_PRINT_ERROR, "vs_main_listen_loop(): failed\n"); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } } else { v_print_log(VRS_PRINT_ERROR, "unsupported stream protocol: %d\n", vs_ctx.stream_protocol); vs_destroy_ctx(&vs_ctx); exit(EXIT_FAILURE); } /* Free Verse server context */ vs_destroy_ctx(&vs_ctx); /* Join cli thread */ if(pthread_join(vs_ctx.cli_thread, &res) != 0) { v_print_log(VRS_PRINT_ERROR, "pthread_join(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } else { if(res != PTHREAD_CANCELED && res != NULL) free(res); } /* TODO: replace following ifdef */ #ifndef __APPLE__ /* Join data thread */ if(pthread_join(vs_ctx.data_thread, &res) != 0) { v_print_log(VRS_PRINT_ERROR, "pthread_join(): %s\n", strerror(errno)); exit(EXIT_FAILURE); } else { if(res != PTHREAD_CANCELED && res != NULL) free(res); } /* Try to close named semaphore s*/ if(sem_close(vs_ctx.data.sem) == -1) { v_print_log(VRS_PRINT_ERROR, "sem_close(): %s\n", strerror(errno)); } #endif /* Try to unlink named semphore */ if(vs_ctx.data.sem != NULL && sem_unlink(DATA_SEMAPHORE_NAME) == -1) { v_print_log(VRS_PRINT_ERROR, "sem_unlink(): %s\n", strerror(errno)); } return EXIT_SUCCESS; }
int main (int argc, char *argv[]) { int opt; int quiet = 0; /* Initialize the app_data structure */ vc_init_data(&app_data); /* Parse command line */ while ((opt = getopt(argc, argv, "dqs:h")) != -1) { switch (opt) { case 'd': /* Daemonize - do not open /dev/stdin */ app_data.daemonize = 1; break; case 'q': /* Quiet - do not print startup messages */ quiet = 1; break; case 's': /* Server IP address */ strcpy(app_data.cfg.server_ip_addr, optarg); break; case 'h': default: /* '?' */ vs_print_help(); return 0; } } if(!strlen(app_data.cfg.server_ip_addr)){ vs_print_help(); return 0; } if(!quiet){ printf("glivec - Gstreamer Live Example Client \n" "(C) John Weber, Avnet Electronics Marketing\n"); } /* Initialize configuration data */ app_data.cfg.rtp_recv_port = DEFAULT_RX_RTP_PORT; app_data.cfg.rtcp_send_port = DEFAULT_TX_RTCP_PORT; app_data.cfg.rtcp_recv_port = DEFAULT_RX_RTCP_PORT; app_data.cfg.server_port = DEFAULT_SERVER_PORT; printf( "Server IP address: %s\n" "Server port: %d\n" "Sending RTP data on port: %d\n" "Sending RTCP data on port: %d\n" "Expecting RTCP data on port: %d\n", app_data.cfg.server_ip_addr, app_data.cfg.server_port, app_data.cfg.rtp_recv_port, app_data.cfg.rtcp_send_port, app_data.cfg.rtcp_recv_port); /* Setup the file descriptors for polling, starting with /dev/stdin */ if(!app_data.daemonize){ app_data.fds[FD_INDEX_STDIN].fd = open("/dev/stdin", O_RDONLY); if( app_data.fds[FD_INDEX_STDIN].fd == -1) { printf("Error opening /dev/stdin for reading\n"); return -1; } app_data.fds[FD_INDEX_STDIN].events = POLLIN; } else { printf("glivec starting as background task.\n"); } if(link_init_as_client((char*)app_data.cfg.server_ip_addr, app_data.cfg.server_port) < 0){ debug_printf("%s: Failed to init link as client\n", __func__); return -1; } /* Initialization */ gst_init (&argc, &argv); vc_sigint_setup(); /* Main Loop */ printf ("Running...\n"); vc_mainloop(&app_data); /* Out of the main loop, clean up nicely */ printf ("Returned, stopping playback\n"); return vc_cleanup(&app_data); }