1 // 2 // Copyright (c) 2010-2024 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 using System.Net; 11 using System.Net.Sockets; 12 using Antmicro.Migrant; 13 using Antmicro.Renode.Core; 14 using Antmicro.Renode.Utilities; 15 using Antmicro.Renode.Exceptions; 16 17 namespace Antmicro.Renode.Sockets 18 { 19 public class SocketsManager : IDisposable 20 { SocketsManager()21 static SocketsManager() 22 { 23 Instance = new SocketsManager(); 24 sockets = new List<SocketInstance>(); 25 } 26 Dispose()27 public void Dispose() 28 { 29 foreach(var socketInstance in sockets) 30 { 31 socketInstance.Dispose(); 32 } 33 } 34 CleanUp()35 public void CleanUp() 36 { 37 sockets = new List<SocketInstance>(); 38 } 39 List()40 public string[,] List() 41 { 42 var table = new Table().AddRow("Owner", "Type", "EndPoint", "Bound", "Connected"); 43 table.AddRows(sockets, x => x.Owner.ToString(), x => x.Type.ToString(), x => x.EndPoint, x => x.IsBound.ToString(), x => x.IsConnected.ToString()); 44 return table.ToArray(); 45 } 46 AcquireSocket(IEmulationElement owner, AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, EndPoint endpoint, string nameAppendix = R, int? listeningBacklog = null, int connectingTimeout = 0, int receiveTimeout = 0, int sendTimeout = 0, bool asClient = false, bool noDelay = true)47 public Socket AcquireSocket(IEmulationElement owner, AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, EndPoint endpoint, string nameAppendix = "", int? listeningBacklog = null, int connectingTimeout = 0, int receiveTimeout = 0, int sendTimeout = 0, bool asClient = false, bool noDelay = true) 48 { 49 var s = new SocketInstance(owner, addressFamily, socketType, protocolType, endpoint, nameAppendix: nameAppendix, asClient: asClient, noDelay: noDelay, listeningBacklog: listeningBacklog); 50 sockets.Add(s); 51 return s.socket; 52 } 53 TryDropSocket(Socket socket)54 public bool TryDropSocket(Socket socket) 55 { 56 SocketInstance socketInstance = sockets.Where(x => x.socket == socket).FirstOrDefault(); 57 if(socketInstance != null) 58 { 59 sockets.Remove(socketInstance); 60 socketInstance.Dispose(); 61 return true; 62 } 63 return false; 64 } 65 66 [Transient] 67 private static List<SocketInstance> sockets; 68 69 public static SocketsManager Instance { get; private set; } 70 71 class SocketInstance : IDisposable 72 { SocketInstance(IEmulationElement owner, AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, EndPoint endpoint, string nameAppendix = R, int? listeningBacklog = null, bool asClient = false, bool noDelay = true)73 public SocketInstance(IEmulationElement owner, AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, EndPoint endpoint, string nameAppendix = "", int? listeningBacklog = null, bool asClient = false, bool noDelay = true) 74 { 75 string name; 76 if(!EmulationManager.Instance.CurrentEmulation.TryGetEmulationElementName((object)owner, out name)) 77 { 78 name = owner?.ToString() ?? ""; // If name is not obtainable, use the peripheral name 79 } 80 ownerName = String.Format("{0}{1}{2}", name, name.Length == 0 ? "" : ":", nameAppendix); 81 socket = new Socket(addressFamily, socketType, protocolType); 82 if(protocolType == ProtocolType.Tcp) 83 { 84 socket.NoDelay = noDelay; 85 } 86 this.endpoint = endpoint.ToString(); 87 try 88 { 89 if(asClient) 90 { 91 socket.Connect(endpoint); 92 } 93 else 94 { 95 socket.Bind(endpoint); 96 socket.Listen(listeningBacklog ?? 0); 97 } 98 } 99 catch(SocketException e) 100 { 101 throw new RecoverableException($"Unable to create '{this.endpoint}' socket:[{e.SocketErrorCode}] {e.Message}"); 102 } 103 } 104 Dispose()105 public void Dispose() 106 { 107 try 108 { 109 if(socket.Connected) 110 { 111 socket.Shutdown(SocketShutdown.Both); 112 } 113 } 114 finally 115 { 116 socket.Close(); 117 } 118 119 socket.Dispose(); 120 } 121 122 public string EndPoint => endpoint; 123 public bool IsConnected => socket.Connected; 124 public bool IsBound => socket.IsBound; 125 public SocketType Type => socket.SocketType; 126 public string Owner => ownerName; 127 128 private string ownerName; 129 private string endpoint; 130 public Socket socket; 131 } 132 } 133 } 134