Example #1
0
static void
_poll(struct connection_server * server) {
	int timeout = 100;
	void * buffer = NULL;
	for (;;) {
		struct connection * c = connection_poll(server->pool, timeout);
		if (c==NULL) {
			skynet_command(server->ctx,"TIMEOUT","1");
			return;
		}
		timeout = 0;

		if (buffer == NULL) {
			buffer = malloc(DEFAULT_BUFFER_SIZE);
		}

		int size = read(c->fd, buffer, DEFAULT_BUFFER_SIZE);
		if (size < 0) {
			continue;
		}
		if (size == 0) {
			free(buffer);
			buffer = NULL;
			if (c->close == 0) {
				c->close = 1;
				skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, NULL, 0);
				connection_del(server->pool, c->fd);
			}
		} else {
			skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, buffer, size);
			buffer = NULL;
		}
	}
}
Example #2
0
File: net.c Project: 95ulisse/tinc
/*
  Check if the other end is active.
  If we have sent packets, but didn't receive any,
  then possibly the other end is dead. We send a
  PING request over the meta connection. If the other
  end does not reply in time, we consider them dead
  and close the connection.
*/
static void check_dead_connections(void) {
	avl_node_t *node, *next;
	connection_t *c;

	for(node = connection_tree->head; node; node = next) {
		next = node->next;
		c = node->data;

		if(c->last_ping_time + pingtimeout <= now) {
			if(c->status.active) {
				if(c->status.pinged) {
					ifdebug(CONNECTIONS) logger(LOG_INFO, "%s (%s) didn't respond to PING in %ld seconds",
							   c->name, c->hostname, (long)now - c->last_ping_time);
					c->status.timeout = true;
					terminate_connection(c, true);
				} else if(c->last_ping_time + pinginterval <= now) {
					send_ping(c);
				}
			} else {
				if(c->status.remove) {
					logger(LOG_WARNING, "Old connection_t for %s (%s) status %04x still lingering, deleting...",
						   c->name, c->hostname, bitfield_to_int(&c->status, sizeof c->status));
					connection_del(c);
					continue;
				}
				ifdebug(CONNECTIONS) logger(LOG_WARNING, "Timeout from %s (%s) during authentication",
						   c->name, c->hostname);
				if(c->status.connecting) {
					c->status.connecting = false;
					closesocket(c->socket);
					do_outgoing_connection(c);
				} else {
					terminate_connection(c, false);
				}
			}
		}

		if(c->outbuflen > 0 && c->last_flushed_time + pingtimeout <= now) {
			if(c->status.active) {
				ifdebug(CONNECTIONS) logger(LOG_INFO,
						"%s (%s) could not flush for %ld seconds (%d bytes remaining)",
						c->name, c->hostname, (long)now - c->last_flushed_time, c->outbuflen);
				c->status.timeout = true;
				terminate_connection(c, true);
			}
		}
	}
}
Example #3
0
static void
_del(struct connection_server * server, int fd) {
	int i;
	for (i=0;i<server->max_connection;i++) {
		struct connection * c = &server->conn[i];
		if (c->fd == fd) {
			if (c->close == 0) {
				skynet_send(server->ctx, 0, c->address, PTYPE_CLIENT | PTYPE_TAG_DONTCOPY, 0, NULL, 0);
				connection_del(server->pool, fd);
			}
			c->address = 0;
			c->fd = 0;
			c->close = 0;
			close(fd);
			return;
		}
	}

	skynet_error(server->ctx, "[connection] Delete invalid handle %d", fd);
}
Example #4
0
File: net.c Project: 95ulisse/tinc
/*
  put all file descriptors in an fd_set array
  While we're at it, purge stuff that needs to be removed.
*/
static int build_fdset(fd_set *readset, fd_set *writeset) {
	avl_node_t *node, *next;
	connection_t *c;
	int i, max = 0;

	FD_ZERO(readset);
	FD_ZERO(writeset);

	for(node = connection_tree->head; node; node = next) {
		next = node->next;
		c = node->data;

		if(c->status.remove) {
			connection_del(c);
			if(!connection_tree->head)
				purge();
		} else {
			FD_SET(c->socket, readset);
			if(c->outbuflen > 0 || c->status.connecting)
				FD_SET(c->socket, writeset);
			if(c->socket > max)
				max = c->socket;
		}
	}

	for(i = 0; i < listen_sockets; i++) {
		FD_SET(listen_socket[i].tcp, readset);
		if(listen_socket[i].tcp > max)
			max = listen_socket[i].tcp;
		FD_SET(listen_socket[i].udp, readset);
		if(listen_socket[i].udp > max)
			max = listen_socket[i].udp;
	}

	if(device_fd >= 0)
		FD_SET(device_fd, readset);
	if(device_fd > max)
		max = device_fd;
	
	return max;
}
Example #5
0
int connection_close(server *srv, connection *con) {
#ifdef USE_OPENSSL
	server_socket *srv_sock = con->srv_socket;
#endif

#ifdef USE_OPENSSL
	if (srv_sock->is_ssl) {
		if (con->ssl) SSL_free(con->ssl);
		con->ssl = NULL;
	}
#endif

	fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
	fdevent_unregister(srv->ev, con->fd);
#ifdef __WIN32
	if (closesocket(con->fd)) {
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"(warning) close:", con->fd, strerror(errno));
	}
