root/plugin/ipc/socket/socketwrappers.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. socket
  2. connect
  3. bind
  4. listen
  5. process_accept
  6. accept
  7. accept4
  8. setsockopt
  9. getsockopt
  10. socketpair
  11. getaddrinfo
  12. getnameinfo
  13. gethostbyname
  14. 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 }

/* [<][>][^][v][top][bottom][index][help] */