viosocket.c 11.8 KB
Newer Older
unknown's avatar
unknown committed
1 2 3 4 5 6 7 8
/* Copyright (C) 2000 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
unknown's avatar
unknown committed
10 11 12 13 14 15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 17 18 19 20 21 22 23

/*
  Note that we can't have assertion on file descriptors;  The reason for
  this is that during mysql shutdown, another thread can close a file
  we are working on.  In this case we should just return read errors from
  the file descriptior.
*/

24
#include "vio_priv.h"
25

unknown's avatar
unknown committed
26
int vio_errno(Vio *vio __attribute__((unused)))
27
{
28
  return socket_errno;		/* On Win32 this mapped to WSAGetLastError() */
29 30 31
}


unknown's avatar
unknown committed
32
int vio_read(Vio * vio, gptr buf, int size)
33 34 35 36
{
  int r;
  DBUG_ENTER("vio_read");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
37

38 39 40 41 42 43 44 45 46
#ifdef __WIN__
  r = recv(vio->sd, buf, size,0);
#else
  errno=0;					/* For linux */
  r = read(vio->sd, buf, size);
#endif /* __WIN__ */
#ifndef DBUG_OFF
  if (r < 0)
  {
47
    DBUG_PRINT("vio_error", ("Got error %d during read",errno));
48 49 50 51 52 53 54
  }
#endif /* DBUG_OFF */
  DBUG_PRINT("exit", ("%d", r));
  DBUG_RETURN(r);
}


unknown's avatar
unknown committed
55
int vio_write(Vio * vio, const gptr buf, int size)
56 57 58 59
{
  int r;
  DBUG_ENTER("vio_write");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));
60 61
#ifdef __WIN__
  r = send(vio->sd, buf, size,0);
62 63 64 65 66 67
#else
  r = write(vio->sd, buf, size);
#endif /* __WIN__ */
#ifndef DBUG_OFF
  if (r < 0)
  {
68
    DBUG_PRINT("vio_error", ("Got error on write: %d",socket_errno));
69 70 71 72 73 74
  }
#endif /* DBUG_OFF */
  DBUG_PRINT("exit", ("%d", r));
  DBUG_RETURN(r);
}

75 76
int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode,
		 my_bool *old_mode)
77 78 79
{
  int r=0;
  DBUG_ENTER("vio_blocking");
80 81 82 83

  *old_mode= test(!(vio->fcntl_mode & O_NONBLOCK));
  DBUG_PRINT("enter", ("set_blocking_mode: %d  old_mode: %d",
		       (int) set_blocking_mode, (int) *old_mode));
84 85 86 87 88 89 90 91 92 93 94 95 96

#if !defined(___WIN__) && !defined(__EMX__)
#if !defined(NO_FCNTL_NONBLOCK)
  if (vio->sd >= 0)
  {
    int old_fcntl=vio->fcntl_mode;
    if (set_blocking_mode)
      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
    else
      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
    if (old_fcntl != vio->fcntl_mode)
      r = fcntl(vio->sd, F_SETFL, vio->fcntl_mode);
  }
97 98
#else
  r= set_blocking_mode ? 0 : 1;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
#endif /* !defined(NO_FCNTL_NONBLOCK) */
#else /* !defined(__WIN__) && !defined(__EMX__) */
#ifndef __EMX__
  if (vio->type != VIO_TYPE_NAMEDPIPE)  
#endif
  { 
    ulong arg;
    int old_fcntl=vio->fcntl_mode;
    if (set_blocking_mode)
    {
      arg = 0;
      vio->fcntl_mode &= ~O_NONBLOCK; /* clear bit */
    }
    else
    {
      arg = 1;
      vio->fcntl_mode |= O_NONBLOCK; /* set bit */
    }
    if (old_fcntl != vio->fcntl_mode)
      r = ioctlsocket(vio->sd,FIONBIO,(void*) &arg, sizeof(arg));
  }
120 121 122 123
#ifndef __EMX__
  else
    r=  test(!(vio->fcntl_mode & O_NONBLOCK)) != set_blocking_mode;
#endif /* __EMX__ */
124
#endif /* !defined(__WIN__) && !defined(__EMX__) */
125
  DBUG_PRINT("exit", ("%d", r));
126 127 128 129
  DBUG_RETURN(r);
}

