1 /*------------------------------------------------------------------------- 2 * drawElements Utility Library 3 * ---------------------------- 4 * 5 * Copyright 2014 The Android Open Source Project 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 *//*! 20 * \file 21 * \brief Socket abstraction. 22 *//*--------------------------------------------------------------------*/ 23 24 #include "deSocket.h" 25 #include "deMemory.h" 26 #include "deMutex.h" 27 28 #if (DE_OS == DE_OS_WIN32) 29 # define DE_USE_WINSOCK 30 #elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX) || (DE_OS == DE_OS_IOS) || (DE_OS == DE_OS_ANDROID) || (DE_OS == DE_OS_SYMBIAN) 31 # define DE_USE_BERKELEY_SOCKETS 32 #else 33 # error Implement deSocket for your OS. 34 #endif 35 36 /* Common utilities. */ 37 38 const char* deGetSocketResultName (deSocketResult result) 39 { 40 switch (result) 41 { 42 case DE_SOCKETRESULT_SUCCESS: return "DE_SOCKETRESULT_SUCCESS"; 43 case DE_SOCKETRESULT_WOULD_BLOCK: return "DE_SOCKETRESULT_WOULD_BLOCK"; 44 case DE_SOCKETRESULT_CONNECTION_CLOSED: return "DE_SOCKETRESULT_CONNECTION_CLOSED"; 45 case DE_SOCKETRESULT_CONNECTION_TERMINATED: return "DE_SOCKETRESULT_CONNECTION_TERMINATED"; 46 case DE_SOCKETRESULT_ERROR: return "DE_SOCKETRESULT_ERROR"; 47 default: return DE_NULL; 48 } 49 } 50 51 const char* deGetSocketFamilyName (deSocketFamily family) 52 { 53 switch (family) 54 { 55 case DE_SOCKETFAMILY_INET4: return "DE_SOCKETFAMILY_INET4"; 56 case DE_SOCKETFAMILY_INET6: return "DE_SOCKETFAMILY_INET6"; 57 default: return DE_NULL; 58 } 59 } 60 61 #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS) 62 63 /* Common deSocketAddress implementation. */ 64 65 struct deSocketAddress_s 66 { 67 char* host; 68 int port; 69 deSocketFamily family; 70 deSocketType type; 71 deSocketProtocol protocol; 72 }; 73 74 deSocketAddress* deSocketAddress_create (void) 75 { 76 deSocketAddress* addr = (deSocketAddress*)deCalloc(sizeof(deSocketAddress)); 77 if (!addr) 78 return addr; 79 80 /* Sane defaults. */ 81 addr->family = DE_SOCKETFAMILY_INET4; 82 addr->type = DE_SOCKETTYPE_STREAM; 83 addr->protocol = DE_SOCKETPROTOCOL_TCP; 84 85 return addr; 86 } 87 88 deBool deSocketAddress_setFamily (deSocketAddress* address, deSocketFamily family) 89 { 90 address->family = family; 91 return DE_TRUE; 92 } 93 94 deSocketFamily deSocketAddress_getFamily (const deSocketAddress* address) 95 { 96 return address->family; 97 } 98 99 void deSocketAddress_destroy (deSocketAddress* address) 100 { 101 deFree(address->host); 102 deFree(address); 103 } 104 105 deBool deSocketAddress_setPort (deSocketAddress* address, int port) 106 { 107 address->port = port; 108 return DE_TRUE; 109 } 110 111 int deSocketAddress_getPort (const deSocketAddress* address) 112 { 113 return address->port; 114 } 115 116 deBool deSocketAddress_setHost (deSocketAddress* address, const char* host) 117 { 118 if (address->host) 119 { 120 deFree(address->host); 121 address->host = DE_NULL; 122 } 123 124 address->host = deStrdup(host); 125 return address->host != DE_NULL; 126 } 127 128 const char* deSocketAddress_getHost (const deSocketAddress* address) 129 { 130 return address->host; 131 } 132 133 134 deBool deSocketAddress_setType (deSocketAddress* address, deSocketType type) 135 { 136 address->type = type; 137 return DE_TRUE; 138 } 139 140 deSocketType deSocketAddress_getType (const deSocketAddress* address) 141 { 142 return address->type; 143 } 144 145 deBool deSocketAddress_setProtocol (deSocketAddress* address, deSocketProtocol protocol) 146 { 147 address->protocol = protocol; 148 return DE_TRUE; 149 } 150 151 deSocketProtocol deSocketAddress_getProtocol (const deSocketAddress* address) 152 { 153 return address->protocol; 154 } 155 156 #endif 157 158 #if defined(DE_USE_WINSOCK) 159 160 /* WinSock spesific. */ 161 # include <WinSock2.h> 162 # include <WinDef.h> 163 164 static deBool initWinsock (void) 165 { 166 WSADATA wsaData; 167 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 168 return DE_FALSE; 169 170 return DE_TRUE; 171 } 172 173 #elif defined(DE_USE_BERKELEY_SOCKETS) 174 175 /* Berkeley Socket includes. */ 176 # include <sys/socket.h> 177 # include <netinet/in.h> 178 # include <netinet/tcp.h> 179 # include <arpa/inet.h> 180 # include <netdb.h> 181 # include <unistd.h> 182 # include <fcntl.h> 183 # include <errno.h> 184 185 #endif 186 187 /* Socket type. */ 188 #if defined(DE_USE_WINSOCK) 189 /* \note SOCKET is unsigned type! */ 190 typedef SOCKET deSocketHandle; 191 # define DE_INVALID_SOCKET_HANDLE INVALID_SOCKET 192 #else 193 typedef int deSocketHandle; 194 # define DE_INVALID_SOCKET_HANDLE -1 195 #endif 196 197 DE_INLINE deBool deSocketHandleIsValid (deSocketHandle handle) 198 { 199 return handle != DE_INVALID_SOCKET_HANDLE; 200 } 201 202 #if defined(DE_USE_WINSOCK) || defined(DE_USE_BERKELEY_SOCKETS) 203 204 /* Shared berkeley and winsock implementation. */ 205 206 struct deSocket_s 207 { 208 deSocketHandle handle; 209 210 deMutex stateLock; 211 volatile deSocketState state; 212 volatile deUint32 openChannels; 213 }; 214 215 /* Common socket functions. */ 216 217 static int deSocketFamilyToBsdProtocolFamily (deSocketFamily family) 218 { 219 switch (family) 220 { 221 case DE_SOCKETFAMILY_INET4: return PF_INET; 222 case DE_SOCKETFAMILY_INET6: return PF_INET6; 223 default: 224 DE_ASSERT(DE_FALSE); 225 return 0; 226 } 227 } 228 229 static int deSocketTypeToBsdType (deSocketType type) 230 { 231 switch (type) 232 { 233 case DE_SOCKETTYPE_STREAM: return SOCK_STREAM; 234 case DE_SOCKETTYPE_DATAGRAM: return SOCK_DGRAM; 235 default: 236 DE_ASSERT(DE_FALSE); 237 return 0; 238 } 239 } 240 241 static int deSocketProtocolToBsdProtocol (deSocketProtocol protocol) 242 { 243 switch (protocol) 244 { 245 case DE_SOCKETPROTOCOL_TCP: return IPPROTO_TCP; 246 case DE_SOCKETPROTOCOL_UDP: return IPPROTO_UDP; 247 default: 248 DE_ASSERT(DE_FALSE); 249 return 0; 250 } 251 } 252 253 static deBool deSocketAddressToBsdAddress (const deSocketAddress* address, struct sockaddr* bsdAddr, int* bsdAddrSize, deSocketFamily* family) 254 { 255 deBool hasHost = address->host != DE_NULL; 256 deUint8 hostAddr[16]; /*!< Binary representation. */ 257 258 deMemset(bsdAddr, 0, sizeof(struct sockaddr)); 259 260 *family = address->family; 261 262 /* If host is supplied, use gethostbyname() to determine actual family. */ 263 if (hasHost) 264 { 265 struct hostent* host = gethostbyname(address->host); 266 267 if (!host) 268 return DE_FALSE; 269 270 if (host->h_addrtype == AF_INET) 271 *family = DE_SOCKETFAMILY_INET4; 272 else if (host->h_addrtype == AF_INET6) 273 *family = DE_SOCKETFAMILY_INET6; 274 else 275 return DE_FALSE; 276 277 DE_ASSERT((host->h_addrtype == AF_INET && host->h_length == 4) || 278 (host->h_addrtype == AF_INET6 && host->h_length == 16)); 279 280 /* Use first address. */ 281 if (host->h_addr_list[0] != 0) 282 deMemcpy(hostAddr, host->h_addr_list[0], host->h_length); 283 else 284 return DE_FALSE; 285 } 286 287 if (*family == DE_SOCKETFAMILY_INET4) 288 { 289 struct sockaddr_in* addr4 = (struct sockaddr_in*)bsdAddr; 290 291 addr4->sin_port = htons((deUint16)address->port); 292 addr4->sin_family = AF_INET; 293 294 if (hasHost) 295 deMemcpy(&addr4->sin_addr, hostAddr, 4); 296 else 297 addr4->sin_addr.s_addr = INADDR_ANY; 298 299 *bsdAddrSize = sizeof(struct sockaddr_in); 300 return DE_TRUE; 301 } 302 else if (*family == DE_SOCKETFAMILY_INET6) 303 { 304 DE_ASSERT(!"TODO"); 305 return DE_FALSE; 306 } 307 else 308 return DE_FALSE; 309 } 310 311 void deBsdAddressToSocketAddress (deSocketAddress* address, const struct sockaddr* bsdAddr, int addrLen) 312 { 313 /* Decode client address info. */ 314 if (bsdAddr->sa_family == AF_INET) 315 { 316 const struct sockaddr_in* addr4 = (const struct sockaddr_in*)bsdAddr; 317 DE_ASSERT(addrLen >= (int)sizeof(struct sockaddr_in)); 318 DE_UNREF(addrLen); 319 320 deSocketAddress_setFamily(address, DE_SOCKETFAMILY_INET4); 321 deSocketAddress_setPort(address, ntohs(addr4->sin_port)); 322 323 #if defined(DE_USE_WINSOCK) 324 deSocketAddress_setHost(address, inet_ntoa(addr4->sin_addr)); 325 #else 326 { 327 char buf[16]; 328 inet_ntop(AF_INET, &addr4->sin_addr, buf, sizeof(buf)); 329 deSocketAddress_setHost(address, buf); 330 } 331 #endif 332 } 333 else 334 DE_ASSERT(DE_FALSE); 335 } 336 337 deSocket* deSocket_create (void) 338 { 339 deSocket* sock = (deSocket*)deCalloc(sizeof(deSocket)); 340 if (!sock) 341 return sock; 342 343 #if defined(DE_USE_WINSOCK) 344 /* Make sure WSA is up. */ 345 if (!initWinsock()) 346 return 0; 347 #endif 348 349 sock->stateLock = deMutex_create(0); 350 sock->handle = DE_INVALID_SOCKET_HANDLE; 351 sock->state = DE_SOCKETSTATE_CLOSED; 352 353 return sock; 354 } 355 356 void deSocket_destroy (deSocket* sock) 357 { 358 if (sock->state != DE_SOCKETSTATE_CLOSED) 359 deSocket_close(sock); 360 361 deMutex_destroy(sock->stateLock); 362 deFree(sock); 363 } 364 365 deSocketState deSocket_getState (const deSocket* sock) 366 { 367 return sock->state; 368 } 369 370 deUint32 deSocket_getOpenChannels (const deSocket* sock) 371 { 372 return sock->openChannels; 373 } 374 375 deBool deSocket_setFlags (deSocket* sock, deUint32 flags) 376 { 377 deSocketHandle fd = sock->handle; 378 379 if (sock->state == DE_SOCKETSTATE_CLOSED) 380 return DE_FALSE; 381 382 /* Keepalive. */ 383 { 384 int mode = (flags & DE_SOCKET_KEEPALIVE) ? 1 : 0; 385 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&mode, sizeof(mode)) != 0) 386 return DE_FALSE; 387 } 388 389 /* Nodelay. */ 390 { 391 int mode = (flags & DE_SOCKET_NODELAY) ? 1 : 0; 392 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&mode, sizeof(mode)) != 0) 393 return DE_FALSE; 394 } 395 396 /* Non-blocking. */ 397 { 398 #if defined(DE_USE_WINSOCK) 399 u_long mode = (flags & DE_SOCKET_NONBLOCKING) ? 1 : 0; 400 if (ioctlsocket(fd, FIONBIO, &mode) != 0) 401 return DE_FALSE; 402 #else 403 int oldFlags = fcntl(fd, F_GETFL, 0); 404 int newFlags = (flags & DE_SOCKET_NONBLOCKING) ? (oldFlags | O_NONBLOCK) : (oldFlags & ~O_NONBLOCK); 405 if (fcntl(fd, F_SETFL, newFlags) != 0) 406 return DE_FALSE; 407 #endif 408 } 409 410 /* Close on exec. */ 411 { 412 #if defined(DE_USE_BERKELEY_SOCKETS) 413 int oldFlags = fcntl(fd, F_GETFD, 0); 414 int newFlags = (flags & DE_SOCKET_CLOSE_ON_EXEC) ? (oldFlags | FD_CLOEXEC) : (oldFlags & ~FD_CLOEXEC); 415 if (fcntl(fd, F_SETFD, newFlags) != 0) 416 return DE_FALSE; 417 #endif 418 } 419 420 return DE_TRUE; 421 } 422 423 deBool deSocket_listen (deSocket* sock, const deSocketAddress* address) 424 { 425 const int backlogSize = 4; 426 struct sockaddr bsdAddr; 427 int bsdAddrLen; 428 deSocketFamily family; 429 430 if (sock->state != DE_SOCKETSTATE_CLOSED) 431 return DE_FALSE; 432 433 /* Resolve address. */ 434 if (!deSocketAddressToBsdAddress(address, &bsdAddr, &bsdAddrLen, &family)) 435 return DE_FALSE; 436 437 /* Create socket. */ 438 sock->handle = socket(deSocketFamilyToBsdProtocolFamily(family), deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol)); 439 if (!deSocketHandleIsValid(sock->handle)) 440 return DE_FALSE; 441 442 sock->state = DE_SOCKETSTATE_DISCONNECTED; 443 444 /* Allow re-using address. */ 445 { 446 int reuseVal = 1; 447 setsockopt(sock->handle, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseVal, (int)sizeof(reuseVal)); 448 } 449 450 /* Bind to address. */ 451 if (bind(sock->handle, &bsdAddr, bsdAddrLen) != 0) 452 { 453 deSocket_close(sock); 454 return DE_FALSE; 455 } 456 457 /* Start listening. */ 458 if (listen(sock->handle, backlogSize) != 0) 459 { 460 deSocket_close(sock); 461 return DE_FALSE; 462 } 463 464 sock->state = DE_SOCKETSTATE_LISTENING; 465 466 return DE_TRUE; 467 } 468 469 deSocket* deSocket_accept (deSocket* sock, deSocketAddress* clientAddress) 470 { 471 deSocketHandle newFd = DE_INVALID_SOCKET_HANDLE; 472 deSocket* newSock = DE_NULL; 473 struct sockaddr addr; 474 int addrLen = (int)sizeof(addr); 475 476 deMemset(&addr, 0, sizeof(addr)); 477 478 #if defined(DE_USE_WINSOCK) 479 newFd = accept(sock->handle, (struct sockaddr*)&addr, &addrLen); 480 #else 481 newFd = accept(sock->handle, (struct sockaddr*)&addr, (socklen_t*)&addrLen); 482 #endif 483 if (!deSocketHandleIsValid(newFd)) 484 return DE_NULL; 485 486 newSock = (deSocket*)deCalloc(sizeof(deSocket)); 487 if (!newSock) 488 { 489 #if defined(DE_USE_WINSOCK) 490 closesocket(newFd); 491 #else 492 close(newFd); 493 #endif 494 return DE_NULL; 495 } 496 497 newSock->stateLock = deMutex_create(0); 498 newSock->handle = newFd; 499 newSock->state = DE_SOCKETSTATE_CONNECTED; 500 newSock->openChannels = DE_SOCKETCHANNEL_BOTH; 501 502 if (clientAddress) 503 deBsdAddressToSocketAddress(clientAddress, &addr, addrLen); 504 505 return newSock; 506 } 507 508 deBool deSocket_connect (deSocket* sock, const deSocketAddress* address) 509 { 510 struct sockaddr bsdAddr; 511 int bsdAddrLen; 512 deSocketFamily family; 513 514 /* Resolve address. */ 515 if (!deSocketAddressToBsdAddress(address, &bsdAddr, &bsdAddrLen, &family)) 516 return DE_FALSE; 517 518 /* Create socket. */ 519 sock->handle = socket(deSocketFamilyToBsdProtocolFamily(family), deSocketTypeToBsdType(address->type), deSocketProtocolToBsdProtocol(address->protocol)); 520 if (!deSocketHandleIsValid(sock->handle)) 521 return DE_FALSE; 522 523 /* Connect. */ 524 if (connect(sock->handle, &bsdAddr, bsdAddrLen) != 0) 525 return DE_FALSE; 526 527 sock->state = DE_SOCKETSTATE_CONNECTED; 528 sock->openChannels = DE_SOCKETCHANNEL_BOTH; 529 530 return DE_TRUE; 531 } 532 533 deBool deSocket_shutdown (deSocket* sock, deUint32 channels) 534 { 535 deUint32 closedChannels = 0; 536 537 deMutex_lock(sock->stateLock); 538 539 if (sock->state == DE_SOCKETSTATE_DISCONNECTED || 540 sock->state == DE_SOCKETSTATE_CLOSED) 541 { 542 deMutex_unlock(sock->stateLock); 543 return DE_FALSE; 544 } 545 546 DE_ASSERT(channels != 0 && (channels & ~DE_SOCKETCHANNEL_BOTH) == 0); 547 548 /* Don't attempt to close already closed channels on partially open socket. */ 549 channels &= sock->openChannels; 550 551 if (channels == 0) 552 { 553 deMutex_unlock(sock->stateLock); 554 return DE_FALSE; 555 } 556 557 #if defined(DE_USE_WINSOCK) 558 { 559 int how = 0; 560 561 if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH) 562 how = SD_BOTH; 563 else if (channels & DE_SOCKETCHANNEL_SEND) 564 how = SD_SEND; 565 else if (channels & DE_SOCKETCHANNEL_RECEIVE) 566 how = SD_RECEIVE; 567 568 if (shutdown(sock->handle, how) == 0) 569 closedChannels = channels; 570 else 571 { 572 int err = WSAGetLastError(); 573 574 /* \note Due to asynchronous behavior certain errors are perfectly ok. */ 575 if (err == WSAECONNABORTED || err == WSAECONNRESET || err == WSAENOTCONN) 576 closedChannels = DE_SOCKETCHANNEL_BOTH; 577 else 578 { 579 deMutex_unlock(sock->stateLock); 580 return DE_FALSE; 581 } 582 } 583 } 584 #else 585 { 586 int how = 0; 587 588 if ((channels & DE_SOCKETCHANNEL_BOTH) == DE_SOCKETCHANNEL_BOTH) 589 how = SHUT_RDWR; 590 else if (channels & DE_SOCKETCHANNEL_SEND) 591 how = SHUT_WR; 592 else if (channels & DE_SOCKETCHANNEL_RECEIVE) 593 how = SHUT_RD; 594 595 if (shutdown(sock->handle, how) == 0) 596 closedChannels = channels; 597 else 598 { 599 if (errno == ENOTCONN) 600 closedChannels = DE_SOCKETCHANNEL_BOTH; 601 else 602 { 603 deMutex_unlock(sock->stateLock); 604 return DE_FALSE; 605 } 606 } 607 } 608 #endif 609 610 sock->openChannels &= ~closedChannels; 611 if (sock->openChannels == 0) 612 sock->state = DE_SOCKETSTATE_DISCONNECTED; 613 614 deMutex_unlock(sock->stateLock); 615 return DE_TRUE; 616 } 617 618 deBool deSocket_close (deSocket* sock) 619 { 620 deMutex_lock(sock->stateLock); 621 622 if (sock->state == DE_SOCKETSTATE_CLOSED) 623 { 624 deMutex_unlock(sock->stateLock); 625 return DE_FALSE; 626 } 627 628 #if !defined(DE_USE_WINSOCK) 629 if (sock->state == DE_SOCKETSTATE_LISTENING) 630 { 631 /* There can be a thread blockin in accept(). Release it by calling shutdown. */ 632 shutdown(sock->handle, SHUT_RDWR); 633 } 634 #endif 635 636 #if defined(DE_USE_WINSOCK) 637 if (closesocket(sock->handle) != 0) 638 return DE_FALSE; 639 #else 640 if (close(sock->handle) != 0) 641 return DE_FALSE; 642 #endif 643 sock->state = DE_SOCKETSTATE_CLOSED; 644 sock->handle = DE_INVALID_SOCKET_HANDLE; 645 sock->openChannels = 0; 646 647 deMutex_unlock(sock->stateLock); 648 return DE_TRUE; 649 } 650 651 static deSocketResult mapSendRecvResult (int numBytes) 652 { 653 if (numBytes > 0) 654 return DE_SOCKETRESULT_SUCCESS; 655 else if (numBytes == 0) 656 return DE_SOCKETRESULT_CONNECTION_CLOSED; 657 else 658 { 659 /* Other errors. */ 660 #if defined(DE_USE_WINSOCK) 661 int error = WSAGetLastError(); 662 switch (error) 663 { 664 case WSAEWOULDBLOCK: return DE_SOCKETRESULT_WOULD_BLOCK; 665 case WSAENETDOWN: 666 case WSAENETRESET: 667 case WSAECONNABORTED: 668 case WSAECONNRESET: return DE_SOCKETRESULT_CONNECTION_TERMINATED; 669 default: return DE_SOCKETRESULT_ERROR; 670 } 671 #else 672 switch (errno) 673 { 674 case EAGAIN: return DE_SOCKETRESULT_WOULD_BLOCK; 675 case ECONNABORTED: 676 case ECONNRESET: return DE_SOCKETRESULT_CONNECTION_TERMINATED; 677 default: return DE_SOCKETRESULT_ERROR; 678 } 679 #endif 680 } 681 } 682 683 DE_INLINE void deSocket_setChannelsClosed (deSocket* sock, deUint32 channels) 684 { 685 deMutex_lock(sock->stateLock); 686 687 sock->openChannels &= ~channels; 688 if (sock->openChannels == 0) 689 sock->state = DE_SOCKETSTATE_DISCONNECTED; 690 691 deMutex_unlock(sock->stateLock); 692 } 693 694 deSocketResult deSocket_send (deSocket* sock, const void* buf, int bufSize, int* numSentPtr) 695 { 696 int numSent = (int)send(sock->handle, (const char*)buf, bufSize, 0); 697 deSocketResult result = mapSendRecvResult(numSent); 698 699 if (numSentPtr) 700 *numSentPtr = numSent; 701 702 /* Update state. */ 703 if (result == DE_SOCKETRESULT_CONNECTION_CLOSED) 704 deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_SEND); 705 else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED) 706 deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH); 707 708 return result; 709 } 710 711 deSocketResult deSocket_receive (deSocket* sock, void* buf, int bufSize, int* numReceivedPtr) 712 { 713 int numRecv = (int)recv(sock->handle, (char*)buf, bufSize, 0); 714 deSocketResult result = mapSendRecvResult(numRecv); 715 716 if (numReceivedPtr) 717 *numReceivedPtr = numRecv; 718 719 /* Update state. */ 720 if (result == DE_SOCKETRESULT_CONNECTION_CLOSED) 721 deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_RECEIVE); 722 else if (result == DE_SOCKETRESULT_CONNECTION_TERMINATED) 723 deSocket_setChannelsClosed(sock, DE_SOCKETCHANNEL_BOTH); 724 725 return result; 726 } 727 728 #endif 729