2 // Copyright 2005 The Android Open Source Project
4 // Local named bi-directional communication channel.
6 #include "LocalBiChannel.h"
9 #if defined(HAVE_WIN32_IPC)
10 # define _WIN32_WINNT 0x0500
13 # include <sys/types.h>
14 # include <sys/socket.h>
15 # include <sys/stat.h>
27 * Our current set of ARM header files don't define this.
29 # define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) \
30 + strlen ((ptr)->sun_path))
33 using namespace android;
35 const unsigned long kInvalidHandle = (unsigned long) -1;
38 * Initialize data fields.
40 LocalBiChannel::LocalBiChannel(void)
41 : mFileName(NULL), mIsListener(false), mHandle(kInvalidHandle)
45 #if defined(HAVE_WIN32_IPC)
47 * Implementation for Win32, using named pipes.
49 * Cygwin actually supports UNIX-domain sockets, but we want to stuff
50 * the file handles into a Pipe, which uses HANDLE under Win32.
53 const int kPipeSize = 4096;
56 * Destructor. If we're the server side, we may need to clean up after
59 LocalBiChannel::~LocalBiChannel(void)
61 if (mHandle != kInvalidHandle)
62 CloseHandle((HANDLE)mHandle);
68 * Construct the full path. The caller must delete[] the return value.
70 static char* makeFilename(const char* name)
72 static const char* kBasePath = "\\\\.\\pipe\\android-";
75 assert(name != NULL && name[0] != '\0');
77 fileName = new char[strlen(kBasePath) + strlen(name) + 1];
78 strcpy(fileName, kBasePath);
79 strcat(fileName, name);
85 * Create a named pipe, so the client has something to connect to.
87 bool LocalBiChannel::create(const char* name)
90 mFileName = makeFilename(name);
95 hPipe = CreateNamedPipe(
96 mFileName, // unique pipe name
97 PIPE_ACCESS_DUPLEX | // open mode
98 FILE_FLAG_FIRST_PIPE_INSTANCE,
99 0, // pipe mode (byte, blocking)
101 kPipeSize, // output buffer
102 kPipeSize, // input buffer
103 NMPWAIT_USE_DEFAULT_WAIT, // client time-out
107 LOG(LOG_ERROR, "lbicomm",
108 "CreateNamedPipe failed (err=%ld)\n", GetLastError());
112 mHandle = (unsigned long) hPipe;
119 * Attach to an existing named pipe.
121 bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
124 HANDLE hPipe, dupHandle;
127 mFileName = makeFilename(name);
130 mFileName, // filename
131 GENERIC_READ | GENERIC_WRITE, // access
134 OPEN_EXISTING, // don't create
137 if (hPipe == INVALID_HANDLE_VALUE) {
138 LOG(LOG_ERROR, "lbicomm",
139 "CreateFile on pipe '%s' failed (err=%ld)\n", name, GetLastError());
143 assert(mHandle == kInvalidHandle);
146 * Set up the pipes. Use the new handle for one, and a duplicate
147 * of it for the other, in case we decide to only close one side.
149 *ppReadPipe = new Pipe();
150 (*ppReadPipe)->createReader((unsigned long) hPipe);
159 DUPLICATE_SAME_ACCESS);
160 *ppWritePipe = new Pipe();
161 (*ppWritePipe)->createWriter((unsigned long) dupHandle);
167 * Listen for a new connection, discarding any existing connection.
169 bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
175 * Create up to 3 instances of the named pipe:
176 * - currently active connection
177 * - connection currently being rejected because one is already active
178 * - a new listener to wait for the next round
180 hPipe = CreateNamedPipe(
181 mFileName, // unique pipe name
182 PIPE_ACCESS_DUPLEX // open mode
183 /*| FILE_FLAG_FIRST_PIPE_INSTANCE*/,
184 0, // pipe mode (byte, blocking)
186 kPipeSize, // output buffer
187 kPipeSize, // input buffer
188 NMPWAIT_USE_DEFAULT_WAIT, // client time-out
192 LOG(LOG_ERROR, "lbicomm",
193 "CreateNamedPipe failed (err=%ld)\n", GetLastError());
198 * If a client is already connected to us, this fails with
199 * ERROR_PIPE_CONNECTED. It returns success if we had to wait
200 * a little bit before the connection happens.
202 connected = ConnectNamedPipe(hPipe, NULL) ?
203 TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
207 * Create the pipes. Give one a duplicated handle so that,
208 * when one closes, we don't lose both.
212 *ppReadPipe = new Pipe();
213 (*ppReadPipe)->createReader((unsigned long) hPipe);
222 DUPLICATE_SAME_ACCESS);
223 *ppWritePipe = new Pipe();
224 (*ppWritePipe)->createWriter((unsigned long) dupHandle);
228 LOG(LOG_WARN, "lbicomm",
229 "ConnectNamedPipe failed (err=%ld)\n", GetLastError());
230 #ifdef HAVE_WIN32_THREADS
231 Sleep(500); /* 500 ms */
233 usleep(500000); // DEBUG DEBUG
242 * Implementation for Linux and Darwin, using UNIX-domain sockets.
246 * Destructor. If we're the server side, blow away the socket file.
248 LocalBiChannel::~LocalBiChannel(void)
250 if (mHandle != kInvalidHandle)
251 close((int) mHandle);
253 if (mIsListener && mFileName != NULL) {
254 LOG(LOG_DEBUG, "lbicomm", "Removing '%s'\n", mFileName);
255 (void) unlink(mFileName);
261 * Construct the full path. The caller must delete[] the return value.
263 static char* makeFilename(const char* name)
265 static const char* kBasePath = "/tmp/android-";
268 assert(name != NULL && name[0] != '\0');
270 fileName = new char[strlen(kBasePath) + strlen(name) + 1];
271 strcpy(fileName, kBasePath);
272 strcat(fileName, name);
278 * Create a UNIX domain socket, carefully removing it if it already
281 bool LocalBiChannel::create(const char* name)
289 mFileName = makeFilename(name);
291 cc = stat(mFileName, &sb);
293 if (errno != ENOENT) {
294 LOG(LOG_ERROR, "lbicomm",
295 "Unable to stat '%s' (errno=%d)\n", mFileName, errno);
299 /* don't touch it if it's not a socket */
300 if (!(S_ISSOCK(sb.st_mode))) {
301 LOG(LOG_ERROR, "lbicomm",
302 "File '%s' exists and is not a socket\n", mFileName);
306 /* remove the cruft */
307 if (unlink(mFileName) < 0) {
308 LOG(LOG_ERROR, "lbicomm",
309 "Unable to remove '%s' (errno=%d)\n", mFileName, errno);
314 struct sockaddr_un addr;
316 sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
318 LOG(LOG_ERROR, "lbicomm",
319 "UNIX domain socket create failed (errno=%d)\n", errno);
323 /* bind the socket; this creates the file on disk */
324 strcpy(addr.sun_path, mFileName); // max 108 bytes
325 addr.sun_family = AF_UNIX;
326 cc = ::bind(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
328 LOG(LOG_ERROR, "lbicomm",
329 "AF_UNIX bind failed for '%s' (errno=%d)\n", mFileName, errno);
333 mHandle = (unsigned long) sock;
345 * Attach to an existing UNIX domain socket.
347 bool LocalBiChannel::attach(const char* name, Pipe** ppReadPipe,
354 assert(ppReadPipe != NULL);
355 assert(ppWritePipe != NULL);
358 mFileName = makeFilename(name);
360 struct sockaddr_un addr;
362 sock = ::socket(AF_UNIX, SOCK_STREAM, 0);
364 LOG(LOG_ERROR, "lbicomm",
365 "UNIX domain socket create failed (errno=%d)\n", errno);
369 /* connect to socket; fails if file doesn't exist */
370 strcpy(addr.sun_path, mFileName); // max 108 bytes
371 addr.sun_family = AF_UNIX;
372 cc = ::connect(sock, (struct sockaddr*) &addr, SUN_LEN(&addr));
374 // ENOENT means socket file doesn't exist
375 // ECONNREFUSED means socket exists but nobody is listening
376 LOG(LOG_ERROR, "lbicomm",
377 "AF_UNIX connect failed for '%s': %s\n", mFileName,strerror(errno));
382 * Create the two halves. We dup() the sock so that closing one side
383 * does not hose the other.
385 *ppReadPipe = new Pipe();
386 (*ppReadPipe)->createReader(sock);
387 *ppWritePipe = new Pipe();
388 (*ppWritePipe)->createWriter(dup(sock));
390 assert(mHandle == kInvalidHandle);
403 * Listen for a new connection.
405 bool LocalBiChannel::listen(Pipe** ppReadPipe, Pipe** ppWritePipe)
408 struct sockaddr_un from;
413 assert(mHandle != kInvalidHandle);
414 lsock = (int) mHandle;
416 LOG(LOG_DEBUG, "lbicomm", "AF_UNIX listening\n");
417 cc = ::listen(lsock, 5);
419 LOG(LOG_ERROR, "lbicomm", "AF_UNIX listen failed (errno=%d)\n", errno);
423 fromlen = sizeof(from); // not SUN_LEN()
424 sock = ::accept(lsock, (struct sockaddr*) &from, &fromlen);
426 LOG(LOG_WARN, "lbicomm", "AF_UNIX accept failed (errno=%d)\n", errno);
431 * Create the two halves. We dup() the sock so that closing one side
432 * does not hose the other.
434 *ppReadPipe = new Pipe();
435 (*ppReadPipe)->createReader(sock);
436 *ppWritePipe = new Pipe();
437 (*ppWritePipe)->createWriter(dup(sock));