//-------------------------------------------------------------- void Connection::setupAddress(){ int fd = libwebsocket_get_socket_fd( ws ); client_ip.resize(128); client_name.resize(128); libwebsockets_get_peer_addresses(fd, &client_name[0], client_name.size(), &client_ip[0], client_ip.size()); }
//-------------------------------------------------------------- unsigned int Reactor::_allow(struct libwebsocket *ws, Protocol* const protocol, const long fd){ std::string client_ip(128, 0); std::string client_name(128, 0); libwebsockets_get_peer_addresses(context, ws, libwebsocket_get_socket_fd(ws), &client_name[0], client_name.size(), &client_ip[0], client_ip.size()); return protocol->_allowClient(client_name, client_ip); }
FString FWebSocket::RemoteEndPoint() { #if !PLATFORM_HTML5 ANSICHAR Peer_Name[128]; ANSICHAR Peer_Ip[128]; libwebsockets_get_peer_addresses(Context, Wsi, libwebsocket_get_socket_fd(Wsi), Peer_Name, sizeof Peer_Name, Peer_Ip, sizeof Peer_Ip); return FString(Peer_Name); #endif #if PLATFORM_HTML5 return FString(TEXT("TODO:REMOTEENDPOINT")); #endif }
int websocket_fd_set(int socket, fd_set *set) { libwebsocket_context *context = contexts[socket].context; if(context == NULL) return -1; context_data *ctx_data = (context_data *)libwebsocket_context_user(context); int max = 0; for(int i = 0; i < WS_CLIENTS; i++) { per_session_data *pss = ctx_data->port_map[i]; if(pss == NULL) continue; int fd = libwebsocket_get_socket_fd(pss->wsi); if(fd > max) max = fd; FD_SET(fd, set); } return max; }
static int websocket_callback(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data *pss = (struct per_session_data *)user; context_data *ctx_data = (context_data *)libwebsocket_context_user(context); switch(reason) { case LWS_CALLBACK_ESTABLISHED: { int port = -1; for(int i = 0; i < WS_CLIENTS; i++) { int j = (ctx_data->last_used_port + i + 1) % WS_CLIENTS; if(ctx_data->port_map[j] == NULL) { port = j; break; } } if(port == -1) { dbg_msg("websockets", "no free ports, dropping"); pss->port = -1; return -1; } ctx_data->last_used_port = port; pss->wsi = wsi; int fd = libwebsocket_get_socket_fd(wsi); socklen_t addr_size = sizeof(pss->addr); getpeername(fd, (struct sockaddr *)&pss->addr, &addr_size); int orig_port = ntohs(pss->addr.sin_port); pss->addr.sin_port = htons(port); pss->send_buffer.Init(); pss->port = port; ctx_data->port_map[port] = pss; char addr_str[NETADDR_MAXSTRSIZE]; inet_ntop(AF_INET, &pss->addr.sin_addr, addr_str, sizeof(addr_str)); dbg_msg("websockets", "connection established with %s:%d , assigned fake port %d", addr_str, orig_port, port); } break; case LWS_CALLBACK_CLOSED: { dbg_msg("websockets", "connection with fake port %d closed", pss->port); if (pss->port > -1) { unsigned char close_packet[] = { 0x10, 0x0e, 0x00, 0x04 }; receive_chunk(ctx_data, pss, &close_packet, sizeof(close_packet)); pss->wsi = 0; ctx_data->port_map[pss->port] = NULL; } } break; case LWS_CALLBACK_SERVER_WRITEABLE: { websocket_chunk *chunk = (websocket_chunk *)pss->send_buffer.First(); if(chunk == NULL) break; int len = chunk->size - chunk->read; int n = libwebsocket_write(wsi, &chunk->data[LWS_SEND_BUFFER_PRE_PADDING + chunk->read], chunk->size - chunk->read, LWS_WRITE_BINARY); if(n < 0) return 1; if(n < len) { chunk->read += n; libwebsocket_callback_on_writable(context, wsi); break; } pss->send_buffer.PopFirst(); libwebsocket_callback_on_writable(context, wsi); } break; case LWS_CALLBACK_RECEIVE: if(pss->port == -1) return -1; if(!receive_chunk(ctx_data, pss, in, len)) return 1; break; default: break; } return 0; }
int janus_websockets_send_message(void *transport, void *request_id, gboolean admin, json_t *message) { if(message == NULL) return -1; if(transport == NULL) { json_decref(message); return -1; } /* Make sure this is not related to a closed /freed WebSocket session */ janus_mutex_lock(&old_wss_mutex); janus_websockets_client *client = (janus_websockets_client *)transport; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(g_list_find(old_wss, client) != NULL || !client->wsi) { #else if(g_list_find(old_wss, client) != NULL || !client->context || !client->wsi) { #endif json_decref(message); message = NULL; transport = NULL; janus_mutex_unlock(&old_wss_mutex); return -1; } janus_mutex_lock(&client->mutex); /* Convert to string and enqueue */ char *payload = json_dumps(message, json_format); g_async_queue_push(client->messages, payload); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(client->wsi); #else libwebsocket_callback_on_writable(client->context, client->wsi); #endif janus_mutex_unlock(&client->mutex); janus_mutex_unlock(&old_wss_mutex); json_decref(message); return 0; } void janus_websockets_session_created(void *transport, guint64 session_id) { /* We don't care */ } void janus_websockets_session_over(void *transport, guint64 session_id, gboolean timeout) { if(transport == NULL || !timeout) return; /* We only care if it's a timeout: if so, close the connection */ janus_websockets_client *client = (janus_websockets_client *)transport; /* Make sure this is not related to a closed WebSocket session */ janus_mutex_lock(&old_wss_mutex); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(g_list_find(old_wss, client) == NULL && client->wsi){ #else if(g_list_find(old_wss, client) == NULL && client->context && client->wsi){ #endif janus_mutex_lock(&client->mutex); client->session_timeout = 1; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(client->wsi); #else libwebsocket_callback_on_writable(client->context, client->wsi); #endif janus_mutex_unlock(&client->mutex); } janus_mutex_unlock(&old_wss_mutex); } /* Thread */ void *janus_websockets_thread(void *data) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws_context *service = (struct lws_context *)data; #else struct libwebsocket_context *service = (struct libwebsocket_context *)data; #endif if(service == NULL) { JANUS_LOG(LOG_ERR, "Invalid service\n"); return NULL; } const char *type = NULL; if(service == wss) type = "WebSocket (Janus API)"; else if(service == swss) type = "Secure WebSocket (Janus API)"; else if(service == admin_wss) type = "WebSocket (Admin API)"; else if(service == admin_swss) type = "Secure WebSocket (Admin API)"; JANUS_LOG(LOG_INFO, "%s thread started\n", type); while(g_atomic_int_get(&initialized) && !g_atomic_int_get(&stopping)) { /* libwebsockets is single thread, we cycle through events here */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_service(service, 50); #else libwebsocket_service(service, 50); #endif } /* Get rid of the WebSockets server */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_cancel_service(service); #else libwebsocket_cancel_service(service); #endif /* Done */ JANUS_LOG(LOG_INFO, "%s thread ended\n", type); return NULL; } /* WebSockets */ static int janus_websockets_callback_http( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* This endpoint cannot be used for HTTP */ switch(reason) { case LWS_CALLBACK_HTTP: JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint\n"); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_return_http_status(wsi, 403, NULL); #else libwebsockets_return_http_status(this, wsi, 403, NULL); #endif /* Close and free connection */ return -1; case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: if (!in) { JANUS_LOG(LOG_VERB, "Rejecting incoming HTTP request on WebSockets endpoint: no sub-protocol specified\n"); return -1; } break; default: break; } return 0; } static int janus_websockets_callback_https( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the HTTP handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_callback_http(wsi, reason, user, in, len); #else return janus_websockets_callback_http(this, wsi, reason, user, in, len); #endif } /* This callback handles Janus API requests */ static int janus_websockets_common_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len, gboolean admin) { const char *log_prefix = admin ? "AdminWSS" : "WSS"; janus_websockets_client *ws_client = (janus_websockets_client *)user; switch(reason) { case LWS_CALLBACK_ESTABLISHED: { /* Is there any filtering we should apply? */ char name[256], ip[256]; #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, 256, ip, 256); #else libwebsockets_get_peer_addresses(this, wsi, libwebsocket_get_socket_fd(wsi), name, 256, ip, 256); #endif JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection opened from %s by %s\n", log_prefix, wsi, ip, name); if(!janus_websockets_is_allowed(ip, admin)) { JANUS_LOG(LOG_ERR, "[%s-%p] IP %s is unauthorized to connect to the WebSockets %s API interface\n", log_prefix, wsi, ip, admin ? "Admin" : "Janus"); /* Close the connection */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif return -1; } JANUS_LOG(LOG_VERB, "[%s-%p] WebSocket connection accepted\n", log_prefix, wsi); if(ws_client == NULL) { JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } /* Clean the old sessions list, in case this pointer was used before */ janus_mutex_lock(&old_wss_mutex); if(g_list_find(old_wss, ws_client) != NULL) old_wss = g_list_remove(old_wss, ws_client); janus_mutex_unlock(&old_wss_mutex); /* Prepare the session */ #ifndef HAVE_LIBWEBSOCKETS_NEWAPI ws_client->context = this; #endif ws_client->wsi = wsi; ws_client->messages = g_async_queue_new(); ws_client->buffer = NULL; ws_client->buflen = 0; ws_client->bufpending = 0; ws_client->bufoffset = 0; ws_client->session_timeout = 0; ws_client->destroy = 0; janus_mutex_init(&ws_client->mutex); /* Let us know when the WebSocket channel becomes writeable */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif JANUS_LOG(LOG_VERB, "[%s-%p] -- Ready to be used!\n", log_prefix, wsi); /* Notify handlers about this new transport */ if(notify_events && gateway->events_is_enabled()) { json_t *info = json_object(); json_object_set_new(info, "event", json_string("connected")); json_object_set_new(info, "admin_api", admin ? json_true() : json_false()); json_object_set_new(info, "ip", json_string(ip)); gateway->notify_event(&janus_websockets_transport, ws_client, info); } return 0; } case LWS_CALLBACK_RECEIVE: { JANUS_LOG(LOG_HUGE, "[%s-%p] Got %zu bytes:\n", log_prefix, wsi, len); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(ws_client == NULL || ws_client->wsi == NULL) { #else if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) { #endif JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } /* Is this a new message, or part of a fragmented one? */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI const size_t remaining = lws_remaining_packet_payload(wsi); #else const size_t remaining = libwebsockets_remaining_packet_payload(wsi); #endif if(ws_client->incoming == NULL) { JANUS_LOG(LOG_HUGE, "[%s-%p] First fragment: %zu bytes, %zu remaining\n", log_prefix, wsi, len, remaining); ws_client->incoming = g_malloc0(len+1); memcpy(ws_client->incoming, in, len); ws_client->incoming[len] = '\0'; JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming); } else { size_t offset = strlen(ws_client->incoming); JANUS_LOG(LOG_HUGE, "[%s-%p] Appending fragment: offset %zu, %zu bytes, %zu remaining\n", log_prefix, wsi, offset, len, remaining); ws_client->incoming = g_realloc(ws_client->incoming, offset+len+1); memcpy(ws_client->incoming+offset, in, len); ws_client->incoming[offset+len] = '\0'; JANUS_LOG(LOG_HUGE, "%s\n", ws_client->incoming+offset); } #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(remaining > 0 || !lws_is_final_fragment(wsi)) { #else if(remaining > 0 || !libwebsocket_is_final_fragment(wsi)) { #endif /* Still waiting for some more fragments */ JANUS_LOG(LOG_HUGE, "[%s-%p] Waiting for more fragments\n", log_prefix, wsi); return 0; } JANUS_LOG(LOG_HUGE, "[%s-%p] Done, parsing message: %zu bytes\n", log_prefix, wsi, strlen(ws_client->incoming)); /* If we got here, the message is complete: parse the JSON payload */ json_error_t error; json_t *root = json_loads(ws_client->incoming, 0, &error); g_free(ws_client->incoming); ws_client->incoming = NULL; /* Notify the core, passing both the object and, since it may be needed, the error */ gateway->incoming_request(&janus_websockets_transport, ws_client, NULL, admin, root, &error); return 0; } case LWS_CALLBACK_SERVER_WRITEABLE: { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI if(ws_client == NULL || ws_client->wsi == NULL) { #else if(ws_client == NULL || ws_client->context == NULL || ws_client->wsi == NULL) { #endif JANUS_LOG(LOG_ERR, "[%s-%p] Invalid WebSocket client instance...\n", log_prefix, wsi); return -1; } if(!ws_client->destroy && !g_atomic_int_get(&stopping)) { janus_mutex_lock(&ws_client->mutex); /* Check if we have a pending/partial write to complete first */ if(ws_client->buffer && ws_client->bufpending > 0 && ws_client->bufoffset > 0 && !ws_client->destroy && !g_atomic_int_get(&stopping)) { JANUS_LOG(LOG_HUGE, "[%s-%p] Completing pending WebSocket write (still need to write last %d bytes)...\n", log_prefix, wsi, ws_client->bufpending); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI int sent = lws_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT); #else int sent = libwebsocket_write(wsi, ws_client->buffer + ws_client->bufoffset, ws_client->bufpending, LWS_WRITE_TEXT); #endif JANUS_LOG(LOG_HUGE, "[%s-%p] -- Sent %d/%d bytes\n", log_prefix, wsi, sent, ws_client->bufpending); if(sent > -1 && sent < ws_client->bufpending) { /* We still couldn't send everything that was left, we'll try and complete this in the next round */ ws_client->bufpending -= sent; ws_client->bufoffset += sent; } else { /* Clear the pending/partial write queue */ ws_client->bufpending = 0; ws_client->bufoffset = 0; } /* Done for this round, check the next response/notification later */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif janus_mutex_unlock(&ws_client->mutex); return 0; } /* Shoot all the pending messages */ char *response = g_async_queue_try_pop(ws_client->messages); if(response && !ws_client->destroy && !g_atomic_int_get(&stopping)) { /* Gotcha! */ int buflen = LWS_SEND_BUFFER_PRE_PADDING + strlen(response) + LWS_SEND_BUFFER_POST_PADDING; if(ws_client->buffer == NULL) { /* Let's allocate a shared buffer */ JANUS_LOG(LOG_HUGE, "[%s-%p] Allocating %d bytes (response is %zu bytes)\n", log_prefix, wsi, buflen, strlen(response)); ws_client->buflen = buflen; ws_client->buffer = g_malloc0(buflen); } else if(buflen > ws_client->buflen) { /* We need a larger shared buffer */ JANUS_LOG(LOG_HUGE, "[%s-%p] Re-allocating to %d bytes (was %d, response is %zu bytes)\n", log_prefix, wsi, buflen, ws_client->buflen, strlen(response)); ws_client->buflen = buflen; ws_client->buffer = g_realloc(ws_client->buffer, buflen); } memcpy(ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, response, strlen(response)); JANUS_LOG(LOG_HUGE, "[%s-%p] Sending WebSocket message (%zu bytes)...\n", log_prefix, wsi, strlen(response)); #ifdef HAVE_LIBWEBSOCKETS_NEWAPI int sent = lws_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT); #else int sent = libwebsocket_write(wsi, ws_client->buffer + LWS_SEND_BUFFER_PRE_PADDING, strlen(response), LWS_WRITE_TEXT); #endif JANUS_LOG(LOG_HUGE, "[%s-%p] -- Sent %d/%zu bytes\n", log_prefix, wsi, sent, strlen(response)); if(sent > -1 && sent < (int)strlen(response)) { /* We couldn't send everything in a single write, we'll complete this in the next round */ ws_client->bufpending = strlen(response) - sent; ws_client->bufoffset = LWS_SEND_BUFFER_PRE_PADDING + sent; JANUS_LOG(LOG_HUGE, "[%s-%p] -- Couldn't write all bytes (%d missing), setting offset %d\n", log_prefix, wsi, ws_client->bufpending, ws_client->bufoffset); } /* We can get rid of the message */ free(response); /* Done for this round, check the next response/notification later */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI lws_callback_on_writable(wsi); #else libwebsocket_callback_on_writable(this, wsi); #endif janus_mutex_unlock(&ws_client->mutex); return 0; } janus_mutex_unlock(&ws_client->mutex); } return 0; } case LWS_CALLBACK_CLOSED: { JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, closing\n", log_prefix, wsi); janus_websockets_destroy_client(ws_client, wsi, log_prefix); JANUS_LOG(LOG_VERB, "[%s-%p] -- closed\n", log_prefix, wsi); return 0; } case LWS_CALLBACK_WSI_DESTROY: { JANUS_LOG(LOG_VERB, "[%s-%p] WS connection down, destroying\n", log_prefix, wsi); janus_websockets_destroy_client(ws_client, wsi, log_prefix); JANUS_LOG(LOG_VERB, "[%s-%p] -- destroyed\n", log_prefix, wsi); return 0; } default: if(wsi != NULL) { JANUS_LOG(LOG_HUGE, "[%s-%p] %d (%s)\n", log_prefix, wsi, reason, janus_websockets_reason_string(reason)); } else { JANUS_LOG(LOG_HUGE, "[%s] %d (%s)\n", log_prefix, reason, janus_websockets_reason_string(reason)); } break; } return 0; } /* This callback handles Janus API requests */ static int janus_websockets_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_common_callback(wsi, reason, user, in, len, FALSE); #else return janus_websockets_common_callback(this, wsi, reason, user, in, len, FALSE); #endif } static int janus_websockets_callback_secure( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the Janus API handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_callback(wsi, reason, user, in, len); #else return janus_websockets_callback(this, wsi, reason, user, in, len); #endif } /* This callback handles Admin API requests */ static int janus_websockets_admin_callback( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_common_callback(wsi, reason, user, in, len, TRUE); #else return janus_websockets_common_callback(this, wsi, reason, user, in, len, TRUE); #endif } static int janus_websockets_admin_callback_secure( #ifdef HAVE_LIBWEBSOCKETS_NEWAPI struct lws *wsi, enum lws_callback_reasons reason, #else struct libwebsocket_context *this, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, #endif void *user, void *in, size_t len) { /* We just forward the event to the Admin API handler */ #ifdef HAVE_LIBWEBSOCKETS_NEWAPI return janus_websockets_admin_callback(wsi, reason, user, in, len); #else return janus_websockets_admin_callback(this, wsi, reason, user, in, len); #endif }
static int callback_mqtt(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct mosquitto_db *db; struct mosquitto *mosq = NULL; struct mosquitto__packet *packet; int count, i, j; const struct libwebsocket_protocols *p; struct libws_mqtt_data *u = (struct libws_mqtt_data *)user; size_t pos; uint8_t *buf; int rc; uint8_t byte; db = &int_db; switch (reason) { case LWS_CALLBACK_ESTABLISHED: mosq = context__init(db, WEBSOCKET_CLIENT); if(mosq){ p = libwebsockets_get_protocol(wsi); for (i=0; i<db->config->listener_count; i++){ if (db->config->listeners[i].protocol == mp_websockets) { for (j=0; db->config->listeners[i].ws_protocol[j].name; j++){ if (p == &db->config->listeners[i].ws_protocol[j]){ mosq->listener = &db->config->listeners[i]; mosq->listener->client_count++; } } } } if(!mosq->listener){ mosquitto__free(mosq); return -1; } #if !defined(LWS_LIBRARY_VERSION_NUMBER) mosq->ws_context = context; #endif mosq->wsi = wsi; #ifdef WITH_TLS if(in){ mosq->ssl = (SSL *)in; if(!mosq->listener->ssl_ctx){ mosq->listener->ssl_ctx = SSL_get_SSL_CTX(mosq->ssl); } } #endif u->mosq = mosq; }else{ return -1; } easy_address(libwebsocket_get_socket_fd(wsi), mosq); if(!mosq->address){ /* getpeername and inet_ntop failed and not a bridge */ mosquitto__free(mosq); u->mosq = NULL; return -1; } if(mosq->listener->max_connections > 0 && mosq->listener->client_count > mosq->listener->max_connections){ if(db->config->connection_messages == true){ log__printf(NULL, MOSQ_LOG_NOTICE, "Client connection from %s denied: max_connections exceeded.", mosq->address); } mosquitto__free(mosq); u->mosq = NULL; return -1; } mosq->sock = libwebsocket_get_socket_fd(wsi); HASH_ADD(hh_sock, db->contexts_by_sock, sock, sizeof(mosq->sock), mosq); break; case LWS_CALLBACK_CLOSED: if(!u){ return -1; } mosq = u->mosq; if(mosq){ if(mosq->sock != INVALID_SOCKET){ HASH_DELETE(hh_sock, db->contexts_by_sock, mosq); mosq->sock = INVALID_SOCKET; mosq->pollfd_index = -1; } mosq->wsi = NULL; #ifdef WITH_TLS mosq->ssl = NULL; #endif do_disconnect(db, mosq); } break; case LWS_CALLBACK_SERVER_WRITEABLE: if(!u){ return -1; } mosq = u->mosq; if(!mosq){ return -1; } db__message_write(db, mosq); if(mosq->out_packet && !mosq->current_out_packet){ mosq->current_out_packet = mosq->out_packet; mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } if(mosq->current_out_packet && !lws_send_pipe_choked(mosq->wsi)){ packet = mosq->current_out_packet; if(packet->pos == 0 && packet->to_process == packet->packet_length){ /* First time this packet has been dealt with. * libwebsockets requires that the payload has * LWS_SEND_BUFFER_PRE_PADDING space available before the * actual data and LWS_SEND_BUFFER_POST_PADDING afterwards. * We've already made the payload big enough to allow this, * but need to move it into position here. */ memmove(&packet->payload[LWS_SEND_BUFFER_PRE_PADDING], packet->payload, packet->packet_length); packet->pos += LWS_SEND_BUFFER_PRE_PADDING; } count = libwebsocket_write(wsi, &packet->payload[packet->pos], packet->to_process, LWS_WRITE_BINARY); if(count < 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } return 0; } #ifdef WITH_SYS_TREE g_bytes_sent += count; #endif packet->to_process -= count; packet->pos += count; if(packet->to_process > 0){ if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } break; } #ifdef WITH_SYS_TREE g_msgs_sent++; if(((packet->command)&0xF6) == PUBLISH){ g_pub_msgs_sent++; } #endif /* Free data and reset values */ mosq->current_out_packet = mosq->out_packet; if(mosq->out_packet){ mosq->out_packet = mosq->out_packet->next; if(!mosq->out_packet){ mosq->out_packet_last = NULL; } } packet__cleanup(packet); mosquitto__free(packet); mosq->next_msg_out = mosquitto_time() + mosq->keepalive; } if (mosq->state == mosq_cs_disconnect_ws || mosq->state == mosq_cs_disconnecting){ return -1; } if(mosq->current_out_packet){ libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } break; case LWS_CALLBACK_RECEIVE: if(!u || !u->mosq){ return -1; } mosq = u->mosq; pos = 0; buf = (uint8_t *)in; G_BYTES_RECEIVED_INC(len); while(pos < len){ if(!mosq->in_packet.command){ mosq->in_packet.command = buf[pos]; pos++; /* Clients must send CONNECT as their first command. */ if(mosq->state == mosq_cs_new && (mosq->in_packet.command&0xF0) != CONNECT){ return -1; } } if(mosq->in_packet.remaining_count <= 0){ do{ if(pos == len){ return 0; } byte = buf[pos]; pos++; mosq->in_packet.remaining_count--; /* Max 4 bytes length for remaining length as defined by protocol. * Anything more likely means a broken/malicious client. */ if(mosq->in_packet.remaining_count < -4){ return -1; } mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult; mosq->in_packet.remaining_mult *= 128; }while((byte & 128) != 0); mosq->in_packet.remaining_count *= -1; if(mosq->in_packet.remaining_length > 0){ mosq->in_packet.payload = mosquitto__malloc(mosq->in_packet.remaining_length*sizeof(uint8_t)); if(!mosq->in_packet.payload){ return -1; } mosq->in_packet.to_process = mosq->in_packet.remaining_length; } } if(mosq->in_packet.to_process>0){ if(len - pos >= mosq->in_packet.to_process){ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], mosq->in_packet.to_process); mosq->in_packet.pos += mosq->in_packet.to_process; pos += mosq->in_packet.to_process; mosq->in_packet.to_process = 0; }else{ memcpy(&mosq->in_packet.payload[mosq->in_packet.pos], &buf[pos], len-pos); mosq->in_packet.pos += len-pos; mosq->in_packet.to_process -= len-pos; return 0; } } /* All data for this packet is read. */ mosq->in_packet.pos = 0; #ifdef WITH_SYS_TREE G_MSGS_RECEIVED_INC(1); if(((mosq->in_packet.command)&0xF5) == PUBLISH){ G_PUB_MSGS_RECEIVED_INC(1); } #endif rc = handle__packet(db, mosq); /* Free data and reset values */ packet__cleanup(&mosq->in_packet); mosq->last_msg_in = mosquitto_time(); if(rc && (mosq->out_packet || mosq->current_out_packet)) { if(mosq->state != mosq_cs_disconnecting){ mosq->state = mosq_cs_disconnect_ws; } libwebsocket_callback_on_writable(mosq->ws_context, mosq->wsi); } else if (rc) { do_disconnect(db, mosq); return -1; } } break; default: break; } return 0; }
void _ortc_parse_message(ortc_context *context, char *message){ char *messageId, *messageCount, *messageTotal, *messagePart, *channelNameStr, *messageStr, *params, *permissionsStr, *exceptionStr, *validateString, *operationType; struct cap pmatch[3], pmatch2[5]; int iMessageTotal, wsSock, opt; size_t len, hbLen; ortc_dnode *ch; char hbStr[24]; if(message[0] == 'a') { if (slre_match(&context->reMessage, message, (int)strlen(message), pmatch)) { //is message channelNameStr = _ortc_get_from_slre(1, pmatch); messageStr = _ortc_get_from_slre(2, pmatch); if(slre_match(&context->reMultipart, messageStr, (int)strlen(messageStr), pmatch2)){ messageId = _ortc_get_from_slre(1, pmatch2); messageCount = _ortc_get_from_slre(2, pmatch2); messageTotal = _ortc_get_from_slre(3, pmatch2); messagePart = _ortc_get_from_slre(4, pmatch2); iMessageTotal = atoi(messageTotal); if(iMessageTotal > 1){ //multipart message _ortc_dlist_insert(context->multiparts, messageId, channelNameStr, messagePart, atoi(messageCount), NULL); _ortc_check_if_got_all_parts(context, messageId, iMessageTotal); } else { _ortc_fire_onMessage(context, channelNameStr, messagePart); } free(messageId); free(messageCount); free(messageTotal); free(messagePart); } else { _ortc_fire_onMessage(context, channelNameStr, messageStr); } free(channelNameStr); free(messageStr); } else if (slre_match(&context->reOperation, message, (int)strlen(message), pmatch)) { params = _ortc_get_from_slre(2, pmatch); operationType = _ortc_get_from_slre(1, pmatch); if(strncmp(operationType, "ortc-validated", 14)==0){ if(slre_match(&context->rePermissions, params, (int)strlen(params), pmatch2)){ permissionsStr = _ortc_get_from_slre(1, pmatch2); _ortc_save_permissions(context, permissionsStr); free(permissionsStr); } _ortc_change_state(context, CONNECTED); } else if(strncmp(operationType, "ortc-subscribed", 15)==0){ if(slre_match(&context->reChannel, params, (int)strlen(params), pmatch2)){ channelNameStr = _ortc_get_from_slre(1, pmatch2); ch = _ortc_dlist_search(context->channels, channelNameStr); if(ch != NULL) ch->num += 2; //isSubscribed if(context->onSubscribed != NULL) context->onSubscribed(context, channelNameStr); free(channelNameStr); } } else if(strncmp(operationType, "ortc-unsubscribed", 17)==0){ if(slre_match(&context->reChannel, params, (int)strlen(params), pmatch2)){ channelNameStr = _ortc_get_from_slre(1, pmatch2); _ortc_dlist_delete(context->channels, channelNameStr); if(context->onUnsubscribed != NULL) context->onUnsubscribed(context, channelNameStr); free(channelNameStr); } } else if(strncmp(operationType, "ortc-error", 10)==0){ if(slre_match(&context->reException, params, (int)strlen(params), pmatch2)){ _ortc_cancel_connecting(context); exceptionStr = _ortc_get_from_slre(1, pmatch2); _ortc_exception(context, exceptionStr); free(exceptionStr); } } free(params); free(operationType); } } else if(message[0] == 'o' && strlen(message)==1){ wsSock = libwebsocket_get_socket_fd(context->wsi); opt = ORTC_SNDBUF_SIZE; setsockopt(wsSock, SOL_SOCKET, SO_SNDBUF, (const char*)&opt, sizeof(opt)); if(context->heartbeatActive){ snprintf(hbStr, sizeof(hbStr), "%d;%d;", context->heartbeatTime, context->heartbeatFails); hbLen = strlen(hbStr); } else { hbLen = 0; } len = 17 + strlen(context->appKey) + strlen(context->authToken) + strlen(context->announcementSubChannel) + strlen(context->sessionId) + strlen(context->metadata) + hbLen; validateString = malloc(len+1); if(validateString == NULL){ _ortc_exception(context, "malloc() failed in ortc parese message"); return; } if(context->heartbeatActive) snprintf(validateString, len, "\"validate;%s;%s;%s;%s;%s;%s\"", context->appKey, context->authToken, context->announcementSubChannel, context->sessionId, context->metadata, hbStr); else snprintf(validateString, len, "\"validate;%s;%s;%s;%s;%s;\"", context->appKey, context->authToken, context->announcementSubChannel, context->sessionId, context->metadata); _ortc_send_command(context, validateString); } else if(strncmp(message, "c[1000,\"Normal closure\"]", 20)==0){ _ortc_exception(context, "Server is about to close the websocket!"); } }
static int websocket_callback(struct libwebsocket_context *context,struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason, void *user,void *in, size_t len) { //printf("Switch: %i\n",reason); DebugOut(5) << __SMALLFILE__ << ":" << __LINE__ << "websocket_callback:" << reason << endl; switch (reason) { case LWS_CALLBACK_CLIENT_WRITEABLE: { break; } case LWS_CALLBACK_CLOSED: { sinkManager->disconnectAll(wsi); break; } case LWS_CALLBACK_CLIENT_RECEIVE: { break; } case LWS_CALLBACK_SERVER_WRITEABLE: { break; } case LWS_CALLBACK_RECEIVE: { } case LWS_CALLBACK_HTTP: { //TODO: Verify that ALL requests get sent via LWS_CALLBACK_HTTP, so we can use that instead of LWS_CALLBACK_RECIEVE //TODO: Do we want exceptions, or just to return an invalid json reply? Probably an invalid json reply. DebugOut() << __SMALLFILE__ << ":" << __LINE__ << " Requested: " << (char*)in << "\n"; QByteArray d((char*)in,len); WebSocketSinkManager * manager = sinkManager; if(manager->expectedMessageFrames && manager->partialMessageIndex < manager->expectedMessageFrames) { manager->incompleteMessage += d; manager->partialMessageIndex++; break; } else if(manager->expectedMessageFrames && manager->partialMessageIndex == manager->expectedMessageFrames) { d = manager->incompleteMessage + d; manager->expectedMessageFrames = 0; } QJsonDocument doc; if(doBinary) doc = QJsonDocument::fromBinaryData(d); else doc = QJsonDocument::fromJson(d); if(doc.isNull()) { DebugOut(DebugOut::Error)<<"Invalid message"<<endl; return 0; } QVariantMap call = doc.toVariant().toMap(); string type = call["type"].toString().toStdString(); string name = call["name"].toString().toStdString(); string id = call["transactionid"].toString().toStdString(); if (type == "multiframe") { manager->expectedMessageFrames = call["frames"].toInt(); manager->partialMessageIndex = 1; manager->incompleteMessage = ""; } else if (type == "method") { if(name == "getRanged") { QVariantMap data = call["data"].toMap(); PropertyList propertyList; propertyList.push_back(data["property"].toString().toStdString()); double timeBegin = data["timeBegin"].toDouble(); double timeEnd = data["timeEnd"].toDouble(); double sequenceBegin = data["sequenceBegin"].toInt(); double sequenceEnd = data["sequenceEnd"].toInt(); if ((timeBegin < 0 && timeEnd > 0) || (timeBegin > 0 && timeEnd < 0)) { DebugOut(DebugOut::Warning)<<"Invalid time begin/end pair"<<endl; } else if ((sequenceBegin < 0 && sequenceEnd > 0) || (sequenceBegin > 0 && sequenceEnd < 0)) { DebugOut(DebugOut::Warning)<<"Invalid sequence begin/end pair"<<endl; } else { sinkManager->addSingleShotRangedSink(wsi,propertyList,timeBegin,timeEnd,sequenceBegin,sequenceEnd,id); } } else if (name == "get") { QVariantMap data = call["data"].toMap(); Zone::Type zone = Zone::None; if(data.contains("zone")) { zone = data["zone"].toInt(); } sinkManager->addSingleShotSink(wsi,data["property"].toString().toStdString(),zone,id); } else if (name == "set") { QVariantMap data = call["data"].toMap(); Zone::Type zone(Zone::None); if(data.contains("zone")) { zone = data["zone"].toInt(); } sinkManager->setValue(wsi,data["property"].toString().toStdString(), data["value"].toString().toStdString(), zone, id); } else if (name == "subscribe") { std::string data = call["data"].toString().toStdString(); sinkManager->addSink(wsi, data, id); } else if (name == "unsubscribe") { std::string data = call["data"].toString().toStdString(); sinkManager->removeSink(wsi,data,id); } else if (name == "getSupportedEventTypes") { QVariantMap reply; QStringList list; PropertyList supported = sinkManager->getSupportedProperties(); for(VehicleProperty::Property i : supported) { list.append(i.c_str()); } reply["type"] = "methodReply"; reply["name"] = "getSupportedEventTypes"; reply["transactionid"] = id.c_str(); reply["data"] = list; QByteArray replystr; if(doBinary) replystr = QJsonDocument::fromVariant(reply).toBinaryData(); else { replystr = QJsonDocument::fromVariant(reply).toJson(); cleanJson(replystr); } lwsWrite(wsi, replystr, replystr.length()); } else { DebugOut(0)<<"Unknown method called."<<endl; } } break; } case LWS_CALLBACK_ADD_POLL_FD: { //printf("Adding poll %i\n",sinkManager); DebugOut(5) << __SMALLFILE__ <<":"<< __LINE__ << "Adding poll" << endl; if (sinkManager != 0) { //sinkManager->addPoll((int)(long)user); sinkManager->addPoll(libwebsocket_get_socket_fd(wsi)); } else { DebugOut(5) << "Error, invalid sink manager!!" << endl; } break; } case LWS_CALLBACK_DEL_POLL_FD: { sinkManager->removePoll(libwebsocket_get_socket_fd(wsi)); break; } case LWS_CALLBACK_SET_MODE_POLL_FD: { //Set the poll mode break; } case LWS_CALLBACK_CLEAR_MODE_POLL_FD: { //Don't handle this yet. break; } default: { //printf("Unhandled callback: %i\n",reason); DebugOut() << __SMALLFILE__ <<":"<< __LINE__ << "Unhandled callback:" << reason << "\n"; break; } } return 0; }
int WebSocketClient2::lws_callback_vopp(struct libwebsocket_context * ctx, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING]; int l; int n; std::string str1, str2; struct client_session_user_data *ssd = (struct client_session_user_data*)user; WebSocketClient2 *wsc = (WebSocketClient2*)(libwebsocket_context_user_data(ctx)); switch (reason) { case LWS_CALLBACK_CLOSED: fprintf(stderr, "mirror: LWS_CALLBACK_CLOSED\n"); if (ssd->pc != NULL) { delete ssd->pc; ssd->pc = NULL; } wsc->lws_connection_closed(wsi); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: // 因为在调用libwebsocket_client_connect的时候,事件循环还没有启动, // 所以事件不会传递出来。 qLogx()<<"connection state:" <<libwebsockets_remaining_packet_payload(wsi) <<libwebsocket_get_socket_fd(wsi) <<libwebsocket_get_connect_state(wsi); ssd->pc = new PackageCombiner; wsc->lws_new_connection_established(wsi); /* * start the ball rolling, * LWS_CALLBACK_CLIENT_WRITEABLE will come next service */ // libwebsocket_callback_on_writable(ctx, wsi); break; case LWS_CALLBACK_CLIENT_RECEIVE: /* fprintf(stderr, "rx %d '%s'\n", (int)len, (char *)in); */ // wsc->lws_ws_message_ready(wsi, (char*)in, len); str1 = std::string((char*)in, len); ssd->pc->save_fragment(str1); if (ssd->pc->is_package_finish(str1)) { str2 = ssd->pc->get_full_package(str1); strncpy(ssd->full_message, str2.c_str(), sizeof(ssd->full_message)-1); n = wsc->lws_ws_message_ready(wsi, ssd->full_message, str2.length()); } break; case LWS_CALLBACK_CLIENT_WRITEABLE: // l = sprintf((char *)&buf[LWS_SEND_BUFFER_PRE_PADDING], // "c #%06X %d %d %d;", // (int)random() & 0xffffff, // (int)random() % 500, // (int)random() % 250, // (int)random() % 24); // libwebsocket_write(wsi, // &buf[LWS_SEND_BUFFER_PRE_PADDING], l, LWS_WRITE_TEXT); // /* get notified as soon as we can write again */ // libwebsocket_callback_on_writable(ctx, wsi); libwebsocket_callback_on_writable(ctx, wsi); // /* // * Without at least this delay, we choke the browser // * and the connection stalls, despite we now take care about // * flow control // */ // usleep(200); break; default: break; } return 0; }
bool WebSocketClient2::on_wsctx_inited() { QUrl mu(this->m_uri); qLogx()<<mu; unsigned short port = mu.port(18080); QString host = mu.host(); QString path = mu.path(); // 默认为1,最安全 int ssl_mode = 1; // 0,ws://, 1,wss://encrypt, 2,wss://self signed if (mu.scheme().toLower() == "ws") { ssl_mode = 0; } else if (mu.scheme().toLower() == "wss") { ssl_mode = 2; } else { Q_ASSERT(1==2); } int conn_retry = 3; while (conn_retry -- > 0) { // 需要关注测试一下,这个调用是否是阻塞式的,如果是非阻塞式,则可以这么用 // 否则,还需要考虑其他解决方式。 qLogx()<<this->m_uri<<host<<path<<port; qLogx()<<"Before libwss clint connect..."<<QDateTime::currentDateTime(); this->m_wsi = libwebsocket_client_connect(this->m_lws_ctx, host.toAscii().data(), port, ssl_mode, path.toAscii().data(), host.toAscii().data(), host.toAscii().data(), vopp_client_protocols[0].name, -1); // this->m_wsi = libwebsocket_client_connect(this->m_lws_ctx, host.toAscii().data(), port, 0, // path.toAscii().data(), // host.toAscii().data(), host.toAscii().data(), // vopp_client_protocols[0].name, -1); if (this->m_wsi == NULL) { qLogx()<<"libwebsocket dumb connect failed."; return false; } // here the conn state is 4, but when run to CALLBACK_ESTABLISH, the state will be 3 ok qLogx()<<"After libwss client connect..."<<QDateTime::currentDateTime() <<libwebsockets_remaining_packet_payload(this->m_wsi) <<libwebsocket_get_socket_fd(this->m_wsi) <<libwebsocket_get_connect_state(this->m_wsi); qLogx()<<"client wsi:"<<this->m_wsi; if (libwebsocket_client_is_connected(this->m_wsi)) { break; } else { break; this->m_wsi = NULL; qLogx()<<"Invalid client wsi state, retry.. "<<conn_retry; if (conn_retry == 0) { Q_ASSERT(1==2); return false; } } } return true; }
static int websocketCallback(struct libwebsocket_context *context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { switch (reason) { case LWS_CALLBACK_ESTABLISHED: { // TODO: should be earlier? int fd = libwebsocket_get_socket_fd(wsi); struct sockaddr sadr; memset(&sadr, 0, sizeof(sadr)); socklen_t len = sizeof(sadr); int retval = getpeername(fd, &sadr, &len); if (retval < 0) { Com_Printf("getpeername failed: %s (%d)\n", LOG_NET, strerror(errno), errno); return -1; } STUBBED("FIXME: bad macro shit"); netadr_t addr; netadr_t *temp = &addr; SockadrToNetadr(&sadr, temp); auto it = wsState->connections.find(addr); if (it != wsState->connections.end()) { // must not exist yet Com_Printf("ERROR: New connection from \"%s\" but it already exists", LOG_NET, NET_AdrToString(&addr)); return -1; } std::unique_ptr<Connection> conn(new Connection(addr, wsi)); conn->setReadyState(Open); wsState->wsiLookup.emplace(wsi, conn.get()); bool success = false; std::tie(it, success) = wsState->connections.emplace(addr, std::move(conn)); assert(success); // it wasn't there before so this can't fail libwebsocket_callback_on_writable(wsState->websocketContext, wsi); } break; case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: Com_Printf("websocketCallback LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH\n", LOG_NET); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: { auto wsiIt = wsState->wsiLookup.find(wsi); if (wsiIt == wsState->wsiLookup.end()) { Com_Printf("ERROR: Established on connection we don't know\n", LOG_NET); return -1; } Connection *conn = wsiIt->second; assert(conn->wsi == wsi); assert(conn->readyState == Connecting); conn->setReadyState(Open); libwebsocket_callback_on_writable(wsState->websocketContext, wsi); } break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: case LWS_CALLBACK_CLOSED: { assert(wsi != NULL); auto wsiIt = wsState->wsiLookup.find(wsi); if (wsiIt == wsState->wsiLookup.end()) { Com_Printf("ERROR: Close on connection we don't know\n", LOG_NET); return -1; } Connection *conn = wsiIt->second; assert(conn->wsi == wsi); assert(conn->readyState != Closed); conn->setReadyState(Closed); netadr_t addr = conn->addr; auto connIt = wsState->connections.find(addr); // it must be there assert(connIt != wsState->connections.end()); assert(conn == connIt->second.get()); bool hasDataRemaining = !conn->recvBuffer.empty(); if (hasDataRemaining) { // if there's data remaining it must also be in pendingData assert(wsState->pendingData.find(conn) != wsState->pendingData.end()); } Com_Printf("Disconnecting from %s\n", LOG_NET, NET_AdrToString(&addr)); wsState->connections.erase(connIt); // Connection destructor should have removed this wsiIt = wsState->wsiLookup.find(wsi); assert(wsiIt == wsState->wsiLookup.end()); if (hasDataRemaining) { // if it was in pendingData the destructor must have removed it assert(wsState->pendingData.find(conn) == wsState->pendingData.end()); } } break; case LWS_CALLBACK_RECEIVE: case LWS_CALLBACK_CLIENT_RECEIVE: { assert(wsi != NULL); Connection *conn = wsState->findConnection(wsi); if (!conn) { Com_Printf("ERROR: Receive on connection we don't know\n", LOG_NET); return -1; } assert(conn->readyState == Open); bool alreadyHasData = !conn->recvBuffer.empty(); if (alreadyHasData) { // if there's data already in the buffer the connection must also be in pendingData assert(wsState->pendingData.find(conn) != wsState->pendingData.end()); } assert(conn->wsi == wsi); const char *buf = reinterpret_cast<char *>(in); conn->recvBuffer.insert(conn->recvBuffer.end(), buf, buf + len); if (!alreadyHasData) { wsState->pendingData.insert(conn); } } break; case LWS_CALLBACK_CLIENT_WRITEABLE: case LWS_CALLBACK_SERVER_WRITEABLE: { assert(wsi != NULL); Connection *conn = wsState->findConnection(wsi); if (!conn) { Com_Printf("ERROR: Writable on connection we don't know\n", LOG_NET); return -1; } assert(conn->wsi == wsi); if (conn->readyState == Closed || conn->readyState == Closing) { // game has closed, close the actual connection return -1; } conn->writable = true; } break; case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: Com_Printf("websocketCallback LWS_CALLBACK_FILTER_NETWORK_CONNECTION\n", LOG_NET); break; case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED: Com_Printf("websocketCallback LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED\n", LOG_NET); break; case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: Com_Printf("websocketCallback LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION\n", LOG_NET); break; case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: Com_Printf("websocketCallback LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER\n", LOG_NET); break; case LWS_CALLBACK_PROTOCOL_INIT: // ignored break; case LWS_CALLBACK_PROTOCOL_DESTROY: // ignored break; case LWS_CALLBACK_WSI_CREATE: Com_Printf("websocketCallback LWS_CALLBACK_WSI_CREATE\n", LOG_NET); break; case LWS_CALLBACK_WSI_DESTROY: Com_Printf("websocketCallback LWS_CALLBACK_WSI_DESTROY\n", LOG_NET); break; case LWS_CALLBACK_GET_THREAD_ID: // ignored break; case LWS_CALLBACK_ADD_POLL_FD: // ignored break; case LWS_CALLBACK_DEL_POLL_FD: // ignored break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: // ignored break; case LWS_CALLBACK_LOCK_POLL: // ignored break; case LWS_CALLBACK_UNLOCK_POLL: // ignored break; default: Com_Printf ("websocketCallback reason %d\n", LOG_NET, reason); break; } return 0; }
int EchoDataWebSocket::callback_dumb_increment(struct libwebsocket_context * context, struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { #ifdef DEBUG_WEBSERVER fprintf(stderr, "callback Data websocket, fd: %d, reason: %s\n", libwebsocket_get_socket_fd(wsi), ServerConstants::getCallbackReasonText(reason)); #endif int n; //unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + // LWS_SEND_BUFFER_POST_PADDING]; //unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING]; struct sessionDataProtocol_1 *pss = (sessionDataProtocol_1 *)user; switch (reason) { case LWS_CALLBACK_ESTABLISHED: #ifdef DEBUG_WEBSERVER fprintf(stdout, "********Data websocket established\n"); #endif break; /* * in this protocol, we just use the broadcast action as the chance to * send our own connection-specific data and ignore the broadcast info * that is available in the 'in' parameter */ case LWS_CALLBACK_BROADCAST: #ifdef DEBUG_WEBSERVER fprintf(stdout, "********Data websocket LWS_CALLBACK_BROADCAST\n"); #endif n = libwebsocket_write(wsi, &broadcastEchoMsg[LWS_SEND_BUFFER_PRE_PADDING], broadcastEchoLength, LWS_WRITE_TEXT); #ifdef DEBUG_WEBSERVER fprintf(stdout, "** END **Data websocket LWS_CALLBACK_BROADCAST, length: %d\n", broadcastEchoLength); #endif break; case LWS_CALLBACK_RECEIVE: #ifdef DEBUG_WEBSERVER fprintf(stdout, "Data websocket LWS_CALLBACK_RECEIVE\n"); #endif fprintf(stderr, "rx %d\n", (int)len); if (len < 6) break; if (strcmp((char*)in, "reset\n") == 0) pss->number = 0; break; /* * this just demonstrates how to use the protocol filter. If you won't * study and reject connections based on header content, you don't need * to handle this callback */ case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: //dump_handshake_info((struct lws_tokens *)(long)user); /* you could return non-zero here and kill the connection */ break; default: #ifdef DEBUG_WEBSERVER fprintf(stderr, "!!! callback Data websocket, default case? Reason %d**********\n", (int)reason); #endif break; } return 0; }