data_size = recvfrom(sock_raw , buffer , 1024, 0 , &saddr ,
(socklen_t*)&saddr_size);
here is a recvfrom function, where i want to create a struct to 'saddr' and 'saddr_size' which is declared in the main() as follows
struct sockaddr saddr;
int saddr_size;
saddr_size = sizeof saddr;
and instead of buffer mentioned in the below write() api i have to use the struct variable.
int cont= write(logfile,buffer,data_size);
My question is: Below i have used structure.Is this the way to define struct for the following fields? Is it declared correctly? if not please somebody guide me to correct it.
struct data{
unsigned char buffer[1024];
unsigned long int saddr;
// struct sockaddr saddr;
int saddr_size;
};
struct data {
unsigned char buffer[1024];
struct sockaddr saddr;
socklen_t saddr_size;
};
Related
What does this error mean? error: expected expression before 'Addr'
typedef struct sockaddr_in Addr;
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
ZeroMemory(&Addr, sizeof(Addr)); // Error occurs here
return 0;
}
I added a comment where the error was occurring at.
You're not actually creating a variable you can call the function with, you're just typedef 'ing a type of variable that suits your needs. You actually need to declare a variable of that struct type in order for it to work.
Like this:
typedef struct sockaddr_in Addr; // Defining what a variable (struct) of type Addr is
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr testAddr; // Actually declaring a variable of type Addr
ZeroMemory(&testAddr, sizeof(Addr));
return 0;
}
Something like this should solve your error:
typedef struct sockaddr_in Addr;
int main() {
WSADATA Winsock;
SOCKET Socket, Sub;
Addr addr;
ZeroMemory(&addr, sizeof(Addr));
return 0;
}
Explanation here.
In a kernel module, given a struct sockaddr with sa_family initialized as AF_UNSPEC, how can I reliably determine if it is a struct sockaddr_in or struct sockaddr_in6? On Linux 3.16.0-4-686-pae (x86).
struct sockaddr {
unsigned short sa_family; // AF_UNSPEC
char sa_data[14]; // ?
};
struct sockaddr_in {
unsigned short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
struct sockaddr_in6 {
unsigned short sin6_family;
unsigned short sin6_port;
unsigned int sin6_flowinfo;
struct in6_addr sin6_addr;
unsigned int sin6_scope_id;
};
Usually, when something calls into the kernel and gives a struct sockaddr, it also has to give the length of the struct sockaddr. For example, see sendto():
ssize_t sendto (int sockfd, const void *buf, size_t buflen, int flags,
const struct sockaddr *addr, socklen_t addrlen);
Using the size of the buffer, you ought to be able to get a good guess as to what type of sockaddr you need to use:
if (addr.sa_family == AF_UNSPEC) {
switch (addrlen) {
case sizeof (struct sockaddr_in): {
addr.sa_family = AF_INET;
break;
}
case sizeof (struct sockaddr_in6): {
addr.sa_family = AF_INET6;
break;
}
default: {
// handle error
break;
}
}
}
In an ideal world, the sa_family would be set to seither AF_INET (IPv4) or AF_INET6 (IPv6) already, but unfortunately that doesn't appear to be the case here.
There was problem in receiving and processing the packets because i used to send just a buffer not 'saddr' and its 'size'
Hence i used structure to declare all the members ow instead of the field buffer in write() api i need to send the struct variable name . do i need to use pointer there?
struct fields
{
unsigned char buffer[1024];
socklen_t saddr_size;
} data;
First of all recvfrom returns the length of the message.
n = recvfrom(sock,buffer,1024,0,(struct sockaddr *)&from, &length);
if (n < 0) error("recvfrom");
Here length is the size of the socket structure you are using. This must be initialized prior to the call to recvfrom so that the kernel knows how much space is available to return the socket address.
also, note that (struct sockaddr *)&from will have the address of the remote socket used to send the datagram.
Now, in your call
data_size = recvfrom(sock_raw , buffer , 1024, 0 , &saddr , (socklen_t*)&saddr_size);
int cont= write(logfile,&data,data_size);
data_size will have the length of the message. But, size of data structure is more than the size of data_size. so, write may not write complete data to the logfile.
and make a note of Klas Lindbäck's comment. That is what you needed.
Please see the answer here.
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
struct fields
{
unsigned char buffer[1024];
struct sockaddr saddr;
socklen_t saddr_size;
} data;
int main()
{
int saddr_size;
struct fields data; // Note: this variable will hide the global variabledata.
struct sockaddr saddr;
ssize_t data_size;
int sock_raw, logfile=1;
// Need to insert code to create raw socket.
data_size = recvfrom(sock_raw, data.buffer, 1024, 0, &data.saddr,
&data.saddr_size);
int cont = write(logfile, &data, sizeof data);
return 0;
}
We know the Recvfrom function has following synopses
SYNOPSIS
#include <sys/socket.h>
int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
The from has the struct of sockaddr.
struct sockaddr {
__uint8_t sa_len; // total length
sa_family_t sa_family; // [XSI] address family
char sa_data[14]; // [XSI] addr value (actually larger)
};
But sockaddr doesn't seem to able to hold IP address.
Shouldn't recvfrom be using struct socaddr_in * from because
struct sockaddr_in {
__uint8_t sin_len;
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
And sin_addr will give the IP address. Is that a valid assumption?
The from parameter is defined as sockaddr* for historic reasons, to support legacy code that predates IPv6. sock_addr is fairly agnostic, but it also is not large enough to handle newer socket types. Any socket function that has a sockaddr* parameter actually expects whatever sockaddr-based struct is appropriate for the type of socket that is being used.
If you read from an IPv4 socket, it expects a sockaddr_in*, eg:
struct sockaddr_in from;
socklen_t len = sizeof(from);
recvfrom(s, ..., (struct sockaddr*)&from, &len);
// use from.sin_addr and from.sin_port as needed...
If you read from an IPv6 socket, it expects a sockaddr_in6* instead, eg:
struct sockaddr_in6 from;
socklen_t len = sizeof(from);
recvfrom(s, ..., (struct sockaddr*)&from, &len);
// use from.sin6_addr and from.sin6_port as needed...
If you want to write code that supports multiple protocols, use sockaddr_storage and type-cast as needed, eg:
struct sockaddr_storage from;
socklen_t len = sizeof(from);
recvfrom(s, ..., (struct sockaddr*)&from, &len);
switch (from.ss_family)
{
case AF_INET:
// use ((struct sockaddr_in*)&from) as needed...
break;
case AF_INET6:
// use ((struct sockaddr_in6*)&from) as needed...
break;
...
}
The same applies to other sockaddr-based functions, including connect(), bind(), accept() and sendto().
You can proceed as follows:
struct scokaddr_in A;
char buf[200];
int len;
recvfrom(fd, buf, 200, 0, (struct sockaddr*)&A, &len);
//from ip-address is stored in A.sin_addr...
If you wanted to save the IP address as a string, you could use the inet_ntop() function. Beej's guide provides some usefull info about how to use it, with IP-version agnostic examples.
Any one could describe how (struct sockaddr *)&server works here? Is it possible to cast bigger struct to smaller struct?
See these structs:
// IPv4 AF_INET sockets:
struct sockaddr_in {
short sin_family; // e.g. AF_INET, AF_INET6
unsigned short sin_port; // e.g. htons(3490)
struct in_addr sin_addr; // see struct in_addr, below
char sin_zero[8]; // zero this if you want to
};
struct in_addr {
unsigned long s_addr; // load with inet_pton()
};
struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};
This is the main program:
int main(int argc , char *argv[])
{
int socket_desc;
struct sockaddr_in server;
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
server.sin_addr.s_addr = inet_addr("74.125.235.20");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(socket_desc , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
return 0;
}
This is refered as Type Punning. Here, both structures have the same size, so there is no question of struct size. Although you can cast almost anything to anything, doing it with structures is error-prone.
This is C's form of "inheritance" (notice the quotes). This works because C does not care about the underlying data in an address, just what you represent it as.
The function determines what structure it actually is by using the sa_family field, and casting it into the proper sockaddr_in inside the function.
You can cast sockaddr_in to sockaddr, but you cannot usually cast ANY struct to ANY other and assume that things will work properly.
In C, it's possible to cast anything to anything. You could even omit the cast to (struct sockaddr*), and probably just get a compiler warning.