Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(28)

Side by Side Diff: mojo/edk/system/raw_channel_posix.cc

Issue 1649633002: Remove files that are no longer used in the Port EDK. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/edk/system/raw_channel.cc ('k') | mojo/edk/system/raw_channel_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "mojo/edk/system/raw_channel.h"
6
7 #include <errno.h>
8 #include <stddef.h>
9 #include <sys/socket.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12 #include <sys/uio.h>
13 #include <unistd.h>
14 #include <algorithm>
15 #include <deque>
16 #include <utility>
17
18 #include "base/bind.h"
19 #include "base/location.h"
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "base/memory/weak_ptr.h"
23 #include "base/message_loop/message_loop.h"
24 #include "base/synchronization/lock.h"
25 #include "mojo/edk/embedder/embedder_internal.h"
26 #include "mojo/edk/embedder/platform_channel_utils_posix.h"
27 #include "mojo/edk/embedder/platform_handle.h"
28 #include "mojo/edk/embedder/platform_handle_vector.h"
29 #include "mojo/edk/system/transport_data.h"
30 #include "mojo/public/cpp/system/macros.h"
31
32 #if !defined(SO_PEEK_OFF)
33 #define SO_PEEK_OFF 42
34 #endif
35
36 namespace mojo {
37 namespace edk {
38
39 namespace {
40
41 class RawChannelPosix final : public RawChannel,
42 public base::MessageLoopForIO::Watcher {
43 public:
44 explicit RawChannelPosix(ScopedPlatformHandle handle);
45 ~RawChannelPosix() override;
46
47 PlatformHandle GetFD() { return fd_.get(); }
48
49 private:
50 // |RawChannel| protected methods:
51 // Actually override this so that we can send multiple messages with (only)
52 // FDs if necessary.
53 void EnqueueMessageNoLock(scoped_ptr<MessageInTransit> message) override;
54 // Override this to handle those extra FD-only messages.
55 bool OnReadMessageForRawChannel(
56 const MessageInTransit::View& message_view) override;
57
58 ScopedPlatformHandle ReleaseHandleNoLock(
59 std::vector<char>* serialized_read_buffer,
60 std::vector<char>* serialized_write_buffer,
61 std::vector<int>* serialized_read_fds,
62 std::vector<int>* serialized_write_fds,
63 bool* write_error) override;
64 void SetSerializedFDs(std::vector<int>* serialized_read_fds,
65 std::vector<int>* serialized_write_fds) override;
66 bool IsHandleValid() override;
67 IOResult Read(size_t* bytes_read) override;
68 IOResult ScheduleRead() override;
69 ScopedPlatformHandleVectorPtr GetReadPlatformHandles(
70 size_t num_platform_handles,
71 const void* platform_handle_table) override;
72 size_t SerializePlatformHandles(std::vector<int>* fds) override;
73 IOResult WriteNoLock(size_t* platform_handles_written,
74 size_t* bytes_written) override;
75 IOResult ScheduleWriteNoLock() override;
76 void OnInit() override;
77 void OnShutdownNoLock(scoped_ptr<ReadBuffer> read_buffer,
78 scoped_ptr<WriteBuffer> write_buffer) override;
79
80 // |base::MessageLoopForIO::Watcher| implementation:
81 void OnFileCanReadWithoutBlocking(int fd) override;
82 void OnFileCanWriteWithoutBlocking(int fd) override;
83
84 // Implements most of |Read()| (except for a bit of clean-up):
85 IOResult ReadImpl(size_t* bytes_read);
86
87 // Watches for |fd_| to become writable. Must be called on the I/O thread.
88 void WaitToWrite();
89
90 ScopedPlatformHandle fd_;
91
92 // The following members are only used on the I/O thread:
93 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> read_watcher_;
94 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> write_watcher_;
95
96 bool pending_read_;
97
98 std::deque<PlatformHandle> read_platform_handles_;
99
100 // The following members are used on multiple threads and protected by
101 // |write_lock()|:
102 bool pending_write_;
103
104 // This is used for posting tasks from write threads to the I/O thread. It
105 // must only be accessed under |write_lock_|. The weak pointers it produces
106 // are only used/invalidated on the I/O thread.
107 base::WeakPtrFactory<RawChannelPosix> weak_ptr_factory_;
108
109 MOJO_DISALLOW_COPY_AND_ASSIGN(RawChannelPosix);
110 };
111
112 RawChannelPosix::RawChannelPosix(ScopedPlatformHandle handle)
113 : fd_(std::move(handle)),
114 pending_read_(false),
115 pending_write_(false),
116 weak_ptr_factory_(this) {
117 DCHECK(fd_.is_valid());
118 }
119
120 RawChannelPosix::~RawChannelPosix() {
121 DCHECK(!pending_read_);
122 DCHECK(!pending_write_);
123
124 // No need to take the |write_lock()| here -- if there are still weak pointers
125 // outstanding, then we're hosed anyway (since we wouldn't be able to
126 // invalidate them cleanly, since we might not be on the I/O thread).
127 DCHECK(!weak_ptr_factory_.HasWeakPtrs());
128
129 // These must have been shut down/destroyed on the I/O thread.
130 DCHECK(!read_watcher_);
131 DCHECK(!write_watcher_);
132
133 CloseAllPlatformHandles(&read_platform_handles_);
134 }
135
136 void RawChannelPosix::EnqueueMessageNoLock(
137 scoped_ptr<MessageInTransit> message) {
138 if (message->transport_data()) {
139 PlatformHandleVector* const platform_handles =
140 message->transport_data()->platform_handles();
141 if (platform_handles &&
142 platform_handles->size() > kPlatformChannelMaxNumHandles) {
143 // We can't attach all the FDs to a single message, so we have to "split"
144 // the message. Send as many control messages as needed first with FDs
145 // attached (and no data).
146 size_t i = 0;
147 for (; platform_handles->size() - i > kPlatformChannelMaxNumHandles;
148 i += kPlatformChannelMaxNumHandles) {
149 scoped_ptr<MessageInTransit> fd_message(new MessageInTransit(
150 MessageInTransit::Type::RAW_CHANNEL_POSIX_EXTRA_PLATFORM_HANDLES, 0,
151 nullptr));
152 ScopedPlatformHandleVectorPtr fds(
153 new PlatformHandleVector(
154 platform_handles->begin() + i,
155 platform_handles->begin() + i + kPlatformChannelMaxNumHandles));
156 fd_message->SetTransportData(make_scoped_ptr(new TransportData(
157 std::move(fds), GetSerializedPlatformHandleSize())));
158 RawChannel::EnqueueMessageNoLock(std::move(fd_message));
159 }
160
161 // Remove the handles that we "moved" into the other messages.
162 platform_handles->erase(platform_handles->begin(),
163 platform_handles->begin() + i);
164 }
165 }
166
167 RawChannel::EnqueueMessageNoLock(std::move(message));
168 }
169
170 bool RawChannelPosix::OnReadMessageForRawChannel(
171 const MessageInTransit::View& message_view) {
172 if (message_view.type() ==
173 MessageInTransit::Type::RAW_CHANNEL_POSIX_EXTRA_PLATFORM_HANDLES) {
174 // We don't need to do anything. |RawChannel| won't extract the platform
175 // handles, and they'll be accumulated in |Read()|.
176 return true;
177 }
178
179 return RawChannel::OnReadMessageForRawChannel(message_view);
180 }
181
182
183 ScopedPlatformHandle RawChannelPosix::ReleaseHandleNoLock(
184 std::vector<char>* serialized_read_buffer,
185 std::vector<char>* serialized_write_buffer,
186 std::vector<int>* serialized_read_fds,
187 std::vector<int>* serialized_write_fds,
188 bool* write_error) {
189 read_watcher_.reset();
190 write_watcher_.reset();
191
192 SerializeReadBuffer(0u, serialized_read_buffer);
193 SerializeWriteBuffer(0u, 0u, serialized_write_buffer, serialized_write_fds);
194
195 while (!read_platform_handles_.empty()) {
196 serialized_read_fds->push_back(read_platform_handles_.front().handle);
197 read_platform_handles_.pop_front();
198 }
199
200 return std::move(fd_);
201 }
202
203 void RawChannelPosix::SetSerializedFDs(
204 std::vector<int>* serialized_read_fds,
205 std::vector<int>* serialized_write_fds) {
206 if (serialized_read_fds) {
207 for(auto i: *serialized_read_fds)
208 read_platform_handles_.push_back(PlatformHandle(i));
209 }
210
211 if (serialized_write_fds) {
212 size_t i = 0;
213 while (i < serialized_write_fds->size()) {
214 size_t batch = std::min(kPlatformChannelMaxNumHandles,
215 serialized_write_fds->size() - i);
216 scoped_ptr<MessageInTransit> fd_message(new MessageInTransit(
217 MessageInTransit::Type::RAW_CHANNEL_POSIX_EXTRA_PLATFORM_HANDLES, 0,
218 nullptr));
219 ScopedPlatformHandleVectorPtr fds(
220 new PlatformHandleVector(serialized_write_fds->begin() + i,
221 serialized_write_fds->begin() + i + batch));
222 fd_message->SetTransportData(make_scoped_ptr(new TransportData(
223 std::move(fds), GetSerializedPlatformHandleSize())));
224 RawChannel::EnqueueMessageNoLock(std::move(fd_message));
225 i += batch;
226 }
227 }
228 }
229
230 bool RawChannelPosix::IsHandleValid() {
231 return fd_.is_valid();
232 }
233
234 RawChannel::IOResult RawChannelPosix::Read(size_t* bytes_read) {
235 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
236 DCHECK(!pending_read_);
237
238 IOResult rv = ReadImpl(bytes_read);
239 if (rv != IO_SUCCEEDED && rv != IO_PENDING) {
240 // Make sure that |OnFileCanReadWithoutBlocking()| won't be called again.
241 read_watcher_.reset();
242 }
243 return rv;
244 }
245
246 RawChannel::IOResult RawChannelPosix::ScheduleRead() {
247 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
248 DCHECK(!pending_read_);
249
250 pending_read_ = true;
251
252 return IO_PENDING;
253 }
254
255 ScopedPlatformHandleVectorPtr RawChannelPosix::GetReadPlatformHandles(
256 size_t num_platform_handles,
257 const void* /*platform_handle_table*/) {
258 DCHECK_GT(num_platform_handles, 0u);
259
260 if (read_platform_handles_.size() < num_platform_handles) {
261 CloseAllPlatformHandles(&read_platform_handles_);
262 read_platform_handles_.clear();
263 return ScopedPlatformHandleVectorPtr();
264 }
265
266 ScopedPlatformHandleVectorPtr rv(
267 new PlatformHandleVector(num_platform_handles));
268 rv->assign(read_platform_handles_.begin(),
269 read_platform_handles_.begin() + num_platform_handles);
270 read_platform_handles_.erase(
271 read_platform_handles_.begin(),
272 read_platform_handles_.begin() + num_platform_handles);
273 return rv;
274 }
275
276 size_t RawChannelPosix::SerializePlatformHandles(std::vector<int>* fds) {
277 if (!write_buffer_no_lock()->HavePlatformHandlesToSend())
278 return 0u;
279
280 size_t num_platform_handles;
281 PlatformHandle* platform_handles;
282 void* serialization_data; // Actually unused.
283 write_buffer_no_lock()->GetPlatformHandlesToSend(
284 &num_platform_handles, &platform_handles, &serialization_data);
285 DCHECK_GT(num_platform_handles, 0u);
286 DCHECK_LE(num_platform_handles, kPlatformChannelMaxNumHandles);
287 for (size_t i = 0; i < num_platform_handles; ++i)
288 fds->push_back(platform_handles[i].handle);
289 return num_platform_handles;
290 }
291
292 RawChannel::IOResult RawChannelPosix::WriteNoLock(
293 size_t* platform_handles_written,
294 size_t* bytes_written) {
295 write_lock().AssertAcquired();
296
297 DCHECK(!pending_write_);
298
299 size_t num_platform_handles = 0;
300 ssize_t write_result;
301 if (write_buffer_no_lock()->HavePlatformHandlesToSend()) {
302 PlatformHandle* platform_handles;
303 void* serialization_data; // Actually unused.
304 write_buffer_no_lock()->GetPlatformHandlesToSend(
305 &num_platform_handles, &platform_handles, &serialization_data);
306 DCHECK_GT(num_platform_handles, 0u);
307 DCHECK_LE(num_platform_handles, kPlatformChannelMaxNumHandles);
308 DCHECK(platform_handles);
309
310 // TODO(vtl): Reduce code duplication. (This is duplicated from below.)
311 std::vector<WriteBuffer::Buffer> buffers;
312 write_buffer_no_lock()->GetBuffers(&buffers);
313 DCHECK(!buffers.empty());
314 const size_t kMaxBufferCount = 10;
315 iovec iov[kMaxBufferCount];
316 size_t buffer_count = std::min(buffers.size(), kMaxBufferCount);
317 for (size_t i = 0; i < buffer_count; ++i) {
318 iov[i].iov_base = const_cast<char*>(buffers[i].addr);
319 iov[i].iov_len = buffers[i].size;
320 }
321
322 write_result = PlatformChannelSendmsgWithHandles(
323 fd_.get(), iov, buffer_count, platform_handles, num_platform_handles);
324 if (write_result >= 0) {
325 for (size_t i = 0; i < num_platform_handles; i++)
326 platform_handles[i].CloseIfNecessary();
327 }
328 } else {
329 std::vector<WriteBuffer::Buffer> buffers;
330 write_buffer_no_lock()->GetBuffers(&buffers);
331 DCHECK(!buffers.empty());
332
333 if (buffers.size() == 1) {
334 write_result = PlatformChannelWrite(fd_.get(), buffers[0].addr,
335 buffers[0].size);
336 } else {
337 const size_t kMaxBufferCount = 10;
338 iovec iov[kMaxBufferCount];
339 size_t buffer_count = std::min(buffers.size(), kMaxBufferCount);
340 for (size_t i = 0; i < buffer_count; ++i) {
341 iov[i].iov_base = const_cast<char*>(buffers[i].addr);
342 iov[i].iov_len = buffers[i].size;
343 }
344
345 write_result = PlatformChannelWritev(fd_.get(), iov, buffer_count);
346 }
347 }
348
349 if (write_result >= 0) {
350 *platform_handles_written = num_platform_handles;
351 *bytes_written = static_cast<size_t>(write_result);
352 return IO_SUCCEEDED;
353 }
354
355 if (errno == EPIPE)
356 return IO_FAILED_SHUTDOWN;
357
358 if (errno != EAGAIN && errno != EWOULDBLOCK) {
359 PLOG(WARNING) << "sendmsg/write/writev";
360 return IO_FAILED_UNKNOWN;
361 }
362
363 return ScheduleWriteNoLock();
364 }
365
366 RawChannel::IOResult RawChannelPosix::ScheduleWriteNoLock() {
367 write_lock().AssertAcquired();
368
369 DCHECK(!pending_write_);
370
371 // Set up to wait for the FD to become writable.
372 // If we're not on the I/O thread, we have to post a task to do this.
373 if (!internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()) {
374 internal::g_io_thread_task_runner->PostTask(
375 FROM_HERE,
376 base::Bind(&RawChannelPosix::WaitToWrite,
377 weak_ptr_factory_.GetWeakPtr()));
378 pending_write_ = true;
379 return IO_PENDING;
380 }
381
382 if (base::MessageLoopForIO::current()->WatchFileDescriptor(
383 fd_.get().handle, false, base::MessageLoopForIO::WATCH_WRITE,
384 write_watcher_.get(), this)) {
385 pending_write_ = true;
386 return IO_PENDING;
387 }
388
389 return IO_FAILED_UNKNOWN;
390 }
391
392 void RawChannelPosix::OnInit() {
393 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
394 if (!fd_.is_valid()) {
395 DVLOG(1) << "Note: RawChannelPOSIX " << this << " early exiting in OnInit "
396 << "because there's no fd. This is valid if it's been sent.";
397 return;
398 }
399
400 DCHECK(!read_watcher_);
401 read_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher());
402 DCHECK(!write_watcher_);
403 write_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher());
404
405 // I don't know how this can fail (unless |fd_| is bad, in which case it's a
406 // bug in our code). I also don't know if |WatchFileDescriptor()| actually
407 // fails cleanly.
408 CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor(
409 fd_.get().handle, true, base::MessageLoopForIO::WATCH_READ,
410 read_watcher_.get(), this));
411 }
412
413 void RawChannelPosix::OnShutdownNoLock(
414 scoped_ptr<ReadBuffer> /*read_buffer*/,
415 scoped_ptr<WriteBuffer> /*write_buffer*/) {
416 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
417 write_lock().AssertAcquired();
418
419 read_watcher_.reset(); // This will stop watching (if necessary).
420 write_watcher_.reset(); // This will stop watching (if necessary).
421
422 pending_read_ = false;
423 pending_write_ = false;
424
425 fd_.reset();
426
427 weak_ptr_factory_.InvalidateWeakPtrs();
428 }
429
430 void RawChannelPosix::OnFileCanReadWithoutBlocking(int fd) {
431 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
432 base::AutoLock locker(read_lock());
433 if (!fd_.is_valid()) {
434 pending_read_ = false;
435 return; // ReleaseHandle has been called.
436 }
437
438 if (!pending_read_) {
439 NOTREACHED();
440 return;
441 }
442
443 pending_read_ = false;
444 size_t bytes_read = 0;
445 IOResult io_result = Read(&bytes_read);
446 if (io_result != IO_PENDING) {
447 OnReadCompletedNoLock(io_result, bytes_read);
448 // TODO(vtl): If we weren't destroyed, we'd like to do
449 //
450 // DCHECK(!read_watcher_ || pending_read_);
451 //
452 // On failure, |read_watcher_| must have been reset; on success, we assume
453 // that |OnReadCompleted()| always schedules another read. Otherwise, we
454 // could end up spinning -- getting |OnFileCanReadWithoutBlocking()| again
455 // and again but not doing any actual read.
456 // TODO(yzshen): An alternative is to stop watching if RawChannel doesn't
457 // schedule a new read. But that code won't be reached under the current
458 // RawChannel implementation.
459 return; // |this| may have been destroyed in |OnReadCompleted()|.
460 }
461
462 DCHECK(pending_read_);
463 }
464
465 void RawChannelPosix::OnFileCanWriteWithoutBlocking(int fd) {
466 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
467 base::AutoLock locker(read_lock());
468 if (!fd_.is_valid()) {
469 pending_write_ = false;
470 return; // ReleaseHandle has been called.
471 }
472
473 IOResult io_result;
474 size_t platform_handles_written = 0;
475 size_t bytes_written = 0;
476 {
477 base::AutoLock locker(write_lock());
478
479 DCHECK(pending_write_);
480
481 pending_write_ = false;
482 io_result = WriteNoLock(&platform_handles_written, &bytes_written);
483 }
484
485 if (io_result != IO_PENDING) {
486 base::AutoLock locker(write_lock());
487 OnWriteCompletedNoLock(io_result, platform_handles_written, bytes_written);
488 return;
489 }
490 }
491
492 RawChannel::IOResult RawChannelPosix::ReadImpl(size_t* bytes_read) {
493 char* buffer = nullptr;
494 size_t bytes_to_read = 0;
495 read_buffer()->GetBuffer(&buffer, &bytes_to_read);
496
497 size_t old_num_platform_handles = read_platform_handles_.size();
498 ssize_t read_result = PlatformChannelRecvmsg(
499 fd_.get(), buffer, bytes_to_read, &read_platform_handles_);
500 if (read_platform_handles_.size() > old_num_platform_handles) {
501 DCHECK_LE(read_platform_handles_.size() - old_num_platform_handles,
502 kPlatformChannelMaxNumHandles);
503
504 // We should never accumulate more than |TransportData::kMaxPlatformHandles
505 // + kPlatformChannelMaxNumHandles| handles. (The latter part is
506 // possible because we could have accumulated all the handles for a message,
507 // then received the message data plus the first set of handles for the next
508 // message in the subsequent |recvmsg()|.)
509 if (read_platform_handles_.size() >
510 (TransportData::GetMaxPlatformHandles() +
511 kPlatformChannelMaxNumHandles)) {
512 LOG(ERROR) << "Received too many platform handles";
513 CloseAllPlatformHandles(&read_platform_handles_);
514 read_platform_handles_.clear();
515 return IO_FAILED_UNKNOWN;
516 }
517 }
518
519 if (read_result > 0) {
520 *bytes_read = static_cast<size_t>(read_result);
521 return IO_SUCCEEDED;
522 }
523
524 // |read_result == 0| means "end of file".
525 if (read_result == 0)
526 return IO_FAILED_SHUTDOWN;
527
528 if (errno == EAGAIN || errno == EWOULDBLOCK)
529 return ScheduleRead();
530
531 if (errno == ECONNRESET)
532 return IO_FAILED_BROKEN;
533
534 PLOG(WARNING) << "recvmsg";
535 return IO_FAILED_UNKNOWN;
536 }
537
538 void RawChannelPosix::WaitToWrite() {
539 DCHECK(internal::g_io_thread_task_runner->RunsTasksOnCurrentThread());
540
541 DCHECK(write_watcher_);
542
543 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
544 fd_.get().handle, false, base::MessageLoopForIO::WATCH_WRITE,
545 write_watcher_.get(), this)) {
546 base::AutoLock locker(write_lock());
547 DCHECK(pending_write_);
548 pending_write_ = false;
549 OnWriteCompletedNoLock(IO_FAILED_UNKNOWN, 0, 0);
550 return;
551 }
552 }
553
554 } // namespace
555
556 // -----------------------------------------------------------------------------
557
558 // Static factory method declared in raw_channel.h.
559 // static
560 RawChannel* RawChannel::Create(ScopedPlatformHandle handle) {
561 return new RawChannelPosix(std::move(handle));
562 }
563
564 size_t RawChannel::GetSerializedPlatformHandleSize() {
565 // We don't actually need any space on POSIX (since we just send FDs).
566 return 0;
567 }
568
569 bool RawChannel::IsOtherEndOf(RawChannel* other) {
570 #if defined(OFFICIAL_BUILD)
571 return false;
572 #else
573 // We don't check the return code of getsockopt because this is only available
574 // on Linux after 3.4. This is a developer error, so we just have to catch it
575 // on platforms that developers use.
576 // Note that since we're storing a 32 bit integer, we can get collisions so we
577 // will only use it in non-official builds.
578 DCHECK_NE(other, this);
579 PlatformHandle this_handle = static_cast<RawChannelPosix*>(this)->GetFD();
580 PlatformHandle other_handle = static_cast<RawChannelPosix*>(other)->GetFD();
581
582 int id1 = 0;
583 int id2 = 1;
584 socklen_t peek_off_size = sizeof(id1);
585 getsockopt(this_handle.handle, SOL_SOCKET, SO_PEEK_OFF, &id1, &peek_off_size);
586 getsockopt(other_handle.handle, SOL_SOCKET, SO_PEEK_OFF, &id2,
587 &peek_off_size);
588 return id1 == id2;
589 #endif
590 }
591
592 } // namespace edk
593 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/raw_channel.cc ('k') | mojo/edk/system/raw_channel_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698