Skip to content

Commit 97abffa

Browse files
sandbox: enabled and working on testnet
1 parent 64ce4ba commit 97abffa

36 files changed

+1153
-153
lines changed

src/app/firedancer-dev/commands/backtest.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ fd_topo_run_tile_t fdctl_tile_run( fd_topo_tile_t const * tile );
3737

3838
static void
3939
backtest_topo( config_t * config ) {
40+
41+
config->development.sandbox = 0;
42+
config->development.no_clone = 1;
43+
4044
ulong exec_tile_cnt = config->firedancer.layout.exec_tile_count;
4145

4246
int disable_snap_loader = !config->gossip.entrypoints_cnt;

src/app/firedancer/config/default.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,9 +1499,7 @@ user = ""
14991499
# This option cannot be enabled in production. In development, you
15001500
# can also launch Firedancer as a single process for with the
15011501
# `--no-clone` argument to `firedancer-dev`.
1502-
#
1503-
# TODO: No clone should not be on by default, fix sandbox.
1504-
no_clone = true
1502+
no_clone = false
15051503

15061504
# As part of security sandboxing, the dumpable bit of each process
15071505
# is cleared with prctl( PR_SET_DUMPABLE, 0 ). This prevents other

src/app/firedancer/topology.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -696,10 +696,10 @@ fd_topo_initialize( config_t * config ) {
696696
for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
697697
fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
698698

699-
fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
700699
fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
701-
fd_topob_tile_uses( topo, poh_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
700+
fd_topo_tile_t * bank_tile = &topo->tiles[ fd_topo_find_tile( topo, "bank", i ) ];
702701
fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
702+
fd_topob_tile_uses( topo, bank_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
703703
FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
704704
}
705705

src/app/shared/commands/run/run.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ main_pid_namespace( void * _args ) {
256256

257257
pid_t child_pids[ FD_TOPO_MAX_TILES+1 ];
258258
char child_names[ FD_TOPO_MAX_TILES+1 ][ 32 ];
259+
ulong child_idxs[ FD_TOPO_MAX_TILES+1 ];
259260
struct pollfd fds[ FD_TOPO_MAX_TILES+2 ];
260261

261262
int config_memfd = fd_config_to_memfd( config );
@@ -310,6 +311,7 @@ main_pid_namespace( void * _args ) {
310311
if( FD_UNLIKELY( pipe2( pipefd, O_CLOEXEC ) ) ) FD_LOG_ERR(( "pipe2() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
311312
fds[ child_cnt ] = (struct pollfd){ .fd = pipefd[ 0 ], .events = 0 };
312313
child_pids[ child_cnt ] = execve_tile( tile, floating_cpu_set, save_priority, config_memfd, pipefd[ 1 ] );
314+
child_idxs[ child_cnt ] = i;
313315
if( FD_UNLIKELY( close( pipefd[ 1 ] ) ) ) FD_LOG_ERR(( "close() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
314316
strncpy( child_names[ child_cnt ], tile->name, 32 );
315317
child_cnt++;
@@ -410,8 +412,7 @@ main_pid_namespace( void * _args ) {
410412
}
411413

412414
char * tile_name = child_names[ i ];
413-
ulong tile_idx = 0UL;
414-
if( FD_LIKELY( i>0UL ) ) tile_idx = (!config->is_firedancer && config->development.no_agave) ? i : i-1UL;
415+
ulong tile_idx = child_idxs[ i ];
415416
ulong tile_id = config->topo.tiles[ tile_idx ].kind_id;
416417

417418
/* Child process died, reap it to figure out exit code. */

src/discof/genesis/fd_genesi_tile.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "../../disco/topo/fd_topo.h"
22
#include "../../funk/fd_funk.h"
3-
#include "generated/fd_genesi_tile_seccomp.h"
43
#include "../../flamenco/types/fd_types.h"
54
#include "../../ballet/lthash/fd_lthash.h"
65
#include "../../ballet/sha256/fd_sha256.h"
@@ -12,6 +11,7 @@
1211
#include <sys/stat.h>
1312
#include <unistd.h>
1413

14+
#include "generated/fd_genesi_tile_seccomp.h"
1515
struct fd_genesi_tile {
1616
int fd;
1717

@@ -245,10 +245,13 @@ populate_allowed_seccomp( fd_topo_t const * topo,
245245
fd_topo_tile_t const * tile,
246246
ulong out_cnt,
247247
struct sock_filter * out ) {
248-
(void)topo;
249-
(void)tile;
250248

251-
populate_sock_filter_policy_fd_genesi_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
249+
void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
250+
251+
FD_SCRATCH_ALLOC_INIT( l, scratch );
252+
fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
253+
254+
populate_sock_filter_policy_fd_genesi_tile( out_cnt, out, (uint)fd_log_private_logfile_fd(), (uint)ctx->fd );
252255
return sock_filter_policy_fd_genesi_tile_instr_cnt;
253256
}
254257

@@ -257,15 +260,18 @@ populate_allowed_fds( fd_topo_t const * topo,
257260
fd_topo_tile_t const * tile,
258261
ulong out_fds_cnt,
259262
int * out_fds ) {
260-
(void)topo;
261-
(void)tile;
263+
void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
264+
265+
FD_SCRATCH_ALLOC_INIT( l, scratch );
266+
fd_genesi_tile_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_genesi_tile_t ), sizeof( fd_genesi_tile_t ) );
262267

263-
if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
268+
if( FD_UNLIKELY( out_fds_cnt<3UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
264269

265270
ulong out_cnt = 0UL;
266271
out_fds[ out_cnt++ ] = 2; /* stderr */
267272
if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
268273
out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
274+
if( FD_LIKELY( ctx->fd!=-1 ) ) out_fds[ out_cnt++ ] = ctx->fd;
269275
return out_cnt;
270276
}
271277

src/discof/genesis/fd_genesi_tile.seccomppolicy

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# logfile_fd: It can be disabled by configuration, but typically tiles
22
# will open a log file on boot and write all messages there.
3-
unsigned int logfile_fd
3+
unsigned int logfile_fd, unsigned int genesis_fd
44

55
# logging: all log messages are written to a file and/or pipe
66
#
@@ -16,3 +16,21 @@ write: (or (eq (arg 0) 2)
1616
#
1717
# arg 0 is the file descriptor to fsync.
1818
fsync: (eq (arg 0) logfile_fd)
19+
20+
# genesis: obtain information about the genesis file
21+
#
22+
# arg 0 is the file descriptor for the genesis file
23+
fstat: (eq (arg 0) genesis_fd)
24+
25+
# genesis: close the file after we are done reading from it
26+
#
27+
# arg 0 is the file descriptor for the genesis file
28+
close: (eq (arg 0) genesis_fd)
29+
30+
# read: read data in from the genesis file
31+
#
32+
# arg 0 is the file descriptor for the genesis file
33+
read: (eq (arg 0) genesis_fd)
34+
35+
# shutdown: exit is called on shutdown
36+
exit: (eq (arg 0) 0)

src/discof/genesis/generated/fd_genesi_tile_seccomp.h

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,34 +21,58 @@
2121
#else
2222
# error "Target architecture is unsupported by seccomp."
2323
#endif
24-
static const unsigned int sock_filter_policy_fd_genesi_tile_instr_cnt = 14;
24+
static const unsigned int sock_filter_policy_fd_genesi_tile_instr_cnt = 26;
2525

26-
static void populate_sock_filter_policy_fd_genesi_tile( ulong out_cnt, struct sock_filter * out, unsigned int logfile_fd ) {
27-
FD_TEST( out_cnt >= 14 );
28-
struct sock_filter filter[14] = {
26+
static void populate_sock_filter_policy_fd_genesi_tile( ulong out_cnt, struct sock_filter * out, unsigned int logfile_fd, unsigned int genesis_fd ) {
27+
FD_TEST( out_cnt >= 26 );
28+
struct sock_filter filter[26] = {
2929
/* Check: Jump to RET_KILL_PROCESS if the script's arch != the runtime arch */
3030
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, arch ) ) ),
31-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 10 ),
31+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, ARCH_NR, 0, /* RET_KILL_PROCESS */ 22 ),
3232
/* loading syscall number in accumulator */
3333
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, ( offsetof( struct seccomp_data, nr ) ) ),
3434
/* allow write based on expression */
35-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 2, 0 ),
35+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_write, /* check_write */ 6, 0 ),
3636
/* allow fsync based on expression */
37-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 5, 0 ),
37+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fsync, /* check_fsync */ 9, 0 ),
38+
/* allow fstat based on expression */
39+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_fstat, /* check_fstat */ 10, 0 ),
40+
/* allow close based on expression */
41+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_close, /* check_close */ 11, 0 ),
42+
/* allow read based on expression */
43+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_read, /* check_read */ 12, 0 ),
44+
/* allow exit based on expression */
45+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, SYS_exit, /* check_exit */ 13, 0 ),
3846
/* none of the syscalls matched */
39-
{ BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 6 },
47+
{ BPF_JMP | BPF_JA, 0, 0, /* RET_KILL_PROCESS */ 14 },
4048
// check_write:
4149
/* load syscall argument 0 in accumulator */
4250
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
43-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_ALLOW */ 5, /* lbl_1 */ 0 ),
51+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 2, /* RET_ALLOW */ 13, /* lbl_1 */ 0 ),
4452
// lbl_1:
4553
/* load syscall argument 0 in accumulator */
4654
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
47-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 3, /* RET_KILL_PROCESS */ 2 ),
55+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 11, /* RET_KILL_PROCESS */ 10 ),
4856
// check_fsync:
4957
/* load syscall argument 0 in accumulator */
5058
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
51-
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 1, /* RET_KILL_PROCESS */ 0 ),
59+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, logfile_fd, /* RET_ALLOW */ 9, /* RET_KILL_PROCESS */ 8 ),
60+
// check_fstat:
61+
/* load syscall argument 0 in accumulator */
62+
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
63+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, genesis_fd, /* RET_ALLOW */ 7, /* RET_KILL_PROCESS */ 6 ),
64+
// check_close:
65+
/* load syscall argument 0 in accumulator */
66+
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
67+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, genesis_fd, /* RET_ALLOW */ 5, /* RET_KILL_PROCESS */ 4 ),
68+
// check_read:
69+
/* load syscall argument 0 in accumulator */
70+
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
71+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, genesis_fd, /* RET_ALLOW */ 3, /* RET_KILL_PROCESS */ 2 ),
72+
// check_exit:
73+
/* load syscall argument 0 in accumulator */
74+
BPF_STMT( BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, args[0])),
75+
BPF_JUMP( BPF_JMP | BPF_JEQ | BPF_K, 0, /* RET_ALLOW */ 1, /* RET_KILL_PROCESS */ 0 ),
5276
// RET_KILL_PROCESS:
5377
/* KILL_PROCESS is placed before ALLOW since it's the fallthrough case. */
5478
BPF_STMT( BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS ),