my_bool
unknown's avatar
unknown committed
130
vio_is_blocking(Vio * vio)
131 132 133 134 135 136 137 138 139
{
  my_bool r;
  DBUG_ENTER("vio_is_blocking");
  r = !(vio->fcntl_mode & O_NONBLOCK);
  DBUG_PRINT("exit", ("%d", (int) r));
  DBUG_RETURN(r);
}


unknown's avatar
unknown committed
140
int vio_fastsend(Vio * vio __attribute__((unused)))
141 142 143 144
{
  int r=0;
  DBUG_ENTER("vio_fastsend");

145
#if defined(IPTOS_THROUGHPUT) && !defined(__EMX__)
146 147
  {
    int tos = IPTOS_THROUGHPUT;
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    r= setsockopt(vio->sd, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof(tos));
  }
#endif                                    /* IPTOS_THROUGHPUT && !__EMX__ */
  if (!r)
  {
#ifdef __WIN__
    BOOL nodelay= 1;
    r= setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (const char*) &nodelay,
                  sizeof(nodelay));
#else
    int nodelay = 1;
    r= setsockopt(vio->sd, IPPROTO_TCP, TCP_NODELAY, (void*) &nodelay,
                  sizeof(nodelay));
#endif                                          /* __WIN__ */
  }
  if (r)
  {
    DBUG_PRINT("warning", ("Couldn't set socket option for fast send"));
    r= -1;
167 168 169 170 171
  }
  DBUG_PRINT("exit", ("%d", r));
  DBUG_RETURN(r);
}

unknown's avatar
unknown committed
172
int vio_keepalive(Vio* vio, my_bool set_keep_alive)
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
{
  int r=0;
  uint opt = 0;
  DBUG_ENTER("vio_keepalive");
  DBUG_PRINT("enter", ("sd=%d, set_keep_alive=%d", vio->sd, (int)
		       set_keep_alive));
  if (vio->type != VIO_TYPE_NAMEDPIPE)
  {
    if (set_keep_alive)
      opt = 1;
    r = setsockopt(vio->sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &opt,
		   sizeof(opt));
  }
  DBUG_RETURN(r);
}


my_bool
unknown's avatar
unknown committed
191
vio_should_retry(Vio * vio __attribute__((unused)))
192
{
193
  int en = socket_errno;
194 195
  return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
	  en == SOCKET_EWOULDBLOCK);
196 197 198
}


unknown's avatar
unknown committed
199
int vio_close(Vio * vio)
200
{
201
  int r=0;
202 203 204 205 206 207 208 209 210 211
  DBUG_ENTER("vio_close");
#ifdef __WIN__
  if (vio->type == VIO_TYPE_NAMEDPIPE)
  {
#if defined(__NT__) && defined(MYSQL_SERVER)
    CancelIo(vio->hPipe);
    DisconnectNamedPipe(vio->hPipe);
#endif
    r=CloseHandle(vio->hPipe);
  }
212
  else
213
#endif /* __WIN__ */
214
 if (vio->type != VIO_CLOSED)
215
  {
216
    DBUG_ASSERT(vio->sd >= 0);
217 218 219 220 221 222 223
    if (shutdown(vio->sd,2))
      r= -1;
    if (closesocket(vio->sd))
      r= -1;
  }
  if (r)
  {
224
    DBUG_PRINT("vio_error", ("close() failed, error: %d",socket_errno));
225 226 227 228 229 230 231 232
    /* FIXME: error handling (not critical for MySQL) */
  }
  vio->type= VIO_CLOSED;
  vio->sd=   -1;
  DBUG_RETURN(r);
}


unknown's avatar
unknown committed
233
const char *vio_description(Vio * vio)
234 235 236 237
{
  return vio->desc;
}

unknown's avatar
unknown committed
238
enum enum_vio_type vio_type(Vio* vio)
239 240 241 242
{
  return vio->type;
}

unknown's avatar
unknown committed
243
my_socket vio_fd(Vio* vio)
244 245 246 247 248
{
  return vio->sd;
}


