1/********************************************************************
2 * Copyright (c) 2013 - 2014, Pivotal Inc.
3 * All rights reserved.
4 *
5 * Author: Zhanwei Wang
6 ********************************************************************/
7/********************************************************************
8 * 2014 -
9 * open source under Apache License Version 2.0
10 ********************************************************************/
11/**
12 * Licensed to the Apache Software Foundation (ASF) under one
13 * or more contributor license agreements. See the NOTICE file
14 * distributed with this work for additional information
15 * regarding copyright ownership. The ASF licenses this file
16 * to you under the Apache License, Version 2.0 (the
17 * "License"); you may not use this file except in compliance
18 * with the License. You may obtain a copy of the License at
19 *
20 * http://www.apache.org/licenses/LICENSE-2.0
21 *
22 * Unless required by applicable law or agreed to in writing, software
23 * distributed under the License is distributed on an "AS IS" BASIS,
24 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 * See the License for the specific language governing permissions and
26 * limitations under the License.
27 */
28#include "platform.h"
29
30#include <cassert>
31#include <cstddef>
32#include <cstring>
33#include <errno.h>
34#include <netinet/in.h>
35#include <stdint.h>
36#include <sys/socket.h>
37#include <sys/types.h>
38#include <sys/un.h>
39#include <unistd.h>
40#include <vector>
41
42#include "DateTime.h"
43#include "Exception.h"
44#include "ExceptionInternal.h"
45#include "DomainSocket.h"
46#include "Syscall.h"
47
48namespace Hdfs {
49namespace Internal {
50
51DomainSocketImpl::DomainSocketImpl() {}
52
53DomainSocketImpl::~DomainSocketImpl() {}
54
55void DomainSocketImpl::connect(const char *host, int port, int timeout) {
56 connect(host, "", timeout);
57}
58
59void DomainSocketImpl::connect(const char *host, const char *port,
60 int timeout) {
61 remoteAddr = host;
62 assert(-1 == sock);
63 sock = HdfsSystem::socket(AF_UNIX, SOCK_STREAM, 0);
64
65 if (-1 == sock) {
66 THROW(HdfsNetworkException, "Create socket failed when connect to %s: %s",
67 remoteAddr.c_str(), GetSystemErrorInfo(errno));
68 }
69
70 try {
71 int len, rc;
72 disableSigPipe();
73 struct sockaddr_un addr;
74 memset(&addr, 0, sizeof(addr));
75 addr.sun_family = AF_UNIX;
76 rc = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", host);
77
78 if (rc < 0 || rc >= static_cast<int>(sizeof(addr.sun_path))) {
79 THROW(HdfsNetworkException, "error computing UNIX domain socket path: %s",
80 remoteAddr.c_str());
81 }
82
83 len = offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path);
84
85 do {
86 rc = HdfsSystem::connect(sock, (struct sockaddr *)&addr, len);
87 } while (rc < 0 && EINTR == errno && !CheckOperationCanceled());
88
89 if (rc < 0) {
90 THROW(HdfsNetworkConnectException, "Connect to \"%s:\" failed: %s", host,
91 GetSystemErrorInfo(errno));
92 }
93 } catch (...) {
94 close();
95 throw;
96 }
97}
98
99void DomainSocketImpl::connect(struct addrinfo *paddr, const char *host,
100 const char *port, int timeout) {
101 assert(false && "not implemented");
102 abort();
103}
104
105int32_t DomainSocketImpl::receiveFileDescriptors(int fds[], size_t nfds,
106 char *buffer, int32_t size) {
107 assert(-1 != sock);
108 ssize_t rc;
109 struct iovec iov[1];
110 struct msghdr msg;
111
112 iov[0].iov_base = buffer;
113 iov[0].iov_len = size;
114
115 struct cmsghdr *cmsg;
116 size_t auxSize = CMSG_SPACE(sizeof(int) * nfds);
117 std::vector<char> aux(auxSize, 0); /* ancillary data buffer */
118
119 memset(&msg, 0, sizeof(msg));
120 msg.msg_iov = &iov[0];
121 msg.msg_iovlen = 1;
122 msg.msg_control = &aux[0];
123 msg.msg_controllen = aux.size();
124 cmsg = CMSG_FIRSTHDR(&msg);
125 cmsg->cmsg_level = SOL_SOCKET;
126 cmsg->cmsg_type = SCM_RIGHTS;
127 cmsg->cmsg_len = CMSG_LEN(sizeof(int) * nfds);
128 msg.msg_controllen = cmsg->cmsg_len;
129
130 do {
131 rc = HdfsSystem::recvmsg(sock, &msg, 0);
132 } while (-1 == rc && EINTR == errno && !CheckOperationCanceled());
133
134 if (-1 == rc) {
135 THROW(HdfsNetworkException, "Read file descriptors failed from %s: %s",
136 remoteAddr.c_str(), GetSystemErrorInfo(errno));
137 }
138
139 if (0 == rc) {
140 THROW(HdfsEndOfStream,
141 "Read file descriptors failed from %s: End of the stream",
142 remoteAddr.c_str());
143 }
144
145 if (msg.msg_controllen != cmsg->cmsg_len) {
146 THROW(HdfsEndOfStream, "Read file descriptors failed from %s.",
147 remoteAddr.c_str());
148 }
149
150 int *fdptr = (int *)CMSG_DATA(cmsg);
151
152 for (size_t i = 0; i < nfds; ++i) {
153 fds[i] = fdptr[i];
154 }
155
156 return rc;
157}
158}
159}
160