2017-06-22 60 views
1

我工作在基于网络安全的iOS应用程序。我正在尝试为线程之间的通信创建一个本地套接字。我在iOS应用程序中使用C语言进行此操作。套接字创建失败,但套接字()和绑定()方法不返回-1

问题是,当我创建和绑定套接字它不会给出任何错误。但是当我尝试通过这个套接字发送一些数据时,它会失败。代码创建和插座的绑定如下:

int open_and_bind_socket(int *sockfd, const char *sname) 
{ 
    //sname is socket name with full path 
    size_t len = strlen (sname); 

    size_t bytes = sizeof (struct sockaddr_un) + len + 1 - sizeof (((struct sockaddr_un *)0)->sun_path); 

    struct sockaddr_un *unaddr = (struct sockaddr_un *)malloc (bytes); 

    size_t size; 

    if((*sockfd = socket (AF_LOCAL, SOCK_DGRAM, 0)) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to open socket"); 
     return ~0; 
    } 

    unaddr->sun_family = AF_UNIX; 
    unaddr->sun_len = bytes; 
    memcpy(unaddr->sun_path, sname,len+1); 

    size = (offsetof (struct sockaddr_un, sun_path) 
       + strlen (unaddr->sun_path)); 

    if(bind(*sockfd,(struct sockaddr*)unaddr,size) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to bind the socket"); 
     AGENT_DEBUG(LOG_ERR, "Recvfrom MSG_PEEK Failure: %s, Socket Fd = %d\n", 
        strerror(errno), sockfd); 
     return ~0; 
    } 

    if(0 != chmod(sname, 0666)) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Unable to chmod Socket"); 
     return ~0; 
    } 
    //unlink(sname); 
    return 0; 
} 

插槽上发送数据的代码如下:

int data_send(int sockfd, tsIpcMsg *pMsgData) 
{ 
    memset(x,'\0', sizeof(x)); 
    strcpy(x, buffer); 
    strcat(x,"/AGENTSOCKET"); 
    size_t len = strlen (x); 

    size_t bytes = sizeof (struct sockaddr_un) + len + 1 - sizeof (((struct sockaddr_un *)0)->sun_path); 

    struct sockaddr_un *saun = (struct sockaddr_un *)malloc (bytes); 

    memset(saun, 0, sizeof(*saun)); 
    saun->sun_family = AF_UNIX;  
    saun->sun_len=bytes; 
    memcpy(saun->sun_path, x,len+1); 
    memset(x,'\0', sizeof(x)); 

    if(-1 == (sendto(sockfd,(void*)pMsgData, sizeof(tsIpcMsg)+pMsgData->dataLen , 0, (struct sockaddr *)saun, sizeof(*saun)))) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to send message from thread to main"); 
     return ~0; 
    } 
    return 0; 
} 

当我登录通过的sendto()返回的错误号功能它赋予价值'2'表示“不存在这样的文件或目录:路径名中的组件不存在或者是悬挂的符号链接,或者路径名为空。”

所以,我认为套接字没有得到正确创建,这就是为什么sendto()方法失败,而套接字和绑定方法不会给出任何错误。

我在ios模拟器(iPhone 7 plus)上运行这个应用程序。插槽的路径如下: “/ Users/Admin/Library/Developer/CoreSimulator/Devices/FC85979F-A627-4361-B4BD-DD794AB009C9/data/Containers/Data/Application/C45B9A05-F482-4011-8EA0- 947A8C489367/Documents/app/AGENTSOCKET“,其中AGENTSOCKET是套接字的名称。

我创建的目录结构,直到应用程序文件夹,然后附加插槽名称,而它通过以下方式创建套接字:

mkdir(path,0777);//path is till app directory 
strcat(path, "/AGENTSOCKET"); 

谁能帮我解决了这一点。

谢谢。

+1

这是一种奇怪的方式来计算地址所需要的尺寸结构体。 'offsetof(struct sockaddr_un,sun_path)+ len + 1'不会更简单和更清晰吗? –

+0

此外,POSIX没有为'struct sockaddr_un'记录一个'sun_len'成员,并且我甚至无法找到它的文档,甚至不能作为iOS特有的功能。如果它实际上存在,那么它不太可能用于应用程序。 –

+0

什么是'x' ...?你的'data_send'以'memset(x,'\ 0',sizeof(x))''开始......但它是什么? – Myst

回答

0

sun_path字段限于92-108个字符(取决于平台)的任何位置,包括空终止符。您显示的字符串为data_send()的字符串为185个字符,但没有空终止符。所以,如果它被截断,那可能会导致你得到的ENOENT错误。

这就是说,您正在计算大小sockaddr_un不正确,并将错误的地址大小传递到bind()sendto()。此外,open_and_bind_socket()data_send()正在泄漏内存。

尝试一些更喜欢这个:

int open_and_bind_socket(int *sockfd, const char *sname) 
{ 
    *sockfd = -1; 

    //sname is socket name with full path 
    size_t len = strlen (sname); 

    size_t size = offsetof (struct sockaddr_un, sun_path) + len + 1; 

    struct sockaddr_un *unaddr = (struct sockaddr_un *) malloc (size); 
    if (!unaddr) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to allocate memory\n"); 
     return ~0; 
    } 

    memset(unaddr, 0, size); 
    unaddr->sun_family = AF_UNIX; 
    memcpy(unaddr->sun_path, sname, len); 
    unaddr->sun_len = SUN_LEN(unaddr); 

    int sock = socket (AF_LOCAL, SOCK_DGRAM, 0); 
    if (sock < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to create socket: %s\n", strerror(errno)); 
     free(unaddr); 
     return ~0; 
    } 

    if (bind(sock, (struct sockaddr*)unaddr, unaddr->sun_len) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to bind the socket: %s\n", strerror(errno)); 
     close(sock); 
     free(unaddr); 
     return ~0; 
    } 

    if (0 != chmod(sname, 0666)) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Unable to chmod socket: %s\n", strerror(errno)); 
     close(sock); 
     free(unaddr); 
     return ~0; 
    } 

    free(unaddr); 

    //unlink(sname); 

    *sockfd = sock; 

    return 0; 
} 

int data_send(int sockfd, tsIpcMsg *pMsgData) 
{ 
    // this is a buffer overflow waiting to happen! 
    memset(x, '\0', sizeof(x)); 
    strcpy(x, buffer); 
    strcat(x, "/AGENTSOCKET"); 

    size_t len = strlen (x); 

    size_t size = offsetof (struct sockaddr_un, sun_path) + len + 1; 

    struct sockaddr_un *saun = (struct sockaddr_un *) malloc (size); 
    if (!saun) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to allocate memory\n"); 
     return ~0; 
    } 

    memset(saun, 0, size); 
    saun->sun_family = AF_UNIX;  
    memcpy(saun->sun_path, x, len); 
    saun->sun_len = SUN_LEN(saun); 

    if (sendto(sockfd, (void*)pMsgData, sizeof(tsIpcMsg) + pMsgData->dataLen, 0, (struct sockaddr *)saun, saun->sun_len) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to send message from thread to main: %s\n", strerror(errno)); 
     free(saun); 
     return ~0; 
    } 

    free(saun); 
    return 0; 
} 

或者,你并不需要动态分配sockaddr_un都:

int open_and_bind_socket(int *sockfd, const char *sname) 
{ 
    *sockfd = -1; 

    struct sockaddr_un unaddr; 

    memset(&unaddr, 0, sizeof(unaddr)); 
    unaddr.sun_family = AF_UNIX; 
    strncpy(unaddr.sun_path, sname, sizeof(unaddr.sun_path)-1); 
    unaddr.sun_len = SUN_LEN(&unaddr); 

    int sock = socket (AF_LOCAL, SOCK_DGRAM, 0); 
    if (sock < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to create socket: %s\n", strerror(errno)); 
     return ~0; 
    } 

    if (bind(sock, (struct sockaddr*) &unaddr, unaddr.sun_len) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to bind the socket: %s\n", strerror(errno)); 
     close(sock); 
     return ~0; 
    } 

    if (0 != chmod(sname, 0666)) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Unable to chmod socket: %s\n", strerror(errno)); 
     close(sock); 
     return ~0; 
    } 

    //unlink(sname); 

    *sockfd = sock; 

    return 0; 
} 

int data_send(int sockfd, tsIpcMsg *pMsgData) 
{ 
    // this is a buffer overflow waiting to happen! 
    memset(x, '\0', sizeof(x)); 
    strcpy(x, buffer); 
    strcat(x, "/AGENTSOCKET"); 

    struct sockaddr_un saun; 

    memset(&saun, 0, sizeof(saun)); 
    saun.sun_family = AF_UNIX;  
    strncpy(saun.sun_path, x, sizeof(saun.sun_path)-1); 
    // alternatively this is safer: 
    // snprintf(saun.sun_path, sizeof(saun.sun_path), "%s/AGENTSOCKET", buffer); 
    saun.sun_len = SUN_LEN(&saun); 

    if (sendto(sockfd, (void*)pMsgData, sizeof(*pMsgData) + pMsgData->dataLen, 0, (struct sockaddr *) &saun, saun.sun_len) < 0) 
    { 
     AGENT_DEBUG(LOG_ERR, "%s", "Failed to send message from thread to main: %s\n", strerror(errno)); 
     return ~0; 
    } 

    return 0; 
} 
+0

感谢您的帮助,第一个解决方案为我工作。我需要使用malloc,因为我创建套接字的路径太长而无法进入sun_path,因为默认情况下它只允许使用104个字符。 –

+0

@ S.Vishwakarma在大多数Linux系统上,'sun_path'是108,[manpage](http://man7.org/linux/man-pages/man7/unix.7.html)说:“*长度的路径名,包括终止空字节,不应超过sun_path的大小......在对可移植应用程序进行编码时,请记住一些实现的sun_path只有92个字节。*“我期望在iOS中有类似的限制。如果'bind'和'sendto'正在接受更长的'sun_path'值,那不是可移植的行为。 –