1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define LOG_TAG "mq"
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <assert.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <fcntl.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <pthread.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/socket.h>
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h>
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/un.h>
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/uio.h>
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/array.h>
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/hashmap.h>
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <cutils/selector.h>
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "loghack.h"
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "buffer.h"
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Number of dead peers to remember. */
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#define PEER_HISTORY (16)
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct sockaddr SocketAddress;
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct sockaddr_un UnixAddress;
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Process/user/group ID. We don't use ucred directly because it's only
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * available on Linux.
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct {
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid;
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    uid_t uid;
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    gid_t gid;
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} Credentials;
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Listens for bytes coming from remote peers. */
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef void BytesListener(Credentials credentials, char* bytes, size_t size);
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Listens for the deaths of remote peers. */
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef void DeathListener(pid_t pid);
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Types of packets. */
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef enum {
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Request for a connection to another peer. */
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    CONNECTION_REQUEST,
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** A connection to another peer. */
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    CONNECTION,
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Reports a failed connection attempt. */
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    CONNECTION_ERROR,
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** A generic packet of bytes. */
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    BYTES,
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} PacketType;
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef enum {
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Reading a packet header. */
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    READING_HEADER,
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Waiting for a connection from the master. */
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ACCEPTING_CONNECTION,
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Reading bytes. */
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    READING_BYTES,
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} InputState;
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** A packet header. */
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project// TODO: Use custom headers for master->peer, peer->master, peer->peer.
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct {
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PacketType type;
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    union {
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /** Packet size. Used for BYTES. */
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        size_t size;
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /** Credentials. Used for CONNECTION and CONNECTION_REQUEST. */
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Credentials credentials;
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    };
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} Header;
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** A packet which will be sent to a peer. */
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct OutgoingPacket OutgoingPacket;
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct OutgoingPacket {
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Packet header. */
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Header header;
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    union {
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /** Connection to peer. Used with CONNECTION. */
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        int socket;
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        /** Buffer of bytes. Used with BYTES. */
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Buffer* bytes;
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    };
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Frees all resources associated with this packet. */
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    void (*free)(OutgoingPacket* packet);
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Optional context. */
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    void* context;
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Next packet in the queue. */
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* nextPacket;
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Represents a remote peer. */
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct PeerProxy PeerProxy;
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Local peer state. You typically have one peer per process. */
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct {
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** This peer's PID. */
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid;
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /**
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Map from pid to peer proxy. The peer has a peer proxy for each remote
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * peer it's connected to.
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     *
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Acquire mutex before use.
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Hashmap* peerProxies;
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Manages I/O. */
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Selector* selector;
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Used to synchronize operations with the selector thread. */
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_t mutex;
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Is this peer the master? */
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool master;
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Peer proxy for the master. */
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* masterProxy;
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Listens for packets from remote peers. */
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    BytesListener* onBytes;
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Listens for deaths of remote peers. */
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    DeathListener* onDeath;
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Keeps track of recently dead peers. Requires mutex. */
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t deadPeers[PEER_HISTORY];
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    size_t deadPeerCursor;
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} Peer;
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstruct PeerProxy {
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Credentials of the remote process. */
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Credentials credentials;
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Keeps track of data coming in from the remote peer. */
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    InputState inputState;
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* inputBuffer;
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* connecting;
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** File descriptor for this peer. */
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* fd;
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /**
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Queue of packets to be written out to the remote peer.
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     *
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Requires mutex.
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // TODO: Limit queue length.
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* currentPacket;
182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* lastPacket;
183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Used to write outgoing header. */
185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer outgoingHeader;
186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** True if this is the master's proxy. */
188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool master;
189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /** Reference back to the local peer. */
191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer;
192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /**
194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * Used in master only. Maps this peer proxy to other peer proxies to
195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * which the peer has been connected to. Maps pid to PeerProxy. Helps
196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     * keep track of which connections we've sent to whom.
197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project     */
198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Hashmap* connections;
199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project};
200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Server socket path. */
202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic const char* MASTER_PATH = "/master.peer";
203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Credentials of the master peer. */
205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic const Credentials MASTER_CREDENTIALS = {0, 0, 0};
206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Creates a peer proxy and adds it to the peer proxy map. */
208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials);
209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Sets the non-blocking flag on a descriptor. */
211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void setNonBlocking(int fd) {
212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int flags;
213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("fcntl() error: %s", strerror(errno));
218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Closes a fd and logs a warning if the close fails. */
222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void closeWithWarning(int fd) {
223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int result = close(fd);
224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result == -1) {
225ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("close() error: %s", strerror(errno));
226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Hashes pid_t keys. */
230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic int pidHash(void* key) {
231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t* pid = (pid_t*) key;
232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return (int) (*pid);
233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Compares pid_t keys. */
236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool pidEquals(void* keyA, void* keyB) {
237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t* a = (pid_t*) keyA;
238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t* b = (pid_t*) keyB;
239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return *a == *b;
240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Gets the master address. Not thread safe. */
243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic UnixAddress* getMasterAddress() {
244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    static UnixAddress masterAddress;
245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    static bool initialized = false;
246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (initialized == false) {
247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        masterAddress.sun_family = AF_LOCAL;
248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        strcpy(masterAddress.sun_path, MASTER_PATH);
249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        initialized = true;
250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return &masterAddress;
252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Gets exclusive access to the peer for this thread. */
255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerLock(Peer* peer) {
256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_lock(&peer->mutex);
257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Releases exclusive access to the peer. */
260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerUnlock(Peer* peer) {
261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutex_unlock(&peer->mutex);
262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Frees a simple, i.e. header-only, outgoing packet. */
265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void outgoingPacketFree(OutgoingPacket* packet) {
2668d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Freeing outgoing packet.");
267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project	free(packet);
268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Prepare to read a new packet from the peer.
272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
273dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyExpectHeader(PeerProxy* peerProxy) {
274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->inputState = READING_HEADER;
275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferPrepareForRead(peerProxy->inputBuffer, sizeof(Header));
276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Sets up the buffer for the outgoing header. */
279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyPrepareOutgoingHeader(PeerProxy* peerProxy) {
280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->outgoingHeader.data
281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        = (char*) &(peerProxy->currentPacket->header);
282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->outgoingHeader.size = sizeof(Header);
283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferPrepareForWrite(&peerProxy->outgoingHeader);
284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Adds a packet to the end of the queue. Callers must have the mutex. */
287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyEnqueueOutgoingPacket(PeerProxy* peerProxy,
288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        OutgoingPacket* newPacket) {
289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    newPacket->nextPacket = NULL; // Just in case.
290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy->currentPacket == NULL) {
291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // The queue is empty.
292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->currentPacket = newPacket;
293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->lastPacket = newPacket;
294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyPrepareOutgoingHeader(peerProxy);
296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->lastPacket->nextPacket = newPacket;
298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Takes the peer lock and enqueues the given packet. */
302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyLockAndEnqueueOutgoingPacket(PeerProxy* peerProxy,
303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        OutgoingPacket* newPacket) {
304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer = peerProxy->peer;
305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peer);
306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyEnqueueOutgoingPacket(peerProxy, newPacket);
307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(peer);
308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Frees current packet and moves to the next one. Returns true if there is
312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * a next packet or false if the queue is empty.
313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool peerProxyNextPacket(PeerProxy* peerProxy) {
315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer = peerProxy->peer;
316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peer);
317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* current = peerProxy->currentPacket;
319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (current == NULL) {
321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    	// The queue is already empty.
322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* next = current->nextPacket;
327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->currentPacket = next;
328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    current->nextPacket = NULL;
329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    current->free(current);
330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (next == NULL) {
331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // The queue is empty.
332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->lastPacket = NULL;
333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyPrepareOutgoingHeader(peerProxy);
338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // TODO: Start writing next packet? It would reduce the number of
340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // system calls, but we could also starve other peers.
341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return true;
342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Checks whether a peer died recently.
347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool peerIsDead(Peer* peer, pid_t pid) {
349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    size_t i;
350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    for (i = 0; i < PEER_HISTORY; i++) {
351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        pid_t deadPeer = peer->deadPeers[i];
352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (deadPeer == 0) {
353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return false;
354dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (deadPeer == pid) {
356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return true;
357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
358dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
359dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return false;
360dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
361dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
362dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
363dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Cleans up connection information.
364dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
365dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool peerProxyRemoveConnection(void* key, void* value, void* context) {
366dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* deadPeer = (PeerProxy*) context;
367dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* otherPeer = (PeerProxy*) value;
368dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hashmapRemove(otherPeer->connections, &(deadPeer->credentials.pid));
369dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return true;
370dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
371dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
372dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
373dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Called when the peer dies.
374dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
375dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyKill(PeerProxy* peerProxy, bool errnoIsSet) {
376dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (errnoIsSet) {
377fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block        ALOGI("Peer %d died. errno: %s", peerProxy->credentials.pid,
378dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                strerror(errno));
379dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
380fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block        ALOGI("Peer %d died.", peerProxy->credentials.pid);
381dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
382dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
383dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // If we lost the master, we're up a creek. We can't let this happen.
384dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy->master) {
385dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Lost connection to master.");
386dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
387dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
388dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* localPeer = peerProxy->peer;
389dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid = peerProxy->credentials.pid;
390dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
391dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(localPeer);
392dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
393dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Remember for awhile that the peer died.
394dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->deadPeers[localPeer->deadPeerCursor]
395dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        = peerProxy->credentials.pid;
396dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->deadPeerCursor++;
397dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (localPeer->deadPeerCursor == PEER_HISTORY) {
398dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        localPeer->deadPeerCursor = 0;
399dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
400dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
401dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Remove from peer map.
402dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hashmapRemove(localPeer->peerProxies, &pid);
403dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
404dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // External threads can no longer get to this peer proxy, so we don't
405dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // need the lock anymore.
406dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(localPeer);
407dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
408dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Remove the fd from the selector.
409dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy->fd != NULL) {
410dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->fd->remove = true;
411dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
412dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
413dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Clear outgoing packet queue.
414dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while (peerProxyNextPacket(peerProxy)) {}
415dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
416dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferFree(peerProxy->inputBuffer);
417dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
418dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // This only applies to the master.
419dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy->connections != NULL) {
420dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We can't leave these other maps pointing to freed memory.
421dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        hashmapForEach(peerProxy->connections, &peerProxyRemoveConnection,
422dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxy);
423dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        hashmapFree(peerProxy->connections);
424dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
425dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
426dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Invoke death listener.
427dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->onDeath(pid);
428dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
429dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Free the peer proxy itself.
430dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    free(peerProxy);
431dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
432dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
433dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyHandleError(PeerProxy* peerProxy, char* functionName) {
434dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (errno == EINTR) {
435dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Log interruptions but otherwise ignore them.
436ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("%s() interrupted.", functionName);
437dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (errno == EAGAIN) {
4388d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("EWOULDBLOCK");
439dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Ignore.
440dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
441ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Error returned by %s().", functionName);
442dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyKill(peerProxy, true);
443dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
444dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
445dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
446dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
447dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Buffers output sent to a peer. May be called multiple times until the entire
448dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * buffer is filled. Returns true when the buffer is empty.
449dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
450dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool peerProxyWriteFromBuffer(PeerProxy* peerProxy, Buffer* outgoing) {
451dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t size = bufferWrite(outgoing, peerProxy->fd->fd);
452dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (size < 0) {
453dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyHandleError(peerProxy, "write");
454dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
455dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
456dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return bufferWriteComplete(outgoing);
457dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
458dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
459dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
460dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Writes packet bytes to peer. */
461dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyWriteBytes(PeerProxy* peerProxy) {
462dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project	Buffer* buffer = peerProxy->currentPacket->bytes;
463dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project	if (peerProxyWriteFromBuffer(peerProxy, buffer)) {
4648d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Bytes written.");
465dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyNextPacket(peerProxy);
466dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
467dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
468dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
469dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Sends a socket to the peer. */
470dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyWriteConnection(PeerProxy* peerProxy) {
471dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int socket = peerProxy->currentPacket->socket;
472dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
473dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Why does sending and receiving fds have to be such a PITA?
474dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct msghdr msg;
475dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iovec iov[1];
476dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
477dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    union {
478dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct cmsghdr cm;
479dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        char control[CMSG_SPACE(sizeof(int))];
480dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } control_un;
481dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
482dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct cmsghdr *cmptr;
483dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
484dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_control = control_un.control;
485dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_controllen = sizeof(control_un.control);
486dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    cmptr = CMSG_FIRSTHDR(&msg);
487dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    cmptr->cmsg_len = CMSG_LEN(sizeof(int));
488dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    cmptr->cmsg_level = SOL_SOCKET;
489dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    cmptr->cmsg_type = SCM_RIGHTS;
490dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
491dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Store the socket in the message.
492dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    *((int *) CMSG_DATA(cmptr)) = peerProxy->currentPacket->socket;
493dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
494dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_name = NULL;
495dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_namelen = 0;
496dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_base = "";
497dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_len = 1;
498dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_iov = iov;
499dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_iovlen = 1;
500dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
501dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t result = sendmsg(peerProxy->fd->fd, &msg, 0);
502dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
503dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result < 0) {
504dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyHandleError(peerProxy, "sendmsg");
505dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
506dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Success. Queue up the next packet.
507dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyNextPacket(peerProxy);
508dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
509dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
510dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
511dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
512dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
513dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Writes some outgoing data.
514dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
515dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyWrite(SelectableFd* fd) {
516dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // TODO: Try to write header and body with one system call.
517dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
518dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = (PeerProxy*) fd->data;
519dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* current = peerProxy->currentPacket;
520dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
521dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (current == NULL) {
522dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We have nothing left to write.
523dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
524dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
525dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
526dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Write the header.
527dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* outgoingHeader = &peerProxy->outgoingHeader;
528dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool headerWritten = bufferWriteComplete(outgoingHeader);
529dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!headerWritten) {
5308d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Writing header...");
531dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        headerWritten = peerProxyWriteFromBuffer(peerProxy, outgoingHeader);
532dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (headerWritten) {
5338d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block            ALOGD("Header written.");
534dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
535dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
536dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
537dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Write body.
538dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (headerWritten) {
539dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        PacketType type = current->header.type;
540dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        switch (type) {
541dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case CONNECTION:
542dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxyWriteConnection(peerProxy);
543dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
544dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case BYTES:
545dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxyWriteBytes(peerProxy);
546dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
547dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case CONNECTION_REQUEST:
548dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            case CONNECTION_ERROR:
549dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // These packets consist solely of a header.
550dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxyNextPacket(peerProxy);
551dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                break;
552dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            default:
553dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                LOG_ALWAYS_FATAL("Unknown packet type: %d", type);
554dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
555dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
556dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
557dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
558dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
559dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Sets up a peer proxy's fd before we try to select() it.
560dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
561dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyBeforeSelect(SelectableFd* fd) {
5628d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Before select...");
563dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
564dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = (PeerProxy*) fd->data;
565dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
566dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peerProxy->peer);
567dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bool hasPackets = peerProxy->currentPacket != NULL;
568dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(peerProxy->peer);
569dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
570dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (hasPackets) {
5718d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block        ALOGD("Packets found. Setting onWritable().");
572dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
573dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fd->onWritable = &peerProxyWrite;
574dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
575dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We have nothing to write.
576dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fd->onWritable = NULL;
577dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
578dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
579dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
580dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Prepare to read bytes from the peer. */
581dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyExpectBytes(PeerProxy* peerProxy, Header* header) {
5828d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Expecting %d bytes.", header->size);
5838d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block
5848d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    peerProxy->inputState = READING_BYTES;
585dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (bufferPrepareForRead(peerProxy->inputBuffer, header->size) == -1) {
586ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Couldn't allocate memory for incoming data. Size: %u",
587dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                (unsigned int) header->size);
588dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
589dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // TODO: Ignore the packet and log a warning?
590dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyKill(peerProxy, false);
591dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
592dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
593dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
594dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
595dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Gets a peer proxy for the given ID. Creates a peer proxy if necessary.
596dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Sends a connection request to the master if desired.
597dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
598dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Returns NULL if an error occurs. Sets errno to EHOSTDOWN if the peer died
599dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * or ENOMEM if memory couldn't be allocated.
600dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
601dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic PeerProxy* peerProxyGetOrCreate(Peer* peer, pid_t pid,
602dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        bool requestConnection) {
603dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pid == peer->pid) {
604dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = EINVAL;
605dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
606dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
607dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
608dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerIsDead(peer, pid)) {
609dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = EHOSTDOWN;
610dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
611dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
612dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
613dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = hashmapGet(peer->peerProxies, &pid);
614dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy != NULL) {
615dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return peerProxy;
616dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
617dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
618dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // If this is the master peer, we already know about all peers.
619dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peer->master) {
620dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = EHOSTDOWN;
621dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
622dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
623dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
624dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Try to create a peer proxy.
625dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Credentials credentials;
626dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.pid = pid;
627dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
628dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Fake gid and uid until we have the real thing. The real creds are
629dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // filled in by masterProxyExpectConnection(). These fake creds will
630dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // never be exposed to the user.
631dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.uid = 0;
632dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.gid = 0;
633dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
634dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make sure we can allocate the connection request packet.
635dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packet = NULL;
636dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (requestConnection) {
637dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet = calloc(1, sizeof(OutgoingPacket));
638dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (packet == NULL) {
639dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            errno = ENOMEM;
640dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return NULL;
641dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
642dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
643dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet->header.type = CONNECTION_REQUEST;
644dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet->header.credentials = credentials;
645dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet->free = &outgoingPacketFree;
646dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
647dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
648dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy = peerProxyCreate(peer, credentials);
649dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
650dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packet);
651dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
652dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
653dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
654dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Send a connection request to the master.
655dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (requestConnection) {
656dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            PeerProxy* masterProxy = peer->masterProxy;
657dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            peerProxyEnqueueOutgoingPacket(masterProxy, packet);
658dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
659dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
660dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return peerProxy;
661dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
662dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
663dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
664dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
665dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Switches the master peer proxy into a state where it's waiting for a
666dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * connection from the master.
667dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
668dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterProxyExpectConnection(PeerProxy* masterProxy,
669dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Header* header) {
670dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // TODO: Restructure things so we don't need this check.
671dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Verify that this really is the master.
672dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!masterProxy->master) {
673ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Non-master process %d tried to send us a connection.",
674dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterProxy->credentials.pid);
675dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Kill off the evil peer.
676dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyKill(masterProxy, false);
677dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
678dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
679dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
680dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    masterProxy->inputState = ACCEPTING_CONNECTION;
681dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* localPeer = masterProxy->peer;
682dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
683dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create a peer proxy so we have somewhere to stash the creds.
684dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // See if we already have a proxy set up.
685dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid = header->credentials.pid;
686dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(localPeer);
687dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = peerProxyGetOrCreate(localPeer, pid, false);
688dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
689ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Peer proxy creation failed: %s", strerror(errno));
690dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
691dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Fill in full credentials.
692dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxy->credentials = header->credentials;
693dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
694dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(localPeer);
695dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
696dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Keep track of which peer proxy we're accepting a connection for.
697dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    masterProxy->connecting = peerProxy;
698dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
699dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
700dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
701dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Reads input from a peer process.
702dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
703dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyRead(SelectableFd* fd);
704dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
705dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Sets up fd callbacks. */
706dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxySetFd(PeerProxy* peerProxy, SelectableFd* fd) {
707dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->fd = fd;
708dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd->data = peerProxy;
709dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd->onReadable = &peerProxyRead;
710dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fd->beforeSelect = &peerProxyBeforeSelect;
711dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
712dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make the socket non-blocking.
713dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    setNonBlocking(fd->fd);
714dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
715dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
716dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
717dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Accepts a connection sent by the master proxy.
718dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
719dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterProxyAcceptConnection(PeerProxy* masterProxy) {
720dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct msghdr msg;
721dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct iovec iov[1];
722dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t size;
723dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char ignored;
724dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int incomingFd;
725dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
726dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // TODO: Reuse code which writes the connection. Who the heck designed
727dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // this API anyway?
728dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    union {
729dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        struct cmsghdr cm;
730dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        char control[CMSG_SPACE(sizeof(int))];
731dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } control_un;
732dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct cmsghdr *cmptr;
733dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_control = control_un.control;
734dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_controllen = sizeof(control_un.control);
735dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
736dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_name = NULL;
737dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_namelen = 0;
738dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
739dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // We sent 1 byte of data so we can detect EOF.
740dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_base = &ignored;
741dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    iov[0].iov_len = 1;
742dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_iov = iov;
743dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    msg.msg_iovlen = 1;
744dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
745dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    size = recvmsg(masterProxy->fd->fd, &msg, 0);
746dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (size < 0) {
747dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (errno == EINTR) {
748dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Log interruptions but otherwise ignore them.
749ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block            ALOGW("recvmsg() interrupted.");
750dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return;
751dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else if (errno == EAGAIN) {
752dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Keep waiting for the connection.
753dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            return;
754dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
755dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("Error reading connection from master: %s",
756dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    strerror(errno));
757dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
758dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (size == 0) {
759dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // EOF.
760dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Received EOF from master.");
761dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
762dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
763dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Extract fd from message.
764dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if ((cmptr = CMSG_FIRSTHDR(&msg)) != NULL
765dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
766dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (cmptr->cmsg_level != SOL_SOCKET) {
767dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("Expected SOL_SOCKET.");
768dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
769dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (cmptr->cmsg_type != SCM_RIGHTS) {
770dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("Expected SCM_RIGHTS.");
771dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
772dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        incomingFd = *((int*) CMSG_DATA(cmptr));
773dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
774dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Expected fd.");
775dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
776dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
777dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // The peer proxy this connection is for.
778dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = masterProxy->connecting;
779dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
780ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Received connection for unknown peer.");
781dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        closeWithWarning(incomingFd);
782dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
783dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Peer* peer = masterProxy->peer;
784dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
785dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        SelectableFd* selectableFd = selectorAdd(peer->selector, incomingFd);
786dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (selectableFd == NULL) {
787ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block            ALOGW("Error adding fd to selector for %d.",
788dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    peerProxy->credentials.pid);
789dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            closeWithWarning(incomingFd);
790dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            peerProxyKill(peerProxy, false);
791dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
792dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
793dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxySetFd(peerProxy, selectableFd);
794dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
795dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
796dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyExpectHeader(masterProxy);
797dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
798dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
799dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
800dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Frees an outgoing packet containing a connection.
801dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
802dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void outgoingPacketFreeSocket(OutgoingPacket* packet) {
803dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    closeWithWarning(packet->socket);
804dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    outgoingPacketFree(packet);
805dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
806dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
807dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
808dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Connects two known peers.
809dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
810dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterConnectPeers(PeerProxy* peerA, PeerProxy* peerB) {
811dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int sockets[2];
812dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int result = socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets);
813dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result == -1) {
814ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("socketpair() error: %s", strerror(errno));
815dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // TODO: Send CONNECTION_FAILED packets to peers.
816dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
817dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
818dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
819dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packetA = calloc(1, sizeof(OutgoingPacket));
820dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packetB = calloc(1, sizeof(OutgoingPacket));
821dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (packetA == NULL || packetB == NULL) {
822dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packetA);
823dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packetB);
824ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("malloc() error. Failed to tell process %d that process %d is"
825dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                " dead.", peerA->credentials.pid, peerB->credentials.pid);
826dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
827dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
828dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
829dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetA->header.type = CONNECTION;
830dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetB->header.type = CONNECTION;
831dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
832dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetA->header.credentials = peerB->credentials;
833dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetB->header.credentials = peerA->credentials;
834dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
835dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetA->socket = sockets[0];
836dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetB->socket = sockets[1];
837dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
838dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetA->free = &outgoingPacketFreeSocket;
839dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packetB->free = &outgoingPacketFreeSocket;
840dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
841dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peerA->peer);
842dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyEnqueueOutgoingPacket(peerA, packetA);
843dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyEnqueueOutgoingPacket(peerB, packetB);
844dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(peerA->peer);
845dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
846dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
847dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
848dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Informs a peer that the peer they're trying to connect to couldn't be
849dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * found.
850dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
851dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterReportConnectionError(PeerProxy* peerProxy,
852dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Credentials credentials) {
853dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
854dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (packet == NULL) {
855ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("malloc() error. Failed to tell process %d that process %d is"
856dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                " dead.", peerProxy->credentials.pid, credentials.pid);
857dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
858dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
859dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
860dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.type = CONNECTION_ERROR;
861dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.credentials = credentials;
862dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->free = &outgoingPacketFree;
863dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
864dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyLockAndEnqueueOutgoingPacket(peerProxy, packet);
865dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
866dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
867dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
868dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Handles a request to be connected to another peer.
869dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
870dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterHandleConnectionRequest(PeerProxy* peerProxy,
871dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Header* header) {
872dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* master = peerProxy->peer;
873dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t targetPid = header->credentials.pid;
874dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (!hashmapContainsKey(peerProxy->connections, &targetPid)) {
875dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We haven't connected these peers yet.
876dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        PeerProxy* targetPeer
877dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            = (PeerProxy*) hashmapGet(master->peerProxies, &targetPid);
878dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (targetPeer == NULL) {
879dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Unknown process.
880dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterReportConnectionError(peerProxy, header->credentials);
881dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
882dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterConnectPeers(peerProxy, targetPeer);
883dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
884dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
885dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
886dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // This packet is complete. Get ready for the next one.
887dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyExpectHeader(peerProxy);
888dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
889dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
890dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
891dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * The master told us this peer is dead.
892dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
893dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterProxyHandleConnectionError(PeerProxy* masterProxy,
894dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        Header* header) {
895dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer = masterProxy->peer;
896dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
897dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Look up the peer proxy.
898dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid = header->credentials.pid;
899dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = NULL;
900dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peer);
901dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy = hashmapGet(peer->peerProxies, &pid);
902dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(peer);
903dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
904dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy != NULL) {
905fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block        ALOGI("Couldn't connect to %d.", pid);
906dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyKill(peerProxy, false);
907dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
908ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Peer proxy for %d not found. This shouldn't happen.", pid);
909dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
910dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
911dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyExpectHeader(masterProxy);
912dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
913dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
914dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
915dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Handles a packet header.
916dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
917dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyHandleHeader(PeerProxy* peerProxy, Header* header) {
918dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    switch (header->type) {
919dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case CONNECTION_REQUEST:
920dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterHandleConnectionRequest(peerProxy, header);
921dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
922dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case CONNECTION:
923dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterProxyExpectConnection(peerProxy, header);
924dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
925dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case CONNECTION_ERROR:
926dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterProxyHandleConnectionError(peerProxy, header);
927dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
928dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case BYTES:
929dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            peerProxyExpectBytes(peerProxy, header);
930dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
931dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        default:
932ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block            ALOGW("Invalid packet type from %d: %d", peerProxy->credentials.pid,
933dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    header->type);
934dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            peerProxyKill(peerProxy, false);
935dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
936dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
937dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
938dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
939dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Buffers input sent by peer. May be called multiple times until the entire
940dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * buffer is filled. Returns true when the buffer is full.
941dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
942dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic bool peerProxyBufferInput(PeerProxy* peerProxy) {
943dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* in = peerProxy->inputBuffer;
944dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    ssize_t size = bufferRead(in, peerProxy->fd->fd);
945dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (size < 0) {
946dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyHandleError(peerProxy, "read");
947dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
948dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (size == 0) {
949dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // EOF.
950fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block    	ALOGI("EOF");
951dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyKill(peerProxy, false);
952dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
953dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (bufferReadComplete(in)) {
954dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // We're done!
955dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return true;
956dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
957dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Continue reading.
958dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return false;
959dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
960dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
961dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
962dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
963dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Reads input from a peer process.
964dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
965dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void peerProxyRead(SelectableFd* fd) {
9668d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Reading...");
967dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = (PeerProxy*) fd->data;
968dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int state = peerProxy->inputState;
969dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* in = peerProxy->inputBuffer;
970dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    switch (state) {
971dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case READING_HEADER:
972dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (peerProxyBufferInput(peerProxy)) {
9738d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("Header read.");
974dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // We've read the complete header.
975dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                Header* header = (Header*) in->data;
976dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxyHandleHeader(peerProxy, header);
977dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
978dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
979dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case READING_BYTES:
9808d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block            ALOGD("Reading bytes...");
981dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (peerProxyBufferInput(peerProxy)) {
9828d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block                ALOGD("Bytes read.");
983dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // We have the complete packet. Notify bytes listener.
984dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxy->peer->onBytes(peerProxy->credentials,
985dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    in->data, in->size);
986dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
987dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                // Get ready for the next packet.
988dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                peerProxyExpectHeader(peerProxy);
989dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
990dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
991dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        case ACCEPTING_CONNECTION:
992dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            masterProxyAcceptConnection(peerProxy);
993dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            break;
994dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        default:
995dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG_ALWAYS_FATAL("Unknown state: %d", state);
996dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
997dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
998dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
999dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic PeerProxy* peerProxyCreate(Peer* peer, Credentials credentials) {
1000dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = calloc(1, sizeof(PeerProxy));
1001dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
1002dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
1003dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1004dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1005dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->inputBuffer = bufferCreate(sizeof(Header));
1006dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy->inputBuffer == NULL) {
1007dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(peerProxy);
1008dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return NULL;
1009dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1010dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1011dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->peer = peer;
1012dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->credentials = credentials;
1013dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1014dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Initial state == expecting a header.
1015dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxyExpectHeader(peerProxy);
1016dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1017dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Add this proxy to the map. Make sure the key points to the stable memory
1018dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // inside of the peer proxy itself.
1019dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t* pid = &(peerProxy->credentials.pid);
1020dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    hashmapPut(peer->peerProxies, pid, peerProxy);
1021dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return peerProxy;
1022dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1023dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1024dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Accepts a connection to the master peer. */
1025dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void masterAcceptConnection(SelectableFd* listenerFd) {
1026dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Accept connection.
1027dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int socket = accept(listenerFd->fd, NULL, NULL);
1028dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (socket == -1) {
1029ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("accept() error: %s", strerror(errno));
1030dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
1031dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1032dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
10338d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Accepted connection as fd %d.", socket);
1034dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1035dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Get credentials.
1036dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Credentials credentials;
1037dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    struct ucred ucredentials;
1038dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    socklen_t credentialsSize = sizeof(struct ucred);
1039dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int result = getsockopt(socket, SOL_SOCKET, SO_PEERCRED,
1040dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                &ucredentials, &credentialsSize);
1041dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // We might want to verify credentialsSize.
1042dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result == -1) {
1043ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("getsockopt() error: %s", strerror(errno));
1044dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        closeWithWarning(socket);
1045dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
1046dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1047dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1048dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Copy values into our own structure so we know we have the types right.
1049dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.pid = ucredentials.pid;
1050dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.uid = ucredentials.uid;
1051dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    credentials.gid = ucredentials.gid;
1052dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1053fe71a61e5b0cb666675900d206251a7c18ed944bSteve Block    ALOGI("Accepted connection from process %d.", credentials.pid);
1054dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1055dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* masterPeer = (Peer*) listenerFd->data;
1056dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1057dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(masterPeer);
1058dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1059dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make sure we don't already have a connection from that process.
1060dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy
1061dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        = hashmapGet(masterPeer->peerProxies, &credentials.pid);
1062dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy != NULL) {
1063dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(masterPeer);
1064ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("Alread connected to process %d.", credentials.pid);
1065dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        closeWithWarning(socket);
1066dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
1067dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1068dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1069dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Add connection to the selector.
1070dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* socketFd = selectorAdd(masterPeer->selector, socket);
1071dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (socketFd == NULL) {
1072dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(masterPeer);
1073ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("malloc() failed.");
1074dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        closeWithWarning(socket);
1075dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return;
1076dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1077dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1078dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create a peer proxy.
1079dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy = peerProxyCreate(masterPeer, credentials);
1080dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerUnlock(masterPeer);
1081dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
1082ae8b56c0d17a97aff0b98e6405c7cc9811bbbc3dSteve Block        ALOGW("malloc() failed.");
1083dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        socketFd->remove = true;
1084dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        closeWithWarning(socket);
1085dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1086dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxy->connections = hashmapCreate(10, &pidHash, &pidEquals);
1087dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxySetFd(peerProxy, socketFd);
1088dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1089dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1090dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
1091dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Creates the local peer.
1092dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
1093dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic Peer* peerCreate() {
1094dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer = calloc(1, sizeof(Peer));
1095dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peer == NULL) {
1096dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
1097dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1098dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peer->peerProxies = hashmapCreate(10, &pidHash, &pidEquals);
1099dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peer->selector = selectorCreate();
1100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pthread_mutexattr_t attributes;
1102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pthread_mutexattr_init(&attributes) != 0) {
1103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("pthread_mutexattr_init() error.");
1104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE) != 0) {
1106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("pthread_mutexattr_settype() error.");
1107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pthread_mutex_init(&peer->mutex, &attributes) != 0) {
1109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("pthread_mutex_init() error.");
1110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peer->pid = getpid();
1113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return peer;
1114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** The local peer. */
1117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic Peer* localPeer;
1118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Frees a packet of bytes. */
1120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void outgoingPacketFreeBytes(OutgoingPacket* packet) {
11218d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Freeing outgoing packet.");
1122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferFree(packet->bytes);
1123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    free(packet);
1124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
1127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Sends a packet of bytes to a remote peer. Returns 0 on success.
1128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
1129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
1130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
1131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * to EINVAL if pid is the same as the local pid.
1132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
1133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint peerSendBytes(pid_t pid, const char* bytes, size_t size) {
1134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project	Peer* peer = localPeer;
1135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    assert(peer != NULL);
1136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
1138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (packet == NULL) {
1139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
1140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* copy = bufferCreate(size);
1144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (copy == NULL) {
1145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packet);
1146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
1147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Copy data.
1151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(copy->data, bytes, size);
1152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    copy->size = size;
1153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->bytes = copy;
1155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.type = BYTES;
1156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.size = size;
1157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->free = outgoingPacketFreeBytes;
1158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferPrepareForWrite(packet->bytes);
1159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peer);
1161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
1163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
1164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // The peer is already dead or we couldn't alloc memory. Either way,
1165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // errno is set.
1166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
1167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet->free(packet);
1168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
1170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyEnqueueOutgoingPacket(peerProxy, packet);
1171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
1172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        selectorWakeUp(peer->selector);
1173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
1174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Keeps track of how to free shared bytes. */
1178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projecttypedef struct {
1179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    void (*free)(void* context);
1180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    void* context;
1181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} SharedBytesFreer;
1182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Frees shared bytes. */
1184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectstatic void outgoingPacketFreeSharedBytes(OutgoingPacket* packet) {
1185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SharedBytesFreer* sharedBytesFreer
1186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        = (SharedBytesFreer*) packet->context;
1187dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sharedBytesFreer->free(sharedBytesFreer->context);
1188dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    free(sharedBytesFreer);
1189dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    free(packet);
1190dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1191dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1192dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
1193dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Sends a packet of bytes to a remote peer without copying the bytes. Calls
1194dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * free() with context after the bytes have been sent.
1195dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
1196dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Returns -1 if an error occurs. Sets errno to ENOMEM if memory couldn't be
1197dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * allocated. Sets errno to EHOSTDOWN if the peer died recently. Sets errno
1198dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * to EINVAL if pid is the same as the local pid.
1199dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
1200dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint peerSendSharedBytes(pid_t pid, char* bytes, size_t size,
1201dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        void (*free)(void* context), void* context) {
1202dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Peer* peer = localPeer;
1203dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    assert(peer != NULL);
1204dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1205dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    OutgoingPacket* packet = calloc(1, sizeof(OutgoingPacket));
1206dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (packet == NULL) {
1207dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
1208dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1209dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1210dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1211dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    Buffer* wrapper = bufferWrap(bytes, size, size);
1212dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (wrapper == NULL) {
1213dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packet);
1214dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
1215dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1216dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1217dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1218dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SharedBytesFreer* sharedBytesFreer = malloc(sizeof(SharedBytesFreer));
1219dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (sharedBytesFreer == NULL) {
1220dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(packet);
1221dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        free(wrapper);
1222dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        errno = ENOMEM;
1223dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1224dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1225dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sharedBytesFreer->free = free;
1226dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    sharedBytesFreer->context = context;
1227dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1228dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->bytes = wrapper;
1229dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->context = sharedBytesFreer;
1230dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.type = BYTES;
1231dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->header.size = size;
1232dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    packet->free = &outgoingPacketFreeSharedBytes;
1233dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    bufferPrepareForWrite(packet->bytes);
1234dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1235dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerLock(peer);
1236dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1237dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* peerProxy = peerProxyGetOrCreate(peer, pid, true);
1238dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (peerProxy == NULL) {
1239dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // The peer is already dead or we couldn't alloc memory. Either way,
1240dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // errno is set.
1241dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
1242dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        packet->free(packet);
1243dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return -1;
1244dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
1245dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerProxyEnqueueOutgoingPacket(peerProxy, packet);
1246dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        peerUnlock(peer);
1247dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        selectorWakeUp(peer->selector);
1248dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        return 0;
1249dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1250dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1251dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1252dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
1253dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Starts the master peer. The master peer differs from other peers in that
1254dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * it is responsible for connecting the other peers. You can only have one
1255dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * master peer.
1256dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
1257dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Goes into an I/O loop and does not return.
1258dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
1259dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid masterPeerInitialize(BytesListener* bytesListener,
1260dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        DeathListener* deathListener) {
1261dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create and bind socket.
1262dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int listenerSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
1263dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (listenerSocket == -1) {
1264dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
1265dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1266dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    unlink(MASTER_PATH);
1267dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int result = bind(listenerSocket, (SocketAddress*) getMasterAddress(),
1268dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            sizeof(UnixAddress));
1269dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result == -1) {
1270dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("bind() error: %s", strerror(errno));
1271dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1272dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
12738d66c49258ac4f59bd67c23c9c914cca81f85b01Steve Block    ALOGD("Listener socket: %d",  listenerSocket);
1274dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1275dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Queue up to 16 connections.
1276dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    result = listen(listenerSocket, 16);
1277dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result != 0) {
1278dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("listen() error: %s", strerror(errno));
1279dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1280dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1281dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make socket non-blocking.
1282dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    setNonBlocking(listenerSocket);
1283dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1284dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create the peer for this process. Fail if we already have one.
1285dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (localPeer != NULL) {
1286dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Peer is already initialized.");
1287dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1288dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer = peerCreate();
1289dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (localPeer == NULL) {
1290dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() failed.");
1291dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1292dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->master = true;
1293dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->onBytes = bytesListener;
1294dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->onDeath = deathListener;
1295dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1296dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make listener socket selectable.
1297dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* listenerFd = selectorAdd(localPeer->selector, listenerSocket);
1298dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (listenerFd == NULL) {
1299dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
1300dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1301dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    listenerFd->data = localPeer;
1302dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    listenerFd->onReadable = &masterAcceptConnection;
1303dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1304dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1305dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/**
1306dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Starts a local peer.
1307dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
1308dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Goes into an I/O loop and does not return.
1309dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
1310dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid peerInitialize(BytesListener* bytesListener,
1311dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        DeathListener* deathListener) {
1312dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Connect to master peer.
1313dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int masterSocket = socket(AF_LOCAL, SOCK_STREAM, 0);
1314dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (masterSocket == -1) {
1315dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("socket() error: %s", strerror(errno));
1316dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1317dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int result = connect(masterSocket, (SocketAddress*) getMasterAddress(),
1318dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            sizeof(UnixAddress));
1319dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (result != 0) {
1320dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("connect() error: %s", strerror(errno));
1321dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1322dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1323dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create the peer for this process. Fail if we already have one.
1324dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (localPeer != NULL) {
1325dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("Peer is already initialized.");
1326dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1327dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer = peerCreate();
1328dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (localPeer == NULL) {
1329dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() failed.");
1330dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1331dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->onBytes = bytesListener;
1332dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->onDeath = deathListener;
1333dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1334dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Make connection selectable.
1335dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    SelectableFd* masterFd = selectorAdd(localPeer->selector, masterSocket);
1336dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (masterFd == NULL) {
1337dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
1338dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1339dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1340dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Create a peer proxy for the master peer.
1341dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    PeerProxy* masterProxy = peerProxyCreate(localPeer, MASTER_CREDENTIALS);
1342dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (masterProxy == NULL) {
1343dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG_ALWAYS_FATAL("malloc() error.");
1344dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
1345dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    peerProxySetFd(masterProxy, masterFd);
1346dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    masterProxy->master = true;
1347dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    localPeer->masterProxy = masterProxy;
1348dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1349dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1350dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/** Starts the master peer I/O loop. Doesn't return. */
1351dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid peerLoop() {
1352dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    assert(localPeer != NULL);
1353dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1354dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Start selector.
1355dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    selectorLoop(localPeer->selector);
1356dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
1357dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
1358