/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- socket
- connect
- bind
- listen
- process_accept
- accept
- accept4
- setsockopt
- getsockopt
- socketpair
- getaddrinfo
- getnameinfo
- gethostbyname
- gethostbyaddr
1 /****************************************************************************
2 * Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
3 * jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu *
4 * *
5 * This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src). *
6 * *
7 * DMTCP:dmtcp/src is free software: you can redistribute it and/or *
8 * modify it under the terms of the GNU Lesser General Public License as *
9 * published by the Free Software Foundation, either version 3 of the *
10 * License, or (at your option) any later version. *
11 * *
12 * DMTCP:dmtcp/src is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU Lesser General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU Lesser General Public *
18 * License along with DMTCP:dmtcp/src. If not, see *
19 * <http://www.gnu.org/licenses/>. *
20 ****************************************************************************/
21
22 #include <dlfcn.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <pthread.h>
27 #include <sys/select.h>
28 #include <sys/un.h>
29 #include <arpa/inet.h>
30
31 /* According to earlier standards */
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include "socketconnection.h"
37 #include "socketconnlist.h"
38 #include "socketwrappers.h"
39 #include "../jalib/jassert.h"
40 #include "../jalib/jfilesystem.h"
41
42 using namespace dmtcp;
43
44 /* getaddrinfo() (and possibly getnameinfo()) open socket to external services
45 * (DNS etc.) to resolve hostname/address etc. In doing so, the call to
46 * socket() is captured by our wrappers, however, the call to close() is
47 * internal and thus not captured by the close wrapper. This results in a stale
48 * connection. To avoid this problem, we disable socket processing for the
49 * thread calling getaddrinfo().
50 */
51 static __thread bool _doNotProcessSockets = false;
52
53 extern "C" int socket(int domain, int type, int protocol)
54 {
55 DMTCP_PLUGIN_DISABLE_CKPT();
56 int ret = _real_socket(domain, type, protocol);
57 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
58 Connection *con;
59 JTRACE("socket created") (ret) (domain) (type) (protocol);
60 if ((type & 0xff) == SOCK_RAW) {
61 JASSERT(domain == AF_NETLINK) (domain) (type)
62 .Text("Only Netlink Raw sockets supported");
63 con = new RawSocketConnection(domain, type, protocol);
64 } else {
65 con = new TcpConnection(domain, type, protocol);
66 }
67 SocketConnList::instance().add(ret, con);
68 }
69 DMTCP_PLUGIN_ENABLE_CKPT();
70 return ret;
71 }
72
73 extern "C" int connect(int sockfd, const struct sockaddr *serv_addr,
74 socklen_t addrlen)
75 {
76 DMTCP_PLUGIN_DISABLE_CKPT(); // The lock is released inside the macro.
77 int ret = _real_connect(sockfd,serv_addr,addrlen);
78
79 //no blocking connect... need to hang around until it is writable
80 if (ret < 0 && errno == EINPROGRESS)
81 {
82 fd_set wfds;
83 struct timeval tv;
84 int retval;
85
86 FD_ZERO(&wfds);
87 FD_SET(sockfd, &wfds);
88
89 tv.tv_sec = 15;
90 tv.tv_usec = 0;
91
92 retval = select(sockfd+1, NULL, &wfds, NULL, &tv);
93 /* Don't rely on the value of tv now! */
94
95 if (retval == -1)
96 perror("select()");
97 else if (FD_ISSET(sockfd, &wfds))
98 {
99 int val = -1;
100 socklen_t sz = sizeof(val);
101 getsockopt(sockfd,SOL_SOCKET,SO_ERROR,&val,&sz);
102 if (val==0) ret = 0;
103 }
104 else
105 JTRACE("No data within five seconds.");
106 }
107
108 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
109 TcpConnection *con =
110 (TcpConnection*) SocketConnList::instance().getConnection(sockfd);
111 if (con == NULL) {
112 JTRACE("Connect operation on unsupported socket type.");
113 } else {
114 con->onConnect(serv_addr, addrlen);
115
116 #if HANDSHAKE_ON_CONNECT == 1
117 JTRACE("connected, sending 1-way handshake") (sockfd) (con->id());
118 con->sendHandshake(sockfd, DmtcpWorker::instance().coordinatorId());
119 JTRACE("1-way handshake sent");
120 #else
121 JTRACE("connected") (sockfd) (con->id());
122 #endif
123 }
124 }
125 DMTCP_PLUGIN_ENABLE_CKPT();
126 return ret;
127 }
128
129 extern "C" int bind(int sockfd, const struct sockaddr *my_addr,
130 socklen_t addrlen)
131 {
132 DMTCP_PLUGIN_DISABLE_CKPT(); // The lock is released inside the macro.
133 int ret = _real_bind(sockfd, my_addr, addrlen);
134 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
135 TcpConnection *con =
136 (TcpConnection*) SocketConnList::instance().getConnection(sockfd);
137 if (con == NULL) {
138 JTRACE("bind operation on unsupported socket type.");
139 } else {
140 con->onBind((struct sockaddr*) my_addr, addrlen);
141 JTRACE("bind") (sockfd) (con->id());
142 }
143 }
144 DMTCP_PLUGIN_ENABLE_CKPT();
145 return ret;
146 }
147
148 extern "C" int listen(int sockfd, int backlog)
149 {
150 DMTCP_PLUGIN_DISABLE_CKPT(); // The lock is released inside the macro.
151 int ret = _real_listen(sockfd, backlog);
152 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
153 TcpConnection *con =
154 (TcpConnection*) SocketConnList::instance().getConnection(sockfd);
155 if (con == NULL) {
156 JTRACE("listen operation on unsupported socket type.");
157 } else {
158 con->onListen(backlog);
159 JTRACE("listen") (sockfd) (con->id()) (backlog);
160 }
161 }
162 DMTCP_PLUGIN_ENABLE_CKPT();
163 return ret;
164 }
165
166 static void process_accept(int ret, int sockfd, struct sockaddr *addr,
167 socklen_t *addrlen)
168 {
169 JASSERT(ret != -1);
170 TcpConnection *parent =
171 (TcpConnection*) SocketConnList::instance().getConnection(sockfd);
172 TcpConnection* con = new TcpConnection(*parent, ConnectionIdentifier::null());
173 if (con == NULL) {
174 JTRACE("accept operation on unsupported socket type.");
175 return;
176 }
177 SocketConnList::instance().add(ret, con);
178
179 #if HANDSHAKE_ON_CONNECT == 1
180 JTRACE("accepted, waiting for 1-way handshake") (sockfd) (con->id());
181 con->recvHandshake(ret, DmtcpWorker::instance().coordinatorId());
182 JTRACE("1-way handshake received") (con->getRemoteId());
183 #else
184 JTRACE("accepted incoming connection") (sockfd) (con->id());
185 #endif
186 }
187
188 extern "C" int accept(int sockfd, struct sockaddr *addr,
189 socklen_t *addrlen)
190 {
191 /* FIXME: accept() is a blocking call that can alter the process state(by
192 * creating a new socket-fd). This can cause problems if it happens at a time
193 * when some other thread is processing inside a fork() or exec() wrapper.
194 * For more details, please look at the comment in
195 * DmtcpWorker::wrapperExecutionLockLockExcl().
196 *
197 * Since it's a blocking call, we cannot grab the actual wrapper-execution
198 * lock here.
199 */
200 struct sockaddr_storage tmp_addr;
201 socklen_t tmp_len = 0;
202 if (addr == NULL || addrlen == NULL) {
203 memset(&tmp_addr,0,sizeof(tmp_addr));
204 addr = (struct sockaddr*) &tmp_addr;
205 addrlen = &tmp_len;
206 }
207 int ret = _real_accept(sockfd, addr, addrlen);
208 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
209 process_accept(ret, sockfd, addr, addrlen);
210 }
211 return ret;
212 }
213
214 extern "C" int accept4(int sockfd, struct sockaddr *addr,
215 socklen_t *addrlen, int flags)
216 {
217 // Look at the comment for accept()
218 struct sockaddr_storage tmp_addr;
219 socklen_t tmp_len = 0;
220 if (addr == NULL || addrlen == NULL) {
221 memset(&tmp_addr,0,sizeof(tmp_addr));
222 addr = (struct sockaddr*) &tmp_addr;
223 addrlen = &tmp_len;
224 }
225 int ret = _real_accept4(sockfd, addr, addrlen, flags);
226 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
227 process_accept(ret, sockfd, addr, addrlen);
228 }
229 return ret;
230 }
231
232 extern "C" int setsockopt(int sockfd, int level, int optname,
233 const void *optval, socklen_t optlen)
234 {
235 int ret = _real_setsockopt(sockfd, level, optname, optval, optlen);
236 if (ret != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
237 JTRACE("setsockopt") (ret) (sockfd) (optname);
238 TcpConnection *con =
239 (TcpConnection*) SocketConnList::instance().getConnection(sockfd);
240 if (con == NULL) {
241 JTRACE("setsockopt operation on unsupported socket type.");
242 return ret;
243 }
244 }
245 return ret;
246 }
247
248 #if 0
249 extern "C" int getsockopt(int sockfd, int level, int optname,
250 void *optval, socklen_t *optlen)
251 {
252 /* We don't want to acquire the lock here as this is not needed. Also,
253 * aquiring the lock here might cause a deadlock when this function is called
254 * from within connect(). Here is the deadlock situation:
255 * User-thread connect(): acquire lock
256 * Ckpt-thread ckpt(): Queued on wr-lock
257 * User-thread getsockopt(): block on read lock().
258 */
259 int ret = _real_getsockopt(sockfd, level, optname, optval, optlen);
260 PASSTHROUGH_DMTCP_HELPER(getsockopt,sockfd,level,optname,optval,optlen);
261 }
262 #endif
263
264 extern "C" int socketpair(int d, int type, int protocol, int sv[2])
265 {
266 DMTCP_PLUGIN_DISABLE_CKPT();
267
268 JASSERT(sv != NULL);
269 int rv = _real_socketpair(d,type,protocol,sv);
270 if (rv != -1 && dmtcp_is_running_state() && !_doNotProcessSockets) {
271 JTRACE("socketpair()") (sv[0]) (sv[1]);
272
273 TcpConnection *a, *b;
274
275 a = new TcpConnection(d, type, protocol);
276 a->onConnect();
277 b = new TcpConnection(*a, a->id());
278
279 SocketConnList::instance().add(sv[0], a);
280 SocketConnList::instance().add(sv[1], b);
281 }
282
283 DMTCP_PLUGIN_ENABLE_CKPT();
284
285 return rv;
286 }
287
288 extern "C" int getaddrinfo(const char *node, const char *service,
289 const struct addrinfo *hints,
290 struct addrinfo **res)
291 {
292 DMTCP_PLUGIN_DISABLE_CKPT();
293 // See comment near definition of _doNotProcessSockets;
294 _doNotProcessSockets = true;
295 int ret = _real_getaddrinfo(node, service, hints, res);
296 _doNotProcessSockets = false;
297 DMTCP_PLUGIN_ENABLE_CKPT();
298 return ret;
299 }
300
301 extern "C" int getnameinfo(const struct sockaddr *sa, socklen_t salen,
302 char *host, size_t hostlen,
303 char *serv, size_t servlen, int flags)
304 {
305 DMTCP_PLUGIN_DISABLE_CKPT();
306 _doNotProcessSockets = true;
307 int ret = _real_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
308 _doNotProcessSockets = false;
309 DMTCP_PLUGIN_ENABLE_CKPT();
310 return ret;
311 }
312
313 extern "C" struct hostent *gethostbyname(const char *name)
314 {
315 DMTCP_PLUGIN_DISABLE_CKPT();
316 _doNotProcessSockets = true;
317 struct hostent *ret = _real_gethostbyname(name);
318 _doNotProcessSockets = false;
319 DMTCP_PLUGIN_ENABLE_CKPT();
320 return ret;
321 }
322
323 extern "C" struct hostent *gethostbyaddr(const void *addr,
324 socklen_t len, int type)
325 {
326 DMTCP_PLUGIN_DISABLE_CKPT();
327 _doNotProcessSockets = true;
328 struct hostent *ret = _real_gethostbyaddr(addr, len, type);
329 _doNotProcessSockets = false;
330 DMTCP_PLUGIN_ENABLE_CKPT();
331 return ret;
332 }