Beispiel #1
0
static void
connectCallback(NetDescriptor *nd) {
	// Called by the NetManager when a connection has been established.
	ConnectState *connectState =
			(ConnectState *) NetDescriptor_getExtra(nd);
	int err;

	if (connectState->alarm != NULL) {
		Alarm_remove(connectState->alarm);
		connectState->alarm = NULL;
	}

	if (connectState->state == Connect_closed) {
		// The connection attempt has been aborted.
#ifdef DEBUG
		log_add(log_Debug, "Connection attempt was aborted.");
#endif
		ConnectState_decRef(connectState);
		return;
	}

	if (Socket_getError(NetDescriptor_getSocket(nd), &err) == -1) {
		log_add(log_Fatal, "Socket_getError() failed: %s.",
				strerror(errno));
		explode();
	}
	if (err != 0) {
#ifdef DEBUG
		log_add(log_Debug, "connect() failed: %s.", strerror(err));
#endif
		NetDescriptor_close(nd);
		connectState->nd = NULL;
		connectState->infoPtr = connectState->infoPtr->ai_next;
		connectHostNext(connectState);
		return;
	}

#ifdef DEBUG
	log_add(log_Debug, "Connection established.");
#endif

	// Notify the higher layer.
	connectState->nd = NULL;
			// The callback function takes over ownership of the
			// NetDescriptor.
	NetDescriptor_setWriteCallback(nd, NULL);
	// Note that connectState->info and connectState->infoPtr are cleaned up
	// when ConnectState_close() is called by the callback function.
	
	ConnectState_incRef(connectState);
	doConnectCallback(connectState, nd, connectState->infoPtr->ai_addr,
			connectState->infoPtr->ai_addrlen);
	{
		// The callback called should release the last reference to
		// the connectState, by calling ConnectState_close().
		bool released = ConnectState_decRef(connectState);
		assert(released);
		(void) released;  // In case assert() evaluates to nothing.
	}
}
Beispiel #2
0
static void
acceptSingleConnection(ListenState *listenState, NetDescriptor *nd) {
	Socket *sock;
	Socket *acceptResult;
	struct sockaddr_storage addr;
	socklen_t addrLen;
	NetDescriptor *newNd;

	sock = NetDescriptor_getSocket(nd);
	addrLen = sizeof (addr);
	acceptResult = Socket_accept(sock, (struct sockaddr *) &addr, &addrLen);
	if (acceptResult == Socket_noSocket) {
		switch (errno) {
			case EWOULDBLOCK:
			case ECONNABORTED:
				// Nothing serious. Keep listening.
				return;
			case EMFILE:
			case ENFILE:
			case ENOBUFS:
			case ENOMEM:
#ifdef ENOSR
			case ENOSR:
#endif
				// Serious problems, but future connections may still
				// be possible.
				log_add(log_Warning, "accept() reported '%s'",
						strerror(errno));
				return;
			default:
				// Should not happen.
				log_add(log_Fatal, "Internal error: accept() reported "
						"'%s'", strerror(errno));
				explode();
		}
	}

	(void) Socket_setReuseAddr(acceptResult);
			// Ignore errors; it's not a big deal.
	if (Socket_setNonBlocking(acceptResult) == -1) {
		int savedErrno = errno;
		log_add(log_Error, "Could not make socket non-blocking: %s.",
				strerror(errno));
		Socket_close(acceptResult);
		errno = savedErrno;
		return;
	}
	(void) Socket_setInlineOOB(acceptResult);
			// Ignore errors; it's not a big deal as the other
			// party is not not supposed to send any OOB data.
	(void) Socket_setKeepAlive(sock);
			// Ignore errors; it's not a big deal.

#ifdef DEBUG
	{
		char hostname[NI_MAXHOST];
		int gniRes;

		gniRes = getnameinfo((struct sockaddr *) &addr, addrLen,
				hostname, sizeof hostname, NULL, 0, 0);
		if (gniRes != 0) {
			log_add(log_Error, "Error while performing hostname "
					"lookup for incoming connection: %s",
					(gniRes == EAI_SYSTEM) ? strerror(errno) :
					gai_strerror(gniRes));
		} else {
			log_add(log_Debug, "Accepted incoming connection from '%s'.",
					hostname);
		}
	}
#endif
	
	newNd = NetDescriptor_new(acceptResult, NULL);
	if (newNd == NULL) {
		int savedErrno = errno;
		log_add(log_Error, "NetDescriptor_new() failed: %s.",
				strerror(errno));
		Socket_close(acceptResult);
		errno = savedErrno;
		return;
	}

	doListenConnectCallback(listenState, nd, newNd,
			(struct sockaddr *) &addr, addrLen);
	// NB: newNd is now handed over to the callback function, and should
	//     no longer be referenced from here.
}
Beispiel #3
0
void
dataReadyCallback(NetDescriptor *nd) {
	NetConnection *conn = (NetConnection *) NetDescriptor_getExtra(nd);
	Socket *socket = NetDescriptor_getSocket(nd);

	for (;;) {
		ssize_t numRead;
		ssize_t numProcessed;

		numRead = Socket_recv(socket, conn->readEnd,
				NETPLAY_READBUFSIZE - (conn->readEnd - conn->readBuf), 0);
		if (numRead == 0) {
			// Other side closed the connection.
			NetDescriptor_close(nd);
			return;
		}

		if (numRead == -1) {
			switch (errno) {
				case EAGAIN:  // No more data for now.
					return;
				case EINTR:  // System call was interrupted. Retry.
					continue;
				default: {
					int savedErrno = errno;
					log_add(log_Error, "recv() failed: %s.\n",
							strerror(errno));
					NetConnection_doErrorCallback(conn, savedErrno);
					NetDescriptor_close(nd);
					return;
				}
			}
		}

		conn->readEnd += numRead;

		numProcessed = dataReceivedMulti(conn, conn->readBuf,
				conn->readEnd - conn->readBuf);
		if (numProcessed == -1) {
			// An error occured during processing.
			// errno is set.
			NetConnection_doErrorCallback(conn, errno);
			NetDescriptor_close(nd);
			return;
		}
		if (numProcessed == 0) {
			// No packets could be processed. This means we need to receive
			// more data first.
			return;
		}
		
		// Some packets have been processed.
		// We more any rest to the front of the buffer, to make room
		// for more data.
		// A cyclic buffer would obviate the need for this move,
		// but it would complicate things a lot.
		memmove(conn->readBuf, conn->readBuf + numProcessed,
				(conn->readEnd - conn->readBuf) - numProcessed);
		conn->readEnd -= numProcessed;
	}
}