added support for dropp current client - needs a separate thread to remove blocking
This commit is contained in:
parent
9114998d1f
commit
86f0bc612f
4 changed files with 124 additions and 49 deletions
65
client.c
65
client.c
|
@ -83,45 +83,66 @@ int client_write(struct client_t *client, char *databuf, int datalen) {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Waits for client input in "line mode". Blocks until input arrives. */
|
||||||
|
int client_wait_line(struct client_t *client) {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
fd_set read_fds;
|
||||||
|
|
||||||
|
client->data[0] = '\0';
|
||||||
|
/* loop waiting for client input */
|
||||||
|
while (client->data[0] == '\0') {
|
||||||
|
/* setup select() parameters */
|
||||||
|
FD_ZERO(&read_fds);
|
||||||
|
FD_SET(client->socket, &read_fds);
|
||||||
|
/* send prompt character to client */
|
||||||
|
client_write(client, "> ", 2);
|
||||||
|
/* block until input arrives */
|
||||||
|
if (select((client->socket)+1, &read_fds, NULL, NULL, NULL) == -1) return -1;
|
||||||
|
if (FD_ISSET(client->socket, &read_fds)) {
|
||||||
|
/* read client input */
|
||||||
|
ret = client_read(client);
|
||||||
|
if (ret == -1) return -1;
|
||||||
|
/* we don't want empty data so stop on \r or \n */
|
||||||
|
if ( (client->data[0] == '\r') || (client->data[0] == '\n') ) {
|
||||||
|
fprintf(stderr, "client data is empty\n");
|
||||||
|
client->data[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "client data: %s\n", client->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Waits for client to provide a username. Blocks until a username is entered. */
|
/* Waits for client to provide a username. Blocks until a username is entered. */
|
||||||
int client_ask_username(struct client_t *client) {
|
int client_ask_username(struct client_t *client) {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
char databuf[DATABUF_LEN];
|
char msg[DATABUF_LEN];
|
||||||
fd_set read_fds;
|
|
||||||
|
|
||||||
/* send username request to client */
|
/* send username request to client */
|
||||||
snprintf(databuf, DATABUF_LEN,
|
snprintf(msg, DATABUF_LEN,
|
||||||
"\nPlease provide a username to identify yourself to other users (max %d characters):\n", USERNAME_LEN);
|
"\nPlease provide a username to identify yourself to other users (max %d characters):\n", USERNAME_LEN);
|
||||||
client_write(client, databuf, strlen(databuf));
|
client_write(client, msg, strlen(msg));
|
||||||
|
|
||||||
/* wait for client input */
|
/* wait for client input */
|
||||||
client->username[0] = '\0';
|
if (client_wait_line(client) != 0) return -1;
|
||||||
while (client->username[0] == '\0') {
|
|
||||||
/* send prompt character to client */
|
/* save received data as client username */
|
||||||
snprintf(databuf, DATABUF_LEN, "> ");
|
|
||||||
client_write(client, databuf, strlen(databuf));
|
|
||||||
/* setup select() parameters */
|
|
||||||
FD_ZERO(&read_fds);
|
|
||||||
FD_SET(client->socket, &read_fds);
|
|
||||||
select((client->socket)+1, &read_fds, NULL, NULL, NULL);
|
|
||||||
if (FD_ISSET(client->socket, &read_fds)) {
|
|
||||||
client_read(client);
|
|
||||||
/* handle client input */
|
|
||||||
for (i = 0; i < USERNAME_LEN; i++) {
|
for (i = 0; i < USERNAME_LEN; i++) {
|
||||||
if (client->data[i] == '\r') {
|
if ( (client->data[i] == '\r') || (client->data[i] == '\n') ) {
|
||||||
|
/* don't include \r or \n in username */
|
||||||
|
client->username[i] = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
client->username[i] = client->data[i];
|
client->username[i] = client->data[i];
|
||||||
}
|
}
|
||||||
client->username[i+1] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* send welcome message to client */
|
/* send welcome message to client */
|
||||||
snprintf(databuf, DATABUF_LEN,
|
snprintf(msg, DATABUF_LEN,
|
||||||
"\nWelcome %s!\n\n", client->username);
|
"\nWelcome %s!\n\n", client->username);
|
||||||
client_write(client, databuf, strlen(databuf));
|
client_write(client, msg, strlen(msg));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
17
moxerver.c
17
moxerver.c
|
@ -215,9 +215,22 @@ int main(int argc, char *argv[]) {
|
||||||
/* put client in "character" mode */
|
/* put client in "character" mode */
|
||||||
telnet_set_character_mode(&client);
|
telnet_set_character_mode(&client);
|
||||||
}
|
}
|
||||||
/* reject connection request if a client is already connected */
|
/* if a client is already connected then new clients need to be handled */
|
||||||
else {
|
else {
|
||||||
server_reject(&server, &client);
|
/* decide if current client needs to be dropped or new client needs to be rejected */
|
||||||
|
ret = server_drop(&server, &client);
|
||||||
|
if (ret < 0) {
|
||||||
|
/* error in handling new clients, print but continue waiting for new clients */
|
||||||
|
fprintf(stderr, "[%s] problem handling new client request\n", NAME);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* if current client was dropped we need to set up new client */
|
||||||
|
if (ret > 0) {
|
||||||
|
/* ask client to provide a username before going to "character" mode */
|
||||||
|
client_ask_username(&client);
|
||||||
|
/* put client in "character" mode */
|
||||||
|
telnet_set_character_mode(&client);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* check client status if connected */
|
/* check client status if connected */
|
||||||
|
|
22
moxerver.h
22
moxerver.h
|
@ -91,12 +91,15 @@ int server_close(struct server_t *server);
|
||||||
int server_accept(struct server_t *server, struct client_t *accepted_client);
|
int server_accept(struct server_t *server, struct client_t *accepted_client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rejects incoming client connection.
|
* Asks new incoming client connection if current client needs to be dropped.
|
||||||
|
* If current client doesn't need to be dropped then new client is rejected.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 always, errors with rejected client are ignored
|
* - positive value if current client was dropped
|
||||||
|
* - 0 if new client was rejected
|
||||||
|
* - negative value if error occurred
|
||||||
*/
|
*/
|
||||||
int server_reject(struct server_t *server, struct client_t *client);
|
int server_drop(struct server_t *server, struct client_t *client);
|
||||||
|
|
||||||
|
|
||||||
/* Functions handling communication with clients. */
|
/* Functions handling communication with clients. */
|
||||||
|
@ -129,12 +132,23 @@ int client_read(struct client_t *client);
|
||||||
*/
|
*/
|
||||||
int client_write(struct client_t *client, char *databuf, int datalen);
|
int client_write(struct client_t *client, char *databuf, int datalen);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for client input in "line mode", where client sends a whole line of characters.
|
||||||
|
* Blocks until input arrives.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* - 0 on success
|
||||||
|
* - negative value if error occurred
|
||||||
|
*/
|
||||||
|
int client_wait_line(struct client_t *client);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for client to provide a username.
|
* Waits for client to provide a username.
|
||||||
* Blocks until a username is entered.
|
* Blocks until a username is entered.
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 always
|
* - 0 on success
|
||||||
|
* - negative value if error occurred
|
||||||
*/
|
*/
|
||||||
int client_ask_username(struct client_t *client);
|
int client_ask_username(struct client_t *client);
|
||||||
|
|
||||||
|
|
59
server.c
59
server.c
|
@ -103,26 +103,53 @@ int server_accept(struct server_t *server, struct client_t *accepted_client) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rejects incoming client connection. Errors with rejected client are ignored. */
|
/* Drops current client or rejects new client. */
|
||||||
int server_reject(struct server_t *server, struct client_t *client) {
|
int server_drop(struct server_t *server, struct client_t *current_client) {
|
||||||
|
|
||||||
int namelen;
|
struct client_t new_client;
|
||||||
struct client_t rclient;
|
char msg[DATABUF_LEN];
|
||||||
char reject_msg[128];
|
|
||||||
char timestamp[TIMESTAMP_LEN];
|
char timestamp[TIMESTAMP_LEN];
|
||||||
|
|
||||||
/* accept connection request */
|
/* accept new connection request */
|
||||||
namelen = sizeof(rclient.address);
|
if (server_accept(server, &new_client) != 0) return -1;
|
||||||
rclient.socket = accept(server->socket, (struct sockaddr *) &rclient.address, (socklen_t *) &namelen);
|
|
||||||
/* send reject message to client */
|
|
||||||
time2string(client->last_active, timestamp);
|
|
||||||
sprintf(reject_msg, "\nPort %u is already being used:\ncurrent user: %s\nlast activity: @ %s\n\n",
|
|
||||||
server->port, client->username, timestamp);
|
|
||||||
send(rclient.socket, reject_msg, strlen(reject_msg), 0);
|
|
||||||
/* close connection */
|
|
||||||
close(rclient.socket);
|
|
||||||
|
|
||||||
|
/* inform new client that port is already in use */
|
||||||
|
time2string(current_client->last_active, timestamp);
|
||||||
|
sprintf(msg, "\nPort %u is already being used!\nCurrent user and last activity:\n%s @ %s\n",
|
||||||
|
server->port, current_client->username, timestamp);
|
||||||
|
send(new_client.socket, msg, strlen(msg), 0);
|
||||||
|
|
||||||
|
/* ask new client if current client should be dropped */
|
||||||
|
sprintf(msg, "\nDo you want to drop the current user?\nIf yes then please type YES DROP (in uppercase):");
|
||||||
|
send(new_client.socket, msg, strlen(msg), 0);
|
||||||
|
|
||||||
|
/* wait for client input */
|
||||||
|
if (client_wait_line(&new_client) != 0) return -1;
|
||||||
|
|
||||||
|
/* check client confirmation */
|
||||||
|
if (strncmp(new_client.data, "YES DROP", 8) == 0) {
|
||||||
|
/* current client should be dropped, drop it */
|
||||||
|
client_close(current_client);
|
||||||
time2string(time(NULL), timestamp);
|
time2string(time(NULL), timestamp);
|
||||||
fprintf(stderr, "[%s] rejected new client request @ %s\n", __func__, timestamp);
|
fprintf(stderr, "[%s] dropped current client %s on port %u @ %s\n", __func__,
|
||||||
|
current_client->ip_string, server->port, timestamp);
|
||||||
|
/* make new client the current client */
|
||||||
|
memcpy(current_client, &new_client, sizeof(struct client_t));
|
||||||
|
time2string(time(NULL), timestamp);
|
||||||
|
fprintf(stderr, "[%s] accepted new client request %s on port %u @ %s\n", __func__,
|
||||||
|
current_client->ip_string, server->port, timestamp);
|
||||||
|
/* return 1 because current client was dropped */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* new connection should be rejected, close connection */
|
||||||
|
close(new_client.socket);
|
||||||
|
time2string(time(NULL), timestamp);
|
||||||
|
fprintf(stderr, "[%s] rejected new client request %s on port %u @ %s\n", __func__,
|
||||||
|
new_client.ip_string, server->port, timestamp);
|
||||||
|
/* return 0 because new client was rejected */
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue