Back to beaubozarth.com
util_sock.c
/*
* Socket Routines for Authentication server
* Copyright beaubozarth.com 2008
*/
#include "includes.h"
/*
* the last IP received from
*/
struct in_addr lastip;
/*
* the last port received from
*/
int lastport=0;
int smb_read_error = 0;
static char *get_socket_addr(int fd)
{
struct sockaddr sa;
struct sockaddr_in *sockin = (struct sockaddr_in *)
(&sa);
socklen_t length = sizeof(sa);
static fstring addr_buf;
fstrcpy(addr_buf,"0.0.0.0");
if (fd == -1)
{
return addr_buf;
}
if (getsockname(fd, &sa, &length) < 0)
{
DEBUG(0,("getsockname failed.
Error was %s\n", strerror(errno) ));
return addr_buf;
}
fstrcpy(addr_buf,(char
*)inet_ntoa(sockin->sin_addr));
return addr_buf;
}
static int get_socket_port(int fd)
{
struct sockaddr sa;
struct sockaddr_in *sockin = (struct sockaddr_in *)
(&sa);
socklen_t length = sizeof(sa);
if (fd == -1)
return -1;
if (getsockname(fd, &sa, &length) < 0)
{
DEBUG(0,("getsockname failed.
Error was %s\n", strerror(errno) ));
return -1;
}
return ntohs(sockin->sin_port);
}
/*
* Is this file descriptor a socket.
*/
BOOL socket_yes( int fd )
{
int v;
socklen_t l;
l = sizeof(int);
return( getsockopt(fd, SOL_SOCKET, SO_TYPE, ( char *
) &v, &l ) == 0);
}
/*
*Set user socket options.
*/
void set_socket_opts(int fd, const char *options)
{
fstring tok;
while (next_token(&options,tok," \t,",
sizeof(tok)))
{
int ret=0,i;
int value = 1;
char *p;
BOOL got_value = False;
if ((p = strchr_m(tok,'=')))
{
*p = 0;
value =
atoi(p+1);
got_value =
True;
}
for
(i=0;socket_options[i].name;i++)
if
(strequal(socket_options[i].name,tok))
break;
if (!socket_options[i].name)
{
DEBUG(0,("Unknown socket option %s\n",tok));
continue;
}
switch (socket_options[i].opttype)
{
case OPT_BOOL:
case OPT_INT:
ret =
setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char *)&value,sizeof(int));
break;
case OPT_ON:
if (got_value)
DEBUG(0,("syntax error - %s does not take a
value\n",tok));
{
int on = socket_options[i].value;
ret = setsockopt(fd,socket_options[i].level,
socket_options[i].option,(char
*)&on,sizeof(int));
}
break;
}
if (ret != 0)
DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok,
strerror(errno) ));
}
print_socket_options(fd);
}
BOOL send_keepalive(int client)
{
unsigned char buf[4];
buf[0] = SMBkeepalive;
buf[1] = buf[2] = buf[3] = 0;
return(write_socket_data(client,(char *)buf,4) == 4);
}
/*
* Open a socket of the specified type, port, and address for
incoming data.
*/
int open_socket_in(int type, int port, int dlevel, uint32 socket_addr,
BOOL rebind)
{
struct sockaddr_in sock;
int res;
memset((char *)&sock, '\0', sizeof(sock));
#ifdef HAVE_SOCK_SIN_LEN
sock.sin_len =
sizeof(sock);
#endif
sock.sin_port = htons(
port );
sock.sin_family =
AF_INET;
sock.sin_addr.s_addr = socket_addr;
res = socket(AF_INET, type, 0);
if( res == -1 )
{
if(DEBUGLVL(0))
{
dbgtext("open_socket_in(): socket() call failed: ");
dbgtext("%s\n", strerror( errno ));
}
return -1;
}
/*
* This block sets/clears the SO_REUSEADDR and
possibly SO_REUSEPORT.
*/
{
int val = rebind ? 1 : 0;
if(setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val))
== -1)
{
if(DEBUGLVL(
dlevel))
{
dbgtext("open_socket_in(): setsockopt: ");
dbgtext("SO_REUSEADDR = %s ", val?"True":"False");
dbgtext("on port %d failed ", port);
dbgtext("with error = %s\n", strerror(errno));
}
}
#ifdef SO_REUSEPORT
if(setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val))
== -1)
{
if(DEBUGLVL(
dlevel))
{
dbgtext("open_socket_in(): setsockopt: ");
dbgtext("SO_REUSEPORT = %s ", val?"True":"False");
dbgtext("on port %d failed ", port );
dbgtext("with error = %s\n", strerror(errno));
}
}
#endif /* SO_REUSEPORT */
}
/*
* now we've got a socket - we need to bind it
*/
if(bind( res, (struct sockaddr *)&sock,
sizeof(sock) ) == -1)
{
if(DEBUGLVL(dlevel) &&
(port == SMB_PORT1 || port == SMB_PORT2 || port == NMB_PORT))
{
dbgtext("bind
failed on port %d ", port);
dbgtext("socket_addr = %s.\n", inet_ntoa(sock.sin_addr));
dbgtext("Error
= %s\n", strerror(errno));
}
close(res);
return(-1);
}
DEBUG( 10, ("bind succeeded on port %d\n", port));
return(res);
}
/*
* Create an outgoing socket. timeout is in milliseconds.
*/
int open_socket_out(int type, struct in_addr *addr, int port ,int
timeout)
{
struct sockaddr_in sock_out;
int res,ret;
int connect_loop = 10;
int increment = 10;
/*
* create a socket to write to
*/
res = socket(PF_INET, type, 0);
if (res == -1)
{
DEBUG(0,("socket error (%s)\n", strerror(errno)));
return -1;
}
if (type != SOCK_STREAM)
return(res);
memset((char *)&sock_out,'\0',sizeof(sock_out));
putip((char *)&sock_out.sin_addr,(char *)addr);
sock_out.sin_port = htons( port );
sock_out.sin_family = PF_INET;
/*
* set it non-blocking
*/
set_blocking(res,False);
DEBUG(3,("Connecting to %s at port
%d\n",inet_ntoa(*addr),port));
/*
* and connect it to the destination
*/
connect_again:
ret = connect(res,(struct sockaddr
*)&sock_out,sizeof(sock_out));
/*
* Some systems return EAGAIN when they mean
EINPROGRESS
*/
if (ret < 0 && (errno == EINPROGRESS ||
errno == EALREADY ||
errno ==
EAGAIN) && (connect_loop < timeout) )
{
smb_msleep(connect_loop);
timeout -= connect_loop;
connect_loop += increment;
if (increment < 250)
{
/*
* After
8 rounds we end up at a max of 255 msec
*/
increment *=
1.5;
}
goto connect_again;
}
if (ret < 0 && (errno == EINPROGRESS ||
errno == EALREADY ||
errno ==
EAGAIN)) {
DEBUG(1,("timeout connecting to
%s:%d\n",inet_ntoa(*addr),port));
close(res);
return -1;
}
#ifdef EISCONN
if (ret < 0 && errno == EISCONN)
{
errno = 0;
ret = 0;
}
#endif
if (ret < 0) {
DEBUG(2,("error connecting to
%s:%d (%s)\n",
inet_ntoa(*addr),port,strerror(errno)));
close(res);
return -1;
}
/*
* set it blocking again
*/
set_blocking(res,True);
return res;
}
static int client_fd = -1;
void client_setfd(int fd)
{
client_fd = fd;
}
char *client_name(void)
{
return get_peer_name(client_fd,False);
}
char *client_addr(void)
{
return get_peer_addr(client_fd);
}
char *client_socket_addr(void)
{
return get_socket_addr(client_fd);
}
int client_socket_port(void)
{
return get_socket_port(client_fd);
}
struct in_addr *client_inaddr(struct sockaddr *sa)
{
struct sockaddr_in *sockin = (struct sockaddr_in *)
(sa);
socklen_t length = sizeof(*sa);
if (getpeername(client_fd, sa, &length) < 0)
{
DEBUG(0,("getpeername failed.
Error was %s\n", strerror(errno) ));
return NULL;
}
return &sockin->sin_addr;
}