0

I've added a Unix domain socket to a project I'm working on. The socket has a simple function, it simply broadcasts data that the code extracts from another device, the idea is that other applications will be able to read this data from the socket.

I've written a simple server code, and when I run the code on my laptop, using a Ubuntu 10.04 VM, it works perfectly well. However, when I copy the code over onto the embedded device I'm using the code fails, when my application tries to write to the socket the code exits.

In /var/log/messages I see the following messages:

Dec  2 15:12:17 box local1.info my-app[17338]: Socket Opened
Dec  2 15:12:17 box local1.err my-app[17338]: Socket Failed
Dec  2 15:12:17 box local1.err my-app[17338]: Protocol wrong type for socket
Dec  2 15:12:38 box local1.info ./server[17178]: accept failed: Invalid argument

Here is the server code:

#include <stdio.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include<syslog.h>

#define SV_SOCK_PATH "/tmp/rtig.sock"    //path to be used by socket
#define BUF_SIZE 256    //Max length of string listened to
#define BACKLOG 5

int main(int argc, char *argv[]){
  struct sockaddr_un addr;
  int sfd, cfd;        //File Descriptors for the server and the client
  ssize_t numRead;    //Length of the string read from the client.
  u_int8_t buf[BUF_SIZE];    //String that reads messages
  char plain[BUF_SIZE];    //Plain string for writing to the log
  memset(plain, 0, sizeof plain); //blank out plain string

  openlog(argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); //Write the messages to the syslog

//---Declare socket--------------------------------------
  sfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if(sfd!=0){
    syslog(LOG_INFO, "socket success");
  }
  else{
    syslog(LOG_INFO, "socket unsuccessful");
  }

  //--Test to see if there's already a socket at SV_SOCK_PATH, and remove it if there is.
  if (remove(SV_SOCK_PATH) == -1 && errno !=ENOENT){
    syslog(LOG_INFO, "error removing socket");
  }

 //-----------------------------------------------------------

  //--blank out the socket address, then write the information to it
  memset(&addr, 0, sizeof(struct sockaddr_un));
  addr.sun_family = AF_UNIX;
  strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path)-1); //ensure path is null terminated

//----Bind the socket to the address-------------------------------------
  if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un))!=0){
    syslog(LOG_INFO, "bind unsuccessful");
  }
  else{
    syslog(LOG_INFO, "bind successful");
  }
//------------------------------------------------------------------------

//-----Listen on the socket-----------------------------------------------
  if (listen(sfd, BACKLOG) != 0){
    syslog(LOG_INFO, "listen failed");
  }
  else{
    syslog(LOG_INFO, "listen succeeded");
  }
//-------------------------------------------------------------------------

//--------Accept messages on the socket------------------------------------
 socklen_t csize; 

  while(1){

    cfd = accept(sfd, (struct sockaddr *)&addr,&csize);

    if (cfd < 0) {
      syslog(LOG_INFO, "accept failed: %s", strerror(errno));
    }

    while ( (numRead=read(cfd, buf, BUF_SIZE)) > 0 ){ 

    dump_packet(buf, numRead);

    }

  }
 //-------------------------------------------------------------------------

//---code never gets here but this is how to close the log and the socket--
  closelog();
  close(cfd);
}

And here's a simple version of the client that connects to this server from my app:

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define SV_SOCK_PATH "/tmp/rtig.sock"   //path to be used by socket
#define BACKLOG 5

int isDaemon = 1;

void etmlog(int level, char *message)
{
isDaemon == 1 ? syslog(level, message) : printf(message);
}

int main(){
    struct sockaddr_un addr;
    unsigned int sockfd;
    ssize_t numRead;


if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) > 0) {
    etmlog(LOG_INFO, "Socket Opened\n");
}
    else {
    etmlog(LOG_ERR, "Socket Failed:\n");
    etmlog(LOG_ERR, strerror(errno));
    exit(-1);
}

memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path) - 1);    // -1 ensures null terminated string

if (connect
    (sockfd, (struct sockaddr *)&addr,
     sizeof(struct sockaddr_un)) == -1) {
    etmlog(LOG_ERR, "Socket Failed\n");
    etmlog(LOG_ERR, strerror(errno));
    exit(1);
} else {
    etmlog(LOG_INFO, "Socket Connection Successful\n");
}

    while (1){
     // some data is read into buf up here

        if (write(sockfd, buf, rdlen) < 0) {
        etmlog(LOG_ERR, "Write to Socket Failed:");
        etmlog(LOG_ERR, strerror(errno));
        }
    }

   close(sockfd);
   return 0;
 }

I appreciate that I've just posted a lot of code to read through, but I'd be very grateful if someone could give me a few pointers on this.

James
  • 3,957
  • 4
  • 37
  • 82
  • The device's kernel could just omit support for Unix domain sockets. The Linux kernel is very configurable. Unix domain sockets support is a configuration flag selectable at compilation time. – n. m. could be an AI Dec 02 '13 at 16:21
  • Thanks for the suggestion, however I'm certain that the kernel does support unix sockets as they are used in other applications that run on the system. – James Dec 02 '13 at 16:25
  • 1
    Yes indeed, they are supported otherwise `socket` would fail. – n. m. could be an AI Dec 02 '13 at 16:34

1 Answers1

5

You are not using accept correctly. The third argument must be initialized to the size of the second argument, so that accept won't overflow it. See man accept.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • 1
    In particular, it's an in-out parameter: on input, it contains the maximum length of the peer socket address it's willing to accept, and on output, it contains the actual length of the peer socket address. – Adam Rosenfield Dec 02 '13 at 16:45
  • Thanks, I missed that line, I added `csize = sizeof(addr);` and now the code works on both the embedded device and my laptop. – James Dec 02 '13 at 17:02