浏览代码

Merge pull request #210 from tnoho/tnoho

Add mg_websocket_client_write (some TODOs are to be fixed)
bel2125 9 年之前
父节点
当前提交
d8ade358c0
共有 4 个文件被更改,包括 70 次插入12 次删除
  1. 1 1
      examples/websocket_client/Makefile
  2. 7 4
      examples/websocket_client/websocket_client.c
  3. 17 0
      include/civetweb.h
  4. 45 7
      src/civetweb.c

+ 1 - 1
examples/websocket_client/Makefile

@@ -28,7 +28,7 @@ $(PROG): $(CIVETWEB_LIB) $(SRC)
 	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(SRC) $(CIVETWEB_LIB) $(LIBS)
 
 $(CIVETWEB_LIB):
-	$(MAKE) -C $(TOP) clean lib
+	$(MAKE) -C $(TOP) clean lib WITH_WEBSOCKET=1
 	cp $(TOP)/$(CIVETWEB_LIB) .
 
 clean:

+ 7 - 4
examples/websocket_client/websocket_client.c

@@ -82,6 +82,9 @@ websocket_server_data(struct mg_connection *conn,
 #endif
 {
 	printf("Server: Got %u bytes from the client\n", data_len);
+	printf("Server received data from client: ");
+	fwrite(data, 1, data_len, stdout);
+	printf("\n");
 
 	if (data_len < 3 || 0 != memcmp(data, "bye", 3)) {
 		/* Send websocket acknowledge message */
@@ -258,7 +261,7 @@ main(int argc, char *argv[])
 	client1_data.data = NULL;
 	client1_data.len = 0;
 
-	mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5);
+	mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data1", 5);
 
 	sleep(1); /* Should get the acknowledge message */
 	assert(client1_data.closed == 0);
@@ -305,7 +308,7 @@ main(int argc, char *argv[])
 	client2_data.data = NULL;
 	client2_data.len = 0;
 
-	mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5);
+	mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "data2", 5);
 
 	sleep(1); /* Should get the acknowledge message */
 	assert(client1_data.closed == 0);
@@ -321,7 +324,7 @@ main(int argc, char *argv[])
 	client1_data.data = NULL;
 	client1_data.len = 0;
 
-	mg_websocket_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+	mg_websocket_client_write(newconn1, WEBSOCKET_OPCODE_TEXT, "bye", 3);
 
 	sleep(1); /* Should get the goodbye message */
 	assert(client1_data.closed == 0);
@@ -347,7 +350,7 @@ main(int argc, char *argv[])
 	assert(client2_data.data == NULL);
 	assert(client2_data.len == 0);
 
-	mg_websocket_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3);
+	mg_websocket_client_write(newconn2, WEBSOCKET_OPCODE_TEXT, "bye", 3);
 
 	sleep(1); /* Should get the goodbye message */
 	assert(client1_data.closed == 1);

+ 17 - 0
include/civetweb.h

@@ -457,6 +457,23 @@ CIVETWEB_API int mg_websocket_write(struct mg_connection *conn,
                                     const char *data,
                                     size_t data_len);
 
+/* Send data to a websocket server wrapped in a masked websocket frame.  Uses
+   mg_lock_connection to ensure that the transmission is not interrupted,
+   i.e., when the application is proactively communicating and responding to
+   a request simultaneously.
+
+   Send data to a websocket server wrapped in a masked websocket frame.
+   This function is available when civetweb is compiled with -DUSE_WEBSOCKET
+
+   Return:
+    0   when the connection has been closed
+    -1  on error
+    >0  number of bytes written on success */
+CIVETWEB_API int mg_websocket_client_write(struct mg_connection *conn,
+                                           int opcode,
+                                           const char *data,
+                                           size_t data_len);
+
 /* Blocks until unique access is obtained to this connection. Intended for use
    with websockets only.
    Invoke this before mg_write or mg_printf when communicating with a

+ 45 - 7
src/civetweb.c

@@ -8081,13 +8081,14 @@ read_websocket(struct mg_connection *conn,
 	mg_set_thread_name("worker");
 }
 
-int
-mg_websocket_write(struct mg_connection *conn,
-                   int opcode,
-                   const char *data,
-                   size_t dataLen)
+static int
+mg_websocket_write_exec(struct mg_connection *conn,
+                        int opcode,
+                        const char *data,
+                        size_t dataLen,
+                        uint32_t masking_key)
 {
-	unsigned char header[10];
+	unsigned char header[14];
 	size_t headerLen = 1;
 
 	int retval = -1;
@@ -8112,6 +8113,14 @@ mg_websocket_write(struct mg_connection *conn,
 		headerLen = 10;
 	}
 
+	if(masking_key) {
+		/* add mask */
+		header[1] |= 0x80;
+		*(uint32_t *)(void *)(header + headerLen) = masking_key;
+		headerLen += 4;
+	}
+
+
 	/* Note that POSIX/Winsock's send() is threadsafe
 	 * http://stackoverflow.com/questions/1981372/are-parallel-calls-to-send-recv-on-the-same-socket-valid
 	 * but mongoose's mg_printf/mg_write is not (because of the loop in
@@ -8119,12 +8128,41 @@ mg_websocket_write(struct mg_connection *conn,
 	 * outgoing buffer is full). */
 	(void)mg_lock_connection(conn);
 	retval = mg_write(conn, header, headerLen);
-	retval = mg_write(conn, data, dataLen);
+	if (dataLen > 0) {
+		retval = mg_write(conn, data, dataLen);
+	}
 	mg_unlock_connection(conn);
 
 	return retval;
 }
 
+int
+mg_websocket_write(struct mg_connection *conn,
+                   int opcode,
+                   const char *data,
+                   size_t dataLen)
+{
+	return mg_websocket_write_exec(conn, opcode, data, dataLen, 0);
+}
+
+int
+mg_websocket_client_write(struct mg_connection *conn,
+                          int opcode,
+                          const char *data,
+                          size_t dataLen)
+{
+	int retval = -1;
+	size_t i = 0;
+	uint32_t masking_key = 0x1594DAC0;
+	char* masked_data = (char*)mg_malloc(dataLen + 4);
+	for (i = 0; i < dataLen; i+= 4) {
+		*(uint32_t *)(void *)(masked_data + i) = *(uint32_t *)(void *)(data + i) ^ masking_key;
+	}
+	retval = mg_websocket_write_exec(conn, opcode, masked_data, dataLen, masking_key);
+	mg_free(masked_data);
+	return retval;
+}
+
 static void
 handle_websocket_request(struct mg_connection *conn,
                          const char *path,