mirror of
https://github.com/irssi/irssi.git
synced 2025-01-03 14:56:47 -05:00
c2397475c5
git-svn-id: http://svn.irssi.org/repos/irssi/trunk@480 dbcabf3a-b0e7-0310-adc4-f8d773084564
220 lines
4.7 KiB
C
220 lines
4.7 KiB
C
/*
|
|
net-nonblock.c : Nonblocking net_connect()
|
|
|
|
Copyright (C) 1998-2000 Timo Sirainen
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "module.h"
|
|
|
|
#include <signal.h>
|
|
|
|
#include "pidwait.h"
|
|
#include "net-nonblock.h"
|
|
|
|
typedef struct {
|
|
NET_CALLBACK func;
|
|
void *data;
|
|
|
|
int pipes[2];
|
|
int port;
|
|
IPADDR *my_ip;
|
|
int tag;
|
|
} SIMPLE_THREAD_REC;
|
|
|
|
/* nonblocking gethostbyname(), ip (IPADDR) + error (int, 0 = not error) is
|
|
written to pipe when found PID of the resolver child is returned */
|
|
int net_gethostbyname_nonblock(const char *addr, int pipe)
|
|
{
|
|
RESOLVED_IP_REC rec;
|
|
const char *errorstr;
|
|
int pid;
|
|
|
|
g_return_val_if_fail(addr != NULL, FALSE);
|
|
|
|
pid = fork();
|
|
if (pid > 0) {
|
|
/* parent */
|
|
pidwait_add(pid);
|
|
return pid;
|
|
}
|
|
|
|
if (pid != 0) {
|
|
/* failed! */
|
|
g_warning("net_connect_thread(): fork() failed! "
|
|
"Using blocking resolving");
|
|
}
|
|
|
|
/* child */
|
|
memset(&rec, 0, sizeof(rec));
|
|
rec.error = net_gethostbyname(addr, &rec.ip);
|
|
if (rec.error == 0) {
|
|
errorstr = NULL;
|
|
} else {
|
|
errorstr = net_gethosterror(rec.error);
|
|
rec.errlen = strlen(errorstr)+1;
|
|
}
|
|
|
|
write(pipe, &rec, sizeof(rec));
|
|
if (rec.error != 0)
|
|
write(pipe, errorstr, rec.errlen);
|
|
|
|
if (pid == 0)
|
|
_exit(99);
|
|
|
|
/* we used blocking lookup */
|
|
return 0;
|
|
}
|
|
|
|
/* get the resolved IP address */
|
|
int net_gethostbyname_return(int pipe, RESOLVED_IP_REC *rec)
|
|
{
|
|
time_t maxwait;
|
|
int len, ret;
|
|
|
|
rec->error = -1;
|
|
rec->errorstr = NULL;
|
|
|
|
/* get ip+error - try for max. 1-2 seconds */
|
|
fcntl(pipe, F_SETFL, O_NONBLOCK);
|
|
|
|
maxwait = time(NULL)+2;
|
|
len = 0;
|
|
do {
|
|
ret = read(pipe, (char *) rec+len, sizeof(*rec)-len);
|
|
if (ret == -1) return -1;
|
|
|
|
len += ret;
|
|
} while (len < sizeof(*rec) && time(NULL) < maxwait);
|
|
|
|
if (len < sizeof(*rec))
|
|
return -1; /* timeout */
|
|
|
|
if (rec->error) {
|
|
/* read error string */
|
|
rec->errorstr = g_malloc(rec->errlen+1);
|
|
len = 0;
|
|
do {
|
|
ret = read(pipe, rec->errorstr+len, rec->errlen-len);
|
|
if (ret == -1) break;
|
|
len += ret;
|
|
} while (len < rec->errlen && time(NULL) < maxwait);
|
|
|
|
if (len < rec->errlen) {
|
|
/* just ignore the rest of the error message.. */
|
|
rec->errorstr[len] = '\0';
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Get host name, call func when finished */
|
|
int net_gethostbyaddr_nonblock(IPADDR *ip, NET_HOST_CALLBACK func, void *data)
|
|
{
|
|
/*FIXME*/
|
|
return FALSE;
|
|
}
|
|
|
|
/* Kill the resolver child */
|
|
void net_disconnect_nonblock(int pid)
|
|
{
|
|
g_return_if_fail(pid > 0);
|
|
|
|
kill(pid, SIGKILL);
|
|
}
|
|
|
|
static void simple_init(SIMPLE_THREAD_REC *rec, int handle)
|
|
{
|
|
g_return_if_fail(rec != NULL);
|
|
|
|
g_source_remove(rec->tag);
|
|
|
|
if (net_geterror(handle) != 0) {
|
|
/* failed */
|
|
close(handle);
|
|
handle = -1;
|
|
}
|
|
|
|
rec->func(handle, rec->data);
|
|
g_free(rec);
|
|
}
|
|
|
|
static void simple_readpipe(SIMPLE_THREAD_REC *rec, int pipe)
|
|
{
|
|
RESOLVED_IP_REC iprec;
|
|
int handle;
|
|
|
|
g_return_if_fail(rec != NULL);
|
|
|
|
g_source_remove(rec->tag);
|
|
|
|
net_gethostbyname_return(pipe, &iprec);
|
|
g_free_not_null(iprec.errorstr);
|
|
|
|
close(rec->pipes[0]);
|
|
close(rec->pipes[1]);
|
|
|
|
handle = iprec.error == -1 ? -1 :
|
|
net_connect_ip(&iprec.ip, rec->port, rec->my_ip);
|
|
|
|
g_free_not_null(rec->my_ip);
|
|
|
|
if (handle == -1) {
|
|
/* failed */
|
|
rec->func(-1, rec->data);
|
|
g_free(rec);
|
|
return;
|
|
}
|
|
|
|
rec->tag = g_input_add(handle, G_INPUT_READ | G_INPUT_WRITE,
|
|
(GInputFunction) simple_init, rec);
|
|
}
|
|
|
|
/* Connect to server, call func when finished */
|
|
int net_connect_nonblock(const char *server, int port, const IPADDR *my_ip,
|
|
NET_CALLBACK func, void *data)
|
|
{
|
|
SIMPLE_THREAD_REC *rec;
|
|
int fd[2];
|
|
|
|
g_return_val_if_fail(server != NULL, FALSE);
|
|
g_return_val_if_fail(func != NULL, FALSE);
|
|
|
|
if (pipe(fd) != 0) {
|
|
g_warning("net_connect_nonblock(): pipe() failed.");
|
|
return FALSE;
|
|
}
|
|
|
|
/* start nonblocking host name lookup */
|
|
net_gethostbyname_nonblock(server, fd[1]);
|
|
|
|
rec = g_new0(SIMPLE_THREAD_REC, 1);
|
|
rec->port = port;
|
|
if (my_ip != NULL) {
|
|
rec->my_ip = g_malloc(sizeof(IPADDR));
|
|
memcpy(rec->my_ip, my_ip, sizeof(IPADDR));
|
|
}
|
|
rec->func = func;
|
|
rec->data = data;
|
|
rec->pipes[0] = fd[0];
|
|
rec->pipes[1] = fd[1];
|
|
rec->tag = g_input_add(fd[0], G_INPUT_READ,
|
|
(GInputFunction) simple_readpipe, rec);
|
|
|
|
return 1;
|
|
}
|