#include "../config.h"
+#ifdef HAVE_SYS_SOCKET_H
+
#include <osmocom/core/logging.h>
#include <osmocom/core/select.h>
#include <osmocom/core/socket.h>
-#include <arpa/inet.h>
+#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
-#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <ifaddrs.h>
int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto,
- const char *host, uint16_t port, int connect0_bind1)
+ const char *host, uint16_t port, unsigned int flags)
{
struct addrinfo hints, *result, *rp;
- int sfd, rc;
+ int sfd, rc, on = 1;
char portbuf[16];
+ if ((flags & (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT)) ==
+ (OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT))
+ return -EINVAL;
+
sprintf(portbuf, "%u", port);
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = family;
hints.ai_flags = 0;
hints.ai_protocol = proto;
+ if (flags & OSMO_SOCK_F_BIND)
+ hints.ai_flags |= AI_PASSIVE;
+
rc = getaddrinfo(host, portbuf, &hints, &result);
if (rc != 0) {
perror("getaddrinfo returned NULL");
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
- if (connect0_bind1 == 0) {
- if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+ if (flags & OSMO_SOCK_F_NONBLOCK) {
+ if (ioctl(sfd, FIONBIO, (unsigned char *)&on) < 0) {
+ perror("cannot set this socket unblocking");
+ close(sfd);
+ return -EINVAL;
+ }
+ }
+ if (flags & OSMO_SOCK_F_CONNECT) {
+ rc = connect(sfd, rp->ai_addr, rp->ai_addrlen);
+ if (rc != -1 || (rc == -1 && errno == EINPROGRESS))
break;
} else {
+ rc = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR,
+ &on, sizeof(on));
+ if (rc < 0) {
+ perror("cannot setsockopt socket");
+ break;
+ }
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
break;
}
perror("unable to connect/bind socket");
return -ENODEV;
}
+
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+
+ /* Make sure to call 'listen' on a bound, connection-oriented sock */
+ if (flags & OSMO_SOCK_F_BIND) {
+ switch (type) {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ listen(sfd, 10);
+ break;
+ }
+ }
+ return sfd;
+}
+
+int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto,
+ const char *host, uint16_t port, unsigned int flags)
+{
+ int sfd, rc;
+
+ sfd = osmo_sock_init(family, type, proto, host, port, flags);
+ if (sfd < 0)
+ return sfd;
+
+ ofd->fd = sfd;
+ ofd->when = BSC_FD_READ;
+
+ rc = osmo_fd_register(ofd);
+ if (rc < 0) {
+ close(sfd);
+ return rc;
+ }
+
return sfd;
}
int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type,
- uint8_t proto, int connect0_bind1)
+ uint8_t proto, unsigned int flags)
{
char host[NI_MAXHOST];
uint16_t port;
default:
return -EINVAL;
}
- fprintf(stderr, "==> PORT = %u\n", port);
s = getnameinfo(ss, sa_len, host, NI_MAXHOST,
NULL, 0, NI_NUMERICHOST);
return s;
}
- return osmo_sock_init(ss->sa_family, type, proto, host,
- port, connect0_bind1);
+ return osmo_sock_init(ss->sa_family, type, proto, host, port, flags);
}
static int sockaddr_equal(const struct sockaddr *a,
- const struct sockaddr *b, socklen_t len)
+ const struct sockaddr *b, unsigned int len)
{
struct sockaddr_in *sin_a, *sin_b;
struct sockaddr_in6 *sin6_a, *sin6_b;
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ if (!ifa->ifa_addr)
+ continue;
if (sockaddr_equal(ifa->ifa_addr, addr, addrlen))
return 1;
}
return 0;
}
+
+#endif /* HAVE_SYS_SOCKET_H */