more fixes, should work now

This commit is contained in:
Green Sky 2023-11-23 00:01:55 +01:00
parent 3b3b50b7ec
commit 3bf7660b85
No known key found for this signature in database
12 changed files with 428 additions and 341 deletions

View File

@ -17,11 +17,13 @@ add_library(libircclient
./libircclient/src/errors.c ./libircclient/src/errors.c
./libircclient/src/libircclient.c ./libircclient/src/libircclient.c
./libircclient/src/params.h ./libircclient/src/params.h
./libircclient/src/portable.h
./libircclient/src/portable.c ./libircclient/src/portable.c
./libircclient/src/session.h ./libircclient/src/session.h
./libircclient/src/sockets.c ./libircclient/src/sockets.h
./libircclient/src/ssl.h
./libircclient/src/ssl.c ./libircclient/src/ssl.c
./libircclient/src/utils.c ./libircclient/src/utils.h
) )
target_include_directories(libircclient PUBLIC ./libircclient/include) target_include_directories(libircclient PUBLIC ./libircclient/include)

View File

@ -1,14 +1,14 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
@ -16,6 +16,11 @@
#define LIBIRC_DCC_SENDFILE 2 #define LIBIRC_DCC_SENDFILE 2
#define LIBIRC_DCC_RECVFILE 3 #define LIBIRC_DCC_RECVFILE 3
#include "./session.h"
#include "./utils.h"
#include <stdio.h>
#include <string.h>
static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list) static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list)
{ {
@ -54,7 +59,7 @@ static void libirc_dcc_destroy_nolock (irc_session_t * session, irc_dcc_t dccid)
} }
static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list) void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list)
{ {
if ( dcc->sock >= 0 ) if ( dcc->sock >= 0 )
socket_close (&dcc->sock); socket_close (&dcc->sock);
@ -91,7 +96,7 @@ static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_
} }
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd) 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; irc_dcc_session_t * dcc, *dcc_next;
time_t now = time (0); time_t now = time (0);
@ -129,8 +134,8 @@ static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_s
/* /*
* If we're sending file, and the output buffer is empty, we need * If we're sending file, and the output buffer is empty, we need
* to provide some data. * to provide some data.
*/ */
if ( dcc->state == LIBIRC_STATE_CONNECTED if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->dccmode == LIBIRC_DCC_SENDFILE
&& dcc->dccsend_file_fp && dcc->dccsend_file_fp
@ -141,7 +146,7 @@ static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_s
if ( len <= 0 ) if ( len <= 0 )
{ {
int err = (len < 0 ? LIBIRC_ERR_READ : 0); int err = (len < 0 ? LIBIRC_ERR_READ : 0);
libirc_mutex_unlock (&ircsession->mutex_dcc); libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0); (*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
@ -189,17 +194,17 @@ static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_s
case LIBIRC_STATE_CONFIRM_SIZE: case LIBIRC_STATE_CONFIRM_SIZE:
/* /*
* If we're receiving file, then WE should confirm the transferred * 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, * 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 * then RECEIVER should confirm the packet, so we have to receive
* data. * data.
* *
* We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers * We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
* can't change asynchronously. * can't change asynchronously.
*/ */
if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 ) if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
libirc_add_to_set (dcc->sock, out_set, maxfd); libirc_add_to_set (dcc->sock, out_set, maxfd);
if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 ) if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
libirc_add_to_set (dcc->sock, in_set, maxfd); libirc_add_to_set (dcc->sock, in_set, maxfd);
} }
} }
@ -208,14 +213,14 @@ static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_s
} }
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set) void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
{ {
irc_dcc_session_t * dcc; irc_dcc_session_t * dcc;
/* /*
* We need to use such a complex scheme here, because on every callback * We need to use such a complex scheme here, because on every callback
* a number of DCC sessions could be destroyed. * a number of DCC sessions could be destroyed.
*/ */
libirc_mutex_lock (&ircsession->mutex_dcc); libirc_mutex_lock (&ircsession->mutex_dcc);
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next ) for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
@ -238,14 +243,14 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
// On success, change the active socket and change the state // On success, change the active socket and change the state
if ( err == 0 ) if ( err == 0 )
{ {
// close the listen socket, and replace it by a newly // close the listen socket, and replace it by a newly
// accepted // accepted
socket_close (&dcc->sock); socket_close (&dcc->sock);
dcc->sock = nsock; dcc->sock = nsock;
dcc->state = LIBIRC_STATE_CONNECTED; dcc->state = LIBIRC_STATE_CONNECTED;
} }
// If this is DCC chat, inform the caller about accept() // If this is DCC chat, inform the caller about accept()
// success or failure. // success or failure.
// Otherwise (DCC send) there is no reason. // Otherwise (DCC send) there is no reason.
if ( dcc->dccmode == LIBIRC_DCC_CHAT ) if ( dcc->dccmode == LIBIRC_DCC_CHAT )
@ -262,7 +267,7 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
if ( dcc->state == LIBIRC_STATE_CONNECTING if ( dcc->state == LIBIRC_STATE_CONNECTING
&& FD_ISSET (dcc->sock, out_set) ) && FD_ISSET (dcc->sock, out_set) )
{ {
// Now we have to determine whether the socket is connected // Now we have to determine whether the socket is connected
// or the connect is failed // or the connect is failed
struct sockaddr_in saddr; struct sockaddr_in saddr;
socklen_t slen = sizeof(saddr); socklen_t slen = sizeof(saddr);
@ -295,7 +300,7 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
if ( FD_ISSET (dcc->sock, in_set) ) if ( FD_ISSET (dcc->sock, in_set) )
{ {
int length, offset = 0, err = 0; int length, offset = 0, err = 0;
unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset; unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;
length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount); length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);
@ -303,7 +308,7 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
if ( length < 0 ) if ( length < 0 )
{ {
err = LIBIRC_ERR_READ; err = LIBIRC_ERR_READ;
} }
else if ( length == 0 ) else if ( length == 0 )
{ {
err = LIBIRC_ERR_CLOSED; err = LIBIRC_ERR_CLOSED;
@ -325,9 +330,9 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
/* /*
* In LIBIRC_STATE_CONFIRM_SIZE state we don't call any * In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
* callbacks (except there is an error). We just receive * callbacks (except there is an error). We just receive
* the data, and compare it with the amount sent. * the data, and compare it with the amount sent.
*/ */
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE ) if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
{ {
if ( dcc->dccmode != LIBIRC_DCC_SENDFILE ) if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
@ -352,10 +357,10 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
else else
{ {
/* /*
* If it is DCC_CHAT, we send a 0-terminated string * If it is DCC_CHAT, we send a 0-terminated string
* (which is smaller than offset). Otherwise we send * (which is smaller than offset). Otherwise we send
* a full buffer. * a full buffer.
*/ */
libirc_mutex_unlock (&ircsession->mutex_dcc); libirc_mutex_unlock (&ircsession->mutex_dcc);
if ( dcc->dccmode != LIBIRC_DCC_CHAT ) if ( dcc->dccmode != LIBIRC_DCC_CHAT )
@ -365,21 +370,21 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset); (*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);
/* /*
* If the session is not terminated in callback, * If the session is not terminated in callback,
* put the sent amount into the sent_packet_size_net_byteorder * put the sent amount into the sent_packet_size_net_byteorder
*/ */
if ( dcc->state != LIBIRC_STATE_REMOVED ) if ( dcc->state != LIBIRC_STATE_REMOVED )
{ {
dcc->state = LIBIRC_STATE_CONFIRM_SIZE; dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
dcc->file_confirm_offset += offset; dcc->file_confirm_offset += offset;
// Store as big endian // Store as big endian
dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24; dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24;
dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16; dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16;
dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8; dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8;
dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset; dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset;
dcc->outgoing_offset = 4; dcc->outgoing_offset = 4;
} }
} }
else else
@ -394,10 +399,10 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
} }
} }
/* /*
* If error arises somewhere above, we inform the caller * If error arises somewhere above, we inform the caller
* of failure, and destroy this session. * of failure, and destroy this session.
*/ */
if ( err ) if ( err )
{ {
libirc_mutex_unlock (&ircsession->mutex_dcc); libirc_mutex_unlock (&ircsession->mutex_dcc);
@ -407,30 +412,30 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
} }
} }
/* /*
* Session might be closed (with sock = -1) after the in_set * Session might be closed (with sock = -1) after the in_set
* processing, so before out_set processing we should check * processing, so before out_set processing we should check
* for this case * for this case
*/ */
if ( dcc->state == LIBIRC_STATE_REMOVED ) if ( dcc->state == LIBIRC_STATE_REMOVED )
continue; continue;
/* /*
* Write bit set - we can send() something, and it won't block. * Write bit set - we can send() something, and it won't block.
*/ */
if ( FD_ISSET (dcc->sock, out_set) ) if ( FD_ISSET (dcc->sock, out_set) )
{ {
int length, offset, err = 0; int length, offset, err = 0;
/* /*
* Because in some cases outgoing_buf could be changed * Because in some cases outgoing_buf could be changed
* asynchronously (by another thread), we should lock * asynchronously (by another thread), we should lock
* it. * it.
*/ */
libirc_mutex_lock (&dcc->mutex_outbuf); libirc_mutex_lock (&dcc->mutex_outbuf);
offset = dcc->outgoing_offset; offset = dcc->outgoing_offset;
if ( offset > 0 ) if ( offset > 0 )
{ {
length = socket_send (&dcc->sock, dcc->outgoing_buf, offset); length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);
@ -445,7 +450,7 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
* If this was DCC_SENDFILE, and we just sent a packet, * If this was DCC_SENDFILE, and we just sent a packet,
* change the state to wait for confirmation (and store * change the state to wait for confirmation (and store
* sent packet size) * sent packet size)
*/ */
if ( dcc->state == LIBIRC_STATE_CONNECTED if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE ) && dcc->dccmode == LIBIRC_DCC_SENDFILE )
{ {
@ -465,27 +470,27 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
dcc->outgoing_offset -= length; dcc->outgoing_offset -= length;
/* /*
* If we just sent the confirmation data, change state * If we just sent the confirmation data, change state
* back. * back.
*/ */
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
&& dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->dccmode == LIBIRC_DCC_RECVFILE
&& dcc->outgoing_offset == 0 ) && dcc->outgoing_offset == 0 )
{ {
/* /*
* If the file is already received, we should inform * If the file is already received, we should inform
* the caller, and close the session. * the caller, and close the session.
*/ */
if ( dcc->received_file_size == dcc->file_confirm_offset ) if ( dcc->received_file_size == dcc->file_confirm_offset )
{ {
libirc_mutex_unlock (&ircsession->mutex_dcc); libirc_mutex_unlock (&ircsession->mutex_dcc);
libirc_mutex_unlock (&dcc->mutex_outbuf); libirc_mutex_unlock (&dcc->mutex_outbuf);
(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0); (*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
libirc_dcc_destroy_nolock (ircsession, dcc->id); libirc_dcc_destroy_nolock (ircsession, dcc->id);
} }
else else
{ {
/* Continue to receive the file */ /* Continue to receive the file */
dcc->state = LIBIRC_STATE_CONNECTED; dcc->state = LIBIRC_STATE_CONNECTED;
} }
} }
@ -494,10 +499,10 @@ static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *
libirc_mutex_unlock (&dcc->mutex_outbuf); libirc_mutex_unlock (&dcc->mutex_outbuf);
/* /*
* If error arises somewhere above, we inform the caller * If error arises somewhere above, we inform the caller
* of failure, and destroy this session. * of failure, and destroy this session.
*/ */
if ( err ) if ( err )
{ {
libirc_mutex_unlock (&ircsession->mutex_dcc); libirc_mutex_unlock (&ircsession->mutex_dcc);
@ -578,7 +583,7 @@ static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, un
memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr)); memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr));
dcc->remote_addr.sin_family = AF_INET; dcc->remote_addr.sin_family = AF_INET;
dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder? dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder?
dcc->remote_addr.sin_port = htons(port); dcc->remote_addr.sin_port = htons(port);
dcc->state = LIBIRC_STATE_INIT; dcc->state = LIBIRC_STATE_INIT;
} }
@ -596,8 +601,8 @@ static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, un
libirc_mutex_unlock (&session->mutex_dcc); libirc_mutex_unlock (&session->mutex_dcc);
*pdcc = dcc; *pdcc = dcc;
return 0; return 0;
cleanup_exit_error: cleanup_exit_error:
if ( dcc->sock >= 0 ) if ( dcc->sock >= 0 )
@ -710,7 +715,7 @@ int irc_dcc_msg (irc_session_t * session, irc_dcc_t dccid, const char * text)
} }
static void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req) void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req)
{ {
char filenamebuf[256]; char filenamebuf[256];
unsigned long ip, size; unsigned long ip, size;
@ -729,8 +734,8 @@ static void libirc_dcc_request (irc_session_t * session, const char * nick, cons
return; return;
} }
(*session->callbacks.event_dcc_chat_req) (session, (*session->callbacks.event_dcc_chat_req) (session,
nick, nick,
inet_ntoa (dcc->remote_addr.sin_addr), inet_ntoa (dcc->remote_addr.sin_addr),
dcc->id); dcc->id);
} }
@ -750,8 +755,8 @@ static void libirc_dcc_request (irc_session_t * session, const char * nick, cons
return; return;
} }
(*session->callbacks.event_dcc_send_req) (session, (*session->callbacks.event_dcc_send_req) (session,
nick, nick,
inet_ntoa (dcc->remote_addr.sin_addr), inet_ntoa (dcc->remote_addr.sin_addr),
filenamebuf, filenamebuf,
size, size,
@ -787,7 +792,7 @@ int irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dc
dcc->ctx = ctx; dcc->ctx = ctx;
// Initiate the connect // Initiate the connect
if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) ) if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
{ {
libirc_dcc_destroy_nolock (session, dccid); libirc_dcc_destroy_nolock (session, dccid);
libirc_mutex_unlock (&session->mutex_dcc); libirc_mutex_unlock (&session->mutex_dcc);

View File

@ -1,20 +1,27 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
#ifndef INCLUDE_IRC_DCC_H #ifndef INCLUDE_IRC_DCC_H
#define INCLUDE_IRC_DCC_H #define INCLUDE_IRC_DCC_H
#include <stdio.h>
#include "../include/libircclient.h"
#include "./sockets.h"
#include "./portable.h"
#include "./params.h"
/* /*
* This structure keeps the state of a single DCC connection. * This structure keeps the state of a single DCC connection.
@ -26,11 +33,11 @@ struct irc_dcc_session_s
irc_dcc_t id; irc_dcc_t id;
void * ctx; void * ctx;
socket_t sock; /*!< DCC socket */ socket_t sock; /*!< DCC socket */
int dccmode; /*!< Boolean value to differ chat vs send int dccmode; /*!< Boolean value to differ chat vs send
requests. Changes the cb behavior - when requests. Changes the cb behavior - when
it is chat, data is sent by lines with it is chat, data is sent by lines with
stripped CRLFs. In file mode, the data stripped CRLFs. In file mode, the data
is sent as-is */ is sent as-is */
int state; int state;
time_t timeout; time_t timeout;
@ -50,5 +57,9 @@ struct irc_dcc_session_s
irc_dcc_callback_t cb; irc_dcc_callback_t cb;
}; };
void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list);
void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd);
void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req);
void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set);
#endif /* INCLUDE_IRC_DCC_H */ #endif /* INCLUDE_IRC_DCC_H */

