/* * Check if there is a new image available and * send it to the cloud endpoint if the send buffer is not too full. * The image is moved in a new file by the jpeg optimizer function; * this ensures that we will detect a new frame when raspistill writes * it's output file. */ static void send_mjpg_frame(struct mg_connection *nc, const char *file_path) { static int skipped_frames = 0; struct stat st; FILE *fp; /* Check file modification time. */ if (stat(file_path, &st) == 0) { /* Skip the frame if there is too much unsent data. */ if (nc->send_mbuf.len > 256) skipped_frames++; /* Read new mjpg frame into a buffer */ fp = fopen(file_path, "rb"); char buf[st.st_size]; fread(buf, 1, sizeof(buf), fp); fclose(fp); /* * Delete the file so we can detect when raspistill creates a new one. * mtime granularity is only 1s. */ unlink(file_path); /* Send those buffer through the websocket connection */ mg_send_websocket_frame(nc, WEBSOCKET_OP_BINARY, buf, sizeof(buf)); printf("Sent mjpg frame, %lu bytes after skippping %d frames\n", (unsigned long) sizeof(buf), skipped_frames); skipped_frames = 0; } }
void TestHttpClient::SendBinary(struct mg_connection * conn, const std::vector<uint8_t> & bytes) { mg_send_websocket_frame(conn, WEBSOCKET_OP_BINARY, &bytes[0], bytes.size()); }
struct mg_connection * TestHttpClient::Connect(const std::string & address, const std::string & uri) { boost::mutex mutex; boost::condition_variable cond; struct mg_connection * conn; on_connected_ = [&](struct mg_connection * ws) { assert(conn == ws); boost::mutex::scoped_lock lock(mutex); cond.notify_one(); }; conn = mg_connect(&mgr_, address.c_str(), callback); mg_set_protocol_http_websocket(conn); mg_send_websocket_handshake(conn, uri.c_str(), nullptr); const boost::chrono::seconds d(10); boost::mutex::scoped_lock lock(mutex); const auto timeout = cond.wait_for(lock, d); if (boost::cv_status::timeout == timeout) { mg_send_websocket_frame(conn, WEBSOCKET_OP_CLOSE, nullptr, 0); return nullptr; } return conn; }
void TestHttpClient::SendText(struct mg_connection * conn, const std::string & text) { mg_send_websocket_frame(conn, WEBSOCKET_OP_TEXT, text.c_str(), text.length()); }
/* * Sends and encoded chunk with a websocket fragment. * Mongoose WS API for sending fragmenting is quite low level, so we have to do * our own * bookkeeping. TODO(mkm): consider moving to Mongoose. */ static void clubby_proto_ws_emit(char *d, size_t l, int end, void *user_data) { struct mg_connection *nc = (struct mg_connection *) user_data; if (!clubby_proto_is_connected(nc)) { /* * Not trying to reconect here, * It should be done before calling clubby_proto_ws_emit */ LOG(LL_ERROR, ("Clubby is not connected")); return; } int flags = end ? 0 : WEBSOCKET_DONT_FIN; int op = nc->flags & MG_F_WS_FRAGMENTED ? WEBSOCKET_OP_CONTINUE : WEBSOCKET_OP_BINARY; if (!end) { nc->flags |= MG_F_WS_FRAGMENTED; } else { nc->flags &= ~MG_F_WS_FRAGMENTED; } LOG(LL_DEBUG, ("sending websocket frame flags=%x", op | flags)); mg_send_websocket_frame(nc, op | flags, d, l); }
static void _WebSocket_send_string(struct v7 *v7, struct mg_connection *nc, v7_val_t s) { const char *data; size_t len; data = v7_to_string(v7, &s, &len); mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, data, len); }
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { switch (ev) { case MG_EV_HTTP_REQUEST: mg_serve_http(nc, (struct http_message *)ev_data, s_http_server_opts); break; case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { DEBUG("[Server] Client connected!\n"); break; } case MG_EV_WEBSOCKET_FRAME: { struct websocket_message *wm = (struct websocket_message *)ev_data; memcpy(input, wm->data, wm->size); if (BUFFER_SIZE != fwrite(input, sizeof(float), BUFFER_SIZE, dsp_in)) { DEBUG("[Server] Terminated (fread).\n"); s_signal_received = 9; break; } fflush(dsp_in); DEBUG("[Server] Samples sent.\n"); if (BUFFER_SIZE != fread(output, sizeof(float), BUFFER_SIZE, dsp_out)) { printf("Server Terminated (fwrite).\n"); s_signal_received = 9; break; } DEBUG("[Server] Samples received.\n"); mg_send_websocket_frame(nc, WEBSOCKET_OP_BINARY, output, BUFFER_SIZE * sizeof(float)); break; } } }
/* * Sends a Close websocket frame with the given data, and closes the underlying * connection. If `len` is ~0, strlen(data) is used. */ static void mg_ws_close(struct mg_connection *nc, const void *data, size_t len) { if ((int) len == ~0) { len = strlen((const char *) data); } mg_send_websocket_frame(nc, WEBSOCKET_OP_CLOSE, data, len); nc->flags |= MG_F_SEND_AND_CLOSE; }
static bool mg_rpc_channel_ws_send_frame(struct mg_rpc_channel *ch, const struct mg_str f) { struct mg_rpc_channel_ws_data *chd = (struct mg_rpc_channel_ws_data *) ch->channel_data; if (chd->nc == NULL || chd->sending) return false; chd->sending = true; mg_send_websocket_frame(chd->nc, WEBSOCKET_OP_TEXT, f.p, f.len); return true; }
void RestServ::websocketBroadcast(mg_connection& nc, const char* msg, size_t len) { mg_connection* iter; for (iter = mg_next(nc.mgr, nullptr); iter != nullptr; iter = mg_next(nc.mgr, iter)) { mg_send_websocket_frame(iter, WEBSOCKET_OP_TEXT, msg, len); } }
static void save_all( struct mg_connection* nc ) { s_source->pathCount = 0; printf("REMOVE ALL\n"); snprintf( s_output_buffer, kOutputBufferSize, "{ \"cmd\" : \"SAVE-ALL\" }" ); int len = strlen( s_output_buffer ); mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, s_output_buffer, len ); }
/* * Forwards API payload to the device, by scanning through * all the connections to find those that are tagged as WebSocket. */ static void send_command_to_the_device(struct mg_mgr *mgr, const struct mg_str *cmd) { struct mg_connection *nc; for (nc = mg_next(mgr, NULL); nc != NULL; nc = mg_next(mgr, nc)) { if (!(nc->flags & MG_F_IS_WEBSOCKET)) continue; // Ignore non-websocket requests mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, cmd->p, cmd->len); printf("Sent API command [%.*s] to %p\n", (int) cmd->len, cmd->p, nc); } }
static void broadcast_callback(struct mg_connection *nc, int ev, void *ev_data) { char *buf = (char *) ev_data; if (ev != MG_EV_POLL) return; if (!(nc->flags & MG_F_IS_WEBSOCKET)) return; mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, buf, strlen(buf)); }
static void broadcast(struct mg_connection *nc, const struct mg_str msg) { struct mg_connection *c; char buf[500]; char addr[32]; mg_sock_addr_to_str(&nc->sa, addr, sizeof(addr), MG_SOCK_STRINGIFY_IP | MG_SOCK_STRINGIFY_PORT); snprintf(buf, sizeof(buf), "%s %.*s", addr, (int) msg.len, msg.p); printf("%s\n", buf); /* Local echo. */ for (c = mg_next(nc->mgr, NULL); c != NULL; c = mg_next(nc->mgr, c)) { if (c == nc) continue; /* Don't send to the sender. */ mg_send_websocket_frame(c, WEBSOCKET_OP_TEXT, buf, strlen(buf)); } }
static void send_sources( struct mg_connection* nc ) { for (int i=0; i<s_source->pathCount; i++) { int path_len = strlen( s_source->paths[i] ); if (path_len) { printf("SEND %s\n",s_source->paths[i]); snprintf( s_output_buffer, kOutputBufferSize, "{ \"cmd\" : \"LOAD\", \"path\" : \"%s\", \"text\" : \"%s\" }", s_source->paths[i],s_source->text[i]); int len = strlen( s_output_buffer ); mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, s_output_buffer, len ); } } }
void TestHttpClient::Close(struct mg_connection * conn) { boost::mutex mutex; boost::condition_variable cond; on_closed_ = [&](struct mg_connection * ws) { assert(conn == ws); boost::mutex::scoped_lock lock(mutex); cond.notify_one(); }; mg_send_websocket_frame(conn, WEBSOCKET_OP_CLOSE, nullptr, 0); boost::mutex::scoped_lock lock(mutex); cond.wait(lock); }
void mg_printf_websocket_frame(struct mg_connection *nc, int op, const char *fmt, ...) { char mem[MG_VPRINTF_BUFFER_SIZE], *buf = mem; va_list ap; int len; va_start(ap, fmt); if ((len = mg_avprintf(&buf, sizeof(mem), fmt, ap)) > 0) { mg_send_websocket_frame(nc, op, buf, len); } va_end(ap); if (buf != mem && buf != NULL) { MG_FREE(buf); } }
static void _WebSocket_send_blob(struct v7 *v7, struct mg_connection *nc, v7_val_t blob) { const char *data; size_t len; unsigned long alen, i; v7_val_t chunks, chunk; chunks = v7_get(v7, blob, "a", ~0); alen = v7_array_length(v7, chunks); for (i = 0; i < alen; i++) { int op = i == 0 ? WEBSOCKET_OP_BINARY : WEBSOCKET_OP_CONTINUE; int flag = i == alen - 1 ? 0 : WEBSOCKET_DONT_FIN; chunk = v7_array_get(v7, chunks, i); /* * This hack allows us to skip the first or the last frame * while sending blobs. The effect of it is that it's possible to * concatenate more blobs into a single WS message composed of * several fragments. * * WebSocket.send(new Blob(["123", undefined])); * WebSocket.send(new Blob([undefined, "456"])); * * If the last blob component is undefined, the current message is thus * left open. In order to continue sending fragments of the same message * the next send call should have it's first component undefined. * * TODO(mkm): find a better API. */ if (!v7_is_undefined(chunk)) { data = v7_to_string(v7, &chunk, &len); mg_send_websocket_frame(nc, op | flag, data, len); } } }
void RestServ::websocketSend(mg_connection* nc, const char* msg, size_t len) { mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, len); }
static int mg_deliver_websocket_data(struct mg_connection *nc) { /* Using unsigned char *, cause of integer arithmetic below */ uint64_t i, data_len = 0, frame_len = 0, new_data_len = nc->recv_mbuf.len, len, mask_len = 0, header_len = 0; struct mg_ws_proto_data *wsd = mg_ws_get_proto_data(nc); unsigned char *new_data = (unsigned char *) nc->recv_mbuf.buf, *e = (unsigned char *) nc->recv_mbuf.buf + nc->recv_mbuf.len; uint8_t flags; int ok, reass; if (wsd->reass_len > 0) { /* * We already have some previously received data which we need to * reassemble and deliver to the client code when we get the final * fragment. * * NOTE: it doesn't mean that the current message must be a continuation: * it might be a control frame (Close, Ping or Pong), which should be * handled without breaking the fragmented message. */ size_t existing_len = wsd->reass_len; assert(new_data_len >= existing_len); new_data += existing_len; new_data_len -= existing_len; } flags = new_data[0]; reass = new_data_len > 0 && mg_is_ws_fragment(flags) && !(nc->flags & MG_F_WEBSOCKET_NO_DEFRAG); if (reass && mg_is_ws_control_frame(flags)) { /* * Control frames can't be fragmented, so if we encounter fragmented * control frame, close connection immediately. */ mg_ws_close(nc, "fragmented control frames are illegal", ~0); return 0; } else if (new_data_len > 0 && !reass && !mg_is_ws_control_frame(flags) && wsd->reass_len > 0) { /* * When in the middle of a fragmented message, only the continuations * and control frames are allowed. */ mg_ws_close(nc, "non-continuation in the middle of a fragmented message", ~0); return 0; } if (new_data_len >= 2) { len = new_data[1] & 0x7f; mask_len = new_data[1] & FLAGS_MASK_FIN ? 4 : 0; if (len < 126 && new_data_len >= mask_len) { data_len = len; header_len = 2 + mask_len; } else if (len == 126 && new_data_len >= 4 + mask_len) { header_len = 4 + mask_len; data_len = ntohs(*(uint16_t *) &new_data[2]); } else if (new_data_len >= 10 + mask_len) { header_len = 10 + mask_len; data_len = (((uint64_t) ntohl(*(uint32_t *) &new_data[2])) << 32) + ntohl(*(uint32_t *) &new_data[6]); } } frame_len = header_len + data_len; ok = (frame_len > 0 && frame_len <= new_data_len); /* Check for overflow */ if (frame_len < header_len || frame_len < data_len) { ok = 0; mg_ws_close(nc, "overflowed message", ~0); } if (ok) { size_t cleanup_len = 0; struct websocket_message wsm; wsm.size = (size_t) data_len; wsm.data = new_data + header_len; wsm.flags = flags; /* Apply mask if necessary */ if (mask_len > 0) { for (i = 0; i < data_len; i++) { new_data[i + header_len] ^= (new_data + header_len - mask_len)[i % 4]; } } if (reass) { /* This is a message fragment */ if (mg_is_ws_first_fragment(flags)) { /* * On the first fragmented frame, skip the first byte (op) and also * reset size to 1 (op), it'll be incremented with the data len below. */ new_data += 1; wsd->reass_len = 1 /* op */; } /* Append this frame to the reassembled buffer */ memmove(new_data, wsm.data, e - wsm.data); wsd->reass_len += wsm.size; nc->recv_mbuf.len -= wsm.data - new_data; if (flags & FLAGS_MASK_FIN) { /* On last fragmented frame - call user handler and remove data */ wsm.flags = FLAGS_MASK_FIN | nc->recv_mbuf.buf[0]; wsm.data = (unsigned char *) nc->recv_mbuf.buf + 1 /* op */; wsm.size = wsd->reass_len - 1 /* op */; cleanup_len = wsd->reass_len; wsd->reass_len = 0; /* Pass reassembled message to the client code. */ mg_handle_incoming_websocket_frame(nc, &wsm); mbuf_remove(&nc->recv_mbuf, cleanup_len); /* Cleanup frame */ } } else { /* * This is a complete message, not a fragment. It might happen in between * of a fragmented message (in this case, WebSocket protocol requires * current message to be a control frame). */ cleanup_len = (size_t) frame_len; /* First of all, check if we need to react on a control frame. */ switch (flags & FLAGS_MASK_OP) { case WEBSOCKET_OP_PING: mg_send_websocket_frame(nc, WEBSOCKET_OP_PONG, wsm.data, wsm.size); break; case WEBSOCKET_OP_CLOSE: mg_ws_close(nc, wsm.data, wsm.size); break; } /* Pass received message to the client code. */ mg_handle_incoming_websocket_frame(nc, &wsm); /* Cleanup frame */ memmove(nc->recv_mbuf.buf + wsd->reass_len, nc->recv_mbuf.buf + wsd->reass_len + cleanup_len, nc->recv_mbuf.len - wsd->reass_len - cleanup_len); nc->recv_mbuf.len -= cleanup_len; } } return ok; }
static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { struct websocket_message *wm = (struct websocket_message *) ev_data; (void) nc; switch (ev) { case MG_EV_CONNECT: { int status = *((int *) ev_data); if (status != 0) { printf("-- Connection error: %d\n", status); } break; } case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { printf("-- Connected\n"); s_is_connected = 1; break; } case MG_EV_POLL: { char msg[500]; int n = 0; #ifdef _WIN32 /* Windows console input is special. */ INPUT_RECORD inp[100]; HANDLE h = GetStdHandle(STD_INPUT_HANDLE); DWORD i, num; if (!PeekConsoleInput(h, inp, sizeof(inp) / sizeof(*inp), &num)) break; for (i = 0; i < num; i++) { if (inp[i].EventType == KEY_EVENT && inp[i].Event.KeyEvent.wVirtualKeyCode == VK_RETURN) { break; } } if (i == num) break; if (!ReadConsole(h, msg, sizeof(msg), &num, NULL)) break; /* Un-unicode. This is totally not the right way to do it. */ for (i = 0; i < num * 2; i += 2) msg[i / 2] = msg[i]; n = (int) num; #else /* For everybody else, we just read() stdin. */ fd_set read_set, write_set, err_set; struct timeval timeout = {0, 0}; FD_ZERO(&read_set); FD_ZERO(&write_set); FD_ZERO(&err_set); FD_SET(0 /* stdin */, &read_set); if (select(1, &read_set, &write_set, &err_set, &timeout) == 1) { n = read(0, msg, sizeof(msg)); } #endif if (n <= 0) break; while (msg[n - 1] == '\r' || msg[n - 1] == '\n') n--; mg_send_websocket_frame(nc, WEBSOCKET_OP_TEXT, msg, n); break; } case MG_EV_WEBSOCKET_FRAME: { printf("%.*s\n", (int) wm->size, wm->data); break; } case MG_EV_CLOSE: { if (s_is_connected) printf("-- Disconnected\n"); s_done = 1; break; } } }
/** * @brief Close the WebSocket from the web server end. * Previously a client has connected to us and created a WebSocket. By making this call we are * declaring that the socket should be closed from the server end. * @return N/A. */ void WebServer::WebSocketHandler::close() { mg_send_websocket_frame(m_mgConnection, WEBSOCKET_OP_CLOSE, nullptr, 0); } // close
/** * @brief Send data down the WebSocket * @param [in] data The message to send down the socket. * @param [in] size The size of the message * @return N/A. */ void WebServer::WebSocketHandler::sendData(uint8_t *data, uint32_t size) { mg_send_websocket_frame(m_mgConnection, WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, data, size); } // sendData
/** * @brief Send data down the WebSocket * @param [in] message The message to send down the socket. * @return N/A. */ void WebServer::WebSocketHandler::sendData(std::string message) { ESP_LOGD(tag, "WebSocketHandler::sendData(length=%d)", message.length()); mg_send_websocket_frame(m_mgConnection, WEBSOCKET_OP_BINARY | WEBSOCKET_OP_CONTINUE, message.data(), message.length()); } // sendData