private void onConnectionDropped(Connection conn, Connection.DropReason reason) { ROS.Debug()($"[{ThisNode.Name}] TransportPublisherLink: onConnectionDropped from remote {conn.RemoteString} with reason {reason.ToString()}"); if (dropping || conn != connection) { return; } if (reason == Connection.DropReason.TransportDisconnect) { needs_retry = true; next_retry = DateTime.UtcNow.Add(retry_period); if (retry_timer == null) { retry_timer = ROS.timerManager.StartTimer(onRetryTimer, 100); } else { retry_timer.Restart(); } } else { if (reason == Connection.DropReason.HeaderError) { ROS.Error()($"[{ThisNode.Name}] Error in the Header: {( parent != null ? parent.name : "unknown" )}"); } drop(); } }
private void onRetryTimer(object o) { ROS.Debug()($"[{ThisNode.Name}] TransportPublisherLink: onRetryTimer"); if (dropping) { return; } if (needs_retry && DateTime.UtcNow.Subtract(next_retry).TotalMilliseconds < 0) { retry_period = TimeSpan.FromSeconds((retry_period.TotalSeconds > 20) ? 20 : (2 * retry_period.TotalSeconds)); needs_retry = false; TcpTransport old_transport = connection.transport; string host = old_transport.connectedHost; int port = old_transport.connectedPort; TcpTransport transport = new TcpTransport(); if (transport.connect(host, port)) { Connection conn = new Connection(); conn.initialize(transport, false, null); initialize(conn); ConnectionManager.Instance.AddConnection(conn); } } }
public bool pubUpdate(string topic, List <string> pubs) { ROS.Debug()($"[{ThisNode.Name}] TopicManager is updating publishers for {topic}"); Subscription sub = null; lock ( subcriptionsMutex ) { if (shuttingDown) { return(false); } foreach (Subscription s in subscriptions) { if (s.name != topic || s.IsDropped) { continue; } sub = s; break; } } if (sub != null) { return(sub.pubUpdate(pubs)); } ROS.Info()($"[{ThisNode.Name}] Request for updating publishers of topic {topic}, which has no subscribers."); return(false); }
public bool handleHeader(Header header) { if (!header.Values.ContainsKey("md5sum") || !header.Values.ContainsKey("service") || !header.Values.ContainsKey("callerid")) { string bbq = $"[{ThisNode.Name}] Error in TcpRos header. Required elements (md5sum, service, callerid) are missing"; ROS.Error()(bbq); connection.sendHeaderError(ref bbq); return(false); } string md5sum = (string)header.Values["md5sum"]; string service = (string)header.Values["service"]; string client_callerid = (string)header.Values["callerid"]; if (header.Values.ContainsKey("persistent") && ((string)header.Values["persistent"] == "1" || (string)header.Values["persistent"] == "true")) { persistent = true; } ROS.Debug()($"[{ThisNode.Name}] Service client [{client_callerid}] wants service [{service}] with md5sum [{md5sum}]"); IServicePublication isp = ServiceManager.Instance.LookupServicePublication(service); if (isp == null) { string bbq = $"[{ThisNode.Name}] Received a TcpRos connection for a nonexistent service [{service}]"; ROS.Warn()(bbq); connection.sendHeaderError(ref bbq); return(false); } if (isp.md5sum != md5sum && md5sum != "*" && isp.md5sum != "*") { string bbq = $"[{ThisNode.Name}] Client wants service {service} to have md5sum {md5sum} but it has {isp.md5sum}. Dropping connection"; ROS.Error()(bbq); connection.sendHeaderError(ref bbq); return(false); } if (isp.isDropped) { string bbq = $"[{ThisNode.Name}] Received a TcpRos connection for a nonexistent service [{service}]"; ROS.Warn()(bbq); connection.sendHeaderError(ref bbq); return(false); } parent = isp; IDictionary <string, string> m = new Dictionary <string, string>(); m["request_type"] = isp.req_datatype; m["response_type"] = isp.res_datatype; m["type"] = isp.datatype; m["md5sum"] = isp.md5sum; m["callerid"] = ThisNode.Name; connection.writeHeader(m, onHeaderWritten); isp.addServiceClientLink(this); return(true); }
public void AddPollThreadListener(Action poll) { ROS.Debug()($"[{ThisNode.Name}] Adding pollthreadlistener {poll.Target}:{poll.GetMethodInfo().Name}"); lock ( signal_mutex ) { signals.Add(new PollSignal(poll)); } CallSignal(); }
internal override CallResult Call() { ROS.Debug()($"[{ThisNode.Name}] Called PeerConnDisconnCallback"); SingleSubscriberPublisher pub = new SingleSubscriberPublisher(sub_link); ROS.Debug()($"[{ThisNode.Name}] Callback: Name: {pub.SubscriberName} Topic: {pub.Topic}"); callback(pub); return(CallResult.Success); }
internal override CallResult Call() { ROS.Debug()("Called PeerConnDisconnCallback"); SingleSubscriberPublisher pub = new SingleSubscriberPublisher(subscriberLink); logger.LogDebug($"Callback: Name: {pub.SubscriberName} Topic: {pub.Topic}"); callback(pub); return(CallResult.Success); }
public bool Initialize(Connection connection) { if (parent != null) { ROS.Debug()($"Init transport subscriber link: {parent.Name}"); } this.connection = connection; connection.DroppedEvent += OnConnectionDropped; return(true); }
private bool onResponseOkAndLength(Connection conn, byte[] buf, int size, bool success) { if (conn != connection) { throw new ArgumentException("Unknown connection", nameof(conn)); } if (size != 5) { throw new ArgumentException($"Wrong size {size}", nameof(size)); } if (!success) { return(false); } byte ok = buf[0]; int len = BitConverter.ToInt32(buf, 1); int lengthLimit = 1000000000; if (len > lengthLimit) { ROS.Error()($"[{ThisNode.Name}] Message length exceeds limit of {lengthLimit}. Dropping connection."); connection.drop(Connection.DropReason.Destructing); return(false); } lock ( call_queue_mutex ) { if (ok != 0) { current_call.success = true; } else { current_call.success = false; } } if (len > 0) { ROS.Debug()($"[{ThisNode.Name}] Reading message with length of {len}."); connection.read(len, onResponse); } else { byte[] f = new byte[0]; onResponse(conn, f, 0, true); } return(true); }
public bool call(RosMessage req, ref RosMessage resp) { if (resp == null) { //instantiate null response IN CASE this call succeeds resp = RosMessage.Generate(req.MessageType.Replace("Request", "Response")); } CallInfo info = new CallInfo { req = req, resp = resp, success = false, finished = false }; bool immediate = false; lock ( call_queue_mutex ) { if (connection.dropped) { return(false); } if (call_queue.Count == 0 && header_written && header_read) { immediate = true; } call_queue.Enqueue(info); } if (immediate) { processNextCall(); } while (!info.finished) { ROS.Debug()($"[{ThisNode.Name}] info.finished_condition.WaitOne();"); info.finished_condition.WaitOne(); } if (info.success) { // response is only sent on success => don't try to deserialize on failure. resp.Deserialize(resp.Serialized); } if (!string.IsNullOrEmpty(info.exception)) { ROS.Error()($"[{ThisNode.Name}] Service call failed: service [{name}] responded with an error: {info.exception}"); } return(info.success); }
private void ThreadFunc() { while (!shutting_down) { CallSignal(); Thread.Sleep(ROS.WallDuration); if (shutting_down) { return; } } ROS.Debug()($"[{ThisNode.Name}] PollManager thread finished"); }
public override void drop() { dropping = true; connection.drop(Connection.DropReason.Destructing); if (parent != null) { parent.removePublisherLink(this); } else { ROS.Debug()($"[{ThisNode.Name}] Last publisher link removed"); } }
private void OnConnectionDropped(Connection conn, Connection.DropReason reason) { if (conn != connection || parent == null) { return; } ROS.Debug()($"[{ThisNode.Name}] TransportSubscriberLink: OnConnectionDropped from remote {conn.RemoteString} with reason {reason.ToString()}"); lock ( parent ) { parent.removeSubscriberLink(this); } }
public bool HandleHeader(Header header) { if (!header.Values.ContainsKey("topic")) { string msg = $"[{ThisNode.Name}] Header from subscriber did not have the required element: topic"; ROS.Warn()(msg); connection.sendHeaderError(ref msg); return(false); } string name = (string)header.Values["topic"]; string client_callerid = (string)header.Values["callerid"]; Publication pt = TopicManager.Instance.lookupPublication(name); if (pt == null) { string msg = $"[{ThisNode.Name}] received a connection for a nonexistent topic [{name}] from [{connection.transport}] [{client_callerid}]"; ROS.Warn()(msg); connection.sendHeaderError(ref msg); return(false); } string error_message = ""; if (!pt.validateHeader(header, ref error_message)) { connection.sendHeaderError(ref error_message); ROS.Error()($"[{ThisNode.Name}] {error_message}"); return(false); } destination_caller_id = client_callerid; connection_id = ConnectionManager.Instance.GetNewConnectionId(); name = pt.Name; topic = name; parent = pt; lock ( parent ) { maxQueue = parent.MaxQueue; } var m = new Dictionary <string, string>(); m["type"] = pt.DataType; m["md5sum"] = pt.Md5sum; m["message_definition"] = pt.MessageDefinition; m["callerid"] = ThisNode.Name; m["latching"] = Convert.ToString(pt.Latch); connection.writeHeader(m, OnHeaderWritten); pt.addSubscriberLink(this); ROS.Debug()($"[{ThisNode.Name}] Finalize transport subscriber link for {name}"); return(true); }
private void onConnectionDropped(Connection connection, Connection.DropReason reason) { if (connection != this.connection) { throw new ArgumentException("Unknown connection", nameof(connection)); } ROS.Debug()($"[{ThisNode.Name}] Service client from [{connection.RemoteString}] for [{name}] dropped"); clearCalls(); ServiceManager.Instance.RemoveServiceServerLink(this); IsValid = false; }
private void ThreadFunc() { TimeSpan wallDuration = new TimeSpan(0, 0, 0, 0, ROS.WallDuration); while (ROS.ok) { DateTime begin = DateTime.UtcNow; CallAvailable(ROS.WallDuration); DateTime end = DateTime.UtcNow; var remainingTime = wallDuration - (end - begin); if (remainingTime > TimeSpan.Zero) { Thread.Sleep(remainingTime); } } ROS.Debug()($"[{ThisNode.Name}] CallbackQueue thread broke out!"); }
private void RemoveDroppedConnections() { Connection[] localDroppedConnections = null; lock ( dropped_connections_mutex ) { localDroppedConnections = dropped_connections.ToArray(); dropped_connections.Clear(); } lock ( connections_mutex ) { foreach (Connection c in localDroppedConnections) { ROS.Debug()($"[{ThisNode.Name}] Removing dropped connection: {c.CallerID}"); connections.Remove(c); } } }
async Task HandleConnection() { try { await Handshake().ConfigureAwait(false); while (await callQueue.MoveNext(cancel).ConfigureAwait(false)) { var call = callQueue.Current; await ProcessCall(call).ConfigureAwait(false); } connection.Socket.Shutdown(SocketShutdown.Send); connection.Close(50); } catch (System.IO.EndOfStreamException ex) { ROS.Debug()("EndOfStreamException during connection handling. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (System.IO.IOException ex) { ROS.Debug()("IOException during connection handling. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (Exception e) { if (!(e is OperationCanceledException)) { logger.LogDebug($"Service client for [{name}] dropped: {e.Message}"); } FlushCallQueue(e); callQueue = new AsyncQueue <CallInfo>(MAX_CALL_QUEUE_LENGTH, true); throw; } finally { logger.LogDebug($"Removing service client for [{name}] from ServiceManager."); ServiceManager.Instance.RemoveServiceServerLinkAsync(this); } }
public void RemoveById(long ownerId) { SetupTls(); IDInfo idinfo; lock ( idInfoMutex ) { if (!idInfo.ContainsKey(ownerId)) { return; } idinfo = idInfo[ownerId]; } if (idinfo.id == tls.calling_in_this_thread) { RemoveAll(ownerId); } else { ROS.Debug()($"[{ThisNode.Name}] removeByID w/ WRONG THREAD ID"); RemoveAll(ownerId); } }
public bool initialize(Connection connection) { ROS.Debug()($"[{ThisNode.Name}] Init transport publisher link: {parent.name }"); this.connection = connection; connection.DroppedEvent += onConnectionDropped; if (connection.transport.getRequiresHeader()) { connection.setHeaderReceivedCallback(onHeaderReceived); IDictionary <string, string> header = new Dictionary <string, string>(); header["topic"] = parent.name; header["md5sum"] = parent.md5sum; header["callerid"] = ThisNode.Name; header["type"] = parent.datatype; header["tcp_nodelay"] = "1"; connection.writeHeader(header, onHeaderWritten); } else { connection.read(4, onMessageLength); } return(true); }
public bool NegotiateConnection(string xmlRpcUri) { int protos = 0; XmlRpcValue tcpros_array = new XmlRpcValue(), protos_array = new XmlRpcValue(), Params = new XmlRpcValue(); tcpros_array.Set(0, "TCPROS"); protos_array.Set(protos++, tcpros_array); Params.Set(0, ThisNode.Name); Params.Set(1, name); Params.Set(2, protos_array); if (!Network.SplitUri(xmlRpcUri, out string peerHost, out int peerPort)) { ROS.Error()($"[{ThisNode.Name}] Bad xml-rpc URI: [{xmlRpcUri}]"); return(false); } var client = new XmlRpcClient(peerHost, peerPort); var requestTopicTask = client.ExecuteAsync("requestTopic", Params); if (requestTopicTask.IsFaulted) { ROS.Error()($"[{ThisNode.Name}] Failed to contact publisher [{peerHost}:{peerPort}for topic [{name}]"); return(false); } ROS.Debug()($"[{ThisNode.Name}] Began asynchronous xmlrpc connection to http://{peerHost}:{peerPort}/ for topic [{name}]"); var conn = new PendingConnection(client, requestTopicTask, xmlRpcUri); lock ( pendingConnections ) { pendingConnections.Add(conn); requestTopicTask.ContinueWith(t => PendingConnectionDone(conn, t)); } return(true); }
private async Task RunServiceLoopAsync(Header header) { await Task.Yield(); try { try { await HandleHeader(header).ConfigureAwait(false); } catch (Exception e) { if (ROS.shuttingDown) { await connection.SendHeaderError("ROS node shutting down", cancel).ConfigureAwait(false); } else { ROS.Error()(e.Message); await connection.SendHeaderError(e.Message, cancel).ConfigureAwait(false); } connection.Close(50); throw; } while (true) { cancel.ThrowIfCancellationRequested(); // read request int requestLength = await connection.ReadInt32(cancel).ConfigureAwait(false); if (requestLength < 0 || requestLength > Connection.MESSAGE_SIZE_LIMIT) { var errorMessage = $"Message length exceeds limit of {Connection.MESSAGE_SIZE_LIMIT}. Dropping connection."; ROS.Error()(errorMessage); throw new ConnectionError(errorMessage); } byte[] requestBuffer = await connection.ReadBlock(requestLength, cancel).ConfigureAwait(false); try { // process var(result, success) = await parent.ProcessRequest(requestBuffer, this).ConfigureAwait(false); await ProcessResponse(result, success).ConfigureAwait(false); } catch (Exception e) { string errorMessage = "Exception thrown while processing service call: " + e.Message; ROS.Error()(errorMessage); await ProcessResponse(errorMessage, false).ConfigureAwait(false); } if (!persistent) { break; } } } catch (System.IO.EndOfStreamException ex) { ROS.Debug()("EndOfStreamException during connection handling. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (System.IO.IOException ex) { ROS.Debug()("IOException during connection handling. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (Exception ex) { ROS.Error()("Error during service loop. Error: {0}, Stacktrace: {1}", ex.ToString(), ex.StackTrace); } finally { UnregisterServiceLink(); } }
public bool connect(string host, int port) { socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); connectedHost = host; connectedPort = port; if (!setNonBlocking()) { throw new Exception($"[{ThisNode.Name}] Failed to make socket nonblocking"); } setNoDelay(true); IPAddress ip; if (!IPAddress.TryParse(host, out ip)) { ip = Dns.GetHostAddressesAsync(host).Result.Where(x => !x.ToString().Contains(":")).FirstOrDefault(); if (ip == null) { close(); ROS.Error()($"[{ThisNode.Name}] Couldn't resolve host name [{host}]"); return(false); } } if (ip == null) { return(false); } IPEndPoint ipep = new IPEndPoint(ip, port); LocalEndPoint = ipep; DateTime connectionAttempted = DateTime.UtcNow; IAsyncResult asyncres = socket.BeginConnect(ipep, iar => { lock (this) { if (socket != null) { try { socket.EndConnect(iar); } catch (Exception e) { ROS.Error()($"[{ThisNode.Name}] {e.ToString()}"); } } } }, null); bool completed = false; while (ROS.ok && !ROS.shutting_down) { completed = asyncres.AsyncWaitHandle.WaitOne(10); if (completed) { break; } if (DateTime.UtcNow.Subtract(connectionAttempted).TotalSeconds >= 3) { ROS.Info()($"[{ThisNode.Name}] Trying to connect for {DateTime.UtcNow.Subtract( connectionAttempted ).TotalSeconds}s\t: {this}"); if (!asyncres.AsyncWaitHandle.WaitOne(100)) { socket.Close(); socket = null; } } } if (!completed || socket == null || !socket.Connected) { return(false); } else { ROS.Debug()($"[{ThisNode.Name}] TcpTransport connection established."); } return(ROS.ok && initializeSocket()); }
private async Task HandleConnection() { // establish connection using (var client = new TcpClient()) { await client.ConnectAsync(host, port).ConfigureAwait(false); client.NoDelay = true; try { this.connection = new Connection(client); // write/read header handshake await WriteHeader().ConfigureAwait(false); var headerFields = await connection.ReadHeader(cancel).ConfigureAwait(false); SetHeader(new Header(headerFields)); // connection established this.connected = true; while (!cancel.IsCancellationRequested) { // read message length int length = await connection.ReadInt32(cancel).ConfigureAwait(false); if (length > Connection.MESSAGE_SIZE_LIMIT) { var message = $"Message received in TransportPublisherLink exceeds length limit of {Connection.MESSAGE_SIZE_LIMIT}. Dropping connection"; throw new RosException(message); } // read message var messageBuffer = await connection.ReadBlock(length, cancel).ConfigureAwait(false); // deserialize message RosMessage msg = RosMessage.Generate(Parent.DataType); msg.Serialized = messageBuffer; msg.connection_header = this.Header.Values; HandleMessage(msg); // reset retry delay after first successfully processed message retryDelay = BASE_RETRY_DELAY; } client.Close(); } catch (System.IO.EndOfStreamException ex) { ROS.Debug()("EndOfStreamException during connection handling to a publisher. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (System.IO.IOException ex) { ROS.Debug()("IOException during connection handling to a publisher. Message: {0}, Stacktrace : {1}", ex.ToString(), ex.StackTrace); } catch (Exception ex) { ROS.Error()("Error during connection handling to a publisher. Error: {0}, Stacktrace: {1}", ex.ToString(), ex.StackTrace); } finally { this.connected = false; this.connection = null; } } }
private void PendingConnectionDone(PendingConnection conn, Task <XmlRpcCallResult> callTask) { lock ( pendingConnections ) { pendingConnections.Remove(conn); } if (callTask.IsFaulted) { List <string> errorMessages = new List <string>(); foreach (Exception exception in callTask.Exception.InnerExceptions) { errorMessages.Add(BuildExceptionMessages(exception)); } ROS.Warn()($"[{ThisNode.Name}] Negotiating for {name} has failed (Error: {string.Join( ", ", errorMessages.ToArray() )})."); return; } if (!callTask.Result.Success) { ROS.Warn()($"[{ThisNode.Name}] Negotiating for {name} has failed. XML-RPC call failed."); return; } var resultValue = callTask.Result.Value; lock ( shutdown_mutex ) { if (shutting_down || _dropped) { return; } } var proto = new XmlRpcValue(); if (!XmlRpcManager.Instance.ValidateXmlRpcResponse("requestTopic", resultValue, proto)) { ROS.Warn()($"[{ThisNode.Name}] Negotiating for {name} has failed."); return; } string peerHost = conn.Client.Host; int peerPort = conn.Client.Port; string xmlrpcUri = $"http://{peerHost}:{peerPort}/"; if (proto.Count == 0) { ROS.Debug()($"[{ThisNode.Name}] Could not agree on any common protocols with [{xmlrpcUri}] for topic [{name}]"); return; } if (proto.Type != XmlRpcType.Array) { ROS.Warn()($"[{ThisNode.Name}] Available protocol info returned from {xmlrpcUri} is not a list."); return; } string protoName = proto[0].GetString(); if (protoName == "UDPROS") { ROS.Error()($"[{ThisNode.Name}] UDP is currently not supported. Use TCPROS instead."); } else if (protoName == "TCPROS") { if (proto.Count != 3 || proto[1].Type != XmlRpcType.String || proto[2].Type != XmlRpcType.Int) { ROS.Warn()($"[{ThisNode.Name}] TcpRos Publisher should implement string, int as parameter"); return; } string pubHost = proto[1].GetString(); int pubPort = proto[2].GetInt(); ROS.Debug()($"[{ThisNode.Name}] Connecting via tcpros to topic [{name}] at host [{pubHost}:{pubPort}]"); var transport = new TcpTransport(PollManager.Instance.poll_set) { _topic = name }; if (transport.connect(pubHost, pubPort)) { var connection = new Connection(); var pubLink = new TransportPublisherLink(this, xmlrpcUri); connection.initialize(transport, false, null); pubLink.initialize(connection); ConnectionManager.Instance.AddConnection(connection); lock ( publisher_links_mutex ) { addPublisherLink(pubLink); } ROS.Debug()($"[{ThisNode.Name}] Connected to publisher of topic [{name}] at [{pubHost}:{pubPort}]"); } else { ROS.Error()($"[{ThisNode.Name}] Failed to connect to publisher of topic [{name}] at [{pubHost}:{pubPort}]"); } } else { ROS.Error()($"[{ThisNode.Name}] The XmlRpc Server does not provide a supported protocol."); } }
public bool pubUpdate(IEnumerable <string> publisherUris) { lock ( shutdown_mutex ) { if (shutting_down || _dropped) { return(false); } } bool retval = true; ROS.Debug()($"[{ThisNode.Name}] Publisher update for [{name}]"); var additions = new List <string>(); List <PublisherLink> subtractions; lock ( publisher_links_mutex ) { subtractions = publisher_links.Where(x => !publisherUris.Any(u => urisEqual(x.XmlRpcUri, u))).ToList(); foreach (string uri in publisherUris) { bool found = publisher_links.Any(spc => urisEqual(uri, spc.XmlRpcUri)); if (found) { continue; } lock ( pendingConnections ) { if (pendingConnections.Any(pc => urisEqual(uri, pc.RemoteUri))) { found = true; } if (!found) { additions.Add(uri); } } } } foreach (PublisherLink link in subtractions) { if (link.XmlRpcUri != XmlRpcManager.Instance.Uri) { ROS.Debug()($"[{ThisNode.Name}] Disconnecting from publisher [{link.CallerID}] of topic [{name}] at [{link.XmlRpcUri}]"); link.drop(); } else { ROS.Warn()($"[{ThisNode.Name}] Cannot disconnect from self for topic: {name}"); } } foreach (string i in additions) { ROS.Debug()($"[{ThisNode.Name}] Start connecting to {i} for [{name}]"); if (XmlRpcManager.Instance.Uri != i) { retval &= NegotiateConnection(i); //ROS.Debug()("NEGOTIATINGING"); } else { ROS.Info()($"[{ThisNode.Name}] Skipping myself ({name}, {XmlRpcManager.Instance.Uri})"); } } return(retval); }
private bool ValidateFailed(string method, string errorFormat, params object[] args) { ROS.Debug()($"[{ThisNode.Name}] XML-RPC Call [{method}] {string.Format(errorFormat, args)} failed validation"); return(false); }