View File

@ -1,18 +1,21 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
static const char * libirc_strerror[LIBIRC_ERR_MAX] = #include "../include/libircclient.h"
#include "./session.h"
static const char * libirc_strerror[LIBIRC_ERR_MAX] =
{ {
"No error", "No error",
"Invalid argument", "Invalid argument",

View File

@ -14,17 +14,19 @@
#define IS_DEBUG_ENABLED(s) ((s)->options & LIBIRC_OPTION_DEBUG) #define IS_DEBUG_ENABLED(s) ((s)->options & LIBIRC_OPTION_DEBUG)
#include "portable.c" #include "./portable.h"
#include "sockets.c" #include "./sockets.h"
#include "libircclient.h" #include "../include/libircclient.h"
#include "session.h" #include "./session.h"
#include "utils.c" #include "./utils.h"
#include "errors.c" /*#include "errors.c"*/
#include "colors.c" /*#include "colors.c"*/
#include "dcc.c" #include "./dcc.h"
#include "ssl.c" /*#include "dcc.c"*/
/*#include "ssl.c"*/
#include "./ssl.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -797,11 +799,11 @@ static void libirc_process_incoming_data (irc_session_t * session, size_t proces
{ {
; /* ignore this event - not all servers generate this */ ; /* ignore this event - not all servers generate this */
} }
else else
{ {
/* /*
* The "unknown" event is triggered upon receipt of any number of * The "unknown" event is triggered upon receipt of any number of
* unclassifiable miscellaneous messages, which aren't handled by * unclassifiable miscellaneous messages, which aren't handled by
* the library. * the library.
*/ */
@ -816,7 +818,7 @@ int irc_process_select_descriptors (irc_session_t * session, fd_set *in_set, fd_
{ {
char buf[256], hname[256]; char buf[256], hname[256];
if ( session->sock < 0 if ( session->sock < 0
|| session->state == LIBIRC_STATE_INIT || session->state == LIBIRC_STATE_INIT
|| session->state == LIBIRC_STATE_DISCONNECTED ) || session->state == LIBIRC_STATE_DISCONNECTED )
{ {
@ -833,7 +835,7 @@ int irc_process_select_descriptors (irc_session_t * session, fd_set *in_set, fd_
// If the socket is not connected yet, wait longer - it is not an error // If the socket is not connected yet, wait longer - it is not an error
if ( !FD_ISSET (session->sock, out_set) ) if ( !FD_ISSET (session->sock, out_set) )
return 0; return 0;
// Now we have to determine whether the socket is connected // Now we have to determine whether the socket is connected
// or the connect is failed // or the connect is failed
struct sockaddr_storage saddr, laddr; struct sockaddr_storage saddr, laddr;

View File

@ -1,132 +1,18 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
#if !defined (_WIN32) #include "./portable.h"
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#if defined (ENABLE_THREADS)
#include <pthread.h>
typedef pthread_mutex_t port_mutex_t;
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
#endif
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#if defined (ENABLE_THREADS)
typedef CRITICAL_SECTION port_mutex_t;
#endif
#define inline
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#endif
#if defined (ENABLE_SSL)
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#endif
#if defined (ENABLE_THREADS)
static inline int libirc_mutex_init (port_mutex_t * mutex)
{
#if defined (_WIN32)
InitializeCriticalSection (mutex);
return 0;
#elif defined (PTHREAD_MUTEX_RECURSIVE)
pthread_mutexattr_t attr;
return (pthread_mutexattr_init (&attr)
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|| pthread_mutex_init (mutex, &attr));
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
return pthread_mutex_init (mutex, 0);
#endif /* defined (_WIN32) */
}
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
{
#if defined (_WIN32)
DeleteCriticalSection (mutex);
#else
pthread_mutex_destroy (mutex);
#endif
}
static inline void libirc_mutex_lock (port_mutex_t * mutex)
{
#if defined (_WIN32)
EnterCriticalSection (mutex);
#else
pthread_mutex_lock (mutex);
#endif
}
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
{
#if defined (_WIN32)
LeaveCriticalSection (mutex);
#else
pthread_mutex_unlock (mutex);
#endif
}
#else
typedef void * port_mutex_t;
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
#endif
/* /*
* Stub for WIN32 dll to initialize winsock API * Stub for WIN32 dll to initialize winsock API

133
libircclient/src/portable.h Normal file
View File

@ -0,0 +1,133 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_PORTABLE_H
#define INCLUDE_IRC_PORTABLE_H
#if !defined (_WIN32)
//#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#if defined (ENABLE_THREADS)
#include <pthread.h>
typedef pthread_mutex_t port_mutex_t;
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
#endif
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#if defined (ENABLE_THREADS)
typedef CRITICAL_SECTION port_mutex_t;
#endif
#define inline
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#endif
#if defined (ENABLE_SSL)
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#endif
#if defined (ENABLE_THREADS)
static inline int libirc_mutex_init (port_mutex_t * mutex)
{
#if defined (_WIN32)
InitializeCriticalSection (mutex);
return 0;
#elif defined (PTHREAD_MUTEX_RECURSIVE)
pthread_mutexattr_t attr;
return (pthread_mutexattr_init (&attr)
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|| pthread_mutex_init (mutex, &attr));
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
return pthread_mutex_init (mutex, 0);
#endif /* defined (_WIN32) */
}
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
{
#if defined (_WIN32)
DeleteCriticalSection (mutex);
#else
pthread_mutex_destroy (mutex);
#endif
}
static inline void libirc_mutex_lock (port_mutex_t * mutex)
{
#if defined (_WIN32)
EnterCriticalSection (mutex);
#else
pthread_mutex_lock (mutex);
#endif
}
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
{
#if defined (_WIN32)
LeaveCriticalSection (mutex);
#else
pthread_mutex_unlock (mutex);
#endif
}
#else
typedef void * port_mutex_t;
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
#endif
#endif /* INCLUDE_IRC_PORTABLE_H */

View File

@ -17,9 +17,9 @@
#define INCLUDE_IRC_SESSION_H #define INCLUDE_IRC_SESSION_H
#include "params.h" #include "./params.h"
#include "dcc.h" #include "./dcc.h"
#include "libirc_events.h" #include "../include/libirc_events.h"
// Session flags // Session flags

View File

@ -12,6 +12,9 @@
* License for more details. * License for more details.
*/ */
#ifndef INCLUDE_IRC_SOCKET_H
#define INCLUDE_IRC_SOCKET_H
/* /*
* The sockets interface was moved out to simplify going OpenSSL integration. * The sockets interface was moved out to simplify going OpenSSL integration.
*/ */
@ -159,3 +162,5 @@ static int socket_send (socket_t * sock, const void *buf, size_t len)
return length; return length;
} }
#endif /* INCLUDE_IRC_SOCKET_H */

View File

@ -1,17 +1,21 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
#include "./ssl.h"
#include "../include/libircclient.h"
#include "./session.h"
#if defined (ENABLE_SSL) #if defined (ENABLE_SSL)
@ -26,22 +30,22 @@ static CRITICAL_SECTION * mutex_buf = 0;
// OpenSSL callback to utilize static locks // OpenSSL callback to utilize static locks
static void cb_openssl_locking_function( int mode, int n, const char * file, int line ) static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
{ {
if ( mode & CRYPTO_LOCK) if ( mode & CRYPTO_LOCK)
EnterCriticalSection( &mutex_buf[n] ); EnterCriticalSection( &mutex_buf[n] );
else else
LeaveCriticalSection( &mutex_buf[n] ); LeaveCriticalSection( &mutex_buf[n] );
} }
// OpenSSL callback to get the thread ID // OpenSSL callback to get the thread ID
static unsigned long cb_openssl_id_function(void) static unsigned long cb_openssl_id_function(void)
{ {
return ((unsigned long) GetCurrentThreadId() ); return ((unsigned long) GetCurrentThreadId() );
} }
static int alloc_mutexes( unsigned int total ) static int alloc_mutexes( unsigned int total )
{ {
unsigned int i; unsigned int i;
// Enable thread safety in OpenSSL // Enable thread safety in OpenSSL
mutex_buf = (CRITICAL_SECTION*) malloc( total * sizeof(CRITICAL_SECTION) ); mutex_buf = (CRITICAL_SECTION*) malloc( total * sizeof(CRITICAL_SECTION) );
@ -50,7 +54,7 @@ static int alloc_mutexes( unsigned int total )
for ( i = 0; i < total; i++) for ( i = 0; i < total; i++)
InitializeCriticalSection( &(mutex_buf[i]) ); InitializeCriticalSection( &(mutex_buf[i]) );
return 0; return 0;
} }
@ -63,13 +67,13 @@ static pthread_mutex_t * mutex_buf = 0;
// OpenSSL callback to utilize static locks // OpenSSL callback to utilize static locks
static void cb_openssl_locking_function( int mode, int n, const char * file, int line ) static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
{ {
(void)file; (void)file;
(void)line; (void)line;
if ( mode & CRYPTO_LOCK) if ( mode & CRYPTO_LOCK)
pthread_mutex_lock( &mutex_buf[n] ); pthread_mutex_lock( &mutex_buf[n] );
else else
pthread_mutex_unlock( &mutex_buf[n] ); pthread_mutex_unlock( &mutex_buf[n] );
} }
// OpenSSL callback to get the thread ID // OpenSSL callback to get the thread ID
@ -82,7 +86,7 @@ static void cb_openssl_id_function( CRYPTO_THREADID * id )
static int alloc_mutexes( unsigned int total ) static int alloc_mutexes( unsigned int total )
{ {
unsigned i; unsigned i;
// Enable thread safety in OpenSSL // Enable thread safety in OpenSSL
mutex_buf = (pthread_mutex_t*) malloc( total * sizeof(pthread_mutex_t) ); mutex_buf = (pthread_mutex_t*) malloc( total * sizeof(pthread_mutex_t) );
@ -91,7 +95,7 @@ static int alloc_mutexes( unsigned int total )
for ( i = 0; i < total; i++) for ( i = 0; i < total; i++)
pthread_mutex_init( &(mutex_buf[i]), 0 ); pthread_mutex_init( &(mutex_buf[i]), 0 );
return 0; return 0;
} }
@ -115,7 +119,7 @@ static int ssl_init_context( irc_session_t * session )
SSL_library_init(); SSL_library_init();
#else #else
OPENSSL_init_ssl(0, NULL); OPENSSL_init_ssl(0, NULL);
#endif #endif
if ( RAND_status() == 0 ) if ( RAND_status() == 0 )
return LIBIRC_ERR_SSL_INIT_FAILED; return LIBIRC_ERR_SSL_INIT_FAILED;
@ -139,13 +143,13 @@ static int ssl_init_context( irc_session_t * session )
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_NONE, 0 ); SSL_CTX_set_verify( ssl_context, SSL_VERIFY_NONE, 0 );
else else
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_PEER, 0 ); SSL_CTX_set_verify( ssl_context, SSL_VERIFY_PEER, 0 );
// Disable session caching // Disable session caching
SSL_CTX_set_session_cache_mode( ssl_context, SSL_SESS_CACHE_OFF ); SSL_CTX_set_session_cache_mode( ssl_context, SSL_SESS_CACHE_OFF );
// Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER so we can move the buffer during sending // Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER so we can move the buffer during sending
SSL_CTX_set_mode( ssl_context, SSL_CTX_get_mode(ssl_context) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE ); SSL_CTX_set_mode( ssl_context, SSL_CTX_get_mode(ssl_context) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );
return 0; return 0;
} }
@ -162,13 +166,13 @@ static int ssl_init_context( irc_session_t * session )
static int ssl_init( irc_session_t * session ) static int ssl_init( irc_session_t * session )
{ {
static int ssl_context_initialized = 0; static int ssl_context_initialized = 0;
#if defined (_WIN32) #if defined (_WIN32)
static HANDLE initmutex = 0; static HANDLE initmutex = 0;
// First time run? Create the mutex // First time run? Create the mutex
if ( initmutex == 0 ) if ( initmutex == 0 )
{ {
HANDLE m = CreateMutex( 0, FALSE, 0 ); HANDLE m = CreateMutex( 0, FALSE, 0 );
// Now we check if the mutex has already been created by another thread performing the init concurrently. // Now we check if the mutex has already been created by another thread performing the init concurrently.
@ -180,28 +184,28 @@ static int ssl_init( irc_session_t * session )
#else #else
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
#endif #endif
// This initialization needs to be performed only once. The problem is that it is called from // This initialization needs to be performed only once. The problem is that it is called from
// irc_connect() and this function may be called simultaneously from different threads. So we have // irc_connect() and this function may be called simultaneously from different threads. So we have
// to use mutex on Linux because it allows static mutex initialization. Windows doesn't, so here // to use mutex on Linux because it allows static mutex initialization. Windows doesn't, so here
// we do the sabre dance around it. // we do the sabre dance around it.
SSLINIT_LOCK_MUTEX( initmutex ); SSLINIT_LOCK_MUTEX( initmutex );
if ( ssl_context_initialized == 0 ) if ( ssl_context_initialized == 0 )
{ {
int res = ssl_init_context( session ); int res = ssl_init_context( session );
if ( res ) if ( res )
{ {
SSLINIT_UNLOCK_MUTEX( initmutex ); SSLINIT_UNLOCK_MUTEX( initmutex );
return res; return res;
} }
ssl_context_initialized = 1; ssl_context_initialized = 1;
} }
SSLINIT_UNLOCK_MUTEX( initmutex ); SSLINIT_UNLOCK_MUTEX( initmutex );
// Get the SSL context // Get the SSL context
session->ssl = SSL_new( ssl_context ); session->ssl = SSL_new( ssl_context );
@ -211,7 +215,7 @@ static int ssl_init( irc_session_t * session )
// Let OpenSSL use our socket // Let OpenSSL use our socket
if ( SSL_set_fd( session->ssl, session->sock) != 1 ) if ( SSL_set_fd( session->ssl, session->sock) != 1 )
return LIBIRC_ERR_SSL_INIT_FAILED; return LIBIRC_ERR_SSL_INIT_FAILED;
// Since we're connecting on our own, tell openssl about it // Since we're connecting on our own, tell openssl about it
SSL_set_connect_state( session->ssl ); SSL_set_connect_state( session->ssl );
@ -227,7 +231,7 @@ static void ssl_handle_error( irc_session_t * session, int ssl_error )
session->lasterror = LIBIRC_ERR_SSL_CERT_VERIFY_FAILED; session->lasterror = LIBIRC_ERR_SSL_CERT_VERIFY_FAILED;
return; return;
} }
if ( ERR_GET_REASON(ssl_error) == SSL_R_UNKNOWN_PROTOCOL ) if ( ERR_GET_REASON(ssl_error) == SSL_R_UNKNOWN_PROTOCOL )
{ {
session->lasterror = LIBIRC_ERR_CONNECT_SSL_FAILED; session->lasterror = LIBIRC_ERR_CONNECT_SSL_FAILED;
@ -237,7 +241,7 @@ static void ssl_handle_error( irc_session_t * session, int ssl_error )
#if defined (ENABLE_DEBUG) #if defined (ENABLE_DEBUG)
if ( IS_DEBUG_ENABLED(session) ) if ( IS_DEBUG_ENABLED(session) )
fprintf (stderr, "[DEBUG] SSL error: %s\n\t(%d, %d)\n", fprintf (stderr, "[DEBUG] SSL error: %s\n\t(%d, %d)\n",
ERR_error_string( ssl_error, NULL), ERR_GET_LIB( ssl_error), ERR_GET_REASON(ssl_error) ); ERR_error_string( ssl_error, NULL), ERR_GET_LIB( ssl_error), ERR_GET_REASON(ssl_error) );
#endif #endif
} }
@ -246,42 +250,42 @@ static int ssl_recv( irc_session_t * session )
{ {
int count; int count;
unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset; unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset;
ERR_clear_error(); ERR_clear_error();
// Read up to m_bufferLength bytes // Read up to m_bufferLength bytes
count = SSL_read( session->ssl, session->incoming_buf + session->incoming_offset, amount ); count = SSL_read( session->ssl, session->incoming_buf + session->incoming_offset, amount );
if ( count > 0 ) if ( count > 0 )
return count; return count;
else if ( count == 0 ) else if ( count == 0 )
return -1; // remote connection closed return -1; // remote connection closed
else else
{ {
int ssl_error = SSL_get_error( session->ssl, count ); int ssl_error = SSL_get_error( session->ssl, count );
// Handle SSL error since not all of them are actually errors // Handle SSL error since not all of them are actually errors
switch ( ssl_error ) switch ( ssl_error )
{ {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
// This is not really an error. We received something, but // This is not really an error. We received something, but
// OpenSSL gave nothing to us because all it read was // OpenSSL gave nothing to us because all it read was
// internal data. Repeat the same read. // internal data. Repeat the same read.
return 0; return 0;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
// This is not really an error. We received something, but // This is not really an error. We received something, but
// now OpenSSL needs to send the data before returning any // now OpenSSL needs to send the data before returning any
// data to us (like negotiations). This means we'd need // data to us (like negotiations). This means we'd need
// to wait for WRITE event, but call SSL_read() again. // to wait for WRITE event, but call SSL_read() again.
session->flags |= SESSIONFL_SSL_READ_WANTS_WRITE; session->flags |= SESSIONFL_SSL_READ_WANTS_WRITE;
return 0; return 0;
} }
// This is an SSL error, handle it // This is an SSL error, handle it
ssl_handle_error( session, ERR_get_error() ); ssl_handle_error( session, ERR_get_error() );
} }
return -1; return -1;
} }
@ -289,37 +293,37 @@ static int ssl_recv( irc_session_t * session )
static int ssl_send( irc_session_t * session ) static int ssl_send( irc_session_t * session )
{ {
int count; int count;
ERR_clear_error(); ERR_clear_error();
count = SSL_write( session->ssl, session->outgoing_buf, session->outgoing_offset ); count = SSL_write( session->ssl, session->outgoing_buf, session->outgoing_offset );
if ( count > 0 ) if ( count > 0 )
return count; return count;
else if ( count == 0 ) else if ( count == 0 )
return -1; return -1;
else else
{ {
int ssl_error = SSL_get_error( session->ssl, count ); int ssl_error = SSL_get_error( session->ssl, count );
switch ( ssl_error ) switch ( ssl_error )
{ {
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
// This is not really an error. We sent some internal OpenSSL data, // This is not really an error. We sent some internal OpenSSL data,
// but now it needs to read more data before it can send anything. // but now it needs to read more data before it can send anything.
// Thus we wait for READ event, but will call SSL_write() again. // Thus we wait for READ event, but will call SSL_write() again.
session->flags |= SESSIONFL_SSL_WRITE_WANTS_READ; session->flags |= SESSIONFL_SSL_WRITE_WANTS_READ;
return 0; return 0;
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
// This is not really an error. We sent some data, but now OpenSSL // This is not really an error. We sent some data, but now OpenSSL
// wants to send some internal data before sending ours. // wants to send some internal data before sending ours.
// Repeat the same write. // Repeat the same write.
return 0; return 0;
} }
// This is an SSL error, handle it // This is an SSL error, handle it
ssl_handle_error( session, ERR_get_error() ); ssl_handle_error( session, ERR_get_error() );
} }
return -1; return -1;
} }
@ -331,7 +335,7 @@ static int ssl_send( irc_session_t * session )
// Returns -1 in case there is an error and socket should be closed/connection terminated // Returns -1 in case there is an error and socket should be closed/connection terminated
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case) // Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
// Returns a positive number if we actually read something // Returns a positive number if we actually read something
static int session_socket_read( irc_session_t * session ) int session_socket_read( irc_session_t * session )
{ {
int length; int length;
@ -345,19 +349,19 @@ static int session_socket_read( irc_session_t * session )
ssl_send( session ); ssl_send( session );
return 0; return 0;
} }
return ssl_recv( session ); return ssl_recv( session );
} }
#endif #endif
length = socket_recv( &session->sock, length = socket_recv( &session->sock,
session->incoming_buf + session->incoming_offset, session->incoming_buf + session->incoming_offset,
(sizeof (session->incoming_buf) - 1) - session->incoming_offset ); (sizeof (session->incoming_buf) - 1) - session->incoming_offset );
// There is no "retry" errors for regular sockets // There is no "retry" errors for regular sockets
if ( length <= 0 ) if ( length <= 0 )
return -1; return -1;
return length; return length;
} }
@ -365,7 +369,7 @@ static int session_socket_read( irc_session_t * session )
// Returns -1 in case there is an error and socket should be closed/connection terminated // Returns -1 in case there is an error and socket should be closed/connection terminated
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case) // Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
// Returns a positive number if we actually sent something // Returns a positive number if we actually sent something
static int session_socket_write( irc_session_t * session ) int session_socket_write( irc_session_t * session )
{ {
int length; int length;
@ -379,16 +383,16 @@ static int session_socket_write( irc_session_t * session )
ssl_recv( session ); ssl_recv( session );
return 0; return 0;
} }
return ssl_send( session ); return ssl_send( session );
} }
#endif #endif
length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset); length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset);
// There is no "retry" errors for regular sockets // There is no "retry" errors for regular sockets
if ( length <= 0 ) if ( length <= 0 )
return -1; return -1;
return length; return length;
} }

