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; }
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); } }
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; }
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); } }
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); }
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); }
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); } }
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; }
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)); }