Browse Source

faux.net: Move net functions to net/net.c

Serj Kalichev 3 years ago
parent
commit
bae86e4a40
6 changed files with 301 additions and 187 deletions
  1. 3 0
      faux/Makefile.am
  2. 0 181
      faux/base/io.c
  3. 0 6
      faux/faux.h
  4. 15 0
      faux/net.h
  5. 2 0
      faux/net/Makefile.am
  6. 281 0
      faux/net/net.c

+ 3 - 0
faux/Makefile.am

@@ -19,6 +19,7 @@ nobase_include_HEADERS += \
 	faux/argv.h \
 	faux/time.h \
 	faux/sched.h \
+	faux/net.h \
 	faux/testc_helpers.h
 
 EXTRA_DIST += \
@@ -34,6 +35,7 @@ EXTRA_DIST += \
 	faux/argv/Makefile.am \
 	faux/time/Makefile.am \
 	faux/sched/Makefile.am \
+	faux/net/Makefile.am \
 	faux/testc_helpers/Makefile.am
 
 include $(top_srcdir)/faux/base/Makefile.am
@@ -48,6 +50,7 @@ include $(top_srcdir)/faux/file/Makefile.am
 include $(top_srcdir)/faux/argv/Makefile.am
 include $(top_srcdir)/faux/time/Makefile.am
 include $(top_srcdir)/faux/sched/Makefile.am
+include $(top_srcdir)/faux/net/Makefile.am
 include $(top_srcdir)/faux/testc_helpers/Makefile.am
 
 if TESTC

+ 0 - 181
faux/base/io.c

@@ -145,184 +145,3 @@ size_t faux_read_block(int fd, void *buf, size_t n)
 
 	return total_readed;
 }
