X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/0fb3fc9b633724644a4528871430c7e4e7555e2b..05123b198d59b22c133d23dcf9b03934b4653e5e:/src/gras/Transport/transport_plugin_tcp.c diff --git a/src/gras/Transport/transport_plugin_tcp.c b/src/gras/Transport/transport_plugin_tcp.c index 490ceeb430..2683d7a7fa 100644 --- a/src/gras/Transport/transport_plugin_tcp.c +++ b/src/gras/Transport/transport_plugin_tcp.c @@ -2,60 +2,44 @@ /* tcp trp (transport) - send/receive a bunch of bytes from a tcp socket */ -/* Authors: Martin Quinson */ -/* Copyright (C) 2004 Martin Quinson. */ +/* Copyright (c) 2004 Martin Quinson. All rights reserved. */ /* This program is free software; you can redistribute it and/or modify it - under the terms of the license (GNU LGPL) which comes with this package. */ - -#include /* close() pipe() read() write() */ -#include /* close() pipe() read() write() */ -#include /* sometimes required for #include */ -#include /* TCP_NODELAY */ -#include /* inet_ntoa() */ -#include /* getprotobyname() */ -#include /* struct timeval */ -#include /* errno */ -#include /* waitpid() */ -#include /* getpeername() socket() */ -#include - - -#include "gras_private.h" -#include "transport_private.h" + * under the terms of the license (GNU LGPL) which comes with this package. */ -GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(trp_tcp,transport); +#include "portable.h" -typedef struct { - int buffsize; -} gras_trp_tcp_sock_specific_t; +#if 0 +# include /* close() pipe() read() write() */ +# include /* waitpid() */ +#endif + + +#include "transport_private.h" + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(trp_tcp,transport,"TCP transport"); /*** *** Prototypes ***/ -gras_error_t gras_trp_tcp_socket_client(gras_trp_plugin_t *self, - const char *host, - unsigned short port, - unsigned int bufSize, - /* OUT */ gras_socket_t **dst); -gras_error_t gras_trp_tcp_socket_server(gras_trp_plugin_t *self, - unsigned short port, - unsigned int bufSize, - /* OUT */ gras_socket_t **dst); -gras_error_t gras_trp_tcp_socket_accept(gras_socket_t *sock, - gras_socket_t **dst); - -void gras_trp_tcp_socket_close(gras_socket_t *sd); +xbt_error_t gras_trp_tcp_socket_client(gras_trp_plugin_t *self, + gras_socket_t sock); +xbt_error_t gras_trp_tcp_socket_server(gras_trp_plugin_t *self, + gras_socket_t sock); +xbt_error_t gras_trp_tcp_socket_accept(gras_socket_t sock, + gras_socket_t *dst); + +void gras_trp_tcp_socket_close(gras_socket_t sd); -gras_error_t gras_trp_tcp_bloc_send(gras_socket_t *sd, - char *data, - size_t size); +xbt_error_t gras_trp_tcp_chunk_send(gras_socket_t sd, + const char *data, + long int size); -gras_error_t gras_trp_tcp_bloc_recv(gras_socket_t *sd, - char *data, - size_t size); +xbt_error_t gras_trp_tcp_chunk_recv(gras_socket_t sd, + char *data, + long int size); -void gras_trp_tcp_free_specific(void *s); +void gras_trp_tcp_exit(gras_trp_plugin_t *plug); static int TcpProtoNumber(void); @@ -64,182 +48,203 @@ static int TcpProtoNumber(void); ***/ typedef struct { - fd_set incoming_socks; -} gras_trp_tcp_specific_t; + fd_set msg_socks; + fd_set meas_socks; +} gras_trp_tcp_plug_data_t; /*** *** Specific socket part ***/ +typedef struct { + int buffsize; +} gras_trp_tcp_sock_data_t; + /*** *** Code ***/ -gras_error_t -gras_trp_tcp_init(gras_trp_plugin_t **dst) { +xbt_error_t gras_trp_tcp_setup(gras_trp_plugin_t *plug) { - gras_trp_plugin_t *res=malloc(sizeof(gras_trp_plugin_t)); - gras_trp_tcp_specific_t *tcp = malloc(sizeof(gras_trp_tcp_specific_t)); - if (!res || !tcp) - RAISE_MALLOC; + gras_trp_tcp_plug_data_t *data = xbt_new(gras_trp_tcp_plug_data_t,1); - FD_ZERO(&(tcp->incoming_socks)); + FD_ZERO(&(data->msg_socks)); + FD_ZERO(&(data->meas_socks)); - res->socket_client = gras_trp_tcp_socket_client; - res->socket_server = gras_trp_tcp_socket_server; - res->socket_accept = gras_trp_tcp_socket_accept; - res->socket_close = gras_trp_tcp_socket_close; + plug->socket_client = gras_trp_tcp_socket_client; + plug->socket_server = gras_trp_tcp_socket_server; + plug->socket_accept = gras_trp_tcp_socket_accept; + plug->socket_close = gras_trp_tcp_socket_close; - res->specific = (void*)tcp; - res->free_specific = gras_trp_tcp_free_specific; + plug->chunk_send = gras_trp_tcp_chunk_send; + plug->chunk_recv = gras_trp_tcp_chunk_recv; - *dst = res; + plug->flush = NULL; /* nothing's cached */ + + plug->data = (void*)data; + plug->exit = gras_trp_tcp_exit; + return no_error; } -void gras_trp_tcp_free_specific(void *s) { - gras_trp_tcp_specific_t *specific = s; - free(specific); +void gras_trp_tcp_exit(gras_trp_plugin_t *plug) { + DEBUG1("Exit plugin TCP (free %p)", plug->data); + free(plug->data); } -gras_error_t gras_trp_tcp_socket_client(gras_trp_plugin_t *self, - const char *host, - unsigned short port, - unsigned int bufSize, - /* OUT */ gras_socket_t **dst){ - - int addrCount; - IPAddress addresses[10]; - int i; - int sd; +xbt_error_t gras_trp_tcp_socket_client(gras_trp_plugin_t *self, + gras_socket_t sock){ - if (!(*sock=malloc(sizeof(gras_socket_t)))) - RAISE_MALLOC; + struct sockaddr_in addr; + struct hostent *he; + struct in_addr *haddr; + int size = sock->bufSize * 1024; + + sock->incoming = 1; /* TCP sockets are duplex'ed */ + + sock->sd = socket (AF_INET, SOCK_STREAM, 0); - (*sock)->peer_addr=NULL; + if (sock->sd < 0) { + RAISE1(system_error, + "Failed to create socket: %s", + sock_errstr); + } + + if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) || + setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) { + WARN1("setsockopt failed, cannot set buffer size: %s",sock_errstr); + } - if (!(addrCount = IPAddressValues(host, addresses, 10))) { + he = gethostbyname (sock->peer_name); + if (he == NULL) { RAISE2(system_error, - "tcp address retrieval of '%s' failed: %s", - host,strerror(errno)); + "Failed to lookup hostname %s: %s", + sock->peer_name, sock_errstr); } - for(i = 0; i < addrCount && i<10 ; i++) { - if(CallAddr(addresses[i], port, &sd, -1)) { - (*sock)->sock = sd; - (*sock)->port = port; - return no_error; - } + haddr = ((struct in_addr *) (he->h_addr_list)[0]); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons (sock->peer_port); + + DEBUG2("Connect to %s:%d",sock->peer_name, sock->peer_port); + if (connect (sock->sd, (struct sockaddr*) &addr, sizeof (addr)) < 0) { + tcp_close(sock->sd); + RAISE3(system_error, + "Failed to connect socket to %s:%d (%s)", + sock->peer_name, sock->peer_port, sock_errstr); } - free(*sock); - RAISE2(system_error,"Something wicked happenned while connecting to %s:%d", - host,port); + + return no_error; } /** * gras_trp_tcp_socket_server: * - * Open a socket used to receive messages. bufSize is in ko. + * Open a socket used to receive messages. */ -gras_error_t gras_trp_tcp_socket_server(gras_trp_plugin_t *self, - unsigned short port, - unsigned int bufSize, - /* OUT */ gras_socket_t **dst){ - int size = bufSize * 1024; +xbt_error_t gras_trp_tcp_socket_server(gras_trp_plugin_t *self, + /* OUT */ gras_socket_t sock){ + int size = sock->bufSize * 1024; int on = 1; - int sd = -1; struct sockaddr_in server; - gras_socket_t *res; - gras_trp_tcp_specific_t *data=(gras_trp_tcp_specific_t*)self -> specific; + gras_trp_tcp_plug_data_t *tcp=(gras_trp_tcp_plug_data_t*)self->data; - res=malloc(sizeof(gras_socket_t)); - if (!res) - RAISE_MALLOC; + sock->outgoing = 1; /* TCP => duplex mode */ - server.sin_port = htons((u_short)port); + server.sin_port = htons((u_short)sock->port); server.sin_addr.s_addr = INADDR_ANY; server.sin_family = AF_INET; - if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - free(res); - RAISE1(system_error,"socket allocation failed: %s", strerror(errno)); + if((sock->sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + RAISE1(system_error,"Socket allocation failed: %s", sock_errstr); } - (void)setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); - (void)setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)); - (void)setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size)); - if (bind(sd, (struct sockaddr *)&server, sizeof(server)) == -1) { - free(res); - close(sd); - RAISE2(system_error,"Cannot bind to port %d: %s",port, strerror(errno)); + if (setsockopt(sock->sd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on))) { + RAISE1(system_error,"setsockopt failed, cannot condition the socket: %s", + sock_errstr); } - - if (listen(sd, 5) != -1) { - free(res); - close(sd); - RAISE2(system_error,"Cannot listen to port %d: %s",port,strerror(errno)); + + if (setsockopt(sock->sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) || + setsockopt(sock->sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) { + WARN1("setsockopt failed, cannot set buffer size: %s", + sock_errstr); + } + + if (bind(sock->sd, (struct sockaddr *)&server, sizeof(server)) == -1) { + tcp_close(sock->sd); + RAISE2(system_error,"Cannot bind to port %d: %s",sock->port, sock_errstr); } - FD_SET(sd, &(data->incoming_socks)); + DEBUG1("Listen on port %d",sock->port); + if (listen(sock->sd, 5) < 0) { + tcp_close(sock->sd); + RAISE2(system_error,"Cannot listen on port %d: %s",sock->port,sock_errstr); + } - *dst=res; - res->plugin = self; - res->incoming = 1; - res->sd = sd; - res->port=port; - res->peer_port=-1; - res->peer_name=NULL; + if (sock->meas) + FD_SET(sock->sd, &(tcp->meas_socks)); + else + FD_SET(sock->sd, &(tcp->msg_socks)); - DEBUG2("Openned a server socket on port %d (sock %d)",port,sd); + DEBUG2("Openned a server socket on port %d (sock %d)",sock->port,sock->sd); return no_error; } -gras_error_t -gras_trp_tcp_socket_accept(gras_socket_t *sock, - gras_socket_t **dst) { - gras_socket_t *res; +xbt_error_t +gras_trp_tcp_socket_accept(gras_socket_t sock, + gras_socket_t *dst) { + gras_socket_t res; struct sockaddr_in peer_in; socklen_t peer_in_len = sizeof(peer_in); int sd; int tmp_errno; - - res=malloc(sizeof(gras_socket_t)); - if (!res) - RAISE_MALLOC; + int size; + + XBT_IN; + gras_trp_socket_new(1,&res); sd = accept(sock->sd, (struct sockaddr *)&peer_in, &peer_in_len); tmp_errno = errno; - if(sd == -1) { + if (sd == -1) { gras_socket_close(sock); RAISE1(system_error, - "Accept failed (%s). Droping server socket.", strerror(tmp_errno)); + "Accept failed (%s). Droping server socket.", sock_errstr); } else { int i = 1; socklen_t s = sizeof(int); if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, s) || setsockopt(sd, TcpProtoNumber(), TCP_NODELAY, (char *)&i, s)) { - WARNING0("setsockopt failed, cannot condition the accepted socket"); - } - - i = ((gras_trp_tcp_sock_specific_t*)sock->specific)->buffsize; - if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&i, s) - || setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&i, s)) { - WARNING0("setsockopt failed, cannot set buffsize"); + RAISE1(system_error,"setsockopt failed, cannot condition the socket: %s", + sock_errstr); } - - res->plugin = sock->plugin; - res->incoming = 1; - res->sd = sd; - res->port= -1; - res->peer_port= peer_in.sin_port; + res->bufSize = sock->bufSize; + size = sock->bufSize * 1024; + if (setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&size, sizeof(size)) + || setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&size, sizeof(size))) { + WARN1("setsockopt failed, cannot set buffer size: %s", + sock_errstr); + } + + res->plugin = sock->plugin; + res->incoming = sock->incoming; + res->outgoing = sock->outgoing; + res->accepting = 0; + res->sd = sd; + res->port = -1; + res->peer_port = peer_in.sin_port; + + /* FIXME: Lock to protect inet_ntoa */ if (((struct sockaddr *)&peer_in)->sa_family != AF_INET) { - res->peer_name = strdup("unknown"); + res->peer_name = (char*)strdup("unknown"); } else { struct in_addr addrAsInAddr; char *tmp; @@ -248,27 +253,28 @@ gras_trp_tcp_socket_accept(gras_socket_t *sock, tmp = inet_ntoa(addrAsInAddr); if (tmp != NULL) { - res->peer_name = strdup(inet_ntoa(addrAsInAddr)); + res->peer_name = (char*)strdup(tmp); } else { - res->peer_name = strdup("unknown"); + res->peer_name = (char*)strdup("unknown"); } } - VERB3("accepted socket %d to %s:%d\n", sd, res->peer_name,res->peer_port); + VERB3("Accepted socket %d to %s:%d", sd, res->peer_name,res->peer_port); *dst = res; + XBT_OUT; return no_error; } } -void gras_trp_tcp_socket_close(gras_socket_t *sock){ - gras_trp_tcp_specific_t *tcp; +void gras_trp_tcp_socket_close(gras_socket_t sock){ + gras_trp_tcp_plug_data_t *tcp; if (!sock) return; /* close only once */ - tcp=sock->plugin->specific; + tcp=sock->plugin->data; - DEBUG1("close tcp connection %d\n", sock->sd); + DEBUG1("close tcp connection %d", sock->sd); /* FIXME: no pipe in GRAS so far if(!FD_ISSET(sd, &connectedPipes)) { @@ -284,14 +290,23 @@ void gras_trp_tcp_socket_close(gras_socket_t *sock){ } } */ +#ifndef HAVE_WINSOCK_H + /* forget about the socket + ... but not when using winsock since accept'ed socket can not fit + into the fd_set*/ + if (sock->meas){ + FD_CLR(sock->sd, &(tcp->meas_socks)); + } else { + FD_CLR(sock->sd, &(tcp->msg_socks)); + } +#endif + /* close the socket */ - if(close(sock->sd) < 0) { - WARNING3("error while closing tcp socket %d: %d (%s)\n", sock->sd, errno, strerror(errno)); + if(tcp_close(sock->sd) < 0) { + WARN3("error while closing tcp socket %d: %d (%s)\n", + sock->sd, sock_errno, sock_errstr); } - /* forget about it */ - FD_CLR(sock->sd, &(tcp->incoming_socks)); - } /** @@ -299,32 +314,32 @@ void gras_trp_tcp_socket_close(gras_socket_t *sock){ * * Send data on a TCP socket */ -gras_error_t -gras_trp_tcp_chunk_send(gras_socket_t *sock, - char *data, - size_t size) { +xbt_error_t +gras_trp_tcp_chunk_send(gras_socket_t sock, + const char *data, + long int size) { - /* gras_assert0(sock && !sock->incoming, - "Asked to send stuff on an incomming socket");*/ - gras_assert0(size >= 0, "Cannot send a negative amount of data"); + /* TCP sockets are in duplex mode, don't check direction */ + xbt_assert0(size >= 0, "Cannot send a negative amount of data"); while (size) { int status = 0; - status = write(sock->sd, data, (size_t)size); - DEBUG3("write(%d, %p, %ld);\n", sock->sd, data, size); + status = tcp_write(sock->sd, data, (size_t)size); + DEBUG3("write(%d, %p, %ld);", sock->sd, data, size); - if (status == -1) { - RAISE4(system_error,"write(%d,%p,%d) failed: %s", - sock->sd, data, (int)size, - strerror(errno)); + if (status < 0) { + RAISE4(system_error,"write(%d,%p,%ld) failed: %s", + sock->sd, data, size, + sock_errstr); } if (status) { size -= status; data += status; } else { - RAISE0(system_error,"file descriptor closed"); + RAISE1(system_error,"file descriptor closed (%s)", + sock_errstr); } } @@ -335,31 +350,32 @@ gras_trp_tcp_chunk_send(gras_socket_t *sock, * * Receive data on a TCP socket. */ -gras_error_t -gras_trp_tcp_chunk_recv(gras_socket_t *sock, +xbt_error_t +gras_trp_tcp_chunk_recv(gras_socket_t sock, char *data, - size_t size) { - gras_assert0(sock && !sock->incoming, - "Ascked to receive stuff on an outcomming socket"); - gras_assert0(size >= 0, "Cannot receive a negative amount of data"); + long int size) { + + /* TCP sockets are in duplex mode, don't check direction */ + xbt_assert0(sock, "Cannot recv on an NULL socket"); + xbt_assert0(size >= 0, "Cannot receive a negative amount of data"); while (size) { int status = 0; - status = read(sock->sd, data, (size_t)size); - DEBUG3("read(%d, %p, %ld);\n", sock->sd, data, size); + status = tcp_read(sock->sd, data, (size_t)size); + DEBUG3("read(%d, %p, %ld);", sock->sd, data, size); - if (status == -1) { + if (status < 0) { RAISE4(system_error,"read(%d,%p,%d) failed: %s", sock->sd, data, (int)size, - strerror(errno)); + sock_errstr); } if (status) { size -= status; data += status; } else { - RAISE0(system_error,"file descriptor closed"); + RAISE0(system_error,"file descriptor closed (nothing read on the socket)"); } } @@ -378,9 +394,134 @@ static int TcpProtoNumber(void) { if(returnValue == 0) { fetchedEntry = getprotobyname("tcp"); - gras_assert0(fetchedEntry, "getprotobyname(tcp) gave NULL"); + xbt_assert0(fetchedEntry, "getprotobyname(tcp) gave NULL"); returnValue = fetchedEntry->p_proto; } return returnValue; } + +#if 0 /* KILLME */ +/* Data exchange over measurement sockets. Placing this in there is a kind of crude hack. + It means that the only possible measurement sockets are TCP where we may want to do UDP for them. + But I fail to find a good internal organization for now. We may want to split + meas and regular sockets more efficiently. +*/ +xbt_error_t gras_socket_meas_exchange(gras_socket_t peer, + int sender, + unsigned int timeout, + unsigned long int exp_size, + unsigned long int msg_size) { + char *chunk; + int res_last, msg_sofar, exp_sofar; + + fd_set rd_set; +/* int rv; */ + + struct timeval timeOut; + + chunk = xbt_malloc(msg_size); + + for (exp_sofar=0; exp_sofar < exp_size; exp_sofar += msg_size) { + for(msg_sofar=0; msg_sofar < msg_size; msg_sofar += res_last) { + + if(sender) { + res_last = send(peer->sd, chunk, msg_size - msg_sofar, 0); + } else { + res_last = 0; + FD_ZERO(&rd_set); + FD_SET(peer->sd,&rd_set); + timeOut.tv_sec = timeout; + timeOut.tv_usec = 0; + + if (0 < select(peer->sd+1,&rd_set,NULL,NULL,&timeOut)) + res_last = recv(peer->sd, chunk, msg_size-msg_sofar, 0); + + } + if (res_last == 0) { + /* No progress done, bail out */ + free(chunk); + RAISE0(unknown_error,"Not exchanged a single byte, bailing out"); + } + } + } + + free(chunk); + return no_error; +} +#endif + +#ifdef HAVE_WINSOCK_H +#define RETSTR( x ) case x: return #x + +const char *gras_wsa_err2string( int err ) { + switch( err ) { + RETSTR( WSAEINTR ); + RETSTR( WSAEBADF ); + RETSTR( WSAEACCES ); + RETSTR( WSAEFAULT ); + RETSTR( WSAEINVAL ); + RETSTR( WSAEMFILE ); + RETSTR( WSAEWOULDBLOCK ); + RETSTR( WSAEINPROGRESS ); + RETSTR( WSAEALREADY ); + RETSTR( WSAENOTSOCK ); + RETSTR( WSAEDESTADDRREQ ); + RETSTR( WSAEMSGSIZE ); + RETSTR( WSAEPROTOTYPE ); + RETSTR( WSAENOPROTOOPT ); + RETSTR( WSAEPROTONOSUPPORT ); + RETSTR( WSAESOCKTNOSUPPORT ); + RETSTR( WSAEOPNOTSUPP ); + RETSTR( WSAEPFNOSUPPORT ); + RETSTR( WSAEAFNOSUPPORT ); + RETSTR( WSAEADDRINUSE ); + RETSTR( WSAEADDRNOTAVAIL ); + RETSTR( WSAENETDOWN ); + RETSTR( WSAENETUNREACH ); + RETSTR( WSAENETRESET ); + RETSTR( WSAECONNABORTED ); + RETSTR( WSAECONNRESET ); + RETSTR( WSAENOBUFS ); + RETSTR( WSAEISCONN ); + RETSTR( WSAENOTCONN ); + RETSTR( WSAESHUTDOWN ); + RETSTR( WSAETOOMANYREFS ); + RETSTR( WSAETIMEDOUT ); + RETSTR( WSAECONNREFUSED ); + RETSTR( WSAELOOP ); + RETSTR( WSAENAMETOOLONG ); + RETSTR( WSAEHOSTDOWN ); + RETSTR( WSAEHOSTUNREACH ); + RETSTR( WSAENOTEMPTY ); + RETSTR( WSAEPROCLIM ); + RETSTR( WSAEUSERS ); + RETSTR( WSAEDQUOT ); + RETSTR( WSAESTALE ); + RETSTR( WSAEREMOTE ); + RETSTR( WSASYSNOTREADY ); + RETSTR( WSAVERNOTSUPPORTED ); + RETSTR( WSANOTINITIALISED ); + RETSTR( WSAEDISCON ); + +#ifdef HAVE_WINSOCK2 + RETSTR( WSAENOMORE ); + RETSTR( WSAECANCELLED ); + RETSTR( WSAEINVALIDPROCTABLE ); + RETSTR( WSAEINVALIDPROVIDER ); + RETSTR( WSASYSCALLFAILURE ); + RETSTR( WSASERVICE_NOT_FOUND ); + RETSTR( WSATYPE_NOT_FOUND ); + RETSTR( WSA_E_NO_MORE ); + RETSTR( WSA_E_CANCELLED ); + RETSTR( WSAEREFUSED ); +#endif /* HAVE_WINSOCK2 */ + + RETSTR( WSAHOST_NOT_FOUND ); + RETSTR( WSATRY_AGAIN ); + RETSTR( WSANO_RECOVERY ); + RETSTR( WSANO_DATA ); + } + return "unknown WSA error"; +} +#endif /* HAVE_WINSOCK_H */