00001 /* 00002 * Copyright (c) 2002 - 2003 00003 * NetGroup, Politecnico di Torino (Italy) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 3. Neither the name of the Politecnico di Torino nor the names of its 00016 * contributors may be used to endorse or promote products derived from 00017 * this software without specific prior written permission. 00018 * 00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00020 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00022 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00023 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00024 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00025 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00026 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00027 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00029 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00030 * 00031 */ 00032 00033 00034 00035 #include "sockutils.h" 00036 #include <string.h> // for strerror 00037 #include <errno.h> // for the errno variable 00038 #include <stdio.h> // for the stderr file 00039 00054 // WinSock Initialization 00055 #ifdef WIN32 00056 #define WINSOCK_MAJOR_VERSION 2 00057 #define WINSOCK_MINOR_VERSION 2 00058 int sockcount= 0; 00059 #endif 00060 00061 // Some minor differences between UNIX and Win32 00062 #ifdef WIN32 00063 #define SHUT_WR SD_SEND 00064 #define snprintf _snprintf 00065 #endif 00066 00067 00068 00069 /**************************************************** 00070 * * 00071 * Locally defined functions * 00072 * * 00073 ****************************************************/ 00074 00075 int sock_ismcastaddr(const struct sockaddr *saddr); 00076 00077 00078 00079 /* 00080 \brief Global variable; needed to keep the message due to an error that we want to discard. 00081 00082 This can happen, for instance, because we already have an error message and we want to keep 00083 the first one. 00084 */ 00085 char fakeerrbuf[SOCK_ERRBUF_SIZE + 1]; 00086 00087 00088 00089 00090 00091 /**************************************************** 00092 * * 00093 * Function bodies * 00094 * * 00095 ****************************************************/ 00096 00097 00116 void sock_geterror(const char *caller, char *string, int size) 00117 { 00118 #ifdef WIN32 00119 int retval; 00120 int code; 00121 char message[SOCK_ERRBUF_SIZE]; 00122 00123 code= GetLastError(); 00124 00125 retval= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | 00126 FORMAT_MESSAGE_MAX_WIDTH_MASK, 00127 NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 00128 (LPSTR) message, SOCK_ERRBUF_SIZE, NULL); 00129 00130 if (retval == 0) 00131 { 00132 snprintf(string, size, "%sUnable to get the exact error message", caller); 00133 return; 00134 } 00135 00136 snprintf(string, size, "%s%s (code %d)", caller, message, code); 00137 00138 #else 00139 char *message; 00140 00141 message= strerror(errno); 00142 snprintf(string, size, "%s%s (code %d)", caller, message, errno); 00143 #endif 00144 } 00145 00146 00147 00160 int sock_init(char *errbuf) 00161 { 00162 #ifdef WIN32 00163 if (sockcount == 0) 00164 { 00165 WSADATA wsaData; // helper variable needed to initialize Winsock 00166 00167 // Ask for Winsock version 2.2. 00168 if ( WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 00169 { 00170 snprintf(errbuf, SOCK_ERRBUF_SIZE, "Failed to initialize Winsock\n"); 00171 WSACleanup(); 00172 return -1; 00173 } 00174 } 00175 00176 sockcount++; 00177 #endif 00178 00179 return 0; 00180 } 00181 00182 00183 00192 void sock_cleanup() 00193 { 00194 #ifdef WIN32 00195 sockcount--; 00196 if (sockcount == 0) 00197 WSACleanup(); 00198 #endif 00199 } 00200 00201 00202 00208 int sock_ismcastaddr(const struct sockaddr *saddr) 00209 { 00210 if (saddr->sa_family == PF_INET) 00211 { 00212 struct sockaddr_in *saddr4 = (struct sockaddr_in *) saddr; 00213 if (IN_MULTICAST(ntohl(saddr4->sin_addr.s_addr))) return 0; 00214 else return -1; 00215 } 00216 else 00217 { 00218 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *) saddr; 00219 if (IN6_IS_ADDR_MULTICAST(&saddr6->sin6_addr)) return 0; 00220 else return -1; 00221 } 00222 } 00223 00224 00225 00254 int sock_open(struct addrinfo *addrinfo, int server, int nconn, char *errbuf) 00255 { 00256 SOCKET sock; 00257 00258 sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); 00259 if (sock == -1) 00260 { 00261 sock_geterror("socket(): ", errbuf, SOCK_ERRBUF_SIZE); 00262 return -1; 00263 } 00264 00265 00266 // This is a server socket 00267 if (server) 00268 { 00269 #ifdef BSD 00270 // Force the use of IPv6-only addresses; in BSD you can accept both v4 and v6 00271 // connections if you have a "NULL" pointer as the nodename in the getaddrinfo() 00272 // This behaviour is not clear in the RFC 2553, so each system implements the 00273 // bind() differently from this point of view 00274 00275 if (addrinfo->ai_family == PF_INET6) 00276 { 00277 int on; 00278 00279 if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDV6ONLY, (char *)&on, sizeof (int)) == -1) 00280 { 00281 snprintf(errbuf, SOCK_ERRBUF_SIZE, "setsockopt(IPV6_BINDV6ONLY)"); 00282 return -1; 00283 } 00284 } 00285 #endif 00286 00287 // WARNING: if the address is a mcast one, I should place the proper Win32 code here 00288 if (bind(sock, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) 00289 { 00290 sock_geterror("bind(): ", errbuf, SOCK_ERRBUF_SIZE); 00291 return -1; 00292 } 00293 00294 if (addrinfo->ai_socktype == SOCK_STREAM) 00295 if (listen(sock, nconn) == -1) 00296 { 00297 sock_geterror("listen(): ", errbuf, SOCK_ERRBUF_SIZE); 00298 return -1; 00299 } 00300 00301 // server side ended 00302 return sock; 00303 } 00304 else // we're the client 00305 { 00306 if (connect(sock, addrinfo->ai_addr, addrinfo->ai_addrlen) == -1) 00307 { 00308 sock_geterror("Is libpcap/WinPcap properly installed on the other host? connect() failed: ", errbuf, SOCK_ERRBUF_SIZE); 00309 closesocket(sock); 00310 return -1; 00311 } 00312 00313 return sock; 00314 } 00315 } 00316 00317 00318 00319 00334 int sock_close(SOCKET sock, char *errbuf) 00335 { 00336 // SHUT_WR: subsequent calls to the send function are disallowed. 00337 // For TCP sockets, a FIN will be sent after all data is sent and 00338 // acknowledged by the Server. 00339 if (shutdown(sock, SHUT_WR) ) 00340 { 00341 sock_geterror("shutdown(): ", errbuf, SOCK_ERRBUF_SIZE); 00342 // close the socket anyway 00343 closesocket(sock); 00344 return -1; 00345 } 00346 00347 closesocket(sock); 00348 return 0; 00349 } 00350 00351 00352 00353 00354 00355 00386 int sock_validaddr(const char *address, const char *port, 00387 struct addrinfo *hints, struct addrinfo **addrinfo, char *errbuf) 00388 { 00389 int retval; 00390 00391 retval = getaddrinfo(address, port, hints, addrinfo); 00392 if (retval != 0) 00393 { 00394 // if the getaddrinfo() fails, you have to use gai_strerror(), instead of using the standard 00395 // error routines (WSAGetLastError() in Win32 anderrono in UNIX) 00396 snprintf(errbuf, SOCK_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval)); 00397 return -1; 00398 } 00404 // This software only supports PF_INET and PF_INET6. 00405 if (( (*addrinfo)->ai_family != PF_INET) && ( (*addrinfo)->ai_family != PF_INET6)) 00406 { 00407 snprintf(errbuf, SOCK_ERRBUF_SIZE, "getaddrinfo(): socket type not supported"); 00408 return -1; 00409 } 00410 00411 if ( ( (*addrinfo)->ai_socktype == SOCK_STREAM) && (sock_ismcastaddr( (*addrinfo)->ai_addr) == 0) ) 00412 { 00413 snprintf(errbuf, SOCK_ERRBUF_SIZE, "getaddrinfo(): multicast addresses are not valid when using TCP streams"); 00414 return -1; 00415 } 00416 00417 return 0; 00418 } 00419 00420 00421 00443 int sock_send(SOCKET socket, const char *buffer, int size, char *errbuf) 00444 { 00445 int nsent; 00446 00447 send: 00448 #ifdef linux 00449 /* 00450 Another pain... in Linux there's this flag 00451 MSG_NOSIGNAL 00452 Requests not to send SIGPIPE on errors on stream 00453 oriented sockets when the other end breaks the con 00454 nection. The EPIPE error is still returned. 00455 */ 00456 nsent = send(socket, buffer, size, MSG_NOSIGNAL); 00457 #else 00458 nsent = send(socket, buffer, size, 0); 00459 #endif 00460 00461 if (nsent == -1) 00462 { 00463 sock_geterror("send(): ", errbuf, SOCK_ERRBUF_SIZE); 00464 return -1; 00465 } 00466 00467 if (nsent != size) 00468 { 00469 size-= nsent; 00470 buffer+= nsent; 00471 goto send; 00472 } 00473 00474 return 0; 00475 } 00476 00477 00524 int sock_bufferize(const char *buffer, int size, char *tempbuf, int *offset, int totsize, int checkonly, char *errbuf) 00525 { 00526 00527 if ((*offset + size) > totsize) 00528 { 00529 snprintf(errbuf, SOCK_ERRBUF_SIZE, "Not enough space in the temporary send buffer."); 00530 return -1; 00531 }; 00532 00533 if (!checkonly) 00534 memcpy(tempbuf + (*offset), buffer, size); 00535 00536 (*offset)+= size; 00537 00538 return 0; 00539 } 00540 00541 00542 00566 int sock_recv(SOCKET sock, char *buffer, int size, char *errbuf) 00567 { 00568 int nread; 00569 int totread= 0; 00570 // We can obtain the same result using the MSG_WAITALL flag 00571 // However, this is not supported by recv() in Win32 00572 00573 if (size == 0) 00574 { 00575 SOCK_ASSERT("I have been requested to read zero bytes", 1); 00576 return 0; 00577 } 00578 00579 again: 00580 nread= recv(sock, &(buffer[totread]), size - totread, 0); 00581 00582 if (nread == -1) 00583 { 00584 sock_geterror("recv(): ", errbuf, SOCK_ERRBUF_SIZE); 00585 return -1; 00586 } 00587 00588 if (nread == 0) 00589 { 00590 snprintf(errbuf, SOCK_ERRBUF_SIZE, "The other host terminated the connection."); 00591 return -1; 00592 } 00593 00594 totread+= nread; 00595 00596 if (totread != size) 00597 goto again; 00598 00599 return totread; 00600 } 00601 00602 00603 00635 int sock_recv_dgram(SOCKET sock, char *buffer, int size, char *errbuf) 00636 { 00637 int nread; 00638 00639 nread= recv(sock, buffer, size, 0); 00640 00641 if (nread == -1) 00642 { 00643 sock_geterror("recv(): ", errbuf, SOCK_ERRBUF_SIZE); 00644 return -1; 00645 } 00646 00647 return nread; 00648 } 00649 00650 00672 int sock_discard(SOCKET sock, int size, char *errbuf) 00673 { 00674 #define TEMP_BUF_SIZE 65536 00675 00676 char buffer[TEMP_BUF_SIZE]; // network buffer, to be used when the message is discarded 00677 00678 // A static allocation avoids the need of a 'malloc()' each time we want to discard a message 00679 // Our feeling is that a buffer if 65536 is enough for mot of the application; 00680 // in case this is not enough, the "while" loop discards the message by calling the 00681 // sockrecv() several times. 00682 00683 while (size > TEMP_BUF_SIZE) 00684 { 00685 if (sock_recv(sock, buffer, TEMP_BUF_SIZE, errbuf) == -1) 00686 return -1; 00687 size-= TEMP_BUF_SIZE; 00688 } 00689 00690 // If there is still data to be discarded 00691 // In this case, the data can fit into the temporaty buffer 00692 if (size) 00693 { 00694 if (sock_recv(sock, buffer, size, errbuf) == -1) 00695 return -1; 00696 } 00697 00698 SOCK_ASSERT("I'm currently discarding data\n", 1); 00699 00700 return 0; 00701 } 00702 00703 00704 00726 int sock_check_hostlist(char *hostlist, const char *sep, struct sockaddr_storage *from, char *errbuf) 00727 { 00728 // checks if the connecting host is among the ones allowed 00729 if (hostlist[0]) 00730 { 00731 char *token; // temp, needed to separate items into the hostlist 00732 struct addrinfo *addrinfo, *ai_next; 00733 char *temphostlist; 00734 00735 temphostlist= (char *) malloc (strlen(hostlist) + 1); 00736 if (temphostlist == NULL) 00737 { 00738 sock_geterror("sock_check_hostlist(), malloc() failed", errbuf, SOCK_ERRBUF_SIZE); 00739 return -1; 00740 } 00741 00742 // The problem is that strtok modifies the original variable by putting '0' at the end of each token 00743 // So, we have to create a new temporary string in which the original content is kept 00744 strcpy(temphostlist, hostlist); 00745 00746 token= strtok(temphostlist, sep); 00747 00748 while( token != NULL ) 00749 { 00750 struct addrinfo hints; 00751 int retval; 00752 00753 addrinfo = NULL; 00754 memset(&hints, 0, sizeof (struct addrinfo) ); 00755 hints.ai_family = PF_UNSPEC; 00756 hints.ai_socktype= SOCK_STREAM; 00757 00758 retval = getaddrinfo(token, "0", &hints, &addrinfo); 00759 if (retval != 0) 00760 { 00761 snprintf(errbuf, SOCK_ERRBUF_SIZE, "getaddrinfo() %s", gai_strerror(retval)); 00762 SOCK_ASSERT(errbuf, 1); 00763 00764 // Get next token 00765 token = strtok( NULL, sep); 00766 continue; 00767 } 00768 00769 // ai_next is required to preserve the content of addrinfo, in order to deallocate it properly 00770 ai_next= addrinfo; 00771 while(ai_next) 00772 { 00773 if (sock_cmpaddr(from, (struct sockaddr_storage *) ai_next->ai_addr) == 0) 00774 { 00775 free(temphostlist); 00776 return 0; 00777 } 00778 00779 // If we are here, it means that the current address does not matches 00780 // Let's try with the next one in the header chain 00781 ai_next= ai_next->ai_next; 00782 } 00783 00784 freeaddrinfo(addrinfo); 00785 addrinfo= NULL; 00786 // Get next token 00787 token = strtok( NULL, sep); 00788 } 00789 00790 if (addrinfo) 00791 { 00792 freeaddrinfo(addrinfo); 00793 addrinfo= NULL; 00794 } 00795 00796 snprintf(errbuf, SOCK_ERRBUF_SIZE, "The host is not in the allowed host list. Connection refused."); 00797 free(temphostlist); 00798 return -1; 00799 } 00800 00801 return 0; 00802 } 00803 00804 00823 int sock_cmpaddr(struct sockaddr_storage *first, struct sockaddr_storage *second) 00824 { 00825 if (first->ss_family == second->ss_family) 00826 { 00827 if (first->ss_family == AF_INET) 00828 { 00829 if (memcmp( &(((struct sockaddr_in *) first)->sin_addr), 00830 &(((struct sockaddr_in *) second)->sin_addr), 00831 sizeof(struct in_addr) ) == 0) 00832 return 0; 00833 } 00834 else // address family is AF_INET6 00835 { 00836 if (memcmp( &(((struct sockaddr_in6 *) first)->sin6_addr), 00837 &(((struct sockaddr_in6 *) second)->sin6_addr), 00838 sizeof(struct in6_addr) ) == 0) 00839 return 0; 00840 } 00841 } 00842 00843 return -1; 00844 } 00845
documentation. Copyright (c) 2002-2003 Politecnico di Torino. All rights reserved.