+enum block_bool {
+ NO_BLOCK,
+ BLOCK
+};
+
+/* Read any incoming data, placing it into the buffer. */
+static int remote_bitbang_fill_buf(enum block_bool block)
+{
+ if (remote_bitbang_recv_buf_empty()) {
+ /* If the buffer is empty, reset it to 0 so we get more
+ * contiguous space. */
+ remote_bitbang_recv_buf_start = 0;
+ remote_bitbang_recv_buf_end = 0;
+ }
+
+ if (block == BLOCK) {
+ if (remote_bitbang_flush() != ERROR_OK)
+ return ERROR_FAIL;
+ socket_block(remote_bitbang_fd);
+ }
+
+ bool first = true;
+ while (!remote_bitbang_recv_buf_full()) {
+ unsigned int contiguous_available_space =
+ remote_bitbang_recv_buf_contiguous_available_space();
+ ssize_t count = read_socket(remote_bitbang_fd,
+ remote_bitbang_recv_buf + remote_bitbang_recv_buf_end,
+ contiguous_available_space);
+ if (first && block == BLOCK)
+ socket_nonblock(remote_bitbang_fd);
+ first = false;
+ if (count > 0) {
+ remote_bitbang_recv_buf_end += count;
+ if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf))
+ remote_bitbang_recv_buf_end = 0;
+ } else if (count == 0) {
+ return ERROR_OK;
+ } else if (count < 0) {
+#ifdef _WIN32
+ if (WSAGetLastError() == WSAEWOULDBLOCK) {
+#else
+ if (errno == EAGAIN) {
+#endif
+ return ERROR_OK;
+ } else {
+ log_socket_error("remote_bitbang_fill_buf");
+ return ERROR_FAIL;
+ }
+ }
+ }
+
+ return ERROR_OK;
+}
+
+typedef enum {
+ NO_FLUSH,
+ FLUSH_SEND_BUF
+} flush_bool_t;
+
+static int remote_bitbang_queue(int c, flush_bool_t flush)
+{
+ remote_bitbang_send_buf[remote_bitbang_send_buf_used++] = c;
+ if (flush == FLUSH_SEND_BUF ||
+ remote_bitbang_send_buf_used >= ARRAY_SIZE(remote_bitbang_send_buf))
+ return remote_bitbang_flush();
+ return ERROR_OK;
+}
+
+static int remote_bitbang_quit(void)
+{
+ if (remote_bitbang_queue('Q', FLUSH_SEND_BUF) == ERROR_FAIL)
+ return ERROR_FAIL;
+
+ if (close_socket(remote_bitbang_fd) != 0) {
+ log_socket_error("close_socket");