unknown's avatar
unknown committed
249
my_bool vio_peer_addr(Vio * vio, char *buf, uint16 *port)
250 251
{
  DBUG_ENTER("vio_peer_addr");
252
  DBUG_PRINT("enter", ("sd: %d", vio->sd));
253 254 255
  if (vio->localhost)
  {
    strmov(buf,"127.0.0.1");
256
    *port= 0;
257 258 259
  }
  else
  {
260 261
    size_socket addrLen = sizeof(vio->remote);
    if (getpeername(vio->sd, (struct sockaddr *) (&vio->remote),
262 263
		    &addrLen) != 0)
    {
264
      DBUG_PRINT("exit", ("getpeername gave error: %d", socket_errno));
265 266
      DBUG_RETURN(1);
    }
267
    my_inet_ntoa(vio->remote.sin_addr,buf);
268
    *port= ntohs(vio->remote.sin_port);
269
  }
270
  DBUG_PRINT("exit", ("addr: %s", buf));
271 272 273 274
  DBUG_RETURN(0);
}


unknown's avatar
unknown committed
275
void vio_in_addr(Vio *vio, struct in_addr *in)
276 277 278
{
  DBUG_ENTER("vio_in_addr");
  if (vio->localhost)
279
    bzero((char*) in, sizeof(*in));
280 281 282 283 284 285 286 287
  else
    *in=vio->remote.sin_addr;
  DBUG_VOID_RETURN;
}


/* Return 0 if there is data to be read */

unknown's avatar
unknown committed
288
my_bool vio_poll_read(Vio *vio,uint timeout)
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
{
#ifndef HAVE_POLL
  return 0;
#else
  struct pollfd fds;
  int res;
  DBUG_ENTER("vio_poll");
  fds.fd=vio->sd;
  fds.events=POLLIN;
  fds.revents=0;
  if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
  {
    DBUG_RETURN(res < 0 ? 0 : 1);		/* Don't return 1 on errors */
  }
  DBUG_RETURN(fds.revents & POLLIN ? 0 : 1);
#endif
}
306

307 308 309 310 311 312 313 314 315 316

void vio_timeout(Vio *vio __attribute__((unused)),
		 uint timeout __attribute__((unused)))
{
#ifdef __WIN__
  ulong wait_timeout= (ulong) timeout * 1000;
  (void) setsockopt(vio->sd, SOL_SOCKET, SO_RCVTIMEO, (char*) &wait_timeout,
		    sizeof(wait_timeout));
#endif /* __WIN__ */
}
unknown's avatar
unknown committed
317 318


319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
#ifdef __WIN__
int vio_read_pipe(Vio * vio, gptr buf, int size)
{
  DWORD length;
  DBUG_ENTER("vio_read_pipe");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));

  if (!ReadFile(vio->hPipe, buf, size, &length, NULL))
    DBUG_RETURN(-1);

  DBUG_PRINT("exit", ("%d", length));
  DBUG_RETURN(length);
}


int vio_write_pipe(Vio * vio, const gptr buf, int size)
{
  DWORD length;
  DBUG_ENTER("vio_write_pipe");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));

  if (!WriteFile(vio->hPipe, (char*) buf, size, &length, NULL))
    DBUG_RETURN(-1);

  DBUG_PRINT("exit", ("%d", length));
  DBUG_RETURN(length);
}

int vio_close_pipe(Vio * vio)
{
  int r;
  DBUG_ENTER("vio_close_pipe");
#if defined(__NT__) && defined(MYSQL_SERVER)
  CancelIo(vio->hPipe);
  DisconnectNamedPipe(vio->hPipe);
#endif
  r=CloseHandle(vio->hPipe);
  if (r)
  {
    DBUG_PRINT("vio_error", ("close() failed, error: %d",GetLastError()));
    /* FIXME: error handling (not critical for MySQL) */
  }
  vio->type= VIO_CLOSED;
  vio->sd=   -1;
  DBUG_RETURN(r);
}

366 367 368 369 370 371 372

void vio_ignore_timeout(Vio *vio __attribute__((unused)),
			uint timeout __attribute__((unused)))
{
}


373 374 375 376 377 378 379 380 381 382 383 384 385
#ifdef HAVE_SMEM

int vio_read_shared_memory(Vio * vio, gptr buf, int size)
{
  int length;
  int remain_local;
  char *current_postion;

  DBUG_ENTER("vio_read_shared_memory");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));

  remain_local = size;
  current_postion=buf;
386
  do
