connected client needs to provide a username which will be communicated to rejected clients
This commit is contained in:
parent
55367f5fee
commit
75b30f3aa6
5 changed files with 63 additions and 17 deletions
43
client.c
43
client.c
|
@ -82,3 +82,46 @@ int client_write(struct client_t *client, char *databuf, int datalen) {
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Waits for client to provide a username. Blocks until a username is entered. */
|
||||||
|
int client_ask_username(struct client_t *client) {
|
||||||
|
|
||||||
|
int i;
|
||||||
|
char databuf[DATABUF_LEN];
|
||||||
|
fd_set read_fds;
|
||||||
|
|
||||||
|
/* send username request to client */
|
||||||
|
snprintf(databuf, DATABUF_LEN,
|
||||||
|
"\nPlease provide a username to identify yourself to other users (max %d characters):\n", USERNAME_LEN);
|
||||||
|
client_write(client, databuf, strlen(databuf));
|
||||||
|
|
||||||
|
/* wait for client input */
|
||||||
|
client->username[0] = '\0';
|
||||||
|
while (client->username[0] == '\0') {
|
||||||
|
/* send prompt character to client */
|
||||||
|
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++) {
|
||||||
|
if (client->data[i] == '\r') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
client->username[i] = client->data[i];
|
||||||
|
}
|
||||||
|
client->username[i+1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send welcome message to client */
|
||||||
|
snprintf(databuf, DATABUF_LEN,
|
||||||
|
"\nWelcome %s!\n\n", client->username);
|
||||||
|
client_write(client, databuf, strlen(databuf));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
- support multiple client connections at the same time
|
|
||||||
- first client has control
|
|
||||||
- additional clients can see the traffic
|
|
||||||
- read-only: requests from controlling client and responses from tty device
|
|
||||||
- need to avoid unintentional lock up if controlling client stays connected but user goes away and forgets about it
|
|
||||||
- additional clients should be able to force disconnecting controlling client
|
|
||||||
- first additional client that forces this becomes controlling client
|
|
||||||
|
|
||||||
- require username when connecting to the server
|
|
||||||
- allows tracking users
|
|
||||||
- makes the feature above (forcing disconnect) easier to use
|
|
||||||
- username can be connected to a person easier than an IP address
|
|
|
@ -210,12 +210,14 @@ int main(int argc, char *argv[]) {
|
||||||
fprintf(stderr, "[%s] problem accepting client\n", NAME);
|
fprintf(stderr, "[%s] problem accepting client\n", NAME);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
/* ask client to provide a username before going to "character" mode */
|
||||||
|
client_ask_username(&client);
|
||||||
/* 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 */
|
/* reject connection request if a client is already connected */
|
||||||
else {
|
else {
|
||||||
server_reject(&server);
|
server_reject(&server, &client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* check client status if connected */
|
/* check client status if connected */
|
||||||
|
|
13
moxerver.h
13
moxerver.h
|
@ -17,6 +17,7 @@
|
||||||
#define TIMESTAMP_FORMAT "%d.%m.%Y. %H:%M:%S"
|
#define TIMESTAMP_FORMAT "%d.%m.%Y. %H:%M:%S"
|
||||||
#define TIMESTAMP_LEN 20+1 /* calculated following timestamp format */
|
#define TIMESTAMP_LEN 20+1 /* calculated following timestamp format */
|
||||||
#define CONFILE "moxanix.cfg"
|
#define CONFILE "moxanix.cfg"
|
||||||
|
#define USERNAME_LEN 32
|
||||||
|
|
||||||
/* Structures used for communication parameters. */
|
/* Structures used for communication parameters. */
|
||||||
struct server_t {
|
struct server_t {
|
||||||
|
@ -30,6 +31,7 @@ struct client_t {
|
||||||
struct sockaddr_in address; /* client address information */
|
struct sockaddr_in address; /* client address information */
|
||||||
char ip_string[INET_ADDRSTRLEN]; /* client IP address as a string */
|
char ip_string[INET_ADDRSTRLEN]; /* client IP address as a string */
|
||||||
time_t last_active; /* time of client's last activity in seconds from Epoch */
|
time_t last_active; /* time of client's last activity in seconds from Epoch */
|
||||||
|
char username[USERNAME_LEN]; /* username for human identification */
|
||||||
char data[DATABUF_LEN]; /* buffer for data received from client */
|
char data[DATABUF_LEN]; /* buffer for data received from client */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,7 +96,7 @@ int server_accept(struct server_t *server, struct client_t *accepted_client);
|
||||||
* Returns:
|
* Returns:
|
||||||
* 0 always, errors with rejected client are ignored
|
* 0 always, errors with rejected client are ignored
|
||||||
*/
|
*/
|
||||||
int server_reject(struct server_t *server);
|
int server_reject(struct server_t *server, struct client_t *client);
|
||||||
|
|
||||||
|
|
||||||
/* Functions handling communication with clients. */
|
/* Functions handling communication with clients. */
|
||||||
|
@ -127,6 +129,15 @@ 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 to provide a username.
|
||||||
|
* Blocks until a username is entered.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 always
|
||||||
|
*/
|
||||||
|
int client_ask_username(struct client_t *client);
|
||||||
|
|
||||||
|
|
||||||
/* Functions handling details related to telnet protocol. */
|
/* Functions handling details related to telnet protocol. */
|
||||||
|
|
||||||
|
|
8
server.c
8
server.c
|
@ -104,7 +104,7 @@ int server_accept(struct server_t *server, struct client_t *accepted_client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rejects incoming client connection. Errors with rejected client are ignored. */
|
/* Rejects incoming client connection. Errors with rejected client are ignored. */
|
||||||
int server_reject(struct server_t *server) {
|
int server_reject(struct server_t *server, struct client_t *client) {
|
||||||
|
|
||||||
int namelen;
|
int namelen;
|
||||||
struct client_t rclient;
|
struct client_t rclient;
|
||||||
|
@ -114,8 +114,10 @@ int server_reject(struct server_t *server) {
|
||||||
/* accept connection request */
|
/* accept connection request */
|
||||||
namelen = sizeof(rclient.address);
|
namelen = sizeof(rclient.address);
|
||||||
rclient.socket = accept(server->socket, (struct sockaddr *) &rclient.address, (socklen_t *) &namelen);
|
rclient.socket = accept(server->socket, (struct sockaddr *) &rclient.address, (socklen_t *) &namelen);
|
||||||
/* send reject message */
|
/* send reject message to client */
|
||||||
sprintf(reject_msg, "[%s] port %u is already being used\n", __func__, server->port);
|
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);
|
send(rclient.socket, reject_msg, strlen(reject_msg), 0);
|
||||||
/* close connection */
|
/* close connection */
|
||||||
close(rclient.socket);
|
close(rclient.socket);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue