Spring Websocket connection getting closed automatically with reason Invalid reserved bit - websocket

My spring websocket code runs in Liberty server. The code works fine in local. When I move to my server, when I try from 'Simple Websocket Client', I get an error like
WebSocket connection to 'wss://url' failed: One or more reserved bits
are on: reserved1 = 0, reserved2 = 1, reserved3 = 1
On the server side logs, I can see that afterConnectionEstablished method gets triggered, and immediately afterConnectionClosed gets triggered and when I print close status, it gives me
Code 1002 Reason:: Invalid reserved bit.
Am not clear on what this means and what are reasons this could come from.
public class NotificationHandler extends TextWebSocketHandler {
Logger logger = LogManager.getLogger(NotificationHandler.class);
#Override
public void afterConnectionEstablished(WebSocketSession session)
throws IOException {
logger.info("In NotificationHandler, afterConnectionEstablished.. ");
session.sendMessage(new TextMessage("Hello !"));
}
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message) throws IOException {
logger.info("In NotificationHandler, handleTextMessage.. ");
session.sendMessage(new TextMessage("Hello Text Message!"));
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
logger.info("In NotificationHandler, afterConnectionClosed, Code:: "+ status.getCode() + ".. Reason:: " + status.getReason());
}
}
Please let me know if you need more details.

Given the exact wording, that is not a reason code coming from the Liberty Websocket code, so I am guessing it is coming from the Spring code. If you are running on Liberty I would think you would want the system configured to use the Liberty Websocket code and not another provider.

Related

Sending async message from micronaut ServerWebSocket

I am trying to implement simple WebSocket server using Micronaut (and Groovy). I am new to Micronaut, so learning it as I go, and with it some RxJava seems required. So learning that as well.
I can make the basic example work:
#CompileStatic
#ServerWebSocket("/ws")
class TimeseriesWebSocket {
#OnOpen
public Publisher<String> onOpen(WebSocketSession session) {
println("opening connection")
return session.send("Hello")
}
#OnMessage
public Publisher<String> onMessage(String message, WebSocketSession session) {
println("message received")
return session.send("Thanks for the message")
}
#OnClose
public Publisher<String> onClose(WebSocketSession session) {
println("Closing")
//this seems not to be delivered, I guess due to session being closed already
return session.send("OK")
}
}
So this prints out all the messages I put there and works fine with a client connecting. The client also sees the "Hello" and "Thanks for the message" messages that are return with session.send(..).
Now my problem is, I am trying to send a message outside these methods. Like this:
#CompileStatic
#ServerWebSocket("/ws")
class MyWebSocket {
#OnOpen
public Publisher<String> onOpen(WebSocketSession session) {
println("opening connection")
startPing()
return session.send("Hello")
}
//...(same as above)
public void startPing(WebSocketSession session) {
PingPing ping = new PingPing(session)
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
exec.scheduleAtFixedRate(ping, 0, 1, TimeUnit.SECONDS);
}
}
class PingPing {
WebSocketSession session
public PingPing(WebSocketSession session) {
this.session = session
}
#Override
void run() {
println("pinging..")
try {
session.send("Ping...")
} catch (Exception e) {
e.printStackTrace()
}
}
}
This executes but nothing shows up on the client end. Now if I change session.send() to session.sendSync() it works fine. The ping is delivered.
The send() signature is actually
default <T> Publisher<T> send(T message)
I figured at first I should provide the Publisher to some other source to have it sent. But I guess this is not the case. I realized it is sort of a Future object, so if I subscribe to it myself like this:
def publisher = session.send("Ping...")
publisher.subscribe(new Subscriber<GString>() {
#Override
void onSubscribe(Subscription s) {
println("subscription")
}
#Override
void onNext(GString gString) {
println("next")
}
#Override
void onError(Throwable t) {
println("error")
t.printStackTrace()
}
#Override
void onComplete() {
println("complete")
}
})
println("publisher: ${publisher}")
Running the above piece of code (with subscribe), I guess it triggers the session.send() on the current thread and returns a result. But where should I actually call this? On what thread? I looked at the RxJava schedulers but could not quite understand where to call it from.
Further, the result of running the above actually delivers the message to the client, but also throws an error:
error
io.reactivex.exceptions.MissingBackpressureException: create: could not emit value due to lack of requests
at io.reactivex.internal.operators.flowable.FlowableCreate$ErrorAsyncEmitter.onOverflow(FlowableCreate.java:438)
at io.reactivex.internal.operators.flowable.FlowableCreate$NoOverflowBaseAsyncEmitter.onNext(FlowableCreate.java:406)
at io.micronaut.http.netty.websocket.NettyRxWebSocketSession.lambda$null$2(NettyRxWebSocketSession.java:191)
at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:577)
What is the backpressure and values / requests this referring to, and what is the actual way I should process an async send of the message? I expect it to just send the single item I am trying to send..
The Micronaut API documentation mentions following the javax.websocket API closely but
the javax.websocket async API seems to make more sense in just providing a Future to listen to.
So the short question is, how to use the Micronaut Websocket API to send message with the async mode outside the Micronaut provided functions? Or am I doing it all wrong?
It seems like I might be making some general wrong assumption about this API, but cannot figure it out from docs and cannot find example.
I had the same problem with micronaut v1.3.2.
I managed to get it working with sendAsync/sendSync instead of send.
I had a look at the implementation of NettyRxWebSocketSession and it looks like send is implemented somewhat differently than sendAsync. Not clear if its due to configuration or just problem with the implementation of send.
I hope this helps.

