⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 server_loop.c

📁 NAT打洞
💻 C
字号:
#include "server_loop.h"

void set_sockets(MASTER_FD *master, fd_set *read_fds,  fd_set *write_fds,  fd_set *exc_fds);

int tcp_verbose = 0;
long now;

void init_master(MASTER_FD *master){
  	FD_ZERO(&master->read);    						// clear the master and temp sets
  	FD_ZERO(&master->write);    						// clear the master and temp sets
  	FD_ZERO(&master->exception);    						// clear the master and temp sets
  	master->fdmax = 0;
  	master->fdmin = 0;
}

int server_loop(
	int (__cdecl *client_handler)(void*, MASTER_FD*, int what),
  	void *(__cdecl *get_data_item)(SOCKET, struct sockaddr_in),
  	struct sockaddr_in(__cdecl *get_data_item_addr)(void *data_item),
  	char *buf,
	HASHMAP *data,
  	unsigned short listen_port,
  	char *(__cdecl *hello)(void),
  	MASTER_FD *master,
  	int (__cdecl *cycle_func)(void*)
){

  	fd_set read_fds, write_fds, exc_fds; 								// temp file descriptor list for select()
  	struct sockaddr_in myaddr;     	// server address
  	struct sockaddr_in remoteaddr; 	// client address
  	SOCKET listener;     							// listening socket descriptor
  	SOCKET newfd;        							// newly accept()ed socket descriptor
  	int nbytes;
  	int yes=1;        							// for setsockopt() SO_REUSEADDR, below
#if defined(WIN32) || defined(__WIN32__)
  	int addrlen;
#else
  	unsigned addrlen;
#endif
  	int i, j;
  	struct timeval timeout;

  	// get the listener
  	if (
    	SOCKET_IS_INVALID(
    		(listener = socket(AF_INET, SOCK_STREAM, 0))
    	)
  	) {
	    if(tcp_verbose){
  	    	handle_error(__FILE__, __LINE__);
      	}
      	exit(1);
  	}

  	if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(int)) != 0) {
	    if(tcp_verbose){
      		handle_error(__FILE__, __LINE__);
      	}
      	exit(1);
  	}

  	// bind
  	myaddr.sin_family = AF_INET;
  	myaddr.sin_addr.s_addr = INADDR_ANY;
  	myaddr.sin_port = htons(listen_port);
  	memset(&(myaddr.sin_zero), '\0', 8);
  	if (bind(listener, (struct sockaddr *)&myaddr, sizeof(myaddr)) != 0) {
	    if(tcp_verbose){
      		handle_error(__FILE__, __LINE__);
      	}
      	exit(1);
  	}

  	// listen
  	if (listen(listener, 100) != 0) {
	    if(tcp_verbose){
      		handle_error(__FILE__, __LINE__);
      	}
      	exit(1);
  	}

  	if(tcp_verbose){
  		if(hello != NULL){
    		char *hi = hello();
  			printf("%s\n", hi);
      		free(hi);
    	}
  	}

  	// add the listener to the master set