-
-
-/** @brief Sends data to socket.
- *
- * The system send() can be interrupted by signal. This function will retry to
- * send in a case of interrupted call.
- *
- * @param [in] fd Socket.
- * @param [in] buf Buffer to write.
- * @param [in] n Number of bytes to write.
- * @param [in] flags Flags.
- * @return Number of bytes written or < 0 on error.
- */
-ssize_t faux_send(int fd, const void *buf, size_t n, int flags)
-{
-	ssize_t bytes_written = 0;
-
-	assert(fd != -1);
-	assert(buf);
-	if ((-1 == fd) || !buf)
-		return -1;
-	if (0 == n)
-		return 0;
-
-	do {
-		bytes_written = send(fd, buf, n, flags);
-	} while ((bytes_written < 0) && (EINTR == errno));
-
-	return bytes_written;
-}
-
-
-/** @brief Sends data block to socket.
- *
- * The system send() can be interrupted by signal or can write less bytes
- * than specified. This function will continue to send data until all data
- * will be sent or error occured.
- *
- * @param [in] fd Socket.
- * @param [in] buf Buffer to write.
- * @param [in] n Number of bytes to write.
- * @param [in] flags Flags.
- * @return Number of bytes written.
- * < n then insufficient space or error (but some data was already written).
- * < 0 - error.
- */
-ssize_t faux_send_block(int fd, const void *buf, size_t n, int flags)
-{
-	ssize_t bytes_written = 0;
-	size_t total_written = 0;
-	size_t left = n;
-	const void *data = buf;
-
-	do {
-		bytes_written = faux_send(fd, data, left, flags);
-		if (bytes_written < 0) { // Error
-			if (total_written != 0)
-				return total_written;
-			return -1;
-		}
-		if (0 == bytes_written) // Insufficient space
-			return total_written;
-		data += bytes_written;
-		left = left - bytes_written;
-		total_written += bytes_written;
-	} while (left > 0);
-
-	return total_written;
-}
-
-
-/** @brief Sends struct iovec data blocks to socket.
- *
- * This function is like a faux_send_block() function but uses scatter/gather.
- *
- * @see faux_send_block().
- * @param [in] fd Socket.
- * @param [in] buf Buffer to write.
- * @param [in] n Number of bytes to write.
- * @param [in] flags Flags.
- * @return Number of bytes written.
- * < n then insufficient space or error (but some data was already written).
- * < 0 - error.
- */
-ssize_t faux_sendv_block(int fd, const struct iovec *iov, int iovcnt, int flags)
-{
-	ssize_t bytes_written = 0;
-	size_t total_written = 0;
-	int i = 0;
-
-	if (!iov)
-		return -1;
-	if (iovcnt == 0)
-		return 0;
-
-	for (i = 0; i < iovcnt; i++) {
-		if (iov[i].iov_len == 0)
-			continue;
-		bytes_written = faux_send_block(fd, iov[i].iov_base, iov[i].iov_len, flags);
-		if (bytes_written < 0) { // Error
-			if (total_written != 0)
-				return total_written;
-			return -1;
-		}
-		if (0 == bytes_written) // Insufficient space
-			return total_written;
-		total_written += bytes_written;
-	}
-
-	return total_written;
-}
-
-
-/** @brief Receive data from socket.
- *
- * The system recv() can be interrupted by signal. This function will retry to
- * receive if it was interrupted by signal.
- *
- * @param [in] fd Socket.
- * @param [in] buf Buffer to write.
- * @param [in] n Number of bytes to write.
- * @param [in] flags Flags.
- * @return Number of bytes readed or < 0 on error.
- * 0 bytes indicates EOF
- */
-ssize_t faux_recv(int fd, void *buf, size_t n, int flags)
-{
-	ssize_t bytes_readed = 0;
-
-	assert(fd != -1);
-	assert(buf);
-	if ((-1 == fd) || !buf)
-		return -1;
-	if (0 == n)
-		return 0;
-
-	do {
-		bytes_readed = recv(fd, buf, n, flags);
-	} while ((bytes_readed < 0) && (EINTR == errno));
-
-	return bytes_readed;
-}
-
-
-/** @brief Receive data block from socket.
- *
- * The system recv() can be interrupted by signal or can read less bytes
- * than specified. This function will continue to read data until all data
- * will be readed or error occured.
- *
- * @param [in] fd Socket.
- * @param [in] buf Buffer to write.
- * @param [in] n Number of bytes to write.
- * @param [in] flags Flags.
- * @return Number of bytes readed.
- * < n EOF or error (but some data was already readed).
- * < 0 Error.
- */
-size_t faux_recv_block(int fd, void *buf, size_t n, int flags)
-{
-	ssize_t bytes_readed = 0;
-	size_t total_readed = 0;
-	size_t left = n;
-	void *data = buf;
-
-	do {
-		bytes_readed = recv(fd, data, left, flags);
-		if (bytes_readed < 0) {
-			if (total_readed != 0)
-				return total_readed;
-			return -1;
-		}
-		if (0 == bytes_readed) // EOF
-			return total_readed;
-		data += bytes_readed;
-		left = left - bytes_readed;
-		total_readed += bytes_readed;
-	} while (left > 0);
-
-	return total_readed;
-}

+ 0 - 6
faux/faux.h

@@ -73,12 +73,6 @@ ssize_t faux_read(int fd, void *buf, size_t n);
 ssize_t faux_write_block(int fd, const void *buf, size_t n);
 size_t faux_read_block(int fd, void *buf, size_t n);
 
-ssize_t faux_send(int fd, const void *buf, size_t n, int flags);
-ssize_t faux_send_block(int fd, const void *buf, size_t n, int flags);
-ssize_t faux_sendv_block(int fd, const struct iovec *iov, int iovcnt, int flags);
-ssize_t faux_recv(int fd, void *buf, size_t n, int flags);
-size_t faux_recv_block(int fd, void *buf, size_t n, int flags);
-
 // Filesystem
 int faux_rm(const char *path);
 char *faux_expand_tilde(const char *path);

+ 15 - 0
faux/net.h

@@ -0,0 +1,15 @@
+/** @file net.h
+ * @brief Public interface for faux net functions.
+ */
+
+#ifndef _faux_net_h
+#define _faux_net_h
+
+#include <faux/faux.h>
+
+C_DECL_BEGIN
+
+
+C_DECL_END
+
+#endif

+ 2 - 0
faux/net/Makefile.am

