Example #1
0
        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;
        }
Example #2
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; 
}
Example #4
0
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;
}
Example #5
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;
}
Example #9
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;
}
Example #11
0
LWS_VISIBLE LWS_EXTERN void *
libwebsocket_context_user(struct lws_context *context)
{
    return lws_context_user(context);
}
Example #12
0
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;
}
Example #13
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;
}