if(tcp_verbose){printf("[%s,%d]\n", __FILE__, __LINE__);}
  	add_socket(listener, NULL, NULL, master, MASTER_READ);

  	// main loop
  	for(;;) {
  		int res;
    	unsigned int i;
    	void *data_item = NULL;

		set_sockets(master, &read_fds,  &write_fds,  &exc_fds);
    	timeout.tv_sec = SELECT_TIMEOUT_SEC;
    	timeout.tv_usec = SELECT_TIMEOUT_USEC;
//print_master(master);
    	res = select(master->fdmax + 1, &read_fds, &write_fds, &exc_fds, &timeout);
    	now = time(NULL);
    	if(cycle_func != NULL){
      		cycle_func(NULL);
    	}
    	if (res < 0) {
	    	if(tcp_verbose){
	      		handle_error(__FILE__, __LINE__);
      		}
      		if (listen(listener, 100) != 0) {
			    if(tcp_verbose){
    	      	handle_error(__FILE__, __LINE__);
          	}
          	exit(1);
      	}

      	init_master(master);
		  	add_socket(listener, NULL, NULL, master, MASTER_READ);
      		continue;
    	}
    	if(res == 0){
    		continue;
    	}
        for(i = master->fdmin; i <= master->fdmax; i++){
    		if(FD_ISSET(i, &exc_fds)){
        		if(i != listener){
        	  		data_item = hashmap_get(data, i);
          			if(data_item != NULL){
            		int res = client_handler(data_item, master, WHAT_EXCEPTION);
	            	if(res > 0){ // close connection
    	       	   		if((res & MASTER_DISCONNECT) == MASTER_DISCONNECT){
        	        		if(tcp_verbose){
            	      			printf("- [%s:%d]\n", inet_ntoa(get_data_item_addr(data_item).sin_addr), ntohs(get_data_item_addr(data_item).sin_port));
                			}
              			}
	              		rm_socket(i, data, master, res);
    	        	}
        	  	}
	        }
    	}
    	if(FD_ISSET(i, &read_fds)){
        	if(i == listener){
          		addrlen = sizeof(struct sockaddr_in);
          		newfd = accept(listener, (struct sockaddr*)&remoteaddr, &addrlen);
          		if(
			    	SOCKET_IS_INVALID(
            		    newfd
    				)
          		){
					if(tcp_verbose){
			      		handle_error(__FILE__, __LINE__);
            		}
          		}
          		else {
            		data_item = get_data_item(newfd, remoteaddr);
if(tcp_verbose){printf("[%s,%d]\n", __FILE__, __LINE__);}
            		add_socket(newfd, data, data_item, master, MASTER_READ);
            		if(tcp_verbose){
              			printf("+ [%s:%d]\n", inet_ntoa(remoteaddr.sin_addr), ntohs(remoteaddr.sin_port));
            		}
          		}
        	}
        	else {
          		data_item = hashmap_get(data, i);
        	}
            if(data_item != NULL){
          		int res = client_handler(data_item, master, WHAT_READ);
          		if(res > 0){ // close connection
            		if((res & MASTER_DISCONNECT) == MASTER_DISCONNECT){
              			if(tcp_verbose){
                        	printf("- [%s:%d]\n", inet_ntoa(get_data_item_addr(data_item).sin_addr), ntohs(get_data_item_addr(data_item).sin_port));
              			}
            		}
            		rm_socket(i, data, master, res);
          		}
          		else if(res == -1){
				    if(tcp_verbose){
			      		handle_error(__FILE__, __LINE__);
            		}
          		}
            }
      	}
    	if(FD_ISSET(i, &write_fds)){
        	if(i != listener){
          		data_item = hashmap_get(data, i);
          		if(data_item != NULL){
            		int res = client_handler(data_item, master, WHAT_WRITE);
            		if(res > 0){ // close connection
              			if((res & MASTER_DISCONNECT) == MASTER_DISCONNECT){
                			if(tcp_verbose){
                  				printf("- [%s:%d]\n", inet_ntoa(get_data_item_addr(data_item).sin_addr), ntohs(get_data_item_addr(data_item).sin_port));
                			}
              			}
              			rm_socket(i, data, master, res);
            		}
          		}
        	}
      	}
    }
  }

}

void lock_master(MASTER_FD *master){
#if defined(WIN32) || defined(__WIN32__)
  	EnterCriticalSection(&master->lock);
#else
	struct sembuf sops;
  	sops.sem_num = 0;
  	sops.sem_op = 0;
  	sops.sem_flg = 0;
	semop(master->lock, &sops, 1);
  	sops.sem_op = 1;
	semop(master->lock, &sops, 1);
#endif
}

void unlock_master(MASTER_FD *master){
#if defined(WIN32) || defined(__WIN32__)
  	LeaveCriticalSection(&master->lock);
#else
	struct sembuf sops;
  	sops.sem_num = 0;
  	sops.sem_op = -1;
  	sops.sem_flg = 0;
	semop(master->lock, &sops, 1);
//  master->locked = 0;
#endif
}

void set_sockets(MASTER_FD *master, fd_set *read_fds,  fd_set *write_fds,  fd_set *exc_fds){
  	lock_master(master);
  	*read_fds = master->read; // copy it
	*write_fds = master->write; // copy it
	*exc_fds = master->exception; // copy it
  	unlock_master(master);
}

