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.
Related
int main (int argc, char **argv){
int sockfd = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in addr;
bzero(&addr,sizeof addr);
addr.sin_family = AF_INET;
addr.sin_port = htons(9999);
struct hostent *server = gethostbyname("192.168.1.139");
printf("%s %d\n",server->h_addr,inet_pton(AF_INET,server->h_addr,&addr.sin_addr.s_addr));
int res = connect(sockfd,(struct sockaddr *)&addr,sizeof addr);
printf("%d\n",res);
while (1){
char buf[100] = "";
fgets(buf,100,stdin);
send(sockfd,buf,sizeof buf,0);
}
}
If I execute this code, I always get:
$ ./client
��� 0
-1
So:
Why I get these random chars? Why I don't see the IP string of h_addr?
Why the return of inet_pton is 0? It should be 1, 0 is for unsuccessfull, so why it fails?
Obviously, the connect fails.
Also, if instead of using inet_pton, I use this line:
bcopy((char *)server->h_addr,(char *)&addr.sin_addr.s_addr,h_length);
it works. BUT WHY it works this way and in the other way it doesn't??
My English is not very good, so please understand.
See gethostbyname() man page.
The gethostbyname() function returns a structure of type hostent for the given host name. Here name is either a hostname or an IPv4 address in standard dot notation (as for inet_addr(3)). If name is an IPv4 address, no lookup is performed and gethostbyname() simply copies name into the h_name field and its struct in_addr equivalent into the h_addr_list[0] field of the returned hostent structure.
h_addr_list[0] is struct in_addr and h_addr_list[0] is h_addr, See below.
struct hostent
struct hostent {
char * h_name;
char ** h_aliases;
int h_addrtype;
int h_length;
char ** h_addr_list;
};
#define h_addr h_addr_list[0]
struct in_addr
struct in_addr {
uint32_t s_addr;
}
So, if you want to see the IP string of h_addr, see the code below.
printf("%s\n", inet_ntoa(*(struct in_addr*)server->h_addr));
And you can use it by assigning the value of s_addr as addr.sin_addr.s_addr = *(unit32_t *)server->haddr;
Or you can make it simpler using addr.sin_addr.s_addr = inet_addr("192.168.1.139");
I was trying to write an ICMP ping code in C.
The following code works very well:
int main(){
struct sockaddr_in addr;
hname = gethostbyname("192.168.1.5");
bzero(&addr, sizeof(addr));
addr.sin_addr.s_addr = *(long*)hname->h_addr;
ping(&addr);
}
void ping(struct sockaddr_in *addr){
sendto(sd,&pckt,sizeof(pckt),0,(struct sockaddr*)addr,sizeof(*addr))
}
But when I removed the parameter of function ping as following, compile failed.
int main(){
ping();
}
void ping(){
struct sockaddr_in addr;
hname = gethostbyname("192.168.1.5");
bzero(&addr, sizeof(addr));
addr.sin_addr.s_addr = *(long*)hname->h_addr;
sendto(sd,&pckt,sizeof(pckt),0,(struct sockaddr*)addr,sizeof(*addr))
}
The error was:error: invalid type argument of unary ‘*’ (have ‘struct sockaddr_in’)
When I removed the * in sendto() function it still compiled error as:
error: conversion to non-scalar type requested
btw, I created struct sockaddr_in in ping() function, because I need to do multiple process and need to avoid share the same struct by multiple processes.
There was an error in the pointer to 'struct sockaddr_in addr'. I did some other fixes. You must be root to run this code.
#include <string.h>
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
void ping(char *, int);
int main(){
ping("data", 4);
}
void ping(char * pckt, int size){
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
struct hostent * hname = gethostbyname("localhost");
memcpy(&addr.sin_addr, hname->h_addr, hname->h_length);
int sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sd >= 0) {
if (sendto(sd,&pckt,size,0,(struct sockaddr*)&addr,sizeof(addr)) > 0) {
printf("send ok\n");
} else {
printf("send error\n");
}
} else {
printf("socket error\n");
}
}
Why you have
struct sockaddr_in *addr
in the upper one as argument
but
struct sockaddr_in addr
in the failed one?
why not define addr as struct pointer ?
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.
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.