387
  {
388
    if (vio->shared_memory_remain == 0)
389
    {
unknown's avatar
unknown committed
390 391 392 393 394 395 396 397 398
      HANDLE events[2];
      events[0]= vio->event_server_wrote;
      events[1]= vio->event_conn_closed;
      /*
        WaitForMultipleObjects can return next values:
         WAIT_OBJECT_0+0 - event from vio->event_server_wrote
         WAIT_OBJECT_0+1 - event from vio->event_conn_closed. We can't read anything
         WAIT_ABANDONED_0 and WAIT_TIMEOUT - fail.  We can't read anything
      */
unknown's avatar
unknown committed
399
      if (WaitForMultipleObjects(2, (HANDLE*)&events,FALSE,
unknown's avatar
unknown committed
400
                                 vio->net->read_timeout*1000) != WAIT_OBJECT_0)
401 402 403
      {
        DBUG_RETURN(-1);
      };
unknown's avatar
unknown committed
404

405 406 407 408 409 410 411
      vio->shared_memory_pos = vio->handle_map;
      vio->shared_memory_remain = uint4korr((ulong*)vio->shared_memory_pos);
      vio->shared_memory_pos+=4;
    }

    length = size;

412
    if (vio->shared_memory_remain < length)
413
       length = vio->shared_memory_remain;
414
    if (length > remain_local)
415 416 417 418 419 420 421 422 423
       length = remain_local;

    memcpy(current_postion,vio->shared_memory_pos,length);

    vio->shared_memory_remain-=length;
    vio->shared_memory_pos+=length;
    current_postion+=length;
    remain_local-=length;

424
    if (!vio->shared_memory_remain)
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
      if (!SetEvent(vio->event_client_read)) DBUG_RETURN(-1);
  } while (remain_local);
  length = size;

  DBUG_PRINT("exit", ("%d", length));
  DBUG_RETURN(length);
}


int vio_write_shared_memory(Vio * vio, const gptr buf, int size)
{
  int length;
  uint remain;
  HANDLE pos;
  int sz;
  char *current_postion;

  DBUG_ENTER("vio_write_shared_memory");
  DBUG_PRINT("enter", ("sd=%d, buf=%p, size=%d", vio->sd, buf, size));

  remain = size;
  current_postion = buf;
447
  while (remain != 0)
448
  {
unknown's avatar
unknown committed
449 450
    if (WaitForSingleObject(vio->event_server_read, vio->net->write_timeout*1000) 
                            != WAIT_OBJECT_0)
451
    {
452
      DBUG_RETURN(-1);
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
    };

    sz = remain > shared_memory_buffer_length ? shared_memory_buffer_length: remain;

    int4store(vio->handle_map,sz);
    pos = vio->handle_map + 4;
    memcpy(pos,current_postion,sz);
    remain-=sz;
    current_postion+=sz;
    if (!SetEvent(vio->event_client_wrote)) DBUG_RETURN(-1);
  }
  length = size;

  DBUG_PRINT("exit", ("%d", length));
  DBUG_RETURN(length);
}


int vio_close_shared_memory(Vio * vio)
{
  int r;
  DBUG_ENTER("vio_close_shared_memory");
unknown's avatar
unknown committed
475
  if (vio->type != VIO_CLOSED)
476
  {
unknown's avatar
unknown committed
477 478 479 480
    /*
      Set event_conn_closed for notification of both client and server that
      connection is closed
    */
unknown's avatar
unknown committed
481
    SetEvent(vio->event_conn_closed);
unknown's avatar
unknown committed
482 483 484 485 486 487 488
    /*
      Close all handlers. UnmapViewOfFile and CloseHandle return non-zero
      result if they are success.
    */
    r= UnmapViewOfFile(vio->handle_map) || CloseHandle(vio->event_server_wrote) ||
       CloseHandle(vio->event_server_read) || CloseHandle(vio->event_client_wrote) ||
       CloseHandle(vio->event_client_read) || CloseHandle(vio->handle_file_map);
unknown's avatar
unknown committed
489 490 491 492 493
    if (!r)
    {
      DBUG_PRINT("vio_error", ("close() failed, error: %d",r));
      /* FIXME: error handling (not critical for MySQL) */
    }
494 495 496
  }
  vio->type= VIO_CLOSED;
  vio->sd=   -1;
unknown's avatar
unknown committed
497
  DBUG_RETURN(!r);
498
}
unknown's avatar
unknown committed
499 500
#endif /* HAVE_SMEM */
#endif /* __WIN__ */