2

I'm running this example http://doc.qt.io/qt-5/qtcore-ipc-localfortuneserver-example.html

Using cat <socket_name> works fine, I even managed to connect with python.

However this unfortunately fails. -> connect() failed: [2][No such file or directory] ? W H Y ¿

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

#define SOCK_PATH "/Users/Name/socket"

int main(void) {
    int sockfd = 0,n = 0, err = 0;
    char recvBuff[1024];
    struct sockaddr_un serv_addr;
    const char* const pcSocketName = SOCK_PATH;
    memset(recvBuff, '0' ,sizeof(recvBuff));
    if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0))< 0) {
        printf("\n Error : Could not create socket \n");
        return 1;
    }
    serv_addr.sun_family = AF_UNIX;
    serv_addr.sun_path[0] = '\0';
    strncpy(serv_addr.sun_path+1, pcSocketName, strlen(pcSocketName));
    err = connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
    if(0 != err) {
        printf("connect() failed: [%d][%s]\n", errno, strerror(errno));
        return(-1);
    }
    while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) {
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF) {
            printf("\n Error : Fputs error");
        }
        printf("\n");
    }
    if( n < 0) {
        printf("\n Read Error \n");
    }
    printf("Over..\n");
    return 0;
}

I'm running on MacOS, building with gcc. Parts of this code were put together from various places on the web.

thomas
  • 325
  • 3
  • 11

1 Answers1

3

The socket path copy line is wrong:

strncpy(serv_addr.sun_path+1, pcSocketName, strlen(pcSocketName));

You want to copy pcSocketName to serv_addr.sun. Also protection strlen(pcSocketName) does not make any sense here. You can use just

strcpy(serv_addr.sun_path, pcSocketName);

In the simple example strcpy is safe if we are sure that the length of SOCK_PATH is small enough to fit in the buffer serv_addr.sun_path. However, to avoid accidental errors or in more complex cases when the string length can vary it makes sense to protect from the potential overflow. The function strncpy can be used to copy no more than sizeof(serv_addr.sun_path) - 1 bytes from pcSocketName. One byte is reserved for zero terminating character. If the length limit is reached in strncpy the last null character is not appended. So, it should be set manually:

serv_addr.sun_path[sizeof(serv_addr.sun_path) - 1] = '\0';
strncpy(serv_addr.sun_path, pcSocketName, sizeof(serv_addr.sun_path) - 1);

I guess that your code is based on Can not connect to Linux "abstract" unix socket

That resulted in the initial connecting issues. The first byte in sun_path[] should be zero (serv_addr.sun_path[0] = '\0';) to work with abstract namespace UNIX sockets. However such abstract namespace is a nonportable Linux extension:

  • abstract namespace sockets are not supported on Mac OS X (and OS X)
  • Qt QLocalSocket does not support it even on Linux: QTBUG-16090

So, QLocalSocket works with the filesystem sockets. Such sockets should be accessed in C just by a null-terminated filesystem pathname in sun_path.

Community
  • 1
  • 1
Orest Hera
  • 6,706
  • 2
  • 21
  • 35
  • Concerning the protection, am I right in thinking that one or the other are enough but both redondant? – thomas Oct 20 '15 at 10:11
  • @thomas Yes, you can use either `strcpy` (your path length is small enough and you set it manually) or to be sure that the path fits into `serv_addr.sun_path` you can use `strncpy` and manually set the last zero byte. BTW, to clarify connecting issues I guess that your code is from the post about `abstract` sockets http://stackoverflow.com/questions/11640826/can-not-connect-to-linux-abstract-unix-socket You can find that abstract sockets does not use real file names, but you have real file that can be used with `cat`. – Orest Hera Oct 20 '15 at 10:19