#include #include #include #include #include #include #include #include #include #include #include "server.h" #include "server_data_processing.h" #include "server_game_process.h" #include "card_stack.h" #include "card_queue.h" void handler(int s) { if(s == SIGPIPE) signal(SIGPIPE, handler); } static void init_session(struct session *new_session, struct sockaddr_in *from, int fd, int player_position) { new_session->fd = fd; new_session->record = 1; new_session->state = display_only_table; new_session->player_position = player_position; new_session->tm = none; new_session->defense_lost = 0; init_stack(&new_session->deck); } static int accept_client(struct server *serv) { int fd, i; struct sockaddr_in addr; struct session *new_session; socklen_t len = sizeof(addr); fd = accept(serv->listen_socket, (struct sockaddr*) &addr, &len); if(fd == -1) return -1; if(fd >= serv->max_sess_arr_size) { int newlen = serv->max_sess_arr_size; while(fd >= newlen) newlen += init_sess_arr_size; serv->sess_arr = realloc(serv->sess_arr, newlen * sizeof(struct session*)); for(i = serv->max_sess_arr_size; i < newlen; i++) serv->sess_arr[i] = NULL; serv->max_sess_arr_size = newlen; } new_session = malloc(sizeof(struct session)); serv->sess_arr[fd] = new_session; ++serv->connected_players_counter; init_session(new_session, &addr, fd, serv->connected_players_counter); return 1; } static void close_connection(struct server *serv) { int i; for(i = 0; i < serv->max_sess_arr_size; ++i) { if(!serv->sess_arr[i]) continue; serv->sess_arr[i]->state = disconnect; if(serv->sess_arr[i]->fd != -1) { send_disconnect_status(serv->sess_arr[i]->fd); close(serv->sess_arr[i]->fd); } clear_stack(&serv->sess_arr[i]->deck); free(serv->sess_arr[i]); serv->sess_arr[i] = NULL; } serv->connected_players_counter = 0; if(serv->cc.number_arr) { free(serv->cc.number_arr); serv->cc.number_arr = NULL; } if(serv->shuffled_deck) { free(serv->shuffled_deck); serv->shuffled_deck = NULL; } if(serv->turn_queue) { free(serv->turn_queue); serv->turn_queue = NULL; } if(serv->gi) { free(serv->gi); serv->gi = NULL; } clear_queue(&serv->cq); } static int check_playable_player_number(struct server *serv) { return serv->connected_players_counter >= 2 && serv->connected_players_counter < 8; } static int is_max_playable_player_number(struct server *serv) { return serv->connected_players_counter == 8; } static void init_new_game(struct server *serv) { int i,j, lowest_trump, current_trump, who_attack; /* idx in serv->turn_queue */ who_attack = -1; lowest_trump = 0; serv->shuffled_deck_size = max_shuffled_deck_size; serv->shuffled_deck = get_shuffled_deck(); serv->trump_card = extract_trump_card(serv->shuffled_deck, &serv->shuffled_deck_size); serv->trump_suit = serv->trump_card + strlen(serv->trump_card) - 1; serv->turn_queue = malloc(sizeof(struct session*) * serv->connected_players_counter); serv->turn_queue_size = serv->connected_players_counter; /* number of cards each player holds */ serv->cc.number_arr_idx = serv->connected_players_counter - 1; serv->cc.number_arr = malloc(sizeof(int) * serv->connected_players_counter); serv->position_whose_turn = 0; serv->cot.card_arr_idx = -1; /* * dealing cards to all and * determining who moves first */ for(i = 0, j = 0; i < serv->max_sess_arr_size; ++i) { if(serv->sess_arr[i]) { serv->turn_queue[j] = serv->sess_arr[i]; deal_first_cards(serv->shuffled_deck, &serv->shuffled_deck_size, &serv->sess_arr[i]->deck); current_trump = find_lowest_trump(serv->sess_arr[i]->deck, serv->trump_suit); if(current_trump) if(!lowest_trump || current_trump < lowest_trump) { lowest_trump = current_trump; who_attack = j; } ++j; } } /* random selection of the first player */ if(who_attack == -1) { who_attack = 0 + (int)((double)serv->connected_players_counter*rand()/ (RAND_MAX + 1.0)); } for(i = 0; i < who_attack; ++i) shift_turn_queue_by_one(serv->turn_queue, serv->connected_players_counter); update_card_quantity_arr(serv->turn_queue, serv->cc); init_queue(&serv->cq); serv->gi = get_new_game_info(serv->connected_players_counter, serv->cc.number_arr, serv->shuffled_deck_size, serv->trump_card, serv->position_whose_turn, &serv->cq, &serv->cot); serv->durak_position = 0; serv->tossing_limit = 0; } static void set_whose_turn(struct server *serv, enum client_game_states state) { switch(state) { case attack: serv->position_whose_turn = serv->turn_queue[0]->player_position; break; case defense: serv->position_whose_turn = serv->turn_queue[1]->player_position; break; case tossing: default: serv->position_whose_turn = 0; } } /* * state set during game play */ static void set_state_for_client(struct server *serv, enum client_game_states state) { int i; switch(state) { case attack: serv->turn_queue[0]->state = attack; break; case defense: serv->turn_queue[1]->state = defense; break; case tossing: serv->turn_queue[1]->state = tossing_expectation; default: {} } for(i = 0; i < serv->turn_queue_size; ++i) { if(serv->turn_queue[i]->state == spectator) continue; switch(state) { case attack: if(serv->turn_queue[i] && serv->turn_queue[i] != serv->turn_queue[0]) serv->turn_queue[i]->state = attack_expectation; break; case defense: if(serv->turn_queue[i] && serv->turn_queue[i] != serv->turn_queue[1]) serv->turn_queue[i]->state = defense_expectation; break; case tossing: if(serv->turn_queue[i] && serv->turn_queue[i] != serv->turn_queue[1]) { if(check_player_can_toss_card(serv->turn_queue[i]->deck, &serv->cot)) { serv->turn_queue[i]->tm = answer_wait; serv->turn_queue[i]->state = tossing; } else { serv->turn_queue[i]->tm = none; serv->turn_queue[i]->state = tossing_expectation; } } break; case display_only_table: if(serv->turn_queue[i]) serv->turn_queue[i]->state = display_only_table; break; default: {} } } /* end of game */ if(state == result) for(i = 0; i < serv->max_sess_arr_size; ++i) if(serv->sess_arr[i]) serv->sess_arr[i]->state = result; } static void set_record_status_for_all(struct server *serv) { int i; for(i = 0; i < serv->max_sess_arr_size; ++i) if(serv->sess_arr[i]) serv->sess_arr[i]->record = 1; } #if 0 static int print_table_condition(struct server *serv) { return !check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, serv->trump_suit) && !check_someone_can_toss_card(serv->turn_queue, serv->connected_players_counter, &serv->cq, &serv->cot); } #endif static int defense_condition(struct server *serv) { return check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, serv->trump_suit); } static void define_phase_after_attack(struct server *serv) { if(defense_condition(serv)) { set_state_for_client(serv, defense); set_whose_turn(serv, defense); put_one_card_from_queue_to_table(&serv->cot, &serv->cq); serv->state = defense_phase_out; /* defender can't keep defense */ } else { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(check_someone_can_toss_card(serv->turn_queue, serv->connected_players_counter, &serv->cq, &serv->cot) && !is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } } #if 0 if(print_table_condition(serv)) { set_state_for_client(serv, display_only_table); put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); serv->turn_queue[1]->defense_lost = 1; serv->state = end_round; } else if(defense_condition(serv)) { set_state_for_client(serv, defense); set_whose_turn(serv, defense); put_one_card_from_queue_to_table(&serv->cot, &serv->cq); serv->state = defense_phase_out; } else { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq)) { set_state_for_client(serv, display_only_table); serv->state = end_round; } else { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } } #endif } static void define_phase_after_defense(struct server *serv) { /* card wasn't beated */ if(serv->cot.card_arr[serv->cot.card_arr_idx][0] == '-') { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); /* go to tossing cards */ if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; /* then begin new attack */ } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } /* can defender continue defense? */ } else { /* the defender has beaten the attack or tossing phase completely */ if(is_empty_queue(&serv->cq)) { if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[0]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } /* card queue contains some cards for defender */ } else { /* defender can defense */ if(defense_condition(serv)) { put_one_card_from_queue_to_table(&serv->cot, &serv->cq); set_state_for_client(serv, defense); set_whose_turn(serv, defense); serv->state = defense_phase_out; /* defender can't defense */ } else { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(check_someone_can_toss_card(serv->turn_queue, serv->connected_players_counter, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } } } } } static void define_phase_after_tossing(struct server *serv) { if(serv->turn_queue[1]->defense_lost) { if(is_empty_queue(&serv->cq)) { /* nobody's put any cards on the end_round */ set_state_for_client(serv, display_only_table); serv->state = end_round; } else { put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } } /* defense continue? */ } else { if(is_empty_queue(&serv->cq)) { set_state_for_client(serv, display_only_table); serv->state = end_round; } else { if(check_defender_can_defend(&serv->cq, serv->turn_queue[1]->deck, serv->trump_suit)) { put_one_card_from_queue_to_table(&serv->cot, &serv->cq); set_state_for_client(serv, defense); set_whose_turn(serv, defense); serv->state = defense_phase_out; } else { serv->turn_queue[1]->defense_lost = 1; put_all_cards_from_queue_to_table(&serv->cot, &serv->cq); if(!is_receiving_cards_limit(&serv->cot, serv->turn_queue[1]->deck, &serv->cq) && check_someone_can_toss_card(serv->turn_queue, serv->turn_queue_size, &serv->cq, &serv->cot)) { set_state_for_client(serv, tossing); set_whose_turn(serv, tossing); serv->state = tossing_phase_out; } else { set_state_for_client(serv, display_only_table); serv->state = end_round; } } } } } static void analyze_attackers_move(struct server *serv, int *turn_queue_resizing, struct session **defender) { int key; key = serv->turn_queue[0]->player_position-1; *defender = serv->turn_queue[1]; /* attacker was left without cards */ if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { serv->turn_queue[0]->state = spectator; /* resizing of turn_queue */ shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size); --serv->turn_queue_size; *turn_queue_resizing = 1; } } static void analyze_defenders_move(struct server *serv, int turn_queue_resizing, struct session *defender) { int key; if(defender->defense_lost) { clear_defense_lost_status(defender); move_all_cards_to_defender(&serv->cot, &defender->deck); update_card_quantity_arr(serv->turn_queue, serv->cc); if(!serv->shuffled_deck_size && serv->turn_queue_size == 1) { serv->durak_position = defender->player_position; set_state_for_client(serv, result); serv->state = end_game; } else { turn_queue_resizing ? shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size) : move_turn_queue_two_players_ahead(serv->turn_queue, serv->turn_queue_size); set_whose_turn(serv, attack); set_state_for_client(serv, attack); serv->state = attack_phase_out; } } else { remove_cards_from_table(&serv->cot); key = defender->player_position - 1; if(!serv->shuffled_deck_size && !serv->cc.number_arr[key]) { /* * the final attack was completely beaten. * The defender also has no cards left */ if(serv->turn_queue_size == 1) { /* draw */ serv->durak_position = 0; set_state_for_client(serv, result); serv->state = end_game; } else { /* attacker has no cards in current part*/ if(turn_queue_resizing) { shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size); --serv->turn_queue_size; defender->state = spectator; set_state_for_client(serv, attack); set_whose_turn(serv, attack); serv->state = attack_phase_out; /* third (last) player has cards */ if(serv->turn_queue_size == 1) { serv->durak_position = serv->turn_queue[0]->player_position; set_state_for_client(serv, result); serv->state = end_game; } } else { /* behind defender */ move_turn_queue_two_players_ahead(serv->turn_queue, serv->turn_queue_size); --serv->turn_queue_size; defender->state = spectator; set_state_for_client(serv, attack); set_whose_turn(serv, attack); serv->state = attack_phase_out; if(serv->turn_queue_size == 1) { /* attacker is durak */ serv->durak_position = serv->turn_queue[0]->player_position; set_state_for_client(serv, result); serv->state = end_game; } } } } else { if(serv->turn_queue_size == 1) { serv->durak_position = defender->player_position; set_state_for_client(serv, result); serv->state = end_game; } else { if(!turn_queue_resizing) shift_turn_queue_by_one(serv->turn_queue, serv->turn_queue_size); set_state_for_client(serv, attack); set_whose_turn(serv, attack); serv->state = attack_phase_out; } } } } static void analyze_end_round(struct server *serv) { int turn_queue_resizing = 0; struct session *defender = NULL; update_card_quantity_arr(serv->turn_queue, serv->cc); /* ========= result of attacker's move ===========*/ analyze_attackers_move(serv, &turn_queue_resizing, &defender); /* ========= result of defender's move =========== */ analyze_defenders_move(serv, turn_queue_resizing, defender); } static void dealing_cards_phase(struct server *serv) { /* ======== dealing cards =========== */ if(serv->shuffled_deck_size) { if(check_everyone_can_replanish_deck(serv->shuffled_deck_size, serv->turn_queue, serv->turn_queue_size, serv->cc.number_arr)) { deal_cards(serv->shuffled_deck, &serv->shuffled_deck_size, serv->turn_queue, serv->turn_queue_size, serv->cc.number_arr); } else deal_one_card_in_turn(serv->shuffled_deck, &serv->shuffled_deck_size, serv->turn_queue, serv->turn_queue_size, serv->cc); /* update the card count after giving out cards */ update_card_quantity_arr(serv->turn_queue, serv->cc); } } static void determine_server_state(struct server *serv) { switch(serv->state) { case no_players: serv->state = first_player; break; case first_player: if(check_playable_player_number(serv)) serv->state = confirmation_waiting; break; case confirmation_waiting: set_record_status_for_all(serv); init_new_game(serv); serv->state = start_game; break; case start_game: set_state_for_client(serv, attack); set_whose_turn(serv, attack); update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); set_record_status_for_all(serv); serv->state = attack_phase_out; break; case attack_phase_out: serv->state = attack_phase_in; break; case attack_phase_in: case defense_phase_in: case tossing_phase_in: if(serv->state == attack_phase_in) define_phase_after_attack(serv); else if(serv->state == defense_phase_in) define_phase_after_defense(serv); else /* all answers received or the limit on card tossing was reached */ define_phase_after_tossing(serv); set_record_status_for_all(serv); update_card_quantity_arr(serv->turn_queue, serv->cc); update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); break; case end_round: analyze_end_round(serv); dealing_cards_phase(serv); update_game_info(serv->gi, serv->connected_players_counter, serv->shuffled_deck_size, serv->position_whose_turn); set_record_status_for_all(serv); serv->tossing_limit = 0; break; case defense_phase_out: serv->state = defense_phase_in; break; case tossing_phase_out: serv->state = tossing_phase_in; break; case end_game: close_connection(serv); serv->state = no_players; } serv->change_server_state = 0; } static int new_player_tracking_condition(enum server_states state) { return state == no_players || state == first_player || state == confirmation_waiting; } /* * when accepting new players */ static int server_state_change_condition(struct server *serv) { return serv->state == no_players || (serv->state == first_player && check_playable_player_number(serv)) || (serv->state == confirmation_waiting && is_max_playable_player_number(serv)); } static int accept_new_player(struct server *serv) { int accept_result; accept_result = accept_client(serv); if(accept_result == -1) { syslog(LOG_ERR, "accept error"); return -1; } /* update info about connected players */ set_record_status_for_all(serv); if(server_state_change_condition(serv)) serv->change_server_state = 1; return 1; } static void set_up_player_tracking(struct server *serv, fd_set *readfds, fd_set *writefds, int *maxfd) { int i; for(i = 0; i < serv->max_sess_arr_size; ++i) { if(!serv->sess_arr[i]) continue; switch(serv->state) { case first_player: case confirmation_waiting: FD_SET(i, readfds); *maxfd = i > *maxfd ? i : *maxfd; if(serv->sess_arr[i]->record) FD_SET(i, writefds); break; case start_game: case attack_phase_out: case end_round: case defense_phase_out: case tossing_phase_out: case end_game: if(serv->sess_arr[i]->record) { FD_SET(i, writefds); *maxfd = i > *maxfd ? i : *maxfd; } break; case attack_phase_in: if(serv->sess_arr[i]->state == attack) { FD_SET(i, readfds); *maxfd = i > *maxfd ? i : *maxfd; } break; case defense_phase_in: if(serv->sess_arr[i]->state == defense) { FD_SET(i, readfds); *maxfd = i > *maxfd ? i : *maxfd; } break; case tossing_phase_in: if(serv->sess_arr[i]->state == tossing && serv->sess_arr[i]->tm == answer_wait) { FD_SET(i, readfds); *maxfd = i > *maxfd ? i : *maxfd; } break; case no_players: {} } } } static int check_server_state_change_conditions(struct server *serv) { switch(serv->state) { case start_game: case attack_phase_out: case attack_phase_in: case defense_phase_out: case defense_phase_in: case tossing_phase_out: case end_round: case end_game: return 1; case tossing_phase_in: if(serv->tossing_limit || check_all_answers_were_received((const struct session**) serv->turn_queue, serv->turn_queue_size)) return 1; default: return 0; } return 0; } static void make_data_transfer(struct server *serv, fd_set *readfds, fd_set *writefds) { int i, result, close_connection_status = 0; for(i = 0; i < serv->max_sess_arr_size; ++i) { if(!serv->sess_arr[i]) continue; switch(serv->state) { case first_player: if(FD_ISSET(i, writefds)) { result = print_message_for_first_player(i); serv->sess_arr[i]->record = 0; } /* connection was closed? (result == 0) */ if(FD_ISSET(i, readfds)) result = read(i, serv->sess_arr[i]->buffer, max_buffer_size); break; case confirmation_waiting: if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) { result = print_connected_players(i, serv->connected_players_counter); serv->sess_arr[i]->record = 0; } if(FD_ISSET(i, readfds)) { result = check_readiness(serv->sess_arr[i]); if(result == 1) serv->change_server_state = 1; } break; case start_game: case attack_phase_out: case defense_phase_out: case tossing_phase_out: case end_round: if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) result = print_game_part(serv->sess_arr[i], serv->state, serv->gi); serv->sess_arr[i]->record = 0; break; case attack_phase_in: if(FD_ISSET(i, readfds)) result = get_cards_from_attacker(serv->sess_arr[i], &serv->cot, serv->turn_queue[1]->deck, &serv->cq); break; case defense_phase_in: if(FD_ISSET(i, readfds)) result = get_card_from_defender(serv->sess_arr[i], &serv->cot, serv->trump_suit); break; case tossing_phase_in: if(FD_ISSET(i, readfds)) { /* to determine that the player can no longer tossing */ if(serv->tossing_limit) serv->sess_arr[i]->tm = cancel; result = get_cards_from_tossing_player(serv->sess_arr[i], serv->turn_queue[1]->deck, &serv->cot, &serv->cq); if(result == answer_got || result == answer_got_with_limit) serv->sess_arr[i]->tm = answer_got; if(result == answer_got_with_limit) serv->tossing_limit = 1; else if(result == cancel) serv->sess_arr[i]->tm = cancel; } break; case no_players: {} case end_game: if(FD_ISSET(i, writefds) && serv->sess_arr[i]->record) print_game_result(serv->sess_arr[i], serv->durak_position); break; } if(!result) { close(i); serv->sess_arr[i]->fd = -1; close_connection_status = 1; result = 1; /* next can be reading that's not ready */ } } if(serv->state == start_game || serv->state == end_round || serv->state == end_game) sleep(2); if(check_server_state_change_conditions(serv)) serv->change_server_state = 1; /* connection is closed */ if(close_connection_status) { close_connection(serv); serv->change_server_state = 0; serv->state = no_players; } } int main_loop(struct server *serv) { int maxfd, accept_result, select_result; fd_set readfds, writefds; for(;;) { if(serv->change_server_state) determine_server_state(serv); FD_ZERO(&readfds); FD_ZERO(&writefds); if(new_player_tracking_condition(serv->state)) { FD_SET(serv->listen_socket, &readfds); maxfd = serv->listen_socket; } set_up_player_tracking(serv, &readfds, &writefds, &maxfd); select_result = select(maxfd + 1, &readfds, &writefds, NULL, NULL); if(select_result == -1) return 3; if(FD_ISSET(serv->listen_socket, &readfds)) { accept_result = accept_new_player(serv); if(accept_result == -1) return 4; } make_data_transfer(serv, &readfds, &writefds); } } /* * 0 - error * 1 - success */ static int init_server(struct server *serv, int port) { int opt, i; struct sockaddr_in addr; serv->listen_socket = socket(AF_INET, SOCK_STREAM, 0); if(serv->listen_socket == -1) return 0; opt = 1; setsockopt(serv->listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_port = htons(port); if(bind(serv->listen_socket, (struct sockaddr*) &addr, sizeof(addr)) == -1) return 0; serv->sess_arr = malloc(sizeof(*serv->sess_arr) * init_sess_arr_size); serv->max_sess_arr_size = init_sess_arr_size; for(i = 0; i < init_sess_arr_size; i++) serv->sess_arr[i] = NULL; serv->state = no_players; serv->change_server_state = 0; serv->connected_players_counter = 0; serv->shuffled_deck = NULL; serv->shuffled_deck_size = max_shuffled_deck_size; serv->gi = NULL; serv->cc.number_arr = NULL; serv->turn_queue = NULL; serv->cq.first = NULL; serv->cq.last = NULL; listen(serv->listen_socket, listen_qlen); return 1; } static void demonization() { int pid; close(0); close(1); close(2); open("/dev/null", O_RDONLY); open("/dev/null", O_WRONLY); open("/dev/null", O_WRONLY); chdir("/"); pid = fork(); if(pid) exit(0); setsid(); pid = fork(); if(pid) exit(0); } int main(int argc, char **argv) { unsigned short port; struct server serv; if(argc != 2) { fprintf(stderr, "Usage: \n"); return 1; } demonization(); srand(time(NULL)); openlog("durak server", 0, LOG_USER); syslog(LOG_INFO, "daemon started"); signal(SIGPIPE, handler); port = strtol(argv[1], NULL, 10); if(!init_server(&serv, port)) { syslog(LOG_ERR, "server initialization error"); return 2; } return main_loop(&serv); syslog(LOG_INFO, "server terminated"); closelog(); }