Compare commits
10 Commits
c9e57161cc
...
65cd4429bb
Author | SHA1 | Date | |
---|---|---|---|
|
65cd4429bb | ||
|
8648d7a479 | ||
|
ec50c55c36 | ||
|
ced20ad0d9 | ||
|
b841374827 | ||
|
b9a4746b54 | ||
|
460bfbb8ac | ||
|
92faccc639 | ||
|
f6ccf9c4f5 | ||
|
16ecde504d |
108
AUTHORS
108
AUTHORS
|
@ -1,17 +1,101 @@
|
||||||
Oswald Buddenhagen <ossi@users.sf.net>
|
Contact
|
||||||
* Contributor, current maintainer
|
=======
|
||||||
|
|
||||||
Theodore Ts'o <tytso@mit.edu>
|
|
||||||
* Contributor, Debian package co-maintainer
|
|
||||||
|
|
||||||
Nicolas Boullis <nboullis@debian.org>
|
|
||||||
* Debian package maintainer and minor upstream contributions
|
|
||||||
|
|
||||||
Michael Elkins <me@mutt.org>
|
|
||||||
* Original author
|
|
||||||
|
|
||||||
Send questions and bug reports to the isync-devel@lists.sourceforge.net
|
Send questions and bug reports to the isync-devel@lists.sourceforge.net
|
||||||
mailing list.
|
mailing list.
|
||||||
|
|
||||||
_DON'T_ report bugs to Michael, not even in a CC: - he is not actively
|
Do _NOT_ report bugs to Michael, not even in a CC: - he is not actively
|
||||||
involved in isync development any more.
|
involved in isync development any more.
|
||||||
|
|
||||||
|
Lead Developers
|
||||||
|
===============
|
||||||
|
|
||||||
|
Oswald Buddenhagen <ossi@users.sf.net>
|
||||||
|
- Current maintainer
|
||||||
|
|
||||||
|
Michael Elkins <me@mutt.org>
|
||||||
|
- Original author
|
||||||
|
|
||||||
|
Contributors
|
||||||
|
============
|
||||||
|
|
||||||
|
(Some of these people also contributed bugfixes and optimizations.)
|
||||||
|
(In chronological order.)
|
||||||
|
|
||||||
|
Jeremy Katz <katzj@linuxpower.org>
|
||||||
|
- UseNamespace & UseSSL* options
|
||||||
|
|
||||||
|
Daniel Resare <noa@metamatrix.se>
|
||||||
|
- Numerous SSL handling improvements
|
||||||
|
|
||||||
|
Eivind Eklund <eivind@FreeBSD.org>
|
||||||
|
- MaxMessages option
|
||||||
|
|
||||||
|
Theodore Ts'o <tytso@mit.edu>
|
||||||
|
- get-cert script
|
||||||
|
- Maildir UID mapping improvements
|
||||||
|
- Initial version of partial async IMAP support
|
||||||
|
|
||||||
|
Marc Hoersken <info@marc-hoersken.de>
|
||||||
|
- CopyArrivalDate option
|
||||||
|
|
||||||
|
Jack Stone <jwjstone@fastmail.fm>
|
||||||
|
Jan Synacek <jsynacek@redhat.com>
|
||||||
|
- SASL support
|
||||||
|
|
||||||
|
Jesse Weaver <pianohacker@gmail.com>
|
||||||
|
- IMAP stream compression support
|
||||||
|
|
||||||
|
Anton Khirnov <anton@khirnov.net>
|
||||||
|
- ClientKey & ClientCertificate options
|
||||||
|
|
||||||
|
Michael J Gruber <github@grubix.eu>
|
||||||
|
- Support for the $Forwarded/Passed flag
|
||||||
|
|
||||||
|
Patrick Steinhardt <ps@pks.im>
|
||||||
|
- UserCmd option
|
||||||
|
|
||||||
|
Oliver Runge <oliver.runge@gmail.com>
|
||||||
|
- UseKeychain option
|
||||||
|
|
||||||
|
Georgy Kibardin <georgy@kibardin.name>
|
||||||
|
- Support for UTF-7 IMAP mailbox names
|
||||||
|
|
||||||
|
Honorary Contributors
|
||||||
|
=====================
|
||||||
|
|
||||||
|
(These people contributed patches that were too small or obvious
|
||||||
|
to claim copyright, or were rewritten from scratch.)
|
||||||
|
(In alphabetical order.)
|
||||||
|
|
||||||
|
Alessandro Ghedini <ghedo@debian.org>
|
||||||
|
Andreas Grapentin <andreas@grapentin.org>
|
||||||
|
Aurélien Francillon <aurelien.francillon@eurecom.fr>
|
||||||
|
Ben Kibbey <bjk@luxsci.net>
|
||||||
|
Caspar Schutijser <caspar@schutijser.com>
|
||||||
|
Cedric Ware <cedric.ware__bml@normalesup.org>
|
||||||
|
Dmitrij D. Czarkoff <czarkoff@gmail.com>
|
||||||
|
Dmitry Torokhov <dtor@chromium.org>
|
||||||
|
Felipe Contreras <felipe.contreras@gmail.com>
|
||||||
|
Felix Janda <felix.janda@posteo.de>
|
||||||
|
Gergely Risko <gergely@risko.hu>
|
||||||
|
Sung Pae "guns" <self@sungpae.com>
|
||||||
|
Helmut Grohne <helmut@subdivi.de>
|
||||||
|
Hugo Haas <hugo@larve.net>
|
||||||
|
Jaroslav Suchanek <jaroslav.suchanek@gmail.com>
|
||||||
|
Jeremie Courreges-Anglas <jca@openbsd.org>
|
||||||
|
Klemens Nanni <kn@openbsd.org>
|
||||||
|
Lorenzo Martignoni <lorenzo.martignoni@technologist.com>
|
||||||
|
Magnus Jonsson <bigfoot@acc.umu.se>
|
||||||
|
Marcin Niestroj <macius1990w@gmail.com>
|
||||||
|
Martin Stenberg <martin@gnutiken.se>
|
||||||
|
Mike Delaney <mdelan@lusars.net>
|
||||||
|
Nicolas Boullis <nboullis@debian.org>
|
||||||
|
Nihal Jere <nihal@nihaljere.xyz>
|
||||||
|
Reimar Döffinger <Reimar.Doeffinger@gmx.de>
|
||||||
|
Remko Tronçon <remko@el-tramo.be>
|
||||||
|
sbfnk@users.sf.net
|
||||||
|
Thomas Roessler <roessler@does-not-exist.org>
|
||||||
|
Todd T. Fries <todd@fries.net>
|
||||||
|
Vincent Bernat <vincent@bernat.ch>
|
||||||
|
Yuri D'Elia <wavexx@thregr.org>
|
||||||
|
|
42
src/main.c
42
src/main.c
|
@ -89,6 +89,26 @@ PACKAGE " " VERSION " - mailbox synchronizer\n"
|
||||||
exit( code );
|
exit( code );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int child_pipe[2];
|
||||||
|
static notifier_t child_notifier;
|
||||||
|
|
||||||
|
static void
|
||||||
|
childHandler( int n ATTR_UNUSED )
|
||||||
|
{
|
||||||
|
// We can't just reap everything here, as we might steal children
|
||||||
|
// from popen(). Let the main loop handle it synchronously instead.
|
||||||
|
char dummy = 0;
|
||||||
|
write( child_pipe[1], &dummy, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
childReaper( int events ATTR_UNUSED, void *aux ATTR_UNUSED )
|
||||||
|
{
|
||||||
|
char dummy;
|
||||||
|
while (read( child_pipe[0], &dummy, 1 ) == 1) {}
|
||||||
|
while (waitpid( -1, NULL, WNOHANG ) > 0) {}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
static void ATTR_NORETURN
|
static void ATTR_NORETURN
|
||||||
crashHandler( int n )
|
crashHandler( int n )
|
||||||
|
@ -541,9 +561,31 @@ main( int argc, char **argv )
|
||||||
if (load_config( config ))
|
if (load_config( config ))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
signal( SIGPIPE, SIG_IGN );
|
||||||
|
|
||||||
|
if (pipe( child_pipe )) {
|
||||||
|
perror( "pipe" );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fcntl( child_pipe[0], F_SETFL, O_NONBLOCK );
|
||||||
|
fcntl( child_pipe[1], F_SETFL, O_NONBLOCK );
|
||||||
|
init_notifier( &child_notifier, child_pipe[0], childReaper, NULL );
|
||||||
|
conf_notifier( &child_notifier, 0, POLLIN );
|
||||||
|
struct sigaction sa = { 0 };
|
||||||
|
sa.sa_handler = childHandler;
|
||||||
|
sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
|
||||||
|
sigaction( SIGCHLD, &sa, NULL );
|
||||||
|
|
||||||
if (mvars->list_stores)
|
if (mvars->list_stores)
|
||||||
list_stores( mvars, argv + oind );
|
list_stores( mvars, argv + oind );
|
||||||
else
|
else
|
||||||
sync_chans( mvars, argv + oind );
|
sync_chans( mvars, argv + oind );
|
||||||
return mvars->ret;
|
return mvars->ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cleanup_mainloop( void )
|
||||||
|
{
|
||||||
|
cleanup_drivers();
|
||||||
|
wipe_notifier( &child_notifier );
|
||||||
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ do_list_stores( list_vars_t *lvars )
|
||||||
next:
|
next:
|
||||||
advance_store( lvars );
|
advance_store( lvars );
|
||||||
}
|
}
|
||||||
cleanup_drivers();
|
cleanup_mainloop();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -21,5 +21,6 @@ typedef struct {
|
||||||
|
|
||||||
void sync_chans( core_vars_t *cvars, char **argv );
|
void sync_chans( core_vars_t *cvars, char **argv );
|
||||||
void list_stores( core_vars_t *cvars, char **argv );
|
void list_stores( core_vars_t *cvars, char **argv );
|
||||||
|
void cleanup_mainloop( void );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,9 +43,11 @@ print_stats( void )
|
||||||
static void
|
static void
|
||||||
stats_timeout( void *aux ATTR_UNUSED )
|
stats_timeout( void *aux ATTR_UNUSED )
|
||||||
{
|
{
|
||||||
|
if (stats_steps != -1) {
|
||||||
stats_steps = -1;
|
stats_steps = -1;
|
||||||
conf_wakeup( &stats_wakeup, 200 );
|
|
||||||
print_stats();
|
print_stats();
|
||||||
|
}
|
||||||
|
conf_wakeup( &stats_wakeup, 200 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -55,8 +57,10 @@ stats( void )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If the main loop appears to be running, skip the sync path.
|
// If the main loop appears to be running, skip the sync path.
|
||||||
if (stats_steps < 0)
|
if (stats_steps < 0) {
|
||||||
|
stats_steps = -2;
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Rate-limit the (somewhat) expensive timer queries.
|
// Rate-limit the (somewhat) expensive timer queries.
|
||||||
if (++stats_steps < 10)
|
if (++stats_steps < 10)
|
||||||
|
@ -492,7 +496,7 @@ do_sync_chans( main_vars_t *mvars )
|
||||||
next:
|
next:
|
||||||
advance_chan( mvars );
|
advance_chan( mvars );
|
||||||
}
|
}
|
||||||
cleanup_drivers();
|
cleanup_mainloop();
|
||||||
if (!mvars->cvars->list && (DFlags & PROGRESS))
|
if (!mvars->cvars->list && (DFlags & PROGRESS))
|
||||||
wipe_wakeup( &stats_wakeup );
|
wipe_wakeup( &stats_wakeup );
|
||||||
}
|
}
|
||||||
|
@ -668,7 +672,7 @@ static void
|
||||||
do_sync_boxes( main_vars_t *mvars )
|
do_sync_boxes( main_vars_t *mvars )
|
||||||
{
|
{
|
||||||
mvars->box_cben = 0;
|
mvars->box_cben = 0;
|
||||||
for (;;) {
|
while (mvars->state[F] == ST_OPEN && mvars->state[N] == ST_OPEN) {
|
||||||
if (mvars->chanptr->boxlist) {
|
if (mvars->chanptr->boxlist) {
|
||||||
box_ent_t *mbox = mvars->boxptr;
|
box_ent_t *mbox = mvars->boxptr;
|
||||||
if (!mbox)
|
if (!mbox)
|
||||||
|
@ -730,13 +734,11 @@ done_sync( int sts, void *aux )
|
||||||
stats();
|
stats();
|
||||||
if (sts) {
|
if (sts) {
|
||||||
mvars->cvars->ret = 1;
|
mvars->cvars->ret = 1;
|
||||||
if (sts & (SYNC_BAD(F) | SYNC_BAD(N))) {
|
|
||||||
if (sts & SYNC_BAD(F))
|
if (sts & SYNC_BAD(F))
|
||||||
mvars->state[F] = ST_CLOSED;
|
mvars->state[F] = ST_CLOSED;
|
||||||
if (sts & SYNC_BAD(N))
|
if (sts & SYNC_BAD(N))
|
||||||
mvars->state[N] = ST_CLOSED;
|
mvars->state[N] = ST_CLOSED;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mvars->box_done = 1;
|
mvars->box_done = 1;
|
||||||
if (mvars->box_cben)
|
if (mvars->box_cben)
|
||||||
do_sync_boxes( mvars );
|
do_sync_boxes( mvars );
|
||||||
|
|
14
src/mbsync.1
14
src/mbsync.1
|
@ -36,6 +36,7 @@ Multiple replicas of each mailbox can be maintained.
|
||||||
Read configuration from \fIfile\fR.
|
Read configuration from \fIfile\fR.
|
||||||
By default, the configuration is read from $XDG_CONFIG_HOME/isyncrc, and
|
By default, the configuration is read from $XDG_CONFIG_HOME/isyncrc, and
|
||||||
if that does not exist, ~/.mbsyncrc is tried in turn.
|
if that does not exist, ~/.mbsyncrc is tried in turn.
|
||||||
|
$XDG_CONFIG_HOME defaults to ~/.config if not set.
|
||||||
.TP
|
.TP
|
||||||
\fB-a\fR, \fB--all\fR
|
\fB-a\fR, \fB--all\fR
|
||||||
Select all configured Channels. Any Channel/Group specifications on the
|
Select all configured Channels. Any Channel/Group specifications on the
|
||||||
|
@ -80,8 +81,10 @@ operations are determined, but no modifications are actually made
|
||||||
to either the mailboxes or the state files.
|
to either the mailboxes or the state files.
|
||||||
.TP
|
.TP
|
||||||
\fB-e\fR, \fB--ext-exit\fR
|
\fB-e\fR, \fB--ext-exit\fR
|
||||||
Return an extended exit code: Add 32 resp. 64 to the code if any
|
Return an extended exit code: Add 32 or 64 to the code if any
|
||||||
modifications were made on the far resp. near side.
|
modifications were made on the far or near side, respectively; these
|
||||||
|
are not mutually exclusive, so the code may be 96 if changes were both
|
||||||
|
pushed and pulled.
|
||||||
An error may be reported at the same time, so the code may be for example
|
An error may be reported at the same time, so the code may be for example
|
||||||
65 if some changes were successfully pulled, while others failed.
|
65 if some changes were successfully pulled, while others failed.
|
||||||
.TP
|
.TP
|
||||||
|
@ -730,7 +733,8 @@ the appended string is made up according to the pattern
|
||||||
(see also \fBFieldDelimiter\fR below).
|
(see also \fBFieldDelimiter\fR below).
|
||||||
.br
|
.br
|
||||||
(Global default: \fI$XDG_STATE_HOME/isync/\fR, with a fallback to
|
(Global default: \fI$XDG_STATE_HOME/isync/\fR, with a fallback to
|
||||||
\fI~/.mbsync/\fR if only that exists)
|
\fI~/.mbsync/\fR if only that exists.
|
||||||
|
$XDG_STATE_HOME defaults to ~/.local/state if not set.)
|
||||||
.
|
.
|
||||||
.SS Groups
|
.SS Groups
|
||||||
.TP
|
.TP
|
||||||
|
@ -856,11 +860,11 @@ There is no risk as long as the IMAP mailbox is accessed by only one client
|
||||||
.
|
.
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.TP
|
.TP
|
||||||
.B $XDG_CONFIG_HOME/isyncrc
|
\fB$XDG_CONFIG_HOME/isyncrc\fR (usually \fB~/.config/isyncrc\fR)
|
||||||
Default configuration file.
|
Default configuration file.
|
||||||
See also the example file in the documentation directory.
|
See also the example file in the documentation directory.
|
||||||
.TP
|
.TP
|
||||||
.B $XDG_STATE_HOME/isync/
|
\fB$XDG_STATE_HOME/isync/\fR (usually \fB~/.local/state/isync/\fR)
|
||||||
Directory containing synchronization state files.
|
Directory containing synchronization state files.
|
||||||
.TP
|
.TP
|
||||||
.B ~/.mbsyncrc
|
.B ~/.mbsyncrc
|
||||||
|
|
269
src/socket.c
269
src/socket.c
|
@ -28,6 +28,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
SCK_RESOLVING,
|
||||||
SCK_CONNECTING,
|
SCK_CONNECTING,
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
SCK_STARTTLS,
|
SCK_STARTTLS,
|
||||||
|
@ -415,6 +416,7 @@ static void socket_fd_cb( int, void * );
|
||||||
static void socket_fake_cb( void * );
|
static void socket_fake_cb( void * );
|
||||||
static void socket_timeout_cb( void * );
|
static void socket_timeout_cb( void * );
|
||||||
|
|
||||||
|
static void socket_resolve( conn_t * );
|
||||||
static void socket_connect_one( conn_t * );
|
static void socket_connect_one( conn_t * );
|
||||||
static void socket_connect_next( conn_t * );
|
static void socket_connect_next( conn_t * );
|
||||||
static void socket_connect_failed( conn_t * );
|
static void socket_connect_failed( conn_t * );
|
||||||
|
@ -422,15 +424,21 @@ static void socket_connected( conn_t * );
|
||||||
static void socket_connect_bail( conn_t * );
|
static void socket_connect_bail( conn_t * );
|
||||||
|
|
||||||
static void
|
static void
|
||||||
socket_open_internal( conn_t *sock, int fd )
|
socket_register_internal( conn_t *sock, int fd )
|
||||||
{
|
{
|
||||||
sock->fd = fd;
|
sock->fd = fd;
|
||||||
fcntl( fd, F_SETFL, O_NONBLOCK );
|
|
||||||
init_notifier( &sock->notify, fd, socket_fd_cb, sock );
|
init_notifier( &sock->notify, fd, socket_fd_cb, sock );
|
||||||
init_wakeup( &sock->fd_fake, socket_fake_cb, sock );
|
init_wakeup( &sock->fd_fake, socket_fake_cb, sock );
|
||||||
init_wakeup( &sock->fd_timeout, socket_timeout_cb, sock );
|
init_wakeup( &sock->fd_timeout, socket_timeout_cb, sock );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
socket_open_internal( conn_t *sock, int fd )
|
||||||
|
{
|
||||||
|
fcntl( fd, F_SETFL, O_NONBLOCK );
|
||||||
|
socket_register_internal( sock, fd );
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
socket_close_internal( conn_t *sock )
|
socket_close_internal( conn_t *sock )
|
||||||
{
|
{
|
||||||
|
@ -441,32 +449,6 @@ socket_close_internal( conn_t *sock )
|
||||||
sock->fd = -1;
|
sock->fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_IPV6
|
|
||||||
struct addr_info {
|
|
||||||
struct addr_info *ai_next;
|
|
||||||
struct sockaddr_in ai_addr[1];
|
|
||||||
};
|
|
||||||
|
|
||||||
#define freeaddrinfo(ai) free( ai )
|
|
||||||
|
|
||||||
static struct addr_info *
|
|
||||||
init_addrinfo( struct hostent *he )
|
|
||||||
{
|
|
||||||
uint naddr = 0;
|
|
||||||
for (char **addr = he->h_addr_list; *addr; addr++)
|
|
||||||
naddr++;
|
|
||||||
struct addr_info *caddr = nfzalloc( naddr * sizeof(struct addrinfo) );
|
|
||||||
struct addr_info *ret, **caddrp = &ret;
|
|
||||||
for (char **addr = he->h_addr_list; *addr; addr++, caddr++) {
|
|
||||||
caddr->ai_addr->sin_family = AF_INET;
|
|
||||||
memcpy( &caddr->ai_addr->sin_addr.s_addr, *addr, sizeof(struct in_addr) );
|
|
||||||
*caddrp = caddr;
|
|
||||||
caddrp = &caddr->ai_next;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void
|
void
|
||||||
socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
||||||
{
|
{
|
||||||
|
@ -501,77 +483,202 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
||||||
info( "\vok\n" );
|
info( "\vok\n" );
|
||||||
socket_connected( sock );
|
socket_connected( sock );
|
||||||
} else {
|
} else {
|
||||||
#ifdef HAVE_IPV6
|
socket_resolve( sock );
|
||||||
int gaierr;
|
}
|
||||||
struct addrinfo hints;
|
}
|
||||||
|
|
||||||
memset( &hints, 0, sizeof(hints) );
|
static void
|
||||||
|
pipe_write( int fd, void *buf, int len )
|
||||||
|
{
|
||||||
|
do {
|
||||||
|
int wrote = write( fd, buf, len );
|
||||||
|
if (wrote < 0) {
|
||||||
|
perror( "write" );
|
||||||
|
_exit( 1 );
|
||||||
|
}
|
||||||
|
buf = ((char *)buf) + wrote;
|
||||||
|
len -= wrote;
|
||||||
|
} while (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
socket_resolve( conn_t *sock )
|
||||||
|
{
|
||||||
|
info( "Resolving %s...\n", sock->conf->host );
|
||||||
|
|
||||||
|
int pfd[2];
|
||||||
|
if (pipe( pfd )) {
|
||||||
|
perror( "pipe" );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
switch (fork()) {
|
||||||
|
case -1:
|
||||||
|
perror( "fork" );
|
||||||
|
exit( 1 );
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
close( pfd[1] );
|
||||||
|
socket_register_internal( sock, pfd[0] );
|
||||||
|
sock->state = SCK_RESOLVING;
|
||||||
|
conf_notifier( &sock->notify, 0, POLLIN );
|
||||||
|
socket_expect_activity( sock, 1 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
struct addrinfo *res, hints = { 0 };
|
||||||
hints.ai_family = AF_UNSPEC;
|
hints.ai_family = AF_UNSPEC;
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
hints.ai_flags = AI_ADDRCONFIG;
|
hints.ai_flags = AI_ADDRCONFIG;
|
||||||
infon( "Resolving %s... ", conf->host );
|
int gaierr = getaddrinfo( sock->conf->host, NULL, &hints, &res );
|
||||||
if ((gaierr = getaddrinfo( conf->host, NULL, &hints, &sock->addrs ))) {
|
pipe_write( pfd[1], &gaierr, sizeof(gaierr) );
|
||||||
error( "Error: Cannot resolve server '%s': %s\n", conf->host, gai_strerror( gaierr ) );
|
if (gaierr)
|
||||||
socket_connect_bail( sock );
|
_exit( 1 );
|
||||||
return;
|
static_assert( sizeof(((struct addrinfo){ 0 }).ai_family) == sizeof(int), "unexpected size of ai_family" );
|
||||||
|
static_assert( sizeof(struct in_addr) % sizeof(int) == 0, "unexpected size of struct in_addr" );
|
||||||
|
static_assert( sizeof(struct in6_addr) % sizeof(int) == 0, "unexpected size of struct in6_addr" );
|
||||||
|
int nbytes = 0;
|
||||||
|
for (struct addrinfo *cres = res; cres; cres = cres->ai_next) {
|
||||||
|
if (cres->ai_family == AF_INET) {
|
||||||
|
nbytes += sizeof(int) + sizeof(struct in_addr);
|
||||||
|
} else {
|
||||||
|
assert( cres->ai_family == AF_INET6 );
|
||||||
|
nbytes += sizeof(int) + sizeof(struct in6_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pipe_write( pfd[1], &nbytes, sizeof(nbytes) );
|
||||||
|
for (struct addrinfo *cres = res; cres; cres = cres->ai_next) {
|
||||||
|
pipe_write( pfd[1], &cres->ai_family, sizeof(int) );
|
||||||
|
if (cres->ai_family == AF_INET)
|
||||||
|
pipe_write( pfd[1], &((struct sockaddr_in *)cres->ai_addr)->sin_addr, sizeof(struct in_addr) );
|
||||||
|
else
|
||||||
|
pipe_write( pfd[1], &((struct sockaddr_in6 *)cres->ai_addr)->sin6_addr, sizeof(struct in6_addr) );
|
||||||
}
|
}
|
||||||
info( "\vok\n" );
|
|
||||||
#else
|
#else
|
||||||
struct hostent *he;
|
struct hostent *he = gethostbyname( sock->conf->host );
|
||||||
|
int herrno = he ? 0 : h_errno;
|
||||||
|
pipe_write( pfd[1], &herrno, sizeof(herrno) );
|
||||||
|
if (!he)
|
||||||
|
_exit( 1 );
|
||||||
|
static_assert( sizeof(struct in_addr) % sizeof(int) == 0, "unexpected size of struct in_addr" );
|
||||||
|
int nbytes = 0;
|
||||||
|
for (char **addr = he->h_addr_list; *addr; addr++)
|
||||||
|
nbytes += sizeof(struct in_addr);
|
||||||
|
pipe_write( pfd[1], &nbytes, sizeof(nbytes) );
|
||||||
|
for (char **addr = he->h_addr_list; *addr; addr++)
|
||||||
|
pipe_write( pfd[1], *addr, sizeof(struct in_addr) );
|
||||||
|
#endif
|
||||||
|
_exit( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
infon( "Resolving %s... ", conf->host );
|
static void
|
||||||
he = gethostbyname( conf->host );
|
pipe_read( int fd, void *buf, int len )
|
||||||
if (!he) {
|
{
|
||||||
error( "Error: Cannot resolve server '%s': %s\n", conf->host, hstrerror( h_errno ) );
|
do {
|
||||||
|
int didrd = read( fd, buf, len );
|
||||||
|
if (didrd < 0) {
|
||||||
|
sys_error( "read" );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
if (!didrd) {
|
||||||
|
error( "read: unexpected EOF\n" );
|
||||||
|
exit( 1 );
|
||||||
|
}
|
||||||
|
buf = ((char *)buf) + didrd;
|
||||||
|
len -= didrd;
|
||||||
|
} while (len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
socket_resolve_finalize( conn_t *sock )
|
||||||
|
{
|
||||||
|
int errcode;
|
||||||
|
pipe_read( sock->fd, &errcode, sizeof(errcode) );
|
||||||
|
if (errcode) {
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
const char *err = gai_strerror( errcode );
|
||||||
|
#else
|
||||||
|
const char *err = hstrerror( errcode );
|
||||||
|
#endif
|
||||||
|
error( "Error: Cannot resolve server '%s': %s\n", sock->conf->host, err );
|
||||||
|
socket_close_internal( sock );
|
||||||
socket_connect_bail( sock );
|
socket_connect_bail( sock );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
info( "\vok\n" );
|
|
||||||
|
|
||||||
sock->addrs = init_addrinfo( he );
|
int nbytes;
|
||||||
#endif
|
pipe_read( sock->fd, &nbytes, sizeof(nbytes) );
|
||||||
sock->curr_addr = sock->addrs;
|
char *addrs = nfmalloc( nbytes );
|
||||||
|
pipe_read( sock->fd, addrs, nbytes );
|
||||||
|
sock->curr_addr = sock->addrs = addrs;
|
||||||
|
sock->addrs_end = addrs + nbytes;
|
||||||
|
socket_close_internal( sock ); // Get rid of the pipe
|
||||||
socket_connect_one( sock );
|
socket_connect_one( sock );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
socket_resolve_timeout( conn_t *sock )
|
||||||
|
{
|
||||||
|
error( "Error: Cannot resolve server '%s': timeout.\n", sock->conf->host );
|
||||||
|
socket_close_internal( sock );
|
||||||
|
socket_connect_bail( sock );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
socket_connect_one( conn_t *sock )
|
socket_connect_one( conn_t *sock )
|
||||||
{
|
{
|
||||||
int s;
|
char *ai = sock->curr_addr;
|
||||||
#ifdef HAVE_IPV6
|
if (ai == sock->addrs_end) {
|
||||||
struct addrinfo *ai;
|
|
||||||
#else
|
|
||||||
struct addr_info *ai;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!(ai = sock->curr_addr)) {
|
|
||||||
error( "No working address found for %s\n", sock->conf->host );
|
error( "No working address found for %s\n", sock->conf->host );
|
||||||
socket_connect_bail( sock );
|
socket_connect_bail( sock );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct sockaddr any;
|
||||||
|
struct sockaddr_in ip4;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (ai->ai_family == AF_INET6) {
|
struct sockaddr_in6 ip6;
|
||||||
struct sockaddr_in6 *in6 = ((struct sockaddr_in6 *)ai->ai_addr);
|
#endif
|
||||||
|
} addr;
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
int fam = *(int *)ai;
|
||||||
|
ai += sizeof(int);
|
||||||
|
int addr_len;
|
||||||
|
if (fam == AF_INET6) {
|
||||||
|
addr_len = sizeof(addr.ip6);
|
||||||
|
addr.ip6.sin6_addr = *(struct in6_addr *)ai;
|
||||||
|
addr.ip6.sin6_flowinfo = 0;
|
||||||
|
addr.ip6.sin6_scope_id = 0;
|
||||||
|
ai += sizeof(struct in6_addr);
|
||||||
|
} else {
|
||||||
|
addr_len = sizeof(addr.ip4);
|
||||||
|
#else
|
||||||
|
const int fam = AF_INET;
|
||||||
|
const int addr_len = sizeof(addr.ip4);
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
addr.ip4.sin_addr = *(struct in_addr *)ai;
|
||||||
|
ai += sizeof(struct in_addr);
|
||||||
|
}
|
||||||
|
sock->curr_addr = ai;
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (fam == AF_INET6) {
|
||||||
char sockname[64];
|
char sockname[64];
|
||||||
in6->sin6_port = htons( sock->conf->port );
|
inet_ntop( fam, &addr.ip6.sin6_addr, sockname, sizeof(sockname) );
|
||||||
nfasprintf( &sock->name, "%s ([%s]:%hu)",
|
nfasprintf( &sock->name, "%s ([%s]:%hu)",
|
||||||
sock->conf->host, inet_ntop( AF_INET6, &in6->sin6_addr, sockname, sizeof(sockname) ), sock->conf->port );
|
sock->conf->host, sockname, sock->conf->port );
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
struct sockaddr_in *in = ((struct sockaddr_in *)ai->ai_addr);
|
|
||||||
in->sin_port = htons( sock->conf->port );
|
|
||||||
nfasprintf( &sock->name, "%s (%s:%hu)",
|
nfasprintf( &sock->name, "%s (%s:%hu)",
|
||||||
sock->conf->host, inet_ntoa( in->sin_addr ), sock->conf->port );
|
sock->conf->host, inet_ntoa( addr.ip4.sin_addr ), sock->conf->port );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
int s = socket( fam, SOCK_STREAM, 0 );
|
||||||
s = socket( ai->ai_family, SOCK_STREAM, 0 );
|
|
||||||
#else
|
|
||||||
s = socket( PF_INET, SOCK_STREAM, 0 );
|
|
||||||
#endif
|
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
socket_connect_next( sock );
|
socket_connect_next( sock );
|
||||||
return;
|
return;
|
||||||
|
@ -579,11 +686,9 @@ socket_connect_one( conn_t *sock )
|
||||||
socket_open_internal( sock, s );
|
socket_open_internal( sock, s );
|
||||||
|
|
||||||
infon( "Connecting to %s... ", sock->name );
|
infon( "Connecting to %s... ", sock->name );
|
||||||
#ifdef HAVE_IPV6
|
addr.any.sa_family = fam;
|
||||||
if (connect( s, ai->ai_addr, ai->ai_addrlen )) {
|
addr.ip4.sin_port = htons( sock->conf->port ); // Aliased for ip6
|
||||||
#else
|
if (connect( s, &addr.any, addr_len )) {
|
||||||
if (connect( s, ai->ai_addr, sizeof(*ai->ai_addr) )) {
|
|
||||||
#endif
|
|
||||||
if (errno != EINPROGRESS) {
|
if (errno != EINPROGRESS) {
|
||||||
socket_connect_failed( sock );
|
socket_connect_failed( sock );
|
||||||
return;
|
return;
|
||||||
|
@ -604,7 +709,6 @@ socket_connect_next( conn_t *conn )
|
||||||
sys_error( "Cannot connect to %s", conn->name );
|
sys_error( "Cannot connect to %s", conn->name );
|
||||||
free( conn->name );
|
free( conn->name );
|
||||||
conn->name = NULL;
|
conn->name = NULL;
|
||||||
conn->curr_addr = conn->curr_addr->ai_next;
|
|
||||||
socket_connect_one( conn );
|
socket_connect_one( conn );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,10 +722,8 @@ socket_connect_failed( conn_t *conn )
|
||||||
static void
|
static void
|
||||||
socket_connected( conn_t *conn )
|
socket_connected( conn_t *conn )
|
||||||
{
|
{
|
||||||
if (conn->addrs) {
|
free( conn->addrs );
|
||||||
freeaddrinfo( conn->addrs );
|
|
||||||
conn->addrs = NULL;
|
conn->addrs = NULL;
|
||||||
}
|
|
||||||
conf_notifier( &conn->notify, 0, POLLIN );
|
conf_notifier( &conn->notify, 0, POLLIN );
|
||||||
socket_expect_activity( conn, 0 );
|
socket_expect_activity( conn, 0 );
|
||||||
conn->state = SCK_READY;
|
conn->state = SCK_READY;
|
||||||
|
@ -631,10 +733,8 @@ socket_connected( conn_t *conn )
|
||||||
static void
|
static void
|
||||||
socket_cleanup_names( conn_t *conn )
|
socket_cleanup_names( conn_t *conn )
|
||||||
{
|
{
|
||||||
if (conn->addrs) {
|
free( conn->addrs );
|
||||||
freeaddrinfo( conn->addrs );
|
|
||||||
conn->addrs = NULL;
|
conn->addrs = NULL;
|
||||||
}
|
|
||||||
free( conn->name );
|
free( conn->name );
|
||||||
conn->name = NULL;
|
conn->name = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1106,6 +1206,11 @@ socket_fd_cb( int events, void *aux )
|
||||||
{
|
{
|
||||||
conn_t *conn = (conn_t *)aux;
|
conn_t *conn = (conn_t *)aux;
|
||||||
|
|
||||||
|
if (conn->state == SCK_RESOLVING) {
|
||||||
|
socket_resolve_finalize( conn );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((events & POLLERR) || conn->state == SCK_CONNECTING) {
|
if ((events & POLLERR) || conn->state == SCK_CONNECTING) {
|
||||||
int soerr;
|
int soerr;
|
||||||
socklen_t selen = sizeof(soerr);
|
socklen_t selen = sizeof(soerr);
|
||||||
|
@ -1168,7 +1273,9 @@ socket_timeout_cb( void *aux )
|
||||||
{
|
{
|
||||||
conn_t *conn = (conn_t *)aux;
|
conn_t *conn = (conn_t *)aux;
|
||||||
|
|
||||||
if (conn->state == SCK_CONNECTING) {
|
if (conn->state == SCK_RESOLVING) {
|
||||||
|
socket_resolve_timeout( conn );
|
||||||
|
} else if (conn->state == SCK_CONNECTING) {
|
||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
socket_connect_failed( conn );
|
socket_connect_failed( conn );
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -57,11 +57,7 @@ typedef struct {
|
||||||
int fd;
|
int fd;
|
||||||
int state;
|
int state;
|
||||||
const server_conf_t *conf; /* needed during connect */
|
const server_conf_t *conf; /* needed during connect */
|
||||||
#ifdef HAVE_IPV6
|
char *addrs, *addrs_end, *curr_addr; // needed during connect; assumed to be int-aligned
|
||||||
struct addrinfo *addrs, *curr_addr; /* needed during connect */
|
|
||||||
#else
|
|
||||||
struct addr_info *addrs, *curr_addr; /* needed during connect */
|
|
||||||
#endif
|
|
||||||
char *name;
|
char *name;
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
SSL *ssl;
|
SSL *ssl;
|
||||||
|
|
|
@ -1110,6 +1110,8 @@ event_wait( void )
|
||||||
case 0:
|
case 0:
|
||||||
return;
|
return;
|
||||||
case -1:
|
case -1:
|
||||||
|
if (errno == EINTR)
|
||||||
|
return;
|
||||||
perror( "poll() failed in event loop" );
|
perror( "poll() failed in event loop" );
|
||||||
abort();
|
abort();
|
||||||
default:
|
default:
|
||||||
|
@ -1162,6 +1164,8 @@ event_wait( void )
|
||||||
case 0:
|
case 0:
|
||||||
return;
|
return;
|
||||||
case -1:
|
case -1:
|
||||||
|
if (errno == EINTR)
|
||||||
|
return;
|
||||||
perror( "select() failed in event loop" );
|
perror( "select() failed in event loop" );
|
||||||
abort();
|
abort();
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user