Click to See Complete Forum and Search --> : Socket Programming (again)
aph3x
11-09-2000, 03:11 AM
okay, when i compile i get the following warning:
socket.c In function 'main':
socket.c:51 warning: passing arg 2 of 'accept' from incompatible pointer type
here is my declaration for the connecting clients' address:
struct sockaddr_in their_addr;
.
.
.
sock is the orignal socket descriptor from the socket() call and new_sock is the newly created socket. here's how i have passed the clients' address to accept():
if((new_sock = accept(sock, (struct sockaddr_in *)&their_addr, sizeof(struct sockaddr_in))<0)
.
.
.
any idea(s) why im getting this warning?
thanks http://www.linuxnewbie.org/ubb/biggrin.gif
aph3x
11-09-2000, 04:11 AM
okay, ive figured out why im getting the warning... apparently it's beacuse i used sockaddr_in instead of sockaddr in the accept() call (see above). however, this brings up another question: if i declare their_addr as type sockaddr_in, why do i use sockaddr in accept() when using their_addr.
thanks again! http://www.linuxnewbie.org/ubb/biggrin.gif
The_Stack
11-09-2000, 01:01 PM
The definition of accept() requires that the 2nd parameter be of type struct sockaddr*
This means if you attempt to pass &their_addr as the 2nd parameter then the compiler will complain.
If you look at struct sockaddr and struct sockaddr_in you will notice that they take up the same amount of memory; you should be able to cast sockaddr into sockaddr_in and to cast sockaddr_in to sockaddr:
accept(s,(struct sockaddr*)&their_addr,sizof(struct sockaddr_in));
The_Stack
11-09-2000, 01:01 PM
The definition of accept() requires that the 2nd parameter be of type struct sockaddr*
This means if you attempt to pass &their_addr as the 2nd parameter then the compiler will complain.
If you look at struct sockaddr and struct sockaddr_in you will notice that they take up the same amount of memory; you should be able to cast sockaddr into sockaddr_in and to cast sockaddr_in to sockaddr:
accept(s,(struct sockaddr*)&their_addr,sizof(struct sockaddr_in));
Strike
11-09-2000, 01:33 PM
Originally posted by aph3x:
if i declare their_addr as type sockaddr_in, why do i use sockaddr in accept() when using their_addr
Like The_Stack said, it's a matter of what is required by the function. accept() takes (int, sockaddr*, int*) I believe. So, you have to type-case your sockaddr_in as a sockaddr * in order to make accept() happy.
Strike
11-09-2000, 01:38 PM
Actually, the last argument is a socklen_t which I grepped for and found to be an unsigned int:
[ddipaolo@Janus02 ddipaolo]$ grep socklen /usr/include/*/* | grep typedef
...<snipped a bunch of "Is a directory" entries>...
/usr/include/bits/socket.h:typedef unsigned int socklen_t;
aph3x
11-09-2000, 02:17 PM
okay, gotcha...
thanks again http://www.linuxnewbie.org/ubb/biggrin.gif
LloydM
11-10-2000, 04:34 PM
This object oriented programming in C http://www.linuxnewbie.org/ubb/smile.gif
If you look at struct sockaddr and struct sockaddr_in you will notice that they take up the same amount of memory; you should be able to cast sockaddr into sockaddr_in and to cast sockaddr_in to sockaddr
Not exactly. (I don't have any source with me currently, so can't verify it - I already made a mistake with fgets as Jemfinch pointed out). But the idea, is you can have other protocols that supported the BSD sockets interface. struct sockaddr, is the base class structure for address structure. struct sockaddr_in, is IPv4's subclass of struct sockaddr.
There may be other address structures like IPv6's struct sockaddr_in6, which has different fields, but you can be sure, that the first few fields are struct sockaddr. Or a sockets interface for IPX, X.25, etc.
That is why you also pass in the size of the structure, so you know exactly how big it is.
Unfortunately there is no real support for subclassing and polymorphism in C, and why you have to resort to casts.
A cast is simply a statement that says treat this like that. In C++, that is what is really happening, under the covers. To answer the question, cast
new=accept(sock, (struct sockaddr *) &sockaddr_in, &sockaddr_in_length);
The bind statement will look pretty much the same.
Paul
LloydM
11-13-2000, 02:57 AM
Yes a cast basically forces a block of memory to be something, that can easily be manipulated. You can even do this:
FILE *fp = (FILE*)5;
However, that does not mean, that the memory pointed to by 0x05 has FILE structure.
C is not strictly an OO language, but a lot of OO ideas can be done in C using structures.
e.g.
struct base {
int x;
int y;
}
struct derived {
struct derived;
int a;
};
struct derived x;
struct base *ptr = (struct base*) x;
This cast is safe, because we know the first few bytes of derived is identical to struct base (ignoring byte alignment that in some cases).
The first example however, is pretty much unsafe.
To better understand why such cast is needed, here is how a bind function might have been implemented:
int bind( int sock, struct sockaddr* sin, size_t len )
{
switch ( sin->sin_family ) {
case AF_INET:
return bind_ipv4( sock, (struct sockaddr_in*)sin, len );
case AF_INET6:
return bind_ipv6( sock, (struct sockaddr_in6*)sin, len );
default:
return EPROTONOSUPPORT;
}
}
You see we need at least struct sockaddr to let us now what the structure really is, then we can cast it again.