Open
Description
Socket.IO Connection Issue in Firecamp
Describe the Bug
When attempting to connect to a Socket.IO server (v4) using Firecamp, the connection fails with an "Unsupported protocol version" error. Firecamp is attempting to use Engine.IO protocol version 3 (EIO=3) while the server is expecting version 4 (EIO=4), resulting in a protocol version mismatch.
To Reproduce
Steps to reproduce the behavior:
- Set up a Socket.IO v4 server on
localhost:5000
(added dummy server .js below) - Open Firecamp and create a new Socket.IO connection
- Enter
http://localhost:5000
as the connection URL - Attempt to connect
- Connection fails with error: "Unsupported protocol version"
Expected Behavior
Firecamp should either:
- Protocol version should be either
EIO=3
for v2 and v3, orEIO=4
for v4 (would be great to see that in connection url) - Default to the latest protocol version (
EIO=4
) for Socket.IO connections
Screenshots
Error from server logs:
Engine.IO connection error: {
"code": 5,
"message": "Unsupported protocol version",
"context": {
"protocol": 3
}
}
Request headers showing EIO=3
:
url: "/socket.io/?EIO=3&transport=websocket"
Desktop Information
- OS: macOS 10.15.7
- Application: Firecamp v3.3.0-beta.3
- Electron: 29.1.0
- Chrome: 122.0.6261.70
Note:
Maybe, you need to add one more configuration or change something somewhere, but as a User I thought it should be done via dropdown where you chose version? No?;
Couldn't see exactly what's happening in the code, because part of it is not accessible as it seems: io: { v2: SocketIOv2, v3: SocketIOv3, v4: SocketIOv4 },
Test server
Click me
Socket.IO Server Javascript
const http = require('node:http')
const { Server } = require('socket.io')
// Create HTTP server
const server = http.createServer((req, res) => {
console.log(`HTTP Request: ${req.method} ${req.url}`)
// Add CORS headers to all responses
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
res.setHeader('Access-Control-Allow-Headers', 'Content-Type')
if (req.method === 'OPTIONS') {
res.writeHead(204)
res.end()
return
}
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Socket.IO test server running. This is a plain HTTP endpoint.')
})
// Create Socket.IO server with compatibility for v3 and v4
const io = new Server(server, {
// Allow both v3 and v4 clients
allowEIO3: true,
// Ping configuration
pingTimeout: 60000, // How long to wait after a ping before considering the connection closed
pingInterval: 25000, // How often to ping the client
// Connection timeout
connectTimeout: 60000, // How long to wait for a connection to establish
// Transport configuration
transports: ['polling', 'websocket'],
upgradeTimeout: 30000, // How long to wait for transport upgrade
// CORS configuration
cors: {
origin: '*',
methods: ['GET', 'POST', 'OPTIONS'],
credentials: true,
},
// Additional options
maxHttpBufferSize: 1e8, // 100 MB
path: '/socket.io/', // Default path
serveClient: true, // Serve client files
})
// Debug middleware for all Socket.IO connections
io.use((socket, next) => {
console.log('Connection attempt:')
console.log(' IP:', socket.handshake.address)
console.log(' Transport:', socket.conn.transport.name)
console.log(' Headers:', JSON.stringify(socket.handshake.headers))
console.log(' Query:', JSON.stringify(socket.handshake.query))
next()
})
// Socket.IO connection handler
io.on('connection', (socket) => {
console.log(`Client connected: ${socket.id}`)
console.log(`Transport: ${socket.conn.transport.name}`)
// Send immediate welcome message
socket.emit('welcome', {
message: 'Connected to Socket.IO server',
socketId: socket.id,
timestamp: new Date().toISOString(),
})
// Set up a ping interval for this specific socket
const pingInterval = setInterval(() => {
console.log(`Pinging client ${socket.id}...`)
// Custom ping implementation only - don't use socket.conn.ping()
socket.emit('ping_from_server', { timestamp: new Date().toISOString() })
// The built-in ping is handled automatically by Socket.IO
// No need to call socket.conn.ping() manually
}, 20000)
// Handle custom ping response
socket.on('pong_from_client', (data) => {
console.log(`Received pong from ${socket.id}:`, data)
})
// Handle message event
socket.on('message', (data) => {
console.log(`Message from ${socket.id}:`, data)
socket.emit('response', {
echo: data,
timestamp: new Date().toISOString(),
})
})
// Handle any event
socket.onAny((event, ...args) => {
if (event !== 'message' && event !== 'ping_from_server' && event !== 'pong_from_client') {
console.log(`Event "${event}" from ${socket.id}:`, args)
socket.emit(`${event}_response`, {
received: args,
timestamp: new Date().toISOString(),
})
}
})
// Handle errors
socket.on('error', (error) => {
console.error(`Socket error for ${socket.id}:`, error)
})
// Handle disconnection
socket.on('disconnect', (reason) => {
console.log(`Client disconnected: ${socket.id}, reason: ${reason}`)
clearInterval(pingInterval) // Clean up ping interval
})
})
// Engine.IO errors
io.engine.on('connection_error', (err) => {
console.error('Engine.IO connection error:', err)
})
// Start the server
const PORT = 5000
server.listen(PORT, '0.0.0.0', () => {
console.log(`Socket.IO server running on port ${PORT}`)
console.log(`Server time: ${new Date().toISOString()}`)
console.log('Supports both Socket.IO v3 and v4 clients')
console.log('Enhanced ping configuration enabled')
console.log('Connect with Socket.IO client using:')
console.log(` - URL: http://localhost:${PORT}`)
})
// Handle server shutdown
process.on('SIGINT', () => {
console.log('Shutting down server...')
io.close()
server.close()
process.exit(0)
})
Metadata
Metadata
Assignees
Labels
No labels