-
Notifications
You must be signed in to change notification settings - Fork 984
Expand file tree
/
Copy pathdev_disconnect.c
More file actions
131 lines (108 loc) · 3.19 KB
/
dev_disconnect.c
File metadata and controls
131 lines (108 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "config.h"
#include <ccan/err/err.h>
#include <common/dev_disconnect.h>
#include <common/status.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <wire/peer_wire.h>
/* We move the fd if and only if we do a disconnect. */
static int dev_disconnect_fd = -1;
static char dev_disconnect_line[200];
static int dev_disconnect_count, dev_disconnect_len;
static void next_dev_disconnect(void)
{
int r;
char *asterisk;
r = read(dev_disconnect_fd,
dev_disconnect_line, sizeof(dev_disconnect_line)-1);
if (r < 0)
err(1, "Reading dev_disconnect file");
if (lseek(dev_disconnect_fd, -r, SEEK_CUR) < 0) {
err(1, "lseek failure");
}
/* Get first line */
dev_disconnect_line[r] = '\n';
dev_disconnect_len = strcspn(dev_disconnect_line, "\n");
dev_disconnect_line[dev_disconnect_len] = '\0';
asterisk = strchr(dev_disconnect_line, '*');
if (asterisk) {
dev_disconnect_count = atoi(asterisk+1);
if (dev_disconnect_count < 1)
errx(1, "dev_disconnect invalid count: %s",
dev_disconnect_line);
*asterisk = '\0';
} else
dev_disconnect_count = 1;
}
void dev_disconnect_init(int fd)
{
/* So we can move forward if we do use the line. */
dev_disconnect_fd = fd;
}
enum dev_disconnect_out dev_disconnect_out(const struct node_id *id, int pkt_type)
{
if (dev_disconnect_fd == -1)
return DEV_DISCONNECT_OUT_NORMAL;
if (!dev_disconnect_count)
next_dev_disconnect();
if (!dev_disconnect_line[0]
|| dev_disconnect_line[0] == DEV_DISCONNECT_IN_AFTER_RECV
|| !streq(peer_wire_name(pkt_type), dev_disconnect_line+1))
return DEV_DISCONNECT_OUT_NORMAL;
if (--dev_disconnect_count != 0) {
return DEV_DISCONNECT_OUT_NORMAL;
}
if (lseek(dev_disconnect_fd, dev_disconnect_len+1, SEEK_CUR) < 0) {
err(1, "lseek failure");
}
status_peer_debug(id, "dev_disconnect: %s (%s)",
dev_disconnect_line,
peer_wire_name(pkt_type));
return dev_disconnect_line[0];
}
enum dev_disconnect_in dev_disconnect_in(const struct node_id *id, int pkt_type)
{
if (dev_disconnect_fd == -1)
return DEV_DISCONNECT_IN_NORMAL;
if (!dev_disconnect_count)
next_dev_disconnect();
if (dev_disconnect_line[0] != DEV_DISCONNECT_IN_AFTER_RECV
|| !streq(peer_wire_name(pkt_type), dev_disconnect_line+1))
return DEV_DISCONNECT_IN_NORMAL;
if (--dev_disconnect_count != 0) {
return DEV_DISCONNECT_IN_NORMAL;
}
if (lseek(dev_disconnect_fd, dev_disconnect_len+1, SEEK_CUR) < 0) {
err(1, "lseek failure");
}
status_peer_debug(id, "dev_disconnect: %s (%s)",
dev_disconnect_line,
peer_wire_name(pkt_type));
return dev_disconnect_line[0];
}
void dev_sabotage_fd(int fd, bool close_fd)
{
int fds[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0)
err(1, "dev_sabotage_fd: creating socketpair");
#if defined(TCP_NODELAY)
/* On Linux, at least, this flushes. */
int opt = TCP_NODELAY;
int val = 1;
setsockopt(fd, IPPROTO_TCP, opt, &val, sizeof(val));
#else
#error No TCP_NODELAY?
#endif
/* Move fd out the way if we don't want to close it. */
if (!close_fd) {
if (dup(fd) == -1) {
; /* -Wunused-result */
}
} else
/* Close other end of socket. */
close(fds[0]);
/* Move other over to the fd we want to sabotage. */
dup2(fds[1], fd);
close(fds[1]);
}