Skip to content

Commit

Permalink
first try at fr_bio_fd_accept()
Browse files Browse the repository at this point in the history
which creates a new BIO from a parent of type LISTEN
  • Loading branch information
alandekok committed Nov 19, 2024
1 parent a491cf4 commit 1f168ac
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 13 deletions.
110 changes: 107 additions & 3 deletions src/lib/bio/fd.c
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ static ssize_t fr_bio_fd_read_accept(fr_bio_t *bio, void *packet_ctx, void *buff
}


int fr_bio_fd_init_accept(fr_bio_fd_t *my)
int fr_bio_fd_init_listen(fr_bio_fd_t *my)
{
my->bio.read = fr_bio_fd_read_accept;
my->bio.write = fr_bio_null_write;
Expand Down Expand Up @@ -1262,7 +1262,7 @@ int fr_bio_fd_connect_full(fr_bio_t *bio, fr_event_list_t *el, fr_bio_callback_t
* The caller may just call us without caring about what the underlying BIO is. In which case we
* need to be safe.
*/
if ((my->info.socket.af == AF_FILE_BIO) || (my->info.type == FR_BIO_FD_ACCEPT)) {
if ((my->info.socket.af == AF_FILE_BIO) || (my->info.type == FR_BIO_FD_LISTEN)) {
fr_bio_fd_set_open(my);
goto connected;
}
Expand Down Expand Up @@ -1363,6 +1363,7 @@ int fr_bio_fd_write_only(fr_bio_t *bio)
break;

case FR_BIO_FD_CONNECTED:
case FR_BIO_FD_ACCEPTED:
/*
* Further reads are disallowed.
*/
Expand All @@ -1372,11 +1373,114 @@ int fr_bio_fd_write_only(fr_bio_t *bio)
}
break;

case FR_BIO_FD_ACCEPT:
case FR_BIO_FD_LISTEN:
fr_strerror_const("Only unconnected sockets can be marked 'write-only'");
return -1;
}

my->bio.read = fr_bio_fd_read_discard;
return 0;
}

/** Alternative to calling fr_bio_read() on new socket.
*
*/
int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
{
int fd, tries = 0;
int rcode;
fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
socklen_t salen;
struct sockaddr_storage sockaddr;
fr_bio_fd_t *out;
fr_bio_fd_config_t *cfg;

salen = sizeof(sockaddr);
*out_p = NULL;

fr_assert(my->info.type == FR_BIO_FD_LISTEN);
fr_assert(my->info.socket.type == SOCK_STREAM);

retry:
#ifdef __linux__
/*
* Set these flags immediately on the new socket.
*/
fd = accept4(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen, SOCK_NONBLOCK | SOCK_CLOEXEC);
#else
fd = accept(my->info.socket.fd, (struct sockaddr *) &sockaddr, &salen);
#endif
if (fd < 0) {
switch (errno) {
case EINTR:
/*
* Try a few times before giving up.
*/
tries++;
if (tries <= my->max_tries) goto retry;
return 0;

/*
* We can ignore these errors.
*/
case ECONNABORTED:
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
case EAGAIN:
#ifdef EPERM
case EPERM:
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
#endif
return 0;

default:
/*
* Some other error, it's fatal.
*/
fr_bio_shutdown(&my->bio);
break;
}

return fr_bio_error(IO);
}

/*
* Allocate the base BIO and set it up.
*/
out = (fr_bio_fd_t *) fr_bio_fd_alloc(ctx, NULL, my->offset);
if (!out) {
close(fd);
return fr_bio_error(GENERIC);
}

/*
* We have a file descriptor. Initialize the configuration with the new information.
*/
cfg = talloc_memdup(out, my->info.cfg, sizeof(*my->info.cfg));
if (!cfg) {
fr_strerror_const("Out of memory");
close(fd);
talloc_free(out);
return fr_bio_error(GENERIC);
}

/*
* Set the type to ACCEPTED, and set up the rest of the callbacks to match.
*/
cfg->type = FR_BIO_FD_ACCEPTED;
out->info.socket.fd = fd;

rcode = fr_bio_fd_open(bio, cfg);
if (rcode < 0) {
talloc_free(out);
return rcode;
}

fr_assert(out->info.type == FR_BIO_FD_CONNECTED);

*out_p = (fr_bio_t *) out;
return 1;
}
5 changes: 4 additions & 1 deletion src/lib/bio/fd.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ typedef enum {
// updates #fr_bio_fd_packet_ctx_t for reads,
// uses #fr_bio_fd_packet_ctx_t for writes
FR_BIO_FD_CONNECTED, //!< connected client sockets (UDP or TCP)
FR_BIO_FD_ACCEPT, //!< returns new fd in buffer on fr_bio_read()
FR_BIO_FD_LISTEN, //!< returns new fd in buffer on fr_bio_read() or fr_bio_fd_accept()
// updates #fr_bio_fd_packet_ctx_t on successful FD read.
FR_BIO_FD_ACCEPTED, //!< temporarily until it's connected.
} fr_bio_fd_type_t;

