Extract client functions into a separate header

This commit is contained in:
Igor Socec 2016-11-18 23:06:20 +01:00
parent c59b2138f4
commit 2c26ef201a
3 changed files with 118 additions and 98 deletions

120
client.c
View file

@ -1,43 +1,47 @@
/* #include <client.h>
* Handling communication with clients.
*/
#include "moxerver.h" void client_close(client_t *client)
{
/* Closes client connection. */
int client_close(client_t *client) {
char timestamp[TIMESTAMP_LEN]; char timestamp[TIMESTAMP_LEN];
/* force closing in case of error */ /* force closing in case of error */
if (close(client->socket) == -1) { if (close(client->socket) == -1)
{
close(client->socket); close(client->socket);
} }
client->socket = -1; client->socket = -1;
time2string(time(NULL), timestamp); time2string(time(NULL), timestamp);
fprintf(stderr,"[%s] socket closed for client %s @ %s\n", __func__, client->ip_string, timestamp); fprintf(stderr,"[%s] socket closed for client %s @ %s\n", __func__,
return 0; client->ip_string, timestamp);
} }
/* Reads data from client into client data buffer. Returns number of read bytes. */ int client_read(client_t *client)
int client_read(client_t *client) { {
int len; int len;
/* read client data */ /* read data from the client */
len = recv(client->socket, client->data, sizeof(client->data)-1, 0); len = recv(client->socket, client->data, sizeof(client->data)-1, 0);
if (len == -1) { if (len == -1)
fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); {
fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__,
errno, strerror(errno));
return -errno; return -errno;
} }
/* a disconnected client socket is ready for reading but read returns 0 */ /* a disconnected client socket is ready for reading but read returns 0 */
if (len == 0) { if (len == 0)
fprintf(stderr, "[%s:%d] no data available from client\n", __func__, __LINE__); {
fprintf(stderr, "[%s:%d] no data available from client\n",
__func__, __LINE__);
return -ENODATA; return -ENODATA;
} }
//TODO let's print received bytes during development phase... //TODO let's print received bytes during development phase...
if (debug_messages) { if (debug_messages)
{
int i; int i;
for(i = 0; i < len; i++) { for(i = 0; i < len; i++)
{
fprintf(stderr, "client %s <- %u '%c'\n", fprintf(stderr, "client %s <- %u '%c'\n",
client->ip_string, client->ip_string,
(unsigned char) client->data[i], (unsigned char) client->data[i],
@ -45,27 +49,28 @@ int client_read(client_t *client) {
} }
} }
/* handle special telnet characters coming from client */ /* handle special telnet characters coming from the client */
telnet_handle_client_read(client->data, &len); telnet_handle_client_read(client->data, &len);
/* grab current time and store it as client last activity */ /* grab current time and store it as client's last activity */
client->last_active = time(NULL); client->last_active = time(NULL);
return len; return len;
} }
/* Sends data from a buffer to client. Returns number of sent bytes. */ int client_write(client_t *client, char *databuf, int datalen)
int client_write(client_t *client, char *databuf, int datalen) { {
int len; int len;
/* handle special telnet characters to display them correctly on client */ /* handle special telnet characters to display them correctly on client */
//telnet_handle_client_write(databuf, &datalen); //telnet_handle_client_write(databuf, &datalen);
//TODO let's print received bytes during development phase... //TODO let's print received bytes during development phase...
if (debug_messages) { if (debug_messages)
{
int i; int i;
for(i = 0; i < datalen; i++) { for(i = 0; i < datalen; i++)
{
fprintf(stderr, "client %s -> %u '%c'\n", fprintf(stderr, "client %s -> %u '%c'\n",
client->ip_string, client->ip_string,
(unsigned char) databuf[i], (unsigned char) databuf[i],
@ -73,72 +78,87 @@ int client_write(client_t *client, char *databuf, int datalen) {
} }
} }
/* send data to client */ /* send data to the client */
len = send(client->socket, databuf, datalen, 0); len = send(client->socket, databuf, datalen, 0);
if (len == -1) { if (len == -1)
fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__, errno, strerror(errno)); {
fprintf(stderr, "[%s:%d] error %d: %s\n", __func__, __LINE__,
errno, strerror(errno));
return -errno; return -errno;
} }
return len; return len;
} }
/* Waits for client input in "line mode". Blocks until input arrives. */ int client_wait_line(client_t *client)
int client_wait_line(client_t *client) { {
fd_set read_fds; fd_set read_fds;
struct timeval tv; struct timeval tv;
client->data[0] = '\0'; client->data[0] = '\0';
/* loop waiting for client input */ /* loop waiting for client input */
while (client->data[0] == '\0') { while (client->data[0] == '\0')
{
/* setup select() parameters */ /* setup select() parameters */
tv.tv_sec = 15; /* 15 second timeout */ tv.tv_sec = 15; /* 15 second timeout */
tv.tv_usec = 0; tv.tv_usec = 0;
FD_ZERO(&read_fds); FD_ZERO(&read_fds);
FD_SET(client->socket, &read_fds); FD_SET(client->socket, &read_fds);
/* send prompt character to client */ /* send prompt character to the client */
client_write(client, "> ", 2); client_write(client, "> ", 2);
/* block until input arrives */ /* block until input arrives */
if (select((client->socket)+1, &read_fds, NULL, NULL, &tv) <= 0) return -1; if (select((client->socket)+1, &read_fds, NULL, NULL, &tv) <= 0)
if (FD_ISSET(client->socket, &read_fds)) { {
return -1;
}
if (FD_ISSET(client->socket, &read_fds))
{
/* read client input */ /* read client input */
if (client_read(client) == -1) return -1; if (client_read(client) == -1)
{
return -1;
}
/* we don't want empty data so stop on \r or \n */ /* we don't want empty data so stop on \r or \n */
if ( (client->data[0] == '\r') || (client->data[0] == '\n') ) { if ( (client->data[0] == '\r') || (client->data[0] == '\n') )
{
client->data[0] = '\0'; client->data[0] = '\0';
} }
} }
} }
return 0; return 0;
} }
/* Waits for client to provide a username. Blocks until a username is entered. */ int client_ask_username(client_t *client)
int client_ask_username(client_t *client) { {
int i; int i;
char msg[DATABUF_LEN]; char msg[DATABUF_LEN];
/* send username request to client */ /* show username request to the client */
snprintf(msg, 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, msg, strlen(msg)); client_write(client, msg, strlen(msg));
/* wait for client input */ /* wait for client input */
if (client_wait_line(client) != 0) return -1; if (client_wait_line(client) != 0)
{
return -1;
}
/* save received data as client username */ /* save received data as client username */
for (i = 0; i < USERNAME_LEN; i++) { for (i = 0; i < USERNAME_LEN; i++)
if ( (client->data[i] == '\r') || (client->data[i] == '\n') ) { {
/* don't include \r or \n in username */ if ( (client->data[i] == '\r') || (client->data[i] == '\n') )
{
/* don't include \r or \n in the username */
client->username[i] = '\0'; client->username[i] = '\0';
break; break;
} }
client->username[i] = client->data[i]; client->username[i] = client->data[i];
} }
/* send welcome message to client */ /* show welcome message to client */
snprintf(msg, DATABUF_LEN, snprintf(msg, DATABUF_LEN,
"\nWelcome %s!\n\n", client->username); "\nWelcome %s!\n\n", client->username);
client_write(client, msg, strlen(msg)); client_write(client, msg, strlen(msg));

48
client.h Normal file
View file

@ -0,0 +1,48 @@
/* Handles communication with clients. */
#include <moxerver.h>
/**
* Closes a client connection.
*/
void client_close(client_t *client);
/**
* Reads data from a client into the client data buffer.
* Also updates the timestamp of the client's last activity.
*
* Returns:
* - number of read bytes on success,
* - negative ENODATA value (-ENODATA) if the client has disconnected,
* - negative errno value set by an error while reading
*/
int client_read(client_t *client);
/**
* Sends data from a buffer to the client.
*
* Returns:
* - number of sent bytes on success,
* - negative errno value set by an error while sending
*/
int client_write(client_t *client, char *databuf, int datalen);
/**
* Waits for input from the client in "line mode" (client sends a whole line of
* characters). The function blocks until input arrives.
*
* Returns:
* - 0 on success
* - negative value if error occurred
*/
int client_wait_line(client_t *client);
/**
* Asks the client to provide a username.
* Blocks until a string is provided.
*
* Returns:
* - 0 on success
* - negative value if error occurred
*/
int client_ask_username(client_t *client);

View file

@ -110,55 +110,7 @@ int server_accept(server_t *server, client_t *accepted_client);
void* server_new_client_thread(void *args); void* server_new_client_thread(void *args);
/* Functions handling communication with clients. */
/**
* Closes client connection.
*
* Returns:
* 0 always, but internally tries closing again if it fails
*/
int client_close(client_t *client);
/**
* Reads data from client into client data buffer.
* Also updates client's last activity timestamp.
*
* Returns:
* - number of read bytes on success,
* - negative ENODATA value (-ENODATA) if client disconnected,
* - negative errno value set appropriately by error in reading
*/
int client_read(client_t *client);
/**
* Sends data from a buffer to client.
*
* Returns:
* - number of sent bytes on success,
* - negative errno value set appropriately by error in sending
*/
int client_write(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(client_t *client);
/**
* Waits for client to provide a username.
* Blocks until a username is entered.
*
* Returns:
* - 0 on success
* - negative value if error occurred
*/
int client_ask_username(client_t *client);