Websockets in Football ====================== Port sharing ------------ With wsgw, several services can share the same HTTP port. This has potential to become problematic with integrated Websockets, since each service will want its own HTTP port separate from the line-oriented port. The solution is to add a new command to detect/trigger start of session: HELO (configurable). On connecting, a client is expected to either greet with HELO or an HTTP GET. If HELO, the line-oriented protocol is triggered; if HTTP GET, a Websocket session happens. Creating Services ----------------- fb_create_service will need to have single queue size parameter replaced with a structure that contains options. This will be expandable in the future, with nulled data representing defaults. New options include: * http port number * greeting: Default 'HELO'. * HELO: Do not use, allow, fallback, or require. ** Do not use: Don't wait for HELO; begin line-oriented session immediately. ** Required: socket will not speak until it gets it; this allows line protocol and websockets to share a port assignment. ** Allow allows HELO but ignores it. Transitional to allow clients implementation of HELO prior to merging ports. ** Fallback: Waits for HELO, but if it gets something that's neither HELO or a proper HTTP GET then it assumes line protocol. Transitional to allow some old client support after merging ports. Connections ----------- Connections will need some additional state to handle the handshaking at connection. States will include: * Awaiting greeting * Gathering HTTP header * Line-oriented mode active * HTTP/Websocket mode active For websockets, output will also need to be collected until an end-of-line is seen, at which point it will need to bet sent on websockets. A new "assembly queue" will be added using the same structures as the socket output queue. Output ------ fb_queue_single will check socket state and route messages accordingly: * Awaiting greeting: /dev/null * Gathering HTTP header: /dev/null * Line-oriented mode: Send or queue immediately. * HTTP/Websocket mode: Add to assembly queue. If message contains a newline, trigger assembly. The assembly scans the queued components to determine message size, forms the WebSocket packet, and then immediately sends or queues that. Input ----- Websocket messages will represent a complete "line" of input. However, there is the potential for a Websocket message to be split in transmission so we will need multiple read()s to collect it all. fb_read_input will need an if/else statement to divert into two new functions, fb_read_line_input and fb_read_websocket_input. The new functions will be responsible for collecting the input and any buffering that needs to occur to ensure complete commands are passed up. fb_read_input will receive the new responsibility of managing socket state in response to the input: * If in HTTP or line-oriented mode, data will be passed up. * If awaiting the greeting, it will examine the message and use it to select the next socket state. * If gathering HTTP header, it will add the message to a header collection. If it's a blank line, it will trigger header parsing, send the WebSocket accept (or error), and move to HTTP mode. * For an HTTP or shared socket, the new connection event must be generated not on connection but on HELO, WebSocket accept, or fallback. Fallback will (unfortunately) require the clunkiness of queueing an event with the received command so that the connect event can be sent first. Future extensions ----------------- HELO could be extended in the future to request switch to TLS via an optional parameter. Protocol violations ------------------- Websockets connections to line-oriented port will trigger protocol error and disconnection of arriving web clients. In the event they send a request, it will probably not match any parser patterns and be rejected. This is no different than today. Handling of line-oriented connections to Websockets ports will vary depending on HELO mode: * Do not use: Generate a protocol error and disconnect for HELO or anything not HTTP. * Required: Generate a protocol error and disconnect for anything not HELO or HTTP. * Allow: Connect in line-oriented mode, but if first request is "HELO", drop it. * Fallback: If first request is HTTP, do that. If it's HELO, start line-oriented session. Anything else, start line-oriented session then generate event with request. HELO with any options must be rejected with an unsupported protocol error.