Main Page Modules Data Structures File List Data Fields Globals Related Pages

# sockutils.c

Go to the documentation of this file.

    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.