I defined a struct like this (and other fields but they are not relevant with the question)
typedef struct {
struct sockaddr_in addr_destination;
}MY_PACKET;
The main call a function send_command
struct sockaddr_in *addr_server;
socklen_t addr_server_lenght;
MY_PACKET command_packet;
void send_command(char *comm, int socket_file_descriptor, struct sockaddr_in *server_address) {
addr_server = server_address;
addr_server_lenght = sizeof(*addr_server);
printf("Server address: %s\n", inet_ntoa(addr_server->sin_addr));
command_packet.addr_destination = *addr_server;
printf("Server address: %s\n", inet_ntoa(command_packet.addr_destination.sin_addr));
}
so the first printf prints "127.0.0.1" correctly
the second prints "0.0.0.0"
The rest of the program consists on a thread that send this packet to a server and wait for ack (so i must be able to access all the fields of command_packet from the thread function), but I'm stuck saving the server address in the packet correctly, what am I doing wrong? Thanks
Related
From gethostbyname(3) - Linux manual
The functions gethostbyname() and gethostbyaddr() may return pointers
to static data, which may be overwritten by later calls. Copying the
struct hostent does not suffice, since it contains pointers; a deep
copy is required.
I've written programs that make multiple calls to gethostbyname and haven't had anything break because of overwriting of static data.
Could I ask for an example when multiple calls to gethostbyname would overwrite this static data?
It will be a problem when you do something like this:
struct hostent *google = gethostbyname("www.google.com");
struct hostent *youtube = gethostbyname("www.youtube.com");
printf("Official name of host for www.google.com: %s\n", google->h_name);
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);
printf("same? %s\n", google == youtube ? "yes" : "no");
The output will be
Official name of host for www.google.com: youtube-ui.l.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com
same? yes
which is wrong, as the official host name of www.google.com is www.google.com
and not youtube-ui.l.google.com. The problem is that google and youtube
point at the same location (as you can see from the same? yes output),
so the information about www.google.com is lost when you execute gethostbyname again.
If you however do
struct hostent *google = gethostbyname("www.google.com");
printf("Official name of host for www.google.com: %s\n", google->h_name);
struct hostent *youtube = gethostbyname("www.youtube.com");
printf("Official name of host for www.youtube.com: %s\n", youtube->h_name);
then the output will be
Official name of host for www.google.com: www.google.com
Official name of host for www.youtube.com: youtube-ui.l.google.com
So as long as you process the hostent pointer of the first gethostbyname
call before you do the second call, you will be fine.
struct hostent *host1 = gethostbyname("host1");
struct hostent *host2 = gethostbyname("host2");
if(host1......)
the second call has overwritten (possibly) the result of the first one
Here's an example:
struct hostent *he1 = gethostbyname("host1");
struct in_addr *addr1 = (struct in_addr *)(he1->h_addr);
printf("addr1=%s\n", inet_ntoa(*addr1)); // prints IP1
struct hostent *he2 = gethostbyname("host2");
struct in_addr *addr2 = (struct in_addr *)(he2->h_addr);
printf("addr2=%s\n", inet_ntoa(*addr2)); // prints IP2
printf("addr1=%s\n", inet_ntoa(*addr1)); // prints IP1 (!)
In the next code, while I try to connect a client the server shows the following error:
"invalid argument", I can't see the error.
if((l_sock=socket(AF_INET,SOCK_STREAM,0))!=-1)
{
struct sockaddr_in srv_dir;
srv_dir.sin_family=AF_INET;
srv_dir.sin_port=8500;
srv_dir.sin_addr.s_addr=INADDR_ANY;
if((bind(l_sock,(struct sockaddr *)&srv_dir,sizeof(struct sockaddr_in)))!=-1)
{
if(!(listen(l_sock,5)))
{
signal(SIGINT,cerraje);
int t_sock;
struct sockaddr_in cli_dir;
socklen_t tam;
time_t tstmp;
struct tm * res;
res=(struct tm *)malloc(sizeof(struct tm));
while(!key)
{
if((t_sock=accept(l_sock,(struct sockaddr *)&cli_dir,&tam))!=-1)
{
tstmp=time(&tstmp);
res=gmtime(&tstmp);
send(t_sock,res,sizeof(struct tm),0);
wr_hora(*res,cli_dir.sin_addr);
}
else
perror("PeticiĆ³n no atendida");//The error is printed here.
Read the documentation on accept(2):
The addrlen argument is a value-result argument: it should initially contain the size of the structure pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. When addr is NULL nothing is filled in.
So you need to initialize the value of tam passed into accept with sizeof(cli_dir). You're fortunate that the socket library was able to catch your error, because you're passing in uninitialized memory, which results in undefined behavior.
I want to send data to my friend. I don't know his IP address. But I know his MAC address. So I have to send data using Ethernet frames.
I wrote a program, but it is not working. I didn't understand where is the problem? Where I did a mistake?
client side frame sending:
main()
{
int size ;
char req[10];
printf("enter to send\n");
gets(req);
int fd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP));
if (fd==-1)
{
perror("socket");
}
struct ifreq ifr;
char if_name[5]="eth0";
int if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name))
{
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
}
else
{
printf("interface name is too long");
}
if (ioctl(fd,SIOCGIFINDEX,&ifr)==-1)
{
perror("ioctl");
}
int ifindex=ifr.ifr_ifindex;
printf("ethernet interface id:%x\n",ifindex);
const unsigned char ether_broadcast_addr[]={0x00,0x1d,0x09,0x7a,0xDf,0x5e};
struct sockaddr_ll addr={0};
addr.sll_family=PF_PACKET;
addr.sll_ifindex=ifindex;
addr.sll_halen=ETHER_ADDR_LEN;
//addr.sll_protocol=htons(ETH_P_IP);
memcpy(&addr.sll_addr,ether_broadcast_addr,ETHER_ADDR_LEN);
addr.sll_hatype=772;
addr.sll_pkttype=PACKET_OUTGOING;
printf("size=%d\n",size);
if (size=sendto(fd,req,sizeof(req),0,(struct sockaddr*)&addr,sizeof(addr))==-1)
{
perror("sendto");
}
printf("send size=%d\n",size);
}
frame receive code at server side:
main()
{
int size;
char req[20];
int fd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if (fd==-1)
{
perror("socket");
}
struct ifreq ifr;
char if_name[5]="eth0";
int if_name_len=strlen(if_name);
if (if_name_len<sizeof(ifr.ifr_name))
{
memcpy(ifr.ifr_name,if_name,if_name_len);
ifr.ifr_name[if_name_len]=0;
}
else
{
printf("interface name is too long");
}
if (ioctl(fd,SIOCGIFINDEX,&ifr)==-1)
{
perror("ioctl");
}
int ifindex=ifr.ifr_ifindex;
printf("ethernet interface id:%x\n",ifindex);
const unsigned char ether_broadcast_addr[]={0x00,0x1d,0x09,0x7a,0xDf,0x5e};
struct sockaddr_ll addr={0};
addr.sll_family=PF_PACKET;
addr.sll_ifindex=ifindex;
addr.sll_halen=ETHER_ADDR_LEN;
addr.sll_protocol=htons(ETH_P_ALL);
memcpy(&addr.sll_addr,ether_broadcast_addr,ETHER_ADDR_LEN);
addr.sll_pkttype=PACKET_OUTGOING;
addr.sll_hatype=772;
bind (fd, (struct sockaddr*)&addr, sizeof(addr));
printf("size=%d\n",size);
socklen_t a=sizeof(addr);
size=recvfrom(fd,req,sizeof(req),0,(struct sockaddr*)&addr,&a);
if(size==-1)
{
perror("recvfrom");
}
printf("size=%d\n",size);
printf("recv msg=%s\n",req);
}
while your program may work in sending a data frame onto the network it will not get anywhere from there.MAC addresses are non Hierarchical which means the address space is flat. Knowing a MAC address tells you nothing on how to reach that address.
Having someones MAC address is the same as having someones name. You may know their name but you can not call them with our their phone number. Now if you have their full name you can look up their phone number. Networking is similar.
Network data (Packets) are sent from you computer to your default gateway which is a DSL or cable modem that connects to your ISP. When it receives the packet it looks at the IP address to decide where to send it. Since your frame (data without an IP address is called a frame) does not have an IP address the gateway will just delete it. To be more precise since it does not have an destination or source IP address it never really gets to the gateway. It is transmitted on the network and nothing is done with it.
In the next code, while I try to connect a client the server shows the following error:
"invalid argument", I can't see the error.
if((l_sock=socket(AF_INET,SOCK_STREAM,0))!=-1)
{
struct sockaddr_in srv_dir;
srv_dir.sin_family=AF_INET;
srv_dir.sin_port=8500;
srv_dir.sin_addr.s_addr=INADDR_ANY;
if((bind(l_sock,(struct sockaddr *)&srv_dir,sizeof(struct sockaddr_in)))!=-1)
{
if(!(listen(l_sock,5)))
{
signal(SIGINT,cerraje);
int t_sock;
struct sockaddr_in cli_dir;
socklen_t tam;
time_t tstmp;
struct tm * res;
res=(struct tm *)malloc(sizeof(struct tm));
while(!key)
{
if((t_sock=accept(l_sock,(struct sockaddr *)&cli_dir,&tam))!=-1)
{
tstmp=time(&tstmp);
res=gmtime(&tstmp);
send(t_sock,res,sizeof(struct tm),0);
wr_hora(*res,cli_dir.sin_addr);
}
else
perror("PeticiĆ³n no atendida");//The error is printed here.
Read the documentation on accept(2):
The addrlen argument is a value-result argument: it should initially contain the size of the structure pointed to by addr; on return it will contain the actual length (in bytes) of the address returned. When addr is NULL nothing is filled in.
So you need to initialize the value of tam passed into accept with sizeof(cli_dir). You're fortunate that the socket library was able to catch your error, because you're passing in uninitialized memory, which results in undefined behavior.
I have written a small server
#include <stdio.h>
#include <netinet/in.h>
#include <sys/types.h>
int main()
{
int server_fd, newsock_fd, server_len, newsock_len;
struct sockaddr_in server_struct, newsock_struct;
server_fd=socket(AF_INET,SOCK_STREAM,0);
server_struct.sin_family=AF_INET;
server_struct.sin_addr.s_addr=inet_addr("127.0.0.1");
server_struct.sin_port=htons(9734);
server_len=sizeof(server_struct);
newsock_len=server_len;
bind(server_fd,(struct sockaddr *)&server_struct,server_len);
listen(server_fd,5);
while(1)
{
printf("server waiting\n");
newsock_fd=accept(server_fd,(struct sockaddr *)&newsock_fd,&newsock_len);
char ch;
read(newsock_fd,&ch,1);
printf("got charachter %c\n",ch);
close(newsock_fd);
}
return 0;
}
When I am running it, the accept calls blocks initially, but after it creates the new socket it does not blocks for the second time.
I am getting this type of output:-
server waiting <= blocks initially , started client
got charachter a <= correctly displays the charachetr
server waiting <= expected to be blocked again ????
got charachter a
server waiting
got charachter a
server waiting
Am I missing something?
This line here:
newsock_fd=accept(server_fd,(struct sockaddr *)&newsock_fd,&newsock_len);
is, shall we say, rather interesting.
Why do you give the address of your newsock_fd as the second parameter? That's just asking for trouble :-)
I think it should probably be:
newsock_fd = accept (server_fd, (struct sockaddr *)&newsock_struct, &newsock_len);
int server_fd, newsock_fd, server_len, newsock_len;
struct sockaddr_in server_struct, newsock_struct;
/* ... */
newsock_fd=accept(server_fd,(struct sockaddr *)&newsock_fd,&newsock_len);
From accept(2):
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
You're passing a pointer to a file descriptor, not a struct sockaddr.