void irc_destroy_session (irc_session_t * session) { if ( session->sock >= 0 ) socket_close (&session->sock); if ( session->realname ) free (session->realname); if ( session->username ) free (session->username); if ( session->nick ) free (session->nick); if ( session->server ) free (session->server); if ( session->server_password ) free (session->server_password); #if defined (ENABLE_THREADS) libirc_mutex_destroy (&session->mutex_session); #endif /* * delete DCC data * libirc_remove_dcc_session removes the DCC session from the list. */ while ( session->dcc_sessions ) libirc_remove_dcc_session (session, session->dcc_sessions, 0); free (session); }
void irc_destroy_session (irc_session_t * session) { free_ircsession_strings( session ); // The CTCP VERSION must be freed only now if ( session->ctcp_version ) free (session->ctcp_version); if ( session->sock >= 0 ) socket_close (&session->sock); #if defined (ENABLE_THREADS) libirc_mutex_destroy (&session->mutex_session); #endif #if defined (ENABLE_SSL) if ( session->ssl ) SSL_free( session->ssl ); #endif /* * delete DCC data * libirc_remove_dcc_session removes the DCC session from the list. */ while ( session->dcc_sessions ) libirc_remove_dcc_session (session, session->dcc_sessions, 0); libirc_mutex_destroy (&session->mutex_dcc); free (session); }
int irc_dcc_chat (irc_session_t * session, void * ctx, const char * nick, irc_dcc_callback_t callback, irc_dcc_t * dccid) { struct sockaddr_in saddr; socklen_t len = sizeof(saddr); char cmdbuf[128], notbuf[128]; irc_dcc_session_t * dcc; int err; if ( session->state != LIBIRC_STATE_CONNECTED ) { session->lasterror = LIBIRC_ERR_STATE; return 1; } err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_CHAT, ctx, &dcc); if ( err ) { session->lasterror = err; return 1; } if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 ) { session->lasterror = LIBIRC_ERR_SOCKET; libirc_remove_dcc_session (session, dcc, 1); return 1; } sprintf (notbuf, "DCC Chat (%s)", inet_ntoa (saddr.sin_addr)); sprintf (cmdbuf, "DCC CHAT chat %lu %u", (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port)); if ( irc_cmd_notice (session, nick, notbuf) || irc_cmd_ctcp_request (session, nick, cmdbuf) ) { libirc_remove_dcc_session (session, dcc, 1); return 1; } *dccid = dcc->id; dcc->cb = callback; dcc->dccmode = LIBIRC_DCC_CHAT; return 0; }
static void libirc_dcc_add_descriptors(irc_session_t * ircsession) { irc_dcc_session_t * dcc, *dcc_next; 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; // 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) { fdwatch_add_fd(dcc->sock); switch (dcc->state) { case LIBIRC_STATE_CONNECTING: // While connection, only out_set descriptor should be set fdwatch_set_fd(dcc->sock, FDW_WRITE); break; case LIBIRC_STATE_CONNECTED: fdwatch_set_fd(dcc->sock, FDW_READ); break; case LIBIRC_STATE_CONFIRM_SIZE: fdwatch_set_fd(dcc->sock, FDW_WRITE); break; case LIBIRC_STATE_WAITING_FOR_RESUME_ACK: break; default: DBG_WARN("unknown state at libirc_dcc_add_descriptors"); break; } } libirc_mutex_unlock(&ircsession->mutex_dcc); }
void irc_destroy_session(irc_session_t * session) { free_ircsession_strings(session); if (session->sock >= 0) socket_close(&session->sock); #if defined (ENABLE_THREADS) libirc_mutex_destroy(&session->mutex_session); #endif while (session->dcc_sessions) libirc_remove_dcc_session(session, session->dcc_sessions, 0); free_line_parser(session->line_parser); fdwatch_free(); #ifdef ENABLE_SSL if (session->ssl) SSL_free(session->ssl); #endif free(session); }
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); }
int irc_dcc_sendfile (irc_session_t * session, void * ctx, const char * nick, const char * filename, irc_dcc_callback_t callback, irc_dcc_t * dccid) { struct sockaddr_in saddr; socklen_t len = sizeof(saddr); char cmdbuf[128], notbuf[128]; irc_dcc_session_t * dcc; const char * p; int err; long filesize; if ( !session || !dccid || !filename || !callback ) { session->lasterror = LIBIRC_ERR_INVAL; return 1; } if ( session->state != LIBIRC_STATE_CONNECTED ) { session->lasterror = LIBIRC_ERR_STATE; return 1; } if ( (err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_SENDFILE, ctx, &dcc)) != 0 ) { session->lasterror = err; return 1; } if ( (dcc->dccsend_file_fp = fopen (filename, "rb")) == 0 ) { libirc_remove_dcc_session (session, dcc, 1); session->lasterror = LIBIRC_ERR_OPENFILE; return 1; } /* Get file length */ if ( fseek (dcc->dccsend_file_fp, 0, SEEK_END) || (filesize = ftell (dcc->dccsend_file_fp)) == -1 || fseek (dcc->dccsend_file_fp, 0, SEEK_SET) ) { libirc_remove_dcc_session (session, dcc, 1); session->lasterror = LIBIRC_ERR_NODCCSEND; return 1; } if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 ) { libirc_remove_dcc_session (session, dcc, 1); session->lasterror = LIBIRC_ERR_SOCKET; return 1; } // Remove path from the filename if ( (p = strrchr (filename, '\\')) == 0 && (p = strrchr (filename, '/')) == 0 ) p = filename; else p++; // skip directory slash sprintf (notbuf, "DCC Send %s (%s)", p, inet_ntoa (saddr.sin_addr)); sprintf (cmdbuf, "DCC SEND %s %lu %u %ld", p, (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port), filesize); if ( irc_cmd_notice (session, nick, notbuf) || irc_cmd_ctcp_request (session, nick, cmdbuf) ) { libirc_remove_dcc_session (session, dcc, 1); return 1; } *dccid = dcc->id; dcc->cb = callback; return 0; }