How do I throttle the amount of data sent to Stomp queue (handling websockets) so that I can guarantee that I don't overflow the buffer?

I have two Java processes and I am connecting them using a websocket in spring boot. One process acts as the client and connects like this:
List<Transport> transports = new ArrayList<Transport>(1);
transports.add(new WebSocketTransport(new StandardWebSocketClient()));
WebSocketClient client = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSessionHandler firstSessionHandler = new MyStompSessionHandler("Philip");
stompClient.connect("ws://localhost:8080/chat", firstSessionHandler);
The session handler extends StompSessionHandlerAdapter and provides these methods (I am subscribing by username so each client can receive its own messages):
#Override
public void afterConnected(
StompSession session, StompHeaders connectedHeaders) {
session.subscribe("/user/" + userName + "/reply", this);
session.send("/app/chat", getSampleMessage());
}
#Override
public void handleFrame(StompHeaders headers, Object payload) {
Message msg = (Message) payload;
// etc.....
}
On the server side I have a Controller exposed and I am writing data by calling the endpoint from a worker thread.
#Autowired
private SimpMessagingTemplate template;
#MessageMapping("/chat")
public void send(
Message message)
throws Exception {
template.convertAndSendToUser(message.getFrom(),
"/reply",
message);
}
In the websocket config I am overriding the method to set the limits:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic", "/user");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.setMessageSizeLimit(500 * 1024);
registration.setSendBufferSizeLimit(1024 * 1024);
registration.setSendTimeLimit(20000);
}
My question is this, if the load on the server gets high enough and I overrun the limit, the websocket fails catastrophically, and I want to avoid this. What I would like to do is for the controller to have the ability to ask the message broker "will this message fit in the buffer?", so that I can throttle to stay under the limit. I searched the API documentation but I don't see any way of doing that. Are there any other obvious solutions that I am missing?
Thanks.
Actually I found a solution, so if anyone is interested, here it is.
On the server side configuration of the websockets I installed an Interceptor on the Outbound Channel (this is part of the API), which is called after each send from the embedded broker.
So I know how much is coming in, which I keep track of in my Controller class and I know how much is going out through the Interceptor that I installed, and this allows me to always stay under the limit.
The controller, before accepting any new messages to be queued up for the broker first determines if enough room is available and if not queues up the message in external storage until such time as room becomes available.

Spring creating dashboard using web sockets for live updates

The front page of my web app is a dashboard, where I pull out information such as:
Latest entered clients, 5 top male clients, and female and also some calculated statistics.
The approach I went with first, was creating endpoints in my controller that would calculate such things and return a JSON file with the results, and then make an Ajax call and put the data in the html file. But I was told the best way to do this, would be to use Web Sockets, considering that when another users puts a client in, simultaniously he needs to show up on the dashboard.
Following a tutorial what I have so far is this :
public class MyMessageHandler extends TextWebSocketHandler {
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
// The WebSocket has been closed
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
// The WebSocket has been opened
// I might save this session object so that I can send messages to it outside of this method
// Let's send the first message
session.sendMessage(new TextMessage("You are now connected to the server. This is the first message."));
}
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage) throws Exception {
// A message has been received
System.out.println("Message received: " + textMessage.getPayload());
}
}
And the websocket endpoint :
#Configuration
#EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {
#Bean
public WebSocketHandler myMessageHandler() {
return new MyMessageHandler();
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myMessageHandler(), "/my-websocket-endpoint");
}
}
But this tutorial shows how a message will be sent-received real time.
My controller has and endpoint like this:
#RequestMapping(value="getDashboard/{gender}",method=RequestMethod.GET)
public #ResponseBody List<Client> getTopClients(#PathVariable("gender")
char gender) {
return clientService.findTop5ByGenderOrderByResult_DataResults_ScoreDesc(gender);
}
What I'm trying to understand is, where do this service so that it is called as long as the connection is open, so if there's any update, it updates the dashboard real time.
I guess what I'm trying to understand is the skeleton, of what this would look like using web sockets.
Just an overview of its logic/example.
Any help is appreciated and I apologize as I'm a beginner, I dont fully understand how to switch from what I had done before, and I'm trying to learn best practices.

