Example #1
0
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);
}
Example #2
0
void
sync_set_active(struct p_conn_params *cp, pthread_mutex_t *mx, int val)
{
	MXLOCK(mx);
	cp->active = val;	
	MXUNLOCK(mx);
}
void test(void)
{
	LOCK_CLASS(lc);
	struct lock a;

	MXINIT(&a, &lc);

	test_set_panic_string("lockdep: Aborting - releasing unheld lock");

	MXUNLOCK(&a);
}
Example #4
0
int
sync_get_active(struct p_conn_params *cp, pthread_mutex_t *mx)
{
	int ret;
	
	MXLOCK(mx);
	ret = cp->active;
	MXUNLOCK(mx);
	
	return ret;
}
Example #5
0
/* *****************************************************************************
 * 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);
}
Example #6
0
/* *****************************************************************************
 * 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_set_panic_string("lockdep: invalid call to MXUNLOCK");

	MXUNLOCK(NULL);
}
Example #8
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[]) 
{
	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);		
}
Example #9
0
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);
}
Example #10
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);
}