forked from scott/threaded_network_chat
213 lines
4.6 KiB
C++
213 lines
4.6 KiB
C++
#include <string>
|
|
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <pthread.h>
|
|
#include <string.h>
|
|
#include <strings.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "chat.h"
|
|
|
|
typedef struct __wclient_args_t {
|
|
sockaddr_in new_addr;
|
|
socklen_t new_addr_siz;
|
|
int aux;
|
|
|
|
int *bread;
|
|
int *sock;
|
|
std::string log;
|
|
int *lpos;
|
|
} wclient_args_t;
|
|
|
|
typedef struct __wserver_args_t {
|
|
sockaddr_in new_addr;
|
|
socklen_t new_addr_siz;
|
|
int aux;
|
|
|
|
int *bread;
|
|
int *lpos;
|
|
std::string log;
|
|
} wserver_args_t;
|
|
|
|
/*
|
|
* client_start(listen_ip, listen_port, &socket_descriptor_client, log_path, &client_wait_thread);
|
|
*/
|
|
void
|
|
client_start(std::string ip, int port, int *sock, std::string log, pthread_t *thr)
|
|
{
|
|
char msg[1024];
|
|
int bread;
|
|
int bwrit;
|
|
sockaddr_in send_addr;
|
|
|
|
struct timeval time_start;
|
|
struct timeval time_end;
|
|
struct hostent *host = gethostbyname(ip.c_str());
|
|
|
|
auto *a = new wclient_args_t{};
|
|
|
|
bzero((char *)&send_addr, sizeof(send_addr));
|
|
send_addr.sin_family = AF_INET;
|
|
send_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr *)*host->h_addr_list));
|
|
send_addr.sin_port = htons(port);
|
|
*sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
attempt_client_connection:
|
|
int stat = connect(*sock, (sockaddr *)&send_addr, sizeof(send_addr));
|
|
if (stat < 0) {
|
|
log_append(log, "Error connecting to socket, retrying...");
|
|
goto attempt_client_connection;
|
|
}
|
|
|
|
log_append(log, "Connected to the server!");
|
|
bread = bwrit = 0;
|
|
|
|
gettimeofday(&time_start, NULL);
|
|
|
|
a->aux = *sock;
|
|
pthread_create(thr, nullptr, poll_server, a);
|
|
pthread_detach(*thr);
|
|
}
|
|
|
|
int
|
|
server_start(int port, int *sock, std::string log, pthread_t *thr, struct timeval *ts)
|
|
{
|
|
auto *a = new wclient_args_t{};
|
|
sockaddr_in srv_addr;
|
|
sockaddr_in newsock;
|
|
socklen_t newsock_siz = sizeof(newsock);
|
|
int bstat;
|
|
int rc;
|
|
|
|
/* set up socket and connection tools */
|
|
bzero((char *)&srv_addr, sizeof(srv_addr));
|
|
srv_addr.sin_family = AF_INET;
|
|
srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
srv_addr.sin_port = htons(port);
|
|
|
|
/* open stream-oriented socket w inet addr and track sock descriptor */
|
|
*sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (*sock < 0)
|
|
return 1;
|
|
|
|
/* bind sock to its local addr */
|
|
bstat = bind(*sock, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
|
|
if (bstat < 0)
|
|
return 1;
|
|
|
|
log_append(log, "Waiting for a client to connect...");
|
|
|
|
/* listen for up to 5 simultaneous requests */
|
|
listen(*sock, 5);
|
|
a->new_addr = newsock;
|
|
a->new_addr_siz = newsock_siz;
|
|
|
|
rc = pthread_create(thr, nullptr, await_client, a);
|
|
|
|
pthread_detach(*thr);
|
|
|
|
log_append(log, "Server started successfully.");
|
|
|
|
gettimeofday(ts, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *
|
|
await_client(void *args)
|
|
{
|
|
wclient_args_t *a = static_cast<wclient_args_t *>(a);
|
|
|
|
*a->sock = accept(*a->sock, (sockaddr *)&a->new_addr, &a->new_addr_siz);
|
|
|
|
if (*a->sock >= 0) {
|
|
log_append(a->log, "client connected");
|
|
|
|
if (count_lines(a->log) > LOG_LENGTH)
|
|
++*a->lpos;
|
|
|
|
file_disp(a->log, *a->lpos, LOG_LENGTH);
|
|
}
|
|
|
|
/* get what we need for the return and throw the rest away */
|
|
int *s = a->sock;
|
|
int *b = a->bread;
|
|
std::string l = a->log;
|
|
int *p = a->lpos;
|
|
delete a;
|
|
|
|
return poll_client(s, b, l, p);
|
|
}
|
|
|
|
void *
|
|
poll_client(int *sock, int *bread, std::string log, int *lpos)
|
|
{
|
|
char msg[1024];
|
|
for (;;) {
|
|
/* listen for msg from client */
|
|
memset(&msg, 0, sizeof(msg)); /* clear buf */
|
|
*bread += recv(*sock, (char *)&msg, sizeof(msg), 0);
|
|
log_append(log, msg);
|
|
|
|
if (count_lines(log) > LOG_LENGTH)
|
|
++*lpos;
|
|
|
|
file_disp(log, *lpos, LOG_LENGTH);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void *
|
|
poll_server(void *args)
|
|
{
|
|
wserver_args_t *a = static_cast<wserver_args_t *>(args);
|
|
int sock_desc = (int)a->aux;
|
|
char msg[1024];
|
|
|
|
for (;;) {
|
|
memset(&msg, 0, sizeof(msg));
|
|
*a->bread += recv(sock_desc, (char *)&msg, sizeof(msg), 0);
|
|
|
|
log_append(a->log, msg);
|
|
|
|
if (count_lines(a->log) > LOG_LENGTH)
|
|
++*a->lpos;
|
|
|
|
file_disp(a->log, *a->lpos, LOG_LENGTH);
|
|
}
|
|
|
|
delete a;
|
|
}
|
|
|
|
void
|
|
server_stop(struct timeval *start, struct timeval *end, int *sock, int *bread, int *bwrit)
|
|
{
|
|
long e = end->tv_sec - start->tv_sec;
|
|
|
|
gettimeofday(end, NULL);
|
|
close(*sock);
|
|
|
|
/* Don't just die silently */
|
|
puts("********Session********");
|
|
printf("Bytes written: %i\nBytes Read: %i\n", *bwrit, *bread);
|
|
printf("Elapsed time: %ld\n secs\n", e);
|
|
puts("Connection closed...");
|
|
}
|
|
|
|
void
|
|
client_stop(struct timeval *start, struct timeval *end, int *sock, int *bread, int *bwrit)
|
|
{
|
|
long e = end->tv_sec - start->tv_sec;
|
|
|
|
gettimeofday(end, NULL);
|
|
close(*sock);
|
|
puts("********Session********");
|
|
printf("Bytes written: %i\nBytes read: %i\n", *bwrit, *bread);
|
|
printf("Elapsed time: %ld\n secs\n", e);
|
|
puts("Connection closed...");
|
|
}
|