| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379 |
- //------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Net;
- using System.Net.Sockets;
- using System.Runtime;
- using System.Runtime.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Security.Permissions;
- using System.ServiceModel;
- using System.ServiceModel.Diagnostics;
- using System.ServiceModel.Diagnostics.Application;
- using System.Text;
- using System.Threading;
- class SocketConnection : IConnection
- {
- static AsyncCallback onReceiveCompleted;
- static EventHandler<SocketAsyncEventArgs> onReceiveAsyncCompleted;
- static EventHandler<SocketAsyncEventArgs> onSocketSendCompleted;
- // common state
- Socket socket;
- TimeSpan sendTimeout;
- TimeSpan readFinTimeout;
- TimeSpan receiveTimeout;
- CloseState closeState;
- bool isShutdown;
- bool noDelay = false;
- bool aborted;
- TraceEventType exceptionEventType;
- // close state
- TimeoutHelper closeTimeoutHelper;
- static WaitCallback onWaitForFinComplete = new WaitCallback(OnWaitForFinComplete);
- // read state
- int asyncReadSize;
- SocketAsyncEventArgs asyncReadEventArgs;
- byte[] readBuffer;
- int asyncReadBufferSize;
- object asyncReadState;
- WaitCallback asyncReadCallback;
- Exception asyncReadException;
- bool asyncReadPending;
- // write state
- SocketAsyncEventArgs asyncWriteEventArgs;
- object asyncWriteState;
- WaitCallback asyncWriteCallback;
- Exception asyncWriteException;
- bool asyncWritePending;
- IOThreadTimer receiveTimer;
- static Action<object> onReceiveTimeout;
- IOThreadTimer sendTimer;
- static Action<object> onSendTimeout;
- string timeoutErrorString;
- TransferOperation timeoutErrorTransferOperation;
- IPEndPoint remoteEndpoint;
- ConnectionBufferPool connectionBufferPool;
- string remoteEndpointAddress;
- public SocketConnection(Socket socket, ConnectionBufferPool connectionBufferPool, bool autoBindToCompletionPort)
- {
- if (socket == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("socket");
- }
- Fx.Assert(connectionBufferPool != null, "Argument connectionBufferPool cannot be null");
- this.closeState = CloseState.Open;
- this.exceptionEventType = TraceEventType.Error;
- this.socket = socket;
- this.connectionBufferPool = connectionBufferPool;
- this.readBuffer = this.connectionBufferPool.Take();
- this.asyncReadBufferSize = this.readBuffer.Length;
- this.socket.SendBufferSize = this.socket.ReceiveBufferSize = this.asyncReadBufferSize;
- this.sendTimeout = this.receiveTimeout = TimeSpan.MaxValue;
- this.remoteEndpoint = null;
- if (autoBindToCompletionPort)
- {
- this.socket.UseOnlyOverlappedIO = false;
- }
- // In SMSvcHost, sockets must be duplicated to the target process. Binding a handle to a completion port
- // prevents any duplicated handle from ever binding to a completion port. The target process is where we
- // want to use completion ports for performance. This means that in SMSvcHost, socket.UseOnlyOverlappedIO
- // must be set to true to prevent completion port use.
- if (this.socket.UseOnlyOverlappedIO)
- {
- // Init BeginRead state
- if (onReceiveCompleted == null)
- {
- onReceiveCompleted = Fx.ThunkCallback(new AsyncCallback(OnReceiveCompleted));
- }
- }
- this.TraceSocketInfo(socket, TraceCode.SocketConnectionCreate, SR.TraceCodeSocketConnectionCreate, null);
- }
- public int AsyncReadBufferSize
- {
- get { return asyncReadBufferSize; }
- }
- public byte[] AsyncReadBuffer
- {
- get
- {
- return readBuffer;
- }
- }
- object ThisLock
- {
- get { return this; }
- }
- public TraceEventType ExceptionEventType
- {
- get { return this.exceptionEventType; }
- set { this.exceptionEventType = value; }
- }
- public IPEndPoint RemoteIPEndPoint
- {
- get
- {
- // this property should only be called on the receive path
- if (remoteEndpoint == null && this.closeState == CloseState.Open)
- {
- try
- {
- remoteEndpoint = (IPEndPoint)socket.RemoteEndPoint;
- }
- catch (SocketException socketException)
- {
- // will never be a timeout error, so TimeSpan.Zero is ok
- #pragma warning suppress 56503 // Called from Receive path, SocketConnection cannot allow a SocketException to escape.
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertReceiveException(socketException, TimeSpan.Zero), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- #pragma warning suppress 56503 // rethrow
- throw;
- }
- else
- {
- #pragma warning suppress 56503 // Called from Receive path, SocketConnection must convert ObjectDisposedException properly.
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- }
- return remoteEndpoint;
- }
- }
- IOThreadTimer SendTimer
- {
- get
- {
- if (this.sendTimer == null)
- {
- if (onSendTimeout == null)
- {
- onSendTimeout = new Action<object>(OnSendTimeout);
- }
- this.sendTimer = new IOThreadTimer(onSendTimeout, this, false);
- }
- return this.sendTimer;
- }
- }
- IOThreadTimer ReceiveTimer
- {
- get
- {
- if (this.receiveTimer == null)
- {
- if (onReceiveTimeout == null)
- {
- onReceiveTimeout = new Action<object>(OnReceiveTimeout);
- }
- this.receiveTimer = new IOThreadTimer(onReceiveTimeout, this, false);
- }
- return this.receiveTimer;
- }
- }
- string RemoteEndpointAddress
- {
- get
- {
- if (remoteEndpointAddress == null)
- {
- try
- {
- IPEndPoint local, remote;
- if (TryGetEndpoints(out local, out remote))
- {
- this.remoteEndpointAddress = TraceUtility.GetRemoteEndpointAddressPort(remote);
- }
- else
- {
- //null indicates not initialized.
- remoteEndpointAddress = string.Empty;
- }
- }
- catch (Exception exception)
- {
- if (Fx.IsFatal(exception))
- {
- throw;
- }
- }
- }
- return remoteEndpointAddress;
- }
- }
- static void OnReceiveTimeout(object state)
- {
- SocketConnection thisPtr = (SocketConnection)state;
- thisPtr.Abort(SR.GetString(SR.SocketAbortedReceiveTimedOut, thisPtr.receiveTimeout), TransferOperation.Read);
- }
- static void OnSendTimeout(object state)
- {
- SocketConnection thisPtr = (SocketConnection)state;
- thisPtr.Abort(TraceEventType.Warning,
- SR.GetString(SR.SocketAbortedSendTimedOut, thisPtr.sendTimeout), TransferOperation.Write);
- }
- static void OnReceiveCompleted(IAsyncResult result)
- {
- ((SocketConnection)result.AsyncState).OnReceive(result);
- }
- static void OnReceiveAsyncCompleted(object sender, SocketAsyncEventArgs e)
- {
- ((SocketConnection)e.UserToken).OnReceiveAsync(sender, e);
- }
- static void OnSendAsyncCompleted(object sender, SocketAsyncEventArgs e)
- {
- ((SocketConnection)e.UserToken).OnSendAsync(sender, e);
- }
- public void Abort()
- {
- Abort(null, TransferOperation.Undefined);
- }
- void Abort(string timeoutErrorString, TransferOperation transferOperation)
- {
- TraceEventType traceEventType = TraceEventType.Warning;
- // we could be timing out a cached connection
- if (this.ExceptionEventType == TraceEventType.Information)
- {
- traceEventType = this.ExceptionEventType;
- }
- Abort(traceEventType, timeoutErrorString, transferOperation);
- }
- void Abort(TraceEventType traceEventType)
- {
- Abort(traceEventType, null, TransferOperation.Undefined);
- }
- void Abort(TraceEventType traceEventType, string timeoutErrorString, TransferOperation transferOperation)
- {
- if (TD.SocketConnectionAbortIsEnabled())
- {
- TD.SocketConnectionAbort(this.socket.GetHashCode());
- }
- lock (ThisLock)
- {
- if (closeState == CloseState.Closed)
- {
- return;
- }
- this.timeoutErrorString = timeoutErrorString;
- this.timeoutErrorTransferOperation = transferOperation;
- aborted = true;
- closeState = CloseState.Closed;
- if (this.asyncReadPending)
- {
- CancelReceiveTimer();
- }
- else
- {
- this.DisposeReadEventArgs();
- }
- if (this.asyncWritePending)
- {
- CancelSendTimer();
- }
- else
- {
- this.DisposeWriteEventArgs();
- }
- }
- if (DiagnosticUtility.ShouldTrace(traceEventType))
- {
- TraceUtility.TraceEvent(traceEventType, TraceCode.SocketConnectionAbort,
- SR.GetString(SR.TraceCodeSocketConnectionAbort), this);
- }
- socket.Close(0);
- }
- void AbortRead()
- {
- lock (ThisLock)
- {
- if (this.asyncReadPending)
- {
- if (closeState != CloseState.Closed)
- {
- this.SetUserToken(this.asyncReadEventArgs, null);
- this.asyncReadPending = false;
- CancelReceiveTimer();
- }
- else
- {
- this.DisposeReadEventArgs();
- }
- }
- }
- }
- void CancelReceiveTimer()
- {
- // CSDMain 34539: Snapshot the timer so that we don't null ref if there is a ----
- // between calls to CancelReceiveTimer (e.g., Abort, AsyncReadCallback)
- IOThreadTimer receiveTimerSnapshot = this.receiveTimer;
- this.receiveTimer = null;
- if (receiveTimerSnapshot != null)
- {
- receiveTimerSnapshot.Cancel();
- }
- }
- void CancelSendTimer()
- {
- IOThreadTimer sendTimerSnapshot = this.sendTimer;
- this.sendTimer = null;
- if (sendTimerSnapshot != null)
- {
- sendTimerSnapshot.Cancel();
- }
- }
- void CloseAsyncAndLinger()
- {
- readFinTimeout = closeTimeoutHelper.RemainingTime();
- try
- {
- if (BeginReadCore(0, 1, readFinTimeout, onWaitForFinComplete, this) == AsyncCompletionResult.Queued)
- {
- return;
- }
- int bytesRead = EndRead();
- if (bytesRead > 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, socket.RemoteEndPoint)),
- ExceptionEventType);
- }
- }
- catch (TimeoutException timeoutException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
- SR.GetString(SR.SocketCloseReadTimeout, socket.RemoteEndPoint, readFinTimeout), timeoutException),
- ExceptionEventType);
- }
- ContinueClose(closeTimeoutHelper.RemainingTime());
- }
- static void OnWaitForFinComplete(object state)
- {
- SocketConnection thisPtr = (SocketConnection)state;
- try
- {
- int bytesRead;
- try
- {
- bytesRead = thisPtr.EndRead();
- if (bytesRead > 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, thisPtr.socket.RemoteEndPoint)),
- thisPtr.ExceptionEventType);
- }
- }
- catch (TimeoutException timeoutException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
- SR.GetString(SR.SocketCloseReadTimeout, thisPtr.socket.RemoteEndPoint, thisPtr.readFinTimeout),
- timeoutException), thisPtr.ExceptionEventType);
- }
- thisPtr.ContinueClose(thisPtr.closeTimeoutHelper.RemainingTime());
- }
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- {
- throw;
- }
- DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
- // The user has no opportunity to clean up the connection in the async and linger
- // code path, ensure cleanup finishes.
- thisPtr.Abort();
- }
- }
- public void Close(TimeSpan timeout, bool asyncAndLinger)
- {
- lock (ThisLock)
- {
- if (closeState == CloseState.Closing || closeState == CloseState.Closed)
- {
- // already closing or closed, so just return
- return;
- }
- this.TraceSocketInfo(this.socket, TraceCode.SocketConnectionClose, SR.TraceCodeSocketConnectionClose, timeout.ToString());
- closeState = CloseState.Closing;
- }
- // first we shutdown our send-side
- closeTimeoutHelper = new TimeoutHelper(timeout);
- Shutdown(closeTimeoutHelper.RemainingTime());
- if (asyncAndLinger)
- {
- CloseAsyncAndLinger();
- }
- else
- {
- CloseSync();
- }
- }
- void CloseSync()
- {
- byte[] dummy = new byte[1];
- // then we check for a FIN from the other side (i.e. read zero)
- int bytesRead;
- readFinTimeout = closeTimeoutHelper.RemainingTime();
- try
- {
- bytesRead = ReadCore(dummy, 0, 1, readFinTimeout, true);
- if (bytesRead > 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- new CommunicationException(SR.GetString(SR.SocketCloseReadReceivedData, socket.RemoteEndPoint)), ExceptionEventType);
- }
- }
- catch (TimeoutException timeoutException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new TimeoutException(
- SR.GetString(SR.SocketCloseReadTimeout, socket.RemoteEndPoint, readFinTimeout), timeoutException), ExceptionEventType);
- }
- // finally we call Close with whatever time is remaining
- ContinueClose(closeTimeoutHelper.RemainingTime());
- }
- public void ContinueClose(TimeSpan timeout)
- {
- // trace if we're effectively aborting
- if (timeout <= TimeSpan.Zero && DiagnosticUtility.ShouldTraceWarning)
- {
- TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.SocketConnectionAbortClose,
- SR.GetString(SR.TraceCodeSocketConnectionAbortClose), this);
- }
- socket.Close(TimeoutHelper.ToMilliseconds(timeout));
- lock (ThisLock)
- {
- // Abort could have been called on a separate thread and cleaned up
- // our buffers/completion here
- if (this.closeState != CloseState.Closed)
- {
- if (!this.asyncReadPending)
- {
- this.DisposeReadEventArgs();
- }
- if (!this.asyncWritePending)
- {
- this.DisposeWriteEventArgs();
- }
- }
- closeState = CloseState.Closed;
- }
- }
- public void Shutdown(TimeSpan timeout)
- {
- lock (ThisLock)
- {
- if (isShutdown)
- {
- return;
- }
- isShutdown = true;
- }
- try
- {
- socket.Shutdown(SocketShutdown.Send);
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertSendException(socketException, TimeSpan.MaxValue), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Undefined);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- throw;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- }
- void ThrowIfNotOpen()
- {
- if (closeState == CloseState.Closing || closeState == CloseState.Closed)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertObjectDisposedException(new ObjectDisposedException(
- this.GetType().ToString(), SR.GetString(SR.SocketConnectionDisposed)), TransferOperation.Undefined), ExceptionEventType);
- }
- }
- void ThrowIfClosed()
- {
- if (closeState == CloseState.Closed)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertObjectDisposedException(new ObjectDisposedException(
- this.GetType().ToString(), SR.GetString(SR.SocketConnectionDisposed)), TransferOperation.Undefined), ExceptionEventType);
- }
- }
- void TraceSocketInfo(Socket socket, int traceCode, string srString, string timeoutString)
- {
- if (DiagnosticUtility.ShouldTraceInformation)
- {
- Dictionary<string, string> values = new Dictionary<string, string>(4);
- values["State"] = this.closeState.ToString();
- if (timeoutString != null)
- {
- values["Timeout"] = timeoutString;
- }
- if (socket != null && this.closeState != CloseState.Closing)
- {
- if (socket.LocalEndPoint != null)
- {
- values["LocalEndpoint"] = socket.LocalEndPoint.ToString();
- }
- if (socket.RemoteEndPoint != null)
- {
- values["RemoteEndPoint"] = socket.RemoteEndPoint.ToString();
- }
- }
- TraceUtility.TraceEvent(TraceEventType.Information, traceCode, SR.GetString(srString), new DictionaryTraceRecord(values), this, null);
- }
- }
- bool TryGetEndpoints(out IPEndPoint localIPEndpoint, out IPEndPoint remoteIPEndpoint)
- {
- localIPEndpoint = null;
- remoteIPEndpoint = null;
- if (this.closeState == CloseState.Open)
- {
- try
- {
- remoteIPEndpoint = this.remoteEndpoint ?? (IPEndPoint)this.socket.RemoteEndPoint;
- localIPEndpoint = (IPEndPoint)this.socket.LocalEndPoint;
- }
- catch (Exception exception)
- {
- if (Fx.IsFatal(exception))
- {
- throw;
- }
- DiagnosticUtility.TraceHandledException(exception, TraceEventType.Warning);
- }
- }
- return localIPEndpoint != null && remoteIPEndpoint != null;
- }
- public object DuplicateAndClose(int targetProcessId)
- {
- object result = socket.DuplicateAndClose(targetProcessId);
- this.Abort(TraceEventType.Information);
- return result;
- }
- public object GetCoreTransport()
- {
- return socket;
- }
- public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
- {
- return new CompletedAsyncResult<bool>(true, callback, state);
- }
- public bool EndValidate(IAsyncResult result)
- {
- return CompletedAsyncResult<bool>.End(result);
- }
- Exception ConvertSendException(SocketException socketException, TimeSpan remainingTime)
- {
- return ConvertTransferException(socketException, this.sendTimeout, socketException,
- TransferOperation.Write, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, this, remainingTime);
- }
- Exception ConvertReceiveException(SocketException socketException, TimeSpan remainingTime)
- {
- return ConvertTransferException(socketException, this.receiveTimeout, socketException,
- TransferOperation.Read, this.aborted, this.timeoutErrorString, this.timeoutErrorTransferOperation, this, remainingTime);
- }
- internal static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException)
- {
- return ConvertTransferException(socketException, timeout, originalException,
- TransferOperation.Undefined, false, null, TransferOperation.Undefined, null, TimeSpan.MaxValue);
- }
- Exception ConvertObjectDisposedException(ObjectDisposedException originalException, TransferOperation transferOperation)
- {
- if (this.timeoutErrorString != null)
- {
- return ConvertTimeoutErrorException(originalException, transferOperation, this.timeoutErrorString, this.timeoutErrorTransferOperation);
- }
- else if (this.aborted)
- {
- return new CommunicationObjectAbortedException(SR.GetString(SR.SocketConnectionDisposed), originalException);
- }
- else
- {
- return originalException;
- }
- }
- static Exception ConvertTransferException(SocketException socketException, TimeSpan timeout, Exception originalException,
- TransferOperation transferOperation, bool aborted, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation,
- SocketConnection socketConnection, TimeSpan remainingTime)
- {
- if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
- {
- return new CommunicationObjectAbortedException(socketException.Message, socketException);
- }
- if (timeoutErrorString != null)
- {
- return ConvertTimeoutErrorException(originalException, transferOperation, timeoutErrorString, timeoutErrorTransferOperation);
- }
- TraceEventType exceptionEventType = socketConnection == null ? TraceEventType.Error : socketConnection.ExceptionEventType;
- // 10053 can occur due to our timeout sockopt firing, so map to TimeoutException in that case
- if (socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED &&
- remainingTime <= TimeSpan.Zero)
- {
- TimeoutException timeoutException = new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
- if (TD.TcpConnectionTimedOutIsEnabled())
- {
- if (socketConnection != null)
- {
- int socketid = (socketConnection != null && socketConnection.socket != null) ? socketConnection.socket.GetHashCode() : -1;
- TD.TcpConnectionTimedOut(socketid, socketConnection.RemoteEndpointAddress);
- }
- }
- if (DiagnosticUtility.ShouldTrace(exceptionEventType))
- {
- TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionTimedOut, GetEndpointString(SR.TcpConnectionTimedOut, timeout, null, socketConnection), timeoutException, null);
- }
- return timeoutException;
- }
- if (socketException.ErrorCode == UnsafeNativeMethods.WSAENETRESET ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAECONNABORTED ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAECONNRESET)
- {
- if (aborted)
- {
- return new CommunicationObjectAbortedException(SR.GetString(SR.TcpLocalConnectionAborted), originalException);
- }
- else
- {
- CommunicationException communicationException = new CommunicationException(SR.GetString(SR.TcpConnectionResetError, timeout), originalException);
- if (TD.TcpConnectionResetErrorIsEnabled())
- {
- if (socketConnection != null)
- {
- int socketId = (socketConnection.socket != null) ? socketConnection.socket.GetHashCode() : -1;
- TD.TcpConnectionResetError(socketId, socketConnection.RemoteEndpointAddress);
- }
- }
- if (DiagnosticUtility.ShouldTrace(exceptionEventType))
- {
- TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionResetError, GetEndpointString(SR.TcpConnectionResetError, timeout, null, socketConnection), communicationException, null);
- }
- return communicationException;
- }
- }
- else if (socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
- {
- TimeoutException timeoutException = new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout), originalException);
- if (DiagnosticUtility.ShouldTrace(exceptionEventType))
- {
- TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpConnectionTimedOut, GetEndpointString(SR.TcpConnectionTimedOut, timeout, null, socketConnection), timeoutException, null);
- }
- return timeoutException;
- }
- else
- {
- if (aborted)
- {
- return new CommunicationObjectAbortedException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException);
- }
- else
- {
- CommunicationException communicationException = new CommunicationException(SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message), originalException);
- if (DiagnosticUtility.ShouldTrace(exceptionEventType))
- {
- TraceUtility.TraceEvent(exceptionEventType, TraceCode.TcpTransferError, GetEndpointString(SR.TcpTransferError, TimeSpan.MinValue, socketException, socketConnection), communicationException, null);
- }
- return communicationException;
- }
- }
- }
- static Exception ConvertTimeoutErrorException(Exception originalException,
- TransferOperation transferOperation, string timeoutErrorString, TransferOperation timeoutErrorTransferOperation)
- {
- if (timeoutErrorString == null)
- {
- Fx.Assert("Argument timeoutErrorString must not be null.");
- }
- if (transferOperation == timeoutErrorTransferOperation)
- {
- return new TimeoutException(timeoutErrorString, originalException);
- }
- else
- {
- return new CommunicationException(timeoutErrorString, originalException);
- }
- }
- static string GetEndpointString(string sr, TimeSpan timeout, SocketException socketException, SocketConnection socketConnection)
- {
- IPEndPoint remoteEndpoint = null;
- IPEndPoint localEndpoint = null;
- bool haveEndpoints = socketConnection != null && socketConnection.TryGetEndpoints(out localEndpoint, out remoteEndpoint);
- if (string.Compare(sr, SR.TcpConnectionTimedOut, StringComparison.OrdinalIgnoreCase) == 0)
- {
- return haveEndpoints
- ? SR.GetString(SR.TcpConnectionTimedOutWithIP, timeout, localEndpoint, remoteEndpoint)
- : SR.GetString(SR.TcpConnectionTimedOut, timeout);
- }
- else if (string.Compare(sr, SR.TcpConnectionResetError, StringComparison.OrdinalIgnoreCase) == 0)
- {
- return haveEndpoints
- ? SR.GetString(SR.TcpConnectionResetErrorWithIP, timeout, localEndpoint, remoteEndpoint)
- : SR.GetString(SR.TcpConnectionResetError, timeout);
- }
- else
- {
- // sr == SR.TcpTransferError
- return haveEndpoints
- ? SR.GetString(SR.TcpTransferErrorWithIP, socketException.ErrorCode, socketException.Message, localEndpoint, remoteEndpoint)
- : SR.GetString(SR.TcpTransferError, socketException.ErrorCode, socketException.Message);
- }
- }
- public AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
- WaitCallback callback, object state)
- {
- ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
- bool abortWrite = true;
- try
- {
- if (TD.SocketAsyncWriteStartIsEnabled())
- {
- TraceWriteStart(size, true);
- }
- lock (ThisLock)
- {
- Fx.Assert(!this.asyncWritePending, "Called BeginWrite twice.");
- this.ThrowIfClosed();
- this.EnsureWriteEventArgs();
- SetImmediate(immediate);
- SetWriteTimeout(timeout, false);
- this.SetUserToken(this.asyncWriteEventArgs, this);
- this.asyncWritePending = true;
- this.asyncWriteCallback = callback;
- this.asyncWriteState = state;
- }
- this.asyncWriteEventArgs.SetBuffer(buffer, offset, size);
- if (socket.SendAsync(this.asyncWriteEventArgs))
- {
- abortWrite = false;
- return AsyncCompletionResult.Queued;
- }
- this.HandleSendAsyncCompleted();
- abortWrite = false;
- return AsyncCompletionResult.Completed;
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertSendException(socketException, TimeSpan.MaxValue), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- throw;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- finally
- {
- if (abortWrite)
- {
- this.AbortWrite();
- }
- }
- }
- public void EndWrite()
- {
- if (this.asyncWriteException != null)
- {
- this.AbortWrite();
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(this.asyncWriteException, ExceptionEventType);
- }
- lock (ThisLock)
- {
- if (!this.asyncWritePending)
- {
- throw Fx.AssertAndThrow("SocketConnection.EndWrite called with no write pending.");
- }
- this.SetUserToken(this.asyncWriteEventArgs, null);
- this.asyncWritePending = false;
- if (this.closeState == CloseState.Closed)
- {
- this.DisposeWriteEventArgs();
- }
- }
- }
- void OnSendAsync(object sender, SocketAsyncEventArgs eventArgs)
- {
- Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
- this.CancelSendTimer();
- try
- {
- this.HandleSendAsyncCompleted();
- Fx.Assert(eventArgs.BytesTransferred == this.asyncWriteEventArgs.Count, "The socket SendAsync did not send all the bytes.");
- }
- catch (SocketException socketException)
- {
- this.asyncWriteException = ConvertSendException(socketException, TimeSpan.MaxValue);
- }
- #pragma warning suppress 56500 // [....], transferring exception to caller
- catch (Exception exception)
- {
- if (Fx.IsFatal(exception))
- {
- throw;
- }
- this.asyncWriteException = exception;
- }
- this.FinishWrite();
- }
- void HandleSendAsyncCompleted()
- {
- if (this.asyncWriteEventArgs.SocketError == SocketError.Success)
- {
- return;
- }
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)this.asyncWriteEventArgs.SocketError));
- }
- // This method should be called inside ThisLock
- void DisposeWriteEventArgs()
- {
- if (this.asyncWriteEventArgs != null)
- {
- this.asyncWriteEventArgs.Completed -= onSocketSendCompleted;
- this.asyncWriteEventArgs.Dispose();
- }
- }
- void AbortWrite()
- {
- lock (ThisLock)
- {
- if (this.asyncWritePending)
- {
- if (this.closeState != CloseState.Closed)
- {
- this.SetUserToken(this.asyncWriteEventArgs, null);
- this.asyncWritePending = false;
- this.CancelSendTimer();
- }
- else
- {
- this.DisposeWriteEventArgs();
- }
- }
- }
- }
- void FinishWrite()
- {
- WaitCallback asyncWriteCallback = this.asyncWriteCallback;
- object asyncWriteState = this.asyncWriteState;
- this.asyncWriteState = null;
- this.asyncWriteCallback = null;
- asyncWriteCallback(asyncWriteState);
- }
- public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
- {
- // as per http://support.microsoft.com/default.aspx?scid=kb%3ben-us%3b201213
- // we shouldn't write more than 64K synchronously to a socket
- const int maxSocketWrite = 64 * 1024;
- ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- try
- {
- if (TD.SocketWriteStartIsEnabled())
- {
- TraceWriteStart(size, false);
- }
- SetImmediate(immediate);
- int bytesToWrite = size;
- while (bytesToWrite > 0)
- {
- SetWriteTimeout(timeoutHelper.RemainingTime(), true);
- size = Math.Min(bytesToWrite, maxSocketWrite);
- socket.Send(buffer, offset, size, SocketFlags.None);
- bytesToWrite -= size;
- offset += size;
- timeout = timeoutHelper.RemainingTime();
- }
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertSendException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Write);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- throw;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- }
- void TraceWriteStart(int size, bool async)
- {
- if (!async)
- {
- TD.SocketWriteStart(this.socket.GetHashCode(), size, this.RemoteEndpointAddress);
- }
- else
- {
- TD.SocketAsyncWriteStart(this.socket.GetHashCode(), size, this.RemoteEndpointAddress);
- }
- }
- public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
- {
- try
- {
- Write(buffer, offset, size, immediate, timeout);
- }
- finally
- {
- bufferManager.ReturnBuffer(buffer);
- }
- }
- public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
- {
- ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
- ThrowIfNotOpen();
- return ReadCore(buffer, offset, size, timeout, false);
- }
- int ReadCore(byte[] buffer, int offset, int size, TimeSpan timeout, bool closing)
- {
- int bytesRead = 0;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- try
- {
- SetReadTimeout(timeoutHelper.RemainingTime(), true, closing);
- bytesRead = socket.Receive(buffer, offset, size, SocketFlags.None);
- if (TD.SocketReadStopIsEnabled())
- {
- TraceSocketReadStop(bytesRead, false);
- }
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- ConvertReceiveException(socketException, timeoutHelper.RemainingTime()), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- throw;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- return bytesRead;
- }
- private void TraceSocketReadStop(int bytesRead, bool async)
- {
- if (!async)
- {
- TD.SocketReadStop((this.socket != null) ? this.socket.GetHashCode() : -1, bytesRead, this.RemoteEndpointAddress);
- }
- else
- {
- TD.SocketAsyncReadStop((this.socket != null) ? this.socket.GetHashCode() : -1, bytesRead, this.RemoteEndpointAddress);
- }
- }
- public virtual AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
- WaitCallback callback, object state)
- {
- ConnectionUtilities.ValidateBufferBounds(AsyncReadBufferSize, offset, size);
- this.ThrowIfNotOpen();
- return this.BeginReadCore(offset, size, timeout, callback, state);
- }
- AsyncCompletionResult BeginReadCore(int offset, int size, TimeSpan timeout,
- WaitCallback callback, object state)
- {
- bool abortRead = true;
- lock (ThisLock)
- {
- this.ThrowIfClosed();
- this.EnsureReadEventArgs();
- this.asyncReadState = state;
- this.asyncReadCallback = callback;
- this.SetUserToken(this.asyncReadEventArgs, this);
- this.asyncReadPending = true;
- this.SetReadTimeout(timeout, false, false);
- }
- try
- {
- if (socket.UseOnlyOverlappedIO)
- {
- // ReceiveAsync does not respect UseOnlyOverlappedIO but BeginReceive does.
- IAsyncResult result = socket.BeginReceive(AsyncReadBuffer, offset, size, SocketFlags.None, onReceiveCompleted, this);
- if (!result.CompletedSynchronously)
- {
- abortRead = false;
- return AsyncCompletionResult.Queued;
- }
- asyncReadSize = socket.EndReceive(result);
- }
- else
- {
- if (offset != this.asyncReadEventArgs.Offset ||
- size != this.asyncReadEventArgs.Count)
- {
- this.asyncReadEventArgs.SetBuffer(offset, size);
- }
- if (this.ReceiveAsync())
- {
- abortRead = false;
- return AsyncCompletionResult.Queued;
- }
- this.HandleReceiveAsyncCompleted();
- this.asyncReadSize = this.asyncReadEventArgs.BytesTransferred;
- }
- if (TD.SocketReadStopIsEnabled())
- {
- TraceSocketReadStop(asyncReadSize, true);
- }
- abortRead = false;
- return AsyncCompletionResult.Completed;
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertReceiveException(socketException, TimeSpan.MaxValue), ExceptionEventType);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- Exception exceptionToThrow = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
- if (object.ReferenceEquals(exceptionToThrow, objectDisposedException))
- {
- throw;
- }
- else
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
- }
- }
- finally
- {
- if (abortRead)
- {
- AbortRead();
- }
- }
- }
- [Fx.Tag.SecurityNote(Critical = "Uses a SecurityCritical method to suppress ExecutionContext flow when running in fullTrust.",
- Safe = "Safe because we're only suppressing the ExecutionContext if we're already in full trust.")]
- [SecuritySafeCritical]
- bool ReceiveAsync()
- {
- if (!PartialTrustHelpers.ShouldFlowSecurityContext)
- {
- if (!ExecutionContext.IsFlowSuppressed())
- {
- return ReceiveAsyncNoFlow();
- }
- }
- return this.socket.ReceiveAsync(this.asyncReadEventArgs);
- }
- [Fx.Tag.SecurityNote(Critical = "Suppresses execution context flow and restores it after invocation. Fulltrust async callbacks " +
- "will not have an ExecutionContext, LogicalCallcontext or SecurityContext and should not take dependency on them.")]
- [SecurityCritical]
- bool ReceiveAsyncNoFlow()
- {
- using (ExecutionContext.SuppressFlow())
- {
- return this.socket.ReceiveAsync(this.asyncReadEventArgs);
- }
- }
- void OnReceive(IAsyncResult result)
- {
- this.CancelReceiveTimer();
- if (result.CompletedSynchronously)
- {
- return;
- }
- try
- {
- this.asyncReadSize = socket.EndReceive(result);
- if (TD.SocketReadStopIsEnabled())
- {
- TraceSocketReadStop(this.asyncReadSize, true);
- }
- }
- catch (SocketException socketException)
- {
- this.asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue);
- }
- catch (ObjectDisposedException objectDisposedException)
- {
- this.asyncReadException = ConvertObjectDisposedException(objectDisposedException, TransferOperation.Read);
- }
- #pragma warning suppress 56500 // [....], transferring exception to caller
- catch (Exception exception)
- {
- if (Fx.IsFatal(exception))
- {
- throw;
- }
- this.asyncReadException = exception;
- }
- this.FinishRead();
- }
- void OnReceiveAsync(object sender, SocketAsyncEventArgs eventArgs)
- {
- Fx.Assert(eventArgs != null, "Argument 'eventArgs' cannot be NULL.");
- this.CancelReceiveTimer();
- try
- {
- this.HandleReceiveAsyncCompleted();
- this.asyncReadSize = eventArgs.BytesTransferred;
- if (TD.SocketReadStopIsEnabled())
- {
- TraceSocketReadStop(asyncReadSize, true);
- }
- }
- catch (SocketException socketException)
- {
- asyncReadException = ConvertReceiveException(socketException, TimeSpan.MaxValue);
- }
- #pragma warning suppress 56500 // [....], transferring exception to caller
- catch (Exception exception)
- {
- if (Fx.IsFatal(exception))
- {
- throw;
- }
- asyncReadException = exception;
- }
- FinishRead();
- }
- void HandleReceiveAsyncCompleted()
- {
- if (this.asyncReadEventArgs.SocketError == SocketError.Success)
- {
- return;
- }
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException((int)this.asyncReadEventArgs.SocketError));
- }
- void FinishRead()
- {
- WaitCallback asyncReadCallback = this.asyncReadCallback;
- object asyncReadState = this.asyncReadState;
- this.asyncReadState = null;
- this.asyncReadCallback = null;
- asyncReadCallback(asyncReadState);
- }
- // Both BeginRead/ReadAsync paths completed themselves. EndRead's only job is to deliver the result.
- public int EndRead()
- {
- if (this.asyncReadException != null)
- {
- AbortRead();
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(this.asyncReadException, ExceptionEventType);
- }
- lock (ThisLock)
- {
- if (!this.asyncReadPending)
- {
- throw Fx.AssertAndThrow("SocketConnection.EndRead called with no read pending.");
- }
- this.SetUserToken(this.asyncReadEventArgs, null);
- this.asyncReadPending = false;
-
- if (closeState == CloseState.Closed)
- {
- this.DisposeReadEventArgs();
- }
- }
- return this.asyncReadSize;
- }
- // This method should be called inside ThisLock
- void DisposeReadEventArgs()
- {
- if (this.asyncReadEventArgs != null)
- {
- this.asyncReadEventArgs.Completed -= onReceiveAsyncCompleted;
- this.asyncReadEventArgs.Dispose();
- }
- // We release the buffer only if there is no outstanding I/O
- this.TryReturnReadBuffer();
- }
- void TryReturnReadBuffer()
- {
- // The buffer must not be returned and nulled when an abort occurs. Since the buffer
- // is also accessed by higher layers, code that has not yet realized the stack is
- // aborted may be attempting to read from the buffer.
- if (this.readBuffer != null && !this.aborted)
- {
- this.connectionBufferPool.Return(this.readBuffer);
- this.readBuffer = null;
- }
- }
- void SetUserToken(SocketAsyncEventArgs args, object userToken)
- {
- // The socket args can be pinned by the overlapped callback. Ensure SocketConnection is
- // only pinned when there is outstanding IO.
- if (args != null)
- {
- args.UserToken = userToken;
- }
- }
- void SetImmediate(bool immediate)
- {
- if (immediate != this.noDelay)
- {
- lock (ThisLock)
- {
- ThrowIfNotOpen();
- socket.NoDelay = immediate;
- }
- this.noDelay = immediate;
- }
- }
- void SetReadTimeout(TimeSpan timeout, bool synchronous, bool closing)
- {
- if (synchronous)
- {
- CancelReceiveTimer();
- // 0 == infinite for winsock timeouts, so we should preempt and throw
- if (timeout <= TimeSpan.Zero)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType);
- }
- if (UpdateTimeout(this.receiveTimeout, timeout))
- {
- lock (ThisLock)
- {
- if (!closing || this.closeState != CloseState.Closing)
- {
- ThrowIfNotOpen();
- }
- this.socket.ReceiveTimeout = TimeoutHelper.ToMilliseconds(timeout);
- }
- this.receiveTimeout = timeout;
- }
- }
- else
- {
- this.receiveTimeout = timeout;
- if (timeout == TimeSpan.MaxValue)
- {
- CancelReceiveTimer();
- }
- else
- {
- ReceiveTimer.Set(timeout);
- }
- }
- }
- void SetWriteTimeout(TimeSpan timeout, bool synchronous)
- {
- if (synchronous)
- {
- CancelSendTimer();
- // 0 == infinite for winsock timeouts, so we should preempt and throw
- if (timeout <= TimeSpan.Zero)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
- new TimeoutException(SR.GetString(SR.TcpConnectionTimedOut, timeout)), ExceptionEventType);
- }
- if (UpdateTimeout(this.sendTimeout, timeout))
- {
- lock (ThisLock)
- {
- ThrowIfNotOpen();
- this.socket.SendTimeout = TimeoutHelper.ToMilliseconds(timeout);
- }
- this.sendTimeout = timeout;
- }
- }
- else
- {
- this.sendTimeout = timeout;
- if (timeout == TimeSpan.MaxValue)
- {
- CancelSendTimer();
- }
- else
- {
- SendTimer.Set(timeout);
- }
- }
- }
- bool UpdateTimeout(TimeSpan oldTimeout, TimeSpan newTimeout)
- {
- if (oldTimeout == newTimeout)
- {
- return false;
- }
- long threshold = oldTimeout.Ticks / 10;
- long delta = Math.Max(oldTimeout.Ticks, newTimeout.Ticks) - Math.Min(oldTimeout.Ticks, newTimeout.Ticks);
- return delta > threshold;
- }
- // This method should be called inside ThisLock
- void EnsureReadEventArgs()
- {
- if (this.asyncReadEventArgs == null)
- {
- // Init ReadAsync state
- if (onReceiveAsyncCompleted == null)
- {
- onReceiveAsyncCompleted = new EventHandler<SocketAsyncEventArgs>(OnReceiveAsyncCompleted);
- }
- this.asyncReadEventArgs = new SocketAsyncEventArgs();
- this.asyncReadEventArgs.SetBuffer(this.readBuffer, 0, this.readBuffer.Length);
- this.asyncReadEventArgs.Completed += onReceiveAsyncCompleted;
- }
- }
- // This method should be called inside ThisLock
- void EnsureWriteEventArgs()
- {
- if (this.asyncWriteEventArgs == null)
- {
- // Init SendAsync state
- if (onSocketSendCompleted == null)
- {
- onSocketSendCompleted = new EventHandler<SocketAsyncEventArgs>(OnSendAsyncCompleted);
- }
- this.asyncWriteEventArgs = new SocketAsyncEventArgs();
- this.asyncWriteEventArgs.Completed += onSocketSendCompleted;
- }
- }
- enum CloseState
- {
- Open,
- Closing,
- Closed,
- }
- enum TransferOperation
- {
- Write,
- Read,
- Undefined,
- }
- }
- class SocketConnectionInitiator : IConnectionInitiator
- {
- int bufferSize;
- ConnectionBufferPool connectionBufferPool;
- public SocketConnectionInitiator(int bufferSize)
- {
- this.bufferSize = bufferSize;
- this.connectionBufferPool = new ConnectionBufferPool(bufferSize);
- }
- IConnection CreateConnection(Socket socket)
- {
- return new SocketConnection(socket, this.connectionBufferPool, false);
- }
- public static Exception ConvertConnectException(SocketException socketException, Uri remoteUri, TimeSpan timeSpent, Exception innerException)
- {
- if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
- {
- return new CommunicationObjectAbortedException(socketException.Message, socketException);
- }
- if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRNOTAVAIL ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAECONNREFUSED ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAENETDOWN ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAENETUNREACH ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTDOWN ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAEHOSTUNREACH ||
- socketException.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
- {
- if (timeSpent == TimeSpan.MaxValue)
- {
- return new EndpointNotFoundException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
- }
- else
- {
- return new EndpointNotFoundException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException);
- }
- }
- else if (socketException.ErrorCode == UnsafeNativeMethods.WSAENOBUFS)
- {
- return new InsufficientMemoryException(SR.GetString(SR.TcpConnectNoBufs), innerException);
- }
- else if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_NOT_ENOUGH_MEMORY ||
- socketException.ErrorCode == UnsafeNativeMethods.ERROR_NO_SYSTEM_RESOURCES ||
- socketException.ErrorCode == UnsafeNativeMethods.ERROR_OUTOFMEMORY)
- {
- return new InsufficientMemoryException(SR.GetString(SR.InsufficentMemory), socketException);
- }
- else
- {
- if (timeSpent == TimeSpan.MaxValue)
- {
- return new CommunicationException(SR.GetString(SR.TcpConnectError, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message), innerException);
- }
- else
- {
- return new CommunicationException(SR.GetString(SR.TcpConnectErrorWithTimeSpan, remoteUri.AbsoluteUri, socketException.ErrorCode, socketException.Message, timeSpent), innerException);
- }
- }
- }
- static IPAddress[] GetIPAddresses(Uri uri)
- {
- if (uri.HostNameType == UriHostNameType.IPv4 ||
- uri.HostNameType == UriHostNameType.IPv6)
- {
- IPAddress ipAddress = IPAddress.Parse(uri.DnsSafeHost);
- return new IPAddress[] { ipAddress };
- }
- IPHostEntry hostEntry = null;
- try
- {
- hostEntry = DnsCache.Resolve(uri);
- }
- catch (SocketException socketException)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host), socketException));
- }
- if (hostEntry.AddressList.Length == 0)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new EndpointNotFoundException(SR.GetString(SR.UnableToResolveHost, uri.Host)));
- }
- return hostEntry.AddressList;
- }
- static TimeoutException CreateTimeoutException(Uri uri, TimeSpan timeout, IPAddress[] addresses, int invalidAddressCount,
- SocketException innerException)
- {
- StringBuilder addressStringBuilder = new StringBuilder();
- for (int i = 0; i < invalidAddressCount; i++)
- {
- if (addresses[i] == null)
- {
- continue;
- }
- if (addressStringBuilder.Length > 0)
- {
- addressStringBuilder.Append(", ");
- }
- addressStringBuilder.Append(addresses[i].ToString());
- }
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(
- SR.GetString(SR.TcpConnectingToViaTimedOut, uri.AbsoluteUri, timeout.ToString(),
- invalidAddressCount, addresses.Length, addressStringBuilder.ToString()), innerException));
- }
- public IConnection Connect(Uri uri, TimeSpan timeout)
- {
- if (DiagnosticUtility.ShouldTraceInformation)
- {
- TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.InitiatingTcpConnection,
- SR.GetString(SR.TraceCodeInitiatingTcpConnection),
- new StringTraceRecord("Uri", uri.ToString()), this, null);
- }
- int port = uri.Port;
- IPAddress[] addresses = SocketConnectionInitiator.GetIPAddresses(uri);
- Socket socket = null;
- SocketException lastException = null;
- if (port == -1)
- {
- port = TcpUri.DefaultPort;
- }
- int invalidAddressCount = 0;
- TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
- for (int i = 0; i < addresses.Length; i++)
- {
- if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
- }
- AddressFamily addressFamily = addresses[i].AddressFamily;
- if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6)
- {
- addresses[i] = null; // disregard for exception attempt purposes
- continue;
- }
- DateTime connectStartTime = DateTime.UtcNow;
- try
- {
- socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
- socket.Connect(new IPEndPoint(addresses[i], port));
- lastException = null;
- break;
- }
- catch (SocketException socketException)
- {
- invalidAddressCount++;
- SocketConnectionInitiator.TraceConnectFailure(socket, socketException, uri, DateTime.UtcNow - connectStartTime);
- lastException = socketException;
- socket.Close();
- }
- }
- if (socket == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
- }
- if (lastException != null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- SocketConnectionInitiator.ConvertConnectException(lastException, uri,
- timeoutHelper.ElapsedTime(), lastException));
- }
- return CreateConnection(socket);
- }
- public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
- {
- if (DiagnosticUtility.ShouldTraceInformation)
- {
- TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.InitiatingTcpConnection,
- SR.GetString(SR.TraceCodeInitiatingTcpConnection),
- new StringTraceRecord("Uri", uri.ToString()), this, null);
- }
- return new ConnectAsyncResult(uri, timeout, callback, state);
- }
- public IConnection EndConnect(IAsyncResult result)
- {
- Socket socket = ConnectAsyncResult.End(result);
- return CreateConnection(socket);
- }
- public static void TraceConnectFailure(Socket socket, SocketException socketException, Uri remoteUri,
- TimeSpan timeSpentInConnect)
- {
- if (DiagnosticUtility.ShouldTraceWarning)
- {
- Exception traceException = ConvertConnectException(socketException, remoteUri, timeSpentInConnect, socketException);
- TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.TcpConnectError,
- SR.GetString(SR.TraceCodeTcpConnectError), socket, traceException);
- }
- }
- class ConnectAsyncResult : AsyncResult
- {
- IPAddress[] addresses;
- int currentIndex;
- int port;
- SocketException lastException;
- TimeSpan timeout;
- TimeoutHelper timeoutHelper;
- int invalidAddressCount;
- DateTime connectStartTime;
- Socket socket;
- Uri uri;
- static Action<object> startConnectCallback;
- static AsyncCallback onConnect = Fx.ThunkCallback(new AsyncCallback(OnConnect));
- public ConnectAsyncResult(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
- : base(callback, state)
- {
- this.uri = uri;
- addresses = SocketConnectionInitiator.GetIPAddresses(uri);
- port = uri.Port;
- if (port == -1)
- {
- port = TcpUri.DefaultPort;
- }
- currentIndex = 0;
- this.timeout = timeout;
- this.timeoutHelper = new TimeoutHelper(timeout);
- if (Thread.CurrentThread.IsThreadPoolThread)
- {
- if (StartConnect())
- {
- base.Complete(true);
- }
- }
- else
- {
- // If we're not on a threadpool thread, then we need to post a callback to start our accepting loop
- // Otherwise if the calling thread aborts then the async I/O will get inadvertantly cancelled
- if (startConnectCallback == null)
- {
- startConnectCallback = StartConnectCallback;
- }
- ActionItem.Schedule(startConnectCallback, this);
- }
- }
- static void StartConnectCallback(object state)
- {
- ConnectAsyncResult connectAsyncResult = (ConnectAsyncResult)state;
- bool completeSelf = false;
- Exception completionException = null;
- try
- {
- completeSelf = connectAsyncResult.StartConnect();
- }
- #pragma warning suppress 56500 // covered by FxCOP
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- {
- throw;
- }
- completeSelf = true;
- completionException = e;
- }
- if (completeSelf)
- {
- connectAsyncResult.Complete(false, completionException);
- }
- }
- bool StartConnect()
- {
- while (currentIndex < addresses.Length)
- {
- if (timeoutHelper.RemainingTime() == TimeSpan.Zero)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- CreateTimeoutException(uri, timeoutHelper.OriginalTimeout, addresses, invalidAddressCount, lastException));
- }
- AddressFamily addressFamily = addresses[currentIndex].AddressFamily;
- if (addressFamily == AddressFamily.InterNetworkV6 && !Socket.OSSupportsIPv6)
- {
- addresses[currentIndex++] = null; // disregard for exception attempt purposes
- continue;
- }
- this.connectStartTime = DateTime.UtcNow;
- try
- {
- IPEndPoint ipEndPoint = new IPEndPoint(addresses[currentIndex], port);
- this.socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
- IAsyncResult result = socket.BeginConnect(ipEndPoint, onConnect, this);
- if (!result.CompletedSynchronously)
- {
- return false;
- }
- socket.EndConnect(result);
- return true;
- }
- catch (SocketException socketException)
- {
- invalidAddressCount++;
- this.TraceConnectFailure(socketException);
- lastException = socketException;
- currentIndex++;
- }
- }
- if (socket == null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- new EndpointNotFoundException(SR.GetString(SR.NoIPEndpointsFoundForHost, uri.Host)));
- }
- Fx.Assert(lastException != null, "StartConnect: Can't get here without an exception.");
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- SocketConnectionInitiator.ConvertConnectException(lastException, uri,
- timeoutHelper.ElapsedTime(), lastException));
- }
- void TraceConnectFailure(SocketException exception)
- {
- SocketConnectionInitiator.TraceConnectFailure(this.socket, exception, uri, DateTime.UtcNow - connectStartTime);
- this.socket.Close();
- }
- static void OnConnect(IAsyncResult result)
- {
- if (result.CompletedSynchronously)
- {
- return;
- }
- bool completeSelf = false;
- Exception completionException = null;
- ConnectAsyncResult thisPtr = (ConnectAsyncResult)result.AsyncState;
- try
- {
- thisPtr.socket.EndConnect(result);
- completeSelf = true;
- }
- catch (SocketException socketException)
- {
- thisPtr.TraceConnectFailure(socketException);
- thisPtr.lastException = socketException;
- thisPtr.currentIndex++;
- try
- {
- completeSelf = thisPtr.StartConnect();
- }
- #pragma warning suppress 56500 // [....], transferring exception to another thread
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- {
- throw;
- }
- completeSelf = true;
- completionException = e;
- }
- }
- if (completeSelf)
- {
- thisPtr.Complete(false, completionException);
- }
- }
- public static Socket End(IAsyncResult result)
- {
- ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
- return thisPtr.socket;
- }
- }
- }
- internal interface ISocketListenerSettings
- {
- int BufferSize { get; }
- bool TeredoEnabled { get; }
- int ListenBacklog { get; }
- }
- class SocketConnectionListener : IConnectionListener
- {
- IPEndPoint localEndpoint;
- bool isDisposed;
- bool isListening;
- Socket listenSocket;
- ISocketListenerSettings settings;
- bool useOnlyOverlappedIO;
- ConnectionBufferPool connectionBufferPool;
- SocketAsyncEventArgsPool socketAsyncEventArgsPool;
- public SocketConnectionListener(Socket listenSocket, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
- : this(settings, useOnlyOverlappedIO)
- {
- this.listenSocket = listenSocket;
- }
- public SocketConnectionListener(IPEndPoint localEndpoint, ISocketListenerSettings settings, bool useOnlyOverlappedIO)
- : this(settings, useOnlyOverlappedIO)
- {
- this.localEndpoint = localEndpoint;
- }
- SocketConnectionListener(ISocketListenerSettings settings, bool useOnlyOverlappedIO)
- {
- Fx.Assert(settings != null, "Input settings should not be null");
- this.settings = settings;
- this.useOnlyOverlappedIO = useOnlyOverlappedIO;
- this.connectionBufferPool = new ConnectionBufferPool(settings.BufferSize);
- }
- object ThisLock
- {
- get { return this; }
- }
- public IAsyncResult BeginAccept(AsyncCallback callback, object state)
- {
- return new AcceptAsyncResult(this, callback, state);
- }
- SocketAsyncEventArgs TakeSocketAsyncEventArgs()
- {
- return this.socketAsyncEventArgsPool.Take();
- }
- void ReturnSocketAsyncEventArgs(SocketAsyncEventArgs socketAsyncEventArgs)
- {
- Fx.Assert(socketAsyncEventArgsPool != null, "The socketAsyncEventArgsPool should not be null");
- this.socketAsyncEventArgsPool.Return(socketAsyncEventArgs);
- }
- // This is the buffer size that is used by the System.Net for accepting new connections
- static int GetAcceptBufferSize(Socket listenSocket)
- {
- return (listenSocket.LocalEndPoint.Serialize().Size + 16) * 2;
- }
- bool InternalBeginAccept(Func<Socket, bool> acceptAsyncFunc)
- {
- lock (ThisLock)
- {
- if (isDisposed)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(this.GetType().ToString(), SR.GetString(SR.SocketListenerDisposed)));
- }
- if (!isListening)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SocketListenerNotListening)));
- }
- return acceptAsyncFunc(listenSocket);
- }
- }
- public IConnection EndAccept(IAsyncResult result)
- {
- Socket socket = AcceptAsyncResult.End(result);
- if (socket == null)
- return null;
- if (useOnlyOverlappedIO)
- {
- socket.UseOnlyOverlappedIO = true;
- }
- return new SocketConnection(socket, this.connectionBufferPool, false);
- }
- public void Dispose()
- {
- lock (ThisLock)
- {
- if (!isDisposed)
- {
- if (listenSocket != null)
- {
- listenSocket.Close();
- }
- if (this.socketAsyncEventArgsPool != null)
- {
- this.socketAsyncEventArgsPool.Close();
- }
- isDisposed = true;
- }
- }
- }
- public void Listen()
- {
- // If you call listen() on a port, then kill the process, then immediately start a new process and
- // try to listen() on the same port, you sometimes get WSAEADDRINUSE. Even if nothing was accepted.
- // Ports don't immediately free themselves on process shutdown. We call listen() in a loop on a delay
- // for a few iterations for this reason.
- //
- TimeSpan listenTimeout = TimeSpan.FromSeconds(1);
- BackoffTimeoutHelper backoffHelper = new BackoffTimeoutHelper(listenTimeout);
- lock (ThisLock)
- {
- if (this.listenSocket != null)
- {
- this.listenSocket.Listen(settings.ListenBacklog);
- isListening = true;
- }
- while (!isListening)
- {
- try
- {
- this.listenSocket = new Socket(localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
- if (localEndpoint.AddressFamily == AddressFamily.InterNetworkV6 && settings.TeredoEnabled)
- {
- this.listenSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)23, 10);
- }
- this.listenSocket.Bind(localEndpoint);
- this.listenSocket.Listen(settings.ListenBacklog);
- isListening = true;
- }
- catch (SocketException socketException)
- {
- bool retry = false;
- if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE)
- {
- if (!backoffHelper.IsExpired())
- {
- backoffHelper.WaitAndBackoff();
- retry = true;
- }
- }
- if (!retry)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
- SocketConnectionListener.ConvertListenException(socketException, this.localEndpoint));
- }
- }
- }
- this.socketAsyncEventArgsPool = new SocketAsyncEventArgsPool(GetAcceptBufferSize(this.listenSocket));
- }
- }
- public static Exception ConvertListenException(SocketException socketException, IPEndPoint localEndpoint)
- {
- if (socketException.ErrorCode == UnsafeNativeMethods.ERROR_INVALID_HANDLE)
- {
- return new CommunicationObjectAbortedException(socketException.Message, socketException);
- }
- if (socketException.ErrorCode == UnsafeNativeMethods.WSAEADDRINUSE)
- {
- return new AddressAlreadyInUseException(SR.GetString(SR.TcpAddressInUse, localEndpoint.ToString()), socketException);
- }
- else
- {
- return new CommunicationException(
- SR.GetString(SR.TcpListenError, socketException.ErrorCode, socketException.Message, localEndpoint.ToString()),
- socketException);
- }
- }
- class AcceptAsyncResult : AsyncResult
- {
- SocketConnectionListener listener;
- Socket socket;
- SocketAsyncEventArgs socketAsyncEventArgs;
- static Action<object> startAccept;
- EventTraceActivity eventTraceActivity;
- //
- static EventHandler<SocketAsyncEventArgs> acceptAsyncCompleted = new EventHandler<SocketAsyncEventArgs>(AcceptAsyncCompleted);
- static Action<AsyncResult, Exception> onCompleting = new Action<AsyncResult, Exception>(OnInternalCompleting);
- public AcceptAsyncResult(SocketConnectionListener listener, AsyncCallback callback, object state)
- : base(callback, state)
- {
- if (TD.SocketAcceptEnqueuedIsEnabled())
- {
- TD.SocketAcceptEnqueued(this.EventTraceActivity);
- }
- Fx.Assert(listener != null, "listener should not be null");
- this.listener = listener;
- this.socketAsyncEventArgs = listener.TakeSocketAsyncEventArgs();
- this.socketAsyncEventArgs.UserToken = this;
- this.socketAsyncEventArgs.Completed += acceptAsyncCompleted;
- this.OnCompleting = onCompleting;
- // If we're going to start up the thread pool eventually anyway, avoid using RegisterWaitForSingleObject
- if (!Thread.CurrentThread.IsThreadPoolThread)
- {
- if (startAccept == null)
- {
- startAccept = new Action<object>(StartAccept);
- }
- ActionItem.Schedule(startAccept, this);
- }
- else
- {
- bool completeSelf;
- bool success = false;
- try
- {
- completeSelf = StartAccept();
- success = true;
- }
- finally
- {
- if (!success)
- {
- // Return the args when an exception is thrown
- ReturnSocketAsyncEventArgs();
- }
- }
- if (completeSelf)
- {
- base.Complete(true);
- }
- }
- }
- public EventTraceActivity EventTraceActivity
- {
- get
- {
- if (this.eventTraceActivity == null)
- {
- this.eventTraceActivity = new EventTraceActivity();
- }
- return this.eventTraceActivity;
- }
- }
- static void StartAccept(object state)
- {
- AcceptAsyncResult thisPtr = (AcceptAsyncResult)state;
- Exception completionException = null;
- bool completeSelf;
- try
- {
- completeSelf = thisPtr.StartAccept();
- }
- #pragma warning suppress 56500 // [....], transferring exception to another thread
- catch (Exception e)
- {
- if (Fx.IsFatal(e))
- {
- throw;
- }
- completeSelf = true;
- completionException = e;
- }
- if (completeSelf)
- {
- thisPtr.Complete(false, completionException);
- }
- }
- bool StartAccept()
- {
- while (true)
- {
- try
- {
- return listener.InternalBeginAccept(DoAcceptAsync);
- }
- catch (SocketException socketException)
- {
- if (ShouldAcceptRecover(socketException))
- {
- continue;
- }
- else
- {
- throw;
- }
- }
- }
- }
- static bool ShouldAcceptRecover(SocketException exception)
- {
- return (
- (exception.ErrorCode == UnsafeNativeMethods.WSAECONNRESET) ||
- (exception.ErrorCode == UnsafeNativeMethods.WSAEMFILE) ||
- (exception.ErrorCode == UnsafeNativeMethods.WSAENOBUFS) ||
- (exception.ErrorCode == UnsafeNativeMethods.WSAETIMEDOUT)
- );
- }
- // Return true means completed synchronously
- bool DoAcceptAsync(Socket listenSocket)
- {
- SocketAsyncEventArgsPool.CleanupAcceptSocket(this.socketAsyncEventArgs);
- if (listenSocket.AcceptAsync(this.socketAsyncEventArgs))
- {
- // AcceptAsync returns true to indicate that the I/O operation is pending (asynchronous)
- return false;
- }
- Exception exception = HandleAcceptAsyncCompleted();
- if (exception != null)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
- }
- return true;
- }
- static void AcceptAsyncCompleted(object sender, SocketAsyncEventArgs e)
- {
- AcceptAsyncResult thisPtr = (AcceptAsyncResult)e.UserToken;
- Fx.Assert(thisPtr.socketAsyncEventArgs == e, "Got wrong socketAsyncEventArgs");
- Exception completionException = thisPtr.HandleAcceptAsyncCompleted();
- if (completionException != null && ShouldAcceptRecover((SocketException)completionException))
- {
- DiagnosticUtility.TraceHandledException(completionException, TraceEventType.Warning);
- StartAccept(thisPtr);
- return;
- }
- thisPtr.Complete(false, completionException);
- }
- static void OnInternalCompleting(AsyncResult result, Exception exception)
- {
- AcceptAsyncResult thisPtr = result as AcceptAsyncResult;
- if (TD.SocketAcceptedIsEnabled())
- {
- int hashCode = thisPtr.socket != null ? thisPtr.socket.GetHashCode() : -1;
- if (hashCode != -1)
- {
- TD.SocketAccepted(
- thisPtr.EventTraceActivity,
- thisPtr.listener != null ? thisPtr.listener.GetHashCode() : -1,
- hashCode);
- }
- else
- {
- TD.SocketAcceptClosed(thisPtr.EventTraceActivity);
- }
- }
- Fx.Assert(result != null, "Wrong async result has been passed in to OnInternalCompleting");
- thisPtr.ReturnSocketAsyncEventArgs();
- }
- void ReturnSocketAsyncEventArgs()
- {
- if (this.socketAsyncEventArgs != null)
- {
- this.socketAsyncEventArgs.UserToken = null;
- this.socketAsyncEventArgs.Completed -= acceptAsyncCompleted;
- this.listener.ReturnSocketAsyncEventArgs(this.socketAsyncEventArgs);
- this.socketAsyncEventArgs = null;
- }
- }
- Exception HandleAcceptAsyncCompleted()
- {
- Exception completionException = null;
- if (this.socketAsyncEventArgs.SocketError == SocketError.Success)
- {
- this.socket = this.socketAsyncEventArgs.AcceptSocket;
- this.socketAsyncEventArgs.AcceptSocket = null;
- }
- else
- {
- completionException = new SocketException((int)this.socketAsyncEventArgs.SocketError);
- }
- return completionException;
- }
- public static Socket End(IAsyncResult result)
- {
- AcceptAsyncResult thisPtr = AsyncResult.End<AcceptAsyncResult>(result);
- return thisPtr.socket;
- }
- }
- }
- }
|