static FskErr KprWebSocketEndpointStartClosingHandshake(KprWebSocketEndpoint self, UInt16 code, char *reason) { FskErr err = kFskErrNone; char *payload = NULL; UInt32 length = sizeof(UInt16); self->state = kKprWebSocketStateClosing; CALLBACK(closingCallback)(self, self->closeCode, self->closeReason, self->cleanClose, self->refcon); length += FskStrLen(reason); bailIfError(FskMemPtrNew(length, &payload)); *((UInt16 *) payload) = FskEndianU16_NtoB(code); FskMemCopy(&payload[2], reason, length - sizeof(UInt16)); bailIfError(KprWebSocketEndpointSendRawFrame(self, kKprWebSocketOpcodeClose, payload, length)); self->closeWasSent = true; bail: if (payload) FskMemPtrDispose(payload); if (err || (self->closeWasSent && self->closeWasReceived)) { self->cleanClose = (err == kFskErrNone); KprWebSocketEndpointDisconnect(self); } return err; }
static void KprWebSocketHandleError(KprWebSocketEndpoint self, FskErr err, UInt16 code, char *reason) { switch (err) { case kFskErrConnectionClosed: code = 1001; reason = "endpoint closed"; CALLBACK(errorCallback)(self, err, reason, self->refcon); KprWebSocketEndpointDisconnect(self); return; case kFskErrBadData: code = 1002; reason = "protocol error"; break; default: break; } // report error. if (self->state <= kKprWebSocketStateOpen) { CALLBACK(errorCallback)(self, err, reason, self->refcon); KprWebSocketEndpointClose(self, code, reason); } }
static FskErr KprWebSocketEndpointConnectCallback(FskSocket skt, void *refCon) { FskErr err = kFskErrNone; KprWebSocketEndpoint self = refCon; FskDebugStr("CONNECT: callback was called\n"); if (!skt || 0 == skt->ipaddrRemote) { bailIfError(kFskErrSocketNotConnected); } bailIfError(KprWebSocketEndpointSetupSocketReader(self, skt, kKprWebSocketEndpoint_onHeader)); self->doMask = true; self->needNonMaskedFrame = true; if (self->cancelConnection) { KprWebSocketEndpointDisconnect(self); } else { bailIfError(KprWebSocketEndpointUpgradeConnection(self)); } bail: if (err) { CALLBACK(errorCallback)(self, err, "cannot start handshake", self->refcon); } return err; }
static FskErr KprWebSocketEndpointHandleResponse(KprWebSocketEndpoint self, FskHeaders *response) { FskErr err = kFskErrNone; if (self->cancelConnection) { KprWebSocketEndpointDisconnect(self); return err; } if (!KprWebSocketEndpointValidateResponse(self, response)) { KprWebSocketEndpointDisconnect(self); return -1; } FskDebugStr("HANDSHAKE: done. upgraded to websocket\n"); self->state = kKprWebSocketStateOpen; CALLBACK(openCallback)(self, self->refcon); return kFskErrNone; }
void KprWebSocketEndpointDispose(KprWebSocketEndpoint self) { if (self) { FskDebugStr("DISPOSE: KprWebSocketEndpoint\n"); if (self->socket) KprWebSocketEndpointDisconnect(self); if (self->url) FskMemPtrDispose(self->url); if (self->key) FskMemPtrDispose(self->key); if (self->origin) FskMemPtrDispose(self->origin); if (self->closeReason) FskMemPtrDispose(self->closeReason); if (self->parts) FskStrParsedUrlDispose(self->parts); FskInstrumentedItemDispose(self); FskMemPtrDispose(self); } }
void KprWebSocketEndpointDispose(KprWebSocketEndpoint self) { if (self) { if (self->pendingSendCount > 0) { self->disposeRequested = true; return; } FskInstrumentedTypePrintfNormal(&gKprWebSocketEndpointInstrumentation, "DISPOSE: KprWebSocketEndpoint"); if (self->socket) KprWebSocketEndpointDisconnect(self); if (self->url) FskMemPtrDispose(self->url); if (self->key) FskMemPtrDispose(self->key); if (self->origin) FskMemPtrDispose(self->origin); if (self->closeReason) FskMemPtrDispose(self->closeReason); if (self->parts) FskStrParsedUrlDispose(self->parts); FskInstrumentedItemDispose(self); FskMemPtrDispose(self); } }
static FskErr KprWebSocketEndpointHandleCloseFrame(KprWebSocketEndpoint self, void *message, UInt32 length) { FskErr err = kFskErrNone; UInt16 code; if (length >= sizeof(UInt16)) { code = *(UInt16 *)message; code = FskEndianU16_BtoN(code); } else { code = 1005; } self->closeWasReceived = true; if (self->closeWasSent) { KprWebSocketEndpointDisconnect(self); } else { KprWebSocketEndpointClose(self, code, "Another endpoint closed"); } return err; }