src/discof/ipecho/fd_ipecho_client.c

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,12 @@ write_conn( fd_ipecho_client_t * client,
157157
'\n', /* End of request */
158158
};
159159

160-
long written = send( client->pollfds[ conn_idx ].fd,
161-
request+peer->request_bytes_sent,
162-
sizeof(request)-peer->request_bytes_sent,
163-
MSG_NOSIGNAL );
160+
long written = sendto( client->pollfds[ conn_idx ].fd,
161+
request+peer->request_bytes_sent,
162+
sizeof(request)-peer->request_bytes_sent,
163+
MSG_NOSIGNAL,
164+
NULL,
165+
0 );
164166
if( FD_UNLIKELY( -1==written && errno==EAGAIN ) ) return; /* No data was written, continue. */
165167
else if( FD_UNLIKELY( -1==written ) ) {
166168
close_one( client, conn_idx );
@@ -181,12 +183,12 @@ read_conn( fd_ipecho_client_t * client,
181183
fd_ipecho_client_peer_t * peer = &client->peers[ conn_idx ];
182184

183185
if( FD_UNLIKELY( peer->writing ) ) return 1;
184-
185-
long read = recv( client->pollfds[ conn_idx ].fd,
186-
peer->response+peer->response_bytes_read,
187-
sizeof(peer->response)-peer->response_bytes_read,
188-
0 );
189-
186+
long read = recvfrom( client->pollfds[ conn_idx ].fd,
187+
peer->response+peer->response_bytes_read,
188+
sizeof(peer->response)-peer->response_bytes_read,
189+
0,
190+
NULL,
191+
NULL );
190192
if( FD_UNLIKELY( -1==read && (errno==EAGAIN || errno==EINTR) ) ) return 1;
191193
else if( FD_UNLIKELY( -1==read ) ) {
192194
close_one( client, conn_idx );
@@ -216,7 +218,7 @@ fd_ipecho_client_poll( fd_ipecho_client_t * client,
216218
return -1;
217219
}
218220

219-
int nfds = fd_syscall_poll( client->pollfds, 16U, 0 );
221+
int nfds = fd_syscall_poll( client->pollfds, (uint)client->peer_cnt, 0 );
220222
if( FD_UNLIKELY( 0==nfds ) ) return 1;
221223
else if( FD_UNLIKELY( -1==nfds && errno==EINTR ) ) return 1;
222224
else if( FD_UNLIKELY( -1==nfds ) ) FD_LOG_ERR(( "poll() failed (%i-%s)", errno, strerror( errno ) ));
@@ -238,3 +240,8 @@ fd_ipecho_client_poll( fd_ipecho_client_t * client,
238240

239241
return 1;
240242
}
243+
244+
struct pollfd const *
245+
fd_ipecho_client_get_pollfds( fd_ipecho_client_t * client ) {
246+
return client->pollfds;
247+
}

src/discof/ipecho/fd_ipecho_client.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,7 @@ fd_ipecho_client_poll( fd_ipecho_client_t * client,
3232
ushort * shred_version,
3333
int * charge_busy );
3434

35+
struct pollfd const *
36+
fd_ipecho_client_get_pollfds( fd_ipecho_client_t * client );
37+
3538
#endif

src/discof/ipecho/fd_ipecho_server.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ typedef struct fd_ipecho_server_connection fd_ipecho_server_connection_t;
4444
#include "../../util/tmpl/fd_pool.c"
4545

4646
struct fd_ipecho_server {
47+
int sockfd;
48+
4749
ushort shred_version;
4850

4951
ulong evict_idx;
@@ -136,13 +138,16 @@ fd_ipecho_server_init( fd_ipecho_server_t * server,
136138
uint address,
137139
ushort port,
138140
ushort shred_version ) {
141+
142+
/* If the shred version is 0 that means that the shred version has not
143+
been set yet. */
139144
server->shred_version = shred_version;
140145

141-
int sockfd = socket( AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0 );
142-
if( FD_UNLIKELY( -1==sockfd ) ) FD_LOG_ERR(( "socket() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
146+
server->sockfd = socket( AF_INET, SOCK_STREAM|SOCK_NONBLOCK, 0 );
147+
if( FD_UNLIKELY( -1==server->sockfd ) ) FD_LOG_ERR(( "socket() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
143148

144149
int optval = 1;
145-
if( FD_UNLIKELY( -1==setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) ) ) )
150+
if( FD_UNLIKELY( -1==setsockopt( server->sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof( optval ) ) ) )
146151
FD_LOG_ERR(( "setsockopt failed (%i-%s)", errno, strerror( errno ) ));
147152

148153
struct sockaddr_in addr = {
@@ -151,14 +156,20 @@ fd_ipecho_server_init( fd_ipecho_server_t * server,
151156
.sin_addr.s_addr = address,
152157
};
153158

154-
if( FD_UNLIKELY( -1==bind( sockfd, fd_type_pun( &addr ), sizeof( addr ) ) ) ) {
159+
if( FD_UNLIKELY( -1==bind( server->sockfd, fd_type_pun( &addr ), sizeof( addr ) ) ) ) {
155160
FD_LOG_ERR(( "bind(%i,AF_INET," FD_IP4_ADDR_FMT ":%u) failed (%i-%s)",
156-
sockfd, FD_IP4_ADDR_FMT_ARGS( address ), port,
161+
server->sockfd, FD_IP4_ADDR_FMT_ARGS( address ), port,
157162
errno, fd_io_strerror( errno ) ));
158163
}
159-
if( FD_UNLIKELY( -1==listen( sockfd, (int)server->max_connection_cnt ) ) ) FD_LOG_ERR(( "listen() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
164+
if( FD_UNLIKELY( -1==listen( server->sockfd, (int)server->max_connection_cnt ) ) ) FD_LOG_ERR(( "listen() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
160165

161-
server->pollfds[ server->max_connection_cnt ] = (struct pollfd){ .fd = sockfd, .events = POLLIN, .revents = 0 };
166+
server->pollfds[ server->max_connection_cnt ] = (struct pollfd){ .fd = server->sockfd, .events = POLLIN, .revents = 0 };
167+
}
168+
169+
void
170+
fd_ipecho_server_set_shred_version( fd_ipecho_server_t * server,
171+
ushort shred_version ) {
172+
server->shred_version = shred_version;
162173
}
163174

164175
static inline int
@@ -291,7 +302,7 @@ write_conn( fd_ipecho_server_t * server,
291302

292303
if( FD_LIKELY( conn->state==STATE_READING ) ) return;
293304

294-
long sz = send( server->pollfds[ conn_idx ].fd, conn->response_bytes+conn->response_bytes_written, sizeof(conn->response_bytes)-conn->response_bytes_written, MSG_NOSIGNAL );
305+
long sz = sendto( server->pollfds[ conn_idx ].fd, conn->response_bytes+conn->response_bytes_written, sizeof(conn->response_bytes)-conn->response_bytes_written, MSG_NOSIGNAL, NULL, 0 );
295306
if( FD_UNLIKELY( -1==sz && errno==EAGAIN ) ) return; /* No data was written, continue. */
296307
if( FD_UNLIKELY( -1==sz && is_expected_network_error( errno ) ) ) {
297308
close_conn( server, conn_idx, CLOSE_PEER_RESET );
@@ -310,7 +321,12 @@ void
310321
fd_ipecho_server_poll( fd_ipecho_server_t * server,
311322
int * charge_busy,
312323
int timeout_ms ) {
313-
int nfds = fd_syscall_poll( server->pollfds, (uint)( server->max_connection_cnt+1UL ), timeout_ms );
324+
325+
/* If the shred version is 0 that means that the shred version just
326+
has not been set yet. Don't try to accept connections yet. */
327+
if( FD_UNLIKELY( server->shred_version==0U ) ) return;
328+
329+
int nfds = fd_syscall_poll( server->pollfds, (uint)(server->max_connection_cnt+1UL), timeout_ms );
314330
if( FD_UNLIKELY( 0==nfds ) ) return;
315331
else if( FD_UNLIKELY( -1==nfds && errno==EINTR ) ) return;
316332
else if( FD_UNLIKELY( -1==nfds ) ) FD_LOG_ERR(( "poll() failed (%i-%s)", errno, strerror( errno ) ));
@@ -334,3 +350,8 @@ fd_ipecho_server_metrics_t *
334350
fd_ipecho_server_metrics( fd_ipecho_server_t * server ) {
335351
return server->metrics;
336352
}
353+
354+
int
355+
fd_ipecho_server_sockfd( fd_ipecho_server_t * server ) {
356+
return server->sockfd;
357+
}

0 commit comments

Comments
 (0)