James
James

Reputation: 4052

Unix Domain Socket Code Fails on Embedded Device

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.

Upvotes: 0

Views: 1278

Answers (1)

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

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.

Upvotes: 5

Related Questions