reflect send completeness in lws_write return

under load, writing packet sizes to the socket that are normally fine
can do partial writes, eg asking to write 4096 may only take 2800 of
it and return 2800 from the actual send.

Until now lws assumed that if it was safe to send, it could take any
size buffer, that's not the case under load.

This patch changes lws_write to return the amount actually taken...
that and the meaning of it becomes tricky when dealing with
compressed links, the amount taken and the amount sent differ.  Also
there is no way to recover at the moment from a protocol-encoded
frame only being partially accepted... however for http file send
content it can and does recover now.

Small frames don't have to take any care about it but large atomic
sends (> 2K) have been seen to fail under load.

Signed-off-by: Andy Green <andy.green@linaro.org>
diff --git a/test-server/test-client.c b/test-server/test-client.c
index debd43a..b602442 100644
--- a/test-server/test-client.c
+++ b/test-server/test-client.c
@@ -150,9 +150,16 @@
 					(int)random() % 250,
 					(int)random() % 24);
 
-		libwebsocket_write(wsi,
+		n = libwebsocket_write(wsi,
 		   &buf[LWS_SEND_BUFFER_PRE_PADDING], l, opts | LWS_WRITE_TEXT);
 
+		if (n < 0)
+			return -1;
+		if (n < l) {
+			lwsl_err("Partial write LWS_CALLBACK_CLIENT_WRITEABLE\n");
+			return -1;
+		}
+
 		mirror_lifetime--;
 		if (!mirror_lifetime) {
 			fprintf(stderr, "closing mirror session\n");
diff --git a/test-server/test-echo.c b/test-server/test-echo.c
index e9ecf9e..d86d4d0 100644
--- a/test-server/test-echo.c
+++ b/test-server/test-echo.c
@@ -69,6 +69,10 @@
 			lwsl_err("ERROR %d writing to socket, hanging up\n", n);
 			return 1;
 		}
+		if (n < pss->len) {
+			lwsl_err("Partial write\n");
+			return -1;
+		}
 		break;
 
 	case LWS_CALLBACK_RECEIVE:
@@ -101,7 +105,11 @@
 		n = libwebsocket_write(wsi, &pss->buf[LWS_SEND_BUFFER_PRE_PADDING], pss->len, LWS_WRITE_TEXT);
 		if (n < 0) {
 			lwsl_err("ERROR %d writing to socket, hanging up\n", n);
-			return 1;
+			return -1;
+		}
+		if (n < pss->len) {
+			lwsl_err("Partial write\n");
+			return -1;
 		}
 		break;
 #endif
diff --git a/test-server/test-fraggle.c b/test-server/test-fraggle.c
index b517370..01b0819 100644
--- a/test-server/test-fraggle.c
+++ b/test-server/test-fraggle.c
@@ -175,6 +175,12 @@
 				psf->state = FRAGSTATE_POST_PAYLOAD_SUM;
 
 			n = libwebsocket_write(wsi, bp, chunk, write_mode);
+			if (n < 0)
+				return -1;
+			if (n < chunk) {
+				lwsl_err("Partial write\n");
+				return -1;
+			}
 
 			libwebsocket_callback_on_writable(context, wsi);
 			break;
@@ -192,6 +198,12 @@
 
 			n = libwebsocket_write(wsi, (unsigned char *)bp,
 							   4, LWS_WRITE_BINARY);
+			if (n < 0)
+				return -1;
+			if (n < 4) {
+				lwsl_err("Partial write\n");
+				return -1;
+			}
 
 			psf->state = FRAGSTATE_START_MESSAGE;
 
diff --git a/test-server/test-ping.c b/test-server/test-ping.c
index 7cc2c2d..098981c 100644
--- a/test-server/test-ping.c
+++ b/test-server/test-ping.c
@@ -259,14 +259,21 @@
 		global_tx_count++;
 
 		if (use_mirror)
-			libwebsocket_write(wsi,
+			n = libwebsocket_write(wsi,
 				&pingbuf[LWS_SEND_BUFFER_PRE_PADDING],
 					size, write_options | LWS_WRITE_BINARY);
 		else
-			libwebsocket_write(wsi,
+			n = libwebsocket_write(wsi,
 				&pingbuf[LWS_SEND_BUFFER_PRE_PADDING],
 					size, write_options | LWS_WRITE_PING);
 
+		if (n < 0)
+			return -1;
+		if (n < size) {
+			lwsl_err("Partial write\n");
+			return -1;
+		}
+
 		if (flood &&
 			 (psd->ping_index - psd->rx_count) < (screen_width - 1))
 			fprintf(stderr, ".");
diff --git a/test-server/test-server.c b/test-server/test-server.c
index ce2f61e..b059f1c 100644
--- a/test-server/test-server.c
+++ b/test-server/test-server.c
@@ -122,13 +122,12 @@
 	char client_ip[128];
 #endif
 	char buf[256];
-	int n;
+	int n, m;
 	unsigned char *p;
 	static unsigned char buffer[4096];
 	struct stat stat_buf;
 	struct per_session_data__http *pss = (struct per_session_data__http *)user;
 #ifdef EXTERNAL_POLL
-	int m;
 	int fd = (int)(long)in;
 #endif
 
@@ -166,6 +165,7 @@
 			 * send the http headers...
 			 * this won't block since it's the first payload sent
 			 * on the connection since it was established
+			 * (too small for partial)
 			 */
 
 			n = libwebsocket_write(wsi, buffer,
@@ -223,10 +223,13 @@
 			 * because it's HTTP and not websocket, don't need to take
 			 * care about pre and postamble
 			 */
-			n = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
-			if (n < 0)
+			m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
+			if (m < 0)
 				/* write failed, close conn */
 				goto bail;
+			if (m != n)
+				/* partial write, adjust */
+				lseek(pss->fd, m - n, SEEK_CUR);
 
 		} while (!lws_send_pipe_choked(wsi));
 		libwebsocket_callback_on_writable(context, wsi);
@@ -383,6 +386,7 @@
 
 	case LWS_CALLBACK_SERVER_WRITEABLE:
 		n = sprintf((char *)p, "%d", pss->number++);
+		/* too small for partial */
 		n = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
 		if (n < 0) {
 			lwsl_err("ERROR %d writing to di socket\n", n);
@@ -479,6 +483,9 @@
 				lwsl_err("ERROR %d writing to mirror socket\n", n);
 				return -1;
 			}
+			if (n < ringbuffer[pss->ringbuffer_tail].len) {
+				lwsl_err("mirror partial write %d vs %d\n", n, ringbuffer[pss->ringbuffer_tail].len);
+			}
 
 			if (pss->ringbuffer_tail == (MAX_MESSAGE_QUEUE - 1))
 				pss->ringbuffer_tail = 0;