mirror of
https://github.com/weechat/weechat.git
synced 2026-07-01 07:16:37 +02:00
Improved DCC speed (up to x5 on LAN) by forking for DCC files and a new option "dcc_fast_send" (does not wait for ACK) (task #5758)
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
WeeChat - Wee Enhanced Environment for Chat
|
||||
===========================================
|
||||
|
||||
ChangeLog - 2006-07-30
|
||||
ChangeLog - 2006-08-03
|
||||
|
||||
Version 0.2.0 (under dev!):
|
||||
* improved DCC speed (up to x5 on LAN) by forking for DCC files and a
|
||||
new option "dcc_fast_send" (does not wait for ACK) (task #5758)
|
||||
* fixed crash when purging DCC with high number of DCC (> window size)
|
||||
* fixed completion for command handlers (now empty completion_template
|
||||
means nick completion, "-" string means no completion at all)
|
||||
|
||||
+288
-241
File diff suppressed because it is too large
Load Diff
@@ -320,6 +320,9 @@ session_save_dcc (FILE *file)
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_LAST_ACTIVITY, &(ptr_dcc->last_activity), sizeof (time_t)));
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_BYTES_PER_SEC, &(ptr_dcc->bytes_per_sec), sizeof (unsigned long)));
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_ETA, &(ptr_dcc->eta), sizeof (unsigned long)));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_PID, ptr_dcc->child_pid));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_READ, ptr_dcc->child_read));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_WRITE, ptr_dcc->child_write));
|
||||
rc = rc && (session_write_id (file, SESSION_DCC_END));
|
||||
|
||||
if (!rc)
|
||||
@@ -1289,6 +1292,15 @@ session_load_dcc (FILE *file)
|
||||
case SESSION_DCC_ETA:
|
||||
rc = rc && (session_read_buf (file, &(dcc->eta), sizeof (unsigned long)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_PID:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_pid)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_READ:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_read)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_WRITE:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_write)));
|
||||
break;
|
||||
default:
|
||||
weechat_log_printf (_("session: warning: ignoring value from "
|
||||
"DCC (object id: %d)\n"));
|
||||
|
||||
@@ -144,7 +144,10 @@ enum t_session_dcc
|
||||
SESSION_DCC_LAST_CHECK_POS,
|
||||
SESSION_DCC_LAST_ACTIVITY,
|
||||
SESSION_DCC_BYTES_PER_SEC,
|
||||
SESSION_DCC_ETA
|
||||
SESSION_DCC_ETA,
|
||||
SESSION_DCC_CHILD_PID,
|
||||
SESSION_DCC_CHILD_READ,
|
||||
SESSION_DCC_CHILD_WRITE
|
||||
};
|
||||
|
||||
enum t_session_history
|
||||
|
||||
@@ -802,6 +802,7 @@ int cfg_dcc_auto_accept_files;
|
||||
int cfg_dcc_auto_accept_chats;
|
||||
int cfg_dcc_timeout;
|
||||
int cfg_dcc_blocksize;
|
||||
int cfg_dcc_fast_send;
|
||||
char *cfg_dcc_port_range;
|
||||
char *cfg_dcc_own_ip;
|
||||
char *cfg_dcc_download_path;
|
||||
@@ -821,12 +822,16 @@ t_config_option weechat_options_dcc[] =
|
||||
NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, &config_change_noop },
|
||||
{ "dcc_timeout", N_("timeout for dcc request"),
|
||||
N_("timeout for dcc request (in seconds)"),
|
||||
OPTION_TYPE_INT, 1, INT_MAX, 300,
|
||||
OPTION_TYPE_INT, 5, INT_MAX, 300,
|
||||
NULL, NULL, &cfg_dcc_timeout, NULL, &config_change_noop },
|
||||
{ "dcc_blocksize", N_("block size for dcc packets"),
|
||||
N_("block size for dcc packets in bytes (default: 65536)"),
|
||||
OPTION_TYPE_INT, DCC_MIN_BLOCKSIZE, DCC_MAX_BLOCKSIZE, 65536,
|
||||
NULL, NULL, &cfg_dcc_blocksize, NULL, &config_change_noop },
|
||||
{ "dcc_fast_send", N_("does not wait for ACK when sending file"),
|
||||
N_("does not wait for ACK when sending file"),
|
||||
OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
|
||||
NULL, NULL, &cfg_dcc_fast_send, NULL, &config_change_noop },
|
||||
{ "dcc_port_range", N_("allowed ports for outgoing dcc"),
|
||||
N_("restricts outgoing dcc to use only ports in the given range "
|
||||
"(useful for NAT) (syntax: a single port, ie. 5000 or a port "
|
||||
|
||||
@@ -221,6 +221,7 @@ extern int cfg_dcc_auto_accept_files;
|
||||
extern int cfg_dcc_auto_accept_chats;
|
||||
extern int cfg_dcc_timeout;
|
||||
extern int cfg_dcc_blocksize;
|
||||
extern int cfg_dcc_fast_send;
|
||||
extern char *cfg_dcc_port_range;
|
||||
extern char *cfg_dcc_own_ip;
|
||||
extern char *cfg_dcc_download_path;
|
||||
|
||||
@@ -877,7 +877,7 @@ gui_chat_draw (t_gui_buffer *buffer, int erase)
|
||||
char format_empty[32];
|
||||
int i, j, line_pos, count, num_bars;
|
||||
unsigned long pct_complete;
|
||||
char *unit_name[] = { N_("bytes"), N_("Kb"), N_("Mb"), N_("Gb") };
|
||||
char *unit_name[] = { N_("bytes"), N_("KB"), N_("MB"), N_("GB") };
|
||||
char *unit_format[] = { "%.0f", "%.1f", "%.02f", "%.02f" };
|
||||
float unit_divide[] = { 1, 1024, 1024*1024, 1024*1024*1024 };
|
||||
int num_unit;
|
||||
|
||||
+418
-102
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* irc-dcc.c: DCC communications (files & chat) */
|
||||
/* irc-dcc.c: Direct Client-to-Client (DCC) communication (files & chat) */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -26,12 +26,15 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -386,6 +389,34 @@ dcc_free (t_irc_dcc *ptr_dcc)
|
||||
dcc_list = new_dcc_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_child_kill: kill child process and close pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_child_kill (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
/* kill process */
|
||||
if (ptr_dcc->child_pid > 0)
|
||||
{
|
||||
kill (ptr_dcc->child_pid, SIGKILL);
|
||||
waitpid (ptr_dcc->child_pid, NULL, 0);
|
||||
ptr_dcc->child_pid = 0;
|
||||
}
|
||||
|
||||
/* close pipe used with child */
|
||||
if (ptr_dcc->child_read != -1)
|
||||
{
|
||||
close (ptr_dcc->child_read);
|
||||
ptr_dcc->child_read = -1;
|
||||
}
|
||||
if (ptr_dcc->child_write != -1)
|
||||
{
|
||||
close (ptr_dcc->child_write);
|
||||
ptr_dcc->child_write = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_close: close a DCC connection
|
||||
*/
|
||||
@@ -424,6 +455,7 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
|
||||
ptr_dcc->nick,
|
||||
GUI_COLOR(COLOR_WIN_CHAT),
|
||||
(status == DCC_DONE) ? _("OK") : _("FAILED"));
|
||||
dcc_file_child_kill (ptr_dcc);
|
||||
}
|
||||
}
|
||||
if (status == DCC_ABORTED)
|
||||
@@ -553,15 +585,9 @@ dcc_recv_connect_init (t_irc_dcc *ptr_dcc)
|
||||
/* DCC file => look for local filename and open it in writing mode */
|
||||
if (DCC_IS_FILE(ptr_dcc->type))
|
||||
{
|
||||
if (ptr_dcc->start_resume > 0)
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_APPEND | O_WRONLY | O_NONBLOCK);
|
||||
else
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
|
||||
0644);
|
||||
ptr_dcc->start_transfer = time (NULL);
|
||||
ptr_dcc->last_check_time = time (NULL);
|
||||
dcc_file_recv_fork (ptr_dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -683,11 +709,16 @@ dcc_alloc ()
|
||||
new_dcc->port = 0;
|
||||
new_dcc->nick = NULL;
|
||||
new_dcc->sock = -1;
|
||||
new_dcc->child_pid = 0;
|
||||
new_dcc->child_read = -1;
|
||||
new_dcc->child_write = -1;
|
||||
new_dcc->unterminated_message = NULL;
|
||||
new_dcc->fast_send = cfg_dcc_fast_send;
|
||||
new_dcc->file = -1;
|
||||
new_dcc->filename = NULL;
|
||||
new_dcc->local_filename = NULL;
|
||||
new_dcc->filename_suffix = -1;
|
||||
new_dcc->blocksize = cfg_dcc_blocksize;
|
||||
new_dcc->size = 0;
|
||||
new_dcc->pos = 0;
|
||||
new_dcc->ack = 0;
|
||||
@@ -1285,6 +1316,354 @@ dcc_chat_recv (t_irc_dcc *ptr_dcc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_create_pipe: create pipe for communication with child process
|
||||
* return 1 if ok, 0 if error
|
||||
*/
|
||||
|
||||
int
|
||||
dcc_file_create_pipe (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int child_pipe[2];
|
||||
|
||||
if (pipe (child_pipe) < 0)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to create pipe\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr_dcc->child_read = child_pipe[0];
|
||||
ptr_dcc->child_write = child_pipe[1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_write_pipe: write data into pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_write_pipe (t_irc_dcc *ptr_dcc, int status, int error)
|
||||
{
|
||||
char buffer[1 + 1 + 12 + 1]; /* status + error + pos + \0 */
|
||||
|
||||
snprintf (buffer, sizeof (buffer), "%c%c%012lu",
|
||||
status + '0', error + '0', ptr_dcc->pos);
|
||||
write (ptr_dcc->child_write, buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_send_child: child process for sending file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_send_child (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int num_read, num_sent;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t ack;
|
||||
time_t last_sent, new_time;
|
||||
|
||||
last_sent = time (NULL);
|
||||
while (1)
|
||||
{
|
||||
/* read DCC ACK (sent by receiver) */
|
||||
if (ptr_dcc->pos > ptr_dcc->ack)
|
||||
{
|
||||
/* we should receive ACK for packets sent previously */
|
||||
while (1)
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, (char *) &ack, 4, MSG_PEEK);
|
||||
if ((num_read < 1) &&
|
||||
((num_read != -1) || (errno != EAGAIN)))
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
if (num_read == 4)
|
||||
{
|
||||
recv (ptr_dcc->sock, (char *) &ack, 4, 0);
|
||||
ptr_dcc->ack = ntohl (ack);
|
||||
|
||||
/* DCC send ok? */
|
||||
if ((ptr_dcc->pos >= ptr_dcc->size)
|
||||
&& (ptr_dcc->ack >= ptr_dcc->size))
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_DONE, DCC_NO_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* send a block to receiver */
|
||||
if ((ptr_dcc->pos < ptr_dcc->size) &&
|
||||
(ptr_dcc->fast_send || (ptr_dcc->pos <= ptr_dcc->ack)))
|
||||
{
|
||||
lseek (ptr_dcc->file, ptr_dcc->pos, SEEK_SET);
|
||||
num_read = read (ptr_dcc->file, buffer, ptr_dcc->blocksize);
|
||||
if (num_read < 1)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
num_sent = send (ptr_dcc->sock, buffer, num_read, 0);
|
||||
if (num_sent < 0)
|
||||
{
|
||||
/* socket is temporarily not available (receiver can't receive
|
||||
amount of data we sent ?!) */
|
||||
if (errno == EAGAIN)
|
||||
usleep (1000);
|
||||
else
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (num_sent > 0)
|
||||
{
|
||||
ptr_dcc->pos += (unsigned long) num_sent;
|
||||
new_time = time (NULL);
|
||||
if (last_sent != new_time)
|
||||
{
|
||||
last_sent = new_time;
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_ACTIVE, DCC_NO_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
usleep (1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_recv_child: child process for receiving file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_recv_child (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int num_read;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t pos;
|
||||
time_t last_sent, new_time;
|
||||
|
||||
last_sent = time (NULL);
|
||||
while (1)
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
|
||||
if (num_read == -1)
|
||||
{
|
||||
/* socket is temporarily not available (sender is not fast ?!) */
|
||||
if (errno == EAGAIN)
|
||||
usleep (1000);
|
||||
else
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_RECV_BLOCK);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_RECV_BLOCK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (write (ptr_dcc->file, buffer, num_read) == -1)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_WRITE_LOCAL);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr_dcc->pos += (unsigned long) num_read;
|
||||
pos = htonl (ptr_dcc->pos);
|
||||
|
||||
/* we don't check return code, not a problem if an ACK send failed */
|
||||
send (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
|
||||
/* file received ok? */
|
||||
if (ptr_dcc->pos >= ptr_dcc->size)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_DONE, DCC_NO_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
new_time = time (NULL);
|
||||
if (last_sent != new_time)
|
||||
{
|
||||
last_sent = new_time;
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_ACTIVE, DCC_NO_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_child_read: read data from child via pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_child_read (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
char bufpipe[1 + 1 + 12 + 1];
|
||||
int num_read;
|
||||
char *error;
|
||||
|
||||
num_read = read (ptr_dcc->child_read, bufpipe, sizeof (bufpipe));
|
||||
if (num_read > 0)
|
||||
{
|
||||
error = NULL;
|
||||
ptr_dcc->pos = strtol (bufpipe + 2, &error, 10);
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
|
||||
/* read error code */
|
||||
switch (bufpipe[1] - '0')
|
||||
{
|
||||
case DCC_ERROR_READ_LOCAL:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to read local file\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_SEND_BLOCK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to send block to receiver\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_READ_ACK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to read ACK from receiver\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_RECV_BLOCK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to receive block from sender\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_WRITE_LOCAL:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to write local file\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read new DCC status */
|
||||
switch (bufpipe[0] - '0')
|
||||
{
|
||||
case DCC_ACTIVE:
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
break;
|
||||
case DCC_DONE:
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
break;
|
||||
case DCC_FAILED:
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_send_fork: fork process for sending file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_send_fork (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (!dcc_file_create_pipe (ptr_dcc))
|
||||
return;
|
||||
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
|
||||
|
||||
switch (pid = fork ())
|
||||
{
|
||||
/* fork failed */
|
||||
case -1:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to fork\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return;
|
||||
/* child process */
|
||||
case 0:
|
||||
setuid (getuid ());
|
||||
dcc_file_send_child (ptr_dcc);
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
ptr_dcc->child_pid = pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_recv_fork: fork process for receiving file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_recv_fork (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (!dcc_file_create_pipe (ptr_dcc))
|
||||
return;
|
||||
|
||||
if (ptr_dcc->start_resume > 0)
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_APPEND | O_WRONLY | O_NONBLOCK);
|
||||
else
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
|
||||
0644);
|
||||
|
||||
switch (pid = fork ())
|
||||
{
|
||||
/* fork failed */
|
||||
case -1:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to fork\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return;
|
||||
/* child process */
|
||||
case 0:
|
||||
setuid (getuid ());
|
||||
dcc_file_recv_child (ptr_dcc);
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
ptr_dcc->child_pid = pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_handle: receive/send data for all active DCC
|
||||
*/
|
||||
@@ -1293,9 +1672,6 @@ void
|
||||
dcc_handle ()
|
||||
{
|
||||
t_irc_dcc *ptr_dcc;
|
||||
int num_read, num_sent;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t pos;
|
||||
fd_set read_fd;
|
||||
static struct timeval timeout;
|
||||
int sock;
|
||||
@@ -1309,6 +1685,11 @@ dcc_handle ()
|
||||
{
|
||||
if ((cfg_dcc_timeout != 0) && (time (NULL) > ptr_dcc->last_activity + cfg_dcc_timeout))
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: timeout\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
@@ -1336,6 +1717,11 @@ dcc_handle ()
|
||||
ptr_dcc->sock = -1;
|
||||
if (sock < 0)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to create socket for sending file\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
@@ -1343,15 +1729,20 @@ dcc_handle ()
|
||||
ptr_dcc->sock = sock;
|
||||
if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to set 'nonblock' option for socket\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
|
||||
ptr_dcc->status = DCC_ACTIVE;
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
|
||||
ptr_dcc->start_transfer = time (NULL);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
dcc_file_send_fork (ptr_dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1413,98 +1804,18 @@ dcc_handle ()
|
||||
dcc_chat_recv (ptr_dcc);
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->type == DCC_FILE_RECV)
|
||||
else
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
|
||||
if (num_read != -1)
|
||||
FD_ZERO (&read_fd);
|
||||
FD_SET (ptr_dcc->child_read, &read_fd);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* something to read on child pipe? */
|
||||
if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0)
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (write (ptr_dcc->file, buffer, num_read) == -1)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
ptr_dcc->pos += (unsigned long) num_read;
|
||||
pos = htonl (ptr_dcc->pos);
|
||||
send (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
if (ptr_dcc->pos >= ptr_dcc->size)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
}
|
||||
else
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->type == DCC_FILE_SEND)
|
||||
{
|
||||
if (cfg_dcc_blocksize > (int) sizeof (buffer))
|
||||
{
|
||||
irc_display_prefix (NULL, NULL, PREFIX_ERROR);
|
||||
gui_printf (NULL, _("%s DCC failed because blocksize is too "
|
||||
"big. Check value of \"dcc_blocksize\" option, "
|
||||
"max is %d.\n"),
|
||||
WEECHAT_ERROR, DCC_MAX_BLOCKSIZE);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
if (ptr_dcc->pos > ptr_dcc->ack)
|
||||
{
|
||||
/* we should receive ACK for packets sent previously */
|
||||
num_read = recv (ptr_dcc->sock, (char *) &pos, 4, MSG_PEEK);
|
||||
if (num_read != -1)
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
if (num_read < 4)
|
||||
continue;
|
||||
recv (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
ptr_dcc->ack = ntohl (pos);
|
||||
|
||||
if ((ptr_dcc->pos >= ptr_dcc->size)
|
||||
&& (ptr_dcc->ack >= ptr_dcc->size))
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->pos <= ptr_dcc->ack)
|
||||
{
|
||||
lseek (ptr_dcc->file, ptr_dcc->pos, SEEK_SET);
|
||||
num_read = read (ptr_dcc->file, buffer, cfg_dcc_blocksize);
|
||||
if (num_read < 1)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
num_sent = send (ptr_dcc->sock, buffer, num_read, 0);
|
||||
if (num_sent < 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
ptr_dcc->pos += (unsigned long) num_sent;
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
if (FD_ISSET (ptr_dcc->child_read, &read_fd))
|
||||
dcc_file_child_read (ptr_dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1555,11 +1866,16 @@ dcc_print_log ()
|
||||
weechat_log_printf (" port. . . . . . . . : %d\n", ptr_dcc->port);
|
||||
weechat_log_printf (" nick. . . . . . . . : '%s'\n", ptr_dcc->nick);
|
||||
weechat_log_printf (" sock. . . . . . . . : %d\n", ptr_dcc->sock);
|
||||
weechat_log_printf (" child_pid . . . . . : %d\n", ptr_dcc->child_pid);
|
||||
weechat_log_printf (" child_read. . . . . : %d\n", ptr_dcc->child_read);
|
||||
weechat_log_printf (" child_write . . . . : %d\n", ptr_dcc->child_write);
|
||||
weechat_log_printf (" unterminated_message: '%s'\n", ptr_dcc->unterminated_message);
|
||||
weechat_log_printf (" fast_send . . . . . : %d\n", ptr_dcc->fast_send);
|
||||
weechat_log_printf (" file. . . . . . . . : %d\n", ptr_dcc->file);
|
||||
weechat_log_printf (" filename. . . . . . : '%s'\n", ptr_dcc->filename);
|
||||
weechat_log_printf (" local_filename. . . : '%s'\n", ptr_dcc->local_filename);
|
||||
weechat_log_printf (" filename_suffix . . : %d\n", ptr_dcc->filename_suffix);
|
||||
weechat_log_printf (" blocksize . . . . . : %d\n", ptr_dcc->blocksize);
|
||||
weechat_log_printf (" size. . . . . . . . : %lu\n", ptr_dcc->size);
|
||||
weechat_log_printf (" pos . . . . . . . . : %lu\n", ptr_dcc->pos);
|
||||
weechat_log_printf (" ack . . . . . . . . : %lu\n", ptr_dcc->ack);
|
||||
|
||||
@@ -870,11 +870,11 @@ server_recv (t_irc_server *server)
|
||||
}
|
||||
|
||||
/*
|
||||
* server_kill_child: kill child process and close pipe
|
||||
* server_child_kill: kill child process and close pipe
|
||||
*/
|
||||
|
||||
void
|
||||
server_kill_child (t_irc_server *server)
|
||||
server_child_kill (t_irc_server *server)
|
||||
{
|
||||
/* kill process */
|
||||
if (server->child_pid > 0)
|
||||
@@ -904,7 +904,7 @@ server_kill_child (t_irc_server *server)
|
||||
void
|
||||
server_close_connection (t_irc_server *server)
|
||||
{
|
||||
server_kill_child (server);
|
||||
server_child_kill (server);
|
||||
|
||||
/* close network socket */
|
||||
if (server->sock != -1)
|
||||
@@ -962,7 +962,7 @@ server_child_read (t_irc_server *server)
|
||||
int num_read;
|
||||
|
||||
num_read = read (server->child_read, buffer, sizeof (buffer));
|
||||
if (num_read != -1)
|
||||
if (num_read > 0)
|
||||
{
|
||||
switch (buffer[0])
|
||||
{
|
||||
@@ -987,7 +987,7 @@ server_child_read (t_irc_server *server)
|
||||
}
|
||||
#endif
|
||||
/* kill child and login to server */
|
||||
server_kill_child (server);
|
||||
server_child_kill (server);
|
||||
irc_login (server);
|
||||
break;
|
||||
/* adress not found */
|
||||
@@ -1673,7 +1673,7 @@ server_connect (t_irc_server *server)
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process go on here */
|
||||
/* parent process */
|
||||
server->child_pid = pid;
|
||||
|
||||
return 1;
|
||||
|
||||
+25
-1
@@ -241,6 +241,8 @@ struct t_irc_message
|
||||
#define DCC_FILE_RECV 2 /* incoming DCC file */
|
||||
#define DCC_FILE_SEND 3 /* sending DCC file */
|
||||
|
||||
/* DCC status */
|
||||
|
||||
#define DCC_WAITING 0 /* waiting for host answer */
|
||||
#define DCC_CONNECTING 1 /* connecting to host */
|
||||
#define DCC_ACTIVE 2 /* sending/receiving data */
|
||||
@@ -248,14 +250,29 @@ struct t_irc_message
|
||||
#define DCC_FAILED 4 /* DCC failed */
|
||||
#define DCC_ABORTED 5 /* DCC aborted by user */
|
||||
|
||||
/* DCC blocksize (for file) */
|
||||
|
||||
#define DCC_MIN_BLOCKSIZE 1024 /* min DCC block size when sending file */
|
||||
#define DCC_MAX_BLOCKSIZE 102400 /* max DCC block size when sending file */
|
||||
|
||||
/* DCC errors (for file) */
|
||||
|
||||
#define DCC_NO_ERROR 0 /* used when no error to report, all ok! */
|
||||
#define DCC_ERROR_READ_LOCAL 1 /* unable to read local file */
|
||||
#define DCC_ERROR_SEND_BLOCK 2 /* unable to send block to receiver */
|
||||
#define DCC_ERROR_READ_ACK 3 /* unable to read ACK from receiver */
|
||||
#define DCC_ERROR_RECV_BLOCK 4 /* unable to receive block from sender */
|
||||
#define DCC_ERROR_WRITE_LOCAL 5 /* unable to write to local file */
|
||||
|
||||
/* DCC macros for type */
|
||||
|
||||
#define DCC_IS_CHAT(type) ((type == DCC_CHAT_RECV) || (type == DCC_CHAT_SEND))
|
||||
#define DCC_IS_FILE(type) ((type == DCC_FILE_RECV) || (type == DCC_FILE_SEND))
|
||||
#define DCC_IS_RECV(type) ((type == DCC_CHAT_RECV) || (type == DCC_FILE_RECV))
|
||||
#define DCC_IS_SEND(type) ((type == DCC_CHAT_SEND) || (type == DCC_FILE_SEND))
|
||||
|
||||
/* DCC macro for status */
|
||||
|
||||
#define DCC_ENDED(status) ((status == DCC_DONE) || (status == DCC_FAILED) || \
|
||||
(status == DCC_ABORTED))
|
||||
|
||||
@@ -265,7 +282,7 @@ struct t_irc_dcc
|
||||
{
|
||||
t_irc_server *server; /* irc server */
|
||||
t_irc_channel *channel; /* irc channel (for DCC chat only) */
|
||||
int type; /* DCC type (send or receive) */
|
||||
int type; /* DCC type (file/chat, send/receive) */
|
||||
int status; /* DCC status (waiting, sending, ..) */
|
||||
time_t start_time; /* the time when DCC started */
|
||||
time_t start_transfer; /* the time when DCC transfer started */
|
||||
@@ -273,11 +290,16 @@ struct t_irc_dcc
|
||||
int port; /* port */
|
||||
char *nick; /* remote nick */
|
||||
int sock; /* socket for connection */
|
||||
pid_t child_pid; /* pid of child process (sending/recving) */
|
||||
int child_read; /* to read into child pipe */
|
||||
int child_write; /* to write into child pipe */
|
||||
char *unterminated_message; /* beginning of a message in input buf */
|
||||
int fast_send; /* fase send for files: does not wait ACK */
|
||||
int file; /* local file (for reading or writing) */
|
||||
char *filename; /* filename (given by sender) */
|
||||
char *local_filename; /* local filename (with path) */
|
||||
int filename_suffix; /* suffix (.1 for ex) if renaming file */
|
||||
int blocksize; /* block size for sending file */
|
||||
unsigned long size; /* file size */
|
||||
unsigned long pos; /* number of bytes received/sent */
|
||||
unsigned long ack; /* number of bytes received OK */
|
||||
@@ -421,6 +443,8 @@ extern t_irc_dcc *dcc_add (t_irc_server *, int, unsigned long, int, char *, int,
|
||||
char *, char *, unsigned long);
|
||||
extern void dcc_send_request (t_irc_server *, int, char *, char *);
|
||||
extern void dcc_chat_sendf (t_irc_dcc *, char *, ...);
|
||||
extern void dcc_file_send_fork (t_irc_dcc *);
|
||||
extern void dcc_file_recv_fork (t_irc_dcc *);
|
||||
extern void dcc_handle ();
|
||||
extern void dcc_end ();
|
||||
extern void dcc_print_log ();
|
||||
|
||||
+3
-1
@@ -1,9 +1,11 @@
|
||||
WeeChat - Wee Enhanced Environment for Chat
|
||||
===========================================
|
||||
|
||||
ChangeLog - 2006-07-30
|
||||
ChangeLog - 2006-08-03
|
||||
|
||||
Version 0.2.0 (under dev!):
|
||||
* improved DCC speed (up to x5 on LAN) by forking for DCC files and a
|
||||
new option "dcc_fast_send" (does not wait for ACK) (task #5758)
|
||||
* fixed crash when purging DCC with high number of DCC (> window size)
|
||||
* fixed completion for command handlers (now empty completion_template
|
||||
means nick completion, "-" string means no completion at all)
|
||||
|
||||
+291
-229
File diff suppressed because it is too large
Load Diff
+328
-262
File diff suppressed because it is too large
Load Diff
+291
-229
File diff suppressed because it is too large
Load Diff
+287
-226
File diff suppressed because it is too large
Load Diff
+282
-225
File diff suppressed because it is too large
Load Diff
+291
-229
File diff suppressed because it is too large
Load Diff
+288
-241
File diff suppressed because it is too large
Load Diff
@@ -320,6 +320,9 @@ session_save_dcc (FILE *file)
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_LAST_ACTIVITY, &(ptr_dcc->last_activity), sizeof (time_t)));
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_BYTES_PER_SEC, &(ptr_dcc->bytes_per_sec), sizeof (unsigned long)));
|
||||
rc = rc && (session_write_buf (file, SESSION_DCC_ETA, &(ptr_dcc->eta), sizeof (unsigned long)));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_PID, ptr_dcc->child_pid));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_READ, ptr_dcc->child_read));
|
||||
rc = rc && (session_write_int (file, SESSION_DCC_CHILD_WRITE, ptr_dcc->child_write));
|
||||
rc = rc && (session_write_id (file, SESSION_DCC_END));
|
||||
|
||||
if (!rc)
|
||||
@@ -1289,6 +1292,15 @@ session_load_dcc (FILE *file)
|
||||
case SESSION_DCC_ETA:
|
||||
rc = rc && (session_read_buf (file, &(dcc->eta), sizeof (unsigned long)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_PID:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_pid)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_READ:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_read)));
|
||||
break;
|
||||
case SESSION_DCC_CHILD_WRITE:
|
||||
rc = rc && (session_read_int (file, &(dcc->child_write)));
|
||||
break;
|
||||
default:
|
||||
weechat_log_printf (_("session: warning: ignoring value from "
|
||||
"DCC (object id: %d)\n"));
|
||||
|
||||
@@ -144,7 +144,10 @@ enum t_session_dcc
|
||||
SESSION_DCC_LAST_CHECK_POS,
|
||||
SESSION_DCC_LAST_ACTIVITY,
|
||||
SESSION_DCC_BYTES_PER_SEC,
|
||||
SESSION_DCC_ETA
|
||||
SESSION_DCC_ETA,
|
||||
SESSION_DCC_CHILD_PID,
|
||||
SESSION_DCC_CHILD_READ,
|
||||
SESSION_DCC_CHILD_WRITE
|
||||
};
|
||||
|
||||
enum t_session_history
|
||||
|
||||
@@ -802,6 +802,7 @@ int cfg_dcc_auto_accept_files;
|
||||
int cfg_dcc_auto_accept_chats;
|
||||
int cfg_dcc_timeout;
|
||||
int cfg_dcc_blocksize;
|
||||
int cfg_dcc_fast_send;
|
||||
char *cfg_dcc_port_range;
|
||||
char *cfg_dcc_own_ip;
|
||||
char *cfg_dcc_download_path;
|
||||
@@ -821,12 +822,16 @@ t_config_option weechat_options_dcc[] =
|
||||
NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, &config_change_noop },
|
||||
{ "dcc_timeout", N_("timeout for dcc request"),
|
||||
N_("timeout for dcc request (in seconds)"),
|
||||
OPTION_TYPE_INT, 1, INT_MAX, 300,
|
||||
OPTION_TYPE_INT, 5, INT_MAX, 300,
|
||||
NULL, NULL, &cfg_dcc_timeout, NULL, &config_change_noop },
|
||||
{ "dcc_blocksize", N_("block size for dcc packets"),
|
||||
N_("block size for dcc packets in bytes (default: 65536)"),
|
||||
OPTION_TYPE_INT, DCC_MIN_BLOCKSIZE, DCC_MAX_BLOCKSIZE, 65536,
|
||||
NULL, NULL, &cfg_dcc_blocksize, NULL, &config_change_noop },
|
||||
{ "dcc_fast_send", N_("does not wait for ACK when sending file"),
|
||||
N_("does not wait for ACK when sending file"),
|
||||
OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
|
||||
NULL, NULL, &cfg_dcc_fast_send, NULL, &config_change_noop },
|
||||
{ "dcc_port_range", N_("allowed ports for outgoing dcc"),
|
||||
N_("restricts outgoing dcc to use only ports in the given range "
|
||||
"(useful for NAT) (syntax: a single port, ie. 5000 or a port "
|
||||
|
||||
@@ -221,6 +221,7 @@ extern int cfg_dcc_auto_accept_files;
|
||||
extern int cfg_dcc_auto_accept_chats;
|
||||
extern int cfg_dcc_timeout;
|
||||
extern int cfg_dcc_blocksize;
|
||||
extern int cfg_dcc_fast_send;
|
||||
extern char *cfg_dcc_port_range;
|
||||
extern char *cfg_dcc_own_ip;
|
||||
extern char *cfg_dcc_download_path;
|
||||
|
||||
@@ -877,7 +877,7 @@ gui_chat_draw (t_gui_buffer *buffer, int erase)
|
||||
char format_empty[32];
|
||||
int i, j, line_pos, count, num_bars;
|
||||
unsigned long pct_complete;
|
||||
char *unit_name[] = { N_("bytes"), N_("Kb"), N_("Mb"), N_("Gb") };
|
||||
char *unit_name[] = { N_("bytes"), N_("KB"), N_("MB"), N_("GB") };
|
||||
char *unit_format[] = { "%.0f", "%.1f", "%.02f", "%.02f" };
|
||||
float unit_divide[] = { 1, 1024, 1024*1024, 1024*1024*1024 };
|
||||
int num_unit;
|
||||
|
||||
+418
-102
@@ -17,7 +17,7 @@
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* irc-dcc.c: DCC communications (files & chat) */
|
||||
/* irc-dcc.c: Direct Client-to-Client (DCC) communication (files & chat) */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -26,12 +26,15 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
@@ -386,6 +389,34 @@ dcc_free (t_irc_dcc *ptr_dcc)
|
||||
dcc_list = new_dcc_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_child_kill: kill child process and close pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_child_kill (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
/* kill process */
|
||||
if (ptr_dcc->child_pid > 0)
|
||||
{
|
||||
kill (ptr_dcc->child_pid, SIGKILL);
|
||||
waitpid (ptr_dcc->child_pid, NULL, 0);
|
||||
ptr_dcc->child_pid = 0;
|
||||
}
|
||||
|
||||
/* close pipe used with child */
|
||||
if (ptr_dcc->child_read != -1)
|
||||
{
|
||||
close (ptr_dcc->child_read);
|
||||
ptr_dcc->child_read = -1;
|
||||
}
|
||||
if (ptr_dcc->child_write != -1)
|
||||
{
|
||||
close (ptr_dcc->child_write);
|
||||
ptr_dcc->child_write = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_close: close a DCC connection
|
||||
*/
|
||||
@@ -424,6 +455,7 @@ dcc_close (t_irc_dcc *ptr_dcc, int status)
|
||||
ptr_dcc->nick,
|
||||
GUI_COLOR(COLOR_WIN_CHAT),
|
||||
(status == DCC_DONE) ? _("OK") : _("FAILED"));
|
||||
dcc_file_child_kill (ptr_dcc);
|
||||
}
|
||||
}
|
||||
if (status == DCC_ABORTED)
|
||||
@@ -553,15 +585,9 @@ dcc_recv_connect_init (t_irc_dcc *ptr_dcc)
|
||||
/* DCC file => look for local filename and open it in writing mode */
|
||||
if (DCC_IS_FILE(ptr_dcc->type))
|
||||
{
|
||||
if (ptr_dcc->start_resume > 0)
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_APPEND | O_WRONLY | O_NONBLOCK);
|
||||
else
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
|
||||
0644);
|
||||
ptr_dcc->start_transfer = time (NULL);
|
||||
ptr_dcc->last_check_time = time (NULL);
|
||||
dcc_file_recv_fork (ptr_dcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -683,11 +709,16 @@ dcc_alloc ()
|
||||
new_dcc->port = 0;
|
||||
new_dcc->nick = NULL;
|
||||
new_dcc->sock = -1;
|
||||
new_dcc->child_pid = 0;
|
||||
new_dcc->child_read = -1;
|
||||
new_dcc->child_write = -1;
|
||||
new_dcc->unterminated_message = NULL;
|
||||
new_dcc->fast_send = cfg_dcc_fast_send;
|
||||
new_dcc->file = -1;
|
||||
new_dcc->filename = NULL;
|
||||
new_dcc->local_filename = NULL;
|
||||
new_dcc->filename_suffix = -1;
|
||||
new_dcc->blocksize = cfg_dcc_blocksize;
|
||||
new_dcc->size = 0;
|
||||
new_dcc->pos = 0;
|
||||
new_dcc->ack = 0;
|
||||
@@ -1285,6 +1316,354 @@ dcc_chat_recv (t_irc_dcc *ptr_dcc)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_create_pipe: create pipe for communication with child process
|
||||
* return 1 if ok, 0 if error
|
||||
*/
|
||||
|
||||
int
|
||||
dcc_file_create_pipe (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int child_pipe[2];
|
||||
|
||||
if (pipe (child_pipe) < 0)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to create pipe\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr_dcc->child_read = child_pipe[0];
|
||||
ptr_dcc->child_write = child_pipe[1];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_write_pipe: write data into pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_write_pipe (t_irc_dcc *ptr_dcc, int status, int error)
|
||||
{
|
||||
char buffer[1 + 1 + 12 + 1]; /* status + error + pos + \0 */
|
||||
|
||||
snprintf (buffer, sizeof (buffer), "%c%c%012lu",
|
||||
status + '0', error + '0', ptr_dcc->pos);
|
||||
write (ptr_dcc->child_write, buffer, sizeof (buffer));
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_send_child: child process for sending file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_send_child (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int num_read, num_sent;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t ack;
|
||||
time_t last_sent, new_time;
|
||||
|
||||
last_sent = time (NULL);
|
||||
while (1)
|
||||
{
|
||||
/* read DCC ACK (sent by receiver) */
|
||||
if (ptr_dcc->pos > ptr_dcc->ack)
|
||||
{
|
||||
/* we should receive ACK for packets sent previously */
|
||||
while (1)
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, (char *) &ack, 4, MSG_PEEK);
|
||||
if ((num_read < 1) &&
|
||||
((num_read != -1) || (errno != EAGAIN)))
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
if (num_read == 4)
|
||||
{
|
||||
recv (ptr_dcc->sock, (char *) &ack, 4, 0);
|
||||
ptr_dcc->ack = ntohl (ack);
|
||||
|
||||
/* DCC send ok? */
|
||||
if ((ptr_dcc->pos >= ptr_dcc->size)
|
||||
&& (ptr_dcc->ack >= ptr_dcc->size))
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_DONE, DCC_NO_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* send a block to receiver */
|
||||
if ((ptr_dcc->pos < ptr_dcc->size) &&
|
||||
(ptr_dcc->fast_send || (ptr_dcc->pos <= ptr_dcc->ack)))
|
||||
{
|
||||
lseek (ptr_dcc->file, ptr_dcc->pos, SEEK_SET);
|
||||
num_read = read (ptr_dcc->file, buffer, ptr_dcc->blocksize);
|
||||
if (num_read < 1)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
num_sent = send (ptr_dcc->sock, buffer, num_read, 0);
|
||||
if (num_sent < 0)
|
||||
{
|
||||
/* socket is temporarily not available (receiver can't receive
|
||||
amount of data we sent ?!) */
|
||||
if (errno == EAGAIN)
|
||||
usleep (1000);
|
||||
else
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_READ_LOCAL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (num_sent > 0)
|
||||
{
|
||||
ptr_dcc->pos += (unsigned long) num_sent;
|
||||
new_time = time (NULL);
|
||||
if (last_sent != new_time)
|
||||
{
|
||||
last_sent = new_time;
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_ACTIVE, DCC_NO_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
usleep (1000);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_recv_child: child process for receiving file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_recv_child (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
int num_read;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t pos;
|
||||
time_t last_sent, new_time;
|
||||
|
||||
last_sent = time (NULL);
|
||||
while (1)
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
|
||||
if (num_read == -1)
|
||||
{
|
||||
/* socket is temporarily not available (sender is not fast ?!) */
|
||||
if (errno == EAGAIN)
|
||||
usleep (1000);
|
||||
else
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_RECV_BLOCK);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_RECV_BLOCK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (write (ptr_dcc->file, buffer, num_read) == -1)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_FAILED, DCC_ERROR_WRITE_LOCAL);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr_dcc->pos += (unsigned long) num_read;
|
||||
pos = htonl (ptr_dcc->pos);
|
||||
|
||||
/* we don't check return code, not a problem if an ACK send failed */
|
||||
send (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
|
||||
/* file received ok? */
|
||||
if (ptr_dcc->pos >= ptr_dcc->size)
|
||||
{
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_DONE, DCC_NO_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
new_time = time (NULL);
|
||||
if (last_sent != new_time)
|
||||
{
|
||||
last_sent = new_time;
|
||||
dcc_file_write_pipe (ptr_dcc, DCC_ACTIVE, DCC_NO_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_child_read: read data from child via pipe
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_child_read (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
char bufpipe[1 + 1 + 12 + 1];
|
||||
int num_read;
|
||||
char *error;
|
||||
|
||||
num_read = read (ptr_dcc->child_read, bufpipe, sizeof (bufpipe));
|
||||
if (num_read > 0)
|
||||
{
|
||||
error = NULL;
|
||||
ptr_dcc->pos = strtol (bufpipe + 2, &error, 10);
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
|
||||
/* read error code */
|
||||
switch (bufpipe[1] - '0')
|
||||
{
|
||||
case DCC_ERROR_READ_LOCAL:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to read local file\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_SEND_BLOCK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to send block to receiver\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_READ_ACK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to read ACK from receiver\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_RECV_BLOCK:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to receive block from sender\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
case DCC_ERROR_WRITE_LOCAL:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to write local file\n"),
|
||||
WEECHAT_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
/* read new DCC status */
|
||||
switch (bufpipe[0] - '0')
|
||||
{
|
||||
case DCC_ACTIVE:
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
break;
|
||||
case DCC_DONE:
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
break;
|
||||
case DCC_FAILED:
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_send_fork: fork process for sending file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_send_fork (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (!dcc_file_create_pipe (ptr_dcc))
|
||||
return;
|
||||
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
|
||||
|
||||
switch (pid = fork ())
|
||||
{
|
||||
/* fork failed */
|
||||
case -1:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to fork\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return;
|
||||
/* child process */
|
||||
case 0:
|
||||
setuid (getuid ());
|
||||
dcc_file_send_child (ptr_dcc);
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
ptr_dcc->child_pid = pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_file_recv_fork: fork process for receiving file
|
||||
*/
|
||||
|
||||
void
|
||||
dcc_file_recv_fork (t_irc_dcc *ptr_dcc)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if (!dcc_file_create_pipe (ptr_dcc))
|
||||
return;
|
||||
|
||||
if (ptr_dcc->start_resume > 0)
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_APPEND | O_WRONLY | O_NONBLOCK);
|
||||
else
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename,
|
||||
O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
|
||||
0644);
|
||||
|
||||
switch (pid = fork ())
|
||||
{
|
||||
/* fork failed */
|
||||
case -1:
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to fork\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
return;
|
||||
/* child process */
|
||||
case 0:
|
||||
setuid (getuid ());
|
||||
dcc_file_recv_child (ptr_dcc);
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process */
|
||||
ptr_dcc->child_pid = pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* dcc_handle: receive/send data for all active DCC
|
||||
*/
|
||||
@@ -1293,9 +1672,6 @@ void
|
||||
dcc_handle ()
|
||||
{
|
||||
t_irc_dcc *ptr_dcc;
|
||||
int num_read, num_sent;
|
||||
static char buffer[DCC_MAX_BLOCKSIZE];
|
||||
uint32_t pos;
|
||||
fd_set read_fd;
|
||||
static struct timeval timeout;
|
||||
int sock;
|
||||
@@ -1309,6 +1685,11 @@ dcc_handle ()
|
||||
{
|
||||
if ((cfg_dcc_timeout != 0) && (time (NULL) > ptr_dcc->last_activity + cfg_dcc_timeout))
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: timeout\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
@@ -1336,6 +1717,11 @@ dcc_handle ()
|
||||
ptr_dcc->sock = -1;
|
||||
if (sock < 0)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to create socket for sending file\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
@@ -1343,15 +1729,20 @@ dcc_handle ()
|
||||
ptr_dcc->sock = sock;
|
||||
if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
|
||||
{
|
||||
irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
|
||||
PREFIX_ERROR);
|
||||
gui_printf (ptr_dcc->server->buffer,
|
||||
_("%s DCC: unable to set 'nonblock' option for socket\n"),
|
||||
WEECHAT_ERROR);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
|
||||
ptr_dcc->status = DCC_ACTIVE;
|
||||
ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
|
||||
ptr_dcc->start_transfer = time (NULL);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
dcc_file_send_fork (ptr_dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1413,98 +1804,18 @@ dcc_handle ()
|
||||
dcc_chat_recv (ptr_dcc);
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->type == DCC_FILE_RECV)
|
||||
else
|
||||
{
|
||||
num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
|
||||
if (num_read != -1)
|
||||
FD_ZERO (&read_fd);
|
||||
FD_SET (ptr_dcc->child_read, &read_fd);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* something to read on child pipe? */
|
||||
if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0)
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (write (ptr_dcc->file, buffer, num_read) == -1)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
ptr_dcc->pos += (unsigned long) num_read;
|
||||
pos = htonl (ptr_dcc->pos);
|
||||
send (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
if (ptr_dcc->pos >= ptr_dcc->size)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
}
|
||||
else
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->type == DCC_FILE_SEND)
|
||||
{
|
||||
if (cfg_dcc_blocksize > (int) sizeof (buffer))
|
||||
{
|
||||
irc_display_prefix (NULL, NULL, PREFIX_ERROR);
|
||||
gui_printf (NULL, _("%s DCC failed because blocksize is too "
|
||||
"big. Check value of \"dcc_blocksize\" option, "
|
||||
"max is %d.\n"),
|
||||
WEECHAT_ERROR, DCC_MAX_BLOCKSIZE);
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
if (ptr_dcc->pos > ptr_dcc->ack)
|
||||
{
|
||||
/* we should receive ACK for packets sent previously */
|
||||
num_read = recv (ptr_dcc->sock, (char *) &pos, 4, MSG_PEEK);
|
||||
if (num_read != -1)
|
||||
{
|
||||
if (num_read == 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
if (num_read < 4)
|
||||
continue;
|
||||
recv (ptr_dcc->sock, (char *) &pos, 4, 0);
|
||||
ptr_dcc->ack = ntohl (pos);
|
||||
|
||||
if ((ptr_dcc->pos >= ptr_dcc->size)
|
||||
&& (ptr_dcc->ack >= ptr_dcc->size))
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_DONE);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptr_dcc->pos <= ptr_dcc->ack)
|
||||
{
|
||||
lseek (ptr_dcc->file, ptr_dcc->pos, SEEK_SET);
|
||||
num_read = read (ptr_dcc->file, buffer, cfg_dcc_blocksize);
|
||||
if (num_read < 1)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
num_sent = send (ptr_dcc->sock, buffer, num_read, 0);
|
||||
if (num_sent < 0)
|
||||
{
|
||||
dcc_close (ptr_dcc, DCC_FAILED);
|
||||
dcc_redraw (HOTLIST_MSG);
|
||||
continue;
|
||||
}
|
||||
ptr_dcc->last_activity = time (NULL);
|
||||
ptr_dcc->pos += (unsigned long) num_sent;
|
||||
dcc_calculate_speed (ptr_dcc, 0);
|
||||
dcc_redraw (HOTLIST_LOW);
|
||||
if (FD_ISSET (ptr_dcc->child_read, &read_fd))
|
||||
dcc_file_child_read (ptr_dcc);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1555,11 +1866,16 @@ dcc_print_log ()
|
||||
weechat_log_printf (" port. . . . . . . . : %d\n", ptr_dcc->port);
|
||||
weechat_log_printf (" nick. . . . . . . . : '%s'\n", ptr_dcc->nick);
|
||||
weechat_log_printf (" sock. . . . . . . . : %d\n", ptr_dcc->sock);
|
||||
weechat_log_printf (" child_pid . . . . . : %d\n", ptr_dcc->child_pid);
|
||||
weechat_log_printf (" child_read. . . . . : %d\n", ptr_dcc->child_read);
|
||||
weechat_log_printf (" child_write . . . . : %d\n", ptr_dcc->child_write);
|
||||
weechat_log_printf (" unterminated_message: '%s'\n", ptr_dcc->unterminated_message);
|
||||
weechat_log_printf (" fast_send . . . . . : %d\n", ptr_dcc->fast_send);
|
||||
weechat_log_printf (" file. . . . . . . . : %d\n", ptr_dcc->file);
|
||||
weechat_log_printf (" filename. . . . . . : '%s'\n", ptr_dcc->filename);
|
||||
weechat_log_printf (" local_filename. . . : '%s'\n", ptr_dcc->local_filename);
|
||||
weechat_log_printf (" filename_suffix . . : %d\n", ptr_dcc->filename_suffix);
|
||||
weechat_log_printf (" blocksize . . . . . : %d\n", ptr_dcc->blocksize);
|
||||
weechat_log_printf (" size. . . . . . . . : %lu\n", ptr_dcc->size);
|
||||
weechat_log_printf (" pos . . . . . . . . : %lu\n", ptr_dcc->pos);
|
||||
weechat_log_printf (" ack . . . . . . . . : %lu\n", ptr_dcc->ack);
|
||||
|
||||
@@ -870,11 +870,11 @@ server_recv (t_irc_server *server)
|
||||
}
|
||||
|
||||
/*
|
||||
* server_kill_child: kill child process and close pipe
|
||||
* server_child_kill: kill child process and close pipe
|
||||
*/
|
||||
|
||||
void
|
||||
server_kill_child (t_irc_server *server)
|
||||
server_child_kill (t_irc_server *server)
|
||||
{
|
||||
/* kill process */
|
||||
if (server->child_pid > 0)
|
||||
@@ -904,7 +904,7 @@ server_kill_child (t_irc_server *server)
|
||||
void
|
||||
server_close_connection (t_irc_server *server)
|
||||
{
|
||||
server_kill_child (server);
|
||||
server_child_kill (server);
|
||||
|
||||
/* close network socket */
|
||||
if (server->sock != -1)
|
||||
@@ -962,7 +962,7 @@ server_child_read (t_irc_server *server)
|
||||
int num_read;
|
||||
|
||||
num_read = read (server->child_read, buffer, sizeof (buffer));
|
||||
if (num_read != -1)
|
||||
if (num_read > 0)
|
||||
{
|
||||
switch (buffer[0])
|
||||
{
|
||||
@@ -987,7 +987,7 @@ server_child_read (t_irc_server *server)
|
||||
}
|
||||
#endif
|
||||
/* kill child and login to server */
|
||||
server_kill_child (server);
|
||||
server_child_kill (server);
|
||||
irc_login (server);
|
||||
break;
|
||||
/* adress not found */
|
||||
@@ -1673,7 +1673,7 @@ server_connect (t_irc_server *server)
|
||||
_exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* parent process go on here */
|
||||
/* parent process */
|
||||
server->child_pid = pid;
|
||||
|
||||
return 1;
|
||||
|
||||
+25
-1
@@ -241,6 +241,8 @@ struct t_irc_message
|
||||
#define DCC_FILE_RECV 2 /* incoming DCC file */
|
||||
#define DCC_FILE_SEND 3 /* sending DCC file */
|
||||
|
||||
/* DCC status */
|
||||
|
||||
#define DCC_WAITING 0 /* waiting for host answer */
|
||||
#define DCC_CONNECTING 1 /* connecting to host */
|
||||
#define DCC_ACTIVE 2 /* sending/receiving data */
|
||||
@@ -248,14 +250,29 @@ struct t_irc_message
|
||||
#define DCC_FAILED 4 /* DCC failed */
|
||||
#define DCC_ABORTED 5 /* DCC aborted by user */
|
||||
|
||||
/* DCC blocksize (for file) */
|
||||
|
||||
#define DCC_MIN_BLOCKSIZE 1024 /* min DCC block size when sending file */
|
||||
#define DCC_MAX_BLOCKSIZE 102400 /* max DCC block size when sending file */
|
||||
|
||||
/* DCC errors (for file) */
|
||||
|
||||
#define DCC_NO_ERROR 0 /* used when no error to report, all ok! */
|
||||
#define DCC_ERROR_READ_LOCAL 1 /* unable to read local file */
|
||||
#define DCC_ERROR_SEND_BLOCK 2 /* unable to send block to receiver */
|
||||
#define DCC_ERROR_READ_ACK 3 /* unable to read ACK from receiver */
|
||||
#define DCC_ERROR_RECV_BLOCK 4 /* unable to receive block from sender */
|
||||
#define DCC_ERROR_WRITE_LOCAL 5 /* unable to write to local file */
|
||||
|
||||
/* DCC macros for type */
|
||||
|
||||
#define DCC_IS_CHAT(type) ((type == DCC_CHAT_RECV) || (type == DCC_CHAT_SEND))
|
||||
#define DCC_IS_FILE(type) ((type == DCC_FILE_RECV) || (type == DCC_FILE_SEND))
|
||||
#define DCC_IS_RECV(type) ((type == DCC_CHAT_RECV) || (type == DCC_FILE_RECV))
|
||||
#define DCC_IS_SEND(type) ((type == DCC_CHAT_SEND) || (type == DCC_FILE_SEND))
|
||||
|
||||
/* DCC macro for status */
|
||||
|
||||
#define DCC_ENDED(status) ((status == DCC_DONE) || (status == DCC_FAILED) || \
|
||||
(status == DCC_ABORTED))
|
||||
|
||||
@@ -265,7 +282,7 @@ struct t_irc_dcc
|
||||
{
|
||||
t_irc_server *server; /* irc server */
|
||||
t_irc_channel *channel; /* irc channel (for DCC chat only) */
|
||||
int type; /* DCC type (send or receive) */
|
||||
int type; /* DCC type (file/chat, send/receive) */
|
||||
int status; /* DCC status (waiting, sending, ..) */
|
||||
time_t start_time; /* the time when DCC started */
|
||||
time_t start_transfer; /* the time when DCC transfer started */
|
||||
@@ -273,11 +290,16 @@ struct t_irc_dcc
|
||||
int port; /* port */
|
||||
char *nick; /* remote nick */
|
||||
int sock; /* socket for connection */
|
||||
pid_t child_pid; /* pid of child process (sending/recving) */
|
||||
int child_read; /* to read into child pipe */
|
||||
int child_write; /* to write into child pipe */
|
||||
char *unterminated_message; /* beginning of a message in input buf */
|
||||
int fast_send; /* fase send for files: does not wait ACK */
|
||||
int file; /* local file (for reading or writing) */
|
||||
char *filename; /* filename (given by sender) */
|
||||
char *local_filename; /* local filename (with path) */
|
||||
int filename_suffix; /* suffix (.1 for ex) if renaming file */
|
||||
int blocksize; /* block size for sending file */
|
||||
unsigned long size; /* file size */
|
||||
unsigned long pos; /* number of bytes received/sent */
|
||||
unsigned long ack; /* number of bytes received OK */
|
||||
@@ -421,6 +443,8 @@ extern t_irc_dcc *dcc_add (t_irc_server *, int, unsigned long, int, char *, int,
|
||||
char *, char *, unsigned long);
|
||||
extern void dcc_send_request (t_irc_server *, int, char *, char *);
|
||||
extern void dcc_chat_sendf (t_irc_dcc *, char *, ...);
|
||||
extern void dcc_file_send_fork (t_irc_dcc *);
|
||||
extern void dcc_file_recv_fork (t_irc_dcc *);
|
||||
extern void dcc_handle ();
|
||||
extern void dcc_end ();
|
||||
extern void dcc_print_log ();
|
||||
|
||||
Reference in New Issue
Block a user