}
#undef flag_blocked
-#define flag_blocked info.read_blocked
+#define flag_blocked read_blocked
#include "fd_errno.h"
return fr_bio_error(IO);
if (rcode >= 0) return rcode;
#undef flag_blocked
-#define flag_blocked info.read_blocked
+#define flag_blocked read_blocked
#include "fd_errno.h"
return fr_bio_error(IO);
return rcode;
}
- if (rcode == 0 ) return rcode;
+ if (rcode == 0) return rcode;
#undef flag_blocked
-#define flag_blocked info.read_blocked
+#define flag_blocked read_blocked
#include "fd_errno.h"
return fr_bio_error(IO);
}
-
/** Write to fd.
*
* This function is used for connected sockets, where we ignore the packet_ctx.
*/
if (!buffer) return 0;
- my->info.write_blocked = false;
-
retry:
/*
* We could call send() instead of write()! Posix says:
* here.
*/
rcode = write(my->info.socket.fd, buffer, size);
- if (rcode >= 0) return rcode;
-#undef flag_blocked
-#define flag_blocked info.write_blocked
-#include "fd_errno.h"
+#include "fd_write.h"
return fr_bio_error(IO);
}
*/
if (!buffer) return 0;
- my->info.write_blocked = false;
-
// get destination IP
(void) fr_ipaddr_to_sockaddr(&sockaddr, &salen, &addr->socket.inet.dst_ipaddr, addr->socket.inet.dst_port);
retry:
rcode = sendto(my->info.socket.fd, buffer, size, 0, (struct sockaddr *) &sockaddr, salen);
- if (rcode >= 0) return rcode;
-#undef flag_blocked
-#define flag_blocked info.write_blocked
-#include "fd_errno.h"
+#include "fd_write.h"
return fr_bio_error(IO);
}
if (rcode == 0) return rcode;
#undef flag_blocked
-#define flag_blocked info.read_blocked
+#define flag_blocked read_blocked
#include "fd_errno.h"
return fr_bio_error(IO);
fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
- my->info.write_blocked = false;
-
memset(&my->cbuf, 0, sizeof(my->cbuf));
memset(&my->msgh, 0, sizeof(struct msghdr));
rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
if (rcode >= 0) return rcode;
-#undef flag_blocked
-#define flag_blocked info.write_blocked
-#include "fd_errno.h"
+#include "fd_write.h"
return fr_bio_error(IO);
}
fr_bio_fd_t *my = talloc_get_type_abort(bio, fr_bio_fd_t);
fr_bio_fd_packet_ctx_t *addr = fr_bio_fd_packet_ctx(my, packet_ctx);
- my->info.write_blocked = false;
-
memset(&my->cbuf, 0, sizeof(my->cbuf));
memset(&my->msgh, 0, sizeof(struct msghdr));
retry:
rcode = sendmsg(my->info.socket.fd, &my->msgh, 0);
- if (rcode >= 0) return rcode;
-#undef flag_blocked
-#define flag_blocked info.write_blocked
-#include "fd_errno.h"
+#include "fd_write.h"
return fr_bio_error(IO);
}
* to call fr_bio_fd_connect() before calling write()
*/
case EINPROGRESS:
+ if (!my->info.write_blocked && my->cb.write_blocked) my->cb.write_blocked((fr_bio_t *) my);
+
my->info.write_blocked = true;
+
return fr_bio_error(IO_WOULD_BLOCK);
default:
my->info.eof = false;
- /*
- * The socket shouldn't be selected for read. But it should be selected for write.
- */
my->info.read_blocked = false;
- my->info.write_blocked = true;
+ my->info.write_blocked = false;
#ifdef SO_NOSIGPIPE
/*
if (rcode != fr_bio_error(IO_WOULD_BLOCK)) return rcode;
+ /*
+ * The socket is blocked, and should be selected for writing.
+ */
fr_assert(my->info.write_blocked);
fr_assert(my->info.state == FR_BIO_FD_STATE_CONNECTING);
.af = AF_UNSPEC,
},
.type = FR_BIO_FD_UNCONNECTED,
- .read_blocked = true,
- .write_blocked = true,
+ .read_blocked = false,
+ .write_blocked = false,
.eof = false,
.state = FR_BIO_FD_STATE_CLOSED,
};
if (rcode >= 0) return 0;
#undef flag_blocked
-#define flag_blocked info.read_blocked
+#define flag_blocked read_blocked
#include "fd_errno.h"
return fr_bio_error(IO);
--- /dev/null
+/*
+ * Common finalization code for the write functions.
+ *
+ * This is in a header file because of "goto retry" in fd_errno.h.
+ *
+ * @todo - do we want the callbacks to notify the _previous_ BIO in the chain? That way the top-level
+ * BIO can notify the application.
+ */
+if (rcode > 0) {
+ /*
+ * We weren't blocked, but we are now.
+ */
+ if (!my->info.write_blocked) {
+ if ((size_t) rcode == size) {
+ return rcode;
+ }
+
+ fr_assert((size_t) rcode < size);
+
+ /*
+ * Set the flag and run the callback.
+ */
+ my->info.write_blocked = true;
+ if (my->cb.write_blocked) my->cb.write_blocked((fr_bio_t *) my);
+
+ return rcode;
+ }
+
+ /*
+ * We were blocked. We're still blocked if we wrote _less_ than the amount of requested data.
+ * If we wrote all of the data which was requested, then we're unblocked.
+ */
+ my->info.write_blocked = ((size_t) rcode == size);
+
+ /*
+ * Call the "resume" function if we transitioned to being unblocked.
+ */
+ if (!my->info.write_blocked && my->cb.write_resume) my->cb.write_resume((fr_bio_t *) my);
+
+ return rcode;
+}
+
+if (rcode == 0) return rcode;
+
+#undef flag_blocked
+#define flag_blocked write_blocked
+#include "fd_errno.h"