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; }
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; } session->lasterror = 0; 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_storage 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; } if (saddr.ss_family == AF_INET) memcpy (&session->local_addr, &((struct sockaddr_in *)&laddr)->sin_addr, sizeof(struct in_addr)); else memcpy (&session->local_addr, &((struct sockaddr_in6 *)&laddr)->sin6_addr, sizeof(struct in6_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 ) { session->lasterror = LIBIRC_ERR_STATE; return 1; } // Hey, we've got something to read! if ( FD_ISSET (session->sock, in_set) ) { int offset, length = session_socket_read( session ); if ( length < 0 ) { if ( session->lasterror == 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); offset = libirc_findcrlf_offset(session->incoming_buf, offset, session->incoming_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 ( 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 = session_socket_write( session ); if ( length < 0 ) { if ( session->lasterror == 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 ( 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; }