int websocket_server_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { websocket_user_info *info = (websocket_user_info *)user; switch (reason) { case LWS_CALLBACK_ESTABLISHED: // just log message that someone is connecting { info->conn = std::make_shared<websocket_connection>(wsi); websocket_server *server = (websocket_server *)lws_context_user(info->context); info->conn->set_world(server->world()); server->add_websocket(info->conn); info->conn->show_welcome(); lws_callback_on_writable(wsi); break; } case LWS_CALLBACK_RECEIVE: // the funny part { info->conn->buffered_writer::writeln(); info->conn->process_input((char *)in); lws_callback_on_writable(wsi); break; } case LWS_CALLBACK_SERVER_WRITEABLE: { info->conn->show_prompt(); info->conn->write_from_buffer(); break; } default: break; } return 0; }
static int unreal_networking_server ( struct lws *Wsi, enum lws_callback_reasons Reason, void *User, void *In, size_t Len ) { struct lws_context *Context = lws_get_context(Wsi); PerSessionDataServer* BufferInfo = (PerSessionDataServer*)User; FWebSocketServer* Server = (FWebSocketServer*)lws_context_user(Context); if (!Server->IsAlive) { return 0; } switch (Reason) { case LWS_CALLBACK_ESTABLISHED: { BufferInfo->Socket = new FWebSocket(Context, Wsi); Server->ConnectedCallBack.ExecuteIfBound(BufferInfo->Socket); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); } break; case LWS_CALLBACK_RECEIVE: { BufferInfo->Socket->OnRawRecieve(In, Len); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); } break; case LWS_CALLBACK_SERVER_WRITEABLE: { BufferInfo->Socket->OnRawWebSocketWritable(Wsi); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); } break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { BufferInfo->Socket->ErrorCallBack.ExecuteIfBound(); } break; case LWS_CALLBACK_WSI_DESTROY: case LWS_CALLBACK_PROTOCOL_DESTROY: case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED_HTTP: { Server->IsAlive = false; } break; } return 0; }
bool FJavascriptWebSocketServer::Init(uint32 Port, FJavascriptWebSocketClientConnectedCallBack CallBack) { // setup log level. #if !UE_BUILD_SHIPPING lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_DEBUG | LLL_INFO, lws_debugLog_JS); #endif Protocols = new lws_protocols[3]; FMemory::Memzero(Protocols, sizeof(lws_protocols) * 3); Protocols[0].name = "binary"; Protocols[0].callback = [](lws *Wsi, lws_callback_reasons Reason, void *User, void *In, size_t Len) { auto context = lws_get_context(Wsi); return reinterpret_cast<FJavascriptWebSocketServer*>(lws_context_user(context))->unreal_networking_server(Wsi, Reason, User, In, Len); }; Protocols[0].per_session_data_size = sizeof(PerSessionDataServer); Protocols[0].rx_buffer_size = 10 * 1024 * 1024; Protocols[1].name = nullptr; Protocols[1].callback = nullptr; Protocols[1].per_session_data_size = 0; struct lws_context_creation_info Info; memset(&Info, 0, sizeof(lws_context_creation_info)); // look up libwebsockets.h for details. Info.port = Port; ServerPort = Port; // we listen on all available interfaces. Info.iface = NULL; Info.protocols = &Protocols[0]; // no extensions Info.extensions = NULL; Info.gid = -1; Info.uid = -1; Info.options = 0; // tack on this object. Info.user = this; Info.port = Port; Context = lws_create_context(&Info); if (Context == NULL) { ServerPort = 0; delete Protocols; Protocols = NULL; IsAlive = false; return false; // couldn't create a server. } ConnectedCallBack = CallBack; IsAlive = true; return true; }
static int unreal_networking_client( struct lws *Wsi, enum lws_callback_reasons Reason, void *User, void *In, size_t Len) { struct lws_context *Context = lws_get_context(Wsi); FWebSocket* Socket = (FWebSocket*)lws_context_user(Context); switch (Reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: { Socket->ConnectedCallBack.Broadcast(); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); check(Socket->Wsi == Wsi); } break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { Socket->ErrorCallBack.Broadcast(); return -1; } break; case LWS_CALLBACK_CLIENT_RECEIVE: { // push it on the socket. Socket->OnRawRecieve(In, (uint32)Len, !!lws_frame_is_binary(Wsi)); check(Socket->Wsi == Wsi); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); break; } case LWS_CALLBACK_CLIENT_WRITEABLE: { check(Socket->Wsi == Wsi); Socket->OnRawWebSocketWritable(Wsi); lws_callback_on_writable(Wsi); lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 0); break; } case LWS_CALLBACK_CLOSED: { Socket->ErrorCallBack.Broadcast(); return -1; } } return 0; }
int callback(clws::lws *wsi, clws::lws_callback_reasons reason, void *user, void *in, size_t len) { lws::ServerInternals *serverInternals = (lws::ServerInternals *) lws_context_user(lws_get_context(wsi)); SocketExtension *ext = (SocketExtension *) user; switch (reason) { case clws::LWS_CALLBACK_SERVER_WRITEABLE: { SocketExtension::Message &message = ext->messages.front(); lws_write(wsi, (unsigned char *) message.buffer + LWS_SEND_BUFFER_PRE_PADDING, message.length, message.binary ? clws::LWS_WRITE_BINARY : clws::LWS_WRITE_TEXT); if (message.owned) { delete [] message.buffer; } ext->messages.pop(); if (!ext->messages.empty()) { lws_callback_on_writable(wsi); } break; } case clws::LWS_CALLBACK_ESTABLISHED: { new (&ext->messages) queue<SocketExtension::Message>; serverInternals->connectionCallback({wsi, ext}); break; } case clws::LWS_CALLBACK_CLOSED: { while (!ext->messages.empty()) { delete [] ext->messages.front().buffer; ext->messages.pop(); } ext->messages.~queue<SocketExtension::Message>(); serverInternals->disconnectionCallback({wsi, ext}); break; } case clws::LWS_CALLBACK_RECEIVE: { serverInternals->messageCallback({wsi, ext}, std::string((char *) in, len)); break; } default: break; } return 0; }
// callback. int FJavascriptWebSocketServer::unreal_networking_server(lws *InWsi, lws_callback_reasons Reason, void* User, void *In, size_t Len) { struct lws_context *LwsContext = lws_get_context(InWsi); PerSessionDataServer* BufferInfo = (PerSessionDataServer*)User; FJavascriptWebSocketServer* Server = (FJavascriptWebSocketServer*)lws_context_user(LwsContext); if (!Server->IsAlive) { return 0; } switch (Reason) { case LWS_CALLBACK_ESTABLISHED: { BufferInfo->Socket = new FJavascriptWebSocket(LwsContext, InWsi); ConnectedCallBack.ExecuteIfBound(BufferInfo->Socket); lws_set_timeout(InWsi, NO_PENDING_TIMEOUT, 0); } break; case LWS_CALLBACK_RECEIVE: { BufferInfo->Socket->OnRawRecieve(In, Len); lws_set_timeout(InWsi, NO_PENDING_TIMEOUT, 0); } break; case LWS_CALLBACK_SERVER_WRITEABLE: if (BufferInfo->Socket->Context == LwsContext) // UE-68340 -- bandaid until this file is removed in favor of using LwsWebSocketsManager.cpp & LwsWebSocket.cpp { BufferInfo->Socket->OnRawWebSocketWritable(InWsi); } lws_set_timeout(InWsi, NO_PENDING_TIMEOUT, 0); break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { BufferInfo->Socket->ErrorCallBack.ExecuteIfBound(); } break; case LWS_CALLBACK_WSI_DESTROY: case LWS_CALLBACK_PROTOCOL_DESTROY: case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED_HTTP: break; } return 0; }
// This static function handles all callbacks coming in and when context is services via lws_service // return value of -1, closes the connection. int FNetworkFileServerHttp::CallBack_HTTP( struct lws *Wsi, enum lws_callback_reasons Reason, void *User, void *In, size_t Len) { struct lws_context *Context = lws_get_context(Wsi); PerSessionData* BufferInfo = (PerSessionData*)User; FNetworkFileServerHttp* Server = (FNetworkFileServerHttp*)lws_context_user(Context); switch (Reason) { case LWS_CALLBACK_HTTP: // hang on to socket even if there's no data for atleast 60 secs. lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 60); /* if it was not legal POST URL, let it continue and accept data */ if (!lws_hdr_total_length(Wsi, WSI_TOKEN_POST_URI)) { char *requested_uri = (char *) In; // client request the base page. e.g http://unrealfileserver:port/ // just return a banner, probably add some more information, e,g Version, Config, Game. etc. if ( FCString::Strcmp(ANSI_TO_TCHAR(requested_uri), TEXT("/")) == 0 ) { TCHAR Buffer[1024]; TCHAR ServerBanner[] = TEXT("<HTML>This is Unreal File Server</HTML>"); int x = FCString::Sprintf( Buffer, TEXT("HTTP/1.0 200 OK\x0d\x0a") TEXT("Server: Unreal File Server\x0d\x0a") TEXT("Connection: close\x0d\x0a") TEXT("Content-Type: text/html; charset=utf-8\x0d\x0a") TEXT("Content-Length: %u\x0d\x0a\x0d\x0a%s"), FCString::Strlen(ServerBanner), ServerBanner ); // very small data being sent, its fine to just send. lws_write(Wsi,(unsigned char*)TCHAR_TO_ANSI(Buffer),FCStringAnsi::Strlen(TCHAR_TO_ANSI(Buffer)), LWS_WRITE_HTTP); } else { // client has asked for a file. ( only html/js files are served.) // what type is being served. FString FilePath = FPaths::GameDir() / TEXT("Binaries/HTML5") + FString((ANSICHAR*)In); TCHAR Mime[512]; if ( FilePath.Contains(".js")) { FCStringWide::Strcpy(Mime,TEXT("application/javascript;charset=UTF-8")); } else { FCStringWide::Strcpy(Mime,TEXT("text/html;charset=UTF-8")); } UE_LOG(LogFileServer, Warning, TEXT("HTTP Serving file %s with mime %s "), *FilePath, (Mime)); FString AbsoluteFilePath = FPaths::ConvertRelativePathToFull(FilePath); AbsoluteFilePath.ReplaceInline(TEXT("/"),TEXT("\\")); // we are going to read the complete file in memory and then serve it in batches. // rather than reading and sending in batches because Unreal NFS servers are not running in memory // constrained env and the added complexity is not worth it. TArray<uint8> FileData; FFileHelper::LoadFileToArray(FileData, *AbsoluteFilePath, FILEREAD_Silent); if (FileData.Num() == 0) { // umm. we didn't find file, we should tell the client that we couldn't find it. // send 404. char Header[]= "HTTP/1.1 404 Not Found\x0d\x0a" "Server: Unreal File Server\x0d\x0a" "Connection: close\x0d\x0a"; lws_write(Wsi,(unsigned char*)Header,FCStringAnsi::Strlen(Header), LWS_WRITE_HTTP); // chug along, client will close the connection. break; } // file up the header. TCHAR Header[1024]; int Length = 0; if (FilePath.Contains("gz")) { Length = FCString::Sprintf(Header, TEXT("HTTP/1.1 200 OK\x0d\x0a") TEXT("Server: Unreal File Server\x0d\x0a") TEXT("Connection: close\x0d\x0a") TEXT("Content-Type: %s \x0d\x0a") TEXT("Content-Encoding: gzip\x0d\x0a") TEXT("Content-Length: %u\x0d\x0a\x0d\x0a"), Mime, FileData.Num()); } else { Length = FCString::Sprintf(Header, TEXT("HTTP/1.1 200 OK\x0d\x0a") TEXT("Server: Unreal File Server\x0d\x0a") TEXT("Connection: close\x0d\x0a") TEXT("Content-Type: %s \x0d\x0a") TEXT("Content-Length: %u\x0d\x0a\x0d\x0a"), Mime, FileData.Num()); } // make space for the whole file in our out buffer. BufferInfo->Out.Append((uint8*)TCHAR_TO_ANSI(Header),Length); BufferInfo->Out.Append(FileData); // we need to write back to the client, queue up a write callback. lws_callback_on_writable(Wsi); } } else { // we got a post request!, queue up a write callback. lws_callback_on_writable(Wsi); } break; case LWS_CALLBACK_HTTP_BODY: { // post data is coming in, push it on to our incoming buffer. UE_LOG(LogFileServer, Log, TEXT("Incoming HTTP Partial Body Size %d, total size %d"),Len, Len+ BufferInfo->In.Num()); BufferInfo->In.Append((uint8*)In,Len); // we received some data - update time out. lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 60); } break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: { // we have all the post data from the client. // create archives and process them. UE_LOG(LogFileServer, Log, TEXT("Incoming HTTP total size %d"), BufferInfo->In.Num()); FMemoryReader Reader(BufferInfo->In); TArray<uint8> Writer; FNetworkFileServerHttp::Process(Reader,Writer,Server); // even if we have 0 data to push, tell the client that we don't any data. ANSICHAR Header[1024]; int Length = FCStringAnsi::Sprintf( (ANSICHAR*)Header, "HTTP/1.1 200 OK\x0d\x0a" "Server: Unreal File Server\x0d\x0a" "Connection: close\x0d\x0a" "Content-Type: application/octet-stream \x0d\x0a" "Content-Length: %u\x0d\x0a\x0d\x0a", Writer.Num() ); // Add Http Header BufferInfo->Out.Append((uint8*)Header,Length); // Add Binary Data. BufferInfo->Out.Append(Writer); // we have enqueued data increase timeout and push a writable callback. lws_set_timeout(Wsi, NO_PENDING_TIMEOUT, 60); lws_callback_on_writable(Wsi); } break; case LWS_CALLBACK_CLOSED_HTTP: // client went away or //clean up. BufferInfo->In.Empty(); BufferInfo->Out.Empty(); break; case LWS_CALLBACK_PROTOCOL_DESTROY: // we are going away. break; case LWS_CALLBACK_HTTP_WRITEABLE: // get rid of superfluous write callbacks. if ( BufferInfo == NULL ) break; // we have data o send out. if (BufferInfo->Out.Num()) { int SentSize = lws_write(Wsi,(unsigned char*)BufferInfo->Out.GetData(),BufferInfo->Out.Num(), LWS_WRITE_HTTP); // get rid of the data that has been sent. BufferInfo->Out.RemoveAt(0,SentSize); } break; default: break; } return 0; }
int WebSocketTcpServer::__callback_websocket__(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { if ( nullptr == m_context ) return 0; WebSocketTcpServer *server = static_cast<WebSocketTcpServer*>(lws_context_user(m_context)); if ( server->m_run_thread == false ) return 0; switch ( reason ) { case LWS_CALLBACK_WSI_CREATE: break; case LWS_CALLBACK_ESTABLISHED: { LOG_DEBUG("LWS_CALLBACK_ESTABLISHED \n"); string protocol = server->__getProtocolFromHeader__(wsi); LOG_DEBUG("user : %s \n", protocol.data()); int client_fd = lws_get_socket_fd(wsi); struct sockaddr_in clientaddr; socklen_t peeraddrlen = sizeof(clientaddr); if ( 0 > getpeername(client_fd, (struct sockaddr*)&clientaddr, &peeraddrlen) ) { perror("getpeername error "); } size_t client_id = server->addClientInfo(ClientInfoPtr( new WebSocketTcpClientInfo(client_fd, &clientaddr, wsi, protocol))); NOTIFY_CLIENT_CONNECTED(server->m_server_id, client_id); } break; case LWS_CALLBACK_RECEIVE: LOG_DEBUG("LWS_CALLBACK_RECEIVE \n"); { LOG_DEBUG("received data: %s\n", (char *) in); int client_fd = lws_get_socket_fd(wsi); auto client = static_pointer_cast<WebSocketTcpClientInfo>(server->findClientInfo(client_fd)); NOTIFY_SERVER_RECEIVED_FROM_PROTOCOL( server->m_server_id, client->getClientId(), (char*)in, len, client->getProtocol()); } break; case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: LOG_DEBUG("LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION \n"); break; case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: LOG_DEBUG("LWS_CALLBACK_WS_PEER_INITIATED_CLOSE \n"); break; case LWS_CALLBACK_CLOSED: LOG_DEBUG("LWS_CALLBACK_CLOSED \n"); { int client_fd = lws_get_socket_fd(wsi); size_t client_id = server->removeClientInfo(client_fd); NOTIFY_CLIENT_DISCONNECTED(server->m_server_id, client_id); } break; case LWS_CALLBACK_PROTOCOL_INIT: LOG_DEBUG("LWS_CALLBACK_PROTOCOL_INIT \n"); break; case LWS_CALLBACK_PROTOCOL_DESTROY: LOG_DEBUG("LWS_CALLBACK_PROTOCOL_DESTROY \n"); break; case LWS_CALLBACK_GET_THREAD_ID: /* to be silent */ break; case LWS_CALLBACK_DEL_POLL_FD: LOG_DEBUG("LWS_CALLBACK_DEL_POLL_FD \n"); { int client_fd = lws_get_socket_fd(wsi); size_t client_id = server->removeClientInfo(client_fd); NOTIFY_CLIENT_DISCONNECTED(server->m_server_id, client_id); } break; default: LOG_WARNING("Unhandled callback reason [%d] \n", reason); break; } return 0; }
static int callback_http(struct libwebsocket_context *context, #endif struct libwebsocket *wsi, enum libwebsocket_callback_reasons reason, void *user, void *in, size_t len) { struct libws_http_data *u = (struct libws_http_data *)user; struct libws_mqtt_hack *hack; char *http_dir; size_t buflen; size_t wlen; char *filename_canonical; unsigned char buf[4096]; struct stat filestat; struct mosquitto_db *db = &int_db; struct mosquitto *mosq; struct lws_pollargs *pollargs = (struct lws_pollargs *)in; /* FIXME - ssl cert verification is done here. */ switch (reason) { case LWS_CALLBACK_HTTP: if(!u){ return -1; } #if defined(LWS_LIBRARY_VERSION_NUMBER) hack = (struct libws_mqtt_hack *)lws_context_user(lws_get_context(wsi)); #else hack = (struct libws_mqtt_hack *)libwebsocket_context_user(context); #endif if(!hack){ return -1; } http_dir = hack->http_dir; if(!http_dir){ /* http disabled */ return -1; } /* Forbid POST */ if(lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_METHOD_NOT_ALLOWED, NULL); return -1; } #if defined(LWS_LIBRARY_VERSION_NUMBER) filename_canonical = http__canonical_filename(wsi, (char *)in, http_dir); #else filename_canonical = http__canonical_filename(context, wsi, (char *)in, http_dir); #endif if(!filename_canonical) return -1; u->fptr = fopen(filename_canonical, "rb"); if(!u->fptr){ free(filename_canonical); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_NOT_FOUND, NULL); return -1; } if(fstat(fileno(u->fptr), &filestat) < 0){ free(filename_canonical); libwebsockets_return_http_status(context, wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL); fclose(u->fptr); u->fptr = NULL; return -1; } if((filestat.st_mode & S_IFDIR) == S_IFDIR){ fclose(u->fptr); u->fptr = NULL; free(filename_canonical); /* FIXME - use header functions from lws 2.x */ buflen = snprintf((char *)buf, 4096, "HTTP/1.0 302 OK\r\n" "Location: %s/\r\n\r\n", (char *)in); return libwebsocket_write(wsi, buf, buflen, LWS_WRITE_HTTP); } if((filestat.st_mode & S_IFREG) != S_IFREG){ libwebsockets_return_http_status(context, wsi, HTTP_STATUS_FORBIDDEN, NULL); fclose(u->fptr); u->fptr = NULL; free(filename_canonical); return -1; } log__printf(NULL, MOSQ_LOG_DEBUG, "http serving file \"%s\".", filename_canonical); free(filename_canonical); /* FIXME - use header functions from lws 2.x */ buflen = snprintf((char *)buf, 4096, "HTTP/1.0 200 OK\r\n" "Server: mosquitto\r\n" "Content-Length: %u\r\n\r\n", (unsigned int)filestat.st_size); if(libwebsocket_write(wsi, buf, buflen, LWS_WRITE_HTTP) < 0){ fclose(u->fptr); u->fptr = NULL; return -1; } libwebsocket_callback_on_writable(context, wsi); break; case LWS_CALLBACK_HTTP_BODY: /* For extra POST data? */ return -1; case LWS_CALLBACK_HTTP_BODY_COMPLETION: /* For end of extra POST data? */ return -1; case LWS_CALLBACK_FILTER_HTTP_CONNECTION: /* Access control here */ return 0; case LWS_CALLBACK_HTTP_WRITEABLE: /* Send our data here */ if(u && u->fptr){ do{ buflen = fread(buf, 1, sizeof(buf), u->fptr); if(buflen < 1){ fclose(u->fptr); u->fptr = NULL; return -1; } wlen = libwebsocket_write(wsi, buf, buflen, LWS_WRITE_HTTP); if(wlen < buflen){ if(fseek(u->fptr, buflen-wlen, SEEK_CUR) < 0){ fclose(u->fptr); u->fptr = NULL; return -1; } }else{ if(buflen < sizeof(buf)){ fclose(u->fptr); u->fptr = NULL; } } }while(u->fptr && !lws_send_pipe_choked(wsi)); libwebsocket_callback_on_writable(context, wsi); }else{ return -1; } break; case LWS_CALLBACK_CLOSED: case LWS_CALLBACK_CLOSED_HTTP: case LWS_CALLBACK_HTTP_FILE_COMPLETION: if(u && u->fptr){ fclose(u->fptr); u->fptr = NULL; } break; case LWS_CALLBACK_ADD_POLL_FD: case LWS_CALLBACK_DEL_POLL_FD: case LWS_CALLBACK_CHANGE_MODE_POLL_FD: HASH_FIND(hh_sock, db->contexts_by_sock, &pollargs->fd, sizeof(pollargs->fd), mosq); if(mosq && (pollargs->events & POLLOUT)){ mosq->ws_want_write = true; } break; #ifdef WITH_TLS case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if(!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)){ return 1; } break; #endif default: return 0; } return 0; }
static int discord_ws_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct im_connection *ic = NULL; discord_data *dd = NULL; if (wsi == NULL) { return 0; } struct lws_context *wsctx = lws_get_context(wsi); if (wsctx != NULL) { ic = lws_context_user(wsctx); dd = ic->proto_data; } switch(reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: dd->state = WS_CONNECTED; lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: imcb_error(ic, "Websocket connection error"); if (in != NULL) { imcb_error(ic, in); } b_event_remove(dd->keepalive_loop_id); dd->keepalive_loop_id = 0; dd->state = WS_CLOSING; break; case LWS_CALLBACK_CLIENT_WRITEABLE: if (dd->state == WS_CONNECTED) { GString *buf = g_string_new(""); g_string_printf(buf, "{\"d\":{\"v\":3,\"token\":\"%s\",\"properties\":{\"$referring_domain\":\"\",\"$browser\":\"bitlbee-discord\",\"$device\":\"bitlbee\",\"$referrer\":\"\",\"$os\":\"linux\"}},\"op\":2}", dd->token); discord_ws_send_payload(wsi, buf->str, buf->len); g_string_free(buf, TRUE); } else if (dd->state == WS_READY) { GString *buf = g_string_new(""); g_string_printf(buf, "{\"op\":1,\"d\":%tu}", time(NULL)); discord_ws_send_payload(dd->lws, buf->str, buf->len); g_string_free(buf, TRUE); } else { g_print("%s: Unhandled writable callback\n", __func__); } break; case LWS_CALLBACK_CLIENT_RECEIVE: { size_t rpload = lws_remaining_packet_payload(wsi); if (dd->ws_buf == NULL) { dd->ws_buf = g_string_new(""); } dd->ws_buf = g_string_append(dd->ws_buf, in); if (rpload == 0) { discord_parse_message(ic); g_string_free(dd->ws_buf, TRUE); dd->ws_buf = NULL; } break; } case LWS_CALLBACK_CLOSED: b_event_remove(dd->keepalive_loop_id); dd->keepalive_loop_id = 0; dd->state = WS_CLOSING; lws_cancel_service(dd->lwsctx); break; case LWS_CALLBACK_ADD_POLL_FD: { struct lws_pollargs *pargs = in; dd->main_loop_id = b_input_add(pargs->fd, B_EV_IO_READ, discord_ws_service_loop, ic); break; } case LWS_CALLBACK_DEL_POLL_FD: b_event_remove(dd->main_loop_id); break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: { struct lws_pollargs *pargs = in; int flags = 0; b_event_remove(dd->main_loop_id); if (pargs->events & POLLIN) { flags |= B_EV_IO_READ; } if (pargs->events & POLLOUT) { flags |= B_EV_IO_WRITE; } dd->main_loop_id = b_input_add(pargs->fd, flags, discord_ws_service_loop, ic); break; } case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: case LWS_CALLBACK_GET_THREAD_ID: case LWS_CALLBACK_LOCK_POLL: case LWS_CALLBACK_UNLOCK_POLL: case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: case LWS_CALLBACK_PROTOCOL_INIT: case LWS_CALLBACK_PROTOCOL_DESTROY: case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: case LWS_CALLBACK_WSI_CREATE: case LWS_CALLBACK_WSI_DESTROY: // Ignoring these, this block should be removed when defult is set to // stay silent. break; default: g_print("%s: unknown rsn=%d\n", __func__, reason); break; } return 0; }
LWS_VISIBLE LWS_EXTERN void * libwebsocket_context_user(struct lws_context *context) { return lws_context_user(context); }
int callback_socket_io(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { char *buff; char *write_buff; size_t msgLen = 0; socket_io_msg *msg = NULL; struct lws_context *context = lws_get_context(wsi); socket_io_handler *handle =lws_context_user(context); char *ping_msg = "2"; switch(reason){ case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: handle->status = CONN_ERROR; LOG("connection error "); break; case LWS_CALLBACK_CLIENT_ESTABLISHED: handle->status = CONN_CONNECTED; LOG( "Connection Established "); break; case LWS_CALLBACK_CLIENT_RECEIVE: LOG( "There is something to recieve"); break; case LWS_CALLBACK_CLIENT_WRITEABLE: LOG( "if u want u can write "); // get msg from queue msg = socket_io_get_msg(handle); if(msg != NULL){ // convert it into protocol msg socket_io_convert_to_protocol_msg(msg, &buff, &msgLen); if(msgLen){ // libwebsocket require extra pre and post buffer to put header and trailar in place write_buff = malloc(msgLen + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING); memcpy((write_buff + LWS_SEND_BUFFER_PRE_PADDING), buff, msgLen); lws_write(wsi, (write_buff + LWS_SEND_BUFFER_PRE_PADDING), msgLen, LWS_WRITE_TEXT); free(write_buff); free(buff); handle->last_ping = time(NULL); } } if((time(NULL) - handle->last_ping) > PING_INTERVAL){ //fprintf(stderr, "Sending Ping packet\n"); write_buff = malloc(strlen(ping_msg) + LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING); memcpy((write_buff + LWS_SEND_BUFFER_PRE_PADDING), ping_msg, strlen(ping_msg)); lws_write(wsi, (write_buff + LWS_SEND_BUFFER_PRE_PADDING), strlen(ping_msg), LWS_WRITE_TEXT); free(write_buff); handle->last_ping = time(NULL); } break; case LWS_CALLBACK_CLOSED: handle->status = CONN_CLOSE; LOG( "connection closed"); break; } return 0; }
static int ws_events_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct lws_context *context = lws_get_context(wsi); ws_t *ws = lws_context_user(context); struct per_session_data__events *pss = user; int i; switch (reason) { case LWS_CALLBACK_ESTABLISHED: pss->ws = ws; pss->cmd = command_new((command_handler_t) ws_events_command, pss); buf_init(&pss->out_buf); pss->id = ws_session_add(ws, pss); log_debug(2, "ws_events_callback LWS_CALLBACK_ESTABLISHED [%04X]", pss->id); break; case LWS_CALLBACK_SERVER_WRITEABLE: i = pss->out_buf.len - LWS_SEND_BUFFER_PRE_PADDING; if (i > 0) { log_debug(2, "ws_events_callback LWS_CALLBACK_SERVER_WRITEABLE [%04X]: %d bytes", pss->id, i); buf_grow(&pss->out_buf, LWS_SEND_BUFFER_POST_PADDING); int ret = lws_write(wsi, pss->out_buf.base+LWS_SEND_BUFFER_PRE_PADDING, i, LWS_WRITE_TEXT); pss->out_buf.len = 0; if (ret < i) { log_str("HTTP ERROR: %d writing to event websocket", ret); return -1; } } else { log_debug(2, "ws_events_callback LWS_CALLBACK_SERVER_WRITEABLE [%04X]: READY", pss->id); } break; case LWS_CALLBACK_RECEIVE: log_debug(2, "ws_events_callback LWS_CALLBACK_RECEIVE [%04X]: %d bytes", pss->id, len); log_debug_data(in, len); /* Make sure send buffer has room for pre-padding */ if (pss->out_buf.len == 0) { buf_append_zero(&pss->out_buf, LWS_SEND_BUFFER_PRE_PADDING); } /* Execute command */ command_recv(pss->cmd, in, len); /* Trig response write */ lws_callback_on_writable(wsi); break; case LWS_CALLBACK_CLOSED: log_debug(2, "ws_events_callback LWS_CALLBACK_CLOSED [%04X]", pss->id); pss->ws = NULL; if (pss->cmd != NULL) { command_destroy(pss->cmd); pss->cmd = NULL; } buf_cleanup(&pss->out_buf); pss->id = -1; ws_session_remove(ws, pss); 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: log_debug(2, "ws_events_callback LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION [%04X]", pss->id); ws_dump_handshake_info(wsi); /* you could return non-zero here and kill the connection */ // return -1; break; case LWS_CALLBACK_PROTOCOL_INIT: log_debug(2, "ws_events_callback LWS_CALLBACK_PROTOCOL_INIT"); break; default: log_debug(2, "ws_events_callback: reason=%d", reason); break; } return 0; }