void Server_setupUDPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) { int val = 0; int sockets[2] = {-1, -1}; udpsocks = Memory_safeCalloc(nofServerSocks / 2, sizeof(int)); if (hasv4) { sockets[0] = socket(PF_INET, SOCK_DGRAM, 0); if (bind(sockets[0], (struct sockaddr *) addresses[0], sizeof (struct sockaddr_in)) < 0) { char *addressString = Util_addressToString(addresses[0]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno)); free(addressString); } val = 0xe0; if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; if (setsockopt(sockets[0], IPPROTO_IP, IP_TOS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(sockets[0], F_SETFL, O_NONBLOCK); pollfds[(hasv6) ? 2 : 1].fd = sockets[0]; pollfds[(hasv6) ? 2 : 1].events = POLLIN | POLLHUP | POLLERR; udpsocks[0] = sockets[0]; } if (hasv6) { sockets[1] = socket(PF_INET6, SOCK_DGRAM, 0); if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int)) != 0) Log_fatal("setsockopt IPv6: %s", strerror(errno)); if (bind(sockets[1], (struct sockaddr *) addresses[1], sizeof (struct sockaddr_in6)) < 0) { char *addressString = Util_addressToString(addresses[1]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno)); free(addressString); } val = 0xe0; if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(sockets[1], F_SETFL, O_NONBLOCK); pollfds[(hasv4) ? 3 : 1].fd = sockets[1]; pollfds[(hasv4) ? 3 : 1].events = POLLIN | POLLHUP | POLLERR; udpsocks[(hasv4) ? 1 : 0] = sockets[1]; } }
void * Memory_safeMalloc(size_t nmem, size_t size) { // Check if we're going to overflow. if (size && nmem > SIZE_MAX / size) Log_fatal("Request for memory would've overflowed."); // Allocate the memory requested. void * retPtr = malloc(nmem * size); // Check if we had an error. if (retPtr == NULL) Log_fatal("Out of memory."); return retPtr; }
/* Check which IP versions are supported by the system. */ void checkIPversions() { int testsocket = -1; testsocket = socket(PF_INET, SOCK_STREAM, 0); hasv4 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true; if (!(testsocket < 0)) close(testsocket); testsocket = socket(PF_INET6, SOCK_STREAM, 0); hasv6 = (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) ? false : true; if (!(testsocket < 0)) close(testsocket); if(!hasv4) { Log_info("IPv4 is not supported by this system"); nofServerSocks -= 2; } if(!hasv6) { Log_info("IPv6 is not supported by this system"); nofServerSocks -= 2; } if(nofServerSocks == 0) { Log_fatal("Neither IPv4 nor IPv6 are supported by this system"); } }
void lockfile(const char *pidfile) { int lfp, flags; char str[16]; /* Don't use O_TRUNC here -- we want to leave the PID file * unmodified if we cannot lock it. */ lfp = open(pidfile, O_WRONLY|O_CREAT, 0640); if (lfp < 0) Log_fatal("Cannot open PID-file %s for writing", pidfile); /* Try to lock the file. */ if (lockf(lfp, F_TLOCK, 0) < 0) { close(lfp); if (errno == EACCES || errno == EAGAIN) Log_fatal("PID file is locked -- uMurmur already running?"); Log_fatal("Cannot lock PID file: %s", strerror(errno)); } /* Now that we locked the file, erase its contents. */ if (ftruncate(lfp, 0) < 0) { close(lfp); Log_fatal("Cannot truncate PID file: %s", strerror(errno)); } snprintf(str,16,"%d\n", getpid()); (void)write(lfp, str, strlen(str)); /* record pid to lockfile */ Log_info("PID-file: %s", pidfile); /* If uMurmur ever starts to fork()+exec(), we don't want it to * leak the fd to the forked process though. Set the close-on-exec * flag to prevent leakage. */ flags = fcntl(lfp, F_GETFD, 0); flags |= FD_CLOEXEC; fcntl(lfp, F_SETFD, (long) flags); /* Don't close(lfp) here! * We want the fd to remain opened so the lock is held until the * process exits. */ lfp = -1; }
void Server_setupTCPSockets(struct sockaddr_storage* addresses[2], struct pollfd* pollfds) { int yes = 1; int sockets[2]; if (hasv4) { /* IPv4 socket setup */ sockets[0] = socket(PF_INET, SOCK_STREAM, 0); if (sockets[0] < 0) Log_fatal("socket IPv4"); if (setsockopt(sockets[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) Log_fatal("setsockopt IPv4: %s", strerror(errno)); if (bind(sockets[0], (struct sockaddr *)addresses[0], sizeof (struct sockaddr_in)) < 0) { char *addressString = Util_addressToString(addresses[0]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[0]), strerror(errno)); free(addressString); } if (listen(sockets[0], 3) < 0) Log_fatal("listen IPv4"); fcntl(sockets[0], F_SETFL, O_NONBLOCK); pollfds[0].fd = sockets[0]; pollfds[0].events = POLLIN; } if (hasv6) { /* IPv6 socket setup */ sockets[1] = socket(PF_INET6, SOCK_STREAM, 0); if (sockets[1] < 0) Log_fatal("socket IPv6: %s", strerror(errno)); if (setsockopt(sockets[1], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) Log_fatal("setsockopt IPv6: %s", strerror(errno)); if (setsockopt(sockets[1], IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(int)) != 0) Log_fatal("setsockopt IPv6: %s", strerror(errno)); if (bind(sockets[1], (struct sockaddr *)addresses[1], sizeof (struct sockaddr_in6)) < 0) { char *addressString = Util_addressToString(addresses[1]); Log_fatal("bind %s %d: %s", addressString, Util_addressToPort(addresses[1]), strerror(errno)); free(addressString); } if (listen(sockets[1], 3) < 0) Log_fatal("listen IPv6"); fcntl(sockets[1], F_SETFL, O_NONBLOCK); /* If there is an IPv4 address, then IPv6 will use the second socket, otherwise it uses the first */ pollfds[(hasv4) ? 1 : 0].fd = sockets[1]; pollfds[(hasv4) ? 1 : 0].events = POLLIN; } }
void Conf_init(const char *conffile) { config_init(&configuration); if (conffile == NULL) conffile = defaultconfig; if (config_read_file(&configuration, conffile) != CONFIG_TRUE) { Log_fatal("Error in config file %s line %d: %s", conffile, config_error_line(&configuration), config_error_text(&configuration)); } }
void * Memory_safeCalloc(size_t nmem, size_t size) { // Allocate the memory requested. void * retPtr = calloc(nmem, size); // Check if we had an error. if (retPtr == NULL) Log_fatal("Out of memory."); return retPtr; }
void Sharedmemory_init( int bindport, int bindport6 ) { int server_max_clients = getIntConf(MAX_CLIENTS); int shmtotal_size = sizeof( shm_t ) + (sizeof( shmclient_t ) * server_max_clients); if( !bindport ) { bindport = getIntConf(BINDPORT); } sprintf( shm_file_name, "/umurmurd:%i", bindport ); Log_info("SHM_API: shm_fd=\"%s\"", shm_file_name ); shm_fd = shm_open( shm_file_name, O_CREAT | O_RDWR, 0660 ); if(shm_fd == -1) { Log_fatal( "SHM_API: Open failed:%s\n", strerror(errno)); exit(EXIT_FAILURE); } if( ftruncate( shm_fd, shmtotal_size ) == -1 ) { Log_fatal( "SHM_API: ftruncate : %s\n", strerror(errno)); exit(EXIT_FAILURE); } shmptr = mmap( 0, shmtotal_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0 ); if (shmptr == MAP_FAILED) { Log_fatal( "SHM_API: mmap failed : %s\n", strerror(errno)); exit(EXIT_FAILURE); } memset( shmptr, 0, shmtotal_size ); shmptr->umurmurd_pid = getpid(); shmptr->server_max_clients = server_max_clients; shmptr->shmtotal_size = shmtotal_size; shmptr->shmclient_size = sizeof( shmclient_t ) * shmptr->server_max_clients; }
pds_t *Pds_create(uint8_t *buf, int size) { pds_t *pds = malloc(sizeof(pds_t)); if (pds == NULL) Log_fatal("Out of memory"); pds->data = buf; pds->offset = pds->overshoot = 0; pds->maxsize = size; pds->bOk = true; return pds; }
void SSLi_init() { if(gnutls_priority_init(&cipherCache, ciphers, NULL) != GNUTLS_E_SUCCESS) { Log_fatal("Failed to set priorities"); } initializeCertificate(); Log_info("Sucessfully initialized GNUTLS version %s", gnutls_check_version(NULL)); }
void initializeCertificate() { char* certificatePath = (char*) getStrConf(CERTIFICATE); if(!certificatePath) { Log_fatal("No certificate file specified."); } char* keyPath = (char*) getStrConf(KEY); if(!keyPath) { Log_fatal("No key file specified"); } gnutls_certificate_allocate_credentials(&certificate); int error = gnutls_certificate_set_x509_key_file(certificate, certificatePath, keyPath, GNUTLS_X509_FMT_PEM); if( error != GNUTLS_E_SUCCESS ) { Log_fatal("Could not open key (%s) or certificate (%s).", keyPath, certificatePath); } }
static void openlogfile(const char *logfilename) { int fd, flags; logfile = fopen(logfilename, "a"); if (logfile == NULL) { Log_fatal("Failed to open log file '%s' for writing: %s\n", logfilename, strerror(errno)); } /* Set the stream as line buffered */ if (setvbuf(logfile, NULL, _IOLBF, 0) < 0) Log_fatal("setvbuf() failed: %s\n", strerror(errno)); /* XXX - Is it neccessary/appropriate that logging to file is non-blocking? * If not, there's a risk that execution blocks, meaning that voice blocks * as well since uMurmur is single threaded by design. OTOH, what could * cause a block? If the disk causes blocking, it is probably br0ken, but * the log could be on a nfs or smb share, so let's set it up as * non-blocking and we'll see what happens. */ fd = fileno(logfile); flags = fcntl(fd, F_GETFL, 0); fcntl(fd, F_SETFL, flags | O_NONBLOCK); }
/* Drops privileges (if configured to do so). */ static void switch_user(void) { struct passwd *pwd; struct group *grp = NULL; const char *username, *groupname; gid_t gid; username = getStrConf(USERNAME); groupname = getStrConf(GROUPNAME); if (!*username) { /* It's an error to specify groupname * but leave username empty. */ if (*groupname) Log_fatal("username missing"); /* Nothing to do. */ return; } pwd = getpwnam(username); if (!pwd) Log_fatal("Unknown user '%s'", username); if (!*groupname) gid = pwd->pw_gid; else { grp = getgrnam(groupname); if (!grp) Log_fatal("Unknown group '%s'", groupname); gid = grp->gr_gid; } if (initgroups(pwd->pw_name, gid)) Log_fatal("initgroups() failed: %s", strerror(errno)); if (setgid(gid)) Log_fatal("setgid() failed: %s", strerror(errno)); if (setuid(pwd->pw_uid)) Log_fatal("setuid() failed: %s", strerror(errno)); if (!grp) grp = getgrgid(gid); if (!grp) Log_fatal("getgrgid() failed: %s", strerror(errno)); Log_info("Switch to user '%s' group '%s'", pwd->pw_name, grp->gr_name); }
void Server_runLoop(struct pollfd* pollfds) { int timeout, rc, clientcount; etimer_t janitorTimer; Timer_init(&janitorTimer); while (!shutdown_server) { struct sockaddr_storage remote; int i; #ifdef USE_SHAREDMEMORY_API Sharedmemory_alivetick(); #endif for(i = 0; i < nofServerSocks; i++) { pollfds[i].revents = 0; } clientcount = Client_getfds(&pollfds[nofServerSocks]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { Client_janitor(); Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } rc = poll(pollfds, clientcount + nofServerSocks, timeout); if (rc == 0) { /* Poll timed out, do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; } if (rc < 0) { if (errno == EINTR) /* signal */ continue; else Log_fatal("poll: error %d (%s)", errno, strerror(errno)); } /* Check for new connection */ for (i = 0; i < nofServerSocks / 2; i++) { if (pollfds[i].revents) { int tcpfd; uint32_t addrlen = sizeof(struct sockaddr_storage); tcpfd = accept(pollfds[i].fd, (struct sockaddr *)&remote, &addrlen); fcntl(tcpfd, F_SETFL, O_NONBLOCK); setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(int)); char *addressString = Util_addressToString(&remote); Log_debug("Connection from %s port %d\n", addressString, Util_addressToPort(&remote)); free(addressString); if (Client_add(tcpfd, &remote) < 0) close(tcpfd); } } for (i = nofServerSocks / 2; i < nofServerSocks; i++) { if (pollfds[i].revents) Client_read_udp(udpsocks[i - nofServerSocks / 2]); } for (i = 0; i < clientcount; i++) { if (pollfds[nofServerSocks + i].revents & POLLIN) Client_read_fd(pollfds[nofServerSocks + i].fd); if (pollfds[nofServerSocks + i].revents & POLLOUT) Client_write_fd(pollfds[nofServerSocks + i].fd); } #ifdef USE_SHAREDMEMORY_API Sharedmemory_update(); #endif } }
void Server_run() { int timeout = 1000, rc; struct pollfd *pollfds; int tcpsock, sockopt = 1; struct sockaddr_storage sin; int val, clientcount; etimer_t janitorTimer; const char *port; const char *addr; struct addrinfo hints, *res; bool_t enable_ipv6; /* max clients + listen sock + udp sock + client connecting that will be disconnected */ pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd)); if (pollfds == NULL) Log_fatal("out of memory"); /* Figure out bind address and port */ if (bindport != 0) port = bindport; else port = getStrConf(BINDPORT); if (bindaddr != 0) addr = bindaddr; else addr = getStrConf(BINDADDR); /* Prepare TCP socket */ enable_ipv6 = getBoolConf(ENABLE_IPV6); if (enable_ipv6) { /* Test if supported */ int testsock = socket(AF_INET6, SOCK_STREAM, 0); if (testsock < 0 && errno == EAFNOSUPPORT) { Log_warn("IPv6 is not supported on this machine. Falling back to IPv4."); enable_ipv6 = false; } if (testsock > 0) close(testsock); } memset(&hints, 0, sizeof hints); if (enable_ipv6) { hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE | AI_V4MAPPED; hints.ai_protocol = 0; } else { /* IPv4 */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; } rc = getaddrinfo(addr, port, &hints, &res); if (rc != 0) Log_fatal("getaddrinfo: %s", gai_strerror(rc)); Log_info("Bind to [%s]:%s", addr ? addr : "::" , port); tcpsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (tcpsock < 0) Log_fatal("socket: %s", strerror(errno)); if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) Log_fatal("setsockopt: %s",strerror(errno)); rc = bind(tcpsock, res->ai_addr, res->ai_addrlen); if (rc < 0) Log_fatal("bind: %s", strerror(errno)); rc = listen(tcpsock, 3); if (rc < 0) Log_fatal("listen"); fcntl(tcpsock, F_SETFL, O_NONBLOCK); pollfds[LISTEN_SOCK].fd = tcpsock; pollfds[LISTEN_SOCK].events = POLLIN; freeaddrinfo(res); /* Prepare UDP socket */ memset(&hints, 0, sizeof hints); if (enable_ipv6) { hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE | AI_V4MAPPED; hints.ai_protocol = 0; } else { /* IPv4 */ hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; } rc = getaddrinfo(addr, port, &hints, &res); if (rc != 0) Log_fatal("getaddrinfo: %s", gai_strerror(rc)); udpsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); rc = bind(udpsock, res->ai_addr, res->ai_addrlen); if (rc < 0) Log_fatal("bind %d %s: %s", bindport, bindaddr, strerror(errno)); val = 0xe0; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(udpsock, F_SETFL, O_NONBLOCK); listen(udpsock, 10); pollfds[UDP_SOCK].fd = udpsock; pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; freeaddrinfo(res); Timer_init(&janitorTimer); Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d", UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); Log_info("Visit http://code.google.com/p/umurmur/"); /* Main server loop */ while (!shutdown_server) { struct sockaddr_storage remote; int i; pollfds[UDP_SOCK].revents = 0; pollfds[TCP_SOCK].revents = 0; clientcount = Client_getfds(&pollfds[2]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { Client_janitor(); Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } rc = poll(pollfds, clientcount + 2, timeout); if (rc == 0) { /* Timeout */ /* Do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; } if (rc < 0) { if (errno == EINTR) /* signal */ continue; else Log_fatal("poll: error %d", errno); } if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */ int tcpfd, flag = 1; uint32_t addrlen; addrlen = sizeof(struct sockaddr_storage); tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen); fcntl(tcpfd, F_SETFL, O_NONBLOCK); setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); if (Client_add(tcpfd, &remote) < 0) close(tcpfd); } if (pollfds[UDP_SOCK].revents) { Client_read_udp(); } for (i = 0; i < clientcount; i++) { if (pollfds[i + 2].revents & POLLIN) { Client_read_fd(pollfds[i + 2].fd); } if (pollfds[i + 2].revents & POLLOUT) { Client_write_fd(pollfds[i + 2].fd); } } } /* Disconnect clients */ Client_disconnect_all(); free(pollfds); }
int main (int argc, char**argv) { int ret = 0; int heartbeat_usec = 50000; //20Hz is ok by default uint64_t last_beat = 0; Log_info ("cloudvpn starting"); Log (0, "You are using CloudVPN, which is Free software."); Log (0, "For more information please see the GNU GPL license,"); Log (0, "which you should have received along with this program."); setup_sighandler (kill_cloudvpn); /* * initialization */ if (!config_parse (argc, argv) ) { Log_error ("failed to parse config, terminating."); ret = 1; goto failed_config; } if (!config_get_int ("heartbeat", heartbeat_usec) ) heartbeat_usec = 50000; Log_info ("heartbeat is set to %d usec", heartbeat_usec); timestamp_update(); //get initial timestamp status_init(); route_init(); squeue_init(); network_init(); if (poll_init() ) { Log_fatal ("poll initialization failed"); ret = 2; goto failed_poll; } if (do_memlock() ) { Log_fatal ("locking process to memory failed"); ret = 3; goto failed_poll; } if (comm_load() ) { Log_fatal ("failed to load comm data"); ret = 4; goto failed_poll; } if (comm_init() ) { Log_fatal ("communication initialization failed"); ret = 5; goto failed_comm; } if (gate_init() ) { Log_fatal ("gate initialization failed"); ret = 6; goto failed_gate; } if (do_chroot() ) { Log_fatal ("chrooting failed"); ret = 7; goto failed_sec; } if (do_switch_user() ) { Log_fatal ("user switch failed"); ret = 8; goto failed_sec; } /* * main loop */ Log_info ("initialization complete, entering main loop"); last_beat = 0; //update immediately. while (!g_terminate) { timestamp_update(); if ( (timestamp() - last_beat) < (unsigned int) heartbeat_usec) { //poll more stuff poll_wait_for_event (heartbeat_usec - timestamp() + last_beat); //send the results comm_flush_data(); gate_flush_data(); continue; } last_beat = timestamp(); gate_periodic_update(); comm_periodic_update(); route_periodic_update(); status_try_export(); } /* * deinitialization */ Log_info ("shutting down"); failed_sec: gate_shutdown(); failed_gate: comm_shutdown(); failed_comm: if (poll_deinit() ) Log_warn ("poll_deinit somehow failed!"); failed_poll: failed_config: if (!ret) Log_info ("cloudvpn exiting gracefully"); else Log_error ("cloudvpn exiting with code %d", ret); return ret; }
void Server_run() { int timeout = 1000, rc; struct pollfd *pollfds; int tcpsock, sockopt = 1; struct sockaddr_in sin; int val, clientcount; etimer_t janitorTimer; unsigned short port; in_addr_t inet_address; /* max clients + listen sock + udp sock + client connecting that will be disconnected */ pollfds = malloc((getIntConf(MAX_CLIENTS) + 3) * sizeof(struct pollfd)); if (pollfds == NULL) Log_fatal("out of memory"); /* Figure out bind address and port */ if (bindport != 0) port = htons(bindport); else port = htons(getIntConf(BINDPORT)); if (bindaddr != NULL && inet_addr(bindaddr) != -1) inet_address = inet_addr(bindaddr); else if (inet_addr(getStrConf(BINDADDR)) != -1) inet_address = inet_addr(getStrConf(BINDADDR)); else inet_address = inet_addr("0.0.0.0"); Log_info("Bind to %s:%hu", inet_address == 0 ? "*" : inet_ntoa(*((struct in_addr *)&inet_address)), ntohs(port)); /* Prepare TCP socket */ memset(&sin, 0, sizeof(sin)); tcpsock = socket(PF_INET, SOCK_STREAM, 0); if (tcpsock < 0) Log_fatal("socket"); if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, &sockopt, sizeof(int)) != 0) Log_fatal("setsockopt: %s", strerror(errno)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = inet_address; rc = bind(tcpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); if (rc < 0) Log_fatal("bind: %s", strerror(errno)); rc = listen(tcpsock, 3); if (rc < 0) Log_fatal("listen"); fcntl(tcpsock, F_SETFL, O_NONBLOCK); pollfds[LISTEN_SOCK].fd = tcpsock; pollfds[LISTEN_SOCK].events = POLLIN; /* Prepare UDP socket */ memset(&sin, 0, sizeof(sin)); udpsock = socket(PF_INET, SOCK_DGRAM, 0); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = inet_address; rc = bind(udpsock, (struct sockaddr *) &sin, sizeof (struct sockaddr_in)); if (rc < 0) Log_fatal("bind %d %s: %s", getIntConf(BINDPORT), getStrConf(BINDADDR), strerror(errno)); val = 0xe0; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); val = 0x80; rc = setsockopt(udpsock, IPPROTO_IP, IP_TOS, &val, sizeof(val)); if (rc < 0) Log_warn("Server: Failed to set TOS for UDP Socket"); fcntl(udpsock, F_SETFL, O_NONBLOCK); pollfds[UDP_SOCK].fd = udpsock; pollfds[UDP_SOCK].events = POLLIN | POLLHUP | POLLERR; Timer_init(&janitorTimer); Log_info("uMurmur version %s ('%s') protocol version %d.%d.%d", UMURMUR_VERSION, UMURMUR_CODENAME, PROTVER_MAJOR, PROTVER_MINOR, PROTVER_PATCH); Log_info("Visit http://code.google.com/p/umurmur/"); /* Main server loop */ while (!shutdown_server) { struct sockaddr_in remote; int i; pollfds[UDP_SOCK].revents = 0; pollfds[TCP_SOCK].revents = 0; clientcount = Client_getfds(&pollfds[2]); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; if (timeout <= 0) { Client_janitor(); Timer_restart(&janitorTimer); timeout = (int)(1000000LL - (int64_t)Timer_elapsed(&janitorTimer)) / 1000LL; } rc = poll(pollfds, clientcount + 2, timeout); if (rc == 0) { /* Timeout */ /* Do maintenance */ Timer_restart(&janitorTimer); Client_janitor(); continue; } if (rc < 0) { if (errno == EINTR) /* signal */ continue; else Log_fatal("poll: error %d", errno); } if (pollfds[LISTEN_SOCK].revents) { /* New tcp connection */ int tcpfd, flag = 1; uint32_t addrlen; addrlen = sizeof(struct sockaddr_in); tcpfd = accept(pollfds[LISTEN_SOCK].fd, (struct sockaddr*)&remote, &addrlen); fcntl(tcpfd, F_SETFL, O_NONBLOCK); setsockopt(tcpfd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); Log_debug("Connection from %s port %d\n", inet_ntoa(remote.sin_addr), ntohs(remote.sin_port)); if (Client_add(tcpfd, &remote) < 0) close(tcpfd); } if (pollfds[UDP_SOCK].revents) { Client_read_udp(); } for (i = 0; i < clientcount; i++) { if (pollfds[i + 2].revents & POLLIN) { Client_read_fd(pollfds[i + 2].fd); } if (pollfds[i + 2].revents & POLLOUT) { Client_write_fd(pollfds[i + 2].fd); } } } /* Disconnect clients */ Client_disconnect_all(); free(pollfds); }