void clean_exit(int exit_code, pthread_attr_t *attr, int ssock) { struct handler *iter = NULL; struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; sstatus("Clearing client handlers. "); MXLOCK(&mx_list); iter = g_list.head; while (iter != NULL) { MXLOCK(&iter->mx_life); iter->alive = 0; MXUNLOCK(&iter->mx_life); iter = iter->next; } MXUNLOCK(&mx_list); select(0, NULL, NULL, NULL, &timeout); pthread_attr_destroy(attr); p_close_socket(&ssock); sstatus("Server terminated.\n"); exit(exit_code); }
void test(void) { LOCK_CLASS(lc); struct lock a; MXINIT(&a, &lc); MXLOCK(&a); test_set_panic_string("lockdep: Aborting - deadlock"); MXLOCK(&a); }
void sync_set_active(struct p_conn_params *cp, pthread_mutex_t *mx, int val) { MXLOCK(mx); cp->active = val; MXUNLOCK(mx); }
int sync_get_active(struct p_conn_params *cp, pthread_mutex_t *mx) { int ret; MXLOCK(mx); ret = cp->active; MXUNLOCK(mx); return ret; }
/* ***************************************************************************** * Function definitions. * ****************************************************************************/ void clean_exit(int exit_code, struct p_conn_params *cp, pthread_t *t) { MXLOCK(&mx_rdr_life); g_rdr = 0; MXUNLOCK(&mx_rdr_life); pthread_join(*t, NULL); pstatus("Reader thread shutdown."); if (cp->active) { p_close_socket(&cp->socket); } pstatus("Connection closed."); // Exit successfully. printf("\n"); exit(exit_code); }
/* ***************************************************************************** * Function definitions - see declarations for usage info. * ****************************************************************************/ void * io_task(void *arg) { int alive = 1; char input[25]; while (alive) { fgets(input, 25, stdin); fflush(stdout); if (strncmp(input, EXIT_MSG, 5) == 0) { MXLOCK(&mx_exit_var); g_exit_var = 1; MXUNLOCK(&mx_exit_var); alive = 0; } } sstatus("Input thread terminated. "); pthread_exit(NULL); }
void test(void) { test_setup(); MXLOCK(&a); }
/** * Collects user input and performs the main program loop. * @param argc - Number of arguments; should be 3. * @param argv - Command line arguments; 1 should be the server; 2 should be the * port. * @return int - Returns 0 if no errors; nonzero otherwise. */ int main(int argc, char *argv[]) { int server_exit; // = 1 if the server should terminate. int ret; // General purpose return value storage. struct sockaddr *sa = malloc(SA_SZ); // Used to convert network addresses. pthread_t io_tid; // Thread ID of the user input thread. unsigned next_hid = 1; // Used to assign handler IDs. pthread_attr_t h_attr; // Handler thread attributes. struct handler *new_h = NULL; // Used to allocate memory for new handlers. init_handler_list(&g_list); // List of active client handlers (global). struct p_conn_params server; // Server connection parameters. char s_ipstr[INET6_ADDRSTRLEN]; // Server address. int s_port; // Server port - int. char str_port[10]; fd_set listenfds; // 1-element set containing the listening socket. struct timeval timeout; // Timeout before server checks if it should exit. // Set up the handler thread attribute to be in detached state - we do not // need the main thread to join with them; as soon as their client has // disconnected they can have their resources reallocated. ret = pthread_attr_init(&h_attr); if (ret) { ret = p_perror(P_ETATTR, strerror(ret)); clean_exit(ret, &h_attr, server.socket); } ret = pthread_attr_setdetachstate(&h_attr, PTHREAD_CREATE_DETACHED); if (ret) { ret = p_perror(P_ETATTR, strerror(ret)); clean_exit(ret, &h_attr, server.socket); } // Start up the IO thread. if (pthread_create(&io_tid, &h_attr, &io_task, NULL)) { return p_perror(P_EIOTASK, NULL); } sstatus("Server input started. Enter *quit to exit.\n"); // Print the list of interface addresses for this machine. p_print_if_addrs(); // Get the port number the user wishes to listen on, if available. if (argc == 2) { strncpy(str_port, argv[1], 6); str_port[5] = '\0'; } else { strncpy(str_port, DEFAULT_PORT, 6); } // Set up the server socket information p_init_conn_params(&server); p_init_addrinfo(&server.params, AI_PASSIVE, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); ret = setup_server(&server, str_port); if (ret > 0) { clean_exit(ret, &h_attr, server.socket); } else if (ret == -1) { sstatus("The attempted port number was in use: "); printf("%s", str_port); // Loop until we get a usable port.. int p = atoi(str_port); if (p < 1024) p = 1024; while (ret == -1 && p < 65535) { p++; sprintf(str_port, "%d", p); freeaddrinfo(server.server_info); sstatus("Attempting to bind to port: "); printf("%s", str_port); ret = setup_server(&server, str_port); if (ret > 0) { clean_exit(ret, &h_attr, server.socket); } } if (p == 65535) { sstatus("There are no ports available to bind to."); clean_exit(ret, &h_attr, server.socket); } } freeaddrinfo(server.server_info); // Alert user to port. sstatus("Server set up and listening."); if (p_get_sock_name(server.socket, sa, SA_SZ) > 0) { printf(" Port = %i\n", p_port_from_sa(sa)); } MXLOCK(&mx_exit_var); server_exit = g_exit_var; MXUNLOCK(&mx_exit_var); // Main server client-handling loop. while (server_exit == 0) { // Wait for incoming connections. FD_ZERO(&listenfds); FD_SET(server.socket, &listenfds); timeout.tv_sec = SERV_TO_SEC; timeout.tv_usec = 0; ret = select(server.socket + 1, &listenfds, NULL, NULL, &timeout); if (ret == -1) { ret = p_perror(P_ESELECT, strerror(errno)); clean_exit(ret, &h_attr, server.socket); } // There is an incoming connection. else if (FD_ISSET(server.socket, &listenfds)) { sstatus("Incoming connection. "); new_h = new_handler(); new_h->sock = accept(server.socket, (struct sockaddr *)&new_h->addr, &new_h->addr_sz); if (new_h->sock == -1) { // accept() failed ret = p_perror(P_EACCEPT, strerror(errno)); clean_exit(ret, &h_attr, server.socket); } else { // Get some info on the new client and assign an ID. if (p_get_sock_name(new_h->sock, sa, SA_SZ) > 0) { new_h->port = p_port_from_sa(sa); p_ip_from_sa(sa, new_h->ipstr); } new_h->hid = next_hid++; // Spawn a new handler. ret = pthread_create(&new_h->tid, &h_attr, &handler_task, (void *)new_h); if (ret == -1) { ret = p_perror(P_ETHREAD, strerror(ret)); clean_exit(ret, &h_attr, server.socket); } sstatus("New connection established. ID = "); printf("%hi. ", new_h->hid); fflush(stdout); if (new_h->ipstr != NULL) printf("%s", new_h->ipstr); printf(" : %i\n", new_h->port); fflush(stdout); // Add the handler information to the global list. MXLOCK(&mx_list); hl_add_to_head(&g_list, new_h); MXUNLOCK(&mx_list); } } MXLOCK(&mx_exit_var); server_exit = g_exit_var; MXUNLOCK(&mx_exit_var); } // Clean up threads, data structures, etc., and exit. sstatus("Server shutting down.. "); clean_exit(0, &h_attr, server.socket); }
void * rdr_task(void *arg) { int alive; // 1 if the reader should run; 0 if it should end. int active; // 1 if the connection is active (conn->active == 1) int rstatus; struct p_conn_params *conn = (struct p_conn_params *)arg; char testbuf; fd_set sockfds; // Used for select() when waiting for connections. struct timeval timeout; int ret; struct timeval active_wait; // When the reader first starts, check if it should run. MXLOCK(&mx_rdr_life); alive = g_rdr; MXUNLOCK(&mx_rdr_life); // While alive, check the socket for messages and output them. while (alive) { memset(RECVBUF, '\0', sizeof(char)*RECVBUF_SZ); // Wait for the connection to be active. active = sync_get_active(conn, &mx_active); while (active == 0) { // Wait for a little bit, then check again for an active connection. active_wait.tv_sec = 1; active_wait.tv_usec = 0; select(0, NULL, NULL, NULL, &active_wait); active = sync_get_active(conn, &mx_active); } // Use select() to wait for an incoming connection. FD_ZERO(&sockfds); FD_SET(conn->socket, &sockfds); timeout.tv_sec = 1; timeout.tv_usec = 10000; select(conn->socket + 1, &sockfds, NULL, NULL, &timeout); if (FD_ISSET(conn->socket, &sockfds)) { MXLOCK(&mx_socket); // Set max bytes received to RECVBUF_SZ - 1 so we have room to add \0. rstatus = recv(conn->socket, RECVBUF, sizeof(char) * RECVBUF_SZ - 1, MSG_DONTWAIT); MXUNLOCK(&mx_socket); // Print if there was a message. if (rstatus > 0) { RECVBUF[rstatus] = '\0'; printf("\n%s\n>>", RECVBUF); } fflush(stdout); } // Check if it should continue running. MXLOCK(&mx_rdr_life); alive = g_rdr; MXUNLOCK(&mx_rdr_life); } pthread_exit(0); }
/** * Collects user input and performs the main program loop. * @param argc - Number of arguments; should be 3. * @param argv - Command line arguments; 1 should be the server; 2 should be the * port. * @return int - Returns 0 if no errors; nonzero otherwise. */ int main(int argc, char *argv[]) { struct p_conn_params conn; // Holds information for the connection. int errcode; // Hold return error codes. int running = 1; // 0 if program should exit. int unsent_msg = 0; // Indicates if last user message was not sent. pthread_t rdr_id; // Check proper usage. if (argc != 3) { return p_perror(P_EUSAGE, NULL); } // Initialize the connection. p_init_conn_params(&conn); conn.server = argv[1]; conn.port = argv[2]; p_init_addrinfo(&conn.params, 0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP); // Start up the reader. g_rdr = 1; if (pthread_create(&rdr_id, NULL, &rdr_task, (void *) &conn)) { return p_perror(P_EREADER, NULL); } // Main program loop. pstatus("Client program. Enter *quit to quit."); do { // Reconnect if necessary. if (sync_get_active(&conn, &mx_active) != 1) { pstatus("Attempting to establish connection.."); MXLOCK(&mx_socket); MXLOCK(&mx_active); errcode = p_connect(&conn); // Try to connect. MXUNLOCK(&mx_active); MXUNLOCK(&mx_socket); if (errcode) { // Connection failed. p_perror(errcode, "In main loop, after (re)connect block"); clean_exit(errcode, &conn, &rdr_id); } pstatus("Connection opened.\n"); } // Get a line of input from the user, unless the previous message was // unsent (e.g. because of disconnect). fflush(stdout); if (unsent_msg) { pstatus("Last message was unsent. Now sending:"); printf("\n%s\n", INBUF); unsent_msg = 0; } else { printf(">>"); running = get_input(); } // Continue and send if the user had not chosen to quit. if (running) { // Check connection. errcode = p_test_conn(conn.socket); if (errcode == 0) { pstatus("The server closed the connection.\n"); sync_set_active(&conn, &mx_active, 0); p_close_socket(&conn.socket); unsent_msg = 1; } // Send the message if the connection is ok. if (sync_get_active(&conn, &mx_active)) { MXLOCK(&mx_socket); if (p_send_msg(&conn.socket, INBUF, sizeof(char)*strlen(INBUF)) == 0) { p_perror(P_ESENDF, strerror(errno)); running = 0; } MXUNLOCK(&mx_socket); } } } while(running); // Close the socket and join with the reader thread. clean_exit(0, &conn, &rdr_id); }