sockilist_find_reply_socket works now for IPv6

For IPv6 and IPv4 a socket with a good port is chosen for reply.

FossilOrigin-Name: 87778f4dd8978b40a3b818efcd610c845ee990337c74ce53b42f12cc2ed4dc2e
This commit is contained in:
7u83@mail.ru 2016-02-17 19:26:59 +00:00
parent e5161784d1
commit 883afba4fe

View File

@ -32,23 +32,27 @@
#include "socklist.h" #include "socklist.h"
struct socklistelem * socklist=0; #include "stdio.h"
struct socklistelem *socklist = 0;
int socklist_len; int socklist_len;
static pthread_mutex_t socklist_mutex; static pthread_mutex_t socklist_mutex;
static int socklist_wtpcount=0; static int socklist_wtpcount = 0;
int socklist_init() int socklist_init()
{ {
if (pthread_mutex_init(&socklist_mutex,NULL)) if (pthread_mutex_init(&socklist_mutex, NULL))
return 0; return 0;
socklist = malloc(sizeof(struct socklistelem) * SOCKLIST_SIZE); socklist = malloc(sizeof(struct socklistelem) * SOCKLIST_SIZE);
memset(socklist,0,sizeof(struct socklistelem) * SOCKLIST_SIZE); memset(socklist, 0, sizeof(struct socklistelem) * SOCKLIST_SIZE);
if (!socklist){ if (!socklist) {
cw_log(LOG_ERR,"Fatal error while initializing socklist: %s",strerror(errno)); cw_log(LOG_ERR, "Fatal error while initializing socklist: %s",
strerror(errno));
return 0; return 0;
} }
@ -70,11 +74,11 @@ void socklist_unlock()
void socklist_destroy() void socklist_destroy()
{ {
int i; int i;
for(i=0; i<socklist_len; i++){ for (i = 0; i < socklist_len; i++) {
close(socklist[i].sockfd); close(socklist[i].sockfd);
} }
free(socklist); free(socklist);
socklist=0; socklist = 0;
pthread_mutex_destroy(&socklist_mutex); pthread_mutex_destroy(&socklist_mutex);
} }
@ -84,68 +88,92 @@ void socklist_destroy()
* @param sa source address * @param sa source address
* @return socket or -1 if no socket was found * @return socket or -1 if no socket was found
*/ */
int socklist_find_reply_socket(struct sockaddr *sa) int socklist_find_reply_socket(struct sockaddr *sa,int port)
{ {
int bestsockfd=-1; int bestindex = -1;
int i; int i;
for (i=0; i<socklist_len;i++){ for (i = 0; i < socklist_len; i++) {
/* we can only determine a reply socket for IPv4 */ /* we want only an unicast socket for reply */
if (socklist[i].addr.sa_family != AF_INET)
continue;
/* and we want only a unicast socket for reply */
if (socklist[i].type != SOCKLIST_UNICAST_SOCKET) if (socklist[i].type != SOCKLIST_UNICAST_SOCKET)
continue; continue;
/* the first fd would be always the best if don't
/* and we want only sockets with same sa_family */
if (sa->sa_family != socklist[i].addr.sa_family)
continue;
/* the first fd would be always the best, if we don't
* find later a better one */ * find later a better one */
if (bestsockfd == -1){ if (bestindex == -1) {
bestsockfd = socklist[i].sockfd; bestindex = i;
continue; continue;
} }
/* we want first the same port */
if( sock_getport(&socklist[i].addr) != port){
continue;
}
/* if we havn't already found a socket with same port
* this is now our best socket*/
if( sock_getport(&socklist[bestindex].addr) != port){
bestindex=i;
}
/* the next checks only aply to IPv4 */
if (socklist[i].addr.sa_family != AF_INET)
continue;
/* get our source address and netmask */ /* get our source address and netmask */
uint32_t addr = ((struct sockaddr_in*)&socklist[i].addr)->sin_addr.s_addr; uint32_t addr =
uint32_t mask = ((struct sockaddr_in*)&socklist[i].netmask)->sin_addr.s_addr; ((struct sockaddr_in *) &socklist[i].addr)->sin_addr.s_addr;
uint32_t mask =
((struct sockaddr_in *) &socklist[i].netmask)->sin_addr.s_addr;
/* get source of requested address */ /* get source of requested address */
uint32_t saddr = ((struct sockaddr_in*)sa)->sin_addr.s_addr; uint32_t saddr = ((struct sockaddr_in *) sa)->sin_addr.s_addr;
if ( (addr & mask)== (saddr & mask) ){ if ((addr & mask) == (saddr & mask)) {
bestsockfd = socklist[i].sockfd; bestindex = i;
} }
} }
return bestsockfd; if (bestindex != -1)
return socklist[bestindex].sockfd;
return -1;
} }
static int find_reply_socket(struct sockaddr *sa,int bc) static int find_reply_socket(struct sockaddr *sa, int bc)
{ {
//printf("Looking for best sock of: %s\n",sock_addr2str(sa)); //printf("Looking for best sock of: %s\n",sock_addr2str(sa));
int bestsockfd = -1; int bestsockfd = -1;
int i; int i;
for (i=0; i<socklist_len; i++){ for (i = 0; i < socklist_len; i++) {
struct sockaddr_storage sn; struct sockaddr_storage sn;
memset(&sn,0,sizeof(sn)); memset(&sn, 0, sizeof(sn));
unsigned int snlen = sizeof(struct sockaddr_storage); unsigned int snlen = sizeof(struct sockaddr_storage);
if (getsockname(socklist[i].sockfd,(struct sockaddr*)&sn,&snlen)<0){ if (getsockname(socklist[i].sockfd, (struct sockaddr *) &sn, &snlen) < 0) {
continue; continue;
} }
if (sa->sa_family!=sn.ss_family) if (sa->sa_family != sn.ss_family)
continue; continue;
if (sn.ss_family == AF_INET){ if (sn.ss_family == AF_INET) {
int p1 = ntohs(((struct sockaddr_in *)sa)->sin_port); int p1 = ntohs(((struct sockaddr_in *) sa)->sin_port);
int p2 = ntohs(((struct sockaddr_in *)&sn)->sin_port); int p2 = ntohs(((struct sockaddr_in *) &sn)->sin_port);
if (p1 != p2) if (p1 != p2)
continue; continue;
@ -161,10 +189,11 @@ static int find_reply_socket(struct sockaddr *sa,int bc)
struct sockaddr_storage bcaddr; struct sockaddr_storage bcaddr;
if (!sock_getbroadcastaddr((struct sockaddr*)&sn,(struct sockaddr*)&bcaddr)) if (!sock_getbroadcastaddr
((struct sockaddr *) &sn, (struct sockaddr *) &bcaddr))
continue; continue;
if (sock_cmpaddr((struct sockaddr*)&bcaddr,sa,0)) if (sock_cmpaddr((struct sockaddr *) &bcaddr, sa, 0))
continue; continue;
bestsockfd = socklist[i].sockfd; bestsockfd = socklist[i].sockfd;
@ -192,93 +221,102 @@ void socklist_del_connection(int index)
int socklist_add_multicast(const char * addr, const char * port,int ac_proto) int socklist_add_multicast(const char *addr, const char *port, int ac_proto)
{ {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo * res,*res0; struct addrinfo *res, *res0;
memset(&hints,0,sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_flags=AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
int rc = getaddrinfo(addr,port,&hints,&res0); int rc = getaddrinfo(addr, port, &hints, &res0);
if (rc!=0) { if (rc != 0) {
cw_log(LOG_ERR,"Can't bind multicast address '%s': %s",addr,gai_strerror(rc)); cw_log(LOG_ERR, "Can't bind multicast address '%s': %s", addr,
gai_strerror(rc));
return 0; return 0;
} }
for(res=res0; res; res=res->ai_next){ for (res = res0; res; res = res->ai_next) {
struct sockaddr *sa = res->ai_addr; struct sockaddr *sa = res->ai_addr;
int sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0); int sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0);
/* create socket */ /* create socket */
if (sockfd==-1){ if (sockfd == -1) {
cw_log(LOG_ERR,"Can't create multicast socket: %",strerror(errno)); cw_log(LOG_ERR, "Can't create multicast socket: %",
strerror(errno));
continue; continue;
} }
/* bind address */ /* bind address */
if ( bind(sockfd,sa,sock_addrlen(sa)) < 0) { if (bind(sockfd, sa, sock_addrlen(sa)) < 0) {
close(sockfd); close(sockfd);
cw_log(LOG_ERR,"Can't bind multicast %s: %s",addr,strerror(errno)); cw_log(LOG_ERR, "Can't bind multicast %s: %s", addr,
strerror(errno));
continue; continue;
} }
/* use setsockopt() to request that the kernel joins a multicast group */ /* use setsockopt() to request that the kernel joins a multicast group */
void *opt; void *opt;
int optlen; int optlen;
if (res->ai_addr->sa_family == AF_INET){ if (res->ai_addr->sa_family == AF_INET) {
struct ip_mreq mreq; struct ip_mreq mreq;
memset(&mreq,0,sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
struct sockaddr_in * sain = (struct sockaddr_in*)res->ai_addr; struct sockaddr_in *sain = (struct sockaddr_in *) res->ai_addr;
mreq.imr_multiaddr.s_addr=sain->sin_addr.s_addr; mreq.imr_multiaddr.s_addr = sain->sin_addr.s_addr;
mreq.imr_interface.s_addr=htonl(INADDR_ANY); mreq.imr_interface.s_addr = htonl(INADDR_ANY);
opt = &mreq; opt = &mreq;
optlen=sizeof(mreq); optlen = sizeof(mreq);
char sinin[100]; char sinin[100];
sock_addrtostr((struct sockaddr*)sain,sinin,100); sock_addrtostr((struct sockaddr *) sain, sinin, 100);
if (setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,opt,optlen) < 0) { if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, opt, optlen)
< 0) {
close(sockfd); close(sockfd);
cw_log(LOG_ERR,"Can't add multicast membership %s: %s",addr,strerror(errno)); cw_log(LOG_ERR, "Can't add multicast membership %s: %s",
addr, strerror(errno));
continue; continue;
} }
} }
if (res->ai_addr->sa_family == AF_INET6){ if (res->ai_addr->sa_family == AF_INET6) {
struct ipv6_mreq mreq; struct ipv6_mreq mreq;
memset(&mreq,0,sizeof(mreq)); memset(&mreq, 0, sizeof(mreq));
struct sockaddr_in6 * sain6 = (struct sockaddr_in6*)res->ai_addr; struct sockaddr_in6 *sain6 = (struct sockaddr_in6 *) res->ai_addr;
// mreq.ipv6mr_multiaddr.s_addr=sain->sin_addr.s_addr; // mreq.ipv6mr_multiaddr.s_addr=sain->sin_addr.s_addr;
memcpy(&mreq.ipv6mr_multiaddr.s6_addr,&sain6->sin6_addr.s6_addr,sizeof(sain6->sin6_addr.s6_addr)); memcpy(&mreq.ipv6mr_multiaddr.s6_addr, &sain6->sin6_addr.s6_addr,
sizeof(sain6->sin6_addr.s6_addr));
// int si = sizeof(sain6->sin6_addr.s6_addr); // int si = sizeof(sain6->sin6_addr.s6_addr);
// int i = sain6->sin6_addr.s6_addr; // int i = sain6->sin6_addr.s6_addr;
mreq.ipv6mr_interface=0; //htonl(INADDR_ANY); mreq.ipv6mr_interface = 0; //htonl(INADDR_ANY);
opt = &mreq; opt = &mreq;
optlen=sizeof(mreq); optlen = sizeof(mreq);
if (setsockopt(sockfd,IPPROTO_IPV6,IPV6_JOIN_GROUP,opt,optlen) < 0) { if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP, opt, optlen)
< 0) {
close(sockfd); close(sockfd);
cw_log(LOG_ERR,"Can't join multicast group %s: %s",addr,strerror(errno)); cw_log(LOG_ERR, "Can't join multicast group %s: %s", addr,
strerror(errno));
continue; continue;
} }
} }
int rfd = find_reply_socket(sa,0); int rfd = find_reply_socket(sa, 0);
socklist[socklist_len].sockfd=sockfd; socklist[socklist_len].sockfd = sockfd;
socklist[socklist_len].reply_sockfd=rfd; socklist[socklist_len].reply_sockfd = rfd;
socklist[socklist_len].type=SOCKLIST_BCASTMCAST_SOCKET; socklist[socklist_len].type = SOCKLIST_BCASTMCAST_SOCKET;
socklist[socklist_len].family=sa->sa_family; socklist[socklist_len].family = sa->sa_family;
socklist[socklist_len].ac_proto=ac_proto; socklist[socklist_len].ac_proto = ac_proto;
socklist_len++; socklist_len++;
cw_log(LOG_INFO,"Bound to multicast group: %s (fd=%i,r:%i)",addr,sockfd,rfd); cw_log(LOG_INFO, "Bound to multicast group: %s (fd=%i,r:%i)", addr,
sockfd, rfd);
} }
freeaddrinfo(res0); freeaddrinfo(res0);
@ -286,64 +324,71 @@ int socklist_add_multicast(const char * addr, const char * port,int ac_proto)
} }
int socklist_add_unicast(const char *addr, const char * port, int ac_proto) int socklist_add_unicast(const char *addr, const char *port, int ac_proto)
{ {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo * res,*res0; struct addrinfo *res, *res0;
memset(&hints,0,sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_flags=AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
int rc = getaddrinfo(addr,port,&hints,&res0); int rc = getaddrinfo(addr, port, &hints, &res0);
if (rc!=0) { if (rc != 0) {
cw_log(LOG_ERR,"Can't bind unicast address '%s': %s",addr,gai_strerror(rc)); cw_log(LOG_ERR, "Can't bind unicast address '%s': %s", addr,
gai_strerror(rc));
return 0; return 0;
} }
for(res=res0; res; res=res->ai_next){ for (res = res0; res; res = res->ai_next) {
char ifname[64]; char ifname[64];
struct sockaddr netmask; struct sockaddr netmask;
struct sockaddr broadcast; struct sockaddr broadcast;
ifname[0]=0; ifname[0] = 0;
rc = sock_getifinfo(res->ai_addr,ifname,&broadcast,&netmask); rc = sock_getifinfo(res->ai_addr, ifname, &broadcast, &netmask);
if (!rc) { if (!rc) {
cw_log(LOG_ERR,"No interface found for %s, can't bind.",addr); cw_log(LOG_ERR, "No interface found for %s, can't bind.", addr);
continue; continue;
} }
struct sockaddr *sa = res->ai_addr; struct sockaddr *sa = res->ai_addr;
int sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0); int sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0);
/* create socket */ /* create socket */
if (sockfd==-1){ if (sockfd == -1) {
cw_log(LOG_ERR,"Can't create unicast socket: %",strerror(errno)); cw_log(LOG_ERR, "Can't create unicast socket: %s",
strerror(errno));
continue; continue;
} }
/* bind address */ /* bind address */
if ( bind(sockfd,sa,sock_addrlen(sa)) < 0) { if (bind(sockfd, sa, sock_addrlen(sa)) < 0) {
close(sockfd); close(sockfd);
cw_log(LOG_ERR,"Can't bind unicast socket %s: %s",addr,strerror(errno)); cw_log(LOG_ERR, "Can't bind unicast socket %s: %s", addr,
strerror(errno));
continue; continue;
} }
socklist[socklist_len].sockfd=sockfd; socklist[socklist_len].sockfd = sockfd;
socklist[socklist_len].reply_sockfd=sockfd; socklist[socklist_len].reply_sockfd = sockfd;
socklist[socklist_len].family=sa->sa_family; socklist[socklist_len].family = sa->sa_family;
socklist[socklist_len].type=SOCKLIST_UNICAST_SOCKET; socklist[socklist_len].type = SOCKLIST_UNICAST_SOCKET;
socklist[socklist_len].ac_proto=ac_proto; socklist[socklist_len].ac_proto = ac_proto;
if (res->ai_addr->sa_family == AF_INET ) { if (res->ai_addr->sa_family == AF_INET) {
memcpy(&socklist[socklist_len].netmask,&netmask,sock_addrlen(&netmask)); memcpy(&socklist[socklist_len].netmask, &netmask,
memcpy(&socklist[socklist_len].addr,res->ai_addr,sock_addrlen(res->ai_addr)); sock_addrlen(&netmask));
cw_log(LOG_INFO,"Bound to: %s (%i) on interface %s, netmask %s",addr,sockfd,ifname,sock_addr2str(&netmask)); memcpy(&socklist[socklist_len].addr, res->ai_addr,
} sock_addrlen(res->ai_addr));
else{ cw_log(LOG_INFO,
cw_log(LOG_INFO,"Bound to: %s (%i) on interface %s",addr,sockfd,ifname); "Bound to: %s:%s (%i) on interface %s, netmask %s", addr,
port, sockfd, ifname, sock_addr2str(&netmask));
} else {
cw_log(LOG_INFO, "Bound to: %s:%s (%i) on interface %s", addr,
port, sockfd, ifname);
} }
socklist_len++; socklist_len++;
@ -353,71 +398,77 @@ int socklist_add_unicast(const char *addr, const char * port, int ac_proto)
return 1; return 1;
} }
int socklist_add_broadcast(const char *addr, const char * port,int ac_proto) int socklist_add_broadcast(const char *addr, const char *port, int ac_proto)
{ {
struct addrinfo hints; struct addrinfo hints;
struct addrinfo * res,*res0; struct addrinfo *res, *res0;
memset(&hints,0,sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;
hints.ai_family = PF_UNSPEC; hints.ai_family = PF_UNSPEC;
hints.ai_flags=AI_PASSIVE; hints.ai_flags = AI_PASSIVE;
int rc = getaddrinfo(addr,port,&hints,&res0); int rc = getaddrinfo(addr, port, &hints, &res0);
if (rc!=0) { if (rc != 0) {
cw_log(LOG_ERR,"Can't bind broadcast address '%s': %s",addr,gai_strerror(rc)); cw_log(LOG_ERR, "Can't bind broadcast address '%s': %s", addr,
gai_strerror(rc));
return 0; return 0;
} }
int sockfd; int sockfd;
for(res=res0; res; res=res->ai_next){ for (res = res0; res; res = res->ai_next) {
struct sockaddr *sa = res->ai_addr; struct sockaddr *sa = res->ai_addr;
sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0); sockfd = socket(res->ai_addr->sa_family, SOCK_DGRAM, 0);
/* create socket */ /* create socket */
if (sockfd==-1){ if (sockfd == -1) {
cw_log(LOG_ERR,"Can't create broadcast socket: %",strerror(errno)); cw_log(LOG_ERR, "Can't create broadcast socket: %",
strerror(errno));
continue; continue;
} }
#ifdef IP_BINDANY #ifdef IP_BINDANY
struct sockaddr_in * sain = (struct sockaddr_in*)sa; struct sockaddr_in *sain = (struct sockaddr_in *) sa;
if (sain->sin_addr.s_addr==INADDR_BROADCAST ){ if (sain->sin_addr.s_addr == INADDR_BROADCAST) {
int opt=1; int opt = 1;
if (setsockopt(sockfd, IPPROTO_IP, IP_BINDANY, &opt, sizeof(opt))){ if (setsockopt(sockfd, IPPROTO_IP, IP_BINDANY, &opt, sizeof(opt))) {
cw_log(LOG_ERR,"Can't set sockopt IP_BIND_ANY: %s",strerror(errno)); cw_log(LOG_ERR, "Can't set sockopt IP_BIND_ANY: %s",
strerror(errno));
continue; continue;
}; };
} }
#endif #endif
/* bind address */ /* bind address */
if ( bind(sockfd,sa,sock_addrlen(sa)) < 0) { if (bind(sockfd, sa, sock_addrlen(sa)) < 0) {
close(sockfd); close(sockfd);
sockfd=-1; sockfd = -1;
cw_log(LOG_ERR,"Can't bind broadcast %s: %s",addr,strerror(errno)); cw_log(LOG_ERR, "Can't bind broadcast %s: %s", addr,
strerror(errno));
continue; continue;
} }
int rfd = find_reply_socket(sa,1); int rfd = find_reply_socket(sa, 1);
socklist[socklist_len].sockfd = sockfd;
socklist[socklist_len].reply_sockfd = rfd;
socklist[socklist_len].type = SOCKLIST_BCASTMCAST_SOCKET;
socklist[socklist_len].family = sa->sa_family;
socklist[socklist_len].ac_proto = ac_proto;
memcpy(&socklist[socklist_len].addr, res->ai_addr,
sock_addrlen(res->ai_addr));
socklist[socklist_len].sockfd=sockfd;
socklist[socklist_len].reply_sockfd=rfd;
socklist[socklist_len].type=SOCKLIST_BCASTMCAST_SOCKET;
socklist[socklist_len].family=sa->sa_family;
socklist[socklist_len].ac_proto=ac_proto;
// printf ("AC INIT PROTO : %d, i %i\n",ac_proto,socklist_len); // printf ("AC INIT PROTO : %d, i %i\n",ac_proto,socklist_len);
// printf ("sock proto %d\n",socklist[socklist_len].ac_proto); // printf ("sock proto %d\n",socklist[socklist_len].ac_proto);
socklist_len++; socklist_len++;
cw_log(LOG_INFO,"Bound to broadcast: %s:%s (%i,R:%i,I:%d)",addr,port,sockfd,rfd,socklist_len-1); cw_log(LOG_INFO, "Bound to broadcast: %s:%s (%i,R:%i,I:%d)", addr, port,
sockfd, rfd, socklist_len - 1);
} }
freeaddrinfo(res0); freeaddrinfo(res0);
return 1; return 1;
} }