#else
	if (close(con->fd)) {
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"(warning) close:", con->fd, strerror(errno));
	}
#endif

	srv->cur_fds--;
#if 0
	log_error_write(srv, __FILE__, __LINE__, "sd",
			"closed()", con->fd);
#endif

	connection_del(srv, con);
	connection_set_state(srv, con, CON_STATE_CONNECT);

	return 0;
}
Example #6
0
File: net.c Project: 95ulisse/tinc
/*
  this is where it all happens...
*/
int main_loop(void) {
	fd_set readset, writeset;
#ifdef HAVE_PSELECT
	struct timespec tv;
	sigset_t omask, block_mask;
	time_t next_event;
#else
	struct timeval tv;
#endif
	int r, maxfd;
	time_t last_ping_check, last_config_check, last_graph_dump;
	event_t *event;

	last_ping_check = now;
	last_config_check = now;
	last_graph_dump = now;
	
	srand(now);

#ifdef HAVE_PSELECT
	if(lookup_config(config_tree, "GraphDumpFile"))
		graph_dump = true;
	/* Block SIGHUP & SIGALRM */
	sigemptyset(&block_mask);
	sigaddset(&block_mask, SIGHUP);
	sigaddset(&block_mask, SIGALRM);
	sigprocmask(SIG_BLOCK, &block_mask, &omask);
#endif

	running = true;

	while(running) {
#ifdef HAVE_PSELECT
		next_event = last_ping_check + pingtimeout;
		if(graph_dump && next_event > last_graph_dump + 60)
			next_event = last_graph_dump + 60;

		if((event = peek_next_event()) && next_event > event->time)
			next_event = event->time;

		if(next_event <= now)
			tv.tv_sec = 0;
		else
			tv.tv_sec = next_event - now;
		tv.tv_nsec = 0;
#else
		tv.tv_sec = 1;
		tv.tv_usec = 0;
#endif

		maxfd = build_fdset(&readset, &writeset);

#ifdef HAVE_MINGW
		LeaveCriticalSection(&mutex);
#endif
#ifdef HAVE_PSELECT
		r = pselect(maxfd + 1, &readset, &writeset, NULL, &tv, &omask);
#else
		r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
#endif
		now = time(NULL);
#ifdef HAVE_MINGW
		EnterCriticalSection(&mutex);
#endif

		if(r < 0) {
			if(!sockwouldblock(sockerrno)) {
				logger(LOG_ERR, "Error while waiting for input: %s", sockstrerror(sockerrno));
				dump_connections();
				return 1;
			}
		}

		if(r > 0)
			check_network_activity(&readset, &writeset);

		if(do_purge) {
			purge();
			do_purge = false;
		}

		/* Let's check if everybody is still alive */

		if(last_ping_check + pingtimeout <= now) {
			check_dead_connections();
			last_ping_check = now;

			if(routing_mode == RMODE_SWITCH)
				age_subnets();

			age_past_requests();

			/* Should we regenerate our key? */

			if(keyexpires <= now) {
				avl_node_t *node;
				node_t *n;

				ifdebug(STATUS) logger(LOG_INFO, "Expiring symmetric keys");

				for(node = node_tree->head; node; node = node->next) {
					n = node->data;
					if(n->inkey) {
						free(n->inkey);
						n->inkey = NULL;
					}
				}

				send_key_changed();
				keyexpires = now + keylifetime;
			}

			/* Detect ADD_EDGE/DEL_EDGE storms that are caused when
			 * two tinc daemons with the same name are on the VPN.
			 * If so, sleep a while. If this happens multiple times
			 * in a row, sleep longer. */

			if(contradicting_del_edge > 100 && contradicting_add_edge > 100) {
				logger(LOG_WARNING, "Possible node with same Name as us! Sleeping %d seconds.", sleeptime);
				usleep(sleeptime * 1000000LL);
				sleeptime *= 2;
				if(sleeptime < 0)
					sleeptime = 3600;
			} else {
				sleeptime /= 2;
				if(sleeptime < 10)
					sleeptime = 10;
			}

			contradicting_add_edge = 0;
			contradicting_del_edge = 0;
		}

		if(sigalrm) {
			avl_node_t *node;
			logger(LOG_INFO, "Flushing event queue");
			expire_events();
			for(node = connection_tree->head; node; node = node->next) {
				connection_t *c = node->data;
				if(c->status.active)
					send_ping(c);
			}
			sigalrm = false;
		}

		while((event = get_expired_event())) {
			event->handler(event->data);
			free_event(event);
		}

		if(sighup) {
			connection_t *c;
			avl_node_t *node, *next;
			char *fname;
			struct stat s;
			
			sighup = false;

			reopenlogger();
			
			/* Reread our own configuration file */

			exit_configuration(&config_tree);
			init_configuration(&config_tree);

			if(!read_server_config()) {
				logger(LOG_ERR, "Unable to reread configuration file, exitting.");
				return 1;
			}

			/* Cancel non-active outgoing connections */

			for(node = connection_tree->head; node; node = next) {
				next = node->next;
				c = node->data;

				c->outgoing = NULL;

				if(c->status.connecting) {
					terminate_connection(c, false);
					connection_del(c);
				}
			}

			/* Wipe list of outgoing connections */

			for(list_node_t *node = outgoing_list->head; node; node = node->next) {
				outgoing_t *outgoing = node->data;

				if(outgoing->event)
					event_del(outgoing->event);
			}

			list_delete_list(outgoing_list);

			/* Close connections to hosts that have a changed or deleted host config file */
			
			for(node = connection_tree->head; node; node = node->next) {
				c = node->data;
				
				xasprintf(&fname, "%s/hosts/%s", confbase, c->name);
				if(stat(fname, &s) || s.st_mtime > last_config_check)
					terminate_connection(c, c->status.active);
				free(fname);
			}

			last_config_check = now;

			/* If StrictSubnet is set, expire deleted Subnets and read new ones in */

			if(strictsubnets) {
				subnet_t *subnet;

				for(node = subnet_tree->head; node; node = node->next) {
					subnet = node->data;
					subnet->expires = 1;
				}

				load_all_subnets();

				for(node = subnet_tree->head; node; node = next) {
					next = node->next;
					subnet = node->data;
					if(subnet->expires == 1) {
						send_del_subnet(everyone, subnet);
						if(subnet->owner->status.reachable)
							subnet_update(subnet->owner, subnet, false);
						subnet_del(subnet->owner, subnet);
					} else if(subnet->expires == -1) {
						subnet->expires = 0;
					} else {
						send_add_subnet(everyone, subnet);
						if(subnet->owner->status.reachable)
							subnet_update(subnet->owner, subnet, true);
					}
				}
			}

			/* Try to make outgoing connections */
			
			try_outgoing_connections();
		}
		
		/* Dump graph if wanted every 60 seconds*/

		if(last_graph_dump + 60 <= now) {
			dump_graph();
			last_graph_dump = now;
		}
	}

#ifdef HAVE_PSELECT
	/* Restore SIGHUP & SIGALARM mask */
	sigprocmask(SIG_SETMASK, &omask, NULL);
#endif

	return 0;
}
Example #7
0
int connection_close(server *srv, connection *con) {
#ifdef USE_OPENSSL
	server_socket *srv_sock = con->srv_socket;
#endif

#ifdef USE_OPENSSL
	if (srv_sock->is_ssl) {
		if (con->ssl) SSL_free(con->ssl);
		con->ssl = NULL;
	}
#endif

	fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
	fdevent_unregister(srv->ev, con->fd);
#ifdef __WIN32
	if (closesocket(con->fd)) {
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"(warning) close:", con->fd, strerror(errno));
	}
