1589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian/*
2589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * Copyright (C) 2010 The Android Open Source Project
3589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian *
4589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
5589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * you may not use this file except in compliance with the License.
6589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * You may obtain a copy of the License at
7589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian *
8589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
9589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian *
10589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * Unless required by applicable law or agreed to in writing, software
11589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
12589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * See the License for the specific language governing permissions and
14589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian * limitations under the License.
15589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian */
16589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
17801ea093b0e923a61b832f2adba698a273479880Mathias Agopian#include <private/gui/BitTube.h>
18801ea093b0e923a61b832f2adba698a273479880Mathias Agopian
19589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian#include <stdint.h>
207b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian#include <sys/socket.h>
2127c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza#include <sys/types.h>
22589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
23589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian#include <fcntl.h>
2499fe3c6d3dcb6fb26bf283343f946d031b052dffMathias Agopian#include <unistd.h>
25589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
26589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian#include <utils/Errors.h>
27589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
28589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian#include <binder/Parcel.h>
29589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
30589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopiannamespace android {
3127c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozanamespace gui {
32589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
3327c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza// Socket buffer size.  The default is typically about 128KB, which is much larger than we really
3427c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza// need. So we make it smaller.
3590ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopianstatic const size_t DEFAULT_SOCKET_BUFFER_SIZE = 4 * 1024;
367b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian
377d290174b08a56ae6bc6719bec58805ca38b348bDan StozaBitTube::BitTube(size_t bufsize) {
3890ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    init(bufsize, bufsize);
39589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
40589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
417d290174b08a56ae6bc6719bec58805ca38b348bDan StozaBitTube::BitTube(DefaultSizeType) : BitTube(DEFAULT_SOCKET_BUFFER_SIZE) {}
42589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
437d290174b08a56ae6bc6719bec58805ca38b348bDan StozaBitTube::BitTube(const Parcel& data) {
447d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    readFromParcel(&data);
45589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
46589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
4790ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopianvoid BitTube::init(size_t rcvbuf, size_t sndbuf) {
4890ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    int sockets[2];
4990ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) {
5090ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        size_t size = DEFAULT_SOCKET_BUFFER_SIZE;
5190ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
5290ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
5327c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza        // since we don't use the "return channel", we keep it small...
5490ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
5590ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
5690ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        fcntl(sockets[0], F_SETFL, O_NONBLOCK);
5790ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        fcntl(sockets[1], F_SETFL, O_NONBLOCK);
587d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        mReceiveFd.reset(sockets[0]);
597d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        mSendFd.reset(sockets[1]);
6090ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    } else {
617d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        mReceiveFd.reset();
627d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        ALOGE("BitTube: pipe creation failed (%s)", strerror(errno));
6390ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    }
6490ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian}
6590ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian
6627c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozastatus_t BitTube::initCheck() const {
675cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    if (mReceiveFd < 0) {
685cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian        return status_t(mReceiveFd);
695cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    }
705cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    return NO_ERROR;
715cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian}
725cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian
7327c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozaint BitTube::getFd() const {
74589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian    return mReceiveFd;
75589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
76589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
7727c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozaint BitTube::getSendFd() const {
7856ae42613c91f6a6fb0dc3f626daa24666fd18c2Aravind Akella    return mSendFd;
7956ae42613c91f6a6fb0dc3f626daa24666fd18c2Aravind Akella}
8056ae42613c91f6a6fb0dc3f626daa24666fd18c2Aravind Akella
816b698e4fe4ff50dcef818452283637f9870ae770Dan Stozabase::unique_fd BitTube::moveReceiveFd() {
826b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza    return std::move(mReceiveFd);
836b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza}
846b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza
856b698e4fe4ff50dcef818452283637f9870ae770Dan Stozavoid BitTube::setReceiveFd(base::unique_fd&& receiveFd) {
866b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza    mReceiveFd = std::move(receiveFd);
876b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza}
886b698e4fe4ff50dcef818452283637f9870ae770Dan Stoza
8927c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozassize_t BitTube::write(void const* vaddr, size_t size) {
905cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    ssize_t err, len;
915cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    do {
927b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian        len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
9390ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian        // cannot return less than size, since we're using SOCK_SEQPACKET
945cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian        err = len < 0 ? errno : 0;
955cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    } while (err == EINTR);
965cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    return err == 0 ? len : -err;
97589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
98589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
9927c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozassize_t BitTube::read(void* vaddr, size_t size) {
1005cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    ssize_t err, len;
1015cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    do {
1027b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian        len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
1035cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian        err = len < 0 ? errno : 0;
1045cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    } while (err == EINTR);
1053ad3807a5c4039618175c042a1121c926c2c62e9Mathias Agopian    if (err == EAGAIN || err == EWOULDBLOCK) {
10627c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza        // EAGAIN means that we have non-blocking I/O but there was no data to be read. Nothing the
10727c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza        // client should care about.
1083ad3807a5c4039618175c042a1121c926c2c62e9Mathias Agopian        return 0;
1093ad3807a5c4039618175c042a1121c926c2c62e9Mathias Agopian    }
1105cae0d0699a169e468fff3e21165f35db12f2cdeMathias Agopian    return err == 0 ? len : -err;
111589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
112589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
11327c8115510cebda13cbe24fd4caa946ea9c5003cDan Stozastatus_t BitTube::writeToParcel(Parcel* reply) const {
11427c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza    if (mReceiveFd < 0) return -EINVAL;
115589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
116589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian    status_t result = reply->writeDupFileDescriptor(mReceiveFd);
1177d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    mReceiveFd.reset();
118589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian    return result;
119589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian}
120589ce85ee4174829cfedce91b6b2509d2a4002ebMathias Agopian
1217d290174b08a56ae6bc6719bec58805ca38b348bDan Stozastatus_t BitTube::readFromParcel(const Parcel* parcel) {
1227d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    mReceiveFd.reset(dup(parcel->readFileDescriptor()));
1237d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    if (mReceiveFd < 0) {
1247d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        mReceiveFd.reset();
1257d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        int error = errno;
1267d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        ALOGE("BitTube::readFromParcel: can't dup file descriptor (%s)", strerror(error));
1277d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza        return -error;
1287d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    }
1297d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza    return NO_ERROR;
1307d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza}
1317d290174b08a56ae6bc6719bec58805ca38b348bDan Stoza
1326b698e4fe4ff50dcef818452283637f9870ae770Dan Stozassize_t BitTube::sendObjects(BitTube* tube, void const* events, size_t count, size_t objSize) {
13390ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    const char* vaddr = reinterpret_cast<const char*>(events);
13427c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza    ssize_t size = tube->write(vaddr, count * objSize);
13590ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian
13690ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    // should never happen because of SOCK_SEQPACKET
137d723bd7669b4fc88dc282d8bf8ba5ecb2849d22fDan Stoza    LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
13827c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        "BitTube::sendObjects(count=%zu, size=%zu), res=%zd (partial events were "
13927c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        "sent!)",
14027c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        count, objSize, size);
14190ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian
14227c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza    // ALOGE_IF(size<0, "error %d sending %d events", size, count);
143d723bd7669b4fc88dc282d8bf8ba5ecb2849d22fDan Stoza    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
1447b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian}
1457b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian
1466b698e4fe4ff50dcef818452283637f9870ae770Dan Stozassize_t BitTube::recvObjects(BitTube* tube, void* events, size_t count, size_t objSize) {
14790ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    char* vaddr = reinterpret_cast<char*>(events);
14827c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza    ssize_t size = tube->read(vaddr, count * objSize);
14990ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian
15090ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian    // should never happen because of SOCK_SEQPACKET
151d723bd7669b4fc88dc282d8bf8ba5ecb2849d22fDan Stoza    LOG_ALWAYS_FATAL_IF((size >= 0) && (size % static_cast<ssize_t>(objSize)),
15227c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        "BitTube::recvObjects(count=%zu, size=%zu), res=%zd (partial events were "
15327c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        "received!)",
15427c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza                        count, objSize, size);
15590ed3e8d7883d9c80fb8bf11b1c593bd8b2b39d0Mathias Agopian
15627c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza    // ALOGE_IF(size<0, "error %d receiving %d events", size, count);
157d723bd7669b4fc88dc282d8bf8ba5ecb2849d22fDan Stoza    return size < 0 ? size : size / static_cast<ssize_t>(objSize);
1587b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian}
1597b5be95cb3903087742f1079fe89cddd8abe3696Mathias Agopian
16027c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza} // namespace gui
16127c8115510cebda13cbe24fd4caa946ea9c5003cDan Stoza} // namespace android
162