X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Fsocket.c;h=1dbbdeae5eb5c21758f5e1c7789765f706706d71;hb=d7c6e9aaa9df593e951e2f19106dcc71102e74f1;hp=71bb817f847f142aac2cbe53fa3efe33cb902c54;hpb=d14e28387f825d7acc33d655db7a22506b064d83;p=deb_libnfs.git diff --git a/lib/socket.c b/lib/socket.c index 71bb817..1dbbdea 100644 --- a/lib/socket.c +++ b/lib/socket.c @@ -18,7 +18,6 @@ #include "win32_compat.h" #else #include -#include #include #include #include @@ -28,8 +27,18 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif + +#ifdef AROS +#include "aros_compat.h" +#endif + +#ifdef HAVE_POLL_H +#include +#endif + #include #include +#include #include #include #include @@ -69,12 +78,18 @@ static void set_nonblocking(int fd) int rpc_get_fd(struct rpc_context *rpc) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + return rpc->fd; } int rpc_which_events(struct rpc_context *rpc) { - int events = rpc->is_connected ? POLLIN : POLLOUT; + int events; + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + events = rpc->is_connected ? POLLIN : POLLOUT; if (rpc->is_udp != 0) { /* for udp sockets we only wait for pollin */ @@ -91,9 +106,8 @@ static int rpc_write_to_socket(struct rpc_context *rpc) { int32_t count; - if (rpc == NULL) { - return -1; - } + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (rpc->fd == -1) { rpc_set_error(rpc, "trying to write but not connected"); return -1; @@ -135,6 +149,10 @@ static int rpc_read_from_socket(struct rpc_context *rpc) int pdu_size; int32_t count; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + #if defined(WIN32) if (ioctlsocket(rpc->fd, FIONREAD, &available) != 0) { #else @@ -257,6 +275,8 @@ static int rpc_read_from_socket(struct rpc_context *rpc) int rpc_service(struct rpc_context *rpc, int revents) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (revents & POLLERR) { #ifdef WIN32 char err = 0; @@ -335,11 +355,15 @@ int rpc_service(struct rpc_context *rpc, int revents) void rpc_set_autoreconnect(struct rpc_context *rpc) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + rpc->auto_reconnect = 1; } void rpc_unset_autoreconnect(struct rpc_context *rpc) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + rpc->auto_reconnect = 0; } @@ -347,6 +371,8 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s { int socksize; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + switch (s->ss_family) { case AF_INET: socksize = sizeof(struct sockaddr_in); @@ -362,8 +388,6 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s return -1; } - -#if !defined(WIN32) /* Some systems allow you to set capabilities on an executable * to allow the file to be executed with privilege to bind to * privileged system ports, even if the user is not root. @@ -378,42 +402,43 @@ static int rpc_connect_sockaddr_async(struct rpc_context *rpc, struct sockaddr_s * On linux, use * sudo setcap 'cap_net_bind_service=+ep' /path/executable * to make the executable able to bind to a system port. + * + * On Windows, there is no concept of privileged ports. Thus + * binding will usually succeed. */ - if (1) { - static int port = 200; - int i; - int one = 1; - - setsockopt(rpc->fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); - - for (i = 0; i < 500; i++) { - struct sockaddr_in sin; - - if(++port > 700) port = 200; - - memset(&sin, 0, sizeof(sin)); - sin.sin_port = htons(port); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = 0; - - if (bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) != 0 && errno != EACCES) { - /* we didnt get EACCES, so try again */ - continue; + { + struct sockaddr_in sin; + static int portOfs = 0; + const int firstPort = 512; /* >= 512 according to Sun docs */ + const int portCount = IPPORT_RESERVED - firstPort; + int startOfs = portOfs, port, rc; + + do { + rc = -1; + port = htons(firstPort + portOfs); + portOfs = (portOfs + 1) % portCount; + + /* skip well-known ports */ + if (!getservbyport(port, "tcp")) { + memset(&sin, 0, sizeof(sin)); + sin.sin_port = port; + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = 0; + + rc = bind(rpc->fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); +#if !defined(WIN32) + /* we got EACCES, so don't try again */ + if (rc != 0 && errno == EACCES) + break; +#endif } - break; - } + } while (rc != 0 && portOfs != startOfs); } -#endif set_nonblocking(rpc->fd); -#if defined(WIN32) - if (connect(rpc->fd, (struct sockaddr *)s, socksize) == 0 && errno != EINPROGRESS ) -#else - if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) -#endif - { - rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno); + if (connect(rpc->fd, (struct sockaddr *)s, socksize) != 0 && errno != EINPROGRESS) { + rpc_set_error(rpc, "connect() to server failed. %s(%d)", strerror(errno), errno); return -1; } @@ -424,6 +449,8 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc { struct sockaddr_in *sin = (struct sockaddr_in *)&rpc->s; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (rpc->fd != -1) { rpc_set_error(rpc, "Trying to connect while already connected"); return -1; @@ -464,6 +491,8 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc int rpc_disconnect(struct rpc_context *rpc, char *error) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + rpc_unset_autoreconnect(rpc); if (rpc->fd != -1) { @@ -484,6 +513,8 @@ int rpc_disconnect(struct rpc_context *rpc, char *error) static void reconnect_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (status != RPC_STATUS_SUCCESS) { rpc_error_all_pdus(rpc, "RPC ERROR: Failed to reconnect async"); return; @@ -498,6 +529,8 @@ static int rpc_reconnect_requeue(struct rpc_context *rpc) { struct rpc_pdu *pdu; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (rpc->fd != -1) { #if defined(WIN32) closesocket(rpc->fd); @@ -537,6 +570,8 @@ int rpc_bind_udp(struct rpc_context *rpc, char *addr, int port) struct addrinfo *ai = NULL; char service[6]; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (rpc->is_udp == 0) { rpc_set_error(rpc, "Cant not bind UDP. Not UDP context"); return -1; @@ -580,6 +615,8 @@ int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int i struct addrinfo *ai = NULL; char service[6]; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + if (rpc->is_udp == 0) { rpc_set_error(rpc, "Can not set destination sockaddr. Not UDP context"); return -1; @@ -599,6 +636,7 @@ int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int i rpc->udp_dest = malloc(ai->ai_addrlen); if (rpc->udp_dest == NULL) { rpc_set_error(rpc, "Out of memory. Failed to allocate sockaddr structure"); + freeaddrinfo(ai); return -1; } memcpy(rpc->udp_dest, ai->ai_addr, ai->ai_addrlen); @@ -612,6 +650,8 @@ int rpc_set_udp_destination(struct rpc_context *rpc, char *addr, int port, int i struct sockaddr *rpc_get_recv_sockaddr(struct rpc_context *rpc) { + assert(rpc->magic == RPC_CONTEXT_MAGIC); + return (struct sockaddr *)&rpc->udp_src; } @@ -620,6 +660,8 @@ int rpc_queue_length(struct rpc_context *rpc) int i=0; struct rpc_pdu *pdu; + assert(rpc->magic == RPC_CONTEXT_MAGIC); + for(pdu = rpc->outqueue; pdu; pdu = pdu->next) { i++; }