23
libircclient/src/ssl.h Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*/
#include "./session.h"
#ifndef INCLUDE_IRC_SSL_H
#define INCLUDE_IRC_SSL_H
int session_socket_read( irc_session_t * session );
int session_socket_write( irc_session_t * session );
#endif /* INCLUDE_IRC_SSL_H */

View File

@ -1,17 +1,28 @@
/* /*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com * Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
* *
* This library is free software; you can redistribute it and/or modify it * This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by * under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your * the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. * option) any later version.
* *
* This library is distributed in the hope that it will be useful, but WITHOUT * This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details. * License for more details.
*/ */
#ifndef INCLUDE_IRC_UTILS_H
#define INCLUDE_IRC_UTILS_H
//#include <sys/select.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "./session.h"
static void libirc_add_to_set (int fd, fd_set *set, int * maxfd) static void libirc_add_to_set (int fd, fd_set *set, int * maxfd)
{ {
FD_SET (fd, set); FD_SET (fd, set);
@ -62,13 +73,13 @@ static int libirc_findcrlf_offset(const char *buf, int offset, const int length)
static int libirc_findcrorlf (char * buf, int length) static int libirc_findcrorlf (char * buf, int length)
{ {
int offset = 0; int offset = 0;
for ( ; offset < length; offset++ ) for ( ; offset < length; offset++ )
{ {
if ( buf[offset] == 0x0D || buf[offset] == 0x0A ) if ( buf[offset] == 0x0D || buf[offset] == 0x0A )
{ {
buf[offset++] = '\0'; buf[offset++] = '\0';
if ( offset < (length - 1) if ( offset < (length - 1)
&& (buf[offset] == 0x0D || buf[offset] == 0x0A) ) && (buf[offset] == 0x0D || buf[offset] == 0x0A) )
offset++; offset++;
@ -108,7 +119,7 @@ static void libirc_event_ctcp_internal (irc_session_t * session, const char * ev
} }
else if ( !strcmp (params[0], "FINGER") ) else if ( !strcmp (params[0], "FINGER") )
{ {
sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds", sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds",
session->username ? session->username : "nobody", session->username ? session->username : "nobody",
session->realname ? session->realname : "noname"); session->realname ? session->realname : "noname");
@ -128,3 +139,5 @@ static void libirc_event_ctcp_internal (irc_session_t * session, const char * ev
} }
} }
} }
#endif /* INCLUDE_IRC_UTILS_H */