/** *Creates a nonblocking IPv6 socket *@param sin sockaddr_in6 struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int os_getsocket6(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto) { struct sockaddr_in6 sin6; int on; int sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno)); olsr_exit(EXIT_FAILURE); } #ifdef IPV6_V6ONLY on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { OLSR_WARN(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to ipv6 only (%s)\n", strerror(errno)); } #endif //#ifdef SO_BROADCAST /* if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof(on)) < 0) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); close(sock); return (-1); } */ //#endif #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) { OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on); break; } if (on <= 8 * 1024) { OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno)); break; } } } #endif on = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } /* * we are abusing "on" here. The value is 1 which is our intended * hop limit value. */ if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot set multicast hops to 1 for socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, if_name) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } if (bindto == NULL) { memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = htons(port); bindto = (union olsr_sockaddr *)&sin6; } if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } os_socket_set_nonblocking(sock); return sock; }
/** *Creates a nonblocking IPv6 socket *@param sin sockaddr_in6 struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int getsocket6(int bufspace, struct interface *ifp) { struct sockaddr_in6 sin; int on; int sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); syslog(LOG_ERR, "socket: %m"); return (-1); } #ifdef IPV6_V6ONLY on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) { perror("setsockopt(IPV6_V6ONLY)"); syslog(LOG_ERR, "setsockopt(IPV6_V6ONLY): %m"); } #endif //#ifdef SO_BROADCAST /* if (setsockopt(sock, SOL_SOCKET, SO_MULTICAST, &on, sizeof (on)) < 0) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); close(sock); return (-1); } */ //#endif #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) break; if (on <= 8 * 1024) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); break; } } } #endif if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("SO_REUSEADDR failed"); close(sock); return (-1); } /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, ifp->int_name) < 0) { fprintf(stderr, "Could not bind socket to device... exiting!\n\n"); syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n"); close(sock); return -1; } memset(&sin, 0, sizeof(sin)); sin.sin6_family = AF_INET6; sin.sin6_port = htons(olsr_cnf->olsrport); sin.sin6_scope_id = ifp->if_index; if(bufspace <= 0) { memcpy(&sin.sin6_addr, &ifp->int6_addr.sin6_addr, sizeof(struct in6_addr)); } if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { struct ipaddr_str buf; OLSR_PRINTF(1, "Error, cannot bind address %s to %s-socket: %s (%d)\n", inet_ntop(sin.sin6_family, &sin.sin6_addr, buf.buf, sizeof(buf)), bufspace <= 0 ? "transmit" : "receive", strerror(errno), errno); syslog(LOG_ERR, "bind: %m"); close(sock); return (-1); } on = fcntl(sock, F_GETFL); if (on == -1) { syslog(LOG_ERR, "fcntl (F_GETFL): %m\n"); } else { if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) { syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n"); } } return sock; }
/** *Creates a nonblocking broadcast socket. *@param sa sockaddr struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int os_getsocket4(const char *if_name, uint16_t port, int bufspace, union olsr_sockaddr *bindto) { struct sockaddr_in sin4; int on; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot open socket for OLSR PDUs (%s)\n", strerror(errno)); olsr_exit(EXIT_FAILURE); } on = 1; #ifdef SO_BROADCAST if (bindto) { if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot set socket for OLSR PDUs to broadcast mode (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } } #endif if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot reuse address for OLSR PDUs (%s)\n", strerror(errno)); close(sock); olsr_exit(EXIT_FAILURE); } #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) { OLSR_DEBUG(LOG_NETWORKING, "Set socket buffer space to %d\n", on); break; } if (on <= 8 * 1024) { OLSR_WARN(LOG_NETWORKING, "Could not set a socket buffer space for OLSR PDUs (%s)\n", strerror(errno)); break; } } } #endif /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, if_name) < 0) { OLSR_ERROR(LOG_NETWORKING, "Cannot bind socket for OLSR PDUs to interface %s: %s (%d)\n", if_name, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } if (bindto == NULL) { memset(&sin4, 0, sizeof(sin4)); sin4.sin_family = AF_INET; sin4.sin_port = htons(port); sin4.sin_addr.s_addr = 0; bindto = (union olsr_sockaddr *)&sin4; } if (bind(sock, &bindto->std, sizeof(*bindto)) < 0) { #if !defined(REMOVE_LOG_ERROR) struct ipaddr_str buf; #endif OLSR_ERROR(LOG_NETWORKING, "Could not bind socket for OLSR PDUs to %s/%d: %s (%d)\n", inet_ntop(AF_INET, &sin4.sin_addr, buf.buf, sizeof(buf)), port, strerror(errno), errno); close(sock); olsr_exit(EXIT_FAILURE); } os_socket_set_nonblocking(sock); return sock; }
/** *Creates a nonblocking broadcast socket. *@param sa sockaddr struct. Used for bind(2). *@return the FD of the socket or -1 on error. */ int getsocket(int bufspace, struct interface *ifp) { struct sockaddr_in sin; int on; int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { perror("socket"); syslog(LOG_ERR, "socket: %m"); return -1; } on = 1; #ifdef SO_BROADCAST if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); close(sock); return -1; } #endif if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { perror("SO_REUSEADDR failed"); close(sock); return -1; } #ifdef SO_RCVBUF if(bufspace > 0) { for (on = bufspace;; on -= 1024) { if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &on, sizeof(on)) == 0) break; if (on <= 8 * 1024) { perror("setsockopt"); syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m"); break; } } } #endif /* * WHEN USING KERNEL 2.6 THIS MUST HAPPEN PRIOR TO THE PORT BINDING!!!! */ /* Bind to device */ if (bind_socket_to_device(sock, ifp->int_name) < 0) { fprintf(stderr, "Could not bind socket to device... exiting!\n\n"); syslog(LOG_ERR, "Could not bind socket to device... exiting!\n\n"); close(sock); return -1; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(olsr_cnf->olsrport); if(bufspace <= 0) { sin.sin_addr.s_addr = ifp->int_addr.sin_addr.s_addr; } if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); syslog(LOG_ERR, "bind: %m"); close(sock); return -1; } on = fcntl(sock, F_GETFL); if (on == -1) { syslog(LOG_ERR, "fcntl (F_GETFL): %m\n"); } else { if (fcntl(sock, F_SETFL, on | O_NONBLOCK) == -1) { syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n"); } } return sock; }