-
Notifications
You must be signed in to change notification settings - Fork 0
Add extensions for Socket and TcpClient #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /// @file | ||
| /// @copyright Copyright (c) 2026 SafeTwice S.L. All rights reserved. | ||
| /// @license See LICENSE.txt | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace Utilities.DotNet.Network | ||
| { | ||
| /// <summary> | ||
| /// Utility class providing extension methods for the <see cref="Socket"/> class. | ||
| /// </summary> | ||
| public static class SocketExtensions | ||
| { | ||
| //=========================================================================== | ||
| // PUBLIC METHODS | ||
| //=========================================================================== | ||
|
|
||
| /// <summary> | ||
| /// Establishes a connection to a remote host. | ||
| /// </summary> | ||
| /// <param name="socket">Socket used to establish connection.</param> | ||
| /// <param name="address">The IPAddress of the remote host to connect to.</param> | ||
| /// <param name="port">The port on the remote host to connect to.</param> | ||
| /// <param name="timeout">The number of milliseconds to wait for connection to be established, | ||
| /// or <see cref="Timeout.Infinite"/> to wait indefinitely.</param> | ||
| /// <exception cref="SocketException">An error occurred when accessing the socket.</exception> | ||
| /// <exception cref="System.ObjectDisposedException">The <see cref="Socket"/> has been disposed.</exception> | ||
| /// <exception cref="System.Security.SecurityException">A caller higher in the call stack does not have permission for the requested operation.</exception> | ||
| /// <exception cref="System.InvalidOperationException">The <see cref="Socket"/> has been placed in a listening state by calling <see cref="Socket.Listen(int)"/>.</exception> | ||
| public static void Connect( this Socket socket, IPAddress address, int port, int timeout ) | ||
| { | ||
| if( timeout == Timeout.Infinite ) | ||
| { | ||
| socket.Connect( address, port ); | ||
| } | ||
| else | ||
| { | ||
| Task connectTask; | ||
|
|
||
| try | ||
| { | ||
| connectTask = socket.ConnectAsync( address, port ); | ||
|
|
||
| if( !connectTask.Wait( timeout ) ) | ||
| { | ||
| socket.Close(); | ||
| throw new SocketException( (int) SocketError.TimedOut ); | ||
| } | ||
|
Comment on lines
+47
to
+53
|
||
| } | ||
| catch( AggregateException ex ) | ||
| { | ||
| socket.Close(); | ||
| throw ex.InnerException ?? ex; | ||
| } | ||
| catch( Exception ) | ||
| { | ||
| socket.Close(); | ||
| throw; | ||
| } | ||
|
|
||
| Debug.Assert( !connectTask.IsFaulted ); | ||
| Debug.Assert( socket.Connected ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| /// @file | ||
| /// @copyright Copyright (c) 2026 SafeTwice S.L. All rights reserved. | ||
| /// @license See LICENSE.txt | ||
|
|
||
| using System; | ||
| using System.Diagnostics; | ||
| using System.Net; | ||
| using System.Net.Sockets; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|
|
||
| namespace Utilities.DotNet.Network | ||
| { | ||
| /// <summary> | ||
| /// Utility class providing extension methods for the <see cref="TcpClient"/> class. | ||
| /// </summary> | ||
| public static class TcpClientExtensions | ||
| { | ||
| //=========================================================================== | ||
| // PUBLIC METHODS | ||
| //=========================================================================== | ||
|
|
||
| /// <summary> | ||
| /// Establishes a connection to a remote TCP host. | ||
| /// </summary> | ||
| /// <param name="client">TCP client used to establish connection.</param> | ||
| /// <param name="address">The IPAddress of the remote host to connect to.</param> | ||
| /// <param name="port">The port on the remote host to connect to.</param> | ||
| /// <param name="timeout">The number of milliseconds to wait for connection to be established, | ||
| /// or <see cref="Timeout.Infinite"/> to wait indefinitely.</param> | ||
| /// <exception cref="SocketException">An error occurred when accessing the socket.</exception> | ||
| /// <exception cref="ObjectDisposedException">The <see cref="TcpClient"/> has been disposed.</exception> | ||
| public static void Connect( this TcpClient client, IPAddress address, int port, int timeout ) | ||
| { | ||
| if( timeout == Timeout.Infinite ) | ||
| { | ||
| client.Connect( address, port ); | ||
| } | ||
| else | ||
| { | ||
| Task connectTask; | ||
|
|
||
| try | ||
| { | ||
| connectTask = client.ConnectAsync( address, port ); | ||
|
|
||
| if( !connectTask.Wait( timeout ) ) | ||
| { | ||
|
Comment on lines
+33
to
+48
|
||
| client.Close(); | ||
| throw new SocketException( (int) SocketError.TimedOut ); | ||
| } | ||
|
Comment on lines
+45
to
+51
|
||
| } | ||
| catch( AggregateException ex ) | ||
| { | ||
| client.Close(); | ||
| throw ex.InnerException ?? ex; | ||
| } | ||
|
jgonzalez-stw marked this conversation as resolved.
|
||
| catch( Exception ) | ||
| { | ||
| client.Close(); | ||
| throw; | ||
| } | ||
|
|
||
| Debug.Assert( !connectTask.IsFaulted ); | ||
| Debug.Assert( client.Connected ); | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
timeoutis only treated specially forTimeout.Infinite; any other negative value will causeconnectTask.Wait(timeout)to throwArgumentOutOfRangeException, which is then caught and triggerssocket.Close(). Consider validatingtimeoutup front (e.g., allow -1 or >= 0) and throwingArgumentOutOfRangeExceptionwithout closing the socket for invalid input.