Seems that flow not going in " for" loop containing accept in ipv6server.c and hence not able to accept and connect with the client. Whats the mistake ? This code is working fine for IPV4 but after IPV6 changes getting this problem
ipv6server.c
#include <stdio.h>
#include <stdlib.h> /* needed for os x */
#include <string.h> /* for memset */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h> /* defines ERESTART, EINTR */
#include <sys/wait.h> /* defines WNOHANG, for wait() */
#include "port.h" /* defines default port */
#ifndef ERESTART
#define ERESTART EINTR
#endif
extern int errno;
void serve(int port); /* main server function */
void disconn(void);
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
int c, err = 0;
int port = SERVICE_PORT;
static char usage[] = "usage: %s [-d] [-p port]\n";
while ((c = getopt(argc, argv, "dp:")) != -1)
switch (c) {
case 'p':
port = atoi(optarg);
if (port < 1024 || port > 65535) {
fprintf(stderr, "invalid port number: %s\n", optarg);
err = 1;
}
break;
case '?':
err = 1;
break;
}
if (err || (optind < argc)) {
fprintf(stderr, usage, argv[0]);
exit(1);
}
serve(port);
}
/* serve: set up the service */
void
serve(int port)
{
int svc; /* listening socket providing service */
int rqst; /* socket accepting the request */
socklen_t alen; /* length of address structure */
struct sockaddr_in6 my_addr; /* address of this service */
struct sockaddr_in6 client_addr; /* client's address */
int sockoptval = 1;
char hostname[128]; /* host name, for debugging */
gethostname(hostname, 128);
/* get a tcp/ip socket */
/* AF_INET is the Internet address (protocol) family */
/* with SOCK_STREAM we ask for a sequenced, reliable, two-way */
/* conenction based on byte streams. With IP, this means that */
/* TCP will be used */
if ((svc = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
perror("cannot create socket");
exit(1);
}
/* we use setsockopt to set SO_REUSEADDR. This allows us */
/* to reuse the port immediately as soon as the service exits. */
/* Some operating systems will not allow immediate reuse */
/* on the chance that some packets may still be en route */
/* to the port. */
setsockopt(svc, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int));
/* set up our address */
/* htons converts a short integer into the network representation */
/* htonl converts a long integer into the network representation */
/* INADDR_ANY is the special IP address 0.0.0.0 which binds the */
/* transport endpoint to all IP addresses on the machine. */
memset((char*)&my_addr, 0, sizeof(my_addr)); /* 0 out the structure */
my_addr.sin6_family = AF_INET6; /* address family */
my_addr.sin6_port = htons(port);
my_addr.sin6_addr = in6addr_any;
client_addr.sin6_family = AF_INET6; /* address family */
client_addr.sin6_port = htons(port);
client_addr.sin6_addr = in6addr_any;
/* bind to the address to which the service will be offered */
if (bind(svc, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) {
perror("bind failed");
exit(1);
}
/* set up the socket for listening with a queue length of 5 */
if (listen(svc, 5) < 0) {
perror("listen failed");
exit(1);
}
printf("server started on %s, listening on port %d\n", hostname, port);
/* loop forever - wait for connection requests and perform the service */
alen = sizeof(client_addr); /* length of address */
for (;;) {
while ((rqst = accept(svc,
(struct sockaddr *)&client_addr, &alen)) < 0) {
/* we may break out of accept if the system call */
/* was interrupted. In this case, loop back and */
/* try again */
if ((errno != ECHILD) && (errno != ERESTART) && (errno != EINTR)) {
perror("accept failed");
exit(1);
}
}
printf("received a connection from: %s port %d\n",
inet_ntoa(client_addr.sin6_addr), ntohs(client_addr.sin6_port));
shutdown(rqst, 2); /* close the connection */
}
}
ipv6client.c
/*
echoc: a demo of TCP/IP sockets connect
usage: client [-h serverhost] [-p port]
*/
#include <stdio.h>
#include <stdlib.h> /* needed for os x*/
#include <string.h> /* for strlen */
#include <netdb.h> /* for gethostbyname() */
#include <sys/socket.h>
#include <netinet/in.h>
#include "port.h" /* defines default port */
int conn(char *host, int port);
void disconn(void);
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
int c, err = 0;
char *prompt = 0;
int port = SERVICE_PORT; /* default: whatever is in port.h */
char *host = "localhost"; /* default: this host */
static char usage[] =
"usage: %s [-d] [-h serverhost] [-p port]\n";
while ((c = getopt(argc, argv, "dh:p:")) != -1)
switch (c) {
case 'h': /* hostname */
host = optarg;
break;
case 'p': /* port number */
port = atoi(optarg);
if (port < 1024 || port > 65535) {
fprintf(stderr, "invalid port number: %s\n", optarg);
err = 1;
}
break;
case '?':
err = 1;
break;
}
if (err || (optind < argc)) { /* error or extra arguments? */
fprintf(stderr, usage, argv[0]);
exit(1);
}
printf("connecting to %s, port %d\n", host, port);
if (!conn(host, port)) /* connect */
exit(1); /* something went wrong */
disconn(); /* disconnect */
return 0;
}
int fd; /* fd is the file descriptor for the connected socket */
/* conn: connect to the service running on host:port */
/* return 0 on failure, non-zero on success */
int
conn(char *host, int port)
{
struct hostent *hp; /* host information */
unsigned int alen; /* address length when we get the port number */
struct sockaddr_in6 myaddr; /* our address */
struct sockaddr_in6 servaddr; /* server address */
printf("conn(host=\"%s\", port=\"%d\")\n", host, port);
/* get a tcp/ip socket */
/* We do this as we did it for the server */
/* request the Internet address protocol */
/* and a reliable 2-way byte stream */
if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
perror("cannot create socket");
return 0;
}
/* bind to an arbitrary return address */
/* because this is the client side, we don't care about the */
/* address since no application will connect here --- */
/* INADDR_ANY is the IP address and 0 is the socket */
/* htonl converts a long integer (e.g. address) to a network */
/* representation (agreed-upon byte ordering */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin6_family = AF_INET6;
myaddr.sin6_addr = in6addr_any;
myaddr.sin6_port = htons(0);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
perror("bind failed");
return 0;
}
/* this part is for debugging only - get the port # that the operating */
/* system allocated for us. */
alen = sizeof(myaddr);
if (getsockname(fd, (struct sockaddr *)&myaddr, &alen) < 0) {
perror("getsockname failed");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin6_port));
/* fill in the server's address and data */
/* htons() converts a short integer to a network representation */
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(port);
/* look up the address of the server given its name */
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
/* put the host's address into the server address structure */
memcpy((void *)&servaddr.sin6_addr, hp->h_addr_list[0], hp->h_length);
/* connect to server */
if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("connect failed");
return 0;
}
return 1;
}
/* disconnect from the service */
void
disconn(void)
{
printf("disconn()\n");
shutdown(fd, 2); /* 2 means future sends & receives are disallowed */
}
hp = gethostbyname(host);
How do you know this returns an IPv6 address if you pass it "localhost" ? It probably returns the IPv4 address, and things go belly up if you try to copy that into servaddr.sin6_addr
Use getaddrinfo() and explicitly look for an AF_INET6 address (or better yet, make your program independent of the actual address types, see here), or use the global in6addr_loopback as the server address, for testing with localhost.
I can see a few issues of varying degrees:
Don't declare errno yourself - use the headers. It may be a macro instead of an int
(per #Boofhead) don't bind the client socket
Use getaddrinfo() instead of gethostbyname() in the client to get the server's address. gethostbyname() doesn't portably support IPv6
The last of the 3 is actually the real problem. I've tested your code on MacOS X and CentOS 5 and gethostbyname() only returns an IPv4 address.
Related
I have a windows application that works as a client and installed on multiple device and they can communicate with each other, Now I want to encrypt the communication. I tried to found out some methods like Microsoft's SSPI library and SChannel but didn't find an easy implementation, So I am trying with the OpenSSL.
I am trying to create a client and server using winsocket and enabling TLS communication using OpenSSL in Visual Studio 2019. THe problem is it gets connect to the server, the server prints the message connected to client and also client code show connected, but on SSL_Connect method it fails and shows no error in the client code! I also created a normal TCP socket server and try to connect it to this as well than also it fails after connecting.
What is going wrong! Here is my code:
Client:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <errno.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <WS2tcpip.h>
#include <string>
#include <iostream>
#pragma comment (lib, "ws2_32.lib")
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* 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();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char* hostname, int port)
{
int sd;
struct hostent* host;
struct sockaddr_in addr;
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
printf("winsock error");
return 0;
}
if ((host = gethostbyname(hostname)) == NULL)
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
ZeroMemory(&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)
{
closesocket(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{
const SSL_METHOD* method = TLS_client_method(); /* Create new client-method instance */
SSL_CTX* ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
// method = SSLv3_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)
{
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("No certificates.\n");
}
int main()
{
SSL_CTX* ctx;
int server;
SSL* ssl;
char buf[1024];
int bytes;
char hostname[] = "127.0.0.1";
char portnum[] = "54000";
char CertFile[] = "C:/Users/cert/Documents/testing/ec_crt.pem";
char KeyFile[] = "C:/Users/cert/Documents/testing/private-key.pem";
SSL_library_init();
ctx = InitCTX();
LoadCertificates(ctx, CertFile, KeyFile);
printf("clinet certificate loaded");
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if (SSL_connect(ssl) == FAIL) /* perform the connection */ {
printf("Connection failed");
ERR_print_errors_fp(stderr);
}
else
{
const char* msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
closesocket(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
SERVER:
//SSL-Server.c
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <sys/types.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
#define FAIL -1
int OpenListener(int port)
{
int sd;
struct sockaddr_in addr;
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
printf("winsock error");
return 0;
}
sd = socket(PF_INET, SOCK_STREAM, 0);
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
perror("can't bind port");
abort();
}
if (listen(sd, 10) != 0)
{
perror("Can't configure listening port");
abort();
}
listen(sd, SOMAXCONN);
return sd;
}
SSL_CTX* InitServerCTX(void)
{
const SSL_METHOD* method = TLS_client_method(); /* Create new client-method instance */
SSL_CTX* ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
ctx = SSL_CTX_new(method); /* create new context from method */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
//New lines
if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
//End new lines
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* 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();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
//New lines - Force the client-side have a certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_verify_depth(ctx, 4);
//End new lines
}
void ShowCerts(SSL* ssl)
{
X509* cert;
char* line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{
char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho = "<html><body><pre>%s</pre></body></html>\n\n";
if (SSL_accept(ssl) == FAIL) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if (bytes > 0)
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
// sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
closesocket(sd); /* close connection */
}
int main()
{
SSL_CTX* ctx;
int server;
char portnum[] = "54000";
char CertFile[] = "C:/Users/cert/Documents/testing/ec_crt.pem";
char KeyFile[] = "C:/Users/cert/Documents/testing/private-key.pem";
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, CertFile, KeyFile); /* load certs */
printf("Certificate loaded");
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL* ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
//printf("Connection: %s:%d\n", inet_ntop(addr.sin_addr), ntohs(addr.sin_port));
printf("Connected");
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
closesocket(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Maybe you need to use:
const SSL_METHOD* method = TLS_server_method();
in InitServerCtx()?
I'm new to c++ and need help.
I use an UDP server to receive structure however i have problem to read it , the client send a structure I call : ChannAccessReq so the structure is send and the server receive it with RECVFROM and I use a general structure by reading the header (H1) of the struct only and then i do a read when a condition is fullfill with a more precise structure (temp2) for the buffer. However the client need to send the message twice , the first time it goes until recvfrom and the second it reach read() (i think) I tried all the day and wonder if its the size of the buffer ?
I think the most sensitive part is in the server with the recvfrom() who have a struct different from the read() just after..
I hope it's clear!
here is the server :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "struct.h"
#include <iostream>
void DieWithError(char *err) {
perror(err);
exit(1);
}
typedef struct IntMsgHeaderType {
uint8_t code ; // Code message7
uint8_t bourrage ; // Octet de bourrage
uint16_t ParamLength; // Longueur eventuel données complémentaires
} HeaderInt;
typedef struct TextMessage //TESTTESTTEST
{
HeaderInt H; // Code message7
};
int main(int argc, char *argv[])
{
int sock; /* Socket */
struct sockaddr_in echoServAddr; /* Local address */
struct sockaddr_in echoClntAddr; /* Client address */
unsigned int cliAddrLen; /* Length of incoming message */
unsigned short echoServPort; /* Server port */
int recvMsgSize; /* Size of received message */
struct TextMessage * temp = (TextMessage *)malloc(sizeof(struct TextMessage));
HeaderInt *H1 =(HeaderInt *)malloc(104+sizeof(HeaderInt));
ChanAccesReq *temp2=(ChanAccesReq *)malloc(sizeof(ChanAccesReq));
if (!argv[1]) {
fprintf(stderr,"no port number provided");
exit(1);
}
echoServPort = atoi(argv[1]); /* First arg: local port */
/* Create socket for sending/receiving datagrams */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* Construct local address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
echoServAddr.sin_port = htons(echoServPort); /* Local port */
/* Bind to the local address */
if (bind(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
DieWithError("bind() failed");
for (;;) /* Run forever */
{
cliAddrLen = sizeof(echoClntAddr);
int nbrOctet;
if (recvfrom(sock, H1, sizeof(*H1), 0,(struct sockaddr *) &echoClntAddr, &cliAddrLen)>0 && H1->code==1){
//read(sock,H1,sizeof(*H1));
std::cout<<"taille nbrOctet : "<<nbrOctet<<'\n';
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
read(sock, temp2, sizeof(*temp2));
//read(sock,temp2,sizeof(*temp2))>0;
std::cout<<unsigned(temp2->P.linkAddr)<<'\n';
};
}
close(sock);
return 0;
}
and here the client
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "struct.h"
void DieWithError(char *err) {
perror(err);
exit(1);
}
typedef struct {
char transMode ;
uint8_t linkAddr;
} ChanAccessReqParam;
typedef struct {
HeaderInt H;
ChanAccessReqParam P;
} ChanAccesReq ;
int main(int argc, char *argv[])
{
int sock; /* Socket descriptor */
struct sockaddr_in echoServAddr; /* Echo server address */
struct sockaddr_in fromAddr; /* Source address of echo */
unsigned short echoServPort; /* Echo server port */
unsigned int fromSize; /* In-out of address size for recvfrom() */
char *servIP; /* IP address of server */
int structLen; /* Length of string to echo */
int respStringLen; /* Length of received response */
if (!argv[1]) {
fprintf(stderr,"No server IP sepcified at arg 1\n");
exit(1);
}
else if (!argv[2]) {
fprintf(stderr,"No port Number Sepcified at arg 2\n");
exit(2);
}
ChanAccesReq test { 1 ,1,0,'c',15};
servIP = argv[1]; /* First arg: server IP address (dotted quad) */
echoServPort = atoi(argv[2]); /* Use given port, if any */
/* Create a datagram/UDP socket */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet addr family */
echoServAddr.sin_addr.s_addr = inet_addr(servIP); /* Server IP address */
echoServAddr.sin_port = htons(echoServPort); /* Server port */
int tempint = 0;
tempint = sendto(sock, (ChanAccesInd*)&test, 10+(sizeof(test)), 0, (struct sockaddr *)
&echoServAddr, sizeof(echoServAddr));
if (tempint == -1 ) {
printf("Sent struct size: %d\n", tempint);
DieWithError("sendto() sent a different number of bytes than expected\n");
}
close(sock);
exit(0);
}
Thank you for your help
In C++ you have to define the type of the parameters.
As I deduced from the calling place, it should be int and bool.
int GesCanSlotSendTimeInd( int subscIPAddr , bool TransModeFlash){
return 0;
}
Also it is possible to use const qualifier, but you also need the type.
int GesCanSlotSendTimeInd( const int& subscIPAddr , const bool& TransModeFlash){
return 0;
}
For further info please look at cpp reference
You need to use non-blocking mode to poll for recvfrom and sendto at the same time. See here for more details.
int main(int argc, const char** argv) {
setvbuf(stdout, NULL, _IONBF, 0);
int portnum = 9988;
if (argc >= 2) {
portnum = atoi(argv[1]);
}
printf("Listening on port %d\n", portnum);
int sockfd = listen_inet_socket(portnum);
struct sockaddr_in peer_addr;
socklen_t peer_addr_len = sizeof(peer_addr);
int newsockfd = accept(sockfd, (struct sockaddr*)&peer_addr, &peer_addr_len);
if (newsockfd < 0) {
perror_die("ERROR on accept");
}
report_peer_connected(&peer_addr, peer_addr_len);
// Set nonblocking mode on the socket.
int flags = fcntl(newsockfd, F_GETFL, 0);
if (flags == -1) {
perror_die("fcntl F_GETFL");
}
if (fcntl(newsockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
perror_die("fcntl F_SETFL O_NONBLOCK");
}
while (1) {
uint8_t buf[1024];
printf("Calling recv...\n");
int len = recv(newsockfd, buf, sizeof buf, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
usleep(200 * 1000);
continue;
}
perror_die("recv");
} else if (len == 0) {
printf("Peer disconnected; I'm done.\n");
break;
}
printf("recv returned %d bytes\n", len);
}
close(newsockfd);
close(sockfd);
return 0;
}
"A couple of notable differences from the blocking version:
The newsockfd socket returned by accept is set to nonblocking mode by calling fcntl.
When examining the return status of recv, we check whether errno is set to a value saying that no data is available for receiving. In this case we just sleep for 200 milliseconds and continue to the next iteration of the loop."
You can still send() and recvfrom() on the same socket since that you dont really need 2 differents process if that's what you need
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I downloaded a C++ program from Github which does Bandwidth estimation using Pair to pair algorithm. I've compiled and installed the program on my system but when I initialize the Bind() function to bind to port 53 for e.g, it says either Bind() failed, or an infinite "Waiting for Client". I'm not very experienced with socket programming and using BIND. Are there some rules in play?
Here is the program source if needed:
https://github.com/npbendre/Bandwidth-Estimation-using-Packet-Pair-Probing-Algorithm
/********************************************************
* Program: Bandwidth Estimation *
* *
* Summary: *
* This file contains the server code *
* *
*********************************************************/
#include "defs.h"
int quit = 0; /* CNT-C exit flag */
#define RESET 0
#define HEX 16
#define MSZ_BEGIN 5
#define SEQ_BEGIN 5
#define BSZ_BEGIN 9
#define MAX_WAIT 30
#define HEADER_SIZE 28
#define TO_Mbits(x) (x*8/1048576)
struct Client {
int cmd;
char sessionID[ID_LEN+1];
unsigned int msgSize;
unsigned int seq;
unsigned int burstSize;
unsigned int burstCnt;
unsigned int numRecv;
double bandwidth;
};
/* SIGINT handler */
void CNT_C_Code()
{
printf("CNT-C Interrupt, exiting...\n");
quit = 1;
}
/* SIGALRM handler */
void alarmHandler() { }
int main(int argc, char *argv[])
{
int sock; /* Socket */
struct sockaddr_in serverAddr; /* Local address */
struct sockaddr_in clientAddr; /* Client address */
struct sockaddr_in dupClAddr; /* Temporary address */
unsigned int addrLen; /* Client address length */
unsigned int serverPort; /* Local port */
struct sigaction sa_int; /* For SIGINT */
struct sigaction sa_alrm; /* For SIGALRM */
int cmd = RESET; /* Server commands */
char buffer[MIN_MSG_LEN]; /* Receive buffer */
char results[RESULT_LEN]; /* Results buffer */
char *msg = NULL; /* Client message */
struct Client cl; /* Current client */
int recvlen; /* Received message length */
int seq; /* Sequence number */
struct timespec ts1; /* time structure */
struct timespec ts2; /* time structure */
struct timespec *ts = NULL; /* Switch pointer */
int swtch = 0; /* Switch flag for timespecs */
int cnt = 0;
char temp[ID_LEN+1];
/* Invalid invocation of the program */
if (argc != 2) {
printf("Syntax: %s <port number>\n", argv[0]);
exit(1);
}
serverPort = atoi(argv[1]);
/* create datagram socket */
if ((sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
DieWithError("socket() failed");
/* build local address struct */
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(serverPort);
/* bind to local address */
printf("Server: binding to port %d\n", serverPort);
if (bind(sock, (struct sockaddr *) &serverAddr, sizeof(serverAddr)) < 0) {
close(sock);
DieWithError("bind() failed");
}
/* assign handler and initialize set to all signals */
sa_int.sa_handler = CNT_C_Code;
sa_alrm.sa_handler = alarmHandler;
if (sigfillset(&sa_int.sa_mask) < 0 || sigfillset(&sa_alrm.sa_mask) < 0) {
close(sock);
DieWithError("sigfillset() failed");
}
/* set the handler */
sa_int.sa_flags = sa_alrm.sa_flags = 0;
if (sigaction(SIGINT, &sa_int, 0) < 0 || sigaction(SIGALRM, &sa_alrm, 0) < 0) {
close(sock);
DieWithError("sigaction() failed");
}
addrLen = sizeof(struct sockaddr_in);
/* Run until CNT-C */
for ( ; !quit; ) {
if (cmd == RESET) {
/* reset session id */
memset(&cl, 0, sizeof(cl));
errno = swtch = cnt = 0;
ts = &ts1;
printf("Waiting for Client...\n");
/* get the first message from client */
recvfrom(sock, buffer, MIN_MSG_LEN, 0, (struct sockaddr *) &clientAddr, &addrLen);
if (errno == EINTR) continue;
memcpy(&dupClAddr, &clientAddr, addrLen);
cl.cmd = buffer[0]-'0'; /* get the client command */
}
/* Received START_MSG, send START_ACK */
if (cl.cmd == START_MSG) {
getFromMsg(cl.sessionID, buffer, SID_BEGIN, ID_LEN); /* retrieve session ID */
getFromMsg(temp, buffer, MSZ_BEGIN, ID_LEN); /* retrieve message size */
cl.msgSize = strtol(temp, NULL, HEX);
getFromMsg(temp, buffer, BSZ_BEGIN, ID_LEN); /* retrieve burst size */
cl.burstSize = strtol(temp, NULL, HEX);
if (!msg) msg = (char *) calloc(cl.msgSize+1, sizeof(char));
printf("\n");
printf("Serving client with session ID: %s\n", cl.sessionID);
/* set sending buffer to START_ACK */
cmd = START_ACK;
*msg = cmd + '0';
strcpy(msg+SID_BEGIN, cl.sessionID);
/* send START_ACK to client */
printf("=== Received START_MSG, sending START_ACK...\n");
sendto(sock, msg, strlen(msg)+1, 0, (struct sockaddr *) &clientAddr, addrLen);
}
if (cmd == START_ACK) {
int once = 1;
/* accept client bursts */
for ( ; ; ) {
alarm(MAX_WAIT); /* wait till client sends next message, used when client crashes */
recvlen = recvfrom(sock, msg, cl.msgSize+1, 0, (struct sockaddr*) &dupClAddr, &addrLen);
clock_gettime(CLOCK_REALTIME, ts); /* get time */
if (errno == EINTR) {
if (!quit) {
free(msg);
msg = NULL;
cl.cmd = cmd = RESET;
printf("Server Timeout: Resetting...\n\n");
}
break;
}
alarm(0);
if (recvlen != cl.msgSize+1) /* damaged packet */
continue;
/* wrong client */
if (memcmp(&dupClAddr, &clientAddr, addrLen) || strncmp(cl.sessionID, msg+SID_BEGIN, ID_LEN))
break;
if ((cl.cmd = *msg-'0') == START_MSG) /* client did not receive START_ACK */
break;
if (cl.cmd == DONE) { /* Client done bursting */
cmd = RESULTS_MSG;
break;
}
++cl.numRecv;
ts = ((swtch = 1-swtch)) ? &ts2 : &ts1; /* switch time pointer */
getFromMsg(temp, msg, SEQ_BEGIN, ID_LEN); /* get sequence number */
seq = strtol(temp, NULL, HEX);
/* change in sequence */
if (seq != cl.seq) {
once = 1;
cl.seq = seq;
ts = &ts1;
swtch = 0;
++cl.burstCnt;
printf("=== Receiving from burst #%d...\n", cl.seq);
}
else {
/* get time interval only if its from the same burst sequence */
if (once) {
once = 0;
continue;
}
/* calculate average bandwidth */
cl.bandwidth *= cnt++;
cl.bandwidth += ((double) cl.msgSize+1+HEADER_SIZE) /
((swtch) ? getTimeDiff(ts1, ts2) : getTimeDiff(ts2, ts1));
cl.bandwidth /= (double) cnt;
}
/* not retrieving data from message */
}
}
if (cmd == RESULTS_MSG) {
float totExpected = cl.burstSize * cl.burstCnt;
/* create results */
results[0] = cmd + '0';
sprintf(results+SID_BEGIN, "%s:%f:%.2f:%u:%u", cl.sessionID, TO_Mbits(cl.bandwidth),
((totExpected-cl.numRecv)/totExpected)*100, cl.numRecv, cl.burstCnt);
printf("\n");
printf("=== Received DONE, sending RESULTS_MSG...\n");
sendto(sock, results, RESULT_LEN, 0, (struct sockaddr *) &dupClAddr, addrLen);
alarm(MAX_WAIT);
recvfrom(sock, msg, cl.msgSize+1, 0, (struct sockaddr *) &dupClAddr, &addrLen);
if (errno == EINTR) {
if (!quit) {
free(msg);
msg = NULL;
cmd = RESET;
printf("Server Timeout: Resetting...\n\n");
}
continue;
}
alarm(0);
/* wrong client */
if (memcmp(&dupClAddr, &clientAddr, addrLen) || strncmp(cl.sessionID, msg+SID_BEGIN, ID_LEN))
continue;
if (*msg-'0' == DONE) /* client did not receive RESULTS_MSG */
continue;
if (*msg-'0' == DONE_ACK) { /* received DONE_ACK from client */
printf("=== Received DONE_ACK.\n\n");
free(msg);
msg = NULL;
cmd = RESET;
}
}
}
if (msg) free(msg);
close(sock);
return 0;
}
Try port number greater than 1024 - maybe OS is blocking binding on lower number ports for non-privileged applications.
Based on the examples at http://simplestcodings.blogspot.com/2010/08/secure-server-client-using-openssl-in-c.html I have written the following epoll server code to replace the regular tcp sockets with SSL. My code is slightly modified to do mutual authentication and verify the certs since I add
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);.
My OS is Ubuntu 12.04.
I have also generated server cert, client cert, server key, client key, and of course cacert.pem files from the IBM tutorial http://pic.dhe.ibm.com/infocenter/lnxinfo/v3r0m0/index.jsp?topic=%2Fliaat%2Fliaatseccreatecskeycert.htm
I ran the single server - single client code and it runs perfectly fine. Inspired by this I wanted to see how the epoll server code would behave but then I ran into issues. Here is the code for the server
Code that does not work
//(c) 2014 enthusiasticgeek for stackoverflow - epollserver.cc
//============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include <iostream>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
#define MAXEVENTS 64
SSL_CTX* InitServerCTX(void)
{ const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv23_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* 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();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
static int
AibSocketNonBlocking (int sfd)
{
int flags, s;
flags = fcntl (sfd, F_GETFL, 0);
if (flags == -1)
{
perror ("fcntl");
return -1;
}
flags |= O_NONBLOCK;
s = fcntl (sfd, F_SETFL, flags);
if (s == -1)
{
perror ("fcntl");
return -1;
}
return 0;
}
static int
AibCreateAndBind (char *port)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int s, sfd;
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
hints.ai_flags = AI_PASSIVE; /* All interfaces */
s = getaddrinfo (NULL, port, &hints, &result);
if (s != 0)
{
fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
return -1;
}
for (rp = result; rp != NULL; rp = rp->ai_next)
{
sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
if (s == 0)
{
/* We managed to bind successfully! */
break;
}
close (sfd);
}
if (rp == NULL)
{
fprintf (stderr, "Could not bind\n");
return -1;
}
freeaddrinfo (result);
return sfd;
}
int
main (int argc, char *argv[])
{
SSL_CTX *ctx;
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/test/ssl/cert_files/servercert.pem", "/home/test/ssl/cert_files/serverkey.pem"); /* load certs */
int sfd, s;
int efd;
struct epoll_event aibevent;
struct epoll_event *aibevents;
if (argc != 2) {
fprintf (stderr, "Usage: %s [port]\n", argv[0]);
exit (EXIT_FAILURE);
}
char portt[sizeof (unsigned int)];
snprintf(portt,sizeof portt + 1,"%u",atoi(argv[1]));
printf("sizeof %s argv[1] = %d\n",argv[1], sizeof(argv[1]));
printf("sizeof %s portt = %d\n",portt, sizeof(portt));
sfd = AibCreateAndBind (portt);//argv[1]);
if (sfd == -1) {
abort ();
}
s = AibSocketNonBlocking (sfd);
if (s == -1) {
abort ();
}
s = listen (sfd, SOMAXCONN);
if (s == -1) {
perror ("listen");
abort ();
}
efd = epoll_create1 (0);
if (efd == -1) {
perror ("epoll_create");
abort ();
}
aibevent.data.fd = sfd;
aibevent.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &aibevent);
if (s == -1) {
perror ("epoll_ctl");
abort ();
}
// Buffer where events are returned
//events = static_cast<epoll_event*>(calloc (MAXEVENTS, sizeof event));
//aibevents = static_cast<epoll_event*>(malloc (MAXEVENTS * sizeof aibevent));
aibevents = new epoll_event[MAXEVENTS * sizeof aibevent];
// The event loop
while (true)
{
int n, i;
n = epoll_wait (efd, aibevents, MAXEVENTS, -1);
for (i = 0; i < n; i++)
{
if ((aibevents[i].events & EPOLLERR) ||
(aibevents[i].events & EPOLLHUP) ||
(!(aibevents[i].events & EPOLLIN)))
{
// An error has occured on this fd, or the socket is not
// ready for reading (why were we notified then?)
fprintf (stderr, "epoll error\n");
close (aibevents[i].data.fd);
continue;
} else if (sfd == aibevents[i].data.fd) {
// We have a notification on the listening socket, which
// means one or more incoming connections.
while (1)
{
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
in_len = sizeof in_addr;
infd = accept (sfd, &in_addr, &in_len);
if (infd == -1)
{
if ((errno == EAGAIN) ||(errno == EWOULDBLOCK)) {
// We have processed all incoming
// connections.
break;
} else {
perror ("accept");
break;
}
}
s = getnameinfo (&in_addr, in_len,
hbuf, sizeof hbuf,
sbuf, sizeof sbuf,
NI_NUMERICHOST | NI_NUMERICSERV);
if (s == 0) {
printf("Accepted connection on descriptor %d "
"(host=%s, port=%s)\n", infd, hbuf, sbuf);
}
// Make the incoming socket non-blocking and add it to the
// list of fds to monitor.
s = AibSocketNonBlocking (infd);
if (s == -1) {
abort ();
}
aibevent.data.fd = infd;
aibevent.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &aibevent);
if (s == -1) {
perror ("epoll_ctl");
abort ();
}
}
continue;
} else {
// We have data on the fd waiting to be read. Read and
// display it. We must read whatever data is available
// completely, as we are running in edge-triggered mode
// and won't get a notification again for the same
// data.
int done = 0;
int sd;
SSL *ssl;
while (1)
{
ssize_t count;
char buf[1024];
char reply[1024];
printf("Performing exchange.\n");
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, aibevents[i].data.fd); /* set connection socket to SSL state */
printf("Performing exchange 1.\n");
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) { /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
printf("Performing exchange Error 1.\n");
done = 1;
break;
} else {
ShowCerts(ssl); /* get any certificates */
count = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( count > 0 )
{
buf[count] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
} else {
ERR_print_errors_fp(stderr);
printf("Performing exchange Error 2.\n");
done = 1;
break;
}
}
sd = SSL_get_fd(ssl); /* get socket connection */
/*
count = read (aibevents[i].data.fd, buf, sizeof buf);
if (count == -1)
{
// If errno == EAGAIN, that means we have read all
// data. So go back to the main loop.
if (errno != EAGAIN)
{
perror ("read");
done = 1;
}
break;
}
else if (count == 0)
{
// End of file. The remote has closed the
// connection.
done = 1;
break;
}
// Write the buffer to standard output
s = write (1, buf, count);
if (s == -1)
{
perror ("write");
abort ();
}
printf(" read correctly (n > 0) n==%d\n",s);
printf("msg: %s\n", buf);
write(aibevents[i].data.fd, buf,s);
memset(buf,'\0', s);
*/
}
if (done)
{
printf("Freeing data.\n");
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
//printf ("Closed connection on descriptor %d\n",
// aibevents[i].data.fd);
// Closing the descriptor will make epoll remove it
// from the set of descriptors which are monitored.
//close (aibevents[i].data.fd);
}
}
}
}
//free (aibevents);
delete[] aibevents;
close (sfd);
SSL_CTX_free(ctx); /* release context */
return EXIT_SUCCESS;
}
The single server- single client code are listed below for reference. Note that I am using the same client code to interact with the epoll server.
Single server code. Works
//SSL-Single Server code that works ! used as a reference for epoll server
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void)
{ const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv23_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* 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();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/test/ssl/cert_files/servercert.pem", "/home/test/ssl/cert_files/serverkey.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Single client code Works
// Single Client Code that works!
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* 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();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
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 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ 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 = SSLv23_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)
{ 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("No certificates.\n");
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
if ( count != 3 )
{
printf("Usage: %s <host/ip> <portnum>\n", strings[0]);
exit(0);
}
char* hostname=strings[1];//"127.0.0.1";
char* portnum=strings[2];//"3334";
char CertFile[] = "/home/test/ssl/cert_files/clientcert.pem";
char KeyFile[] = "/home/test/ssl/cert_files/clientkey.pem";
SSL_library_init();
ctx = InitCTX();
LoadCertificates(ctx, CertFile, KeyFile);
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ char *msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
I did compilation using
g++ -g <src>.cc -o <src> -lssl -lcrypto for each of the three files (I had a Makefile)
The error that see is
./tcpserver_epoll 3334
sizeof 3334 argv[1] = 4
sizeof 3334 portt = 4
Accepted connection on descriptor 5 (host=127.0.0.1, port=44716)
Performing exchange.
Performing exchange 1.
Performing exchange Error 1.
Freeing data.
Performing exchange.
Performing exchange 1.
3072792824:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:s23_srvr.c:628:
Performing exchange Error 1.
Freeing data.
I am wondering if I have to create multiple instances of SSL_CTX *ctx;. I am a bit lost. Any help is appreciated. Thanks.
Update: Thanks to everyone for guidance. I found an example here that closely matches what I want
http://bendecplusplus.googlecode.com/svn/trunk/ssl_mycode/epoll_ssl/server.c
http://bendecplusplus.googlecode.com/svn/trunk/ssl_mycode/epoll_ssl/client.c
Your code is very hard to read (how about proper indentation?) but I think the main problem is, that you consider a return of -1 from SSL_accept to be a fatal error.
According to the man page (which is true in this case) -1 can happen on fatal error or "It can also occur of action is need to continue the operation for non-blocking BIOs. Call SSL_get_error() with the return value ret to find out the reason.". So you have to check the error and if its SSL_ERROR_WANT_READ you have to wait the socket is readable and on SSL_ERROR_WANT_WRITE until its writable.
I am wondering if I have to create multiple instances of SSL_CTX *ctx;
No, you can use a single SSL_CTX*.
The SSL_CTX* is reference counted. It will be destroyed after the last SSL_free.
Since you are using a common SSL_CTX*, you should tune each SSL session with the non-context API calls. For example, SSL_set_cipher_list rather than SSL_CTX_set_cipher_list or SSL_use_certificate rather than SSL_CTX_use_certificate (unless, of course, its common).
First of all, I'd like to point out that i'm not a good programmer, so please be patient with me. The logic in the program is as follows: the client sends the server a text file, the server saves it under a different name. In short, very similar to this topic:
" File transfer server/client using socket " except that I'm using a different protocol. I think I've managed to succesfully send the file, but it seems like the server, afters creating a blank file, stucks in a loop/doesn't write anything in it.
Here's the code for the client:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h> /* memset() */
#include <sys/time.h> /* select() */
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#define REMOTE_SERVER_PORT 1500
#define MAX_MSG 100
#define PLIK "/home/aatami/Documents/programowanie/serwer/plik.txt"
#define LENGTH 512
int main(int argc, char *argv[]) {
int sd, rc, i,fd;
unsigned int cliLen;
struct sockaddr_in cliAddr, remoteServAddr;
struct hostent *h;
char buf[LENGTH];
/* check command line args */
if(argc<3) {
printf("usage : %s <server> <data1> ... <dataN> \n", argv[0]);
exit(1);
}
/* get server IP address (no check if input is IP address or DNS name */
h = gethostbyname(argv[1]);
if(h==NULL) {
printf("%s: unknown host '%s' \n", argv[0], argv[1]);
exit(1);
}
printf("%s: sending data to '%s' (IP : %s) \n", argv[0], h->h_name,
inet_ntoa(*(struct in_addr *)h->h_addr_list[0]));
remoteServAddr.sin_family = h->h_addrtype;
memcpy((char *) &remoteServAddr.sin_addr.s_addr,
h->h_addr_list[0], h->h_length);
remoteServAddr.sin_port = htons(REMOTE_SERVER_PORT);
/* socket creation */
sd = socket(AF_INET,SOCK_DGRAM,0); /* port 0 - system gets the first free one */
if(sd<0) {
printf("%s: cannot open socket \n",argv[0]);
exit(1);
}
/* bind any port */
cliAddr.sin_family = AF_INET;
cliAddr.sin_addr.s_addr = htonl(INADDR_ANY);
cliAddr.sin_port = htons(0);
rc = bind(sd, (struct sockaddr *) &cliAddr, sizeof(cliAddr));
if(rc<0) {
printf("%s: cannot bind port\n", argv[0]);
exit(1);
}
/* send data */
for(i=2;i<argc;i++) {
rc = sendto(sd, argv[i], strlen(argv[i])+1, 0,
(struct sockaddr *) &remoteServAddr,
sizeof(remoteServAddr));
if(rc<0) {
printf("%s: cannot send data %d \n",argv[0],i-1);
close(sd);
exit(1);
}
/* send text file */
char sdbuf[LENGTH];
printf("[Client] Sending %s to the Server... ", PLIK);
FILE *fs = fopen(PLIK, "r");
if(fs == NULL)
{
printf("ERROR: File %s not found.\n", PLIK);
exit(1);
}
bzero(sdbuf, LENGTH);
int fs_block_sz;
while((fs_block_sz = fread(sdbuf, sizeof(char), LENGTH, fs)) > 0)
{
if(send(sd, sdbuf, fs_block_sz, 0) < 0)
{
fprintf(stderr, "ERROR: Failed to send file %s. (errno = %d)\n", PLIK, errno);
break;
}
bzero(sdbuf, LENGTH);
}
printf("Ok File %s from Client was Sent!\n", PLIK);
}
return 1;
}
And the code for the server:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> /* close() */
#include <string.h> /* memset() */
#include <errno.h>
#define LENGTH 512
#define LOCAL_SERVER_PORT 1500
#define MAX_MSG 100
#define PLIKSERV "/home/aatami/Documents/programowanie/serwer/plikserv.txt"
int main(int argc, char *argv[]) { /* licznik argumentow, tablica argumentow */
int sd, rc,nsockfd;
unsigned int n,cliLen;
struct sockaddr_in cliAddr, servAddr;
char msg[MAX_MSG];
char buf[512],sbuf[LENGTH];
/* socket creation */
sd=socket(AF_INET, SOCK_DGRAM, 0);
if(sd<0) {
printf("%s: cannot open socket \n",argv[0]);
exit(1);
}
/* bind local server port */
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(LOCAL_SERVER_PORT);
rc = bind (sd, (struct sockaddr *) &servAddr,sizeof(servAddr));
if(rc<0) {
printf("%s: cannot bind port number %d \n",
argv[0], LOCAL_SERVER_PORT);
exit(1);
}
printf("%s: waiting for data on port UDP %u\n",
argv[0],LOCAL_SERVER_PORT);
/* server infinite loop */
while(1) {
/* init buffer */
memset(msg,0x0,MAX_MSG);
/* receive message */
cliLen = sizeof(cliAddr);
n = recvfrom(sd, msg, MAX_MSG, 0,
(struct sockaddr *) &cliAddr, &cliLen);
if(n<0) {
printf("%s: cannot receive data \n",argv[0]);
continue;
}
/* print received message */
printf("%s: from %s:UDP%u : %s \n",
argv[0],inet_ntoa(cliAddr.sin_addr),
ntohs(cliAddr.sin_port),msg);
unsigned int sin_size = sizeof(struct sockaddr_in);
FILE *fr = fopen(PLIKSERV, "a");
if(fr == NULL)
printf("File %s Cannot be opened file on server.\n", PLIKSERV);
else
{
bzero(sbuf, LENGTH);
int fr_block_sz = 0;
while((fr_block_sz = recvfrom(sd, buf, LENGTH, 0,(struct sockaddr *) &cliAddr, &cliLen)) > 0)
{
int write_sz = fwrite(buf, sizeof(char), fr_block_sz, fr);
if(write_sz < fr_block_sz)
{
perror("File write failed on server.\n");
}
bzero(buf, LENGTH);
if (fr_block_sz == 0 || fr_block_sz != 512)
{
break;
}
}
if(fr_block_sz < 0)
{
if (errno == EAGAIN)
{
printf("recv() timed out.\n");
}
else
{
fprintf(stderr, "recv() failed due to errno = %d\n", errno);
exit(1);
}
}
printf("Ok received from client!\n");
fclose(fr);
}
}/* end of server infinite loop */
return 0;
}
Any help greatly appreciated!
After seen your code I'd suggest try to send a "Hello world\n" from client to the server, see if you get it there. Once you make the connection between client and server then try to expand the code to do a file transfer.
But keep this in mind about UDP:
"UDP uses a simple transmission model with a minimum of protocol mechanism. It has no handshaking dialogues, and thus exposes any unreliability of the underlying network protocol to the user's program. As this is normally IP over unreliable media, there is no guarantee of delivery, ordering or duplicate protection. If error correction facilities are needed at the network interface level, an application may use the Transmission Control Protocol (TCP) which is designed for this purpose."
As you start the client, it sends all packets as fast as possible, could it be that the packets get lost or disordered or even duplicates at the server site. I also suggest waiting for a packet to acknowledge the correct reception. I mean, when then server receives a packet it sends a packet to acknowledge it to the client. This way, a conversation (dialog) could be held and the transfer accomplished satisfactory.