void Server_run() { struct pollfd *pollfds; checkIPversions(); /* max clients + server sokets + client connecting that will be disconnected */ pollfds = Memory_safeCalloc((getIntConf(MAX_CLIENTS) + nofServerSocks + 1) , sizeof(struct pollfd)); /* Figure out bind address and port */ struct sockaddr_storage** addresses = Server_setupAddressesAndPorts(); /* Prepare TCP sockets */ Server_setupTCPSockets(addresses, pollfds); /* Prepare UDP sockets */ Server_setupUDPSockets(addresses, pollfds); 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 */ Server_runLoop(pollfds); /* Disconnect clients and cleanup memory */ Client_disconnect_all(); free(pollfds); free(addresses[0]); free(addresses[1]); free(addresses); free(udpsocks); }
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; }
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); }
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); }