Spring Integration TcpInboundGateway Read exception resulting in SocketException:Connection reset

I am using spring boot as per examples for TcpInboundGateway,so different devices send data to this Gateways,things works fine but in between in logs it showing following exception:
2015-12-29 18:42:19.455 ERROR 3465 --- [ool-3-thread-47] o.s.i.i.tcp.connection.TcpNetConnection : Read exception 106.221.159.216:38170:8765:934c050d-c4b5-4466-98ab-ee87714c3d00 SocketException:Connection reset
If this exception is resetting connection then how to avoid this reset?What is the cause of this error?
My code as follows
#SpringBootApplication
#IntegrationComponentScan
public class SpringIntegrationApplication extends SpringBootServletInitializer{
public static void main(String[] args) throws IOException {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringIntegrationApplication.class, args);
System.in.read();
ctx.close();
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringIntegrationApplication.class);
}
private static Class<SpringIntegrationApplication> applicationClass = SpringIntegrationApplication.class;
#Bean
TcpNetServerConnectionFactory cf(){
TcpNetServerConnectionFactory connectionFactory=new TcpNetServerConnectionFactory(8765);
return connectionFactory;
}
#Bean
TcpInboundGateway tcpGate(){
TcpInboundGateway gateway=new TcpInboundGateway();
gateway.setConnectionFactory(cf());
gateway.setRequestChannel(requestChannel());
return gateway;
}
#Bean
public MessageChannel requestChannel(){
return new DirectChannel();
}
#MessageEndpoint
public class Echo {
#ServiceActivator(inputChannel="requestChannel")
public byte[] echo(byte[] in,#SuppressWarnings("deprecation") #Header("ip_address") String ip){
byte[] rawbytes = gosDataSerivce.byteArrayToHex(in,ip);//Process bytes and returns result
return rawbytes;
}
}
}
After setting singleUse to true now exception message is changed slightly.
2015-12-31 06:09:00.481 ERROR 16450 --- [ool-3-thread-10] o.s.i.i.tcp.connection.TcpNetConnection : Read exception 106.221.146.40:9195:8765:1b4755e8-5b0c-44b9-b4e6-b3aacc25e228 SocketException:Connection reset
Use Case:
I have several clients that established GPRS connection to TcpInboundGateWay and sends login packet,our server will reply to this login packet.If client receives server reply to login packet then it will send data packets at regular interval. Server needs to reply to these packet also if server fails to send reply to those data packets then client GPRS connection is terminated and client will try to establish connections again.Let me know if this use case can be handle with TcpInboundGateWay
Network Trace Analysis
General flow of communication between client and server is as follows:Client sends login packet from ip say 106.221.148.165 so at server connection named 106.221.148.165:63430:8765:cc105da2-dae4-494b-af9c-d1ba268f34f1 is created, that client sends subsequent packets from that ip only.So everything works fine,but after some time same client sends its login packet from another ip say 106.221.142.204.And subsequent packets from new ip.But in logs following error comes that for previous connection exception occurred.
2016-01-05 05:16:14.871 ERROR 6819 --- [pool-3-thread-5] o.s.i.i.tcp.connection.TcpNetConnection : Read exception 106.221.148.165:63430:8765:cc105da2-dae4-494b-af9c-d1ba268f34f1 SocketException:Connection reset
I have set singleUse true and I am using spring integration 4.2.1
This message is emitted when the client closes the socket - if your client only sends one message then closes the socket, you can set singleUse to true and it will suppress this message (as long as the socket is closed normally - between messages).
With Spring Integration version 4.2 and later, the message is not emitted on a normal close, even if singleUse is false.

Disconnect client session from Spring websocket stomp server