/** Configuration for sockets
Expand Down Expand Up @@ -139,3 +140,5 @@ int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg) CC_HINT(nonnul
int fr_bio_fd_write_only(fr_bio_t *bio) CC_HINT(nonnull);

int fr_bio_fd_reopen(fr_bio_t *bio) CC_HINT(nonnull);

int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out, fr_bio_t *bio) CC_HINT(nonnull);
42 changes: 36 additions & 6 deletions src/lib/bio/fd_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -751,10 +751,19 @@ int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
}
}

fd = socket(my->info.socket.af, my->info.socket.type, protocol);
if (fd < 0) {
fr_strerror_printf("Failed opening socket: %s", fr_syserror(errno));
return -1;
/*
* It's already opened, so we don't need to do that.
*/
if (cfg->type == FR_BIO_FD_ACCEPTED) {
fd = my->info.socket.fd;
fr_assert(fd >= 0);

} else {
fd = socket(my->info.socket.af, my->info.socket.type, protocol);
if (fd < 0) {
fr_strerror_printf("Failed opening socket: %s", fr_syserror(errno));
return -1;
}
}

} else if (cfg->path) {
Expand Down Expand Up @@ -928,10 +937,31 @@ int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
if (fr_bio_fd_init_connected(my) < 0) goto fail;
break;

case FR_BIO_FD_ACCEPTED:
#ifdef SO_NOSIGPIPE
/*
* Although the server ignore SIGPIPE, some operating systems like BSD and OSX ignore the
* ignoring.
*
* Fortunately, those operating systems usually support SO_NOSIGPIPE. We set that to prevent
* them raising the signal in the first place.
*/
{
int on = 1;

setsockopt(my->info.socket.fd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
}
#endif

my->info.type = FR_BIO_FD_CONNECTED;

if (fr_bio_fd_init_common(my) < 0) goto fail;
break;

/*
* Server socket which listens for new stream connections
*/
case FR_BIO_FD_ACCEPT:
case FR_BIO_FD_LISTEN:
fr_assert(my->info.socket.type == SOCK_STREAM);

switch (my->info.socket.af) {
Expand All @@ -956,7 +986,7 @@ int fr_bio_fd_open(fr_bio_t *bio, fr_bio_fd_config_t const *cfg)
goto fail;
}

if (fr_bio_fd_init_accept(my) < 0) goto fail;
if (fr_bio_fd_init_listen(my) < 0) goto fail;
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/bio/fd_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,6 @@ int fr_bio_fd_init_common(fr_bio_fd_t *my);

int fr_bio_fd_init_connected(fr_bio_fd_t *my);

int fr_bio_fd_init_accept(fr_bio_fd_t *my);
int fr_bio_fd_init_listen(fr_bio_fd_t *my);

int fr_bio_fd_socket_name(fr_bio_fd_t *my);
3 changes: 2 additions & 1 deletion src/lib/bio/network.c
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ fr_bio_t *fr_bio_network_alloc(TALLOC_CTX *ctx, fr_ipaddr_t const *allow, fr_ipa
break;

case FR_BIO_FD_CONNECTED:
case FR_BIO_FD_ACCEPTED:
return NULL;

case FR_BIO_FD_ACCEPT:
case FR_BIO_FD_LISTEN:
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/listen/control/proto_control_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ static int mod_open(fr_listen_t *li)
fr_assert(!thread->connection);

cfg = (fr_bio_fd_config_t) {
.type = FR_BIO_FD_ACCEPT,
.type = FR_BIO_FD_LISTEN,
.socket_type = SOCK_STREAM,
.path = inst->filename,
.uid = inst->uid,
Expand Down

0 comments on commit 1f168ac

Please sign in to comment.