I have the following code of a server:
#include <signal.h>
#include <sys/stat.h>
#include "utils.h"
#include "kissdb.h"
#define MY_PORT 6767
#define BUF_SIZE 1160
#define KEY_SIZE 128
#define HASH_SIZE 1024
#define VALUE_SIZE 1024
#define MAX_PENDING_CONNECTIONS 10
// Definition of the operation type.
typedef enum operation {
PUT,
GET
} Operation;
// Definition of the request.
typedef struct request {
Operation operation;
char key[KEY_SIZE];
char value[VALUE_SIZE];
} Request;
// Definition of the database.
KISSDB *db = NULL;
/**
* #name parse_request - Parses a received message and generates a new request.
* #param buffer: A pointer to the received message.
*
* #return Initialized request on Success. NULL on Error.
*/
Request *parse_request(char *buffer) {
char *token = NULL;
Request *req = NULL;
// Check arguments.
if (!buffer)
return NULL;
// Prepare the request.
req = (Request *) malloc(sizeof(Request));
memset(req->key, 0, KEY_SIZE);
memset(req->value, 0, VALUE_SIZE);
// Extract the operation type.
token = strtok(buffer, ":");
if (!strcmp(token, "PUT")) {
req->operation = PUT;
} else if (!strcmp(token, "GET")) {
req->operation = GET;
} else {
free(req);
return NULL;
}
// Extract the key.
token = strtok(NULL, ":");
if (token) {
strncpy(req->key, token, KEY_SIZE);
} else {
free(req);
return NULL;
}
// Extract the value.
token = strtok(NULL, ":");
if (token) {
strncpy(req->value, token, VALUE_SIZE);
} else if (req->operation == PUT) {
free(req);
return NULL;
}
return req;
}
/*
* #name process_request - Process a client request.
* #param socket_fd: The accept descriptor.
*
* #return
*/
void process_request(const int socket_fd) {
char response_str[BUF_SIZE], request_str[BUF_SIZE];
int numbytes = 0;
Request *request = NULL;
// Clean buffers.
memset(response_str, 0, BUF_SIZE);
memset(request_str, 0, BUF_SIZE);
// receive message.
numbytes = read_str_from_socket(socket_fd, request_str, BUF_SIZE);
// parse the request.
if (numbytes) {
request = parse_request(request_str);
if (request) {
switch (request->operation) {
case GET:
// Read the given key from the database.
if (KISSDB_get(db, request->key, request->value))
sprintf(response_str, "GET ERROR\n");
else
sprintf(response_str, "GET OK: %s\n", request->value);
break;
case PUT:
// Write the given key/value pair to the database.
if (KISSDB_put(db, request->key, request->value))
sprintf(response_str, "PUT ERROR\n");
else
sprintf(response_str, "PUT OK\n");
break;
default:
// Unsupported operation.
sprintf(response_str, "UNKOWN OPERATION\n");
}
// Reply to the client.
write_str_to_socket(socket_fd, response_str, strlen(response_str));
if (request)
free(request);
request = NULL;
return;
}
}
// Send an Error reply to the client.
sprintf(response_str, "FORMAT ERROR\n");
write_str_to_socket(socket_fd, response_str, strlen(response_str));
}
/*
* #name main - The main routine.
*
* #return 0 on success, 1 on error.
*/
int main() {
int socket_fd, // listen on this socket for new connections
new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
// create socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
ERROR("socket()");
// Ignore the SIGPIPE signal in order to not crash when a
// client closes the connection unexpectedly.
signal(SIGPIPE, SIG_IGN);
// create socket adress of server (type, IP-adress and port number)
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // any local interface
server_addr.sin_port = htons(MY_PORT);
// bind socket to address
if (bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
ERROR("bind()");
// start listening to socket for incoming connections
listen(socket_fd, MAX_PENDING_CONNECTIONS);
fprintf(stderr, "(Info) main: Listening for new connections on port %d ...\n", MY_PORT);
clen = sizeof(client_addr);
// Allocate memory for the database.
if (!(db = (KISSDB *)malloc(sizeof(KISSDB)))) {
fprintf(stderr, "(Error) main: Cannot allocate memory for the database.\n");
return 1;
}
// Open the database.
if (KISSDB_open(db, "mydb.db", KISSDB_OPEN_MODE_RWCREAT, HASH_SIZE, KEY_SIZE, VALUE_SIZE)) {
fprintf(stderr, "(Error) main: Cannot open the database.\n");
return 1;
}
// main loop: wait for new connection/requests
while (1) {
// wait for incoming connection
if ((new_fd = accept(socket_fd, (struct sockaddr *)&client_addr, &clen)) == -1) {
ERROR("accept()");
}
// got connection, serve request
fprintf(stderr, "(Info) main: Got connection from '%s'\n", inet_ntoa(client_addr.sin_addr));
process_request(new_fd);
close(new_fd);
}
// Destroy the database.
// Close the database.
KISSDB_close(db);
// Free memory.
if (db)
free(db);
db = NULL;
return 0;
}
which handles a database (KISSDB here) that stores and prints values based on a key . I want to modify it , adding threads , producer and consumer ones. Producer thread should accept clients request and consumer thread execute it. I thought about putting all socket functions in a *producer() function that would handle them and let the consumer handle 'process_request() as it is . In main the threads are being created and called . It doesn't seem to run though , it compiles okay , but when executing ./client -a localhost -i 1 -p to start the client in the terminal , the program doesn't stop. I suspect the
pthread_create(&consumer_thread,NULL,process_request,(void*)&thread_args.new_fd);
is the problem. When I try to run the server , I get :
(Info) main: Listening for new connections on port 6767 ...
Error in read_from_socket(). Cause: Bad file descriptor
See what I've tried :
#define _POSIX_C_SOURCE 200809L
#include <inttypes.h>
#include <math.h>
#include<time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include<pthread.h>
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t c = PTHREAD_COND_INITIALIZER;
#include <signal.h>
#include <sys/stat.h>
#include "utils.h"
#include "kissdb.h"
//we have to use it
#define MY_PORT 6767
#define BUF_SIZE 1160
#define KEY_SIZE 128
#define HASH_SIZE 1024
#define VALUE_SIZE 1024
#define MAX_PENDING_CONNECTIONS 10
// =======================================
//struct timespec { // INCLUDE IN <time.h> ?
// time_t tv_sec; /* seconds */
// long tv_nsec; /* nanoseconds */
//};
/*
int socket_fd, // listen on this socket for new connections
new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
*/
struct data {
int socket_fd; // listen on this socket for new connections
int new_fd; // use this socket to service a new connection
};
// Definition of the operation type.
typedef enum operation {
PUT,
GET
} Operation;
// Definition of the request.
typedef struct request {
Operation operation;
char key[KEY_SIZE];
char value[VALUE_SIZE];
} Request;
// Definition of the database.
KISSDB *db = NULL;
/**
* #name parse_request - Parses a received message and generates a new request.
* #param buffer: A pointer to the received message.
*
* #return Initialized request on Success. NULL on Error.
*/
Request *parse_request(char *buffer) {
char *token = NULL;
Request *req = NULL;
// Check arguments.
if (!buffer)
return NULL;
// Prepare the request.
req = (Request *) malloc(sizeof(Request));
memset(req->key, 0, KEY_SIZE);
memset(req->value, 0, VALUE_SIZE);
// Extract the operation type.
token = strtok(buffer, ":");
if (!strcmp(token, "PUT")) {
req->operation = PUT;
} else if (!strcmp(token, "GET")) {
req->operation = GET;
} else {
free(req);
return NULL;
}
// Extract the key.
token = strtok(NULL, ":");
if (token) {
strncpy(req->key, token, KEY_SIZE);
} else {
free(req);
return NULL;
}
// Extract the value.
token = strtok(NULL, ":");
if (token) {
strncpy(req->value, token, VALUE_SIZE);
} else if (req->operation == PUT) {
free(req);
return NULL;
}
return req;
}
/*
* #name process_request - Process a client request.
* #param socket_fd: The accept descriptor.
*
* #return
*/
//for consumer
void *process_request(void * socket_fd) {
char response_str[BUF_SIZE], request_str[BUF_SIZE];
int numbytes = 0;
Request *request = NULL;
// Clean buffers.
memset(response_str, 0, BUF_SIZE);
memset(request_str, 0, BUF_SIZE);
// receive message.
numbytes = read_str_from_socket(socket_fd, request_str, BUF_SIZE);
// parse the request.
if (numbytes) {
request = parse_request(request_str);
if (request) {
switch (request->operation) {
case GET:
// Read the given key from the database.
if (KISSDB_get(db, request->key, request->value))
sprintf(response_str, "GET ERROR\n");
else
sprintf(response_str, "GET OK: %s\n", request->value);
break;
case PUT:
// Write the given key/value pair to the database.
if (KISSDB_put(db, request->key, request->value))
sprintf(response_str, "PUT ERROR\n");
else
sprintf(response_str, "PUT OK\n");
break;
default:
// Unsupported operation.
sprintf(response_str, "UNKOWN OPERATION\n");
}
// Reply to the client.
write_str_to_socket(socket_fd, response_str, strlen(response_str));
if (request)
free(request);
request = NULL;
return;
}
}
// Send an Error reply to the client.
sprintf(response_str, "FORMAT ERROR\n");
write_str_to_socket(socket_fd, response_str, strlen(response_str));
}
///////////////////////////////////////////////////////////////////////////////
void *producer(void *arg) {
// int socket_fd, // listen on this socket for new connections
// new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
struct data *d = (struct data *) arg;
// create socket
if ((d->socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
ERROR("socket()");
// Ignore the SIGPIPE signal in order to not crash when a
// client closes the connection unexpectedly.
signal(SIGPIPE, SIG_IGN);
// create socket adress of server (type, IP-adress and port number)
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // any local interface
server_addr.sin_port = htons(MY_PORT);
// bind socket to address
if (bind(d->socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
ERROR("bind()");
// start listening to socket for incoming connections
listen(d->socket_fd, MAX_PENDING_CONNECTIONS);
fprintf(stderr, "(Info) main: Listening for new connections on port %d ...\n", MY_PORT);
clen = sizeof(client_addr);
// wait for incoming connection EDW 8A KANOUME TA THREADS ?
if ((d->new_fd = accept(d->socket_fd, (struct sockaddr *)&client_addr, &clen)) == -1) { // to client_socket pou 8a peira3oume
ERROR("accept()");
}
//clock_gettime(CLOCK_REALTIME, &spec);
//s = spec.tv_sec;
//ms = spec.tv_nsec;
//fprintf(stderr, "Current time: %li . %03ld seconds since the connection\n",(long)s, ms);
// got connection, serve request
fprintf(stderr, "(Info) main: Got connection from '%s'\n", inet_ntoa(client_addr.sin_addr));
}
/*
* #name main - The main routine.
*
* #return 0 on success, 1 on error.
*/
int main() {
long ms; // Milliseconds
time_t s; // Seconds
struct timespec spec;
struct data thread_args;
// Allocate memory for the database.
if (!(db = (KISSDB *)malloc(sizeof(KISSDB)))) {
fprintf(stderr, "(Error) main: Cannot allocate memory for the database.\n");
return 1;
}
// Open the database.
if (KISSDB_open(db, "mydb.db", KISSDB_OPEN_MODE_RWCREAT, HASH_SIZE, KEY_SIZE, VALUE_SIZE)) {
fprintf(stderr, "(Error) main: Cannot open the database.\n");
return 1;
}
pthread_t producer_thread;
pthread_create(&producer_thread,NULL,producer,(void *) &thread_args);
// main loop: wait for new connection/requests
while (1) {
//process_request(new_fd); // nai !
/*teo's new code , for (i) part of project */
pthread_t consumer_thread;
pthread_create(&consumer_thread,NULL,process_request,(void*)&thread_args.new_fd);
pthread_join(consumer_thread,NULL); // necessary
/* */
//close(new_fd);
}
// Destroy the database.
// Close the database.
KISSDB_close(db);
// Free memory.
if (db)
free(db);
db = NULL;
return 0;
}
Related
I'm trying to make a client/server program with the OpenSSL that can set up a secure connection and then pass encrypted messages back and forth. I'm using a self-signed certificate for the server and a private key for the client. When a connection is established, I use SSL_accept() to initiate the handshake. This is where the program breaks. On the client-side, the error message is:
140104940065408:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1543:SSL alert number 40
and on the server-side the error message is:
140062094398080:error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher:../ssl/statem/statem_srvr.c:2283:
I'm very new to OpenSSL and to cryptography in general so I'm quite lost as to how to proceed from here. Any help would be greatly appreciated. I'll post the full code for the client and server below.
Client Program:
#include <errno.h> /*USING THE ERROR LIBRARY FOR FINDING ERRORS*/
#include <stdio.h> /*standard i/o*/
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#include <malloc.h> /*FOR MEMORY ALLOCATION */
#include <string.h> /*using fgets funtions for geting input from user*/
#include <sys/socket.h> /*for creating sockets*/
#include <resolv.h> /*server to find out the runner's IP address*/
#include <netdb.h> /*definitions for network database operations */
#include <openssl/ssl.h> /*using openssl function's and certificates and configuring them*/
#include <openssl/err.h> /* helps in finding out openssl errors*/
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#define FAIL -1 /*for error output == -1 */
#define BUFFER 1024 /*buffer for reading messages*/
// CLIENT PROGRAM
//code from: https://github.com/ElectronSz/Encrypted-Chat-Server-Using-C-Programming-and-OpenSSL-AES-DES
int OpenConnection(const char *hostname, int port) {
int sd;
struct hostent *host;
struct sockaddr_in addr; /*creating the sockets*/
if ( (host = gethostbyname(hostname)) == NULL ) {
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0); /* setting the connection as tcp it creates endpoint for connection */
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) /*initiate a connection on a socket*/ {
close(sd);
perror(hostname);
abort();
}
return sd;
}
void LoadKey(SSL_CTX* ctx, char* KeyFile) /* to load a certificate into an SSL_CTX structure*/ {
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 ) {
ERR_print_errors_fp(stderr);
abort();
}
}
SSL_CTX* InitCTX(void) /*creating and setting up ssl context structure*/ {
const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = TLS_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL ) {
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl) /*show the ceritficates to server and match them but here we are not using any client certificate*/ {
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL ) {
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
} else {
printf("Info: No client certificates configured.\n");
}
}
int main(int count, char *strings[]) /* getting port and ip as an argument*/ {
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
char input[BUFFER];
int bytes;
char *hostname, *portnum;
pid_t cpid; /* fork variable*/
if ( count != 3 ) {
printf("usage: %s \n", strings[0]);
exit(0);
}
SSL_library_init(); /*load encryption and hash algo's in ssl*/
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
//SSL_CTX_set_ciphersuites(ctx, OSSL_default_ciphersuites());
LoadKey(ctx, "client.pem"); /* load certs */
server = OpenConnection(hostname, atoi(portnum)); /*converting ascii port to interger */
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
//SSL_set_ciphersuites(ssl, OSSL_default_ciphersuites());
/* Host common name */
// Not necessarily needed
//SSL_set_tlsext_host_name(ssl, "Conor");
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */ {
ERR_print_errors_fp(stderr);
} else {
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl);
/* get any certs */
cpid=fork();
/*Fork system call is used to create a new process*/
if(cpid==0) {
while(1) {
fflush(stdout);
printf("\nMESSAGE TO SERVER:");
fgets(input, BUFFER, stdin);
SSL_write(ssl, input, strlen(input)); /* encrypt & send message */
}
} else {
while(1) {
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 ) {
buf[bytes] = 0;
printf("\nMESSAGE FROM SERVER: %s\n", buf);
printf("\nMESSAGE TO SERVER:");
fflush(stdout);
}
}
}
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
Server Program:
//#include <openssl/applink.c>
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#include <errno.h> /*USING THE ERROR LIBRARY FOR FINDING ERRORS*/
#include <malloc.h> /*FOR MEMORY ALLOCATION */
#include <string.h> /*using fgets funtions for geting input from user*/
#include <arpa/inet.h> /*for using ascii to network bit*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h> /* network to asii bit */
#include <resolv.h> /*server to find out the runner's IP address*/
#include <stdio.h> /*standard i/o*/
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <inttypes.h>
#define FAIL -1 /*for error output == -1 */
#define BUFFER 1024 /*buffer for reading messages*/
// SERVER PROGRAM
void InitializeSSL() {
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
}
void DestroySSL() {
ERR_free_strings();
EVP_cleanup();
}
void ShutdownSSL(SSL* cSSL) {
SSL_shutdown(cSSL);
SSL_free(cSSL);
}
int OpenListener(int port) {
int sd;
struct sockaddr_in addr; /*creating the sockets*/
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr)); /*free output the garbage space in memory*/
addr.sin_family = AF_INET; /*getting ip address form machine */
addr.sin_port = htons(port); /* converting host bit to n/w bit */
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) /* assiging the ip address and port*/ {
perror("can't bind port"); /* reporting error using errno.h library */
abort(); /*if error will be there then abort the process */
}
if ( listen(sd, 10) != 0 ) /*for listening to max of 10 clients in the queue*/ {
perror("Can't configure listening port"); /* reporting error using errno.h library */
abort(); /*if erroor will be there then abort the process */
}
return sd;
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */ {
char buf[1024];
int sd, bytes;
char input[BUFFER];
pid_t cpid;
//Here is the SSL Accept portion. Now all reads and writes must use SSL
int ret = SSL_accept(ssl);
printf("%d\n", ret);
if (ret == 0) {
/* Hard error */
exit(-1);
} else if ( ret == -1 ) /* do SSL-protocol accept */ {
printf("Handshake Error %d\n", SSL_get_error(ssl, ret));
ERR_print_errors_fp(stderr);
exit(-1);
}
/*Fork system call is used to create a new process*/
cpid=fork();
if(cpid==0) {
while(1) {
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request and read message from server*/
if ( bytes > 0 ) {
buf[bytes] = 0;
printf("\nMESSAGE FROM CLIENT: %s\n", buf);
printf("\nMESSAGE TO CLIENT:");
fflush(stdout);
} else {
ERR_print_errors_fp(stderr);
}
}
} else {
while(1) {
fflush(stdout);
printf("\nMESSAGE TO CLIENT:");
fgets(input, BUFFER, stdin); /* get request and reply to client*/
SSL_write(ssl, input, strlen(input));
}
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
bool str_to_uint16(char *str, uint16_t *res) {
char *end;
errno = 0;
intmax_t val = strtoimax(str, &end, 10);
if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || *end != '\0') {
return false;
}
*res = (uint16_t) val;
return true;
}
int main(int count, char *strings[]) /* getting port as a argument*/ {
int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;
char buf[1024];
char input[BUFFER];
int bytes;
char *portnum;
pid_t cpid; /* fork variable*/
if ( count != 2 ) {
printf("Usage: %s <portnum> \n", strings[0]); /*send the usage guide if syntax of setting port is different*/
exit(0);
}
portnum = strings[1];
uint16_t temp;
uint16_t *aPortNumber = &temp;
if (str_to_uint16(portnum, aPortNumber) == false) {
printf("Port number must be between 0 and 65535.");
exit(1);
}
InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0) {
//Log and Error
exit(1);
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = INADDR_ANY;
saiServerAddress.sin_port = htons(*aPortNumber);
bind(sockfd, (struct sockaddr *) &saiServerAddress, sizeof(saiServerAddress));
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &len);
sslctx = SSL_CTX_new( TLS_server_method());
// check return values vvvv
int use_cert = SSL_CTX_use_certificate_file(sslctx, "server.pem" , SSL_FILETYPE_PEM);
if (use_cert == 0) {
ERR_print_errors_fp(stderr);
exit(-1);
}
int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "private-key.pem", SSL_FILETYPE_PEM);
if (use_prv == 0) {
ERR_print_errors_fp(stderr);
exit(-1);
}
cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//SSL_CTX_set_ciphersuites(sslctx, cipher_list.c_str());
//SSL_set_ciphersuites(cSSL, cipher_list.c_str());
Servlet(cSSL);
ShutdownSSL(cSSL);
return 0;
}
I am having a small problem when trying to implement a client-server program with multithreading on the side of the server. My idea is to have the server spin forever, accept a client when it can, and just send it to a client_handle() function using a thread.
Here is the problem: my server and client are using the code seen below. At the point of the initial response of the server, it fails in sending ALL_GOOD_CD. I'm not sure why this is happening, as I print out the socket fd of the client in a line before and it seems to match up with the file descriptor given to us at the time of acception.
One thought is that my socket id is not being passed to the thread correctly. My client never seems to receive the ALL_GOOD_CD (it is blocking on a recv() call after connecting with the server). I am new with threads and sockets, anything would help; thanks!
Here is the client code needed to run:
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
void DieWithError(char *errorMessage); /* Error handling function */
int main(int argc, char *argv[])
{
int sock; /* Socket descriptor */
struct sockaddr_in server_addr; /* Server address */
unsigned short server_port; /* Server port */
char *server_ip; /* Server IP address (dotted quad) */
char server_response[300]; /* Buffer to hold response from the server */
char* username;
/* Test for correct number of arguments */
if (argc != 4) {
fprintf(stderr, "Usage: %s <server_ip> <server_port> <username>\n", argv[0]);
exit(1);
}
server_ip = argv[1]; /* Second arg: server IP address (dotted quad) */
server_port = atoi(argv[2]); /* Third arg: server port number */
username = argv[3]; /* Fourth arg: username */
/* Create a reliable, stream socket using TCP */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError("socket() failed");
/* Construct the server address structure */
memset(&server_addr, 0, sizeof(server_addr)); /* Zero out structure */
server_addr.sin_family = AF_INET; /* Internet address family */
server_addr.sin_addr.s_addr = inet_addr(server_ip); /* Server IP address */
server_addr.sin_port = htons(server_port); /* Server port */
/* Establish the connection to the server */
if (connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0)
DieWithError("connect() failed, could not find server.");
printf("connected\n");
memset(&server_response, 0, 300);
if (recv(sock, server_response, 300, 0) < 0)
DieWithError("recv() for initial response failed");
printf("received initial reponse\n");
}
void DieWithError(char* errorMessage) {
fprintf(stderr, "Dying with error sadface: %s\n", errorMessage);
exit(1);
}
Here is the server code as minified as possible:
#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <arpa/inet.h> /* for sockaddr_in and inet_addr() */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <pthread.h> /* multithreading the clients! */
#define MAXMSGSIZE 150
#define MAXCLIENTS 5
#define TOO_MANY_CD 0
#define ALL_GOOD_CD 1
#define OTHER_BAD_CD 2
struct client {
char* username;
char** subs;
int socket;
char temp_msg[MAXMSGSIZE*2];
};
void DieWithError(char* errorMessage); /* Error handling function */
void handle_client(void* new_socket); /* Client handling function */
static struct client** clients;
static pthread_t* threads;
static pthread_mutex_t clients_mutex;
static pthread_mutex_t threads_mutex;
int main(int argc, char *argv[])
{
int server_sock; /* Server socket descriptor */
unsigned short server_port; /* Echo server port */
struct sockaddr_in server_addr; /* sockaddr_in struct to hold information about the server */
int server_addr_size; /* Size of server_addr struct in bytes */
int client_sock;
int empty_thread;
pthread_attr_t thread_attr;
if (argc != 2) { /* Test for correct number of arguments */
fprintf(stderr, "Usage: %s <server_port>\n", argv[0]);
exit(1);
}
clients = (struct client**) calloc(1, sizeof(struct client*) * MAXCLIENTS);
if (clients == NULL)
DieWithError("calloc() for clients failed");
threads = (pthread_t*) calloc(1, sizeof(pthread_t) * MAXCLIENTS);
if (clients == NULL)
DieWithError("calloc() for clients failed");
pthread_mutex_init(&clients_mutex, NULL);
pthread_mutex_init(&threads_mutex, NULL);
pthread_attr_init(&thread_attr);
pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
server_port = atoi(argv[1]);
/* Create a reliable, stream socket using TCP */
if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
DieWithError("socket() failed");
// Zero out server_addr var and fill with information
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(server_port);
// Bind server with sock, IP, and port so that the clients can connect to us
if (bind(server_sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0)
DieWithError("bind() failed");
// Allow this server to accept 5 clients at a time (queue has 0 capacity because we multithread)
if (listen(server_sock, 0) < 0)
DieWithError("listen() failed");
// Display some information so we can connect with client
printf("Using\n\tport: %d\n\tIP: %s\n", server_port, inet_ntoa(server_addr.sin_addr));
server_addr_size = sizeof(server_addr);
for (;;) {
int* new_socket = (int*)malloc(sizeof(int));
if ((*new_socket = accept(server_sock,
(struct sockaddr*) &server_addr, &server_addr_size)) < 0) {
printf("accept() failed");
continue;
}
int free_spot = -1;
for (int i = 0; i < MAXCLIENTS; i++)
if (!threads[i]) free_spot = i;
if (free_spot == -1) {
printf("no empty threads (max clients handled currently)");
send(*new_socket,(void*) OTHER_BAD_CD, sizeof(OTHER_BAD_CD), 0);
close(*new_socket);
continue;
}
if (pthread_create(&threads[free_spot], &thread_attr,
(void*) &handle_client, (void*) new_socket)) {
printf("pthread_create failed");
close(*new_socket);
continue;
}
printf("sent new client %d to handle_client()\n", *new_socket);
}
}
void handle_client(void* new_socket) {
int socket = *(int*)new_socket;
free(new_socket);
printf("handling new client %d\n", socket);
struct client* curr_cl;
pthread_mutex_lock(&clients_mutex);
printf("locked mutex?\n");
if (send(socket, (void*)ALL_GOOD_CD, sizeof(ALL_GOOD_CD), 0) < 0) {
printf("inital all good resp failed");
send(socket, (void*)OTHER_BAD_CD, sizeof(OTHER_BAD_CD), 0);
return;
}
printf("sent stuff\n");
int free_spot = -1;
for (int i = 0; i < MAXCLIENTS; i++)
if (!clients[i]) free_spot = i;
printf("filtered through clients and got free spot %d\n", free_spot);
if (free_spot == -1) {
printf("didn't find free spot :(\n");
send(socket, (void*)TOO_MANY_CD, sizeof(TOO_MANY_CD), 0);
pthread_mutex_unlock(&clients_mutex);
return;
}
printf("found free spot %d for client %d", free_spot, socket);
clients[free_spot] = (struct client*) calloc(1, sizeof(struct client));
if (clients[free_spot] == NULL) {
send(socket, (void*)OTHER_BAD_CD, sizeof(OTHER_BAD_CD), 0);
pthread_mutex_unlock(&clients_mutex);
return;
}
curr_cl = clients[free_spot];
if (recv(socket, curr_cl->username, sizeof(curr_cl->username), 0) < 0) {
send(socket, (void*)OTHER_BAD_CD, sizeof(OTHER_BAD_CD), 0);
pthread_mutex_unlock(&clients_mutex);
return;
}
// Subscribe client to #ALL automatically
curr_cl->subs[0] = "#ALL";
if (send(socket, (void*)ALL_GOOD_CD, sizeof(ALL_GOOD_CD), 0) < 0) {
printf("send() for final all good failed\n");
send(socket, (void*)OTHER_BAD_CD, sizeof(OTHER_BAD_CD), 0);
pthread_mutex_unlock(&clients_mutex);
return;
}
printf("\taccepted new client %s and now listening\n", curr_cl->username);
pthread_mutex_unlock(&clients_mutex);
return;
}
void DieWithError(char* errorMessage) {
fprintf(stderr, "Dying with error sadface: %s\n", errorMessage);
exit(1);
}
Here is the Makefile
# the compiler: gcc for C
CC = gcc
# compiler flags
CFLAGS = -g
make: ttweetcl.c ttweetsrv.c
gcc -o ttweetcli ttweetcl.c && gcc -o ttweetsrv ttweetsrv.c -lpthread
.PHONY: clean
clean:
rm -f ./ttweetcli ./ttweetsrv
Solved! One comment (now removed) noticed that I was not ending my printf()'s with a \n and therefore was not flushing the buffer. Now that I have added all \n's then the code executes as it should.
My Server can handle multiple clients/switches at a time.
My problem is in my switch I believe, I'm trying to send an open message to the the controller. I create the the tcp socket in the switch and then right after I try to send the message to the controller, however when I try to do this, the socket disconnects from the controller and goes into an infinite loop. I'm not sure why this occurs as I'm creating and sending the message outside of my while loop. If I comment where I send the message, the socket stays connected to the controller and I am able to wait for one of a set of file descriptors to become ready to perform I/O, currently I only have the keyboard and the socket. My socket also receives a message from the controller when it's connected "You are connected to the server". In addition since my switch socket disconnects my recv() return error code 107 due to the fact the socket is disconnected.
I'm not sure If I provided too much code to look through but I added comments where I thought my error was occurring in the switch as well as the controller. Greatly appreciated for some help. I didn't add any of my own header files because they are not necessary.
This where I execute the switch. Sends and receive messages here.
#include "switch.h"
#include "openFIFO.h"
#include "packets.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include<poll.h>
#include <signal.h>
void do_switch(int swIport, char *trafficfile,int swJport, int swKport, int IPlow, int IPhigh,char serverAddress[256], unsigned short portNumber){
int switch_sock;
char server_response[256];
struct pollfd pfds[6];
int rval;
/* Switch */
Switch sw;
sw.swJport = swJport;
sw.swIport = swIport;
sw.swKport = swKport;
sw.IPlow = IPlow;
sw.IPhigh = IPhigh;
int switchLength = sizeof(Switch);
// printf("\n\nstruct switchLength: %d\n", switchLength);
// printf("\n\nSwitch Struct: swIport: %d, swJport: %d, swKport: %d,
IPlow: %d, IPhigh: %d\n", sw.swIport, sw.swJport, sw.swKport, sw.IPlow,
sw.IPhigh);
printf("\n\nSwitch created with the following: swIport: %d, trafficfile:
%s, swJport: %d, swKport: %d, IPlow: %d, IPhigh: %d, serverAddress: %s,
portNumber: %d\n", swIport, trafficfile, swJport, swKport, IPlow, IPhigh,
serverAddress, portNumber);
int fifoWrite[2];
int fifoRead[2];
int counter = 0;
char message[20] = "Hello";
/* Create fifos */
if(swJport != -1){
fifoWrite[0] = openWF(swIport,swJport);
fifoRead[0] = openReadFifo(swJport, swIport);
counter = counter + 2;
}
if(swKport != -1){
fifoWrite[1] = openWF(swIport,swKport);
fifoRead[1] = openReadFifo(swKport, swIport);
counter = counter + 2;
}else if(swKport == -1){
fifoWrite[0] = openWF(swIport,swKport);
fifoRead[0] = openReadFifo(swKport, swIport);
counter = counter + 2;
}
printf("fifoWrite[0]: %d\n", fifoWrite[0]);
printf("fifoRead[0]: %d\n", fifoRead[0]);
printf("fifoWrite[1]: %d\n", fifoWrite[1]);
printf("fifoRead[1]: %d\n", fifoRead[1]);
/* Establish connection between the controller and switch */
/* Send a open packet to the controller */
/* Sending a stuct */
//PROBELM HERE BELOW!!!!!!!
switch_sock = CreateTCPClientSocket(portNumber, serverAddress);
if(send(switch_sock, message, sizeof(message), 0) == -1){
fprintf(stderr, "Send() Failed");
}
else{
printf("Open packet is being sent to the controller\n");
}
/* Initialize poll parameters */
//Keyboard
pfds[0].fd = STDIN_FILENO;
pfds[0].events = POLLIN;
// Socket!
pfds[1].fd = switch_sock;
pfds[1].events = POLLIN;
printf("Starting switch............................\n\n");
while(1){
rval = poll(pfds,2,-1);
if(rval == 0){
fprintf(stderr, "Poll timed out. \n");
}if(rval == -1){
fprintf(stderr, "ERROR: poll() failed");
exit(0);
}
/* Check Keyboard */
if(pfds[0].revents & POLLIN && pfds[0].fd == 0){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
printf("print_switch()\n");
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
printf(" print_switch()\n");
printf("switch-disconnected\n");
close(switch_sock);
exit(0)
}
}
/* Server sent a welcome message */
// Might be PROBELM HERE BELOW when trying to send the initial packet to
controller!!!!!!!
if(pfds[1].revents & POLLIN){
recv(switch_sock, &server_response, sizeof(server_response), 0);
printf("%s\n", server_response);
}
}
}
Creates a TCP Socket for the switch.
int CreateTCPClientSocket( unsigned short port, char *serverAddress){
int sock; /*socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Construct local address structure */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(port);
servAddr.sin_addr.s_addr = inet_addr(serverAddress);
if(connect(sock, (struct sockaddr *)&servAddr, sizeof(struct sockaddr)) <
0){
printf("Error code: %d\n", errno);
fprintf(stderr, "ERROR: connect() just failed\n");
exit(0);
}
return sock;
}
This is the controller
#include "controller.h"
#include "packets.h"
#include "switch.h"
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void do_controller(int nSwitch, int portNumber){
int controller_sock; /* Socket descriptor for server/controller */
int clnSocket; /*Socket descriptor for clients */
int activity;
int max_sd;
int sd;
int client_socket[nSwitch];
struct sockaddr_in address;
int addrlen;
/* Controller stuff */
Controller cont;
cont.ackCounter = 0;
cont.openCounter = 0;
Switch sw;
char message[256] = "You have reached the server\n";
char recv_message[20];
printf("\n\nController created: nSwitch: %d on portNumber: %d\n", nSwitch, portNumber);
/* Initialise all client_socket[] to 0 so not checked */
for(int i = 0; i < nSwitch; i++){
client_socket[i] = 0;
}
/*Create the server/controller socket */
controller_sock = CreateTCPServerSocket(portNumber);
//addrlen = sizeof(address);
/* Prepare for nonblocking I/O polling/select from the controller socket */
printf("Starting server.........\n\n");
while(1){
/* Zero the socket set and set for server sockets */
/* This must be reset every time select() is called */
/* Add keyboard to descriptor */
/* Add client and controller sockets to set */
FD_ZERO(&sockSet);
FD_SET(STDIN_FILENO, &sockSet);
FD_SET(controller_sock, &sockSet);
max_sd = controller_sock;
//max_sd = 0;
printf("nSwitch: %d\n", nSwitch);
for(int x = 0; x < nSwitch; x++){
sd = client_socket[x];
printf("sd: %d\n\n", sd);
if(sd > 0)
FD_SET(sd, &sockSet);
if(sd > max_sd)
max_sd = sd;
}
printf("max_sd: %d\n", max_sd);
//wait for one of the sockets, timeout is Null,
//so wait indefinitely
activity = select(max_sd + 1, &sockSet, NULL, NULL,NULL);
//printf("Activity: %d\n", activity);
if(activity < 0){
fprintf(stderr, "ERROR: select()\n");
exit(0);
}
/*Check keyboard */
if(FD_ISSET(STDIN_FILENO, &sockSet)){
int a;
char command[1024][256];
int commands;
char buf[256];
commands = read(0, buf, 256);
buf[commands] = '\0';
char *token;
token = strtok(buf, " ");
while(token != NULL){
strcpy(command[a], token);
a++;
token = strtok(NULL, " ");
}
a = 0;
bzero(buf, 256);
if(strcmp(command[0], "list") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
}
if(strcmp(command[0], "exit") == 0){
//TODO: Make a print function
print_controller(&cont, nSwitch);
exit(0);
}
continue;
}
/* Check the incoming FIFOS from the controller an attached switches */
/*If something happened on the controller socket,
then its an incomming connection. Accept new communitcation.Wait for a client to connect.
Recieve packets sent to the controller_sock
*/
if(FD_ISSET(controller_sock, &sockSet)){
clnSocket = AcceptTCPConnection(controller_sock);
if(send(clnSocket, message, sizeof(message), 0) != sizeof(message)){
fprintf(stderr, "Send()");
exit(0);
}
puts("Welcome message sent successfuly");
//PROBELM HERE BELOW!!!!!!! Returns error code 107 because the
socket disconnected.
recv(controller_sock, &recv_message, sizeof(recv_message), 0);
printf("This is my recv_message: %s\n", recv_message);
/*add new socket to array of sockets*/
for(int a = 0; a < nSwitch; a++){
/*if position is empty */
if(client_socket[a] == 0){
client_socket[a] = clnSocket;
printf("Adding to list of sockets as %d\n", client_socket[a]);
break;
}
}
}
/* Communicate with the sockets and handle TCP Client */
for(int z = 0; z <nSwitch; z++){
sd = client_socket[z];
/*Check if it was socket closed, and do other stuff */
if(FD_ISSET(sd ,&sockSet )){
getpeername(sd , (struct sockaddr*)&address , (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
close( sd );
client_socket[z] = 0;
}else{
//Do stuff for the client
printf("This is the client %d\n", sd);
}
}
}
}
These are the controllers functions: Assign a port to socket,Set socket to listen
int AcceptTCPConnection(int servSock){
int clntSock; /* Socket descriptor for client */
unsigned int clientAddressLen; /* sizeof(client_address); Length of client */
struct sockaddr_in cli_addr; /* Client address */
/* Set the size of the in-out parameter */
clientAddressLen = sizeof(cli_addr);
printf("ClientAddressLen: %x\n", clientAddressLen);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &cli_addr,
&clientAddressLen)) < 0){
fprintf(stderr, "ERROR: accept failed\n");
exit(0);
}
/* clntSock is connected to a client! */
//infrom user of socket number used in send and receive commands
printf("Handling client %s\n", inet_ntoa(cli_addr.sin_addr));
printf("New connection: socket fd is: %d, ip is: %s, port: %d\n\n",
clntSock, inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
return clntSock;
}
Create a TCP socket
int CreateTCPServerSocket(unsigned short port){
int sock; /* socket to create */
struct sockaddr_in servAddr; /* Local address */
/* Create socket for incoming connections */
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){
fprintf(stderr,"ERROR: socket() failed\n");
exit(0);
}
/* Construct local address structure */
/* Define the server address */
//bzero((char *) &server_address, sizeof(server_address));
memset(&servAddr, 0, sizeof(servAddr)); /* Zero out structure */
servAddr.sin_family = AF_INET; /* Internet address family
*/
servAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface
*/
servAddr.sin_port = htons(port); /* Local port */
/* Bind to the local address */
printf("New connection: ip is: %s, port: %d\n\n",
inet_ntoa(servAddr.sin_addr), ntohs(servAddr.sin_port));
if (bind(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
printf("Error code: %d\n", errno);
fprintf(stderr,"ERROR: bind() just failed\n");
exit(0);
}
/* Mark the socket so it will listen for incoming connections */
if (listen(sock, 5) < 0){
fprintf(stderr,"ERROR: listen() failed\n");
exit(0);
}
return sock;
}
I have been trying to learn sockets programming, and came across this website: http://beej.us/guide/bgnet/output/html/multipage/index.html which is really good. I was able to understand, but after writing a test program myself I ended up with a problem which I cannot figure after 3 hours. Have very limited time, so thought asking experts help here.
This is my server program:
/**
* Program showing how sockets can be used
*/
#include <stdio.h> // For printf
#include <strings.h> // For bzero, memset
#include <stdlib.h> // For exit, atoi
#include <unistd.h> // For close
#include <sys/socket.h> // For socket
#include <sys/types.h> // For types
#include <arpa/inet.h> // For inet_addr
#include <netdb.h> // Import module network database
#include <errno.h> // To access the global errno that holds last system call error
#include <assert.h> // For asserting
#define ADDRESSINFO_GET_SUCCESS 0
const int kSuccess = 0;
const char *kMyPort = "3490"; // Can be either port num or name of the service
const int kMaxListenConn = 10; // How many connections queue will hold
// Utility function to get socket address, IPv4 or IPv6:
void* getSocketAddress(const struct sockaddr *sa)
{
// Cast socketaddr to sockaddr_in to get address and port values from data
if (sa->sa_family == PF_INET) {
return &(((struct sockaddr_in *)sa)->sin_addr);
}
return &(((struct sockaddr_in6 *)sa)->sin6_addr);
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndBindSocket(const struct addrinfo *addrList)
{
int status = -1; // Invalid status
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
char ipAddr[INET6_ADDRSTRLEN];
inet_ntop(addrIt->ai_family, getSocketAddress(addrIt->ai_addr), ipAddr, sizeof ipAddr);
printf("IP: %s\n", ipAddr);
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
printf("Port %d\n",((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
/*
* STEP 2.4: Bind our socket with ip address and port number to listen
*/
status = bind(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
fprintf(stderr, "Failed to bind socket with error:%d\n", errno);
perror("bind"); // Get error desc
// Clear socket
close(socketFileDesc);
socketFileDesc = -1;
continue; // Try next address
}
}
return socketFileDesc;
}
int main()
{
int status = -1; // Status is invalid
struct addrinfo hints; // Holds our hints to get address info
struct addrinfo *addrList; // Contains our address info
/*
* STEP 1: Setup service details
*/
// Make sure struct is empty
bzero(&hints, sizeof hints); // memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; // Don't care IPv4 or v6
hints.ai_socktype = SOCK_STREAM; // Use TCP stream sockets
hints.ai_flags = AI_PASSIVE; // Use my local IPs or you igore this and provide IP manually in first arg
status = getaddrinfo(NULL, kMyPort, &hints, &addrList);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info with error: %s\n", gai_strerror(status));
exit(1);
}
/*
* STEP 2: Create a socket and bind it
*/
int socketFileDesc;
socketFileDesc = createAndBindSocket(addrList);
freeaddrinfo(addrList); // Done with list
if (socketFileDesc == -1) {
exit(1);
}
/*
* STEP 3: Listen to the port for incoming connections
*/
status = listen(socketFileDesc, kMaxListenConn); // Second arg is number of incoming connections in queue
if (status != kSuccess) {
fprintf(stderr, "Failed to listen to the port\n");
perror("listen");
goto exit;
}
printf("Server is listening at the port %s\n", kMyPort);
struct sockaddr_storage inConnAddr; // Big enough to hold both IPv4 and v6
socklen_t inConnAddrLen = sizeof inConnAddr;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize] = {0};
long bytesReceived = -1;
long bytesSent = 0;
int clientSockfd;
while (1) {
/*
* STEP 4: Accept incoming connections
*/
inConnAddrLen = sizeof inConnAddr;
clientSockfd = accept(socketFileDesc, (struct sockaddr *)&inConnAddr, &inConnAddrLen);
// Got new connection ?
if (clientSockfd == -1) {
perror("accept"); // Print error description
continue; // Continue to look for new connections
}
//
// Got connection, create child process to handle request
//
if (!fork()) {
close(socketFileDesc); // No need with child
char ipAddr[INET6_ADDRSTRLEN];
getSocketAddressString((struct sockaddr *)&inConnAddr, ipAddr);
printf("Child process created for hanlding request from %s\n", ipAddr);
/*
* STEP 5: Receive and Send data to requests
*/
bytesReceived = recv(clientSockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data from client %s\n", buff);
while (bytesSent < bytesReceived) {
bytesSent = send(clientSockfd, buff, bytesReceived, 0);
printf("Bytes sent %ld\n", bytesSent);
}
}
if (bytesReceived < 0) {
perror("recv");
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
}
close(clientSockfd); // Close socket
exit(0);
}
}
exit:
/*
* STEP 5: Close the socket
*/
close(socketFileDesc);
return 0;
}
This is my client program:
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <strings.h>
#include <arpa/inet.h>
const char kSuccess = 0;
// Utility function to get socket address
void* getSocketAddress(const struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &( ((struct sockaddr_in *)sa)->sin_addr );
}
return &( ((struct sockaddr_in6 *)sa)->sin6_addr );
}
// Utility function to get socket address string
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr)
{
inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN);
}
int createAndConnectSocket(const struct addrinfo *addrList)
{
int socketFileDesc = -1; // Invalid descriptor
const struct addrinfo *addrIt;
/*
* STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can
*/
for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next)
{
/*
* STEP 2.2: Crete the socket file descriptor for our IP address
*/
socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol);
if (socketFileDesc == -1) {
fprintf(stderr, "Failed to create socket with error: %d\n", errno);
perror("socket"); // Get error desc
continue; // Try next address
}
/*
* STEP 2.3: Set socket behaviour by making ip address to be re-used if used already
*/
int yes=1;
if (setsockopt(socketFileDesc, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("setsockopt");
exit(1);
}
char ipAdd[INET6_ADDRSTRLEN];
getSocketAddressString(addrIt->ai_addr, ipAdd);
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
printf("IP is %s::%d\n", ipAdd,((struct sockaddr_in *)addrIt->ai_addr)->sin_port);
// Connect to the socket
int status;
status = connect(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen);
if (status != kSuccess) {
perror("connect");
close(socketFileDesc);
socketFileDesc = -1;
continue;
}
}
return socketFileDesc;
}
int main(int argc, char* argv[])
{
// Check we have data from arguments
if (argc < 3 || argc > 3) {
perror("Invalid command");
printf("Usage: %s hostname portnumber\n", argv[0]);
printf(" %s 192.168.1.2 3490\n", argv[0]);
}
// Setup server address info
struct addrinfo *serverInfo;
struct addrinfo hints;
int status = -1;
memset(&hints, 0, sizeof hints); // Make sure it is empty
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // Use socket stream
((struct sockaddr_in *)&hints.ai_addr)->sin_port = atoi(argv[2]);
status = getaddrinfo(argv[1], "3490", &hints, &serverInfo);
if (status != kSuccess) {
fprintf(stderr, "Failed to get address info %s\n", gai_strerror(status));
exit(1);
}
printf("Connecting to %s::%s...\n", argv[1], argv[2]);
// Create and bind socket
int sockfd = createAndConnectSocket(serverInfo);
freeaddrinfo(serverInfo); // We are done with serverinfo
if (sockfd == -1) {
exit(1);
}
// Send and receive data from server
long bytesReceived = -1;
long bytesSent = 0;
const size_t kMaxBufferSize = 50;
char buff[kMaxBufferSize];
const char *msg = "Hi! I am client!";
size_t msgLen = strlen(msg);
printf("Connected to server\n");
// Loop to send and receive data
while (1) {
while (bytesSent < msgLen) {
bytesSent = send(sockfd, msg, msgLen, 0);
printf("Bytes sent %ld\n", bytesSent);
}
bytesReceived = recv(sockfd, &buff, kMaxBufferSize - 1, 0);
if (bytesReceived > 0)
{
printf("Data received from server: %s\n", buff);
}
else if (bytesReceived < 0) {
perror("Read error");
break;
}
else if (bytesReceived == 0) {
printf("Connection closed by server\n");
break;
}
}
// Close socket
close(sockfd);
return 0;
}
My problem is: Even though I have set the port and IP in getaddrinfo() call, but when it is binding or connecting the port number found in sockaddr struct is wrong as it is different value. I do know what is happing here, and I get connection refused message when I do that because of that.
Can anyone please take a look at my program and tell me why I am getting connection refused ? I would really appreciate if someone can suggest any improvements in my code.
Thanks
You're not connecting to the port you think you're connecting to.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490");
The value of sin_port must be in network byte order, i.e. big endian. You're instead assigning the value 3490 (via atoi) directly, so the value is in host byte order. Your platform is most likely using little endian byte ordering.
As a result instead of connecting to port 3490 (0DA2 hex) you're connecting to port 41485 (A2 0D hex).
You need to use the htons function, which converts a 16 bit value (since sin_port is a 16 bit field) from host byte order to network byte order. Also, there's no need to use atoi here. Just use a numeric constant instead.
((struct sockaddr_in *)addrIt->ai_addr)->sin_port = htons(3490);
I've been working on a program that was like the one I posted earlier here https://stackoverflow.com/questions/33989328/converting-linked-list-array-client-server-into-single-array except this time I tried to just get the sample code to work making my own program in the process (same basic program but different content) when I get this strange error. In the debugger there is a bit that if argc != 2 it's a usage: client hostname error. I ran it several times and discovered that argc is 1. How do I make argc be 2 and not 1 or 3? There is a client and server program as follows:
edit Now it says connection refused
client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//define constants
#define SERVER_PORT 6500
#define BUFFER_SIZE 1000
void die(const char*);
void pdie(const char *);
int main (int argc, char *argv[]) {
int sock; // file descriptor (fd) for socket connection
struct sockaddr_in server; // Socket info for server
struct sockaddr_in client; // Socket info about us
int clientLen; // length of client socket struct
struct hostent *hp; // return value from gethostbyname()
char buf[BUFFER_SIZE]; // buffer for message reception from server
int i; // loop counter
if (argc != 2) {
die("Usage: client hostname");
}
for(i = 0; i < 3; i++) {
// Open a socket unbound with type ip/tcp
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
pdie("Opening stream socket");
}
puts("created sock");
// Prepare to connect to server
memset((char*)&server, 0, sizeof(server));
server.sin_family = AF_INET;
if ((hp = gethostbyname(argv[1])) == NULL) {
char msg[100];
sprintf(msg, "%s: unknown host\n", argv[1]);
die(msg);
}
puts("prepared to connect to server");
// set sin_addr struct variables
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
// IP address should be set to that of the machine running the server
server.sin_addr.s_addr = inet_addr("replace with your ip address");
server.sin_port = htons((u_short) SERVER_PORT);
// Try to connect
socklen_t serverLen = sizeof(server);
if (connect(sock, (struct sockaddr *) &server, serverLen) < 0) {
pdie("connecting stream socket");
}
// Determine what port client is using
clientLen = sizeof(client);
if (getsockname(sock, (struct sockaddr *) &client, &clientLen)) {
pdie("Getting socket name");
}
if (clientLen != sizeof(client)) {
die("getsocketname() overwrote name structure");
}
printf("Client socket has port %hu\n", ntohs(client.sin_port));
// Prepare our buffer for a read
memset(buf, 0, sizeof(buf));
char input[80];
// get initial prompt
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user action choice and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
// control for translation choice
if (strncmp(input, "t", 1) == 0) {
// get prompt for word to translate
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
// get user word and send to server
scanf("%s", input);
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get translation
read(sock, buf, BUFFER_SIZE);
// output result
if(strncmp((char*)buf, "ERROR", 5) == 0) {
printf("%s\n", (char*)buf);
} else {
printf("%s in Japanese is %s\n", input, (char*)buf);
}
}
// control for add to dictionary choice
else if (strncmp(input, "a", 1) == 0) {
// get prompt for eng word
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
// get eng word from user
printf("%s", (char*)buf);
scanf("%s", input);
// send eng word to server
write(sock, (void*)input, strlen(input));
memset(buf, 0, sizeof(buf));
// get prompt for Japanese word
read(sock, buf, BUFFER_SIZE);
printf("%s", (char*)buf);
scanf("%s", input);
// send Japanese word to server
write(sock, (void*)input, strlen(input));
// get result
memset(buf, 0, sizeof(buf));
read(sock, buf, BUFFER_SIZE);
printf("%s\n", (char*)buf);
}
// Close this connection
close(sock);
}// end for loop
exit(0);
}// end main
// Call perror() to figure out what's going on and die
void pdie(const char *mesg) {
perror(mesg);
exit(1);
}
// Print a message and die
void die(const char *mesg) {
fputs(mesg, stderr);
fputc('\n', stderr);
exit(1);
}
and server
#define _REENTRANT
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/uio.h>
#include <unistd.h>
#include <pthread.h>
// constant declarations
#define TCP_PORT 6500
#define BUFFER_SIZE 1000
// variable declarations
pthread_mutex_t lock;
int serve_count;
// used to store eng word and translation
typedef struct wordpair* wordPairPtr;
struct wordPair
{
char* eng;
char* jap;
wordPairPtr nextPair;
};
typedef struct wordPair wordPair;
// used to store all word pairs in a directory
// implemented as a linked list
struct directory
{
wordPair* dict;
int num_words;
};
typedef struct directory directory;
// function prototypes
void* doKid(void*);
void initializeDirect();
int directAdd(char*, char*);
char* translate(char*);
// global directory variable
directory* d;
main ()
{
// variable declarations
int sockfd;
int newsockfd;
int client;
struct sockaddr_in cli_addr, serv_addr;
pthread_t chld_thr;
initializeDirect();// call function to create directory
puts ("initialized variables");
// build thread attributes
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
puts("set thread attributes");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
fprintf(stderr, "server: can't open stream socket\n");
exit(0);
}
puts("opened stream socket");
// set serv_addr struct variables
memset((char*) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(TCP_PORT);
puts("did serv_addr actions");
if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0 )
{
fprintf(stderr, "server: can't bind local address\n");
exit(0);
}
puts("bound local address");
// set the level of thread concurrency we desire
pthread_setconcurrency(5);
listen(sockfd, 5);
puts("set thread concurrency");
// begin listening for client requests
puts("awaiting requests");
for(;;)
{
client = sizeof(cli_addr);
newsockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &client);
if (newsockfd < 0)
{
fprintf(stderr, "server: accept error\n");
exit(0);
}
// create a new thread to process the incoming request
pthread_create(&chld_thr, &attr, doKid, (void*)newsockfd);
puts("Created thread");
// the server is now free to accept another socket request
}
free(d);
puts("now exiting");
return(0);
}// end main
// allocates memory for directory and stores small set of preloaded words and phrases
void initializeDirect()
{
d = (directory*)malloc(sizeof(directory));
if (d == NULL)
{
exit(1);
}
char *eng[20] = {"good morning", "good afternoon", "good evening", "good-bye",
"good night)", "thank you", "no", "yes",
"I'll go and come back", "I'm home", "mother", "father", "older sister", "older brother", "younger sister", "younger brother", "god", "boy", "girl", "spirit"
};
char *jap[20] = {"ohaiyou", "konnichiwa", "konbanwa", "sayonara",
"oyasumi(nasai)", "arigatou", "iie", "hai",
"ittekimasu", "tadaima", "okaasan", "otousan", "oneesan", "oniisan", "imouto", "otouto", "kami", "shoenen", "shoujo", "genki"
};
int i;
for(i = 0; i < 10; i++)
{
directAdd(eng[i], jap[i]);
}
}// end initializeDirect()
// adds a new word pair alphabetically into the directory
int directAdd(char* eng, char* jap)
{
// test for valid arguments
if (eng == NULL || jap == NULL)
{
return (-1);
}
// allocate memory for new wordPair
wordPair *newPair = (wordPair*)malloc(sizeof(wordPair));
if(newPair == NULL)
return(-1);
// assign passed values to new wordPair
newPair->eng = eng;
newPair->jap = jap;
newPair->nextPair = NULL;
// if this is the first wordPair, add it to the front of the linked list
if(d->dict == NULL)
{
d->dict = newPair;
return 0;
}
// otherwise, search directory for correct location for new word pair
wordPair *current = d->dict;
wordPair *previous = NULL;
while(current != NULL && (strcasecmp(current->eng, newPair->eng) < 0))
{
previous = current;
current = current->nextPair;
}
// if the new word is last in the directory, add it there
if(current == NULL)
{
previous->nextPair = newPair;
return 0;
}
// if the english word is already in the directory, return -2
if(strcasecmp(current->eng, newPair->eng) == 0)
{
free(newPair);
return -2;
}
// if the new word is first in the directory, add it there
if(previous == NULL)
{
newPair->nextPair = d->dict;
d->dict = newPair;
return;
}
// if none of the special cases occurred, add the new word
newPair->nextPair = current;
previous->nextPair = newPair;
// advance total count of words
d->num_words++;
// return success
return 0;
}
char* translate(char* eng)
{
// check that our directory is valid
if (d == NULL || d->dict == NULL)
return NULL;
// start searching at the beginning of the directory
wordPair *current = d->dict;
// loop until we find the word or reach the end of the directory
while(current != NULL && strcasecmp(current->eng, eng) < 0)
{
current = current->nextPair;
}
// the word is not in the directory
if(current == NULL)
{
return NULL;
}
// we found the word, return the translation
if( strcasecmp(current->eng, eng) == 0)
{
return strdup(current->jap);
}
// there was an error, return null
return NULL;
}// end translate
// this is the routine that is executed from a new thread
void *doKid(void* arg)
{
int mysocfd = (int) arg;
char buf[BUFFER_SIZE];
char *eng;
char *jap;
char *msg;
int i;
// allocate strings
memset(buf, 0, BUFFER_SIZE);
eng = (char*)malloc(sizeof(char[20]));
jap = (char*)malloc(sizeof(char[20]));
msg = (char*)malloc(sizeof(char[100]));
// build and send intro prompt for client
msg = "Would you like to translate or add a word? (t/a): ";
write(mysocfd, (void*)msg, strlen(msg));
// read from the given socket
read(mysocfd, buf, BUFFER_SIZE);
// if the client wants to translate a word
if(strncmp((char*)buf, "t", 1) == 0)
{
// build and send prompt for word to translate
msg = "Enter the English word you would like to translate to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// execute translation
char *trans;
trans = (char*)malloc(sizeof(char[20]));
// lock global variable for read
pthread_mutex_lock(&lock);
trans = translate((char*)buf);
pthread_mutex_unlock(&lock);
// if word was not in directory send error msg to client
if (trans == NULL)
{
msg = "ERROR: word is not in the directory.";
write(mysocfd, (void*)msg, strlen(msg));
}
// if word was translated, send result to client
else
{
write(mysocfd, (void*)trans, strlen(trans));
}
}
// if the client wants to add a word
else if (strncmp((char*)buf, "a", 1) == 0)
{
// build and send prompt for english word
msg = "Enter the English word to add: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive word
read(mysocfd, buf, BUFFER_SIZE);
strcpy(eng, buf);
// build and send prompt for jap translation
memset(buf, 0, sizeof(buf));
msg = "Enter the translation to jap: ";
write(mysocfd, (void*)msg, strlen(msg));
// receive translation
memset(buf, 0, sizeof(buf));
read(mysocfd, buf, BUFFER_SIZE);
strcpy(jap, buf);
// lock global variable for word insertion
pthread_mutex_lock(&lock);
int result = directAdd(eng, jap);
pthread_mutex_unlock(&lock);
// if the add to directory was successful, alert client
if (result == 0)
{
msg = "Added to directory";
}
// if the add to directory was unsuccessful send client error msg
else if (result == -2)
{
msg = "Word is already in directory";
}
else
{
msg = "ERROR.";
}
write(mysocfd, (void*)msg, strlen(msg));
}
// if no valid choice was sent by client, exit thread
else
{
close(mysocfd);
pthread_exit(0);
}
printf("Child[%lu]: Done Processing...\n", pthread_self());
// use a mutex to update the global service counter
pthread_mutex_lock(&lock);
serve_count++;
pthread_mutex_unlock(&lock);
printf("Kid thread [%lu]: The total sockets served = %d\n", pthread_self(), serve_count);
// close the socket and exit this thread
close(mysocfd);
pthread_exit(0);
}// end doKid()