@@ -0,0 +1,2 @@
+libfaux_la_SOURCES += \
+	faux/net/net.c

+ 281 - 0
faux/net/net.c

@@ -0,0 +1,281 @@
+/** @file net.c
+ * @brief Network related functions.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <signal.h>
+
+#include "faux/faux.h"
+#include "faux/time.h"
+#include "faux/net.h"
+
+ssize_t faux_send(int fd, const void *buf, size_t n,
+	const struct timespec *timeout, const sigset_t *sigmask)
+{
+	sigset_t all_sigmask = {}; // All signals mask
+	sigset_t orig_sigmask = {}; // Saved signal mask
+	fd_set fdset = {};
+	ssize_t bytes_written = 0;
+	size_t total_written = 0;
+	size_t left = n;
+	const void *data = buf;
+	struct timespec now = {};
+	struct timespec deadline = {};
+
+	assert(fd != -1);
+	assert(buf);
+	if ((-1 == fd) || !buf)
+		return -1;
+	if (0 == n)
+		return 0;
+
+	// Block signals to prevent race conditions right before pselect()
+	// Catch signals while pselect() only
+	// Now blocks all signals
+	sigfillset(&all_sigmask);
+	sigprocmask(SIG_SETMASK, &all_sigmask, &orig_sigmask);
+
+	// Handlers for pselect()
+	FD_ZERO(&fdset);
+	FD_SET(fd, &fdset);
+
+	// Calculate deadline - the time when timeout must occur.
+	if (timeout) {
+		faux_timespec_now(&now);
+		faux_timespec_sum(&deadline, &now, timeout);
+	}
+
+	do {
+		struct timespec *select_timeout = NULL;
+		struct timespec to = {};
+		int sn = 0;
+
+		if (timeout) {
+			if (faux_timespec_before_now(&deadline))
+				break; // Timeout already occured
+			faux_timespec_now(&now);
+			faux_timespec_diff(&to, &deadline, &now);
+			select_timeout = &to;
+		}
+
+		sn = pselect(fd + 1, 0, &fdset, 0, select_timeout, sigmask);
+		// All unneded signals are masked so don't process EINTR
+		// in special way. Just break the loop
+		if (sn < 0)
+			break;
+
+		// Timeout: break the loop. User don't want to wait any more
+		if (0 == sn)
+			break;
+
+		bytes_written = send(fd, data, left, 0);
+		// The send() call can't be interrupted because all signals are
+		// blocked now. So any "-1" result is a really error.
+		if (bytes_written < 0)
+			break;
+
+		// Insufficient space
+		if (0 == bytes_written)
+			break;
+
+		data += bytes_written;
+		left = left - bytes_written;
+		total_written += bytes_written;
+
+	} while (left > 0);
+
+	sigprocmask(SIG_SETMASK, &orig_sigmask, NULL);
+
+	return total_written;
+}
+
+
+/** @brief Sends data to socket.
+ *
+ * The system send() can be interrupted by signal. This function will retry to
+ * send in a case of interrupted call.
+ *
+ * @param [in] fd Socket.
+ * @param [in] buf Buffer to write.
+ * @param [in] n Number of bytes to write.
+ * @param [in] flags Flags.
+ * @return Number of bytes written or < 0 on error.
+ */
+#if 0
+ssize_t faux_send(int fd, const void *buf, size_t n, int flags)
+{
+	ssize_t bytes_written = 0;
+
+	assert(fd != -1);
+	assert(buf);
+	if ((-1 == fd) || !buf)
+		return -1;
+	if (0 == n)
+		return 0;
+
+	do {
+		bytes_written = send(fd, buf, n, flags);
+	} while ((bytes_written < 0) && (EINTR == errno));
+
+	return bytes_written;
+}
+
+
+/** @brief Sends data block to socket.
+ *
+ * The system send() can be interrupted by signal or can write less bytes
+ * than specified. This function will continue to send data until all data
+ * will be sent or error occured.
+ *
+ * @param [in] fd Socket.
+ * @param [in] buf Buffer to write.
+ * @param [in] n Number of bytes to write.
+ * @param [in] flags Flags.
+ * @return Number of bytes written.
+ * < n then insufficient space or error (but some data was already written).
+ * < 0 - error.
+ */
+ssize_t faux_send_block(int fd, const void *buf, size_t n, int flags)
+{
+	ssize_t bytes_written = 0;
+	size_t total_written = 0;
+	size_t left = n;
+	const void *data = buf;
+
+	do {
+		bytes_written = faux_send(fd, data, left, flags);
+		if (bytes_written < 0) { // Error
+			if (total_written != 0)
+				return total_written;
+			return -1;
+		}
+		if (0 == bytes_written) // Insufficient space
+			return total_written;
+		data += bytes_written;
+		left = left - bytes_written;
+		total_written += bytes_written;
+	} while (left > 0);
+
+	return total_written;
+}
+
+
+/** @brief Sends struct iovec data blocks to socket.
+ *
+ * This function is like a faux_send_block() function but uses scatter/gather.
+ *
+ * @see faux_send_block().
+ * @param [in] fd Socket.
+ * @param [in] buf Buffer to write.
+ * @param [in] n Number of bytes to write.
+ * @param [in] flags Flags.
+ * @return Number of bytes written.
+ * < n then insufficient space or error (but some data was already written).
+ * < 0 - error.
+ */
+ssize_t faux_sendv_block(int fd, const struct iovec *iov, int iovcnt, int flags)
+{
+	ssize_t bytes_written = 0;
+	size_t total_written = 0;
+	int i = 0;
+
+	if (!iov)
+		return -1;
+	if (iovcnt == 0)
+		return 0;
+
+	for (i = 0; i < iovcnt; i++) {
+		if (iov[i].iov_len == 0)
+			continue;
+		bytes_written = faux_send_block(fd, iov[i].iov_base, iov[i].iov_len, flags);
+		if (bytes_written < 0) { // Error
+			if (total_written != 0)
+				return total_written;
+			return -1;
+		}
+		if (0 == bytes_written) // Insufficient space
+			return total_written;
+		total_written += bytes_written;
+	}
+
+	return total_written;
+}
+
+
+/** @brief Receive data from socket.
+ *
+ * The system recv() can be interrupted by signal. This function will retry to
+ * receive if it was interrupted by signal.
+ *
+ * @param [in] fd Socket.
+ * @param [in] buf Buffer to write.
+ * @param [in] n Number of bytes to write.
+ * @param [in] flags Flags.
+ * @return Number of bytes readed or < 0 on error.
+ * 0 bytes indicates EOF
+ */
+ssize_t faux_recv(int fd, void *buf, size_t n, int flags)
+{
+	ssize_t bytes_readed = 0;
+
+	assert(fd != -1);
+	assert(buf);
+	if ((-1 == fd) || !buf)
+		return -1;
+	if (0 == n)
+		return 0;
+
+	do {
+		bytes_readed = recv(fd, buf, n, flags);
+	} while ((bytes_readed < 0) && (EINTR == errno));
+
+	return bytes_readed;
+}
+
+
+/** @brief Receive data block from socket.
+ *
+ * The system recv() can be interrupted by signal or can read less bytes
+ * than specified. This function will continue to read data until all data
+ * will be readed or error occured.
+ *
+ * @param [in] fd Socket.
+ * @param [in] buf Buffer to write.
+ * @param [in] n Number of bytes to write.
+ * @param [in] flags Flags.
+ * @return Number of bytes readed.
+ * < n EOF or error (but some data was already readed).
+ * < 0 Error.
+ */
+size_t faux_recv_block(int fd, void *buf, size_t n, int flags)
+{
+	ssize_t bytes_readed = 0;
+	size_t total_readed = 0;
+	size_t left = n;
+	void *data = buf;
+
+	do {
+		bytes_readed = recv(fd, data, left, flags);
+		if (bytes_readed < 0) {
+			if (total_readed != 0)
+				return total_readed;
+			return -1;
+		}
+		if (0 == bytes_readed) // EOF
+			return total_readed;
+		data += bytes_readed;
+		left = left - bytes_readed;
+		total_readed += bytes_readed;
+	} while (left > 0);
+
+	return total_readed;
+}
+
+#endif