|
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ |
|
2 /* vim: set ts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include <fcntl.h> |
|
8 #include "UnixSocketWatcher.h" |
|
9 |
|
10 namespace mozilla { |
|
11 namespace ipc { |
|
12 |
|
13 UnixSocketWatcher::~UnixSocketWatcher() |
|
14 { |
|
15 } |
|
16 |
|
17 void UnixSocketWatcher::Close() |
|
18 { |
|
19 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
20 |
|
21 mConnectionStatus = SOCKET_IS_DISCONNECTED; |
|
22 UnixFdWatcher::Close(); |
|
23 } |
|
24 |
|
25 nsresult |
|
26 UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen) |
|
27 { |
|
28 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
29 MOZ_ASSERT(IsOpen()); |
|
30 MOZ_ASSERT(aAddr || !aAddrLen); |
|
31 |
|
32 if (connect(GetFd(), aAddr, aAddrLen) < 0) { |
|
33 if (errno == EINPROGRESS) { |
|
34 mConnectionStatus = SOCKET_IS_CONNECTING; |
|
35 // Set up a write watch to receive the connect signal |
|
36 AddWatchers(WRITE_WATCHER, false); |
|
37 } else { |
|
38 OnError("connect", errno); |
|
39 } |
|
40 return NS_ERROR_FAILURE; |
|
41 } |
|
42 |
|
43 mConnectionStatus = SOCKET_IS_CONNECTED; |
|
44 OnConnected(); |
|
45 |
|
46 return NS_OK; |
|
47 } |
|
48 |
|
49 nsresult |
|
50 UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen) |
|
51 { |
|
52 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
53 MOZ_ASSERT(IsOpen()); |
|
54 MOZ_ASSERT(aAddr || !aAddrLen); |
|
55 |
|
56 if (bind(GetFd(), aAddr, aAddrLen) < 0) { |
|
57 OnError("bind", errno); |
|
58 return NS_ERROR_FAILURE; |
|
59 } |
|
60 if (listen(GetFd(), 1) < 0) { |
|
61 OnError("listen", errno); |
|
62 return NS_ERROR_FAILURE; |
|
63 } |
|
64 mConnectionStatus = SOCKET_IS_LISTENING; |
|
65 OnListening(); |
|
66 |
|
67 return NS_OK; |
|
68 } |
|
69 |
|
70 UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop) |
|
71 : UnixFdWatcher(aIOLoop) |
|
72 , mConnectionStatus(SOCKET_IS_DISCONNECTED) |
|
73 { |
|
74 } |
|
75 |
|
76 UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd, |
|
77 ConnectionStatus aConnectionStatus) |
|
78 : UnixFdWatcher(aIOLoop, aFd) |
|
79 , mConnectionStatus(aConnectionStatus) |
|
80 { |
|
81 } |
|
82 |
|
83 void |
|
84 UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus) |
|
85 { |
|
86 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
87 |
|
88 SetFd(aFd); |
|
89 mConnectionStatus = aConnectionStatus; |
|
90 } |
|
91 |
|
92 void |
|
93 UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd) |
|
94 { |
|
95 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
96 MOZ_ASSERT(aFd == GetFd()); |
|
97 |
|
98 if (mConnectionStatus == SOCKET_IS_CONNECTED) { |
|
99 OnSocketCanReceiveWithoutBlocking(); |
|
100 } else if (mConnectionStatus == SOCKET_IS_LISTENING) { |
|
101 sockaddr_any addr; |
|
102 socklen_t addrLen = sizeof(addr); |
|
103 int fd = TEMP_FAILURE_RETRY(accept(GetFd(), |
|
104 reinterpret_cast<struct sockaddr*>(&addr), &addrLen)); |
|
105 if (fd < 0) { |
|
106 OnError("accept", errno); |
|
107 } else { |
|
108 OnAccepted(fd, &addr, addrLen); |
|
109 } |
|
110 } else { |
|
111 NS_NOTREACHED("invalid connection state for reading"); |
|
112 } |
|
113 } |
|
114 |
|
115 void |
|
116 UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd) |
|
117 { |
|
118 MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop()); |
|
119 MOZ_ASSERT(aFd == GetFd()); |
|
120 |
|
121 if (mConnectionStatus == SOCKET_IS_CONNECTED) { |
|
122 OnSocketCanSendWithoutBlocking(); |
|
123 } else if (mConnectionStatus == SOCKET_IS_CONNECTING) { |
|
124 RemoveWatchers(WRITE_WATCHER); |
|
125 int error = 0; |
|
126 socklen_t len = sizeof(error); |
|
127 if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
|
128 OnError("getsockopt", errno); |
|
129 } else if (error) { |
|
130 OnError("connect", error); |
|
131 } else { |
|
132 mConnectionStatus = SOCKET_IS_CONNECTED; |
|
133 OnConnected(); |
|
134 } |
|
135 } else { |
|
136 NS_NOTREACHED("invalid connection state for writing"); |
|
137 } |
|
138 } |
|
139 |
|
140 } |
|
141 } |