0

I am dealing with a server for a rather picky protocol (SIP) that needs my local IP and port as part of the header structure. I am using an Akka TCP stream for its awesomeness but I am missing the equivalent of BSD socket's getsockname function. In Akka actor-oriented connections, the connection sends a convenient message reporting the local IP and port, but I cannot find a way to get this from the Akka Streams version. The stream is connected directly to some flow for further processing, but there is no room for a message containing the IP and port of the local side of the connection.

val connection = Tcp().outgoingConnection("www.google.com", 80)

val test = List("GET / HTTP/1.1", "Host: www.google.com", "\r\n").map(s ⇒ ByteString(s + "\r\n"))
val res = Source(test).via(connection).runFold(ByteString.empty)( _ ++ _ )

// How do I get the connection details here?
res.onComplete{
  case Success(resp) ⇒ println(resp.utf8String)
  case Failure(f) ⇒ println(f)
}    

Any ideas?

David Weber
  • 1,965
  • 1
  • 22
  • 32
  • I would start reading around next references: https://doc.akka.io/docs/akka/current/index-network.html possibly its just abstracted away etc – Pavel Mar 23 '18 at 09:06
  • The data is bubbling just below the stream abstraction. I just don't see a "side channel" where the `Connect(remote, local)` can be delivered to or some exposed method to retrieve this information. – David Weber Mar 23 '18 at 09:09
  • 2
    You haven't created the connection yet, just a stream which will, when materialized, create the connection. the address information is available in the materialized value, see: https://doc.akka.io/api/akka/current/akka/stream/scaladsl/Tcp.html – Viktor Klang Mar 23 '18 at 14:00
  • Akka never fails to impress me. Thanks everyone. – David Weber Mar 24 '18 at 06:28

1 Answers1

2

Here is the signature for the Tcp().outgoingConnection method:

def outgoingConnection(host: String, port: Int):
  Flow[ByteString, ByteString, Future[OutgoingConnection]]

The materialized value is a Future[OutgoingConnection], and the OutgoingConnection case class has a localAddress member.

To access the materialized value of the outgoing connection, and in turn the local address, use something like the following:

val (res1, res2) =
  Source(test)
    .viaMat(connection)(Keep.right)
    .toMat(Sink.fold(ByteString.empty)(_ ++ _))(Keep.both)
    .run()

res1 onComplete {
  case Success(OutgoingConnection(_, localAddr)) =>
    println(s"local address: ${localAddr}")
  case Failure(f) =>
    println(f)
}
Jeffrey Chung
  • 19,319
  • 8
  • 34
  • 54