Esempio n. 1
0
int	irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback)
{
	irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);

	if ( !dcc )
		return 1;

	if ( dcc->state != LIBIRC_STATE_INIT )
	{
		session->lasterror = LIBIRC_ERR_STATE;
		libirc_mutex_unlock (&session->mutex_dcc);
		return 1;
	}

	dcc->cb = callback;
	dcc->ctx = ctx;

	// Initiate the connect
    if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
	{
		libirc_dcc_destroy_nolock (session, dccid);
		libirc_mutex_unlock (&session->mutex_dcc);
		session->lasterror = LIBIRC_ERR_CONNECT;
		return 1;
	}

	dcc->state = LIBIRC_STATE_CONNECTING;
	libirc_mutex_unlock (&session->mutex_dcc);
	return 0;
}
Esempio n. 2
0
static void send_current_file_offset_to_sender (irc_session_t *session, irc_dcc_session_t *dcc) {
    int sentBytes, err = 0;

    // we convert out irc_dcc_size_t to uint32_t, because it's defined like that in dcc...
    uint32_t confirmSizeNetworkOrder = htobe32(dcc->file_confirm_offset);
    size_t offset = sizeof(confirmSizeNetworkOrder);

#ifdef ENABLE_SSL
    if (dcc->ssl == 0)
        sentBytes = socket_send(&dcc->sock, &confirmSizeNetworkOrder, offset);
    else {
        int sslError = 0;
        sentBytes = ssl_write_wrapper(session, dcc, &confirmSizeNetworkOrder, offset, &sslError);

        if (sslError == SSL_ERROR_WANT_READ) {
            dcc->state = LIBIRC_STATE_CONNECTED;
            return;
        }
        else if (sslError == SSL_ERROR_WANT_WRITE) {
            return;
        }
    }
#else
    sentBytes = socket_send(&dcc->sock, &confirmSizeNetworkOrder, offset);
#endif
    if (unlikely(sentBytes < 0)) {
        DBG_WARN("err send length < 0");
        DBG_WARN("error msg: %s\n", strerror(errno));
        err = LIBIRC_ERR_WRITE;
    } else if (unlikely(sentBytes == 0)) {
        err = LIBIRC_ERR_CLOSED;
    } else {
        if (unlikely(dcc->received_file_size == dcc->file_confirm_offset)) {
            DBG_OK("dcc->received_file_size == dcc->file_confirm_offset");
            libirc_mutex_unlock(&session->mutex_dcc);
            (*dcc->cb)(session, dcc->id, 0, dcc->ctx, 0, 0);
			libirc_mutex_lock(&session->mutex_dcc);
            libirc_dcc_destroy_nolock(session, dcc->id);
        } else {
            /* Continue to receive the file */
            dcc->state = LIBIRC_STATE_CONNECTED;
        }
    }

    /*
     * If error arises somewhere above, we inform the caller 
     * of failure, and destroy this session.
     */
    if (unlikely(err)) {
        libirc_mutex_unlock(&session->mutex_dcc);
        (*dcc->cb)(session, dcc->id, err, dcc->ctx, 0, 0);
        libirc_mutex_lock(&session->mutex_dcc);

        //libirc_dcc_destroy_nolock (ircsession, dcc->id);
    }
}
Esempio n. 3
0
int irc_dcc_decline(irc_session_t * session, irc_dcc_t dccid) {
    irc_dcc_session_t * dcc = libirc_find_dcc_session(session, dccid, 1);

    if (!dcc)
        return 1;

    if (dcc->state != LIBIRC_STATE_INIT) {
        session->lasterror = LIBIRC_ERR_STATE;
        libirc_mutex_unlock(&session->mutex_dcc);
        return 1;
    }

    libirc_dcc_destroy_nolock(session, dccid);
    libirc_mutex_unlock(&session->mutex_dcc);
    return 0;
}
Esempio n. 4
0
static void handleConnectingState(irc_session_t * ircsession, irc_dcc_session_t *dcc) {
    if (fdwatch_check_fd(dcc->sock, FDW_WRITE)) {
        // Now we have to determine whether the socket is connected 
        // or the connect is failed
        struct sockaddr_in saddr;
        socklen_t slen = sizeof (saddr);
        int err = 0;

        if (getpeername(dcc->sock, (struct sockaddr*) &saddr, &slen) < 0)
            err = LIBIRC_ERR_CONNECT;

        // On success, change the state
        if (err == 0)
            dcc->state = LIBIRC_STATE_CONNECTED;

        if (err)
            libirc_dcc_destroy_nolock(ircsession, dcc->id);

    }
}
Esempio n. 5
0
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd)
{
	irc_dcc_session_t * dcc, *dcc_next;
	time_t now = time (0);

	libirc_mutex_lock (&ircsession->mutex_dcc);

	// Preprocessing DCC list:
	// - ask DCC send callbacks for data;
	// - remove unused DCC structures
	for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next )
	{
		dcc_next = dcc->next;

		// Remove timed-out sessions
		if ( (dcc->state == LIBIRC_STATE_CONNECTING
			|| dcc->state == LIBIRC_STATE_INIT
			|| dcc->state == LIBIRC_STATE_LISTENING)
		&& now - dcc->timeout > ircsession->dcc_timeout )
		{
			// Inform the caller about DCC timeout.
			// Do not inform when state is LIBIRC_STATE_INIT - session
			// was initiated from someone else, and callbacks aren't set yet.
			if ( dcc->state != LIBIRC_STATE_INIT )
			{
				libirc_mutex_unlock (&ircsession->mutex_dcc);

				if ( dcc->cb )
					(*dcc->cb)(ircsession, dcc->id, LIBIRC_ERR_TIMEOUT, dcc->ctx, 0, 0);

				libirc_mutex_lock (&ircsession->mutex_dcc);
			}

			libirc_remove_dcc_session (ircsession, dcc, 0);
		}

		/*
		 * If we're sending file, and the output buffer is empty, we need
         * to provide some data.
         */
		if ( dcc->state == LIBIRC_STATE_CONNECTED
		&& dcc->dccmode == LIBIRC_DCC_SENDFILE
		&& dcc->dccsend_file_fp
		&& dcc->outgoing_offset == 0 )
		{
			int len = fread (dcc->outgoing_buf, 1, sizeof (dcc->outgoing_buf), dcc->dccsend_file_fp);

			if ( len <= 0 )
			{
				int err = (len < 0 ? LIBIRC_ERR_READ : 0);
			
				libirc_mutex_unlock (&ircsession->mutex_dcc);

				(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
				libirc_mutex_lock (&ircsession->mutex_dcc);
				libirc_dcc_destroy_nolock (ircsession, dcc->id);
			}
			else
				dcc->outgoing_offset = len;
		}

		// Clean up unused sessions
		if ( dcc->state == LIBIRC_STATE_REMOVED )
			libirc_remove_dcc_session (ircsession, dcc, 0);
	}

	for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
	{
		switch (dcc->state)
		{
		case LIBIRC_STATE_LISTENING:
			// While listening, only in_set descriptor should be set
			libirc_add_to_set (dcc->sock, in_set, maxfd);
			break;

		case LIBIRC_STATE_CONNECTING:
			// While connection, only out_set descriptor should be set
			libirc_add_to_set (dcc->sock, out_set, maxfd);
			break;

		case LIBIRC_STATE_CONNECTED:
			// Add input descriptor if there is space in input buffer
			// and it is DCC chat (during DCC send, there is nothing to recv)
			if ( dcc->incoming_offset < sizeof(dcc->incoming_buf) - 1 )
				libirc_add_to_set (dcc->sock, in_set, maxfd);

			// Add output descriptor if there is something in output buffer
			libirc_mutex_lock (&dcc->mutex_outbuf);

			if ( dcc->outgoing_offset > 0  )
				libirc_add_to_set (dcc->sock, out_set, maxfd);

			libirc_mutex_unlock (&dcc->mutex_outbuf);
			break;

		case LIBIRC_STATE_CONFIRM_SIZE:
			/*
			 * If we're receiving file, then WE should confirm the transferred
             * part (so we have to sent data). But if we're sending the file, 
             * then RECEIVER should confirm the packet, so we have to receive
             * data.
             *
             * We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
             * can't change asynchronously.
             */
             if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
             	libirc_add_to_set (dcc->sock, out_set, maxfd);

             if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
				libirc_add_to_set (dcc->sock, in_set, maxfd);

             break;
		}
	}

	libirc_mutex_unlock (&ircsession->mutex_dcc);
}
Esempio n. 6
0
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
{
	irc_dcc_session_t * dcc;

	/*
	 * We need to use such a complex scheme here, because on every callback
     * a number of DCC sessions could be destroyed.
     */
	libirc_mutex_lock (&ircsession->mutex_dcc);

	for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
	{
		if ( dcc->state == LIBIRC_STATE_LISTENING
		&& FD_ISSET (dcc->sock, in_set) )
		{
			socklen_t len = sizeof(dcc->remote_addr);
			int nsock, err = 0;

			// New connection is available; accept it.
			if ( socket_accept (&dcc->sock, &nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
				err = LIBIRC_ERR_ACCEPT;

			// On success, change the active socket and change the state
			if ( err == 0 )
			{
				// close the listen socket, and replace it by a newly 
				// accepted
				socket_close (&dcc->sock);
				dcc->sock = nsock;
				dcc->state = LIBIRC_STATE_CONNECTED;
			}

			// If this is DCC chat, inform the caller about accept() 
			// success or failure.
			// Otherwise (DCC send) there is no reason.
			if ( dcc->dccmode == LIBIRC_DCC_CHAT )
			{
				libirc_mutex_unlock (&ircsession->mutex_dcc);
				(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
				libirc_mutex_lock (&ircsession->mutex_dcc);
			}

			if ( err )
				libirc_dcc_destroy_nolock (ircsession, dcc->id);
		}

		if ( dcc->state == LIBIRC_STATE_CONNECTING
		&& FD_ISSET (dcc->sock, out_set) )
		{
			// Now we have to determine whether the socket is connected 
			// or the connect is failed
			struct sockaddr_in saddr;
			socklen_t slen = sizeof(saddr);
			int err = 0;

			if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
				err = LIBIRC_ERR_CONNECT;

			// On success, change the state
			if ( err == 0 )
				dcc->state = LIBIRC_STATE_CONNECTED;

			// If this is DCC chat, inform the caller about connect()
			// success or failure.
			// Otherwise (DCC send) there is no reason.
			if ( dcc->dccmode == LIBIRC_DCC_CHAT )
			{
				libirc_mutex_unlock (&ircsession->mutex_dcc);
				(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
				libirc_mutex_lock (&ircsession->mutex_dcc);
			}

			if ( err )
				libirc_dcc_destroy_nolock (ircsession, dcc->id);
		}

		if ( dcc->state == LIBIRC_STATE_CONNECTED
		|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
		{
			if ( FD_ISSET (dcc->sock, in_set) )
			{
				int length, offset = 0, err = 0;
		
				unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;

				length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);

				if ( length < 0 )
				{
					err = LIBIRC_ERR_READ;
				}	
				else if ( length == 0 )
				{
					err = LIBIRC_ERR_CLOSED;

					if ( dcc->dccsend_file_fp )
					{
						fclose (dcc->dccsend_file_fp);
						dcc->dccsend_file_fp = 0;
					}
				}
				else
				{
					dcc->incoming_offset += length;

					if ( dcc->dccmode != LIBIRC_DCC_CHAT )
						offset = dcc->incoming_offset;
					else
						offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);

					/*
					 * In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
                     * callbacks (except there is an error). We just receive
                     * the data, and compare it with the amount sent.
                     */
					if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
					{
						if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
							abort();

						if ( dcc->incoming_offset == 4 )
						{
							unsigned int received_size = ntohl (*((unsigned int*)dcc->incoming_buf));

							// Sent size confirmed
							if ( dcc->file_confirm_offset == received_size )
							{
								dcc->state = LIBIRC_STATE_CONNECTED;
								dcc->incoming_offset = 0;
							}
							else
								err = LIBIRC_ERR_WRITE;
						}
					}
					else
					{
						/*
						 * If it is DCC_CHAT, we send a 0-terminated string 
						 * (which is smaller than offset). Otherwise we send
	                     * a full buffer. 
	                     */
						libirc_mutex_unlock (&ircsession->mutex_dcc);

						if ( dcc->dccmode != LIBIRC_DCC_CHAT )
						{
							if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
								abort();

							(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);

                            /*
                             * If the session is not terminated in callback,
                             * put the sent amount into the sent_packet_size_net_byteorder
                             */
                             if ( dcc->state != LIBIRC_STATE_REMOVED )
                             {
                             	dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
                             	dcc->file_confirm_offset += offset;
                             	*((unsigned int*)dcc->outgoing_buf) = htonl (dcc->file_confirm_offset);
                             	dcc->outgoing_offset = 4;
							}
						}
						else
							(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));

						libirc_mutex_lock (&ircsession->mutex_dcc);

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

						dcc->incoming_offset -= offset;
					}
				}

                /*
                 * If error arises somewhere above, we inform the caller 
                 * of failure, and destroy this session.
                 */
				if ( err )
				{
					libirc_mutex_unlock (&ircsession->mutex_dcc);
					(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
					libirc_mutex_lock (&ircsession->mutex_dcc);
					libirc_dcc_destroy_nolock (ircsession, dcc->id);
				}
			}

            /*
             * Session might be closed (with sock = -1) after the in_set 
             * processing, so before out_set processing we should check
             * for this case
			 */
			if ( dcc->state == LIBIRC_STATE_REMOVED )
				continue;

			/*
			 * Write bit set - we can send() something, and it won't block.
             */
			if ( FD_ISSET (dcc->sock, out_set) )
			{
				int length, offset, err = 0;

				/*
				 * Because in some cases outgoing_buf could be changed 
				 * asynchronously (by another thread), we should lock 
				 * it.
                 */
				libirc_mutex_lock (&dcc->mutex_outbuf);

				offset = dcc->outgoing_offset;
		
				if ( offset > 0 )
				{
					length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);

					if ( length < 0 )
						err = LIBIRC_ERR_WRITE;
					else if ( length == 0 )
						err = LIBIRC_ERR_CLOSED;
					else
					{
						/*
						 * If this was DCC_SENDFILE, and we just sent a packet,
						 * change the state to wait for confirmation (and store
						 * sent packet size)
	                     */
						if ( dcc->state == LIBIRC_STATE_CONNECTED
						&& dcc->dccmode == LIBIRC_DCC_SENDFILE )
						{
							dcc->file_confirm_offset += offset;
							dcc->state = LIBIRC_STATE_CONFIRM_SIZE;

							libirc_mutex_unlock (&ircsession->mutex_dcc);
							libirc_mutex_unlock (&dcc->mutex_outbuf);
							(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, offset);
							libirc_mutex_lock (&ircsession->mutex_dcc);
							libirc_mutex_lock (&dcc->mutex_outbuf);
						}

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

						dcc->outgoing_offset -= length;

						/*
						 * If we just sent the confirmation data, change state 
						 * back.
                         */
						if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
						&& dcc->dccmode == LIBIRC_DCC_RECVFILE
						&& dcc->outgoing_offset == 0 )
						{
							/*
							 * If the file is already received, we should inform
                             * the caller, and close the session.
                             */
							if ( dcc->received_file_size == dcc->file_confirm_offset )
                            {
								libirc_mutex_unlock (&ircsession->mutex_dcc);
								libirc_mutex_unlock (&dcc->mutex_outbuf);
								(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
								libirc_dcc_destroy_nolock (ircsession, dcc->id);
                            }
                            else
                            {
                            	/* Continue to receive the file */
								dcc->state = LIBIRC_STATE_CONNECTED;
							}
						}
					}
				}

				libirc_mutex_unlock (&dcc->mutex_outbuf);

                /*
                 * If error arises somewhere above, we inform the caller 
                 * of failure, and destroy this session.
                 */
				if ( err )
				{
					libirc_mutex_unlock (&ircsession->mutex_dcc);
					(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
					libirc_mutex_lock (&ircsession->mutex_dcc);

					libirc_dcc_destroy_nolock (ircsession, dcc->id);
				}
			}
		}
	}

	libirc_mutex_unlock (&ircsession->mutex_dcc);
}
Esempio n. 7
0
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
{
	irc_dcc_session_t * dcc;

	/*
	 * We need to use such a complex scheme here, because on every callback
     * a number of DCC sessions could be destroyed.
     */
	libirc_mutex_lock (&ircsession->mutex_dcc);

	for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
	{
		if ( dcc->state == LIBIRC_STATE_LISTENING
		&& FD_ISSET (dcc->sock, in_set) )
		{
			socklen_t len = sizeof(dcc->remote_addr);
			int nsock, err = 0;

			// New connection is available; accept it.
			if ( socket_accept (&dcc->sock, (socket_t*)&nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
				err = LIBIRC_ERR_ACCEPT;

			// On success, change the active socket and change the state
			if ( err == 0 )
			{
				// close the listen socket, and replace it by a newly
				// accepted
				socket_close (&dcc->sock);
				dcc->sock = nsock;
				dcc->state = LIBIRC_STATE_CONNECTED;
			}

			// If this is DCC chat, inform the caller about accept()
			// success or failure.
			// Otherwise (DCC send) there is no reason.
			if ( dcc->dccmode == LIBIRC_DCC_CHAT )
			{
				libirc_mutex_unlock (&ircsession->mutex_dcc);
				(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
				libirc_mutex_lock (&ircsession->mutex_dcc);
			}

			if ( err )
				libirc_dcc_destroy_nolock (ircsession, dcc->id);
		}

		if ( dcc->state == LIBIRC_STATE_CONNECTING
		&& FD_ISSET (dcc->sock, out_set) )
		{
			// Now we have to determine whether the socket is connected
			// or the connect is failed
			struct sockaddr_in saddr;
			socklen_t slen = sizeof(saddr);
			int err = 0;

			if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
				err = LIBIRC_ERR_CONNECT;

			// On success, change the state
			if ( err == 0 )
				dcc->state = LIBIRC_STATE_CONNECTED;

			// If this is DCC chat, inform the caller about connect()
			// success or failure.
			// Otherwise (DCC send) there is no reason.
			if ( dcc->dccmode == LIBIRC_DCC_CHAT )
			{
				libirc_mutex_unlock (&ircsession->mutex_dcc);
				(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
				libirc_mutex_lock (&ircsession->mutex_dcc);
			}

			if ( err )
				libirc_dcc_destroy_nolock (ircsession, dcc->id);
		}

		if ( dcc->state == LIBIRC_STATE_CONNECTED
		|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
		{
			if ( FD_ISSET (dcc->sock, in_set) )
			{
				int length, offset = 0, err = 0;

				unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;

				length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);

				if ( length < 0 )
				{
					err = LIBIRC_ERR_READ;
				}
				else if ( length == 0 )
				{
					err = LIBIRC_ERR_CLOSED;

					if ( dcc->dccsend_file_fp )
					{
						fclose (dcc->dccsend_file_fp);
						dcc->dccsend_file_fp = 0;
					}
				}
				else
				{
					dcc->incoming_offset += length;

					if ( dcc->dccmode != LIBIRC_DCC_CHAT )
						offset = dcc->incoming_offset;
					else
						offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);

					/*
					 * In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
                     * callbacks (except there is an error). We just receive
                     * the data, and compare it with the amount sent.
                     */
					if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
					{
						if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
							abort();

						if ( dcc->incoming_offset == 4 )
						{
							// The order is big-endian
							const unsigned char * bptr = (const unsigned char *) dcc->incoming_buf;
							unsigned int received_size = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8)  | bptr[3];

							// Sent size confirmed
							if ( dcc->file_confirm_offset == received_size )
							{
								dcc->state = LIBIRC_STATE_CONNECTED;
								dcc->incoming_offset = 0;
							}
							else
								err = LIBIRC_ERR_WRITE;
						}
					}
					else
					{
						/*
						 * If it is DCC_CHAT, we send a 0-terminated string
						 * (which is smaller than offset). Otherwise we send
	                     * a full buffer.
	                     */
						libirc_mutex_unlock (&ircsession->mutex_dcc);

						if ( dcc->dccmode != LIBIRC_DCC_CHAT )
						{
							if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
								abort();

							(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);

                            /*
                             * If the session is not terminated in callback,
                             * put the sent amount into the sent_packet_size_net_byteorder
                             */
                             if ( dcc->state != LIBIRC_STATE_REMOVED )
                             {
                             	dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
                             	dcc->file_confirm_offset += offset;

								// Store as big endian
								dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24;
								dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16;
								dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8;
								dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset;
                             	dcc->outgoing_offset = 4;
							}
						}
						else
							(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));

						libirc_mutex_lock (&ircsession->mutex_dcc);

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

						dcc->incoming_offset -= offset;
					}
				}

                /*
                 * If error arises somewhere above, we inform the caller
                 * of failure, and destroy this session.
                 */
				if ( err )
				{
					libirc_mutex_unlock (&ircsession->mutex_dcc);
					(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
					libirc_mutex_lock (&ircsession->mutex_dcc);
					libirc_dcc_destroy_nolock (ircsession, dcc->id);
				}
			}
Esempio n. 8
0
int irc_dcc_accept(irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback) {
    irc_dcc_session_t * dcc = libirc_find_dcc_session(session, dccid, 1);

    if (!dcc)
        return 1;

    if (dcc->state != LIBIRC_STATE_INIT) {
        session->lasterror = LIBIRC_ERR_STATE;
        libirc_mutex_unlock(&session->mutex_dcc);
        return 1;
    }

    dcc->cb = callback;
    dcc->ctx = ctx;

    DBG_OK("going to socket_connect!");

    // Initiate the connect

    if (socket_connect(&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof (dcc->remote_addr))) {
        libirc_dcc_destroy_nolock(session, dccid);
        libirc_mutex_unlock(&session->mutex_dcc);
        session->lasterror = LIBIRC_ERR_CONNECT;
        return 1;
    }
    
#ifdef ENABLE_SSL
    if (dcc->ssl == 1) {
        DBG_OK("using ssl!");

        while (1) {
            int err = SSL_connect(dcc->ssl_ctx);
            if (err <= 0) {
                int ssl_err = SSL_get_error(dcc->ssl_ctx, err);
                if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
                    continue;
                } else {
                    print_ssl_error_stack();
                    session->lasterror = LIBIRC_ERR_CONNECT;
                    return 1;
                }
            }
            DBG_OK("ssl_connect succeded!");
            break;
        }
        
        const char *ciphers_used = "None";
        ciphers_used = SSL_get_cipher_name(dcc->ssl_ctx);
        logprintf(LOG_INFO, "using cipher suite: %s for dcc connection", ciphers_used);
    }
#endif

    DBG_OK("connect succeded2!");

    dcc->state = LIBIRC_STATE_CONNECTING;
#ifdef ENABLE_SSL
    if (dcc->ssl) {
        dcc->state = LIBIRC_STATE_CONNECTED;
    }
#endif
    libirc_mutex_unlock(&session->mutex_dcc);
    return 0;
}
Esempio n. 9
0
static void recv_dcc_file(irc_session_t *ircsession, irc_dcc_session_t *dcc) {
    int rcvdBytes, err = 0;

    size_t amount = LIBIRC_DCC_BUFFER_SIZE;

    do {
#ifdef ENABLE_SSL
        if (dcc->ssl == 0)
            rcvdBytes = socket_recv(&dcc->sock, dcc->incoming_buf, amount);
        else {
            int sslError = 0;
            rcvdBytes = ssl_read_wrapper(ircsession, dcc, dcc->incoming_buf, amount, &sslError);

            if (sslError == SSL_ERROR_WANT_READ) {
                return;
            }
            else if (sslError == SSL_ERROR_WANT_WRITE) {
                dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
                return;
            }
        }
#else
        rcvdBytes = socket_recv(&dcc->sock, dcc->incoming_buf, amount);
#endif

        if (unlikely(rcvdBytes < 0)) {
            err = LIBIRC_ERR_READ;
        }
        else if (unlikely(rcvdBytes == 0)) {
            err = LIBIRC_ERR_CLOSED;
        }
        else {
            libirc_mutex_unlock(&ircsession->mutex_dcc);

            dcc->file_confirm_offset += rcvdBytes;
            (*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, rcvdBytes);
        
      /* if DONT_CONFIRM_OFFSETS_FLAG is set dont send the file offset to the bots
           because some bots dont want to receive the file offsets...*/
            if (cfg_get_bit(getCfg(), DONT_CONFIRM_OFFSETS_FLAG)) {
                dcc->state = LIBIRC_STATE_CONNECTED;
	    } else {
                dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
	    }
	    
            libirc_mutex_lock(&ircsession->mutex_dcc);
        }

        /*
         * If error arises somewhere above, we inform the caller 
         * of failure, and destroy this session.
         */
        if (unlikely(err)) {
            libirc_mutex_unlock(&ircsession->mutex_dcc);
            (*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
            libirc_mutex_lock(&ircsession->mutex_dcc);
            libirc_dcc_destroy_nolock(ircsession, dcc->id);
            return;
        }
    }
    while (hasSocketPendingData(dcc));
}