#else
#ifdef HAVE_LIBMTCP
	if (mtcp_close(srv->mctx, con->fd)) {
#else
	if (close(con->fd)) {
#endif
		log_error_write(srv, __FILE__, __LINE__, "sds",
				"(warning) close:", con->fd, strerror(errno));
	}
#endif

	srv->cur_fds--;
#if 0
	log_error_write(srv, __FILE__, __LINE__, "sd",
			"closed()", con->fd);
#endif

	connection_del(srv, con);
	connection_set_state(srv, con, CON_STATE_CONNECT);

	return 0;
}

#if 0
static void dump_packet(const unsigned char *data, size_t len) {
	size_t i, j;

	if (len == 0) return;

	for (i = 0; i < len; i++) {
		if (i % 16 == 0) fprintf(stderr, "  ");

		fprintf(stderr, "%02x ", data[i]);

		if ((i + 1) % 16 == 0) {
			fprintf(stderr, "  ");
			for (j = 0; j <= i % 16; j++) {
				unsigned char c;

				if (i-15+j >= len) break;

				c = data[i-15+j];

				fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
			}

			fprintf(stderr, "\n");
		}
	}

	if (len % 16 != 0) {
		for (j = i % 16; j < 16; j++) {
			fprintf(stderr, "   ");
		}

		fprintf(stderr, "  ");
		for (j = i & ~0xf; j < len; j++) {
			unsigned char c;

			c = data[j];
			fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
		}
		fprintf(stderr, "\n");
	}
}