147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2007 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macsocketserver.h"
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/common.h"
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macasyncsocket.h"
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macutils.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/thread.h"
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// MacBaseSocketServer
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacBaseSocketServer::MacBaseSocketServer() {
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacBaseSocketServer::~MacBaseSocketServer() {
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncSocket* MacBaseSocketServer::CreateAsyncSocket(int type) {
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return CreateAsyncSocket(AF_INET, type);
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgAsyncSocket* MacBaseSocketServer::CreateAsyncSocket(int family, int type) {
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (SOCK_STREAM != type)
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  MacAsyncSocket* socket = new MacAsyncSocket(this, family);
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!socket->valid()) {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    delete socket;
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return NULL;
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return socket;
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacBaseSocketServer::RegisterSocket(MacAsyncSocket* s) {
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  sockets_.insert(s);
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacBaseSocketServer::UnregisterSocket(MacAsyncSocket* s) {
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  VERIFY(1 == sockets_.erase(s));   // found 1
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacBaseSocketServer::SetPosixSignalHandler(int signum,
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                void (*handler)(int)) {
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Dispatcher* dispatcher = signal_dispatcher();
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!PhysicalSocketServer::SetPosixSignalHandler(signum, handler)) {
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Only register the FD once, when the first custom handler is installed.
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!dispatcher && (dispatcher = signal_dispatcher())) {
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFFileDescriptorContext ctx = { 0 };
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ctx.info = this;
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFFileDescriptorRef desc = CFFileDescriptorCreate(
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        kCFAllocatorDefault,
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        dispatcher->GetDescriptor(),
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        false,
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        &MacBaseSocketServer::FileDescriptorCallback,
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        &ctx);
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!desc) {
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFFileDescriptorEnableCallBacks(desc, kCFFileDescriptorReadCallBack);
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopSourceRef ref =
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, desc, 0);
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (!ref) {
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFRelease(desc);
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopAddSource(CFRunLoopGetCurrent(), ref, kCFRunLoopCommonModes);
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(desc);
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(ref);
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Used to disable socket events from waking our message queue when
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// process_io is false.  Does not disable signal event handling though.
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacBaseSocketServer::EnableSocketCallbacks(bool enable) {
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (std::set<MacAsyncSocket*>::iterator it = sockets().begin();
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org       it != sockets().end(); ++it) {
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (enable) {
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      (*it)->EnableCallbacks();
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      (*it)->DisableCallbacks();
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacBaseSocketServer::FileDescriptorCallback(CFFileDescriptorRef fd,
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                 CFOptionFlags flags,
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                 void* context) {
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  MacBaseSocketServer* this_ss =
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      reinterpret_cast<MacBaseSocketServer*>(context);
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(this_ss);
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  Dispatcher* signal_dispatcher = this_ss->signal_dispatcher();
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(signal_dispatcher);
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  signal_dispatcher->OnPreEvent(DE_READ);
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  signal_dispatcher->OnEvent(DE_READ, 0);
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFFileDescriptorEnableCallBacks(fd, kCFFileDescriptorReadCallBack);
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// MacCFSocketServer
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid WakeUpCallback(void* info) {
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  MacCFSocketServer* server = static_cast<MacCFSocketServer*>(info);
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(NULL != server);
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  server->OnWakeUpCallback();
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCFSocketServer::MacCFSocketServer()
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : run_loop_(CFRunLoopGetCurrent()),
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      wake_up_(NULL) {
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRunLoopSourceContext ctx;
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  memset(&ctx, 0, sizeof(ctx));
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ctx.info = this;
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ctx.perform = &WakeUpCallback;
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  wake_up_ = CFRunLoopSourceCreate(NULL, 0, &ctx);
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(NULL != wake_up_);
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (wake_up_) {
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopAddSource(run_loop_, wake_up_, kCFRunLoopCommonModes);
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCFSocketServer::~MacCFSocketServer() {
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (wake_up_) {
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopSourceInvalidate(wake_up_);
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(wake_up_);
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacCFSocketServer::Wait(int cms, bool process_io) {
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(CFRunLoopGetCurrent() == run_loop_);
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io && cms == 0) {
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // No op.
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return true;
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io) {
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // No way to listen to common modes and not get socket events, unless
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // we disable each one's callbacks.
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EnableSocketCallbacks(false);
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  SInt32 result;
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (kForever == cms) {
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    do {
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Would prefer to run in a custom mode that only listens to wake_up,
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // but we have qtkit sending work to the main thread which is effectively
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // blocked here, causing deadlock.  Thus listen to the common modes.
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // TODO: If QTKit becomes thread safe, do the above.
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10000000, false);
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } while (result != kCFRunLoopRunFinished && result != kCFRunLoopRunStopped);
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  } else {
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // TODO: In the case of 0ms wait, this will only process one event, so we
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // may want to loop until it returns TimedOut.
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFTimeInterval seconds = cms / 1000.0;
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, seconds, false);
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io) {
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Reenable them.  Hopefully this won't cause spurious callbacks or
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // missing ones while they were disabled.
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EnableSocketCallbacks(true);
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (kCFRunLoopRunFinished == result) {
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacCFSocketServer::WakeUp() {
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (wake_up_) {
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopSourceSignal(wake_up_);
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRunLoopWakeUp(run_loop_);
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacCFSocketServer::OnWakeUpCallback() {
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(run_loop_ == CFRunLoopGetCurrent());
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRunLoopStop(run_loop_);
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// MacCarbonSocketServer
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifndef CARBON_DEPRECATED
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst UInt32 kEventClassSocketServer = 'MCSS';
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst UInt32 kEventWakeUp = 'WAKE';
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgconst EventTypeSpec kEventWakeUpSpec[] = {
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  { kEventClassSocketServer, kEventWakeUp }
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstd::string DecodeEvent(EventRef event) {
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::string str;
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DecodeFourChar(::GetEventClass(event), &str);
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  str.push_back(':');
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DecodeFourChar(::GetEventKind(event), &str);
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return str;
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCarbonSocketServer::MacCarbonSocketServer()
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : event_queue_(GetCurrentEventQueue()), wake_up_(NULL) {
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  VERIFY(noErr == CreateEvent(NULL, kEventClassSocketServer, kEventWakeUp, 0,
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              kEventAttributeUserEvent, &wake_up_));
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCarbonSocketServer::~MacCarbonSocketServer() {
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (wake_up_) {
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ReleaseEvent(wake_up_);
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacCarbonSocketServer::Wait(int cms, bool process_io) {
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ASSERT(GetCurrentEventQueue() == event_queue_);
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Listen to all events if we're processing I/O.
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Only listen for our wakeup event if we're not.
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  UInt32 num_types = 0;
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const EventTypeSpec* events = NULL;
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io) {
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    num_types = GetEventTypeCount(kEventWakeUpSpec);
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    events = kEventWakeUpSpec;
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EventTargetRef target = GetEventDispatcherTarget();
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EventTimeout timeout =
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      (kForever == cms) ? kEventDurationForever : cms / 1000.0;
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EventTimeout end_time = GetCurrentEventTime() + timeout;
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool done = false;
25747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  while (!done) {
25847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EventRef event;
25947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    OSStatus result = ReceiveNextEvent(num_types, events, timeout, true,
26047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       &event);
26147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (noErr == result) {
26247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (wake_up_ != event) {
26347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        LOG_F(LS_VERBOSE) << "Dispatching event: " << DecodeEvent(event);
26447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        result = SendEventToEventTarget(event, target);
26547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        if ((noErr != result) && (eventNotHandledErr != result)) {
26647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          LOG_E(LS_ERROR, OS, result) << "SendEventToEventTarget";
26747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        }
26847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      } else {
26947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        done = true;
27047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
27147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ReleaseEvent(event);
27247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (eventLoopTimedOutErr == result) {
27347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ASSERT(cms != kForever);
27447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      done = true;
27547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else if (eventLoopQuitErr == result) {
27647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Ignore this... we get spurious quits for a variety of reasons.
27747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG_E(LS_VERBOSE, OS, result) << "ReceiveNextEvent";
27847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    } else {
27947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Some strange error occurred. Log it.
28047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG_E(LS_WARNING, OS, result) << "ReceiveNextEvent";
28147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return false;
28247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
28347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (kForever != cms) {
28447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      timeout = end_time - GetCurrentEventTime();
28547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
28647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
28747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
28847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
28947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
29047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacCarbonSocketServer::WakeUp() {
29147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!IsEventInQueue(event_queue_, wake_up_)) {
29247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    RetainEvent(wake_up_);
29347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    OSStatus result = PostEventToQueue(event_queue_, wake_up_,
29447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       kEventPriorityStandard);
29547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (noErr != result) {
29647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG_E(LS_ERROR, OS, result) << "PostEventToQueue";
29747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
29847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
29947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
30047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
30247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// MacCarbonAppSocketServer
30347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org///////////////////////////////////////////////////////////////////////////////
30447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
30547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCarbonAppSocketServer::MacCarbonAppSocketServer()
30647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    : event_queue_(GetCurrentEventQueue()) {
30747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Install event handler
30847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  VERIFY(noErr == InstallApplicationEventHandler(
30947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      NewEventHandlerUPP(WakeUpEventHandler), 1, kEventWakeUpSpec, this,
31047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      &event_handler_));
31147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
31247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Install a timer and set it idle to begin with.
31347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  VERIFY(noErr == InstallEventLoopTimer(GetMainEventLoop(),
31447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                        kEventDurationForever,
31547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                        kEventDurationForever,
31647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                        NewEventLoopTimerUPP(TimerHandler),
31747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                        this,
31847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                        &timer_));
31947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
32047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacCarbonAppSocketServer::~MacCarbonAppSocketServer() {
32247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  RemoveEventLoopTimer(timer_);
32347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  RemoveEventHandler(event_handler_);
32447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
32547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
32647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgOSStatus MacCarbonAppSocketServer::WakeUpEventHandler(
32747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EventHandlerCallRef next, EventRef event, void *data) {
32847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  QuitApplicationEventLoop();
32947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return noErr;
33047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
33147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
33247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacCarbonAppSocketServer::TimerHandler(
33347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EventLoopTimerRef timer, void *data) {
33447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  QuitApplicationEventLoop();
33547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
33647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
33747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacCarbonAppSocketServer::Wait(int cms, bool process_io) {
33847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io && cms == 0) {
33947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // No op.
34047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return true;
34147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
34247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (kForever != cms) {
34347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Start a timer.
34447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    OSStatus error =
34547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        SetEventLoopTimerNextFireTime(timer_, cms / 1000.0);
34647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (error != noErr) {
34747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Failed setting next fire time.";
34847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
34947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
35047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io) {
35147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // No way to listen to common modes and not get socket events, unless
35247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // we disable each one's callbacks.
35347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EnableSocketCallbacks(false);
35447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
35547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  RunApplicationEventLoop();
35647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!process_io) {
35747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Reenable them.  Hopefully this won't cause spurious callbacks or
35847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // missing ones while they were disabled.
35947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EnableSocketCallbacks(true);
36047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
36147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
36247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
36347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
36447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgvoid MacCarbonAppSocketServer::WakeUp() {
36547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO: No-op if there's already a WakeUp in flight.
36647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  EventRef wake_up;
36747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  VERIFY(noErr == CreateEvent(NULL, kEventClassSocketServer, kEventWakeUp, 0,
36847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                              kEventAttributeUserEvent, &wake_up));
36947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  OSStatus result = PostEventToQueue(event_queue_, wake_up,
37047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       kEventPriorityStandard);
37147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (noErr != result) {
37247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG_E(LS_ERROR, OS, result) << "PostEventToQueue";
37347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
37447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ReleaseEvent(wake_up);
37547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
37647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
37747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
37847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} // namespace rtc
379