I've searched quite a bit and been unable to find this: Is there a way that a spring websocket stomp server can disconnect a client based on the sessionId (or really based on anything at all)?
It seems to me that once a client connects to a server there is nothing that allows the server to disconnect the client.
Actually using some workarounds you can achieve what you want.
For that you should do:
Use java configuration (not sure if it is possible with XML config)
Extend your config class from WebSocketMessageBrokerConfigurationSupport and implement WebSocketMessageBrokerConfigurer interface
Create custom sub-protocol websocket handler and extend it from SubProtocolWebSocketHandler class
In your custom sub-protocol websocket handler override afterConnectionEstablished method and you will have access to WebSocketSession :)
I've created sample spring-boot project to show how we can disconnect client session from server side:
https://github.com/isaranchuk/spring-websocket-disconnect
You can also disconnect session by implementing a custom WebSocketHandlerDecorator:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig<S extends ExpiringSession> extends AbstractSessionWebSocketMessageBrokerConfigurer<S> {
#Override
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
session.close(CloseStatus.NOT_ACCEPTABLE);
super.afterConnectionEstablished(session);
}
};
}
});
super.configureWebSocketTransport(registration);
}
#Override
protected void configureStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/home")
.setHandshakeHandler(new DefaultHandshakeHandler(
new UndertowRequestUpgradeStrategy() // If you use undertow
// new JettyRequestUpgradeStrategy()
// new TomcatRequestUpgradeStrategy()
))
.withSockJS();
}
}
As far as I know the API doesn't provide what you are looking for, on server-side you can only detect disconnect events. If you want to disconnect a certain client I think you must go for a litte workaround, e.g. this one:
Write a client-side javascript function that is able to trigger a disconnect
As soon as your client is connected to the server, generate a client ID in your javascript and send it to the server. Remember the ID on the client, you'll need it in step (4).
At the time you want the server to disconnect the connection to the specific client (identified by the ID), send a message containing the ID back to the client.
Now your client javascript evaluates the message send from the server and decides to call the disconnect function you wrote in step (1).
Your client disconnects itself.
The workaround is a bit cumbersome but it'll work.
I relied on the idea of #Dániel Kis and implemented the websocket session management with the key point of storing websocket sessions for authenticated users in Singleton-like object.
// WebSocketConfig.java
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
#Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
#Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
#Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
// We will store current user's session into WebsocketSessionHolder after connection is established
String username = session.getPrincipal().getName();
WebsocketSessionHolder.addSession(username, session);
super.afterConnectionEstablished(session);
}
};
}
});
}
}
Class to store websocket users' sessions WebsocketSessionHolder. I use 'synchronized' blocks for thread safety. Actually this blocks are not expensive operations because each of methods (addSession and closeSessions) are used not so often (On establishing and terminating connection). No need to use ConcurrentHashMap or SynchronizedMap here because we perform bunch of operations with the list in these methods.
// WebsocketSessionHolder.java
public class WebsocketSessionHolder {
static {
sessions = new HashMap<>();
}
// key - username, value - List of user's sessions
private static Map<String, List<WebSocketSession>> sessions;
public static void addSession(String username, WebSocketSession session)
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions == null)
userSessions = new ArrayList<WebSocketSession>();
userSessions.add(session);
sessions.put(username, userSessions);
}
}
public static void closeSessions(String username) throws IOException
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions != null)
{
for(var session : userSessions) {
// I use POLICY_VIOLATION to indicate reason of disconnecting for a client
session.close(CloseStatus.POLICY_VIOLATION);
}
sessions.remove(username);
}
}
}
}
And the final touch - terminating (disconnecting) specified user websocket sessions ("ADMIN" in the example), say in some Controller
//PageController.java
#Controller
public class PageController {
#GetMapping("/kill-sessions")
public void killSessions() throws Exception {
WebsocketSessionHolder.closeSessions("ADMIN");
}
}
In case of xml configuration you can use <websocket:decorator-factories> in the <websocket:transport> of your <websocket:message-broker>.
Create custom WebSocketHandlerDecorator and WebSocketHandlerDecoratorFactory which implement decorate method.
This may seem brief but I am not certain what the implementation would look like in your case. But, I think there are some circumstances that would warrant this workaround/solution:
Set a timeout on the back-end (say 30 seconds):
This is how you would do it with Spring Boot Websocket (and Tomcat):
#Bean
public ServletServerContainerFactoryBean websocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(MAX_SESSION_IDLE_TIMEOUT);
return container;
}
If you want to keep the session open - continue to send messages or else actively send ping/pongs. In the case that you want the session to disconnect, stop the ping/pong interaction somewhere suitable in you application.
Of course, if you are wanting to disconnect immediately, this doesn't seem to be an appropriate solution. But if you are simply trying to reduce the number of active connections, ping/pong may be a good fit since it keeps a session open only so long as messages are actively being sent, preventing the session from being closed prematurely.
first you have to introduce a class as your User class by inheritance then use it like this:
if (userObject instanceof User) {
User user = (User) userObject;
if (user.getId().equals(userDTO.getId())) {
for (SessionInformation information : sessionRegistry.getAllSessions(user, true)) {
information.expireNow();
}
}
}

Resources