aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmdsclient/comm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libmdsclient/comm.c')
-rw-r--r--src/libmdsclient/comm.c88
1 files changed, 79 insertions, 9 deletions
diff --git a/src/libmdsclient/comm.c b/src/libmdsclient/comm.c
index 3284043..a01d1d7 100644
--- a/src/libmdsclient/comm.c
+++ b/src/libmdsclient/comm.c
@@ -19,6 +19,12 @@
#include <stdlib.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -119,19 +125,32 @@ void libmds_connection_free(libmds_connection_t* restrict this)
* @param this The connection descriptor, must not be `NULL`
* @param message The message to send, must not be `NULL`
* @param length The length of the message, should be positive
- * @return Zero on success, -1 on error, `ernno`
- * will have been set accordingly on error
+ * @return The number of sent bytes. Less than `length` on error,
+ * `ernno` will have been set accordingly on error
*
- * @throws See pthread_mutex_lock(3)
+ * @throws EACCES See send(2)
+ * @throws EWOULDBLOCK See send(2), only if the socket has been modified to nonblocking
+ * @throws EBADF See send(2)
+ * @throws ECONNRESET If connection was lost
+ * @throws EDESTADDRREQ See send(2)
+ * @throws EFAULT See send(2)
+ * @throws EINVAL See send(2)
+ * @throws ENOBUFS See send(2)
+ * @throws ENOMEM See send(2)
+ * @throws ENOTCONN See send(2)
+ * @throws ENOTSOCK See send(2)
+ * @throws EPIPE See send(2)
+ * @throws See pthread_mutex_lock(3)
*/
-int libmds_connection_send(libmds_connection_t* restrict this, const char* message, size_t length)
+size_t libmds_connection_send(libmds_connection_t* restrict this, const char* message, size_t length)
{
- int r, saved_errno;
+ int saved_errno;
+ size_t r;
if (libmds_connection_lock(this))
- return -1;
+ return 0;
- r = libmds_connection_send_unlocked(this, message, length);
+ r = libmds_connection_send_unlocked(this, message, length, 1);
saved_errno = errno;
(void) libmds_connection_unlock(this);
@@ -139,8 +158,59 @@ int libmds_connection_send(libmds_connection_t* restrict this, const char* messa
}
-int libmds_connection_send_unlocked(libmds_connection_t* restrict this, const char* message, size_t length)
+/**
+ * Send a message to the display server, without locking the
+ * mutex of the conncetion
+ *
+ * @param this The connection descriptor, must not be `NULL`
+ * @param message The message to send, must not be `NULL`
+ * @param length The length of the message, should be positive
+ * @param continue_on_interrupt Whether to continue sending if interrupted by a signal
+ * @return The number of sent bytes. Less than `length` on error,
+ * `ernno` will have been set accordingly on error
+ *
+ * @throws EACCES See send(2)
+ * @throws EWOULDBLOCK See send(2), only if the socket has been modified to nonblocking
+ * @throws EBADF See send(2)
+ * @throws ECONNRESET If connection was lost
+ * @throws EDESTADDRREQ See send(2)
+ * @throws EFAULT See send(2)
+ * @throws EINTR If interrupted by a signal, only if `continue_on_interrupt' is zero
+ * @throws EINVAL See send(2)
+ * @throws ENOBUFS See send(2)
+ * @throws ENOMEM See send(2)
+ * @throws ENOTCONN See send(2)
+ * @throws ENOTSOCK See send(2)
+ * @throws EPIPE See send(2)
+ */
+size_t libmds_connection_send_unlocked(libmds_connection_t* restrict this, const char* message,
+ size_t length, int continue_on_interrupt)
{
- return (void) this, (void) message, (void) length, 0; /* TODO */
+ size_t block_size = length;
+ size_t sent = 0;
+ ssize_t just_sent;
+
+ errno = 0;
+ while (length > 0)
+ if ((just_sent = send(this->socket_fd, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0)
+ {
+ if (errno == EMSGSIZE)
+ {
+ block_size >>= 1;
+ if (block_size == 0)
+ return sent;
+ }
+ else if ((errno == EINTR) && continue_on_interrupt)
+ continue;
+ else
+ return sent;
+ }
+ else
+ {
+ sent += (size_t)just_sent;
+ length -= (size_t)just_sent;
+ }
+
+ return sent;
}