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 | |
48 | namespace Hdfs { |
49 | namespace Internal { |
50 | |
51 | DomainSocketImpl::DomainSocketImpl() {} |
52 | |
53 | DomainSocketImpl::~DomainSocketImpl() {} |
54 | |
55 | void DomainSocketImpl::connect(const char *host, int port, int timeout) { |
56 | connect(host, "" , timeout); |
57 | } |
58 | |
59 | void 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 | |
99 | void DomainSocketImpl::connect(struct addrinfo *paddr, const char *host, |
100 | const char *port, int timeout) { |
101 | assert(false && "not implemented" ); |
102 | abort(); |
103 | } |
104 | |
105 | int32_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 | |