mirror of https://github.com/grpc/grpc.git
commit
d7728cda51
60 changed files with 3467 additions and 179 deletions
@ -0,0 +1,183 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
#import <CoreFoundation/CoreFoundation.h> |
||||
#import "src/core/lib/iomgr/cfstream_handle.h" |
||||
|
||||
#include <grpc/support/atm.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/exec_ctx.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
void* CFStreamHandle::Retain(void* info) { |
||||
CFStreamHandle* handle = static_cast<CFStreamHandle*>(info); |
||||
CFSTREAM_HANDLE_REF(handle, "retain"); |
||||
return info; |
||||
} |
||||
|
||||
void CFStreamHandle::Release(void* info) { |
||||
CFStreamHandle* handle = static_cast<CFStreamHandle*>(info); |
||||
CFSTREAM_HANDLE_UNREF(handle, "release"); |
||||
} |
||||
|
||||
CFStreamHandle* CFStreamHandle::CreateStreamHandle( |
||||
CFReadStreamRef read_stream, CFWriteStreamRef write_stream) { |
||||
return new CFStreamHandle(read_stream, write_stream); |
||||
} |
||||
|
||||
void CFStreamHandle::ReadCallback(CFReadStreamRef stream, |
||||
CFStreamEventType type, |
||||
void* client_callback_info) { |
||||
CFStreamHandle* handle = static_cast<CFStreamHandle*>(client_callback_info); |
||||
CFSTREAM_HANDLE_REF(handle, "read callback"); |
||||
dispatch_async( |
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream ReadCallback (%p, %p, %lu, %p)", handle, |
||||
stream, type, client_callback_info); |
||||
} |
||||
switch (type) { |
||||
case kCFStreamEventOpenCompleted: |
||||
handle->open_event_.SetReady(); |
||||
break; |
||||
case kCFStreamEventHasBytesAvailable: |
||||
case kCFStreamEventEndEncountered: |
||||
handle->read_event_.SetReady(); |
||||
break; |
||||
case kCFStreamEventErrorOccurred: |
||||
handle->open_event_.SetReady(); |
||||
handle->read_event_.SetReady(); |
||||
break; |
||||
default: |
||||
GPR_UNREACHABLE_CODE(return ); |
||||
} |
||||
CFSTREAM_HANDLE_UNREF(handle, "read callback"); |
||||
}); |
||||
} |
||||
void CFStreamHandle::WriteCallback(CFWriteStreamRef stream, |
||||
CFStreamEventType type, |
||||
void* clientCallBackInfo) { |
||||
CFStreamHandle* handle = static_cast<CFStreamHandle*>(clientCallBackInfo); |
||||
CFSTREAM_HANDLE_REF(handle, "write callback"); |
||||
dispatch_async( |
||||
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
||||
grpc_core::ExecCtx exec_ctx; |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream WriteCallback (%p, %p, %lu, %p)", handle, |
||||
stream, type, clientCallBackInfo); |
||||
} |
||||
switch (type) { |
||||
case kCFStreamEventOpenCompleted: |
||||
handle->open_event_.SetReady(); |
||||
break; |
||||
case kCFStreamEventCanAcceptBytes: |
||||
case kCFStreamEventEndEncountered: |
||||
handle->write_event_.SetReady(); |
||||
break; |
||||
case kCFStreamEventErrorOccurred: |
||||
handle->open_event_.SetReady(); |
||||
handle->write_event_.SetReady(); |
||||
break; |
||||
default: |
||||
GPR_UNREACHABLE_CODE(return ); |
||||
} |
||||
CFSTREAM_HANDLE_UNREF(handle, "write callback"); |
||||
}); |
||||
} |
||||
|
||||
CFStreamHandle::CFStreamHandle(CFReadStreamRef read_stream, |
||||
CFWriteStreamRef write_stream) { |
||||
gpr_ref_init(&refcount_, 1); |
||||
open_event_.InitEvent(); |
||||
read_event_.InitEvent(); |
||||
write_event_.InitEvent(); |
||||
CFStreamClientContext ctx = {0, static_cast<void*>(this), nil, nil, nil}; |
||||
CFReadStreamSetClient( |
||||
read_stream, |
||||
kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable | |
||||
kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, |
||||
CFStreamHandle::ReadCallback, &ctx); |
||||
CFWriteStreamSetClient( |
||||
write_stream, |
||||
kCFStreamEventOpenCompleted | kCFStreamEventCanAcceptBytes | |
||||
kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, |
||||
CFStreamHandle::WriteCallback, &ctx); |
||||
CFReadStreamScheduleWithRunLoop(read_stream, CFRunLoopGetMain(), |
||||
kCFRunLoopCommonModes); |
||||
CFWriteStreamScheduleWithRunLoop(write_stream, CFRunLoopGetMain(), |
||||
kCFRunLoopCommonModes); |
||||
} |
||||
|
||||
CFStreamHandle::~CFStreamHandle() { |
||||
open_event_.DestroyEvent(); |
||||
read_event_.DestroyEvent(); |
||||
write_event_.DestroyEvent(); |
||||
} |
||||
|
||||
void CFStreamHandle::NotifyOnOpen(grpc_closure* closure) { |
||||
open_event_.NotifyOn(closure); |
||||
} |
||||
|
||||
void CFStreamHandle::NotifyOnRead(grpc_closure* closure) { |
||||
read_event_.NotifyOn(closure); |
||||
} |
||||
|
||||
void CFStreamHandle::NotifyOnWrite(grpc_closure* closure) { |
||||
write_event_.NotifyOn(closure); |
||||
} |
||||
|
||||
void CFStreamHandle::Shutdown(grpc_error* error) { |
||||
open_event_.SetShutdown(GRPC_ERROR_REF(error)); |
||||
read_event_.SetShutdown(GRPC_ERROR_REF(error)); |
||||
write_event_.SetShutdown(GRPC_ERROR_REF(error)); |
||||
GRPC_ERROR_UNREF(error); |
||||
} |
||||
|
||||
void CFStreamHandle::Ref(const char* file, int line, const char* reason) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&refcount_.count); |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, |
||||
"CFStream Handle ref %p : %s %" PRIdPTR " -> %" PRIdPTR, this, |
||||
reason, val, val + 1); |
||||
} |
||||
gpr_ref(&refcount_); |
||||
} |
||||
|
||||
void CFStreamHandle::Unref(const char* file, int line, const char* reason) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&refcount_.count); |
||||
gpr_log(GPR_ERROR, |
||||
"CFStream Handle unref %p : %s %" PRIdPTR " -> %" PRIdPTR, this, |
||||
reason, val, val - 1); |
||||
} |
||||
if (gpr_unref(&refcount_)) { |
||||
delete this; |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,80 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
/* The CFStream handle acts as an event synchronization entity for
|
||||
* read/write/open/error/eos events happening on CFStream streams. */ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_CFSTREAM_HANDLE_H |
||||
#define GRPC_CORE_LIB_IOMGR_CFSTREAM_HANDLE_H |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
#import <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/lockfree_event.h" |
||||
|
||||
class CFStreamHandle final { |
||||
public: |
||||
static CFStreamHandle* CreateStreamHandle(CFReadStreamRef read_stream, |
||||
CFWriteStreamRef write_stream); |
||||
~CFStreamHandle(); |
||||
CFStreamHandle(const CFReadStreamRef& ref) = delete; |
||||
CFStreamHandle(CFReadStreamRef&& ref) = delete; |
||||
CFStreamHandle& operator=(const CFStreamHandle& rhs) = delete; |
||||
|
||||
void NotifyOnOpen(grpc_closure* closure); |
||||
void NotifyOnRead(grpc_closure* closure); |
||||
void NotifyOnWrite(grpc_closure* closure); |
||||
void Shutdown(grpc_error* error); |
||||
|
||||
void Ref(const char* file = "", int line = 0, const char* reason = nullptr); |
||||
void Unref(const char* file = "", int line = 0, const char* reason = nullptr); |
||||
|
||||
private: |
||||
CFStreamHandle(CFReadStreamRef read_stream, CFWriteStreamRef write_stream); |
||||
static void ReadCallback(CFReadStreamRef stream, CFStreamEventType type, |
||||
void* client_callback_info); |
||||
static void WriteCallback(CFWriteStreamRef stream, CFStreamEventType type, |
||||
void* client_callback_info); |
||||
static void* Retain(void* info); |
||||
static void Release(void* info); |
||||
|
||||
grpc_core::LockfreeEvent open_event_; |
||||
grpc_core::LockfreeEvent read_event_; |
||||
grpc_core::LockfreeEvent write_event_; |
||||
|
||||
gpr_refcount refcount_; |
||||
}; |
||||
|
||||
#ifdef DEBUG |
||||
#define CFSTREAM_HANDLE_REF(handle, reason) \ |
||||
(handle)->Ref(__FILE__, __LINE__, (reason)) |
||||
#define CFSTREAM_HANDLE_UNREF(handle, reason) \ |
||||
(handle)->Unref(__FILE__, __LINE__, (reason)) |
||||
#else |
||||
#define CFSTREAM_HANDLE_REF(handle, reason) (handle)->Ref() |
||||
#define CFSTREAM_HANDLE_UNREF(handle, reason) (handle)->Unref() |
||||
#endif |
||||
|
||||
#endif |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_CFSTREAM_HANDLE_H */ |
@ -0,0 +1,372 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM_ENDPOINT |
||||
|
||||
#import <CoreFoundation/CoreFoundation.h> |
||||
#import "src/core/lib/iomgr/endpoint_cfstream.h" |
||||
|
||||
#include <grpc/slice_buffer.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/gpr/string.h" |
||||
#include "src/core/lib/iomgr/cfstream_handle.h" |
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
#include "src/core/lib/iomgr/error_cfstream.h" |
||||
#include "src/core/lib/slice/slice_internal.h" |
||||
#include "src/core/lib/slice/slice_string_helpers.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
typedef struct { |
||||
grpc_endpoint base; |
||||
gpr_refcount refcount; |
||||
|
||||
CFReadStreamRef read_stream; |
||||
CFWriteStreamRef write_stream; |
||||
CFStreamHandle* stream_sync; |
||||
|
||||
grpc_closure* read_cb; |
||||
grpc_closure* write_cb; |
||||
grpc_slice_buffer* read_slices; |
||||
grpc_slice_buffer* write_slices; |
||||
|
||||
grpc_closure read_action; |
||||
grpc_closure write_action; |
||||
|
||||
char* peer_string; |
||||
grpc_resource_user* resource_user; |
||||
grpc_resource_user_slice_allocator slice_allocator; |
||||
} CFStreamEndpoint; |
||||
|
||||
static void CFStreamFree(CFStreamEndpoint* ep) { |
||||
grpc_resource_user_unref(ep->resource_user); |
||||
CFRelease(ep->read_stream); |
||||
CFRelease(ep->write_stream); |
||||
CFSTREAM_HANDLE_UNREF(ep->stream_sync, "free"); |
||||
gpr_free(ep->peer_string); |
||||
gpr_free(ep); |
||||
} |
||||
|
||||
#ifndef NDEBUG |
||||
#define EP_REF(ep, reason) CFStreamRef((ep), (reason), __FILE__, __LINE__) |
||||
#define EP_UNREF(ep, reason) CFStreamUnref((ep), (reason), __FILE__, __LINE__) |
||||
static void CFStreamUnref(CFStreamEndpoint* ep, const char* reason, |
||||
const char* file, int line) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&ep->refcount.count); |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, |
||||
"CFStream endpoint unref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, |
||||
reason, val, val - 1); |
||||
} |
||||
if (gpr_unref(&ep->refcount)) { |
||||
CFStreamFree(ep); |
||||
} |
||||
} |
||||
static void CFStreamRef(CFStreamEndpoint* ep, const char* reason, |
||||
const char* file, int line) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_atm val = gpr_atm_no_barrier_load(&ep->refcount.count); |
||||
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, |
||||
"CFStream endpoint ref %p : %s %" PRIdPTR " -> %" PRIdPTR, ep, |
||||
reason, val, val + 1); |
||||
} |
||||
gpr_ref(&ep->refcount); |
||||
} |
||||
#else |
||||
#define EP_REF(ep, reason) CFStreamRef((ep)) |
||||
#define EP_UNREF(ep, reason) CFStreamUnref((ep)) |
||||
static void CFStreamUnref(CFStreamEndpoint* ep) { |
||||
if (gpr_unref(&ep->refcount)) { |
||||
CFStreamFree(ep); |
||||
} |
||||
} |
||||
static void CFStreamRef(CFStreamEndpoint* ep) { gpr_ref(&ep->refcount); } |
||||
#endif |
||||
|
||||
static grpc_error* CFStreamAnnotateError(grpc_error* src_error, |
||||
CFStreamEndpoint* ep) { |
||||
return grpc_error_set_str( |
||||
grpc_error_set_int(src_error, GRPC_ERROR_INT_GRPC_STATUS, |
||||
GRPC_STATUS_UNAVAILABLE), |
||||
GRPC_ERROR_STR_TARGET_ADDRESS, |
||||
grpc_slice_from_copied_string(ep->peer_string)); |
||||
} |
||||
|
||||
static void CallReadCb(CFStreamEndpoint* ep, grpc_error* error) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_read_cb %p %p:%p", ep, |
||||
ep->read_cb, ep->read_cb->cb, ep->read_cb->cb_arg); |
||||
size_t i; |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "read: error=%s", str); |
||||
|
||||
for (i = 0; i < ep->read_slices->count; i++) { |
||||
char* dump = grpc_dump_slice(ep->read_slices->slices[i], |
||||
GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_DEBUG, "READ %p (peer=%s): %s", ep, ep->peer_string, dump); |
||||
gpr_free(dump); |
||||
} |
||||
} |
||||
grpc_closure* cb = ep->read_cb; |
||||
ep->read_cb = nullptr; |
||||
ep->read_slices = nullptr; |
||||
GRPC_CLOSURE_SCHED(cb, error); |
||||
} |
||||
|
||||
static void CallWriteCb(CFStreamEndpoint* ep, grpc_error* error) { |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p call_write_cb %p %p:%p", ep, |
||||
ep->write_cb, ep->write_cb->cb, ep->write_cb->cb_arg); |
||||
const char* str = grpc_error_string(error); |
||||
gpr_log(GPR_DEBUG, "write: error=%s", str); |
||||
} |
||||
grpc_closure* cb = ep->write_cb; |
||||
ep->write_cb = nullptr; |
||||
ep->write_slices = nullptr; |
||||
GRPC_CLOSURE_SCHED(cb, error); |
||||
} |
||||
|
||||
static void ReadAction(void* arg, grpc_error* error) { |
||||
CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg); |
||||
GPR_ASSERT(ep->read_cb != nullptr); |
||||
if (error) { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->read_slices); |
||||
CallReadCb(ep, GRPC_ERROR_REF(error)); |
||||
EP_UNREF(ep, "read"); |
||||
return; |
||||
} |
||||
|
||||
GPR_ASSERT(ep->read_slices->count == 1); |
||||
grpc_slice slice = ep->read_slices->slices[0]; |
||||
size_t len = GRPC_SLICE_LENGTH(slice); |
||||
CFIndex read_size = |
||||
CFReadStreamRead(ep->read_stream, GRPC_SLICE_START_PTR(slice), len); |
||||
if (read_size == -1) { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->read_slices); |
||||
CFErrorRef stream_error = CFReadStreamCopyError(ep->read_stream); |
||||
if (stream_error != nullptr) { |
||||
error = CFStreamAnnotateError( |
||||
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "Read error"), ep); |
||||
CFRelease(stream_error); |
||||
} else { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Read error"); |
||||
} |
||||
CallReadCb(ep, error); |
||||
EP_UNREF(ep, "read"); |
||||
} else if (read_size == 0) { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->read_slices); |
||||
CallReadCb(ep, |
||||
CFStreamAnnotateError( |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Socket closed"), ep)); |
||||
EP_UNREF(ep, "read"); |
||||
} else { |
||||
if (read_size < len) { |
||||
grpc_slice_buffer_trim_end(ep->read_slices, len - read_size, nullptr); |
||||
} |
||||
CallReadCb(ep, GRPC_ERROR_NONE); |
||||
EP_UNREF(ep, "read"); |
||||
} |
||||
} |
||||
|
||||
static void WriteAction(void* arg, grpc_error* error) { |
||||
CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg); |
||||
GPR_ASSERT(ep->write_cb != nullptr); |
||||
if (error) { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->write_slices); |
||||
CallWriteCb(ep, GRPC_ERROR_REF(error)); |
||||
EP_UNREF(ep, "write"); |
||||
return; |
||||
} |
||||
|
||||
grpc_slice slice = grpc_slice_buffer_take_first(ep->write_slices); |
||||
size_t slice_len = GRPC_SLICE_LENGTH(slice); |
||||
CFIndex write_size = CFWriteStreamWrite( |
||||
ep->write_stream, GRPC_SLICE_START_PTR(slice), slice_len); |
||||
if (write_size == -1) { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->write_slices); |
||||
CFErrorRef stream_error = CFWriteStreamCopyError(ep->write_stream); |
||||
if (stream_error != nullptr) { |
||||
error = CFStreamAnnotateError( |
||||
GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "write failed."), ep); |
||||
CFRelease(stream_error); |
||||
} else { |
||||
error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("write failed."); |
||||
} |
||||
CallWriteCb(ep, error); |
||||
EP_UNREF(ep, "write"); |
||||
} else { |
||||
if (write_size < GRPC_SLICE_LENGTH(slice)) { |
||||
grpc_slice_buffer_undo_take_first( |
||||
ep->write_slices, grpc_slice_sub(slice, write_size, slice_len)); |
||||
} |
||||
if (ep->write_slices->length > 0) { |
||||
ep->stream_sync->NotifyOnWrite(&ep->write_action); |
||||
} else { |
||||
CallWriteCb(ep, GRPC_ERROR_NONE); |
||||
EP_UNREF(ep, "write"); |
||||
} |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
grpc_slice trace_slice = grpc_slice_sub(slice, 0, write_size); |
||||
char* dump = grpc_dump_slice(trace_slice, GPR_DUMP_HEX | GPR_DUMP_ASCII); |
||||
gpr_log(GPR_DEBUG, "WRITE %p (peer=%s): %s", ep, ep->peer_string, dump); |
||||
gpr_free(dump); |
||||
grpc_slice_unref_internal(trace_slice); |
||||
} |
||||
} |
||||
grpc_slice_unref_internal(slice); |
||||
} |
||||
|
||||
static void CFStreamReadAllocationDone(void* arg, grpc_error* error) { |
||||
CFStreamEndpoint* ep = static_cast<CFStreamEndpoint*>(arg); |
||||
if (error == GRPC_ERROR_NONE) { |
||||
ep->stream_sync->NotifyOnRead(&ep->read_action); |
||||
} else { |
||||
grpc_slice_buffer_reset_and_unref_internal(ep->read_slices); |
||||
CallReadCb(ep, error); |
||||
EP_UNREF(ep, "read"); |
||||
} |
||||
} |
||||
|
||||
static void CFStreamRead(grpc_endpoint* ep, grpc_slice_buffer* slices, |
||||
grpc_closure* cb) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p read (%p, %p) length:%zu", ep_impl, |
||||
slices, cb, slices->length); |
||||
} |
||||
GPR_ASSERT(ep_impl->read_cb == nullptr); |
||||
ep_impl->read_cb = cb; |
||||
ep_impl->read_slices = slices; |
||||
grpc_slice_buffer_reset_and_unref_internal(slices); |
||||
grpc_resource_user_alloc_slices(&ep_impl->slice_allocator, |
||||
GRPC_TCP_DEFAULT_READ_SLICE_SIZE, 1, |
||||
ep_impl->read_slices); |
||||
EP_REF(ep_impl, "read"); |
||||
} |
||||
|
||||
static void CFStreamWrite(grpc_endpoint* ep, grpc_slice_buffer* slices, |
||||
grpc_closure* cb) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p write (%p, %p) length:%zu", |
||||
ep_impl, slices, cb, slices->length); |
||||
} |
||||
GPR_ASSERT(ep_impl->write_cb == nullptr); |
||||
ep_impl->write_cb = cb; |
||||
ep_impl->write_slices = slices; |
||||
EP_REF(ep_impl, "write"); |
||||
ep_impl->stream_sync->NotifyOnWrite(&ep_impl->write_action); |
||||
} |
||||
|
||||
void CFStreamShutdown(grpc_endpoint* ep, grpc_error* why) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p shutdown (%p)", ep_impl, why); |
||||
} |
||||
CFReadStreamClose(ep_impl->read_stream); |
||||
CFWriteStreamClose(ep_impl->write_stream); |
||||
ep_impl->stream_sync->Shutdown(why); |
||||
grpc_resource_user_shutdown(ep_impl->resource_user); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p shutdown DONE (%p)", ep_impl, why); |
||||
} |
||||
} |
||||
|
||||
void CFStreamDestroy(grpc_endpoint* ep) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CFStream endpoint:%p destroy", ep_impl); |
||||
} |
||||
EP_UNREF(ep_impl, "destroy"); |
||||
} |
||||
|
||||
grpc_resource_user* CFStreamGetResourceUser(grpc_endpoint* ep) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
return ep_impl->resource_user; |
||||
} |
||||
|
||||
char* CFStreamGetPeer(grpc_endpoint* ep) { |
||||
CFStreamEndpoint* ep_impl = reinterpret_cast<CFStreamEndpoint*>(ep); |
||||
return gpr_strdup(ep_impl->peer_string); |
||||
} |
||||
|
||||
int CFStreamGetFD(grpc_endpoint* ep) { return 0; } |
||||
|
||||
void CFStreamAddToPollset(grpc_endpoint* ep, grpc_pollset* pollset) {} |
||||
void CFStreamAddToPollsetSet(grpc_endpoint* ep, grpc_pollset_set* pollset) {} |
||||
void CFStreamDeleteFromPollsetSet(grpc_endpoint* ep, |
||||
grpc_pollset_set* pollset) {} |
||||
|
||||
static const grpc_endpoint_vtable vtable = {CFStreamRead, |
||||
CFStreamWrite, |
||||
CFStreamAddToPollset, |
||||
CFStreamAddToPollsetSet, |
||||
CFStreamDeleteFromPollsetSet, |
||||
CFStreamShutdown, |
||||
CFStreamDestroy, |
||||
CFStreamGetResourceUser, |
||||
CFStreamGetPeer, |
||||
CFStreamGetFD}; |
||||
|
||||
grpc_endpoint* grpc_cfstream_endpoint_create( |
||||
CFReadStreamRef read_stream, CFWriteStreamRef write_stream, |
||||
const char* peer_string, grpc_resource_quota* resource_quota, |
||||
CFStreamHandle* stream_sync) { |
||||
CFStreamEndpoint* ep_impl = |
||||
static_cast<CFStreamEndpoint*>(gpr_malloc(sizeof(CFStreamEndpoint))); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, |
||||
"CFStream endpoint:%p create readStream:%p writeStream: %p", |
||||
ep_impl, read_stream, write_stream); |
||||
} |
||||
ep_impl->base.vtable = &vtable; |
||||
gpr_ref_init(&ep_impl->refcount, 1); |
||||
ep_impl->read_stream = read_stream; |
||||
ep_impl->write_stream = write_stream; |
||||
CFRetain(read_stream); |
||||
CFRetain(write_stream); |
||||
ep_impl->stream_sync = stream_sync; |
||||
CFSTREAM_HANDLE_REF(ep_impl->stream_sync, "endpoint create"); |
||||
|
||||
ep_impl->peer_string = gpr_strdup(peer_string); |
||||
ep_impl->read_cb = nil; |
||||
ep_impl->write_cb = nil; |
||||
ep_impl->read_slices = nil; |
||||
ep_impl->write_slices = nil; |
||||
GRPC_CLOSURE_INIT(&ep_impl->read_action, ReadAction, |
||||
static_cast<void*>(ep_impl), grpc_schedule_on_exec_ctx); |
||||
GRPC_CLOSURE_INIT(&ep_impl->write_action, WriteAction, |
||||
static_cast<void*>(ep_impl), grpc_schedule_on_exec_ctx); |
||||
ep_impl->resource_user = |
||||
grpc_resource_user_create(resource_quota, peer_string); |
||||
grpc_resource_user_slice_allocator_init(&ep_impl->slice_allocator, |
||||
ep_impl->resource_user, |
||||
CFStreamReadAllocationDone, ep_impl); |
||||
|
||||
return &ep_impl->base; |
||||
} |
||||
|
||||
#endif /* GRPC_CFSTREAM_ENDPOINT */ |
@ -0,0 +1,49 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_ENDPOINT_CFSTREAM_H |
||||
#define GRPC_CORE_LIB_IOMGR_ENDPOINT_CFSTREAM_H |
||||
/*
|
||||
Low level TCP "bottom half" implementation, for use by transports built on |
||||
top of a TCP connection. |
||||
|
||||
Note that this file does not (yet) include APIs for creating the socket in |
||||
the first place. |
||||
|
||||
All calls passing slice transfer ownership of a slice refcount unless |
||||
otherwise specified. |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
|
||||
#import <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include "src/core/lib/debug/trace.h" |
||||
#include "src/core/lib/iomgr/cfstream_handle.h" |
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
|
||||
grpc_endpoint* grpc_cfstream_endpoint_create( |
||||
CFReadStreamRef read_stream, CFWriteStreamRef write_stream, |
||||
const char* peer_string, grpc_resource_quota* resource_quota, |
||||
CFStreamHandle* stream_sync); |
||||
|
||||
#endif /* GRPC_CFSTREAM */ |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_ENDPOINT_CFSTREAM_H */ |
@ -0,0 +1,52 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/string_util.h> |
||||
|
||||
#include "src/core/lib/iomgr/error.h" |
||||
|
||||
#define MAX_ERROR_DESCRIPTION 256 |
||||
|
||||
grpc_error* grpc_error_create_from_cferror(const char* file, int line, |
||||
void* arg, const char* custom_desc) { |
||||
CFErrorRef error = static_cast<CFErrorRef>(arg); |
||||
char buf_domain[MAX_ERROR_DESCRIPTION]; |
||||
char buf_desc[MAX_ERROR_DESCRIPTION]; |
||||
char* error_msg; |
||||
CFErrorDomain domain = CFErrorGetDomain((error)); |
||||
CFIndex code = CFErrorGetCode((error)); |
||||
CFStringRef desc = CFErrorCopyDescription((error)); |
||||
CFStringGetCString(domain, buf_domain, MAX_ERROR_DESCRIPTION, |
||||
kCFStringEncodingUTF8); |
||||
CFStringGetCString(desc, buf_desc, MAX_ERROR_DESCRIPTION, |
||||
kCFStringEncodingUTF8); |
||||
gpr_asprintf(&error_msg, "%s (error domain:%s, code:%ld, description:%s)", |
||||
custom_desc, buf_domain, code, buf_desc); |
||||
CFRelease(desc); |
||||
grpc_error* return_error = grpc_error_create( |
||||
file, line, grpc_slice_from_copied_string(error_msg), NULL, 0); |
||||
gpr_free(error_msg); |
||||
return return_error; |
||||
} |
||||
#endif /* GRPC_CFSTREAM */ |
@ -0,0 +1,31 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_IOMGR_ERROR_CFSTREAM_H |
||||
#define GRPC_CORE_LIB_IOMGR_ERROR_CFSTREAM_H |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
// Create an error from Apple Core Foundation CFError object
|
||||
#define GRPC_ERROR_CREATE_FROM_CFERROR(error, desc) \ |
||||
grpc_error_create_from_cferror(__FILE__, __LINE__, \
|
||||
static_cast<void*>((error)), (desc)) |
||||
grpc_error* grpc_error_create_from_cferror(const char* file, int line, |
||||
void* arg, const char* desc); |
||||
#endif /* GRPC_CFSTREAM */ |
||||
|
||||
#endif /* GRPC_CORE_LIB_IOMGR_ERROR_CFSTREAM_H */ |
@ -0,0 +1,216 @@ |
||||
|
||||
/*
|
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc/support/port_platform.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM_CLIENT |
||||
|
||||
#include <CoreFoundation/CoreFoundation.h> |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include <netinet/in.h> |
||||
|
||||
#include "src/core/lib/channel/channel_args.h" |
||||
#include "src/core/lib/gpr/host_port.h" |
||||
#include "src/core/lib/iomgr/cfstream_handle.h" |
||||
#include "src/core/lib/iomgr/closure.h" |
||||
#include "src/core/lib/iomgr/endpoint_cfstream.h" |
||||
#include "src/core/lib/iomgr/error.h" |
||||
#include "src/core/lib/iomgr/error_cfstream.h" |
||||
#include "src/core/lib/iomgr/sockaddr_utils.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "src/core/lib/iomgr/timer.h" |
||||
|
||||
extern grpc_core::TraceFlag grpc_tcp_trace; |
||||
|
||||
typedef struct CFStreamConnect { |
||||
gpr_mu mu; |
||||
gpr_refcount refcount; |
||||
|
||||
CFReadStreamRef read_stream; |
||||
CFWriteStreamRef write_stream; |
||||
CFStreamHandle* stream_sync; |
||||
|
||||
grpc_timer alarm; |
||||
grpc_closure on_alarm; |
||||
grpc_closure on_open; |
||||
|
||||
bool read_stream_open; |
||||
bool write_stream_open; |
||||
bool failed; |
||||
|
||||
grpc_closure* closure; |
||||
grpc_endpoint** endpoint; |
||||
int refs; |
||||
char* addr_name; |
||||
grpc_resource_quota* resource_quota; |
||||
} CFStreamConnect; |
||||
|
||||
static void CFStreamConnectCleanup(CFStreamConnect* connect) { |
||||
grpc_resource_quota_unref_internal(connect->resource_quota); |
||||
CFSTREAM_HANDLE_UNREF(connect->stream_sync, "async connect clean up"); |
||||
CFRelease(connect->read_stream); |
||||
CFRelease(connect->write_stream); |
||||
gpr_mu_destroy(&connect->mu); |
||||
gpr_free(connect->addr_name); |
||||
gpr_free(connect); |
||||
} |
||||
|
||||
static void OnAlarm(void* arg, grpc_error* error) { |
||||
CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnAlarm, error:%p", connect, error); |
||||
} |
||||
gpr_mu_lock(&connect->mu); |
||||
grpc_closure* closure = connect->closure; |
||||
connect->closure = nil; |
||||
const bool done = (--connect->refs == 0); |
||||
gpr_mu_unlock(&connect->mu); |
||||
// Only schedule a callback once, by either OnAlarm or OnOpen. The
|
||||
// first one issues callback while the second one does cleanup.
|
||||
if (done) { |
||||
CFStreamConnectCleanup(connect); |
||||
} else { |
||||
grpc_error* error = |
||||
GRPC_ERROR_CREATE_FROM_STATIC_STRING("connect() timed out"); |
||||
GRPC_CLOSURE_SCHED(closure, error); |
||||
} |
||||
} |
||||
|
||||
static void OnOpen(void* arg, grpc_error* error) { |
||||
CFStreamConnect* connect = static_cast<CFStreamConnect*>(arg); |
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT :%p OnOpen, error:%p", connect, error); |
||||
} |
||||
gpr_mu_lock(&connect->mu); |
||||
grpc_timer_cancel(&connect->alarm); |
||||
grpc_closure* closure = connect->closure; |
||||
connect->closure = nil; |
||||
|
||||
bool done = (--connect->refs == 0); |
||||
grpc_endpoint** endpoint = connect->endpoint; |
||||
|
||||
// Only schedule a callback once, by either OnAlarm or OnOpen. The
|
||||
// first one issues callback while the second one does cleanup.
|
||||
if (done) { |
||||
gpr_mu_unlock(&connect->mu); |
||||
CFStreamConnectCleanup(connect); |
||||
} else { |
||||
if (error == GRPC_ERROR_NONE) { |
||||
CFErrorRef stream_error = CFReadStreamCopyError(connect->read_stream); |
||||
if (stream_error == NULL) { |
||||
stream_error = CFWriteStreamCopyError(connect->write_stream); |
||||
} |
||||
if (stream_error) { |
||||
error = GRPC_ERROR_CREATE_FROM_CFERROR(stream_error, "connect() error"); |
||||
CFRelease(stream_error); |
||||
} |
||||
if (error == GRPC_ERROR_NONE) { |
||||
*endpoint = grpc_cfstream_endpoint_create( |
||||
connect->read_stream, connect->write_stream, connect->addr_name, |
||||
connect->resource_quota, connect->stream_sync); |
||||
} |
||||
} else { |
||||
GRPC_ERROR_REF(error); |
||||
} |
||||
gpr_mu_unlock(&connect->mu); |
||||
GRPC_CLOSURE_SCHED(closure, error); |
||||
} |
||||
} |
||||
|
||||
static void ParseResolvedAddress(const grpc_resolved_address* addr, |
||||
CFStringRef* host, int* port) { |
||||
char *host_port, *host_string, *port_string; |
||||
grpc_sockaddr_to_string(&host_port, addr, 1); |
||||
gpr_split_host_port(host_port, &host_string, &port_string); |
||||
*host = CFStringCreateWithCString(NULL, host_string, kCFStringEncodingUTF8); |
||||
gpr_free(host_string); |
||||
gpr_free(port_string); |
||||
gpr_free(host_port); |
||||
*port = grpc_sockaddr_get_port(addr); |
||||
} |
||||
|
||||
static void CFStreamClientConnect(grpc_closure* closure, grpc_endpoint** ep, |
||||
grpc_pollset_set* interested_parties, |
||||
const grpc_channel_args* channel_args, |
||||
const grpc_resolved_address* resolved_addr, |
||||
grpc_millis deadline) { |
||||
CFStreamConnect* connect; |
||||
|
||||
connect = (CFStreamConnect*)gpr_zalloc(sizeof(CFStreamConnect)); |
||||
connect->closure = closure; |
||||
connect->endpoint = ep; |
||||
connect->addr_name = grpc_sockaddr_to_uri(resolved_addr); |
||||
// connect->resource_quota = resource_quota;
|
||||
connect->refs = 2; // One for the connect operation, one for the timer.
|
||||
gpr_ref_init(&connect->refcount, 1); |
||||
gpr_mu_init(&connect->mu); |
||||
|
||||
if (grpc_tcp_trace.enabled()) { |
||||
gpr_log(GPR_DEBUG, "CLIENT_CONNECT: %s: asynchronously connecting", |
||||
connect->addr_name); |
||||
} |
||||
|
||||
grpc_resource_quota* resource_quota = grpc_resource_quota_create(NULL); |
||||
if (channel_args != NULL) { |
||||
for (size_t i = 0; i < channel_args->num_args; i++) { |
||||
if (0 == strcmp(channel_args->args[i].key, GRPC_ARG_RESOURCE_QUOTA)) { |
||||
grpc_resource_quota_unref_internal(resource_quota); |
||||
resource_quota = grpc_resource_quota_ref_internal( |
||||
(grpc_resource_quota*)channel_args->args[i].value.pointer.p); |
||||
} |
||||
} |
||||
} |
||||
connect->resource_quota = resource_quota; |
||||
|
||||
CFReadStreamRef read_stream; |
||||
CFWriteStreamRef write_stream; |
||||
|
||||
CFStringRef host; |
||||
int port; |
||||
ParseResolvedAddress(resolved_addr, &host, &port); |
||||
CFStreamCreatePairWithSocketToHost(NULL, host, port, &read_stream, |
||||
&write_stream); |
||||
CFRelease(host); |
||||
connect->read_stream = read_stream; |
||||
connect->write_stream = write_stream; |
||||
connect->stream_sync = |
||||
CFStreamHandle::CreateStreamHandle(read_stream, write_stream); |
||||
GRPC_CLOSURE_INIT(&connect->on_open, OnOpen, static_cast<void*>(connect), |
||||
grpc_schedule_on_exec_ctx); |
||||
connect->stream_sync->NotifyOnOpen(&connect->on_open); |
||||
GRPC_CLOSURE_INIT(&connect->on_alarm, OnAlarm, connect, |
||||
grpc_schedule_on_exec_ctx); |
||||
gpr_mu_lock(&connect->mu); |
||||
CFReadStreamOpen(read_stream); |
||||
CFWriteStreamOpen(write_stream); |
||||
grpc_timer_init(&connect->alarm, deadline, &connect->on_alarm); |
||||
gpr_mu_unlock(&connect->mu); |
||||
} |
||||
|
||||
grpc_tcp_client_vtable grpc_posix_tcp_client_vtable = {CFStreamClientConnect}; |
||||
|
||||
#endif /* GRPC_CFSTREAM_CLIENT */ |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,63 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Test" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5EC5E4302081856B000EF4AD" |
||||
BuildableName = "InteropTestsLocalCleartextCFStream.xctest" |
||||
BlueprintName = "InteropTestsLocalCleartextCFStream" |
||||
ReferencedContainer = "container:Tests.xcodeproj"> |
||||
</BuildableReference> |
||||
<SkippedTests> |
||||
<Test |
||||
Identifier = "InteropTests"> |
||||
</Test> |
||||
</SkippedTests> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,63 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Test" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5EC5E441208185CE000EF4AD" |
||||
BuildableName = "InteropTestsLocalSSLCFStream.xctest" |
||||
BlueprintName = "InteropTestsLocalSSLCFStream" |
||||
ReferencedContainer = "container:Tests.xcodeproj"> |
||||
</BuildableReference> |
||||
<SkippedTests> |
||||
<Test |
||||
Identifier = "InteropTests"> |
||||
</Test> |
||||
</SkippedTests> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,61 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Test" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5EC5E420208177CC000EF4AD" |
||||
BuildableName = "InteropTestsRemoteCFStream.xctest" |
||||
BlueprintName = "InteropTestsRemoteCFStream" |
||||
ReferencedContainer = "container:Tests.xcodeproj"> |
||||
</BuildableReference> |
||||
<SkippedTests> |
||||
<Test |
||||
Identifier = "InteropTests"> |
||||
</Test> |
||||
</SkippedTests> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,201 @@ |
||||
/* |
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#import <XCTest/XCTest.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
|
||||
#include <netinet/in.h> |
||||
|
||||
#include <grpc/impl/codegen/sync.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
// static int g_connections_complete = 0; |
||||
static gpr_mu g_mu; |
||||
static int g_connections_complete = 0; |
||||
static grpc_endpoint* g_connecting = nullptr; |
||||
|
||||
static void finish_connection() { |
||||
gpr_mu_lock(&g_mu); |
||||
g_connections_complete++; |
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
|
||||
static void must_succeed(void* arg, grpc_error* error) { |
||||
GPR_ASSERT(g_connecting != nullptr); |
||||
GPR_ASSERT(error == GRPC_ERROR_NONE); |
||||
grpc_endpoint_shutdown(g_connecting, GRPC_ERROR_CREATE_FROM_STATIC_STRING("must_succeed called")); |
||||
grpc_endpoint_destroy(g_connecting); |
||||
g_connecting = nullptr; |
||||
finish_connection(); |
||||
} |
||||
|
||||
static void must_fail(void* arg, grpc_error* error) { |
||||
GPR_ASSERT(g_connecting == nullptr); |
||||
GPR_ASSERT(error != GRPC_ERROR_NONE); |
||||
const char* error_str = grpc_error_string(error); |
||||
NSLog(@"%s", error_str); |
||||
finish_connection(); |
||||
} |
||||
|
||||
@interface CFStreamClientTests : XCTestCase |
||||
|
||||
@end |
||||
|
||||
@implementation CFStreamClientTests |
||||
|
||||
+ (void)setUp { |
||||
grpc_init(); |
||||
gpr_mu_init(&g_mu); |
||||
} |
||||
|
||||
+ (void)tearDown { |
||||
grpc_shutdown(); |
||||
} |
||||
|
||||
- (void)testSucceeds { |
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr); |
||||
int svr_fd; |
||||
int r; |
||||
int connections_complete_before; |
||||
grpc_closure done; |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_log(GPR_DEBUG, "test_succeeds"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
|
||||
/* create a dummy server */ |
||||
svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
GPR_ASSERT(svr_fd >= 0); |
||||
GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr*)addr, (socklen_t)resolved_addr.len)); |
||||
GPR_ASSERT(0 == listen(svr_fd, 1)); |
||||
|
||||
gpr_mu_lock(&g_mu); |
||||
connections_complete_before = g_connections_complete; |
||||
gpr_mu_unlock(&g_mu); |
||||
|
||||
/* connect to it */ |
||||
GPR_ASSERT(getsockname(svr_fd, (struct sockaddr*)addr, (socklen_t*)&resolved_addr.len) == 0); |
||||
GRPC_CLOSURE_INIT(&done, must_succeed, nullptr, grpc_schedule_on_exec_ctx); |
||||
grpc_tcp_client_connect(&done, &g_connecting, nullptr, nullptr, &resolved_addr, |
||||
GRPC_MILLIS_INF_FUTURE); |
||||
|
||||
/* await the connection */ |
||||
do { |
||||
resolved_addr.len = sizeof(addr); |
||||
r = accept(svr_fd, reinterpret_cast<struct sockaddr*>(addr), |
||||
reinterpret_cast<socklen_t*>(&resolved_addr.len)); |
||||
} while (r == -1 && errno == EINTR); |
||||
GPR_ASSERT(r >= 0); |
||||
close(r); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
gpr_mu_lock(&g_mu); |
||||
NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:5]; |
||||
while (connections_complete_before == g_connections_complete) { |
||||
gpr_mu_unlock(&g_mu); |
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline]; |
||||
gpr_mu_lock(&g_mu); |
||||
} |
||||
XCTAssertGreaterThan(g_connections_complete, connections_complete_before); |
||||
|
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
|
||||
- (void)testFails { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in* addr = reinterpret_cast<struct sockaddr_in*>(resolved_addr.addr); |
||||
int connections_complete_before; |
||||
grpc_closure done; |
||||
int svr_fd; |
||||
|
||||
gpr_log(GPR_DEBUG, "test_fails"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = static_cast<socklen_t>(sizeof(struct sockaddr_in)); |
||||
addr->sin_family = AF_INET; |
||||
|
||||
svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
GPR_ASSERT(svr_fd >= 0); |
||||
GPR_ASSERT(0 == bind(svr_fd, (struct sockaddr*)addr, (socklen_t)resolved_addr.len)); |
||||
GPR_ASSERT(0 == listen(svr_fd, 1)); |
||||
GPR_ASSERT(getsockname(svr_fd, (struct sockaddr*)addr, (socklen_t*)&resolved_addr.len) == 0); |
||||
close(svr_fd); |
||||
|
||||
gpr_mu_lock(&g_mu); |
||||
connections_complete_before = g_connections_complete; |
||||
gpr_mu_unlock(&g_mu); |
||||
|
||||
/* connect to a broken address */ |
||||
GRPC_CLOSURE_INIT(&done, must_fail, nullptr, grpc_schedule_on_exec_ctx); |
||||
grpc_tcp_client_connect(&done, &g_connecting, nullptr, nullptr, &resolved_addr, |
||||
GRPC_MILLIS_INF_FUTURE); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
gpr_mu_lock(&g_mu); |
||||
NSDate* deadline = [NSDate dateWithTimeIntervalSinceNow:5]; |
||||
while (g_connections_complete == connections_complete_before) { |
||||
gpr_mu_unlock(&g_mu); |
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline]; |
||||
gpr_mu_lock(&g_mu); |
||||
} |
||||
|
||||
XCTAssertGreaterThan(g_connections_complete, connections_complete_before); |
||||
|
||||
gpr_mu_unlock(&g_mu); |
||||
} |
||||
|
||||
@end |
||||
|
||||
#else // GRPC_CFSTREAM |
||||
|
||||
// Dummy test suite |
||||
@interface CFStreamClientTests : XCTestCase |
||||
|
||||
@end |
||||
|
||||
@implementation CFStreamClientTests |
||||
|
||||
- (void)setUp { |
||||
[super setUp]; |
||||
} |
||||
|
||||
- (void)tearDown { |
||||
[super tearDown]; |
||||
} |
||||
|
||||
@end |
||||
|
||||
#endif // GRPC_CFSTREAM |
@ -0,0 +1,344 @@ |
||||
/* |
||||
* |
||||
* Copyright 2018 gRPC authors. |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
#import <XCTest/XCTest.h> |
||||
|
||||
#include "src/core/lib/iomgr/port.h" |
||||
|
||||
#ifdef GRPC_CFSTREAM |
||||
|
||||
#include <netinet/in.h> |
||||
|
||||
#include <grpc/impl/codegen/sync.h> |
||||
#include <grpc/support/sync.h> |
||||
|
||||
#include "src/core/lib/iomgr/endpoint.h" |
||||
#include "src/core/lib/iomgr/resolve_address.h" |
||||
#include "src/core/lib/iomgr/tcp_client.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
static const int kConnectTimeout = 5; |
||||
static const int kWriteTimeout = 5; |
||||
static const int kReadTimeout = 5; |
||||
|
||||
static const int kBufferSize = 10000; |
||||
|
||||
static const int kRunLoopTimeout = 1; |
||||
|
||||
static void set_atm(void *arg, grpc_error *error) { |
||||
gpr_atm *p = static_cast<gpr_atm *>(arg); |
||||
gpr_atm_full_cas(p, -1, reinterpret_cast<gpr_atm>(error)); |
||||
} |
||||
|
||||
static void init_event_closure(grpc_closure *closure, gpr_atm *atm) { |
||||
*atm = -1; |
||||
GRPC_CLOSURE_INIT(closure, set_atm, static_cast<void *>(atm), grpc_schedule_on_exec_ctx); |
||||
} |
||||
|
||||
static bool compare_slice_buffer_with_buffer(grpc_slice_buffer *slices, const char *buffer, |
||||
size_t buffer_len) { |
||||
if (slices->length != buffer_len) { |
||||
return false; |
||||
} |
||||
|
||||
for (int i = 0; i < slices->count; i++) { |
||||
grpc_slice slice = slices->slices[i]; |
||||
if (0 != memcmp(buffer, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice))) { |
||||
return false; |
||||
} |
||||
buffer += GRPC_SLICE_LENGTH(slice); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
@interface CFStreamEndpointTests : XCTestCase |
||||
|
||||
@end |
||||
|
||||
@implementation CFStreamEndpointTests { |
||||
grpc_endpoint *ep_; |
||||
int svr_fd_; |
||||
} |
||||
|
||||
- (BOOL)waitForEvent:(gpr_atm *)event timeout:(int)timeout { |
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
|
||||
NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:kConnectTimeout]; |
||||
while (gpr_atm_acq_load(event) == -1 && [deadline timeIntervalSinceNow] > 0) { |
||||
NSDate *deadline = [NSDate dateWithTimeIntervalSinceNow:kRunLoopTimeout]; |
||||
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:deadline]; |
||||
} |
||||
|
||||
return (gpr_atm_acq_load(event) != -1); |
||||
} |
||||
|
||||
+ (void)setUp { |
||||
grpc_init(); |
||||
} |
||||
|
||||
+ (void)tearDown { |
||||
grpc_shutdown(); |
||||
} |
||||
|
||||
- (void)setUp { |
||||
self.continueAfterFailure = NO; |
||||
|
||||
// Set up CFStream connection before testing the endpoint |
||||
|
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
grpc_resolved_address resolved_addr; |
||||
struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(resolved_addr.addr); |
||||
int svr_fd; |
||||
int r; |
||||
gpr_atm connected = -1; |
||||
grpc_closure done; |
||||
|
||||
gpr_log(GPR_DEBUG, "test_succeeds"); |
||||
|
||||
memset(&resolved_addr, 0, sizeof(resolved_addr)); |
||||
resolved_addr.len = sizeof(struct sockaddr_in); |
||||
addr->sin_family = AF_INET; |
||||
|
||||
/* create a dummy server */ |
||||
svr_fd = socket(AF_INET, SOCK_STREAM, 0); |
||||
XCTAssertGreaterThanOrEqual(svr_fd, 0); |
||||
XCTAssertEqual(bind(svr_fd, (struct sockaddr *)addr, (socklen_t)resolved_addr.len), 0); |
||||
XCTAssertEqual(listen(svr_fd, 1), 0); |
||||
|
||||
/* connect to it */ |
||||
XCTAssertEqual(getsockname(svr_fd, (struct sockaddr *)addr, (socklen_t *)&resolved_addr.len), 0); |
||||
init_event_closure(&done, &connected); |
||||
grpc_tcp_client_connect(&done, &ep_, nullptr, nullptr, &resolved_addr, GRPC_MILLIS_INF_FUTURE); |
||||
|
||||
/* await the connection */ |
||||
do { |
||||
resolved_addr.len = sizeof(addr); |
||||
r = accept(svr_fd, reinterpret_cast<struct sockaddr *>(addr), |
||||
reinterpret_cast<socklen_t *>(&resolved_addr.len)); |
||||
} while (r == -1 && errno == EINTR); |
||||
XCTAssertGreaterThanOrEqual(r, 0); |
||||
svr_fd_ = r; |
||||
|
||||
/* wait for the connection callback to finish */ |
||||
XCTAssertEqual([self waitForEvent:&connected timeout:kConnectTimeout], YES); |
||||
XCTAssertEqual(reinterpret_cast<grpc_error *>(connected), GRPC_ERROR_NONE); |
||||
} |
||||
|
||||
- (void)tearDown { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
close(svr_fd_); |
||||
grpc_endpoint_destroy(ep_); |
||||
} |
||||
|
||||
- (void)testReadWrite { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_atm read; |
||||
grpc_closure read_done; |
||||
grpc_slice_buffer read_slices; |
||||
grpc_slice_buffer read_one_slice; |
||||
gpr_atm write; |
||||
grpc_closure write_done; |
||||
grpc_slice_buffer write_slices; |
||||
|
||||
grpc_slice slice; |
||||
char write_buffer[kBufferSize]; |
||||
char read_buffer[kBufferSize]; |
||||
size_t recv_size = 0; |
||||
|
||||
grpc_slice_buffer_init(&write_slices); |
||||
slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize); |
||||
grpc_slice_buffer_add(&write_slices, slice); |
||||
init_event_closure(&write_done, &write); |
||||
grpc_endpoint_write(ep_, &write_slices, &write_done); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES); |
||||
XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE); |
||||
|
||||
while (recv_size < kBufferSize) { |
||||
ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0); |
||||
XCTAssertGreaterThanOrEqual(size, 0); |
||||
recv_size += size; |
||||
} |
||||
|
||||
XCTAssertEqual(recv_size, kBufferSize); |
||||
XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0); |
||||
ssize_t send_size = send(svr_fd_, read_buffer, kBufferSize, 0); |
||||
XCTAssertGreaterThanOrEqual(send_size, 0); |
||||
|
||||
grpc_slice_buffer_init(&read_slices); |
||||
grpc_slice_buffer_init(&read_one_slice); |
||||
while (read_slices.length < kBufferSize) { |
||||
init_event_closure(&read_done, &read); |
||||
grpc_endpoint_read(ep_, &read_one_slice, &read_done); |
||||
XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES); |
||||
XCTAssertEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE); |
||||
grpc_slice_buffer_move_into(&read_one_slice, &read_slices); |
||||
XCTAssertLessThanOrEqual(read_slices.length, kBufferSize); |
||||
} |
||||
XCTAssertTrue(compare_slice_buffer_with_buffer(&read_slices, read_buffer, kBufferSize)); |
||||
|
||||
grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE); |
||||
grpc_slice_buffer_reset_and_unref(&read_slices); |
||||
grpc_slice_buffer_reset_and_unref(&write_slices); |
||||
grpc_slice_buffer_reset_and_unref(&read_one_slice); |
||||
} |
||||
|
||||
- (void)testShutdownBeforeRead { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_atm read; |
||||
grpc_closure read_done; |
||||
grpc_slice_buffer read_slices; |
||||
gpr_atm write; |
||||
grpc_closure write_done; |
||||
grpc_slice_buffer write_slices; |
||||
|
||||
grpc_slice slice; |
||||
char write_buffer[kBufferSize]; |
||||
char read_buffer[kBufferSize]; |
||||
size_t recv_size = 0; |
||||
|
||||
grpc_slice_buffer_init(&read_slices); |
||||
init_event_closure(&read_done, &read); |
||||
grpc_endpoint_read(ep_, &read_slices, &read_done); |
||||
|
||||
grpc_slice_buffer_init(&write_slices); |
||||
slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize); |
||||
grpc_slice_buffer_add(&write_slices, slice); |
||||
init_event_closure(&write_done, &write); |
||||
grpc_endpoint_write(ep_, &write_slices, &write_done); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES); |
||||
XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE); |
||||
|
||||
while (recv_size < kBufferSize) { |
||||
ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0); |
||||
XCTAssertGreaterThanOrEqual(size, 0); |
||||
recv_size += size; |
||||
} |
||||
|
||||
XCTAssertEqual(recv_size, kBufferSize); |
||||
XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], NO); |
||||
|
||||
grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE); |
||||
|
||||
grpc_core::ExecCtx::Get()->Flush(); |
||||
XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES); |
||||
XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE); |
||||
|
||||
grpc_slice_buffer_reset_and_unref(&read_slices); |
||||
grpc_slice_buffer_reset_and_unref(&write_slices); |
||||
} |
||||
|
||||
- (void)testRemoteClosed { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_atm read; |
||||
grpc_closure read_done; |
||||
grpc_slice_buffer read_slices; |
||||
gpr_atm write; |
||||
grpc_closure write_done; |
||||
grpc_slice_buffer write_slices; |
||||
|
||||
grpc_slice slice; |
||||
char write_buffer[kBufferSize]; |
||||
char read_buffer[kBufferSize]; |
||||
size_t recv_size = 0; |
||||
|
||||
init_event_closure(&read_done, &read); |
||||
grpc_slice_buffer_init(&read_slices); |
||||
grpc_endpoint_read(ep_, &read_slices, &read_done); |
||||
|
||||
grpc_slice_buffer_init(&write_slices); |
||||
slice = grpc_slice_from_static_buffer(write_buffer, kBufferSize); |
||||
grpc_slice_buffer_add(&write_slices, slice); |
||||
init_event_closure(&write_done, &write); |
||||
grpc_endpoint_write(ep_, &write_slices, &write_done); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&write timeout:kWriteTimeout], YES); |
||||
XCTAssertEqual(reinterpret_cast<grpc_error *>(write), GRPC_ERROR_NONE); |
||||
|
||||
while (recv_size < kBufferSize) { |
||||
ssize_t size = recv(svr_fd_, read_buffer, kBufferSize, 0); |
||||
XCTAssertGreaterThanOrEqual(size, 0); |
||||
recv_size += size; |
||||
} |
||||
|
||||
XCTAssertEqual(recv_size, kBufferSize); |
||||
XCTAssertEqual(memcmp(read_buffer, write_buffer, kBufferSize), 0); |
||||
|
||||
close(svr_fd_); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES); |
||||
XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE); |
||||
|
||||
grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE); |
||||
grpc_slice_buffer_reset_and_unref(&read_slices); |
||||
grpc_slice_buffer_reset_and_unref(&write_slices); |
||||
} |
||||
|
||||
- (void)testRemoteReset { |
||||
grpc_core::ExecCtx exec_ctx; |
||||
|
||||
gpr_atm read; |
||||
grpc_closure read_done; |
||||
grpc_slice_buffer read_slices; |
||||
|
||||
init_event_closure(&read_done, &read); |
||||
grpc_slice_buffer_init(&read_slices); |
||||
grpc_endpoint_read(ep_, &read_slices, &read_done); |
||||
|
||||
struct linger so_linger; |
||||
so_linger.l_onoff = 1; |
||||
so_linger.l_linger = 0; |
||||
setsockopt(svr_fd_, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); |
||||
|
||||
close(svr_fd_); |
||||
|
||||
XCTAssertEqual([self waitForEvent:&read timeout:kReadTimeout], YES); |
||||
XCTAssertNotEqual(reinterpret_cast<grpc_error *>(read), GRPC_ERROR_NONE); |
||||
|
||||
grpc_endpoint_shutdown(ep_, GRPC_ERROR_NONE); |
||||
grpc_slice_buffer_reset_and_unref(&read_slices); |
||||
} |
||||
|
||||
@end |
||||
|
||||
#else // GRPC_CFSTREAM |
||||
|
||||
// Dummy test suite |
||||
@interface CFStreamEndpointTests : XCTestCase |
||||
@end |
||||
|
||||
@implementation CFStreamEndpointTests |
||||
- (void)setUp { |
||||
[super setUp]; |
||||
} |
||||
|
||||
- (void)tearDown { |
||||
[super tearDown]; |
||||
} |
||||
|
||||
@end |
||||
|
||||
#endif // GRPC_CFSTREAM |
@ -0,0 +1,338 @@ |
||||
// !$*UTF8*$! |
||||
{ |
||||
archiveVersion = 1; |
||||
classes = { |
||||
}; |
||||
objectVersion = 48; |
||||
objects = { |
||||
|
||||
/* Begin PBXBuildFile section */ |
||||
5E143B892069D72200715A6E /* CFStreamClientTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E143B882069D72200715A6E /* CFStreamClientTests.mm */; }; |
||||
5E143B8C206B5F9F00715A6E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5E143B8A2069D72700715A6E /* Info.plist */; }; |
||||
5E143B8E206C5B9A00715A6E /* CFStreamEndpointTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5E143B8D206C5B9A00715A6E /* CFStreamEndpointTests.mm */; }; |
||||
604EA96D9CD477A8EA411BDF /* libPods-CFStreamTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = AFFA154D492751CEAC05D591 /* libPods-CFStreamTests.a */; }; |
||||
/* End PBXBuildFile section */ |
||||
|
||||
/* Begin PBXFileReference section */ |
||||
5E143B792069D67300715A6E /* CFStreamTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CFStreamTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
5E143B882069D72200715A6E /* CFStreamClientTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CFStreamClientTests.mm; sourceTree = "<group>"; }; |
||||
5E143B8A2069D72700715A6E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; |
||||
5E143B8D206C5B9A00715A6E /* CFStreamEndpointTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CFStreamEndpointTests.mm; sourceTree = "<group>"; }; |
||||
8CB4409E07E180CCA59987DF /* Pods-CFStreamTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CFStreamTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CFStreamTests/Pods-CFStreamTests.release.xcconfig"; sourceTree = "<group>"; }; |
||||
9E3FAF9DA6B98ED4FE6D6848 /* Pods-CFStreamTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CFStreamTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CFStreamTests/Pods-CFStreamTests.debug.xcconfig"; sourceTree = "<group>"; }; |
||||
AFFA154D492751CEAC05D591 /* libPods-CFStreamTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-CFStreamTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
/* End PBXFileReference section */ |
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */ |
||||
5E143B762069D67300715A6E /* Frameworks */ = { |
||||
isa = PBXFrameworksBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
604EA96D9CD477A8EA411BDF /* libPods-CFStreamTests.a in Frameworks */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXFrameworksBuildPhase section */ |
||||
|
||||
/* Begin PBXGroup section */ |
||||
5E143B582069D67300715A6E = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
5E143B8D206C5B9A00715A6E /* CFStreamEndpointTests.mm */, |
||||
5E143B8A2069D72700715A6E /* Info.plist */, |
||||
5E143B882069D72200715A6E /* CFStreamClientTests.mm */, |
||||
5E143B622069D67300715A6E /* Products */, |
||||
A331D95F7F230B507FBF6D22 /* Pods */, |
||||
6AC36F6C5DB5CA8F717D1B67 /* Frameworks */, |
||||
); |
||||
sourceTree = "<group>"; |
||||
}; |
||||
5E143B622069D67300715A6E /* Products */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
5E143B792069D67300715A6E /* CFStreamTests.xctest */, |
||||
); |
||||
name = Products; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
6AC36F6C5DB5CA8F717D1B67 /* Frameworks */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
AFFA154D492751CEAC05D591 /* libPods-CFStreamTests.a */, |
||||
); |
||||
name = Frameworks; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
A331D95F7F230B507FBF6D22 /* Pods */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
9E3FAF9DA6B98ED4FE6D6848 /* Pods-CFStreamTests.debug.xcconfig */, |
||||
8CB4409E07E180CCA59987DF /* Pods-CFStreamTests.release.xcconfig */, |
||||
); |
||||
name = Pods; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXGroup section */ |
||||
|
||||
/* Begin PBXNativeTarget section */ |
||||
5E143B782069D67300715A6E /* CFStreamTests */ = { |
||||
isa = PBXNativeTarget; |
||||
buildConfigurationList = 5E143B852069D67300715A6E /* Build configuration list for PBXNativeTarget "CFStreamTests" */; |
||||
buildPhases = ( |
||||
4EBA55D3E23FC6C84596E3D5 /* [CP] Check Pods Manifest.lock */, |
||||
5E143B752069D67300715A6E /* Sources */, |
||||
5E143B762069D67300715A6E /* Frameworks */, |
||||
5E143B772069D67300715A6E /* Resources */, |
||||
); |
||||
buildRules = ( |
||||
); |
||||
dependencies = ( |
||||
); |
||||
name = CFStreamTests; |
||||
productName = CFStreamTestsTests; |
||||
productReference = 5E143B792069D67300715A6E /* CFStreamTests.xctest */; |
||||
productType = "com.apple.product-type.bundle.unit-test"; |
||||
}; |
||||
/* End PBXNativeTarget section */ |
||||
|
||||
/* Begin PBXProject section */ |
||||
5E143B592069D67300715A6E /* Project object */ = { |
||||
isa = PBXProject; |
||||
attributes = { |
||||
LastUpgradeCheck = 0920; |
||||
ORGANIZATIONNAME = gRPC; |
||||
TargetAttributes = { |
||||
5E143B782069D67300715A6E = { |
||||
CreatedOnToolsVersion = 9.2; |
||||
ProvisioningStyle = Automatic; |
||||
}; |
||||
}; |
||||
}; |
||||
buildConfigurationList = 5E143B5C2069D67300715A6E /* Build configuration list for PBXProject "CFStreamTests" */; |
||||
compatibilityVersion = "Xcode 8.0"; |
||||
developmentRegion = en; |
||||
hasScannedForEncodings = 0; |
||||
knownRegions = ( |
||||
en, |
||||
Base, |
||||
); |
||||
mainGroup = 5E143B582069D67300715A6E; |
||||
productRefGroup = 5E143B622069D67300715A6E /* Products */; |
||||
projectDirPath = ""; |
||||
projectRoot = ""; |
||||
targets = ( |
||||
5E143B782069D67300715A6E /* CFStreamTests */, |
||||
); |
||||
}; |
||||
/* End PBXProject section */ |
||||
|
||||
/* Begin PBXResourcesBuildPhase section */ |
||||
5E143B772069D67300715A6E /* Resources */ = { |
||||
isa = PBXResourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
5E143B8C206B5F9F00715A6E /* Info.plist in Resources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXResourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */ |
||||
4EBA55D3E23FC6C84596E3D5 /* [CP] Check Pods Manifest.lock */ = { |
||||
isa = PBXShellScriptBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
inputPaths = ( |
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock", |
||||
"${PODS_ROOT}/Manifest.lock", |
||||
); |
||||
name = "[CP] Check Pods Manifest.lock"; |
||||
outputPaths = ( |
||||
"$(DERIVED_FILE_DIR)/Pods-CFStreamTests-checkManifestLockResult.txt", |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
shellPath = /bin/sh; |
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; |
||||
showEnvVarsInLog = 0; |
||||
}; |
||||
/* End PBXShellScriptBuildPhase section */ |
||||
|
||||
/* Begin PBXSourcesBuildPhase section */ |
||||
5E143B752069D67300715A6E /* Sources */ = { |
||||
isa = PBXSourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
5E143B892069D72200715A6E /* CFStreamClientTests.mm in Sources */, |
||||
5E143B8E206C5B9A00715A6E /* CFStreamEndpointTests.mm in Sources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXSourcesBuildPhase section */ |
||||
|
||||
/* Begin XCBuildConfiguration section */ |
||||
5E143B802069D67300715A6E /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "iPhone Developer"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = dwarf; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
ENABLE_TESTABILITY = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_DYNAMIC_NO_PIC = NO; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_OPTIMIZATION_LEVEL = 0; |
||||
GCC_PREPROCESSOR_DEFINITIONS = ( |
||||
"DEBUG=1", |
||||
"$(inherited)", |
||||
); |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.2; |
||||
MTL_ENABLE_DEBUG_INFO = YES; |
||||
ONLY_ACTIVE_ARCH = YES; |
||||
SDKROOT = iphoneos; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
5E143B812069D67300715A6E /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "iPhone Developer"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; |
||||
ENABLE_NS_ASSERTIONS = NO; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
IPHONEOS_DEPLOYMENT_TARGET = 11.2; |
||||
MTL_ENABLE_DEBUG_INFO = NO; |
||||
SDKROOT = iphoneos; |
||||
VALIDATE_PRODUCT = YES; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
5E143B862069D67300715A6E /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
baseConfigurationReference = 9E3FAF9DA6B98ED4FE6D6848 /* Pods-CFStreamTests.debug.xcconfig */; |
||||
buildSettings = { |
||||
CODE_SIGN_STYLE = Automatic; |
||||
GCC_PREPROCESSOR_DEFINITIONS = ( |
||||
"$(inherited)", |
||||
"COCOAPODS=1", |
||||
"$(inherited)", |
||||
"PB_FIELD_32BIT=1", |
||||
"PB_NO_PACKED_STRUCTS=1", |
||||
"GRPC_CFSTREAM=1", |
||||
); |
||||
INFOPLIST_FILE = Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; |
||||
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CFStreamTestsTests; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
TARGETED_DEVICE_FAMILY = "1,2"; |
||||
USER_HEADER_SEARCH_PATHS = ../../../../..; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
5E143B872069D67300715A6E /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
baseConfigurationReference = 8CB4409E07E180CCA59987DF /* Pods-CFStreamTests.release.xcconfig */; |
||||
buildSettings = { |
||||
CODE_SIGN_STYLE = Automatic; |
||||
INFOPLIST_FILE = Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; |
||||
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CFStreamTestsTests; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
TARGETED_DEVICE_FAMILY = "1,2"; |
||||
USER_HEADER_SEARCH_PATHS = ../../../../..; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
/* End XCBuildConfiguration section */ |
||||
|
||||
/* Begin XCConfigurationList section */ |
||||
5E143B5C2069D67300715A6E /* Build configuration list for PBXProject "CFStreamTests" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
5E143B802069D67300715A6E /* Debug */, |
||||
5E143B812069D67300715A6E /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
5E143B852069D67300715A6E /* Build configuration list for PBXNativeTarget "CFStreamTests" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
5E143B862069D67300715A6E /* Debug */, |
||||
5E143B872069D67300715A6E /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
/* End XCConfigurationList section */ |
||||
}; |
||||
rootObject = 5E143B592069D67300715A6E /* Project object */; |
||||
} |
@ -0,0 +1,56 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E143B782069D67300715A6E" |
||||
BuildableName = "CFStreamTests.xctest" |
||||
BlueprintName = "CFStreamTests" |
||||
ReferencedContainer = "container:CFStreamTests.xcodeproj"> |
||||
</BuildableReference> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,61 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
enableAddressSanitizer = "YES" |
||||
enableASanStackUseAfterReturn = "YES" |
||||
language = "" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E143B782069D67300715A6E" |
||||
BuildableName = "CFStreamTests.xctest" |
||||
BlueprintName = "CFStreamTests" |
||||
ReferencedContainer = "container:CFStreamTests.xcodeproj"> |
||||
</BuildableReference> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
enableASanStackUseAfterReturn = "YES" |
||||
language = "" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,78 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E143B782069D67300715A6E" |
||||
BuildableName = "CFStreamTests.xctest" |
||||
BlueprintName = "CFStreamTests" |
||||
ReferencedContainer = "container:CFStreamTests.xcodeproj"> |
||||
</BuildableReference> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
<AdditionalOption |
||||
key = "DYLD_INSERT_LIBRARIES" |
||||
value = "/usr/lib/libgmalloc.dylib" |
||||
isEnabled = "YES"> |
||||
</AdditionalOption> |
||||
<AdditionalOption |
||||
key = "NSZombieEnabled" |
||||
value = "YES" |
||||
isEnabled = "YES"> |
||||
</AdditionalOption> |
||||
<AdditionalOption |
||||
key = "MallocGuardEdges" |
||||
value = "" |
||||
isEnabled = "YES"> |
||||
</AdditionalOption> |
||||
<AdditionalOption |
||||
key = "MallocScribble" |
||||
value = "" |
||||
isEnabled = "YES"> |
||||
</AdditionalOption> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,60 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<Scheme |
||||
LastUpgradeVersion = "0920" |
||||
version = "1.3"> |
||||
<BuildAction |
||||
parallelizeBuildables = "YES" |
||||
buildImplicitDependencies = "YES"> |
||||
</BuildAction> |
||||
<TestAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
enableThreadSanitizer = "YES" |
||||
language = "" |
||||
shouldUseLaunchSchemeArgsEnv = "YES"> |
||||
<Testables> |
||||
<TestableReference |
||||
skipped = "NO"> |
||||
<BuildableReference |
||||
BuildableIdentifier = "primary" |
||||
BlueprintIdentifier = "5E143B782069D67300715A6E" |
||||
BuildableName = "CFStreamTests.xctest" |
||||
BlueprintName = "CFStreamTests" |
||||
ReferencedContainer = "container:CFStreamTests.xcodeproj"> |
||||
</BuildableReference> |
||||
</TestableReference> |
||||
</Testables> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</TestAction> |
||||
<LaunchAction |
||||
buildConfiguration = "Debug" |
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" |
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" |
||||
language = "" |
||||
launchStyle = "0" |
||||
useCustomWorkingDirectory = "NO" |
||||
ignoresPersistentStateOnLaunch = "NO" |
||||
debugDocumentVersioning = "YES" |
||||
stopOnEveryThreadSanitizerIssue = "YES" |
||||
debugServiceExtension = "internal" |
||||
allowLocationSimulation = "YES"> |
||||
<AdditionalOptions> |
||||
</AdditionalOptions> |
||||
</LaunchAction> |
||||
<ProfileAction |
||||
buildConfiguration = "Release" |
||||
shouldUseLaunchSchemeArgsEnv = "YES" |
||||
savedToolIdentifier = "" |
||||
useCustomWorkingDirectory = "NO" |
||||
debugDocumentVersioning = "YES"> |
||||
</ProfileAction> |
||||
<AnalyzeAction |
||||
buildConfiguration = "Debug"> |
||||
</AnalyzeAction> |
||||
<ArchiveAction |
||||
buildConfiguration = "Release" |
||||
revealArchiveInOrganizer = "YES"> |
||||
</ArchiveAction> |
||||
</Scheme> |
@ -0,0 +1,22 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>CFBundleDevelopmentRegion</key> |
||||
<string>$(DEVELOPMENT_LANGUAGE)</string> |
||||
<key>CFBundleExecutable</key> |
||||
<string>$(EXECUTABLE_NAME)</string> |
||||
<key>CFBundleIdentifier</key> |
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||
<key>CFBundleInfoDictionaryVersion</key> |
||||
<string>6.0</string> |
||||
<key>CFBundleName</key> |
||||
<string>$(PRODUCT_NAME)</string> |
||||
<key>CFBundlePackageType</key> |
||||
<string>BNDL</string> |
||||
<key>CFBundleShortVersionString</key> |
||||
<string>1.0</string> |
||||
<key>CFBundleVersion</key> |
||||
<string>1</string> |
||||
</dict> |
||||
</plist> |
@ -0,0 +1,50 @@ |
||||
source 'https://github.com/CocoaPods/Specs.git' |
||||
platform :ios, '8.0' |
||||
|
||||
install! 'cocoapods', :deterministic_uuids => false |
||||
|
||||
# Location of gRPC's repo root relative to this file. |
||||
GRPC_LOCAL_SRC = '../../../../..' |
||||
|
||||
# Install the dependencies in the main target plus all test targets. |
||||
target 'CFStreamTests' do |
||||
pod 'gRPC-Core/CFStream-Implementation', :path => GRPC_LOCAL_SRC |
||||
end |
||||
|
||||
pre_install do |installer| |
||||
# This is the gRPC-Core podspec object, as initialized by its podspec file. |
||||
grpc_core_spec = installer.pod_targets.find{|t| t.name == 'gRPC-Core'}.root_spec |
||||
|
||||
# Copied from gRPC-Core.podspec, except for the adjusted src_root: |
||||
src_root = "$(PODS_ROOT)/../#{GRPC_LOCAL_SRC}" |
||||
grpc_core_spec.pod_target_xcconfig = { |
||||
'GRPC_SRC_ROOT' => src_root, |
||||
'HEADER_SEARCH_PATHS' => '"$(inherited)" "$(GRPC_SRC_ROOT)/include"', |
||||
'USER_HEADER_SEARCH_PATHS' => '"$(GRPC_SRC_ROOT)"', |
||||
# If we don't set these two settings, `include/grpc/support/time.h` and |
||||
# `src/core/lib/gpr/string.h` shadow the system `<time.h>` and `<string.h>`, breaking the |
||||
# build. |
||||
'USE_HEADERMAP' => 'NO', |
||||
'ALWAYS_SEARCH_USER_PATHS' => 'NO', |
||||
} |
||||
end |
||||
|
||||
post_install do |installer| |
||||
installer.pods_project.targets.each do |target| |
||||
target.build_configurations.each do |config| |
||||
config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES' |
||||
end |
||||
|
||||
# CocoaPods creates duplicated library targets of gRPC-Core when the test targets include |
||||
# non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core' |
||||
# and require the same error suppresion. |
||||
if target.name.start_with?('gRPC-Core') |
||||
target.build_configurations.each do |config| |
||||
# TODO(zyc): Remove this setting after the issue is resolved |
||||
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void |
||||
# function" warning |
||||
config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO' |
||||
end |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,39 @@ |
||||
#!/bin/bash |
||||
# Copyright 2018 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# Don't run this script standalone. Instead, run from the repository root: |
||||
# ./tools/run_tests/run_tests.py -l objc |
||||
|
||||
set -e |
||||
|
||||
# CocoaPods requires the terminal to be using UTF-8 encoding. |
||||
export LANG=en_US.UTF-8 |
||||
|
||||
cd "$(dirname "$0")" |
||||
|
||||
hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; } |
||||
hash xcodebuild 2>/dev/null || { |
||||
echo >&2 "XCode command-line tools need to be installed." |
||||
exit 1 |
||||
} |
||||
|
||||
# clean the directory |
||||
rm -rf Pods |
||||
rm -rf CFStreamTests.xcworkspace |
||||
rm -f Podfile.lock |
||||
|
||||
echo "TIME: $(date)" |
||||
pod install |
||||
|
@ -0,0 +1,67 @@ |
||||
#!/bin/bash |
||||
# Copyright 2018 gRPC authors. |
||||
# |
||||
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||
# you may not use this file except in compliance with the License. |
||||
# You may obtain a copy of the License at |
||||
# |
||||
# http://www.apache.org/licenses/LICENSE-2.0 |
||||
# |
||||
# Unless required by applicable law or agreed to in writing, software |
||||
# distributed under the License is distributed on an "AS IS" BASIS, |
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
# See the License for the specific language governing permissions and |
||||
# limitations under the License. |
||||
|
||||
# Don't run this script standalone. Instead, run from the repository root: |
||||
# ./tools/run_tests/run_tests.py -l objc |
||||
|
||||
set -ev |
||||
|
||||
cd "$(dirname "$0")" |
||||
|
||||
echo "TIME: $(date)" |
||||
|
||||
XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )' |
||||
|
||||
xcodebuild \ |
||||
-workspace CFStreamTests.xcworkspace \ |
||||
-scheme CFStreamTests \ |
||||
-destination name="iPhone 8" \ |
||||
test \ |
||||
| egrep -v "$XCODEBUILD_FILTER" \ |
||||
| egrep -v '^$' \ |
||||
| egrep -v "(GPBDictionary|GPBArray)" - |
||||
|
||||
echo "TIME: $(date)" |
||||
|
||||
xcodebuild \ |
||||
-workspace CFStreamTests.xcworkspace \ |
||||
-scheme CFStreamTests_Asan \ |
||||
-destination name="iPhone 8" \ |
||||
test \ |
||||
| egrep -v "$XCODEBUILD_FILTER" \ |
||||
| egrep -v '^$' \ |
||||
| egrep -v "(GPBDictionary|GPBArray)" - |
||||
|
||||
echo "TIME: $(date)" |
||||
|
||||
xcodebuild \ |
||||
-workspace CFStreamTests.xcworkspace \ |
||||
-scheme CFStreamTests_Tsan \ |
||||
-destination name="iPhone 8" \ |
||||
test \ |
||||
| egrep -v "$XCODEBUILD_FILTER" \ |
||||
| egrep -v '^$' \ |
||||
| egrep -v "(GPBDictionary|GPBArray)" - |
||||
|
||||
echo "TIME: $(date)" |
||||
|
||||
xcodebuild \ |
||||
-workspace CFStreamTests.xcworkspace \ |
||||
-scheme CFStreamTests_Msan \ |
||||
-destination name="iPhone 8" \ |
||||
test \ |
||||
| egrep -v "$XCODEBUILD_FILTER" \ |
||||
| egrep -v '^$' \ |
||||
| egrep -v "(GPBDictionary|GPBArray)" - |
Loading…
Reference in new issue