I am creating a UDP socket client in C (unicast) and is wondering why recvfrom() has a struct sockaddr * argument in which in the man page says,
A null pointer, or points to a sockaddr structure in which the sending address is to be stored.
Is it possible that I could receive a message from a different server other than the one I sendto? If yes, how to create this scenario?
If no, is it correct to say that this argument is only useful when broadcast mode is used?
Yes, this is perfectly possible. The reason for this is that UDP is not stream-based, but packet-based. Every packet is treated without any history (other packets sent or received).
For this reason you may also open a UDP port and then send packets to different hosts from it. However, I do not remember how well this is supported by the API.
The UDP socket will recvfrom() any host sending to this one with correct port unless you explicitly connect(), in which case you can just write() and read(), and get errors upon received ICMP messages.
Considering you always have two parties in UDP, it seems rather obvious that someone has to recvfrom() first.
Related
I have a simple C program that binds a socket so that it can
receive and send UDP packets. It uses recvfrom to receive packets, and
shortly after receiving one, it constructs and sends a reply
packet, using sendto in the obvious way, sending to the same
address and port that recvfrom reported.
This program worked perfectly in initial testing, when the
packets were coming in and going out over a regular Ethernet
interface, eth0. But now I'm trying to use it over a PPP
interface, ppp0, and for some reason it's not working.
sendto is not reporting any errors, but tcpdump is not showing
the packets going out. (It is showing the packets coming in, so
I'm pretty sure tcpdump is working.)
And I have an existing program that's doing essentially the same
thing, but it works properly under all circumstances, on all
interfaces. I haven't yet worked out how the existing program
might be setting up its sockets or its send/receive logic
differently, that allows it to work while my new, simpler program
fails.
Some of the packets are large (approaching MTU), but plenty
of them are small (<100 bytes), and none of them are getting
through, so I don't think it's an MTU problem.
Can anyone think of anything that would cause a sent packet to fail to
go out in this way? (I'm not saying it has anything to do with ppp in particular; that it fails under ppp for me may be a coincidence, or it may be a key part of the problem.)
Sorry I can't post the actual code; it's at work and I'm at home.
The relevant part looks something like this:
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
char buf[1600];
int r, r2;
r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &addrlen);
/* ... */
r2 = sendto(sock, buf2, n2, 0, (struct sockaddr *)&addr, addrlen);
(If you need to see a more complete example, I can post that tomorrow.)
If none of traffic works:
There could be routing problem. Check routing table of the host.
You can also check with tcpdump, that traffic is not going out via wrong interface. For example:
If you expect to see traffic in ppp0 by command:
tcpdump -i ppp0 udp port 123
And you don't see the wanted traffic, then check other interfaces by similar command to ensure that traffic does not go out via wrong interface:
tcpdump -i eth0 udp port 123
If part of traffic works:
If you are using some mobile network (often used via ppp0), then your uplink speed may be slower than downlink speed.
So a client may send more traffic to your server (via downlink), than uplink is capable to transfer.
Because UDP doesn't have such reliability and congestion/flow control like TCP have, UDP can discard some packets in overload situation.
I started to program a packet sniffer, And I have searched for the correct parameters to pass to socket() function in order to capture packets with their Ethernet header.
I noticed that in this tutorial , In order to recieve the Ethernet header, they changed this line:
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
To this line:
s = socket.socket( socket.AF_PACKET , socket.SOCK_RAW , socket.ntohs(0x0003))
And my questions are:
I understood from this link that AF_INET with raw socket won't give me the Ethernet header. My question is why?
Why he also changed from IPPROTO_TCP to ntohs(0x0003) which I know that this is GGP protocol. As far as I understood, the third parameter states the protocol which the socket will recieve. If the protocol parameter is GGP, then the socket will look for packets who have GGP as their internet layer protocol, isn't? then why they pass GGP and not TCP or IP? After all, almost every PDU has IP and\or TCP\UDP as their data protocols.. Does it matter what's the third parameter for my packet sniffer?
In addition to the second question, I think that I didn't get the objective of the third parameter. If this is IPPROTO_TCP, the socket will capture packets with TCP in the network layer (and not UDP for example)? and if i'll pass IPPROTO_IP, the socket will capture packets with IP as their internet layer protocol, without checking the other layer's protocols (It doesn't matter for the socket what protocol is used for the network layer? It only cares that IP is exists as the internet layer protocol)?
Thanks and sorry for the grammer mistakes (English isn't my first language).
If you check linux/if_ether.h you will see
#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
So the value of ETH_P_ALL is 0x0003. The authors of this tutorial use 0x0003 instead of ETH_P_ALL because in some systems when used in python a "not defined" error occurs.
The raw socket feature can be set up at different layers of the network stack, in order to allow the kernel do perform some of the work for you at lower levels (eg: ethernet crafting).
The change to GGP protocol might make sense on the website you found the example, but it is ugly to do so and getprotoent() should be used rather than using magic numbers.
Yes you can tweak (filter) how the packet capture will happen. If you want to capture all packets then use ETH_P_ALL:
When protocol is set to htons(ETH_P_ALL) then all protocols are
received.
The man page for recvfrom summarizes its behavior as "receive a message from a socket". If the socket is of type SOCK_STREAM or SOCK_DGRAM, is "message" synonymous with "packet"? If not, how does it differ?
My first thought was recvfrom works on stream sockets just because there's no reason to ban it. As in the famous quote:
"Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things." – Doug Gwyn
If it did what I expected it to do, you could use it like a combination read() and getpeername() since it returns the sender's address. That might be considered clever.
But then I tried it on Linux, and it didn't work that way. The source address buffer was unchanged and the length indicator was set to 0.
So now I'm not sure what to say except don't use it on stream sockets. It's not meant for them.
ADDENDUM: And no, even in my wildest dreams I wouldn't have expected it to give you access to packet boundaries in a TCP stream. Data that has been put through the tcp receiving mechanism simply isn't made of packets anymore.
I need to build a server using Unix domain sockets, and it looks that there are several options to choose the kind of communication.
From man 2 socket:
SOCK_STREAM
SOCK_DGRAM
SOCK_SEQPACKET
So, for what is better suited every one of them? (stream, datagram, packet)
It really depends what kind of server you are going to implement.
If message boundaries are important, then SOCK_DGRAM would be the best choice.
Because recvfrom/recvmsg/select will return when a complete message is received.
With SOCK_STREAM, message receiving is more tricky: One receiving call may return a partial message, or part of two messages, or several messages... etc.
If message boundaries are not important, then SOCK_STREAM could be the best choice.
SOCK_DGRAM of AF_INET is unreliable UDP. But, in most sytems, SOCK_DGRAM of AF_UNIX is reliable.
For example: If queue of receiver is full, sender will be blocked until there is space.
For TCP -> SOCK_STREAM
For UDP -> SOCK_DGRAM
My goal is to send a TCP packet with empty data field, in order to test the socket with the remote machine.
I am using the OutputStream class's method of write(byte[] b).
my attempt:
outClient = ClientSocket.getOutputStream();
outClient.write(("").getBytes());
Doing so, the packet never show up on the wire. It works fine if "" is replaced by " " or any non-zero string.
I tried jpcap, which worked with me, but didn't serve my goal.
I thought of extending the OutputStream class, and implementing my own OutputStream.write method. But this is beyond my knowledge. Please give me advice if someone have already done such a thing.
If you just want to quickly detect silently dropped connections, you can use Socket.setKeepAlive( true ). This method ask TCP/IP to handle heartbeat probing without any data packets or application programming. If you want more control on the frequency of the heartbeat, however, you should implement heartbeat with application level packets.
See here for more details: http://mindprod.com/jgloss/socket.html#DISCONNECT
There is no such thing as an empty TCP packet, because there is no such thing as a TCP packet. TCP is a byte-stream protocol. If you send zero bytes, nothing happens.
To detect broken connections, short of keepalive which only helps you after two hours, you must rely on read timeouts and write exceptions.