I have used wireshark to see the DHCP packet structure. Now I have created a DHCPDISCOVER request and stored it in 'message'. I then broadcast it on the network.
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket");
exit(1);
}
setsockopt(sockfd,SOL_SOCKET,SO_BROADCAST, &on,sizeof(on));
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR, &on,sizeof(on));
bzero(&cliaddr, sizeof(cliaddr));
cliaddr.sin_family = AF_INET;
cliaddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliaddr.sin_port = htons(68);
if (bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr)) < 0) {
perror("bind");
exit(1);
}
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("255.255.255.255");
addr.sin_port = htons(67);
cnt = sendto(sockfd, message, sizeof(message), 0,(struct sockaddr *) &addr, sizeof(addr));
if (cnt < 0) {
perror("sendto");
exit(1);
}
addrlen = sizeof(servaddr);
cnt = recvfrom(sockfd, reply, sizeof(reply), 0,(struct sockaddr *) &servaddr, &addrlen);
if (cnt < 0) {
perror("recvfrom");
exit(1);
}
printf("\nReply Received\n");
I run this program and analyze the packets sent and received using wireshark. I see that a DHCPDISCOVER packet is sent on port 67 and a DHCPOffer packet is received on port 68 in the wireshark window. My client sends the packet fine but does not receive this packet and it blocks on recvfrom call. What is going wrong?
You need to put your receive out before you send the packet request, or else the response probably comes back before you are ready to receive it.
Also, is the response broadcast? If not, and you don't currently have an IP address assigned to your machine, then you're going to have some trouble receiving it because your host will filter received packets by IP address won't know that the response is destined for it (even though the link layer address matches), so it'll not deliver it.
But my guess is it's the first problem. You'll have to either use threads or do a non-blocking receive, or else your receive will block and thus you'll never getting around to sending the request.
Well i disagree with the above answer.. recvfrom should be able receive both the packets.
Here problem lies because ,port no is within the range of 1000. typically , these packets are filtered by linux kernel(iptables) and not sent to. user application.
https://bugzilla.redhat.com/show_bug.cgi?id=983672
Related
I am writing a C client server program using SCTP, so that at begin there is only one socket opened on client side for send and recv which is used by all threads. After a certain condition I have to open a new socket, now I have two of them and at this point both socket should be used for sending and receiving on a round-robin (alternate) fashion by all threads for load sharing. Similarly, as the no of sockets increase, it should be used by client alternative for load sharing.
is there a suggestion to achieve this? Using select, poll, normal sockets etc?
connSock = socket (AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (connSock == -1)
{
perror("socket()");
exit(1);
}
struct sctp_paddrparams params;
len = sizeof(params);
memset(¶ms, 0, sizeof(params));
if (getsockopt(connSock, IPPROTO_SCTP, SCTP_PEER_ADDR_PARAMS, ¶ms, &len)) {
perror("getsockopt");
exit(1);
}
// set client address
struct sockaddr_in localaddr;
localaddr.sin_family = AF_INET;
char* client_ip = get_our_ip();
localaddr.sin_addr.s_addr = inet_addr(client_ip) ;
localaddr.sin_port = 0;
bind(connSock, (struct sockaddr *)&localaddr, sizeof(localaddr));
// set server address
bzero ((void *) &servaddr, sizeof (servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons (port);
servaddr.sin_addr.s_addr = inet_addr(server_ip);
ret = connect(connSock, (struct sockaddr *) &servaddr, sizeof (servaddr));
if (ret == -1)
{
perror("connect()");
close(connSock);
exit(1);
}
// ----> at this point only one socket is opened from client and all threads are using the same.
if(due_to_some_condition_got_new_server_ip){
// --> I have opened a new socket to connect to server_ip2. Now we
// have 2 sockets opened, hence all threads should use sockets alternatively to send and receive data
}
Hi I have following code:
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket(UDP): ");
return 0;
}
family = AF_INET;
if((remote_server_ent = gethostbyname2(hptr, family)) == NULL )
{
perror("gethostbyname2");
return 0;
}
if (family == AF_INET)
{
sin = (struct sockaddr_in *) addr;
sin->sin_family = AF_INET;
sin->sin_port = htons(server_port);;
bcopy( (char *)remote_server_ent->h_addr, (char *)&(sin->sin_addr), remote_server_ent->h_length );
return (sizeof(struct sockaddr_in));
}
if (sendto(fd, msg_data_ptr, sizeof(Msg_data_hdr), 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) != sizeof(Msg_data_hdr))
{
fprintf(stderr, "Error in sending data to the server \n");
}
My APP is listing on port 7000 IP 127.0.0.1.
Now when i stop my application still sendto send the data, it does not give me error. I am always getting the written bytes equal the size of data which i am writting. How will i know if sending is failed or not???
It's UDP (SOCK_DGRAM), so you may never find out. If you need reliability guarantees, use TCP instead. If you're satisfied with a partial solution of just knowing when the receiving side is completely missing/unavailable, see here: ICMP "destination unreachable" packet on udp connected socket
The general idea is that you can receive ICMP "destination unreachable" errors if you connect() your UDP socket and then receive data on it (you will want to use select() or epoll() for this). In some scenarios you will find out that your messages are not making it to the other side...but in other scenarios you may not, because hey, it's UDP.
I have really strange problem. I made server and client communicating using unicast sockets.
Server is sending text file in blocks of 512 bytes and client is receiving and writing blocks to a txt file. But I noticed that without sleep(1) function on both sides server can not send the whole file. For example the file is made of 2939 blocks and in wireshark I can see just 1827, 2005, 1657 but never the whole file , all 2939 blocks ? Why ? Packets are not lost because server and client are connected via ethernet cable to the router and are on the same local network.
Can you give me directions and advices how to solve this problem? Here is the code :
#includes...
#define BUF_SIZE 512
#define PORT 1234
#define IP "192.168.0.103" // address of a client
static int val = 1;
int sent=0;
int main() {
struct sockaddr_in client,server;
char tmp[BUF_SIZE];
int n,s,fd;
ssize_t numRead;
int rv,optval=1;
if((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))<0){
printf("Opening datagram socket error",strerror(errno));
return 1;
}else{
printf("Opening datagram socket....OK.\n");
}
if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1){
printf("Setsockopt error: %s", strerror(errno));
return 1;
}
memset((char *) &server, 0, sizeof(server));
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(PORT);
memset((char *) &client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_addr.s_addr = inet_addr(IP);
client.sin_port = htons(PORT);
if(bind(s, (struct sockaddr*)&server, sizeof(server))){
printf("Binding datagram socket error %s",strerror(errno));
close(s);
return 1;
}
if((fd = open("udp_text.txt", O_RDONLY , 0777))== -1){
printf("Error while opening txt file %s!\n",strerror(errno));
return 1;
}
while (1) {
if((numRead = read(fd,tmp,512)) == 512){
tmp[numRead]='\0';
rv = sendto(s,tmp,sizeof(tmp),0, (struct sockaddr *) &client, sizeof(struct sockaddr_in));
memset(tmp,0,BUF_SIZE);
}else{
rv = sendto(s,tmp,sizeof(tmp),0, (struct sockaddr *) &client, sizeof(struct sockaddr_in));
printf("EOF !\n");
return 1;
}
}
close(s);
return 0;
}
Thx
Since not all the packets show up in wireshark, I would guess that the sender is running out of network packet buffer space in the operating system. UDP can not only suffer packet loss from transmission failures but also if any routing component runs out of capacity and is forced to drop the packet because it is too busy. This includes the local internet protocol stack.
As a start, check the error code from sendto(). If the local operating system is to blame then it will likely have the courtesy of reporting an error.
Update: No error from sendto(), well then, no easy fix.
One final note of caution/advice. Even direct ethernet connections between hosts does not guarantee packets will always get through. If you depend on the file data getting transferred reliably then you'll need to add some kind of acknowledgement response from the receiver to confirm successful reception of the data. And associated logic in the sender to retransmit data as required.
That's a fair bit of work and why you might rather switch to TCP sockets which do all that for you.
If you are going to send files over UDP, at least use an existing protocol that is designed for that purpose, like Trivial FTP (see RFC 1350). It offers buffer size control and safety from dropped packets.
I would like to ask about the getpeername() function since it returns data as the title states. I tried to get value directly from accept() function, and the result also happens the same. Value of port seems to appear randomly even though value of address is correct(address is 127.0.0.1 since I run multi-processes on an only machine). The return code of getpeername() is 0 (status = 0). I'm using gcc version 4.8.1. I write a peer 2 peer chat application without server. The following is my code:
struct sockaddr_in addr;
socklen_t addr_len;
int tempPort, serverSockfd;
char test[100];
// Get serverSockfd successfully....
serverSockFd = initializeSock(PORT) // In this function I initialize socket(), bind() and listen(), serverSockFd is returned by the value of socket()
addr_len = sizeof addr;
newSock = accept(serverSockfd, (struct sockaddr *)&addr, &addr_len);
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
addr_len = sizeof addr;
if ((status = getpeername(newSock, (struct sockaddr *) &addr, &addr_len)) != 0){
printf("getpeername() error!\n");
}
tempPort = ntohs(addr.sin_port);
inet_ntop(AF_INET, &(addr.sin_addr), test, sizeof test);
printf("tempPort\t%d\n", tempPort);
printf("test\t%s\n", test);
Thanks very much for any your comment. Here is a partial code in initializeSock():
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("SocketInit(): socket() error!\n");
exit(1);
}
ret_val = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char*) &flag, sizeof(flag));
if(ret_val == -1)
{
perror("SocketInit(): setsockopt(SO_REUSEADDR) error!\n");
exit(1);
}
gethostname(hostname,100);
host_entry = gethostbyname(hostname);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
ret_val = bind(sd, (struct sockaddr*) &addr, sizeof(addr));
if(ret_val == -1)
{
perror("SocketInit(): bind() error!\n");
printf("For port:%d\n",port);
exit(1);
}
....
return sd;
This is the code to connect to server part of a peer. ConnectSock(portOfPeerA):
sd = socket(AF_INET, SOCK_STREAM, 0);
if(sd < 0)
{
perror("ConnectToServer(): socket() error!\n");
exit(1);
}
if (port != 0) {
addr.sin_family = AF_INET;
addr.sin_port = htons(portOfPeerA);
addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list));
// Do I need to bind() the port of peer B when it would like to connect to peer A?
ret_val = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if(ret_val == -1)
{
printf("Error connect());
exit(1);
}
...
I don't know which port you accept from the peer, but if the peer is connecting to your server (e.g. then one calling accept) it will connect from a (more or less) random port, that's how TCP works. It connects from a fixed port only if the peer explicitly binds to that port before connecting.
This means, that the peers originating port is not defined on the server side (where your code fragments are from) but on the client side (the side which calls connect and where you only do connect but no bind).
But, please note that it might give problems with repeated connections, if both client and server use fixed IP and ports, because then you will get the same 4-tupel in TCP which defines the connections for repeated connections and thus go into all this trouble with the various TIME_WAIT states. So it is better to let the client just pick an available port and not force it to use a specific one.
getpeername() (and accept()) reports the IP and port that the remote party is locally bound to on its end. If the remote party is a client that did not call bind() before calling connect() then connect() performs an implicit bind to a random available port. That is what you are seeing, and that it typical usage. Most clients do not need to call bind() before connect(), but there are use cases where doing so is necessary, so don't rule it out.
I have an application written in C that is a server and a client at the same time. What I do is the following:
sock = socket(AF_INET, SOCK_DGRAM, 0);
bzero(&server, length);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(MYPORT);
char broadcast = '1';
int broadcastlen = sizeof(broadcast);
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &broadcast, &broadcastlen) < 0) {
close(sock);
error("Error in setting broadcast option");
}
if (bind(sock, (struct sockaddr*) &server, sizeof(server)) < 0) {
close(sock);
error("Error in BINDING");
}
bzero(&sender, length);
bcast.sin_family = AF_INET;
bcast.sin_addr.s_addr = NBCAST; // NBCAST is the broadcast address of the subnet
bcast.sin_port = htons(MYPORT);
if (sendto(sock, dateQuery, strlen(dateQuery) + 1, 0, (struct sockaddr*)&bcast, sizeof(bcast)) < 0) {
close(sock);
error("ERROR in sending");
}
Up to this point everything works well. But I start a thread with the sock parameter to listen to, and do the following:
int len = sizeof(struct sockaddr_in);
struct sockaddr_in sender_addr;
recfrom(sock, recvbuff, recvbufflen, 0, (struct sockaddr*) &sender_addr, &len);
And it blocks there forever. I tried to make it work from different PCs, but it doesn't seem to work, because the thread is blocked due to recvfrom(). Can anyone tell me what is wrong with my code?
Thanks
EDIT: if my code is broken, could you please suggest a way to solve this? So, my task is to implement an application in C that is a server and a client at the same time. I send a broadcast message every 3 seconds, and I have to answer to that broadcast message with the system time.
So far this is the idea I came up with, of course I did not answer to that broadcast message since I couldn't even read it.
I just solved the problem. The code works perfectly, I just had to disable the firewall. But I don't know exactly how did this help me. Any way, thanks for the answers and comments.
Perhaps, you have to make the socket non-blocking?
Try:
u_long iMode = 1;
ioctlsocket(sock, FIONBIO, &iMode);