internal override async Task <bool> Stop(ulong timeout) { WSLOG("Stop"); _mustStop = true; if (_reconnectionTimer != null) { _reconnectionTimer.Cancel(); } foreach (Queue <WSRequest> queue in _workingRequests) { while (queue.Count > 0) { WSRequest wsRequest = queue.Peek(); await wsRequest.getResponseBytes(); if (queue.Contains(wsRequest)) { queue.Dequeue(); } } } _webSock.Close(1000, ""); //_outDataWriter = null; WSLOG("Stop end"); return(false); }
internal override async Task <byte[]> hubRequestSync(string req_first_line, byte[] req_head_and_body, uint mstimeout) { WSRequest wsRequest = await sendRequest(req_first_line, req_head_and_body, HUB_TCP_CHANNEL, false, null, null); byte[] full_result = await wsRequest.getResponseBytes(); byte[] immVerifyHttPheader = imm_verifyHTTPheader(full_result); return(immVerifyHttPheader); }
internal override async Task <byte[]> devRequestSync(YDevice device, string req_first_line, byte[] req_head_and_body, uint mstimeout, YGenericHub.RequestProgress progress, object context) { if (mstimeout == 0) { // simulate a wait indefinitely mstimeout = 86400000; //24h } WSRequest wsRequest = await sendRequest(req_first_line, req_head_and_body, DEVICE_TCP_CHANNEL, false, progress, context); byte[] full_result = await wsRequest.getResponseBytes(); return(imm_verifyHTTPheader(full_result)); }
internal override async Task devRequestAsync(YDevice device, string req_first_line, byte[] req_head_and_body, YGenericHub.RequestAsyncResult asyncResult, object asyncContext) { WSRequest wsRequest = await sendRequest(req_first_line, req_head_and_body, DEVICE_TCP_CHANNEL, true, null, null); }
/* * look through all pending request if there is some data that we can send * */ private async Task processRequests(WSRequest request) { int tcpchan = request.Channel; int throttle_start = request.ReqPosition; int throttle_end = request.ReqSize; if (throttle_end > 2108 && _remoteVersion >= YGenericHub.USB_META_WS_PROTO_V2 && tcpchan == 0) { // Perform throttling on large uploads if (request.ReqPosition == 0) { // First chunk is always first multiple of full window (124 bytes) above 2KB throttle_end = 2108; // Prepare to compute effective transfer rate _lastUploadAckBytes[tcpchan] = 0; _lastUploadAckTime[tcpchan] = 0; // Start with initial RTT based estimate _uploadRate = (int)(_tcpMaxWindowSize * 1000 / (int)_tcpRoundTripTime); } else if (_lastUploadAckTime[tcpchan] == 0) { // first block not yet acked, wait more throttle_end = 0; } else { // adapt window frame to available bandwidth long bytesOnTheAir = request.ReqPosition - _lastUploadAckBytes[tcpchan]; ulong timeOnTheAir = YAPI.GetTickCount() - _lastUploadAckTime[tcpchan]; int uploadRate = _uploadRate; int toBeSent = (int)(2 * uploadRate + 1024 - bytesOnTheAir + (uploadRate * (int)timeOnTheAir / 1000)); if (toBeSent + bytesOnTheAir > DEFAULT_TCP_MAX_WINDOW_SIZE) { toBeSent = (int)(DEFAULT_TCP_MAX_WINDOW_SIZE - bytesOnTheAir); } WSLOG(string.Format("throttling: {0} bytes/s ({1} + {2} = {3})", _uploadRate, toBeSent, bytesOnTheAir, bytesOnTheAir + toBeSent)); if (toBeSent < 64) { ulong waitTime = (ulong)(1000 * (128 - toBeSent) / _uploadRate); if (waitTime < 2) { waitTime = 2; } //_next_transmit_tm = YAPI.GetTickCount() + waitTime; WSLOG(string.Format("WS: {0} sent {1}ms ago, waiting {2}ms...", bytesOnTheAir, timeOnTheAir, waitTime)); throttle_end = 0; } if (throttle_end > request.ReqPosition + toBeSent) { // when sending partial content, round up to full frames if (toBeSent > 124) { toBeSent = (toBeSent / 124) * 124; } throttle_end = request.ReqPosition + toBeSent; } } } while (request.ReqPosition < throttle_end) { IBuffer data; int datalen = throttle_end - request.ReqPosition; if (datalen > MAX_DATA_LEN) { datalen = MAX_DATA_LEN; } if (request.imm_isAsync() && (request.ReqPosition + datalen == request.ReqSize)) { if (datalen == MAX_DATA_LEN) { // last frame is already full we must send the async close in another one data = request.imm_GetRequestData(request.ReqPosition, datalen); await Send_WSStream(_webSock, YGenericHub.YSTREAM_TCP, tcpchan, data, 0); //WSLOG(string.Format("ws_req:{0}: sent {1} bytes on chan{2} ({3}/{4})", request, datalen, tcpchan, request.ReqPosition, request.ReqSize)); request.imm_reportDataSent(); request.ReqPosition += datalen; datalen = 0; } data = request.imm_GetRequestData(request.ReqPosition, datalen); await Send_WSStream(_webSock, YGenericHub.YSTREAM_TCP_ASYNCCLOSE, tcpchan, data, request.AsyncId); //WSLOG(string.Format("ws_req:{0}: sent async close {1}", request, request.AsyncId)); request.ReqPosition += datalen; } else { data = request.imm_GetRequestData(request.ReqPosition, datalen); await Send_WSStream(_webSock, YGenericHub.YSTREAM_TCP, tcpchan, data, 0); request.imm_reportDataSent(); //WSLOG(string.Format("ws_req:{0}: sent {1} bytes on chan{2} ({3}/{4})", request, datalen, tcpchan, request.ReqPosition, request.ReqSize)); request.ReqPosition += datalen; } } if (request.ReqPosition < request.ReqSize) { int sent = request.ReqPosition - throttle_start; // not completely sent, cannot do more for now if (sent > 0 && _uploadRate > 0) { ulong waitTime = (ulong)(1000 * sent / _uploadRate); if (waitTime < 2) { waitTime = 2; } //_next_transmit_tm = YAPI.GetTickCount() + waitTime; WSLOG(string.Format("Sent {0}bytes, waiting {1}ms...", sent, waitTime)); } else { //_next_transmit_tm = YAPI.GetTickCount() + 100; } } }
private async Task <WSRequest> sendRequest(string req_first_line, byte[] req_head_and_body, int tcpchanel, bool async, YGenericHub.RequestProgress progress, Object context) { WSRequest request; string debug = req_first_line.Trim(); byte[] full_request; byte[] req_first_lineBytes; if (req_head_and_body == null) { req_first_line += "\r\n\r\n"; req_first_lineBytes = YAPI.DefaultEncoding.GetBytes(req_first_line); full_request = req_first_lineBytes; } else { req_first_line += "\r\n"; req_first_lineBytes = YAPI.DefaultEncoding.GetBytes(req_first_line); full_request = new byte[req_first_lineBytes.Length + req_head_and_body.Length]; Array.Copy(req_first_lineBytes, 0, full_request, 0, req_first_lineBytes.Length); Array.Copy(req_head_and_body, 0, full_request, req_first_lineBytes.Length, req_head_and_body.Length); } ulong timeout = YAPI.GetTickCount() + WS_REQUEST_MAX_DURATION; while ((_connectionState != ConnectionState.CONNECTED && _connectionState != ConnectionState.DEAD)) { if (timeout < YAPI.GetTickCount()) { if (_connectionState != ConnectionState.CONNECTED && _connectionState != ConnectionState.CONNECTING) { throw new YAPI_Exception(YAPI.IO_ERROR, "IO error with hub"); } else { throw new YAPI_Exception(YAPI.TIMEOUT, "Last request did not finished correctly"); } } if (_connectionState == ConnectionState.DEAD) { throw new YAPI_Exception(_session_errno, _session_error); } } if (async) { request = new WSRequest(debug, tcpchanel, _nextAsyncId++, full_request); if (_nextAsyncId >= 127) { _nextAsyncId = 48; } } else { request = new WSRequest(debug, tcpchanel, full_request, progress, context); } _workingRequests[tcpchanel].Enqueue(request); //todo: handle timeout await processRequests(request); if (request.ErrorCode != YAPI.SUCCESS) { throw new YAPI_Exception(request.ErrorCode, request.ErrorMsg); } return(request); }