private void Update() { switch (_readyState) { case ReadyState.OPEN: case ReadyState.CLOSING: case ReadyState.CONNECTING: if (!_context.IsValid()) { return; } _is_polling = true; do { _is_servicing = false; WSApi.lws_service(_context, 0); } while (_is_servicing); _is_polling = false; break; case ReadyState._CONSTRUCTED: Connect(); break; } if (_is_context_destroying) { Destroy(); } }
private void SetClose() { if (_wsi.IsValid()) { _is_closing = true; SetReadyState(ReadyState.CLOSING); WSApi.lws_callback_on_writable(_wsi); _wsi = lws.Null; } else { SetReadyState(ReadyState.CLOSED); } }
// return -1 if error private int OnReceive(IntPtr @in, size_t len) { if (WSApi.lws_is_first_fragment(_wsi) == 1) { _buffer.writerIndex = 0; } _buffer.WriteBytes(@in, len); if (WSApi.lws_is_final_fragment(_wsi) == 1) { var is_binary = WSApi.lws_frame_is_binary(_wsi) == 1; if (is_binary) { unsafe { fixed(byte *ptr = _buffer.data) { var val = JSApi.JS_NewArrayBufferCopy(_jsContext, ptr, _buffer.writerIndex); CallScript("onmessage", val); JSApi.JS_FreeValue(_jsContext, val); } } } else { unsafe { _buffer.WriteByte(0); // make it null terminated fixed(byte *ptr = _buffer.data) { var val = JSApi.JS_NewString(_jsContext, ptr); CallScript("onmessage", val); JSApi.JS_FreeValue(_jsContext, val); } } } } return(0); }
// buffer: buffer for recv private WebSocket(ByteBuffer buffer, string url, List <string> protocols) { _url = url; _buffer = buffer; _protocols = protocols != null?protocols.ToArray() : new string[] { "" }; _websockets.Add(this); do { if (_protocols != null && _protocols.Length > 0) { _context = WSApi.ulws_create(_protocols[0], _callback, 1024 * 4, 1024 * 4); if (_context.IsValid()) { SetReadyState(ReadyState._CONSTRUCTED); break; } } SetReadyState(ReadyState.CLOSED); } while (false); }
private void OnWrite() { if (_pending.Count > 0) { var packet = _pending.Dequeue(); var protocol = packet.is_binary ? lws_write_protocol.LWS_WRITE_BINARY : lws_write_protocol.LWS_WRITE_TEXT; var len = packet.buffer.writerIndex - WSApi.LWS_PRE; unsafe { fixed(byte *buf = packet.buffer.data) { WSApi.lws_write(_wsi, &buf[WSApi.LWS_PRE], len, protocol); } } _bufferedAmount -= len; packet.Release(); if (_pending.Count > 0) { WSApi.lws_callback_on_writable(_wsi); } } }
private static JSValue _js_send(JSContext ctx, JSValue this_obj, int argc, JSValue[] argv) { try { WebSocket self; if (!js_get_classvalue(ctx, this_obj, out self)) { throw new ThisBoundException(); } if (argc == 0) { throw new ParameterException("data", typeof(string), 0); } if (!self._wsi.IsValid() || !self._context.IsValid()) { return(JSApi.JS_ThrowInternalError(ctx, "websocket closed")); } if (argv[0].IsString()) { // send text data size_t psize; var pointer = JSApi.JS_ToCStringLen(ctx, out psize, argv[0]); if (pointer != IntPtr.Zero && psize > 0) { var buffer = ScriptEngine.AllocByteBuffer(ctx, psize + WSApi.LWS_PRE); if (buffer != null) { buffer.WriteBytes(WSApi.LWS_PRE); buffer.WriteBytes(pointer, psize); self._pending.Enqueue(new Packet(false, buffer)); self._bufferedAmount += psize; WSApi.lws_callback_on_writable(self._wsi); } else { JSApi.JS_FreeCString(ctx, pointer); return(JSApi.JS_ThrowInternalError(ctx, "buf alloc failed")); } } JSApi.JS_FreeCString(ctx, pointer); } else { size_t psize; var pointer = JSApi.JS_GetArrayBuffer(ctx, out psize, argv[0]); if (pointer != IntPtr.Zero && psize > 0) { var buffer = ScriptEngine.AllocByteBuffer(ctx, psize + WSApi.LWS_PRE); if (buffer != null) { buffer.WriteBytes(WSApi.LWS_PRE); buffer.WriteBytes(pointer, psize); self._pending.Enqueue(new Packet(false, buffer)); self._bufferedAmount += psize; WSApi.lws_callback_on_writable(self._wsi); } else { return(JSApi.JS_ThrowInternalError(ctx, "buf alloc failed")); } } else { return(JSApi.JS_ThrowInternalError(ctx, "unknown buf type")); } } return(JSApi.JS_UNDEFINED); } catch (Exception exception) { return(JSApi.ThrowException(ctx, exception)); } }
private async void Connect() { if (_readyState != ReadyState._CONSTRUCTED) { return; } SetReadyState(ReadyState._DNS); var uri = new Uri(_url); var ssl_type = uri.Scheme == "ws" ? ulws_ssl_type.ULWS_DEFAULT : ulws_ssl_type.ULWS_USE_SSL_ALLOW_SELFSIGNED; var protocol_names = QuickJS.Utils.TextUtils.GetNullTerminatedBytes(string.Join(",", _protocols)); var path = QuickJS.Utils.TextUtils.GetNullTerminatedBytes(uri.AbsolutePath); var host = QuickJS.Utils.TextUtils.GetNullTerminatedBytes(uri.DnsSafeHost); var port = uri.Port; switch (uri.HostNameType) { case UriHostNameType.IPv4: case UriHostNameType.IPv6: { var address = QuickJS.Utils.TextUtils.GetNullTerminatedBytes(uri.DnsSafeHost); SetReadyState(ReadyState.CONNECTING); unsafe { fixed(byte *protocol_names_ptr = protocol_names) fixed(byte *host_ptr = host) fixed(byte *address_ptr = address) fixed(byte *path_ptr = path) { WSApi.ulws_connect(_context, protocol_names_ptr, ssl_type, host_ptr, address_ptr, path_ptr, port); } } } break; default: { var entry = await Dns.GetHostEntryAsync(uri.DnsSafeHost); if (_readyState != ReadyState._DNS) { // already closed return; } SetReadyState(ReadyState.CONNECTING); try { var ipAddress = Select(entry.AddressList); var address = QuickJS.Utils.TextUtils.GetNullTerminatedBytes(ipAddress.ToString()); unsafe { fixed(byte *protocol_names_ptr = protocol_names) fixed(byte *host_ptr = host) fixed(byte *address_ptr = address) fixed(byte *path_ptr = path) { WSApi.ulws_connect(_context, protocol_names_ptr, ssl_type, host_ptr, address_ptr, path_ptr, port); } } } catch (Exception exception) { // UnityEngine.Debug.LogErrorFormat("{0}", exception); SetReadyState(ReadyState.CLOSED); OnError(exception); } } break; } }
public static int _callback(lws wsi, lws_callback_reasons reason, IntPtr user, IntPtr @in, size_t len) { var context = WSApi.lws_get_context(wsi); var websocket = GetWebSocket(context); if (websocket == null) { return(-1); } switch (reason) { case lws_callback_reasons.LWS_CALLBACK_CHANGE_MODE_POLL_FD: { return(0); } case lws_callback_reasons.LWS_CALLBACK_CLIENT_RECEIVE: { websocket._is_servicing = true; return(websocket.OnReceive(@in, len)); } case lws_callback_reasons.LWS_CALLBACK_CLIENT_WRITEABLE: { websocket._is_servicing = true; if (websocket._is_closing) { WSApi.lws_close_reason(wsi, lws_close_status.LWS_CLOSE_STATUS_NORMAL, ""); return(-1); } websocket.OnWrite(); return(0); } case lws_callback_reasons.LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: { return(0); } case lws_callback_reasons.LWS_CALLBACK_CLIENT_ESTABLISHED: { websocket._is_servicing = true; websocket._wsi = wsi; websocket.OnConnect(); // _on_connect(websocket, lws_get_protocol(wsi)->name); return(0); } case lws_callback_reasons.LWS_CALLBACK_CLIENT_CONNECTION_ERROR: { websocket._is_servicing = true; websocket.OnError(@in, len); websocket.Destroy(); return(-1); } case lws_callback_reasons.LWS_CALLBACK_WS_PEER_INITIATED_CLOSE: { websocket._is_servicing = true; websocket.OnCloseRequest(@in, len); return(0); } case lws_callback_reasons.LWS_CALLBACK_CLIENT_CLOSED: { websocket.SetClose(); // _duk_lws_close(websocket); websocket.Destroy(); websocket.OnClose(); return(0); } default: { return(0); } } }