0

I am writing a simple PHP client and C server programs on Ubuntu 16.04. On client side I have made a simple graphical user interface in HTML, in which there is only one drop down box, and a submit button. When I click on the button, PHP client code is executed (though Apache server), but the client does not connect to the server, which is initially launched in terminal.

I want to pass the value of drop down box to the C server, whatever user selects from drop down. Please help me to figure out what's wrong with my code.

Server.c

//All Libraries are present including pthread

#define BUFFER_SIZE 1024

//the thread function

void *connection_handler(void *);

int main(int argc , char *argv[])
{

  int socket_desc , client_sock , c , *new_sock;

  struct sockaddr_in server , client;

  socket_desc = socket(AF_INET , SOCK_STREAM , 0);

  if (socket_desc == -1)
  {

    printf("Could not create socket");

  }

  puts("Socket created");

  server.sin_family = AF_INET;

  server.sin_addr.s_addr = INADDR_ANY;

  server.sin_port = htons( 8888 );
  //Bind
  if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
  {


    perror("bind failed. Error");
    return 1;
  }
  puts("bind done");

  listen(socket_desc , 3);

  c = sizeof(struct sockaddr_in);

  int threadID;

  //Accept and incoming connection

  puts("Waiting for incoming connections...");

  c = sizeof(struct sockaddr_in);

  while( (client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c)) )

  {

    puts("Connection accepted");

    pthread_t sniffer_thread;

    new_sock = malloc(1);

    *new_sock = client_sock;

    threadID=pthread_create( &sniffer_thread , NULL ,  connection_handler , (void*) new_sock);

    if( threadID < 0)

    {

      perror("could not create thread");

      return 1;

    }

    puts("Handler assigned");

  }



  if (client_sock < 0)

  {

    perror("accept failed");

    return 1;

  }

  return 0;

}

void *connection_handler(void *socket_desc)

{

  int read_size;

  char *serverErrorMsg="Invalid Details!";

  char client_message[2000],client_poll[2000];

  int sock = *(int*)socket_desc;


  //Receive a message from client

  if( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )

  {
    puts("Server Received: ");

    puts(client_message);

  }

  else

  {

    write(sock , serverErrorMsg , strlen(serverErrorMsg));

  }

  free(socket_desc);    

  return 0;

}

Client.php

<?php 

error_reporting(E_ALL);

$host    = "127.0.0.1";

$port    = 8888;

// create socket

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socket\n");

// connect to server

$result = socket_connect($socket, $host, $port) or die("Could not connect to server\n");  

// sending test type to server

$selectedType = $_POST['testType']; //html drop down with name='testType'

socket_write($socket, $selectedType, strlen($message)) or die("Could not send data to server\n");

socket_close($socket);

?>
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60

1 Answers1

0

The code is full of bugs.

Server.c

Checking return values

If socket() fails, you only print a message to the standard output. The program continues to run with invalid descriptor:

socket_desc = socket(AF_INET, SOCK_STREAM, 0)
if (socket_desc == -1) {
  printf("Could not create socket");
}

Standard input/output

You should print errors to the standard error descriptor, then abort(), or exit with a non-zero exit code, e.g.:

#include <errno.h>
#include <string.h>

socket_desc = socket(AF_INET, SOCK_STREAM, 0);
if (socket_desc == -1) {
  fprintf(stderr, "socket() failed: %s\n", strerror(errno));
  exit(1);
}

-Wall

Obviously, you haven't compiled the code with warnings on:

a.c:xxx:yy warning: unused variable ‘client_poll’ [-Wunused-variable]

Always compile with -Wall.

sizeof

There is no need in storing the result of sizeof in memory, as sizeof is a compile-time operator:

/* Don't do this. Use a macro, if you want to shorten sizeof expression */
c = sizeof(struct sockaddr_in)

Closing the socket

The socket descriptor should be closed when a session has been completed:

close(socket_desc);

Otherwise, use SOCK_CLOEXEC flag (socket()'s type argument).

Accessing the sockets from thread handler

You allocate only single byte for the file descriptor for the accepted socket:

new_sock = malloc(1);

You can simply cast integer to void pointer:

#include <stdint.h>

void *connection_handler(void *socket_desc)
{
  int sock = (intptr_t) socket_desc;
  /* ... */
}

threadID = pthread_create(&sniffer_thread, NULL,
  connection_handler, (void *)(intptr_t) new_sock);

Even if you want to use malloc for the hell of it, use the sizeof operator:

/* Allocates memory for an integer */
new_sock = malloc(sizeof(int));

Regarding pthread_create()

The code apparently "thinks" that pthread_create() function returns a thread ID. It doesn't. The return value is zero on success, otherwise it is an error code.

From the moment you spawn a thread, you are responsible for its life cycle until it terminates. Particularly, you should wait for the child threads to terminate using pthread_join() function. The latter accepts a pthread_t, which is initialized by pthread_create(). So you need to store pthread_t buffers somewhere. E.g.:

int rc, i = 0;
const int MAX_THREADS = 10;
pthread_t *threads = calloc(sizeof(pthread_t), MAX_THREADS);
struct sockaddr_storage their_addr;
socklen_t addr_size;

puts("Waiting for incoming connections...");
addr_size = sizeof their_addr;
while ((client_sock = accept(socket_desc, (struct sockaddr *)&their_addr, &addr_size)) > 0) {
  puts("Connection accepted");

  if (i >= MAX_THREADS) {
    fprintf(stderr, "Max threads limit exceeded: %d, closing client socket\n", i);
    close(client_sock);
    break;
  }

  rc = pthread_create(&threads[i++], NULL,
      connection_handler, (void *)(intptr_t) client_sock);
  if (rc) {
    perror("could not create thread");
    break;
  }
}

if (threads) {
  int i;
  for (i = 0; i < MAX_THREADS; i++) {
    if (threads[i])
      pthread_join(threads[i], NULL);
  }
  free(threads);
}

Signal handlers

The program accepts connection until thread limit exceeds, or the user presses Control - C, or terminates the process in other way. You should attach the signal handlers, and implement interthread communication to properly stop accepting connections etc. As this goes beyond the scope of the question, I'll leave it for self-study.

Finally, don't use C++ comments in C.

Client.php

You are passing length of undefined variable $message to socket_write:

socket_write($socket, $selectedType, strlen($message));

Since the variable is undefined, the length is evaluated to zero, which means that you send nothing to the server. Here is a fixed version, for completeness:

socket_write($socket, $selectedType, strlen($selectedType));

Testing

After fixing the above, the programs respond to the user input:

Terminal 1

$ ./server
Socket created
bind done
Waiting for incoming connections...
Connection accepted
Server Received: 
test

Terminal 2

I've changed $selectedType in Client.php for testing in CLI:

$selectedType = isset($_POST['testType']) ? $_POST['testType'] : 'test';
$ php Client.php
Community
  • 1
  • 1
Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60