Browse Source

closingd: Ensure proper closing of TCP socket.

Fixes: #1457
ppa-0.6.1
ZmnSCPxj 7 years ago
committed by Rusty Russell
parent
commit
926b41b7da
  1. 1
      closingd/Makefile
  2. 6
      closingd/closing.c
  3. 1
      common/Makefile
  4. 47
      common/socket_close.c
  5. 23
      common/socket_close.h

1
closingd/Makefile

@ -60,6 +60,7 @@ CLOSINGD_COMMON_OBJS := \
common/permute_tx.o \ common/permute_tx.o \
common/ping.o \ common/ping.o \
common/read_peer_msg.o \ common/read_peer_msg.o \
common/socket_close.o \
common/status.o \ common/status.o \
common/status_wire.o \ common/status_wire.o \
common/subdaemon.o \ common/subdaemon.o \

6
closingd/closing.c

@ -9,6 +9,7 @@
#include <common/peer_billboard.h> #include <common/peer_billboard.h>
#include <common/peer_failed.h> #include <common/peer_failed.h>
#include <common/read_peer_msg.h> #include <common/read_peer_msg.h>
#include <common/socket_close.h>
#include <common/status.h> #include <common/status.h>
#include <common/subdaemon.h> #include <common/subdaemon.h>
#include <common/type_to_string.h> #include <common/type_to_string.h>
@ -581,6 +582,11 @@ int main(int argc, char *argv[])
offer[LOCAL]); offer[LOCAL]);
/* We're done! */ /* We're done! */
/* Properly close the channel first. */
if (!socket_close(PEER_FD))
status_unusual("Closing and draining peerfd gave error: %s",
strerror(errno));
/* Sending the below will kill us! */
wire_sync_write(REQ_FD, take(towire_closing_complete(NULL))); wire_sync_write(REQ_FD, take(towire_closing_complete(NULL)));
tal_free(ctx); tal_free(ctx);
daemon_shutdown(); daemon_shutdown();

1
common/Makefile

@ -33,6 +33,7 @@ COMMON_SRC_NOGEN := \
common/ping.c \ common/ping.c \
common/pseudorand.c \ common/pseudorand.c \
common/read_peer_msg.c \ common/read_peer_msg.c \
common/socket_close.c \
common/sphinx.c \ common/sphinx.c \
common/status.c \ common/status.c \
common/status_wire.c \ common/status_wire.c \

47
common/socket_close.c

@ -0,0 +1,47 @@
#include "socket_close.h"
#include <ccan/noerr/noerr.h>
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
/*
Simplified (minus all the error checks):
shutdown(fd, SHUT_WR);
for (;;) {
char unused[64]
sys_res = read(fd, unused, 64);
if (sys_res == 0)
break;
}
close(fd);
*/
bool socket_close(int fd)
{
char unused[64];
int sys_res;
sys_res = shutdown(fd, SHUT_WR);
if (sys_res < 0) {
close_noerr(fd);
return false;
}
for (;;) {
do {
sys_res = read(fd, unused, sizeof(unused));
} while (sys_res < 0 && errno == EINTR);
if (sys_res < 0) {
close_noerr(fd);
return false;
}
if (sys_res == 0)
break;
}
if (close(fd) < 0)
return false;
else
return true;
}

23
common/socket_close.h

@ -0,0 +1,23 @@
/* common/socket_close - Properly close a socket,
* ensuring that any data we write just before
* the close has been transmitted to the other
* side, and ignoring any data the other side
* has sent at the time the close was started.
*
* Reference:
*
* http://ia800504.us.archive.org/3/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html
*/
#ifndef LIGHTNING_COMMON_SOCKET_CLOSE_H
#define LIGHTNING_COMMON_SOCKET_CLOSE_H
#include "config.h"
#include <stdbool.h>
/* Return false if something failed, true if
* nothing failed.
* If something failed, error is stored in
* `errno.
*/
bool socket_close(int fd);
#endif /* LIGHTNING_COMMON_SOCKET_CLOSE_H */
Loading…
Cancel
Save