#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "server.h" #include "socktool.h" #include "connection.h" #include #include #include #include #include #include #include #include #include #include #include int ras_server_init ( RasServer* server, RasConnPerm perm, int domain, const char* log_file, int id) { /* chain up to parent constructor */ int rval = ras_conn_init (RAS_CONN (server), perm, domain, "ras-server", log_file, id); if (rval < 0) { return rval; } return 0; } void ras_server_destroy (RasServer* server) { if (RAS_CONN (server)->domain == AF_UNIX) { unlink (SOCKADDR_UN (&server->addr)->sun_path); } /* chain up to parent destructor */ ras_conn_destroy (RAS_CONN (server)); } int ras_server_listen (RasServer* server, const char* addr, int arg) { /* domain == AC_LOCAL => arg == mode * domain == AC_INET => arg == port * domain == AC_INET6 => arg == port */ int len, fd; struct sockaddr_storage sock; socklen_t socklen; memset (&sock, 0, sizeof (sock)); switch (RAS_CONN (server)->domain) { case AF_UNIX: socklen = sizeof (struct sockaddr_un); len = socklen - offsetof (struct sockaddr_un, sun_path) - 1; SOCKADDR_UN (&sock)->sun_family = AF_UNIX; strncpy (SOCKADDR_UN (&sock)->sun_path, addr, len); ras_server_log (server, "addr = %s, mode = %o", addr, arg); break; case AF_INET: socklen = sizeof (struct sockaddr_in); SOCKADDR_IN (&sock)->sin_family = AF_INET; SOCKADDR_IN (&sock)->sin_port = htons (arg); if (addr == NULL) { SOCKADDR_IN (&sock)->sin_addr.s_addr = htonl (INADDR_ANY); addr = "any"; } else { if (inet_pton (AF_INET, addr, &(SOCKADDR_IN (&sock)->sin_addr)) <= 0) { ras_server_log (server, "unknown IPv4 address: %s", addr); return -1; } } ras_server_log (server, "addr = %s, port = %d", addr, arg); break; case AF_INET6: socklen = sizeof (struct sockaddr_in6); SOCKADDR_IN6 (&sock)->sin6_family = AF_INET6; SOCKADDR_IN6 (&sock)->sin6_port = htons (arg); if (addr == NULL) { SOCKADDR_IN6 (&sock)->sin6_addr = in6addr_any; addr = "any"; } else { if (inet_pton (AF_INET6, addr, &(SOCKADDR_IN6 (&sock)->sin6_addr)) <= 0) { ras_server_log (server, "unknown IPv6 address: %s", addr); return -1; } } ras_server_log (server, "addr = %s, port = %d", addr, arg); break; default: return -1; } fd = socket (RAS_CONN (server)->domain, SOCK_STREAM, 0); if (fd < 0) { ras_server_log (server, "socket: %s", strerror (errno)); goto fd_opened; } if (RAS_CONN (server)->domain == AF_INET6) { int yes = 1; setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof (yes)); } if (RAS_CONN (server)->domain == AF_UNIX) { fchmod (fd, arg); } if (bind (fd, SOCKADDR (&sock), socklen)) { ras_server_log (server, "bind: %s", strerror (errno)); goto fd_opened; } if (listen (fd, SOMAXCONN)) { ras_server_log (server, "listen: %s", strerror (errno)); goto fd_opened; } RAS_CONN (server)->fd = fd; RAS_CONN (server)->fd_is_set = true; server->addr = sock; server->addrlen = socklen; return 0; fd_opened: close (fd); return -1; }