int irc_process_select_descriptors (irc_session_t * session, fd_set *in_set, fd_set *out_set)
{
	char buf[256], hname[256];

	if ( session->sock < 0
	|| session->state == LIBIRC_STATE_INIT
	|| session->state == LIBIRC_STATE_DISCONNECTED )
	{
		session->lasterror = LIBIRC_ERR_STATE;
		return 1;
	}

	libirc_dcc_process_descriptors (session, in_set, out_set);

	// Handle "connection succeed" / "connection failed"
	if ( session->state == LIBIRC_STATE_CONNECTING
	&& FD_ISSET (session->sock, out_set) )
	{
		// Now we have to determine whether the socket is connected
		// or the connect is failed
		struct sockaddr_in saddr, laddr;
		socklen_t slen = sizeof(saddr);
		socklen_t llen = sizeof(laddr);

		if ( getsockname (session->sock, (struct sockaddr*)&laddr, &llen) < 0
		|| getpeername (session->sock, (struct sockaddr*)&saddr, &slen) < 0 )
		{
			// connection failed
			session->lasterror = LIBIRC_ERR_CONNECT;
			session->state = LIBIRC_STATE_DISCONNECTED;
			return 1;
		}

		memcpy (&session->local_addr, &laddr.sin_addr, sizeof(session->local_addr));

#if defined (ENABLE_DEBUG)
		if ( IS_DEBUG_ENABLED(session) )
			fprintf (stderr, "[DEBUG] Detected local address: %s\n", inet_ntoa(session->local_addr));
#endif

		session->state = LIBIRC_STATE_CONNECTED;

		// Get the hostname
    	if ( gethostname (hname, sizeof(hname)) < 0 )
    		strcpy (hname, "unknown");

		// Prepare the data, which should be sent to the server
		if ( session->server_password )
		{
			snprintf (buf, sizeof(buf), "PASS %s", session->server_password);
			irc_send_raw (session, buf);
		}

		snprintf (buf, sizeof(buf), "NICK %s", session->nick);
		irc_send_raw (session, buf);

		/*
		 * RFC 1459 states that "hostname and servername are normally
         * ignored by the IRC server when the USER command comes from
         * a directly connected client (for security reasons)", therefore
         * we don't need them.
         */
		snprintf (buf, sizeof(buf), "USER %s unknown unknown :%s",
				session->username ? session->username : "******",
				session->realname ? session->realname : "noname");
		irc_send_raw (session, buf);

		return 0;
	}

	if ( session->state != LIBIRC_STATE_CONNECTED )
		return 1;

	// Hey, we've got something to read!
	if ( FD_ISSET (session->sock, in_set) )
	{
		int length, offset;

		unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset;
		length = socket_recv (&session->sock, session->incoming_buf + session->incoming_offset, amount);

		if ( length <= 0 )
		{
			session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);
			session->state = LIBIRC_STATE_DISCONNECTED;
			return 1;
		}

		session->incoming_offset += length;

		// process the incoming data
		while ( (offset = libirc_findcrlf (session->incoming_buf, session->incoming_offset)) > 0 )
		{
#if defined (ENABLE_DEBUG)
			if ( IS_DEBUG_ENABLED(session) )
				libirc_dump_data ("RECV", session->incoming_buf, offset);
#endif
			// parse the string
			libirc_process_incoming_data (session, offset - 2);

			if ( session->incoming_offset - offset > 0 )
				memmove (session->incoming_buf, session->incoming_buf + offset, session->incoming_offset - offset);

			session->incoming_offset -= offset;
		}
	}

	// We can write a stored buffer
	if ( FD_ISSET (session->sock, out_set) )
	{
		int length;

		// Because outgoing_buf could be changed asynchronously, we should
		// lock any change
		libirc_mutex_lock (&session->mutex_session);
		length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset);

		if ( length <= 0 )
		{
			session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);
			session->state = LIBIRC_STATE_DISCONNECTED;

			libirc_mutex_unlock (&session->mutex_session);
			return 1;
		}

#if defined (ENABLE_DEBUG)
		if ( IS_DEBUG_ENABLED(session) )
			libirc_dump_data ("SEND", session->outgoing_buf, length);
#endif

		if ( session->outgoing_offset - length > 0 )
			memmove (session->outgoing_buf, session->outgoing_buf + length, session->outgoing_offset - length);

		session->outgoing_offset -= length;
		libirc_mutex_unlock (&session->mutex_session);
	}

	return 0;
}
Beispiel #2
0
int irc_process_select_descriptors(irc_session_t * session) {
    if (session->sock < 0
            || session->state == LIBIRC_STATE_INIT
            || session->state == LIBIRC_STATE_DISCONNECTED) {
        session->lasterror = LIBIRC_ERR_STATE;
        return 1;
    }

    session->lasterror = 0;
    libirc_dcc_process_descriptors(session);

    // Handle "connection succeed" / "connection failed"
    if (unlikely(session->state == LIBIRC_STATE_CONNECTING
            && fdwatch_check_fd(session->sock, FDW_WRITE))) {
        return handle_connecting_state(session);
    }

    if (unlikely(session->state != LIBIRC_STATE_CONNECTED)) {
        DBG_WARN("session->state != LIBIRC_STATE_CONNECTED");
        session->state = LIBIRC_STATE_DISCONNECTED;
        session->lasterror = LIBIRC_ERR_STATE;
        return 1;
    }

    // Hey, we've got something to read!
    if (likely(fdwatch_check_fd(session->sock, FDW_READ))) {
        int offset, length = session_socket_read(session);

        if (unlikely(length < 0)) {
            if (session->lasterror == 0)
                session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);

            session->state = LIBIRC_STATE_DISCONNECTED;
            DBG_WARN("session->state = LIBIRC_STATE_DISCONNECTED");
            return 1;
        }

        session->incoming_offset += length;

        // process the incoming data
        while ((offset = libirc_findcrlf(session->incoming_buf, session->incoming_offset)) > 0) {
#if defined (ENABLE_DEBUG)
            if (IS_DEBUG_ENABLED(session))
                libirc_dump_data("RECV", session->incoming_buf, offset);
#endif
            // parse the string
            libirc_process_incoming_data(session, offset);

            if (session->incoming_offset - offset > 0)
                memmove(session->incoming_buf, session->incoming_buf + offset, session->incoming_offset - offset);

            session->incoming_offset -= offset;
        }
    }

    // We can write a stored buffer
    if (fdwatch_check_fd(session->sock, FDW_WRITE)) {
        int length;

        // Because outgoing_buf could be changed asynchronously, we should lock any change
        libirc_mutex_lock(&session->mutex_session);
        length = session_socket_write(session);

        if (unlikely(length < 0)) {
            if (session->lasterror == 0)
                session->lasterror = (length == 0 ? LIBIRC_ERR_CLOSED : LIBIRC_ERR_TERMINATED);

            session->state = LIBIRC_STATE_DISCONNECTED;
            DBG_WARN("session->state = LIBIRC_STATE_DISCONNECTED");
            libirc_mutex_unlock(&session->mutex_session);
            return 1;
        }

#if defined (ENABLE_DEBUG)
        if (IS_DEBUG_ENABLED(session))
            libirc_dump_data("SEND", session->outgoing_buf, length);
#endif

        if (length > 0 && session->outgoing_offset - length > 0)
            memmove(session->outgoing_buf, session->outgoing_buf + length, session->outgoing_offset - length);

        session->outgoing_offset -= length;
        libirc_mutex_unlock(&session->mutex_session);
    }

    return 0;
}