void listen_channels(void){ struct atc_conn *childConn; int result; while (1) { if (cur_clients + 1 < MAX_CLIENTS){ childConn = &(nodes[cur_clients + 1].conn); result = atc_accept(&serverConn, childConn); if (result == -1) { puts("Could not accept connection."); return; } fork_client(childConn); } } return; }
static void handle_new_connection(int newfd, int epfd) { struct epoll_event ev; struct client_data *client; struct sockaddr_storage addr; socklen_t addrlen = sizeof (addr); char authbuf[AUTHBUFSIZE]; int pos, is_reg, reconnect_id, authlen, userid; static int connection_id = 1; if (fd_to_client_max > newfd && fd_to_client[newfd] == &new_connection_dummy) { epoll_ctl(epfd, EPOLL_CTL_DEL, newfd, &ev); fd_to_client[newfd] = NULL; } /* it should be possible to read immediately due to the "defer" sockopt */ authlen = read(newfd, authbuf, AUTHBUFSIZE - 1); if (authlen <= 0) { close(newfd); return; } getpeername(newfd, (struct sockaddr *)&addr, &addrlen); log_msg("New connection from %s.", addr2str(&addr)); authbuf[authlen] = '\0'; /* make it safe to use as a string */ /* did we receive too much data? */ if (authlen >= AUTH_MAXLEN) { log_msg("Auth buffer overrun attempt from %s? Peer disconnected.", addr2str(&addr)); close(newfd); return; } /* check the end of the received auth data: a JSON object always ends with '}' */ pos = authlen - 1; while (pos > 0 && isspace(authbuf[pos])) pos--; if (authbuf[pos] != '}') { /* not the end of JSON auth data */ log_msg("authentication for %s failed due to incomplete JSON", addr2str(&addr)); return; } /* * ready to authenticate the user here */ userid = auth_user(authbuf, addr2str(&addr), &is_reg, &reconnect_id); if (userid <= 0) { if (!userid) auth_send_result(newfd, AUTH_FAILED_UNKNOWN_USER, is_reg, 0); else auth_send_result(newfd, AUTH_FAILED_BAD_PASSWORD, is_reg, 0); log_msg("authentication failed for %s", addr2str(&addr)); close(newfd); return; } /* user ok, we'll keep this socket */ ev.events = EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET; ev.data.ptr = NULL; ev.data.fd = newfd; if (epoll_ctl(epfd, EPOLL_CTL_ADD, newfd, &ev) == -1) { log_msg("Error in epoll_ctl for %s: %s", addr2str(&addr), strerror(errno)); close(newfd); return; } /* is the client re-establishing a connection to an existing, disconnected game? */ for (client = disconnected_list_head.next; client; client = client->next) if (client->userid == userid && (!reconnect_id || reconnect_id == client->connid)) break; if (reconnect_id && !client) { /* now search through the active connections. The client might have a new IP address, which would leave the socket open and seemingly valid. */ for (client = connected_list_head.next; client; client = client->next) if (client->userid == userid && reconnect_id == client->connid) break; } if (client) { /* there is a running, disconnected game process for this user */ auth_send_result(newfd, AUTH_SUCCESS_RECONNECT, is_reg, client->connid); client->sock = newfd; map_fd_to_client(client->sock, client); client->state = CLIENT_CONNECTED; unlink_client_data(client); link_client_data(client, &connected_list_head); write(client->pipe_out, "\033", 1); /* signal to reset the read buffer */ log_msg("Connection to game at pid %d reestablished for user %d", client->pid, client->userid); return; } else { client = alloc_client_data(&connected_list_head); client->state = CLIENT_CONNECTED; client->sock = newfd; map_fd_to_client(newfd, client); client->connid = connection_id++; client->userid = userid; /* there is no process yet */ if (fork_client(client, epfd)) auth_send_result(newfd, AUTH_SUCCESS_NEW, is_reg, client->connid); /* else: client communication is shutdown if fork_client errors out */ } log_msg("There are now %d clients on the server", client_count); }