I'm trying to get basic Bonjour discovery up and running using the sample code from a 2012 WWDC session, but having converted it to Swift. It's partially working. I am able to register a port, and register my service on that port. The client is able to discover that service, and resolve it.
Here's the issue: I call CFSocketCreateWithNative() and specify the callback listener, but that callback never gets called. Further, I tried connecting wiht telnet (telnet localhost 12345) and I get:
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
telnet: connect to address 127.0.0.1: Connection refused
Trying fe80::1...
telnet: connect to address fe80::1: Connection refused
telnet: Unable to connect to remote host
This is an abbreviated version of how I'm registering the sockets, with the full Swift file in a Gist:
private func registerIPv4Socket() throws -> (Int32, in_port_t) {
let fd4 = socket(AF_INET, SOCK_STREAM, 0)
var sin = sockaddr_in()
sin.sin_family = sa_family_t(AF_INET)
sin.sin_len = UInt8(sizeofValue(sin))
sin.sin_port = 0
withUnsafePointer(&sin) {
Foundation.bind(fd4, UnsafePointer($0), UInt32(sin.sin_len))
}
var addrLen = socklen_t(sizeofValue(sin))
withUnsafeMutablePointers(&sin, &addrLen) { (sinPtr, addrPtr) -> Int32 in
getsockname(fd4, UnsafeMutablePointer(sinPtr), UnsafeMutablePointer(addrPtr))
}
let listenError = listen(fd4, 5)
return (fd4, sin.sin_port)
}
private func registerIPv6Socket(port: in_port_t) throws -> Int32 {
let fd6 = socket(AF_INET6, SOCK_STREAM, 0)
var one: Int32 = 1
withUnsafePointer(&one) {
setsockopt(fd6, IPPROTO_IPV6, IPV6_V6ONLY, UnsafePointer($0), socklen_t(sizeofValue(one)))
}
var sin6 = sockaddr_in6()
sin6.sin6_family = sa_family_t(AF_INET6)
sin6.sin6_len = UInt8(sizeofValue(sin6))
sin6.sin6_port = port
withUnsafePointer(&sin6) {
Foundation.bind(fd6, UnsafePointer($0), UInt32(sin6.sin6_len))
}
var addrLen = socklen_t(sizeofValue(sin6))
withUnsafeMutablePointers(&sin6, &addrLen) { (sinPtr, addrPtr) -> Int32 in
getsockname(fd6, UnsafeMutablePointer(sinPtr), UnsafeMutablePointer(addrPtr))
}
listen(fd6, 5)
return fd6
}
Why isn't my app listening on the port it's reporting it should be?
Your IPv4 socket is listening on port sin.sin_port.bigEndian, but your IPv6 socket is listening on the little endian port. Update your IPv6 code to use the big endian port:
sin.sin6_port = port.bigEndian
Related
I wrote a simple server code using socket module forward the listening port using ngrok but when i try to connect to ngrok provided url it gives error
socket.gaierror: [Errno 11001] getaddrinfo failed
Server Code
import socket
server = socket.socket()
host = "localhost"
port = 5002
server.bind((host,port))
print("Started Listening.........")
server.listen()
con, addr = server.accept()
print("Connection is accepted from :",str(addr))
while True:
data = con.recv(1024).decode()
if not data:
break
print("From Connected User :",str(data))
data = str(data).upper()
print("Received from User: " + str(data))
data = input("Enter message::::")
con.send(data.encode())
con.close()
Client Code
import socket
host = "tcp://0.tcp.in.ngrok.io:18376"
port = 5002
client = socket.socket()
client.connect((host,port))
mess = input("Enter message::")
while mess!='q':
client.send(mess.encode())
data = client.recv(1024).decode()
print("FROM SERVER = ",data)
mess = input("Enter message ::")
client.close()
I am creating a tcp tunnel using ngrok at 5002 port
ngrok tcp 5002
It generates
Web Interface http://127.0.0.1:4040
Forwarding tcp://0.tcp.in.ngrok.io:18376 -> localhost:5002
i am using this tcp url in my client host code host = "tcp://0.tcp.in.ngrok.io:18376" I tried removing port number and tried only tcp://0.tcp.in.ngrok.io but nothing happend
Can you guide me how to connect to this tcp tunnel from socket module because i am pretty new to socket programming.
I am trying to establish an IPV6 socket connection with net-core 3.0 on a linux-arm platform (raspberry pi).
At the time when I try to bind the socket to the local ethernet adapter an Exception ((22): Invalid argument [fe80::211c:bf90:fbbf:9800]:5400) is thrown.
When i try the same on my windows development machine (with a different link-local ip), everything works fine.
IPV4 socket connection is also possible on both, my windows development machine and on the target linux-arm platform.
To the source code:
I used the socket example of microsoft as a base and changed the IPV4 into an IPV6 address.
The exception is thrown after the "Bind" method.
Here is the client side code:
//definet the target endpoint
IPAddress ipAddress;
IPAddress.TryParse("fe80::211c:bf90:fbbf:9800", out ipAddress);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5400);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily ,SocketType.Stream, ProtocolType.Tcp);
//bind to the local network interface
IPAddress localIp;
IPAddress.TryParse("fe80::833:e68b:32ee:4c39", out localIp);
EndPoint localEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
sender.Bind(localEndPoint);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
The input of Ron was in fact the missing part. Hence the target endpoint IpAddress has to provided with the ScopeId (NIC Nr).
//definet the target endpoint
IPAddress ipAddress;
IPAddress.TryParse("fe80::211c:bf90:fbbf:9800", out ipAddress);
ipAddress.ScopeId = scopeId;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5400);
To the scope ID of the first link local address for example this code can be used:
private static long GetScopeIdForHostLinkLocal()
{
IPAddress firstLinkLocal = null;
var info = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface nic in info)
{
var ipProps = nic.GetIPProperties();
var uniAddresses = ipProps.UnicastAddresses;
foreach (UnicastIPAddressInformation addressInfo in uniAddresses)
{
if (addressInfo.Address.IsIPv6LinkLocal)
{
firstLinkLocal = addressInfo.Address;
break;
}
}
if (firstLinkLocal != null)
{
break;
}
}
if (firstLinkLocal != null)
{
return firstLinkLocal.ScopeId;
}
else
{
return -1;
}
}
I'm struggling to make sense of this. The issue is seen on a machine that is:
Remote (I do not have access to it)
Running Windows 7
NOT running a proxy or VPN (or so I have been told)
My application has a snippet of code that tries to quickly determine which interface the OS prefers. It does the following:
// Create a socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
// Resolve DNS query
DWORD dwRemoteIp = GetHostAddr("www.google.com")
// I've simplified the call here, but "www.google.com" resolves to 172.217.3.100 in host byte order, so the resolution is correct
// Create the remote address to connect to
sockaddr_in remoteaddr = {0};
remoteaddr.sin_family = AF_INET;
remoteaddr.sin_addr.s_addr = htonl(dwRemoteIp);
remoteaddr.sin_port = htons(80);
// Connect the socket
if (0 == connect(sock, (struct sockaddr*)&remoteaddr, sizeof(remoteaddr))) {
// The connection succeeded -- see which local address was bound to
sockaddr_in localaddr = {0};
int len = sizeof(localaddr);
if (0 == getsockname(sock, (struct sockaddr*)&localaddr, (socklen_t *)&len)) {
// Here is where I see dwLocalIp == 0x7F000001, or 127.0.0.1
DWORD dwLocalIp = ntohl(localaddr.sin_addr.s_addr);
}
}
What could be going on here?
Using Wireshark to debug, I receive the following error when sending UDP packets on localhost:
Destination Unreachable (Port Unreachable)
Checksum: 0x0000 (Illegal)
I am constructing my server first on a port between 10000 - 15000 using
startServer :: Port -> IO Server
startServer port = withSocketsDo $ do
-- Look up the server address and port information.
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
-- Bind to the socket.
sock <- socket (addrFamily serverAddress) Datagram defaultProtocol
bindSocket sock (addrAddress serverAddress)
-- Create the server and run the client send and receive threads.
clients <- newMVar $ createEmptyClients
let server = Server sock port clients
_ <- forkIO $ forever $ receiveClientJoin server
return server
I am listening for new clients connecting via UDP using
-- | Connected a client to the server.
receiveClientJoin :: Server -> IO ()
receiveClientJoin server = do
print "Receiving"
(msg, _, clSockAddr) <- recvFrom (sSocket server) 4096
print $ "Server received client join message: " ++ msg
And I am connecting to the server with clients using
connectToServer port = do
-- Get the server's address and port information.
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
sock <- socket (addrFamily serverAddr) Datagram defaultProtocol
sendTo sock "Hello from this client!" (addrAddress serverAddr)
Why are my clients' packets not finding the server?
The problem is you are listening on an IPv6 address and trying to connect to an IPv4 address. This is actually a slightly common problem. For example, I ran across this issue when working with commsec.
Consider the fragments where you discover your AddrInfo:
import Network.Socket
main :: IO ()
main = do
let port = "2474"
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
print serverAddress
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
print serverAddr
Now the output will vary by machine, but on one of my CentOS systems with both IPv4 and IPv6 addresses the output clearly shows the second (connect) address is IPv6 while the first (listen) address is IPv4:
AddrInfo {addrFlags = [AI_PASSIVE], addrFamily = AF_INET, addrSocketType = Stream, addrProtocol = 6, addrAddress = 0.0.0.0:2474, addrCanonName = Nothing}
AddrInfo {addrFlags = [AI_ADDRCONFIG,AI_V4MAPPED], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [::1]:2474, addrCanonName = Nothing}
One solution is to force a particular version of IP via a hint or an address (ex. an IPv4 address as in my comment). The hint solution is probably more desirable:
-- For servers:
addrs <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6
, addrFlags = [AI_PASSIVE] })
Nothing (Just port)
-- For clients:
addrInfo <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6 })
(Just "localhost") (Just port)
I have simple server and client in UDP (WinSocks/C++).
I send datagram client -> server via sendto, and reply from server to client using the ip and port obtained from recvfrom function.
I found out that:
Every sendto from client is being sent from different port
When trying to reply from server Windows returns WSAECONNRESET (which mean that port is closed - http://support.microsoft.com/kb/263823)
How can I properly answer client from server (ie force port binding on client when sending using sendto?)
Edit: Adding some source code:
bool InitClient()
{
internal->sock = socket(PF_INET, SOCK_DGRAM, 0);
char8 yes = 1;
setsockopt(internal->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int32));
return internal->sock != -1;
}
void Send(const IpAddress & target, const uint16 port, const char8 * data, int32 size )
{
sockaddr_in trgt;
memset(&trgt, 0, sizeof(trgt));
trgt.sin_family = AF_INET;
trgt.sin_port = htons(port);
trgt.sin_addr.s_addr = target.GetRaw();
if(sendto(internal->sock, (const char8 *)data, size, 0, (PSOCKADDR)&trgt, sizeof(trgt)) == SOCKET_ERROR)
{
LOG("Network sending error: %d", WSAGetLastError());
}
}
Call the "bind" function to specify a local port to send from. Example of using port 4567 below. Make sure to check the return value from bind.Call this code after you create the socket.
sockaddr_in local = {};
local.family = AF_INET;
local.port = htons(4567);
local.addr = INADDR_ANY;
bind(internal->sock,(sockaddr*)&local, sizeof(local));
If you bind to port zero instead of 4567 then the os will pick a random port for you and use it for all subsequent send and receives. You can call getsockname to discover which port the os picked for you after calling bind.