void add_socket(SOCKET fd, HASHMAP *data, void *data_item, MASTER_FD *master, int flags){
  	lock_master(master);
  	if((data != NULL) && (data_item != NULL)){
  		void *tmp = hashmap_get(data, fd);
        if(tmp == NULL){
  			hashmap_put(data, fd, data_item);
        }
  	}
  	if((flags & MASTER_READ) == MASTER_READ){
	  	FD_SET(fd, &master->read);
  	}
  	if((flags & MASTER_WRITE) == MASTER_WRITE){
	  	FD_SET(fd, &master->write);
  	}
  	if((flags & MASTER_EXCEPTION) == MASTER_EXCEPTION){
	  	FD_SET(fd, &master->exception);
  	}
  	if(master->fdmin == 0){
  		master->fdmin = fd;
  	}
  	else {
    	if(master->fdmin > fd){
      		master->fdmin = fd;
    	}
  	}
  	if(master->fdmax < fd){
    	master->fdmax = fd;
  	}
	if(tcp_verbose){
		printf("[%s, %d]\n", __FILE__, __LINE__);
		print_master(master);
		hashmap_print(data, NULL);
	}
  	unlock_master(master);
}

void calc_min_max(MASTER_FD *master){
  	SOCKET max, min, j;
  	max = 0;
  	min = 0;
  	for(j = master->fdmin; j <= master->fdmax; j++){
    	if(
      		FD_ISSET(j, &master->read)
      		|| FD_ISSET(j, &master->write)
      		|| FD_ISSET(j, &master->exception)
    	){
    	  	if(min == 0){
        		min = j;
	      	}
    	  	else {
        		if(min > j){
          			min = j;
	        	}
    	  	}
      		if(max < j){
	        	max = j;
    	  	}
	    }
  	}
  	master->fdmax = max;
  	master->fdmin = min;
}

void rm_socket(SOCKET fd, HASHMAP *data, MASTER_FD *master, int flags){
  	unsigned j;
  	SOCKET max, min;
  	lock_master(master);
  	if((flags & MASTER_READ) == MASTER_READ){
	  	FD_CLR(fd, &master->read);
  	}
  	if((flags & MASTER_WRITE) == MASTER_WRITE){
	  	FD_CLR(fd, &master->write);
  	}
  	if((flags & MASTER_EXCEPTION) == MASTER_EXCEPTION){
	  	FD_CLR(fd, &master->exception);
  	}
  	if(
  		!FD_ISSET(fd, &master->read)
    	&& !FD_ISSET(fd, &master->write)
    	&& !FD_ISSET(fd, &master->exception)
  	){
    	closesocket(fd);
    	if(data != NULL){
	    	void *data_item = hashmap_remove(data, fd);
      		if(data_item != NULL){
      			free(data_item);
      		}
    	}
    	calc_min_max(master);
  	}
	if(tcp_verbose){
		printf("[%s, %d]\n", __FILE__, __LINE__);
		print_master(master);
		hashmap_print(data, NULL);
	}
  	unlock_master(master);
}

void walk_master(HASHMAP *data, void *data_item, MASTER_FD *master, int (__cdecl *walker)(void*,void*)){
  	unsigned j;
  	int removed = 0;
	if(walker == NULL){
  		return;
  	}
  	lock_master(master);
  	for(j = master->fdmin; j <= master->fdmax; j++){
  		if(FD_ISSET(j, &master->read) || FD_ISSET(j, &master->write) || FD_ISSET(j, &master->exception)){
	    	void *data_item1 = hashmap_get(data, j);
		  	if(data_item1 != NULL){
      			if(walker(data_item, data_item1) != 0){
          			removed = 1;
printf("[%s,%d] %d\n", __FILE__,__LINE__, j);
			    	closesocket(j);
          			data_item1 = hashmap_remove(data, j);
          			if(data_item1 != NULL){
            			free(data_item1);
          			}
        		}
      		}
    	}
  	}
  	if(removed){
    	calc_min_max(master);
  	}
  	unlock_master(master);
}

void print_master(MASTER_FD *master){
  	unsigned j;
  	printf("read: ");
  	for(j = master->fdmin; j <= master->fdmax; j++){
  		if(FD_ISSET(j, &master->read)){
        	printf("%d ", j);
    	}
  	}
  	printf("\nwrite: ");
  	for(j = master->fdmin; j <= master->fdmax; j++){
  		if(FD_ISSET(j, &master->write)){
	  		printf("%d ", j);
    	}
  	}
  	printf("\nexception: ");
  	for(j = master->fdmin; j <= master->fdmax; j++){
  		if(FD_ISSET(j, &master->exception)){
	  		printf("%d ", j);
    	}
  	}
  	printf("\nfdmin: %d, fdmax: %d\n", master->fdmin, master->fdmax);
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -