1 //===-- DomainSocket.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/Host/posix/DomainSocket.h"
11 
12 #include "lldb/Host/FileSystem.h"
13 
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 #ifdef __ANDROID__
21 // Android does not have SUN_LEN
22 #ifndef SUN_LEN
23 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen((ptr)->sun_path))
24 #endif
25 #endif // #ifdef __ANDROID__
26 
27 namespace {
28 
29 const int kDomain = AF_UNIX;
30 const int kType   = SOCK_STREAM;
31 
32 bool SetSockAddr(llvm::StringRef name, const size_t name_offset, sockaddr_un* saddr_un)
33 {
34     if (name.size() + name_offset > sizeof(saddr_un->sun_path))
35         return false;
36 
37     saddr_un->sun_family = kDomain;
38     memset(saddr_un->sun_path, 0, sizeof(saddr_un->sun_path));
39 
40     strncpy(&saddr_un->sun_path[name_offset], name.data(), name.size());
41 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
42     saddr_un->sun_len = SUN_LEN (saddr_un);
43 #endif
44     return true;
45 }
46 
47 }
48 
49 DomainSocket::DomainSocket(NativeSocket socket)
50     : Socket(socket, ProtocolUnixDomain, true)
51 {
52 }
53 
54 DomainSocket::DomainSocket(bool child_processes_inherit, Error &error)
55     : DomainSocket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error))
56 {
57 }
58 
59 DomainSocket::DomainSocket(SocketProtocol protocol, bool child_processes_inherit, Error &error)
60     : Socket(CreateSocket(kDomain, kType, 0, child_processes_inherit, error), protocol, true)
61 {
62 }
63 
64 Error
65 DomainSocket::Connect(llvm::StringRef name)
66 {
67     sockaddr_un saddr_un;
68     if (!SetSockAddr(name, GetNameOffset(), &saddr_un))
69         return Error("Failed to set socket address");
70 
71     Error error;
72     if (::connect(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) < 0)
73         SetLastError (error);
74 
75     return error;
76 }
77 
78 Error
79 DomainSocket::Listen(llvm::StringRef name, int backlog)
80 {
81     sockaddr_un saddr_un;
82     if (!SetSockAddr(name, GetNameOffset(), &saddr_un))
83         return Error("Failed to set socket address");
84 
85     DeleteSocketFile(name);
86 
87     Error error;
88     if (::bind(GetNativeSocket(), (struct sockaddr *)&saddr_un, sizeof(saddr_un)) == 0)
89         if (::listen(GetNativeSocket(), backlog) == 0)
90             return error;
91 
92     SetLastError(error);
93     return error;
94 }
95 
96 Error
97 DomainSocket::Accept(llvm::StringRef name, bool child_processes_inherit, Socket *&socket)
98 {
99     Error error;
100     auto conn_fd = AcceptSocket(GetNativeSocket(), nullptr, nullptr, child_processes_inherit, error);
101     if (error.Success())
102         socket = new DomainSocket(conn_fd);
103 
104     return error;
105 }
106 
107 size_t
108 DomainSocket::GetNameOffset() const
109 {
110     return 0;
111 }
112 
113 void
114 DomainSocket::DeleteSocketFile(llvm::StringRef name)
115 {
116     FileSystem::Unlink(FileSpec{name, true});
117 }
118