Reputation: 81
I am trying to make something with supports IPV4 or IPV6. The code is similar for these two so I tried something like this. Since the only difference in code later on depends on this sin variable how can I compile just one of them. Lets suppose "ipv" variable in IF statement is true or false depends on user input
//FOR IPV4
//struct sockaddr_in sin;
//FOR IPV6
//struct sockaddr_in6 sin;
//IPV4
// IPV4 ---------------------------------------
if (ipv){
struct sockaddr_in sin;
if ( (s = socket(AF_INET, SOCK_STREAM, 0 ) ) < 0) {
perror("Chyba pri vytvareni socketu");
return -1;
}
sin.sin_family = AF_INET;
sin.sin_port = htons(port_number);
sin.sin_addr.s_addr = INADDR_ANY;
}
// IPV6 ---------------------------------------
else{
struct sockaddr_in6 sin;
if ( (s = socket(AF_INET6, SOCK_STREAM, 0 ) ) < 0) {
perror("Chyba pri vytvareni socketu");
return -1;
}
sin.sin6_family = AF_INET6;
sin.sin6_port = htons(port_number);
sin.sin6_addr = in6addr_any;
sin.sin6_flowinfo = 0;
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin) ) < 0 ) {
printf("error on bind\n"); return -1;
}
if (listen(s, 5)) {
printf ("error on listen\n");
return -1;
}
sinlen = sizeof(sin);
pid_t pid;
while (1) {
/* accepting new connection request from client,
socket id for the new connection is returned in t */
if ( (t = accept(s, (struct sockaddr *) &sin, &sinlen) ) < 0 ) {
printf("error on accept\n"); /* accept error */
return -1;
}
continues .... not important
this code will give me:
server.cpp: In function ‘int main(int, char**)’:
server.cpp:132:35: error: ‘sin’ was not declared in this scope
if (bind(s, (struct sockaddr *)&sin, sizeof(sin) ) < 0 ) {
^
server.cpp:145:19: error: ‘sin’ was not declared in this scope
sinlen = sizeof(sin);
^
make: *** [all] Error 1
So question is how can I make this done without writing the same code twice with different "sin";
Upvotes: 4
Views: 1962
Reputation: 2788
It's a typical case when you might use a union.
typedef union {
struct sockaddr_in v4;
struct sockaddr_in6 v6;
} sockaddr_union;
sockaddr_union sin;
Then, when you know you're working with IPV4, use sin.v4 in place of sin, and when you know you're working with IPV6, use sin.v6
Upvotes: 1
Reputation: 81
I did it like this by using sockaddr_storage and its working well
struct sockaddr_storage sin;
struct sockaddr_in *sin4;
struct sockaddr_in *sin6;
// IPV4 ---------------------------------------
if (ipv == true){
sin4 = (struct sockaddr_in*)&sin;
if ( (s = socket(AF_INET, SOCK_STREAM, 0 ) ) < 0) {
perror("Chyba pri vytvareni socketu");
return -1;
}
sin4->sin_family = AF_INET;
sin4->sin_port = htons(port_number);
sin4->sin_addr.s_addr = INADDR_ANY;
}
// IPV6 ---------------------------------------
else{
sin6 = (struct sockaddr_in6*)&sin;
if ( (s = socket(AF_INET6, SOCK_STREAM, 0 ) ) < 0) {
perror("Chyba pri vytvareni socketu");
return -1;
}
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port_number);
sin6->sin6_addr = in6addr_any;
sin6->sin6_flowinfo = 0;
}
if (bind(s, (struct sockaddr *)&sin, sizeof(sin) ) < 0 ) {
printf("error on bind\n"); return -1;
}
if (listen(s, 5)) {
printf ("error on listen\n");
return -1;
}
sinlen = sizeof(sin);
pid_t pid;
while (1) {
/* accepting new connection request from client,
socket id for the new connection is returned in t */
if ( (t = accept(s, (struct sockaddr *) &sin, &sinlen) ) < 0 ) {
printf("error on accept\n"); /* accept error */
return -1;
}
continues .... not important
Upvotes: 2