blob: e360b4e16fdf40ed850b93cfca625276a4d083b7 [file] [log] [blame]
Sreeram Ramachandran8f95def2014-05-12 11:20:12 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "FwmarkClient.h"
18
19#include <stdlib.h>
20#include <sys/socket.h>
21#include <sys/un.h>
22#include <unistd.h>
23
24namespace {
25
26const sockaddr_un FWMARK_SERVER_PATH = {AF_UNIX, "/dev/socket/fwmarkd"};
27
28} // namespace
29
30bool FwmarkClient::shouldSetFwmark(int sockfd, const sockaddr* addr) {
31 return sockfd >= 0 && addr && (addr->sa_family == AF_INET || addr->sa_family == AF_INET6) &&
32 !getenv("ANDROID_NO_USE_FWMARK_CLIENT");
33}
34
35FwmarkClient::FwmarkClient() : mChannel(-1) {
36}
37
38FwmarkClient::~FwmarkClient() {
39 if (mChannel >= 0) {
40 // We don't care about errors while closing the channel, so restore any previous error.
41 int error = errno;
42 close(mChannel);
43 errno = error;
44 }
45}
46
47bool FwmarkClient::send(void* data, size_t len, int fd) {
48 mChannel = socket(AF_UNIX, SOCK_STREAM, 0);
49 if (mChannel == -1) {
50 return false;
51 }
52
53 if (TEMP_FAILURE_RETRY(connect(mChannel, reinterpret_cast<const sockaddr*>(&FWMARK_SERVER_PATH),
54 sizeof(FWMARK_SERVER_PATH))) == -1) {
55 // If we are unable to connect to the fwmark server, assume there's no error. This protects
56 // against future changes if the fwmark server goes away.
57 errno = 0;
58 return true;
59 }
60
61 iovec iov;
62 iov.iov_base = data;
63 iov.iov_len = len;
64
65 msghdr message;
66 memset(&message, 0, sizeof(message));
67 message.msg_iov = &iov;
68 message.msg_iovlen = 1;
69
70 union {
71 cmsghdr cmh;
72 char cmsg[CMSG_SPACE(sizeof(fd))];
73 } cmsgu;
74
75 memset(cmsgu.cmsg, 0, sizeof(cmsgu.cmsg));
76 message.msg_control = cmsgu.cmsg;
77 message.msg_controllen = sizeof(cmsgu.cmsg);
78
79 cmsghdr* const cmsgh = CMSG_FIRSTHDR(&message);
80 cmsgh->cmsg_len = CMSG_LEN(sizeof(fd));
81 cmsgh->cmsg_level = SOL_SOCKET;
82 cmsgh->cmsg_type = SCM_RIGHTS;
83 memcpy(CMSG_DATA(cmsgh), &fd, sizeof(fd));
84
85 if (TEMP_FAILURE_RETRY(sendmsg(mChannel, &message, 0)) == -1) {
86 return false;
87 }
88
89 int error = 0;
90 if (TEMP_FAILURE_RETRY(recv(mChannel, &error, sizeof(error), 0)) == -1) {
91 return false;
92 }
93
94 errno = error;
95 return !error;
96}