Question

I am trying to make a bridge via unix domain socket between Ruby script as server and C app as client but currently I am stuck in the read loop until I kill Ruby script maybe someone could look at the code?

    struct sockaddr_un addr;
  int fd,rc;
  char *socket_path = "/tmp/auth.sock";

  char *output_packet = cern_format_packet(pw, key);


  if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    error("socket error");
    return 0;
  }

  memset(&addr, 0, sizeof(addr));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);

  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
    error("connect error");
    return 0;
  }
  logit("cern_output: %s", output_packet);
  write(fd, output_packet, strlen(output_packet));

#define BUFFERSIZE 1024
#define MAXDATASIZE 256   
  int c, q = 0, success;
  char* input_buffer;
  char data_buffer[MAXDATASIZE];
  size_t input_buffer_size = BUFFERSIZE;
  input_buffer = malloc(input_buffer_size);

  if (input_buffer)
  {
      while((c = read(fd, data_buffer, MAXDATASIZE)) > 0)
      {
          if (c + q > input_buffer_size)
          {
              input_buffer_size *= 2; /* Arbitrary doubling of size. */
              char* tmp = realloc(input_buffer, input_buffer_size);
              if (tmp)
              {
                  input_buffer = tmp;
              }
              else
              {
                  /* memory allocation failure. */
                  free(input_buffer);
                  input_buffer = 0;
                  break;
              }
          }
          memcpy(input_buffer + q, data_buffer, c);
          q += c;
      }
  }
  json_error_t error; 
  json_t *root = json_loads( input_buffer, 0, &error );
  if (root) {
    json_t *json_status = json_object_get( root, "status" );
    json_t *json_command = json_object_get( root, "command" );
    const char *return_comamnd = json_string_value( json_command );
    success = (int)json_integer_value(json_status);
    logit("json_response: status: %i command: %s",success, return_comamnd);
  }


  close(fd);
  return success;

And the ruby script

require "socket"
require 'msgpack'
require "json"

file = "/tmp/auth.sock"

File.unlink if File.exists?(file) && File.socket?(file)

serv = UNIXServer.new(file)

loop do
        s = serv.accept
        msg = s.gets
        msg = msg.gsub("\n", "") if msg
        p JSON.parse(msg)
        a = {}
        a["status"] = 1
        a["command"] = "hello world"
        s.write(JSON.generate(a))
s.close
end
Was it helpful?

Solution

The client's call to read() most likely blocks because the server did send less then the client was told to read, that is MAXDATASIZE bytes.

Do get around this let the server orderly shutdown the socket before closing it.

I'm no Ruby expert but may be something like:

s.shutdown
s.close

would do the job.


Also in the server this line:

msg = s.gets

might block until a \n had been received. (See here for details on gets: http://www.ruby-doc.org/core-2.0.0/IO.html#method-i-gets)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top