/* * init.c * * Cutlass initialization code - These functions run before the * cutlass threads separate. * * Copyright (c) 2004 Todd MacDermid * */ #include #include #include #include /* * cutlass_init creates and initializes a new cutlass_t structure. This * will only be called once during the program, at the very beginning, * before the threads separate. This is the data structure shared by * all threads. */ cutlass_t * cutlass_init() { // FIXME, should be app-configuarable const char* options_file = ".cut_options"; cutlass_t *new_handle; static int initialized = 0; int i; if(initialized) { fprintf(stderr, "WARNING: cutlass_init called twice!\n"); } new_handle = (cutlass_t *)calloc(1, sizeof(cutlass_t)); if(new_handle == NULL) { fprintf(stderr, "cutlass_init: calloc failed\n"); return(NULL); } cutlass_crypto_init(); FD_ZERO(&(new_handle->err_sockets)); FD_ZERO(&(new_handle->read_sockets)); FD_ZERO(&(new_handle->saved_sockets)); new_handle->max_fd = -1; new_handle->user_opts = load_options(options_file); if(new_handle->user_opts == NULL) new_handle->user_opts = new_options(); if(get_int_option(new_handle->user_opts, "port") == -1) set_int_option(new_handle->user_opts, "port", CUT_DEFAULT_PORT); new_handle->connections = hcreate(8); new_handle->directory = hcreate(8); new_handle->groups = hcreate(4); new_handle->running_state = 1; new_handle->action_lock = 1; new_handle->verbose = 0; new_handle->del_stack = NULL; new_handle->audio_handle = NULL; /* initialize some housekeeping settings */ new_handle->sleep_time.tv_sec = 1; new_handle->sleep_time.tv_nsec = 0; new_handle->audio_driver_type = CUTLASS_AUDRIVER_OSS; pthread_mutex_init(&(new_handle->action_mutex), NULL); pthread_mutex_init(&(new_handle->del_stack_mutex), NULL); pthread_mutex_init(&(new_handle->group_mutex), NULL); pthread_mutex_init(&(new_handle->htab_mutex), NULL); pthread_mutex_init(&(new_handle->directory_mutex), NULL); pthread_mutex_init(&(new_handle->fd_set_mutex), NULL); pthread_mutex_init(&(new_handle->handle_mutex), NULL); pthread_mutex_init(&(new_handle->audio_mutex), NULL); for(i = 0; i < CUT_ACTION_MAX; i++) { new_handle->action_handlers[i] = NULL; } initialized = 1; return(new_handle); } /* * cutlass_listen_init initializes the listening UDP socket that accepts * inbound traffic not part of an existing connection. This should * only be called once, at the beginning of the program, before the * threads have separated. * * If the system is behind NAT, or otherwise unreachable, this * function can be skipped. */ int cutlass_listen_init(cutlass_t *cut_handle) { struct sockaddr_in listen_addr; cut_handle->listen_socket = socket(AF_INET, SOCK_DGRAM, 0); if(cut_handle->listen_socket == -1) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_listen_init: Cannot create socket\n"); return(-1); } memset(&listen_addr, 0, sizeof(listen_addr)); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); listen_addr.sin_port = htons( (uint16_t)get_int_option(cut_handle->user_opts, "port") ); if((bind(cut_handle->listen_socket, (struct sockaddr *)&listen_addr, sizeof(listen_addr))) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_listen_init: Failed to bind port\n"); return(-1); } FD_SET(cut_handle->listen_socket, &(cut_handle->saved_sockets)); cut_handle->max_fd = cut_handle->listen_socket; return(0); } /* * cutlass_start kicks off all required subthreads and begins the * loops. */ int cutlass_start(cutlass_t *cut_handle) { if(cutlass_listen_init(cut_handle) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_start: cutlass_listen_init failed\n"); return(-1); } if(pthread_create(&(cut_handle->listen_tid), NULL, listener_thread, cut_handle) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_start: Could not create listening thread\n"); return(-1); } if(pthread_create(&(cut_handle->housekeeping_tid), NULL, housekeeping_thread, cut_handle) < 0) { cutlass_sysmsg(cut_handle, CUT_ERROR, "cutlass_start: Could not create housekeeping thread\n"); return(-1); } return(0); }