The TCP Echo Server sample from the Azure Sphere Samples at github works great and I am able to use my PC or a raspberryPi as a TCP client and communicate to the TCP echo server at the sphere device. However, I have a requirement where I need my Azure Sphere device as a TCP client. I modified the private network services sample application to work as a client (commented out Echo TCP Server) but the connection to the TCP server running at PC fails. The 'connect' returns -1 with errno set to 115 (ERROR: Operation in progress). I have configured the network services at azure sphere device with static ip. I have also verified that the same TCP client and server application works fine when a raspberrypi is used as a client and PC as the server. This is the modified main file of the application:
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "applibs_versions.h"
#include <applibs/log.h>
#include <applibs/networking.h>
#include <hw/sample_hardware.h>
typedef enum {
ExitCode_Success = 0,
ExitCode_TermHandler_SigTerm = 1,
ExitCode_StoppedHandler_Stopped = 2,
ExitCode_CheckStatus_SetInterfaceState = 3,
ExitCode_CheckStatus_GetInterfaceCount = 4,
ExitCode_CheckStatus_GetInterfaceConnectionStatus = 5,
ExitCode_ConfigureStaticIp_IpConfigApply = 6,
ExitCode_StartSntpServer_StartSntp = 7,
ExitCode_StartDhcpServer_StartDhcp = 8,
ExitCode_TimerHandler_Consume = 9,
ExitCode_InitLaunch_Epoll = 10,
ExitCode_InitLaunch_Timer = 11,
ExitCode_Main_WaitCallFailure = 12,
ExitCode_EchoStart_Listen = 13,
ExitCode_OpenIpV4_Socket = 14,
ExitCode_OpenIpV4_SetSockOpt = 15,
ExitCode_OpenIpV4_Bind = 16
} ExitCode;
int tcp_client(void);
static bool isNetworkStackReady = false;
static volatile sig_atomic_t exitCode = ExitCode_Success;
static struct in_addr localServerIpAddress;
static struct in_addr subnetMask;
static struct in_addr gatewayIpAddress;
static const uint16_t LocalTcpServerPort = 11000;
static int serverBacklogSize = 3;
static const char NetworkInterface[] = "eth0";
int tcp_client(void) {
int sock = 0, valread;
struct sockaddr_in serv_addr;
char* hello = "Hello from client";
char buffer[1024] = { 0 };
if ((sock = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0)) < 0)
{
Log_Debug("\n Socket creation error \n");
return -1;
}
Log_Debug("TCP_CLIENT: socket created\n");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
if (inet_pton(AF_INET, "169.254.57.67", &serv_addr.sin_addr) <= 0)
{
Log_Debug("\nInvalid address/ Address not supported \n");
return -1;
}
Log_Debug("TCP_CLIENT: ip assigned\n");
int conn = connect(sock, (struct sockaddr*) & serv_addr, sizeof(serv_addr));
Log_Debug("TCP_CLIENT: conn = %d\n", conn);
Log_Debug("ERROR: %s\n", strerror(errno));
if (conn < 0)
{
Log_Debug("\nConnection Failed \n");
return -1;
}
send(sock, hello, strlen(hello), 0);
Log_Debug("Hello message sent\n");
valread = read(sock, buffer, 1024);
Log_Debug("%s\n", buffer);
return 0;
}
static ExitCode CheckNetworkStatus(void)
{
int result = Networking_SetInterfaceState(NetworkInterface, true);
if (result != 0) {
if (errno == EAGAIN) {
Log_Debug("INFO: The networking stack isn't ready yet, will try again later.\n");
return ExitCode_Success;
} else {
Log_Debug(
"ERROR: Networking_SetInterfaceState for interface '%s' failed: errno=%d (%s)\n",
NetworkInterface, errno, strerror(errno));
return ExitCode_CheckStatus_SetInterfaceState;
}
}
Log_Debug("INFO: CheckNetworkStatus: Network stack is ready\n");
isNetworkStackReady = true;
ssize_t count = Networking_GetInterfaceCount();
if (count == -1) {
Log_Debug("ERROR: Networking_GetInterfaceCount: errno=%d (%s)\n", errno, strerror(errno));
return ExitCode_CheckStatus_GetInterfaceCount;
}
Log_Debug("INFO:CheckNetworkStatus: Networking_GetInterfaceCount: count=%zd\n", count);
// Read current status of all interfaces.
size_t bytesRequired = ((size_t)count) * sizeof(Networking_NetworkInterface);
Networking_NetworkInterface *interfaces = malloc(bytesRequired);
if (!interfaces) {
abort();
}
ssize_t actualCount = Networking_GetInterfaces(interfaces, (size_t)count);
if (actualCount == -1) {
Log_Debug("ERROR: Networking_GetInterfaces: errno=%d (%s)\n", errno, strerror(errno));
}
Log_Debug("INFO: Networking_GetInterfaces: actualCount=%zd\n", actualCount);
for (ssize_t i = 0; i < actualCount; ++i) {
Log_Debug("INFO: interface #%zd\n", i);
Log_Debug("INFO: interfaceName=\"%s\"\n", interfaces[i].interfaceName);
Log_Debug("INFO: isEnabled=\"%d\"\n", interfaces[i].isEnabled);
Networking_IpType ipType = interfaces[i].ipConfigurationType;
const char *typeText;
switch (ipType) {
case Networking_IpType_DhcpNone:
typeText = "DhcpNone";
break;
case Networking_IpType_DhcpClient:
typeText = "DhcpClient";
break;
default:
typeText = "unknown-configuration-type";
break;
}
Log_Debug("INFO: ipConfigurationType=%d (%s)\n", ipType, typeText);
Networking_InterfaceMedium_Type mediumType = interfaces[i].interfaceMediumType;
const char *mediumText;
switch (mediumType) {
case Networking_InterfaceMedium_Unspecified:
mediumText = "unspecified";
break;
case Networking_InterfaceMedium_Wifi:
mediumText = "Wi-Fi";
break;
case Networking_InterfaceMedium_Ethernet:
mediumText = "Ethernet";
break;
default:
mediumText = "unknown-medium";
break;
}
Log_Debug("INFO: interfaceMediumType=%d (%s)\n", mediumType, mediumText);
Networking_InterfaceConnectionStatus status;
int result = Networking_GetInterfaceConnectionStatus(interfaces[i].interfaceName, &status);
if (result != 0) {
Log_Debug("ERROR: Networking_GetInterfaceConnectionStatus: errno=%d (%s)\n", errno,
strerror(errno));
return ExitCode_CheckStatus_GetInterfaceConnectionStatus;
}
Log_Debug("INFO: interfaceStatus=0x%02x\n", status);
}
free(interfaces);
return ExitCode_Success;
}
static ExitCode ConfigureNetworkInterfaceWithStaticIp(const char *interfaceName)
{
Networking_IpConfig ipConfig;
Log_Debug("INFO: ConfigureNetworkInterfaceWithStaticIp: %s.\n", interfaceName);
Networking_IpConfig_Init(&ipConfig);
inet_aton("169.254.57.70", &localServerIpAddress);
inet_aton("255.255.0.0", &subnetMask);
inet_aton("0.0.0.0", &gatewayIpAddress);
Networking_IpConfig_EnableStaticIp(&ipConfig, localServerIpAddress, subnetMask,
gatewayIpAddress);
int result = Networking_IpConfig_Apply(interfaceName, &ipConfig);
Networking_IpConfig_Destroy(&ipConfig);
if (result != 0) {
Log_Debug("ERROR: Networking_IpConfig_Apply: %d (%s)\n", errno, strerror(errno));
return ExitCode_ConfigureStaticIp_IpConfigApply;
}
Log_Debug("INFO: Set static IP address on network interface: %s.\n", interfaceName);
return ExitCode_Success;
}
static ExitCode init_nw_services(void)
{
// Check the network stack readiness and display available interfaces when it's ready.
Log_Debug("INFO: Inside init_nw_services\n");
ExitCode localExitCode = CheckNetworkStatus();
if (localExitCode != ExitCode_Success) {
return localExitCode;
}
if (isNetworkStackReady) {
Log_Debug("INFO: init_nw_services: The network stack is ready, so unregister the timer event handler and launch servers.\n");
localExitCode = ConfigureNetworkInterfaceWithStaticIp(NetworkInterface);
}
return ExitCode_Success;
}
static ExitCode initialize_nw(void)
{
while (!isNetworkStackReady) {
if (!isNetworkStackReady) {
Log_Debug("INFO: init_nw_services\n");
ExitCode localExitCode = init_nw_services();
if (localExitCode != ExitCode_Success) {
exitCode = localExitCode;
return;
}
}
else {
Log_Debug("INFO: Network stack is ready\n");
}
}
Log_Debug("INFO: Initialization and server launch complete\n");
return ExitCode_Success;
}
int main(int argc, char *argv[])
{
Log_Debug("INFO: Private Ethernet TCP server application starting.\n");
exitCode = initialize_nw();
if (isNetworkStackReady)
tcp_client();
Log_Debug("INFO: Application exiting.\n");
return exitCode;
}
Yes this is possible. Please ensure that the destination is in the app manifest under AllowedConnections
Related
Doing some research on high performance TCP server (not necessarily for HTTP) for testing purpose. Followed some sample code and created a libuv based TCP server, however the following sample code will crash with error SIGPIPE on the line uv_write(req, stream, buffer, 1, on_write);. Here is the console output:
client=0x562529924700
1writing to 0x562529924700
2writing to 0x562529924700
wrote.
1writing to 0x562529924700
Note that the tcp client closes the first tcp connection with TCP RESET. Wireshark shows that the TCP client has established the second tcp connection and sent the request, but the tcp server somehow didn't print something similar to the line client=0x562529924700 to indicate that it has accept the second connection.
Any ideas would be appreciated.
Here is the server code
//from https://gist.github.com/Jxck/4305806
// https://nikhilm.github.io/uvbook/networking.html
//api guide http://docs.libuv.org/en/v1.x/
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
#include <string.h>
#include <unistd.h>
#define DEFAULT_PORT 8080
#define DEFAULT_BACKLOG 1000
uv_loop_t *loop;
int cnt = 0;
char *str = "HTTP/1.1 200 Ok\r\nContent-Length: 7\r\n\r\n%07d\n";
void on_write(uv_write_t* req, int status)
{
if (status) {
perror( "uv_write error ");
return;
}
printf("wrote.\n");
free(req);
//uv_close((uv_handle_t*)req->handle, on_close);
}
void write2(uv_stream_t* stream, char *data, int len2) {
uv_buf_t buffer[] = {
{.base = data, .len = len2}
};
uv_write_t *req = malloc(sizeof(uv_write_t));
printf("1writing to %p\n", stream);
uv_write(req, stream, buffer, 1, on_write);
printf("2writing to %p\n", stream);
}
void on_close(uv_handle_t* handle)
{
//printf("closed.");
}
void echo_read(uv_stream_t *sock, ssize_t nread, const uv_buf_t *buf) {
if (nread == -1) {
fprintf(stderr, "error echo_read");
return;
} else if (nread == 0) {
uv_close((uv_handle_t*)sock, on_close);
return;
}
char respMsg[52];
sprintf(respMsg, str, cnt++);
//snprintf(&respMsg[41], 6,"%6d", cnt++);
write2(sock, respMsg, strlen(respMsg));
//printf("result: %s\n", buf->base);
}
static void my_alloc_cb(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
buf->base = malloc(suggested_size);
buf->len = suggested_size;
}
void on_new_connection(uv_stream_t *server, int status) {
if (status < 0) {
fprintf(stderr, "New connection error %s\n", uv_strerror(status));
// error!
return;
}
uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
printf("client=%p\n", client);
uv_tcp_init(loop, client);
if (uv_accept(server, (uv_stream_t*) client) == 0) {
uv_read_start((uv_stream_t*) client, my_alloc_cb, echo_read);
}
else {
printf("failed to accept\n");
uv_close((uv_handle_t*) client, NULL);
}
}
int main() {
loop = uv_default_loop();
uv_tcp_t server;
uv_tcp_init(loop, &server);
struct sockaddr_in addr;
uv_ip4_addr("0.0.0.0", DEFAULT_PORT, &addr);
int r;
r = uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0);
r = uv_listen((uv_stream_t*) &server, DEFAULT_BACKLOG, on_new_connection);
if (r) {
fprintf(stderr, "Listen error %s\n", uv_strerror(r));
return 1;
}
return uv_run(loop, UV_RUN_DEFAULT);
}
Turned out the issue is on echo_read(). When the TCP connection is terminated with tcp reset, nread is not -1, it's some negative number (-4095 in my case).
Was able to take care of it using nread < 0 instead of nread == -1.
void echo_read(uv_stream_t *sock, ssize_t nread, const uv_buf_t *buf) {
if (nread == -1) {
fprintf(stderr, "error echo_read");
return;
} else if (nread == 0) {
uv_close((uv_handle_t*)sock, on_close);
return;
}
Hi I am new to working with openssl, i am trying to implement anonymous Diffie Hellman connection using openssl.
The code server code looks some thing like this:
#include "openssl/err.h"
#include "openssl/ssl.h"
#include "openssl/dh.h"
#include <arpa/inet.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <resolv.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define FAIL -1
// Create the SSL socket and intialize the socket address structure
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;
}
int isRoot() {
if (getuid() != 0) {
return 0;
} else {
return 1;
}
}
SSL_CTX *InitServerCTX(void) {
SSL_METHOD *method;
SSL_CTX *ctx;
DH *dh_;
int codes = 0;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = TLSv1_2_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();
}
if (SSL_CTX_set_cipher_list(ctx, "ADH-AES256-SHA256") != 1) {
ERR_print_errors_fp(stderr);
abort();
}
dh_ = DH_new();
if (dh_ == NULL) {
printf ("Alloc for dh failed\n");
ERR_print_errors_fp(stderr);
abort();
}
// Generate Parameters.
if (!DH_generate_parameters_ex (dh_, 1024, DH_GENERATOR_5, NULL)) {
printf ("Generate Parameters failed!!\n");
ERR_print_errors_fp(stderr);
abort();
ERR_print_errors_fp(stderr);
}
// Check if p and g parameters are safe to use.
if (!DH_check (dh_, &codes)) {
printf ("Cannot perform DH check\n");
ERR_print_errors_fp(stderr);
abort();
}
if (codes) {
printf ("DH codes: %x\n", codes);
ERR_print_errors_fp(stderr);
abort();
}
if (!DH_generate_key (dh_)) {
printf ("Failure in DH Generate key\n");
ERR_print_errors_fp(stderr);
abort();
}
SSL_CTX_set_tmp_dh(ctx, dh_);
DH_free(dh_);
return ctx;
}
void Servlet(SSL *ssl) /* Serve the connection -- threadable */
{
char buf[1024] = {0};
int sd, bytes;
const char *ServerResponse = "<\Body>\
<Name>aticleworld.com</Name>\
<year>1.5</year>\
<BlogType>Embedede and c\c++<\BlogType>\
<Author>amlendra<Author>\
<\Body>";
const char *cpValidMessage = "<Body>\
<UserName>aticle<UserName>\
<Password>123<Password>\
<\Body>";
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 */
buf[bytes] = '\0';
printf("Client msg: \"%s\"\n", buf);
if (bytes > 0) {
if (strcmp(cpValidMessage, buf) == 0) {
SSL_write(ssl, ServerResponse, strlen(ServerResponse)); /* send reply */
} else {
SSL_write(ssl, "Invalid Message",
strlen("Invalid Message")); /* 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 *Argc[]) {
SSL_CTX *ctx;
int server;
char *portnum;
// Only root user have the permsion to run the server
if (!isRoot()) {
printf("This program must be run as root/sudo user!!");
exit(0);
}
if (count != 2) {
printf("Usage: %s <portnum>\n", Argc[0]);
exit(0);
}
// Initialize the SSL library
SSL_library_init();
portnum = Argc[1];
ctx = InitServerCTX(); /* initialize SSL */
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 */
}
The client program looks like this:
#include <errno.h>
#include <malloc.h>
#include <netdb.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/dh.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define FAIL -1
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);
printf ("Connecting....\n");
if (connect(sd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
close(sd);
perror(hostname);
abort();
} else {
printf ("Connected...\n");
}
return sd;
}
SSL_CTX *InitCTX(void) {
SSL_METHOD *method;
SSL_CTX *ctx;
DH *dh_;
int codes = 0;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = TLSv1_2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if (ctx == NULL) {
ERR_print_errors_fp(stderr);
abort();
}
if (SSL_CTX_set_cipher_list(ctx, "ADH-AES256-SHA256") != 1) {
printf("SSL_CTX_set_cipher_list failed\n");
SSL_CTX_free (ctx);
ctx = NULL;
ERR_print_errors_fp(stderr);
abort();
}
dh_ = DH_new();
if (dh_ == NULL) {
printf ("Alloc for dh failed\n");
}
// Generate Parameters.
if (!DH_generate_parameters_ex (dh_, 1024, DH_GENERATOR_5, NULL)) {
printf ("Generate Parameters failed!!\n");
}
// Check if p and g parameters are safe to use.
if (!DH_check (dh_, &codes)) {
printf ("Cannot perform DH check\n");
}
if (codes) {
printf ("DH codes: %x\n", codes);
}
if (!DH_generate_key (dh_)) {
printf ("Failure in DH Generate key\n");
//retVal = false;
//break;
}
SSL_CTX_set_tmp_dh(ctx, dh_);
DH_free(dh_);
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("Info: No client certificates configured.\n");
}
int main(int count, char *strings[]) {
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
char acClientRequest[1024] = {0};
int bytes;
char *hostname, *portnum;
if (count != 3) {
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
hostname = strings[1];
portnum = strings[2];
ctx = InitCTX();
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
printf ("Before connect\n");
if (SSL_connect(ssl) == FAIL) /* perform the connection */
ERR_print_errors_fp(stderr);
else {
char acUsername[16] = {0};
char acPassword[16] = {0};
const char *cpRequestMessage = "<Body>\
<UserName>%s<UserName>\
<Password>%s<Password>\
<\Body>";
printf("Enter the User Name : ");
scanf("%s", acUsername);
printf("\n\nEnter the Password : ");
scanf("%s", acPassword);
sprintf(acClientRequest, cpRequestMessage, acUsername,
acPassword); /* construct reply */
printf("\n\nConnected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, acClientRequest,
strlen(acClientRequest)); /* 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;
}
When i compile and execute this code i get the following error:
server side:
140093403805344:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:996:
client side error:
140134052299200:error:141640B5:SSL routines:tls_construct_client_hello:no ciphers available:../ssl/statem/statem_clnt.c:800:
Can any help me out on how to establish a connection with Anonymous DH?
Hi I'm trying to write a client application which will try to connect a remote server. If it can not connect to the server, it will try once again after 5 seconds. If the socket is closed somehow, it will try to connect once again.
I'm getting an error like connect: Transport endpoint is already connected
What could be the problem ?
static void sig_chld(int signo)
{
pid_t pid;
int stat;
while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main(int argc, char *argv[])
{
int sockfd, numbytes;
char buf[MAXDATASIZE];
pid_t childpid;
struct hostent *he;
struct sockaddr_in their_addr; /* connector's address information */
if ((he=gethostbyname(argv[1])) == NULL) { /* get the host info */
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET; /* host byte order */
their_addr.sin_port = htons(PORT); /* short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8); /* zero the rest of the struct */
for ( ; ; ) {
while (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
sleep(5);
}
if ( (childpid = fork()) == 0)
{ /* child process */
while(1)
{
if (send(sockfd, "Hello, world!\n", 14, 0) == -1)
{
perror("send");
}
sleep(3);
}
close(sockfd);
}
}
return 0;
}
You can't reconnect a socket once you have even tried to connect it before, even if it failed. You have to close it and create a new one.
As a school project , i was asked to build a simple HTTP server which can handle and process multiple and simultaneous requests , and to proof that this server will deliver my home page to the internet browser. (Using RFC 1945/HTTP 1.0)
I took a part of my project so you know how it goes
- the server listens to a fixed port. When it receives a TCP connection request, it sets up a TCP connection through another port and services the request in a separate thread. To simplify this programming task, we will develop the code in two stages. In the first stage, you will write a multi-threaded server that simply displays the contents of the HTTP request message that it receives. After this program is running properly, you will add the code required to generate an appropriate response.
Any ideas or samples?
This is a sample of http server with thread pool which I wrote a year ago:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/mman.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <signal.h>
#define KB 1024
/*function declerations*/
void send_content(int fd, int connfd,int isDir,char* path);
void enqueue(int data);
void* dequeue(void* ptr);
void send_to_client(int connfd, char* line);
/*global vars*/
pthread_mutex_t lock;
pthread_cond_t emp;
int sock =0;
int max_threads =0;
int global_count=0;
int finished =1;
int length=0;
/*Queue*/
struct node{
int info;
struct node *ptr;
}*head,*tail;
struct sigaction ready, last;
int main(int argc, char** argv){
int threads;
int requests;
int port;
int i;
int s;
int len_of_packet=1;
int fd;
int port1;
int file;
char content[16000];
char *fileContent ;
int thrd ;
int rc;
char method[KB];
char path[KB];
int s_len=0;
int r_len=0;
int fileLen;
int parsing;
unsigned int addr_size;
struct sockaddr_in serv_addr, client_addr;
struct stat st;
struct dirent *entry;
DIR *dir;
static fd_set readsocks, socks;
char buf[KB] ;
char Uniform_Resource_Identifier[KB];
int servfd;
int socket_of_accept;
off_t chunk=0;
size_t readData;
int sent;
assert (argc ==3 || argc ==4);
threads = strtol(argv[1], NULL, 10);
if ((errno == ERANGE && (threads == LONG_MAX || threads == LONG_MIN))
|| (errno != 0 && threads == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
max_threads = threads;
requests = strtol(argv[2], NULL, 10);
if ((errno == ERANGE && (requests == LONG_MAX || requests == LONG_MIN))
|| (errno != 0 && requests == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
port = 80;
if (argc == 4){
port = strtol(argv[3], NULL, 10);
if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN))
|| (errno != 0 && port == 0)) {
perror("Error: strtol has been failed\n");
exit(0);
}
}
pthread_t threadsArr[threads];
if(pthread_mutex_init(&lock,NULL)!=0){
printf("Error: failed to init mutex\n");
return 1;
}
pthread_cond_init( &emp, NULL);
head=NULL;
tail=NULL;
/*create threads*/
for (thrd=0; thrd<threads;thrd++){
rc = pthread_create(&threadsArr[thrd], NULL, dequeue, (void*) &thrd);
if (rc){
printf("Error: failed to create thread\n");
return 1;
}
}
/* create socket */
servfd = socket(AF_INET, SOCK_STREAM, 0);
sock = servfd;
if (servfd == -1) {
printf("Error creating socket\n");
exit(1);
}
/* init prepernces */
memset(&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(port);
/* bind */
setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, (const char *) &len_of_packet,sizeof(int));
if (bind(servfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) {
printf("Error: Bind has been failed\n");
perror ("Bind: ");
exit(1);
}
/*listen */
if (listen(servfd, requests) == -1) {
printf("Error: Listen has been failed\n");
perror ("Listen: ");
exit(1);
}
FD_ZERO(&socks);
FD_SET(servfd, &socks);
int startLen = strlen("HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n");
int endLen = strlen("</h1></body></html>\r\n");
while(1){
sigfillset(&ready.sa_mask);
ready.sa_handler = SIG_IGN;
ready.sa_flags = 0;
if (sigaction(SIGINT, &ready,&last) || sigaction(SIGINT,&last,NULL)){
finished=0;
for(i=0; i<threads; i++){
rc = pthread_join(threadsArr[i], NULL);
if(rc != 0){
printf("Error: join has been failed\n");
perror("Join: ");
return 1;
}
}
pthread_mutex_destroy(&lock);
close(sock);
}
addr_size = sizeof(client_addr);
socket_of_accept = accept(servfd, (struct sockaddr *) &client_addr, &addr_size);
if (socket_of_accept == -1) {
printf("Error: Accept has been failed\n");
perror ("Accept: ");
exit(1);
}
enqueue(socket_of_accept);
if (length <= requests){
/*recieve message*/
r_len = recv(socket_of_accept, buf, KB,0);
if (r_len == -1){
printf("Error: recieve has been %d\n", socket_of_accept);
close(socket_of_accept);
exit(1);
}
sscanf(buf,"%s %s", method, Uniform_Resource_Identifier);
sscanf(Uniform_Resource_Identifier,"%s", path);
printf("method = %s, path = %s\n", method, path);
/*GET OR POST*/
if(strcmp(method, "GET")!= 0 && strcmp(method, "POST") != 0){
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
if (stat(path, &st) == -1){ /*file not found*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Not Found (HTTP 404)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}else {
if(S_ISDIR(st.st_mode)){/*directory*/
if((dir = opendir (path)) != NULL){
send_content(fd, socket_of_accept,1,path);
close(socket_of_accept);
}else{
printf("Error: failed to open directory: %s\n", path);
}
}else if(S_ISREG(st.st_mode) && st.st_size != 0){/*regular file*/
fd=open(path,O_RDONLY);
send_content(fd, socket_of_accept,0,path);
close(file);
close(socket_of_accept);
}
else{/*empty file*/
char response[] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1> </h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: failed to send message %s to client %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
}
}
}else{/*full queue*/
/*send (HTTP 503)*/
char response[3000] = "HTTP/1.0 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"<doctype !html><html><head><title></title>"
"<style>body"
"h1 { font-size:4cm; text-align: center; color: black;"
"}</style></head>"
"<body><h1>Service Unavailable (HTTP 503)</h1></body></html>\r\n";
s_len = send(socket_of_accept, response, strlen(response), 0);
if (s_len == -1){
printf("Error: unable to send a message %s to: %d\n", response, socket_of_accept);
close(socket_of_accept);
exit(1);
}
close(socket_of_accept);
}
}
return 0;
}
void send_content(int fd, int connfd,int isDir,char* path){
char line[KB];
memset(line, 0, sizeof(line));
send_to_client(connfd, "HTTP/1.0 200 OK\r\n\r\n");
int return_value;
if(!isDir){
while ((return_value=read(fd, line, KB)) > 0) {
send_to_client(connfd, line);
memset(line, 0, sizeof(line));
}
if (return_value < 0){
perror("Error read");
send_to_client(connfd, "Error Resorces\n");
return;
}
}
else {
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
strcpy(line,dir->d_name);
strcat(line,"\n");
send_to_client(connfd,line);
memset(line, 0, sizeof(line));
}
closedir(d);
}
}
}
/*enqueue*/
void enqueue(int data)
{
int rc;
struct node* temp;
temp = (struct node *)malloc(1*sizeof(struct node));
if(temp == NULL){
printf("Error: couldn't allocate memory\n");
exit(1);
}
temp->ptr = NULL;
temp->info = data;
if (pthread_mutex_lock(&lock) !=0){
printf("Error: failed to lock\n");
exit(1);
}
if (length == 0) /*empty queue*/
{
head = temp;
}else
{
tail->ptr = temp;
}
tail = temp;
length++;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: failed to unlock\n");
pthread_exit(0);
}
return;
}
void send_to_client(int connfd, char* line){
int nsent, totalsent;
int notwritten = strlen(line);
/* keep looping until nothing left to write*/
totalsent = 0;
while (notwritten > 0){
/* notwritten = how much we have left to write
totalsent = how much we've written so far
nsent = how much we've written in last write() call */
nsent = write(connfd, line + totalsent, notwritten);
assert(nsent>=0); // check if error occured (client closed connection?)
totalsent += nsent;
notwritten -= nsent;
}
}
/*dequeue*/
void* dequeue(void* ptr)
{
int rc;
int i=0;
int thread = *((int*)ptr);
struct node* temp;
while(finished){
if (pthread_mutex_lock(&lock) !=0){
printf("Error: lock has been failed\n");
pthread_exit(0);
}
while (length == 0)
{
rc = pthread_cond_wait(&emp, &lock);
assert(rc == 0);
}
int info = head->info;
temp = head;
head = head->ptr;
free(temp);
length--;
rc = pthread_cond_broadcast(&emp);
assert(rc==0);
if (pthread_mutex_unlock(&lock)!=0){
printf("Error: unlock has been failed\n");
pthread_exit(0);
}
}
pthread_exit(0);
}
I have the following codes..
server.c
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
static int clients = 0;
static int* memptr = NULL;
void serve(void*);
int* push(int* memptr, int nsfd) {
clients++;
if (clients == 1)
memptr = (int*)malloc(sizeof(int) * clients);
else
memptr = (int*)realloc(memptr, sizeof(int) * clients);
memptr[clients - 1] = nsfd;
return memptr;
}
int main(int argc, char** argv) {
pthread_t thread[2];
int threadCount = 0;
if (argc != 3){
printf("\nUsage: ./server port_number maximum_clients\n");
return 1;
}
static struct sockaddr_in sock, sock_client;
int len, new_sock_fd;
int sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr("0.0.0.0");
len = sizeof(sock);
if ( bind(sock_fd, (struct sockaddr *)&sock, len) == -1){
perror("bind");
exit(1);
}
if ( listen(sock_fd, atoi(argv[2])) == -1){
perror("listen");
exit(1);
}
while(1) {
new_sock_fd = accept(sock_fd, (struct sockaddr *)&sock_client, (socklen_t *)&len);
memptr = push(memptr, new_sock_fd);
if (new_sock_fd == -1){
perror("accept");
exit(1);
}
pthread_create(&(thread[threadCount]), NULL, (void*)&serve, (void *)&new_sock_fd);
pthread_join(thread[threadCount++], NULL);
printf("threadCount = %d\n", threadCount);
sleep(1);
}
return 0;
}
void serve(void* fd){
int* new_sock_fd = (int*)fd;
Packet packet;
while(1){
bzero(&packet, sizeof(packet));
read(*new_sock_fd , &packet, sizeof(packet));
printf("%d\n", *new_sock_fd);
//printf("recipientId = %d\n", packet.recipientId);
// printf("message = %s\n", packet.data);
write(memptr[packet.recipientId - 1], packet.data, 1024);
}
pthread_exit(0);
}
and the tcp.h looks like
#ifndef __TCP_H__
# define __TCP_H__
typedef struct {
int recipientId; // this is the reciever ID
char data[1024]; // this is the main data part
}Packet;
#endif /* __TCP_H__ */
and each client.h looks like this
#include <stdio.h>
#include "./../linux.h"
#include "./tcp.h"
#include <pthread.h>
void print(void);
void scan(void);
int sock_fd;
int main(int argc, char** argv) {
if (argc != 3){
printf("\nUsage: ./client port_number server_ip\n");
return 1;
}
static struct sockaddr_in sock;
int len;
pthread_t thread1, thread2;
sock_fd = socket(PF_INET, SOCK_STREAM, 0);
if (sock_fd == -1){
perror("socket");
exit(1);
}
sock.sin_family = PF_INET;
sock.sin_port = htons(atoi(argv[1]));
sock.sin_addr.s_addr = inet_addr(argv[2]);
len = sizeof(sock);
if ( connect(sock_fd, (struct sockaddr *)&sock , len) == -1 ){
perror("connect");
exit(1);
}
pthread_create(&thread1, NULL, (void*)&print, NULL);
pthread_create(&thread2, NULL, (void*)&scan, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
void print(){
char messege[1024];
while(1){
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
}
pthread_exit(0);
}
void scan(void){
Packet packet;
while(1){
printf("Enter the reciver ID: ");
scanf("%d", &packet.recipientId);
printf("Enter the data: ");
scanf("%s", packet.data);
if ( write(sock_fd, &packet, sizeof(packet)) == -1) {
perror("read");
return;
}
}
pthread_exit(0);
}
Now the problems are
when I am running the server & the in 2 terminals, 2 clients after each client is accepted threadCount should be printed at the server end but it is not printing. It means the execution stops/skips after the first pthread_join but WHY ??
After connecting two threads, when I sent the data from 1st client to the 1st client itself, it works but not from the 1st client to the 2nd client..rather it is sending to the server terminal window. WHY ??
When sent from the second client nothing works ( sending itself or client 1)..WHY??
Please help..And thanks for patiently reading all the codes above.
TCP is a byte stream protocol, not a message protocol. You are calling TCP functions and expecting them to send or receive messages. They don't. If you want to send or receive messages, you have to implement a message protocol, write functions that send and receive messages, and then call those functions.
if (read(sock_fd, messege, 1024) == -1){
perror("read");
return;
}
printf("messege = %s\n", messege);
This call to printf is a disaster. The %s format specifier is for C-style strings, not arbitrary chunks of bytes received from a byte stream. For the most obvious way to see how bad this is, consider this --- how should printf decide how many bytes to print? You threw away the value read returned after you compared it to -1, so you have no idea how many bytes you received.
I'm sure there are other issues with your code, but the fact that the fundamental design is broken makes it not worth fixing those issues. Instead, design a message protocol and implement that.