modules/sk/socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- func_atexit
- func_sighup
- func_sigint
- SK_close
- SK_getsock
- SK_accept_connection
- SK_read
- SK_write
- SK_gets
- SK_puts
- SK_putc
- SK_getc
- SK_getpeername
- SK_getpeerip
- SK_cd_puts
- SK_cd_gets
- SK_cd_close
/***************************************
$Revision: 1.15 $
Example code: A socket module.
Status: NOT REVUED, NOT TESTED
+html+ <DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
+html+ </UL>
+html+ </DL>
+html+ <PRE>
+html+ </PRE>
******************/ /******************
Modification History:
ottrey (08/03/1999) Created from sockhelp.c.
ottrey (08/03/1998) Heavily butchered.
joao (22/06/1999) Modified socket creation and accepts.
******************/ /******************
REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
***************************************/
#include <arpa/inet.h>
#include "socket.h"
#include "constants.h"
#include "stubs.h"
#include "iproutines.h"
#include "memwrap.h"
extern int h_errno;
/*+ String sizes +*/
#define STR_S 63
#define STR_M 255
#define STR_L 1023
#define STR_XL 4095
#define STR_XXL 16383
/* SK_atoport() */
/*++++++++++++++++++++++++++++++++++++++
Take a service name, and a service type, and return a port number. If the
service name is not found, it tries it as a decimal number. The number
returned is byte ordered for the network.
char *service Service name (or port number).
char *proto Protocol (eg "tcp").
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
int SK_atoport(const char *service, const char *proto) {
/* [<][>][^][v][top][bottom][index][help] */
int port;
long int lport;
struct servent *serv;
char *errpos;
struct servent result;
char buffer[STR_XXL];
/* First try to read it from /etc/services */
/* serv = getservbyname(service, proto); */
serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
if (serv != NULL)
port = serv->s_port;
else { /* Not in services, maybe a number? */
lport = strtol(service,&errpos,0);
if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
return -1; /* Invalid port address */
port = htons(lport);
}
return port;
} /* SK_atoport() */
/* SK_close_listening_socket() */
/*++++++++++++++++++++++++++++++++++++++
XXX Note: Not sure how long this function will last. Shouldn't _really_ need it.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
/*void SK_close_listening_socket() {
close(listening_socket);
} */ /* SK_close_listening_socket */
static void func_atexit(void) {
/* [<][>][^][v][top][bottom][index][help] */
ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_atexit() called");
}
static void func_sighup(int n) {
/* [<][>][^][v][top][bottom][index][help] */
ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sighup(%d) called", n);
}
static void func_sigint(int n) {
/* [<][>][^][v][top][bottom][index][help] */
ER_dbg_va(FAC_SK, ASP_SK_GEN,"func_sigint(%d) called", n);
}
void SK_close(int socket) {
/* [<][>][^][v][top][bottom][index][help] */
ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
close(socket);
}
/* SK_getsock() */
/*++++++++++++++++++++++++++++++++++++++
This function creates a socket and binds to it
int SK_getsock The new socket
int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
u_short port The port to listen on. Remember that ports < 1024 are
reserved for the root user. Must be passed in network byte
order (see "man htons").
uint32_t bind_address Address to bind to, in network order.
More:
+html+ <PRE>
Authors:
ottrey
joao
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
/* [<][>][^][v][top][bottom][index][help] */
struct sockaddr_in address;
int listening_socket;
int reuse_addr = 1;
/* Setup internet address information.
This is used with the bind() call */
memset((char *) &address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = port;
address.sin_addr.s_addr = bind_address;
/* Map all of the signals and exit routine */
atexit(func_atexit);
/* signal.h has a full list of signal names */
listening_socket = socket(AF_INET, socket_type, 0);
if (listening_socket < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
perror("bind");
close(listening_socket);
exit(EXIT_FAILURE);
}
if (socket_type == SOCK_STREAM) {
listen(listening_socket, 5); /* Queue up to five connections before
having them automatically rejected. */
}
return listening_socket;
} /* SK_getsock() */
/*++++++++++++++++++++++++++++++++++++++
Wait for an incoming connection on the specified socket
int SK_accept_connection The socket for communicating to the client
int listening_socket The socket that the server is bound to
More:
+html+ <PRE>
Authors:
joao
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_accept_connection(int listening_socket) {
/* [<][>][^][v][top][bottom][index][help] */
int connected_socket = -1;
while(connected_socket < 0) {
ER_dbg_va(FAC_SK, ASP_SK_GEN,
"Going to accept connections on socket : %d",listening_socket);
/* XXX joao - ? - why is this here?
fflush(NULL);
*/
connected_socket = accept(listening_socket, NULL, NULL);
if (connected_socket < 0) {
/* Either a real error occured, or blocking was interrupted for
some reason. Only abort execution if a real error occured. */
if (errno != EINTR) {
perror("accept");
close(listening_socket);
return(-1);
/* no exit, just return with error */
} else {
continue; /* don't return - do the accept again */
}
}
}
ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
connected_socket
);
return connected_socket;
}
/* SK_read() */
/*++++++++++++++++++++++++++++++++++++++
This is just like the read() system call, except that it will make
sure that all your data goes through the socket.
int SK_read The number of bytes read.
int sockfd The socket file descriptor.
char *buf The buffer to be read from the socket.
size_t count The number of bytes in the buffer.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_read(int sockfd, char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
size_t bytes_read = 0;
int this_read;
while (bytes_read < count) {
do
this_read = read(sockfd, buf, count - bytes_read);
while ( (this_read < 0) && (errno == EINTR) );
if (this_read < 0)
return this_read;
else if (this_read == 0)
return bytes_read;
bytes_read += this_read;
buf += this_read;
}
return count;
} /* SK_read() */
/* SK_write() */
/*++++++++++++++++++++++++++++++++++++++
This is just like the write() system call, accept that it will
make sure that all data is transmitted.
int sockfd The socket file descriptor.
char *buf The buffer to be written to the socket.
size_t count The number of bytes in the buffer.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE><DL COMPACT>
+html+ <DT>Online References:
+html+ <DD><UL>
+html+ </UL></DL>
++++++++++++++++++++++++++++++++++++++*/
int SK_write(int sockfd, const char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
size_t bytes_sent = 0;
int this_write;
ER_dbg_va(FAC_SK, ASP_SK_WRIT,
"SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
sockfd, buf, count);
while (bytes_sent < count) {
do
this_write = write(sockfd, buf, count - bytes_sent);
while ( (this_write < 0) && (errno == EINTR) );
if (this_write <= 0)
return this_write;
bytes_sent += this_write;
buf += this_write;
}
return count;
} /* SK_write() */
/* SK_gets() */
/*++++++++++++++++++++++++++++++++++++++
This function reads from a socket, until it recieves a linefeed
character. It fills the buffer "str" up to the maximum size "count".
int SK_gets The total_count of bytes read.
int sockfd The socket file descriptor.
char *str The buffer to be written from the socket.
size_t count The number of bytes in the buffer.
More:
+html+ <PRE>
Authors:
ottrey
Side Effects:
This function will return -1 if the socket is closed during the read operation.
Note that if a single line exceeds the length of count, the extra data
will be read and discarded! You have been warned.
To Do:
Capture the control-c properly!
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_gets(int sockfd, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
int bytes_read;
int total_count = 0;
char *current_position;
char last_read = 0;
int control_c = 0;
current_position = str;
while (last_read != 10) {
bytes_read = read(sockfd, &last_read, 1);
if (bytes_read <= 0) {
/* The other side may have closed unexpectedly */
return SK_DISCONNECT;
/* Is this effective on other platforms than linux? */
}
if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
*current_position = last_read;
current_position++;
total_count++;
}
if (last_read == -1) {
bytes_read = read(sockfd, &last_read, 1);
if (last_read == -12) {
ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
control_c = 1;
ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
return SK_INTERRUPT;
}
}
}
if (count > 0) {
*current_position = 0;
}
return total_count;
} /* SK_gets() */
/* SK_puts() */
/*++++++++++++++++++++++++++++++++++++++
This function writes a character string out to a socket.
int SK_puts The total_count of bytes written,
or errors (represented as negative numbers)
int sockfd The socket file descriptor.
char *str The buffer to be written from the socket.
More:
+html+ <PRE>
Authors:
ottrey
Side Effects:
This function will return -1 if the socket is closed during the write operation.
Note that if a single line exceeds the length of count, the extra data
will be read and discarded! You have been warned.
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_puts(int sockfd, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
return SK_write(sockfd, str, strlen(str));
} /* SK_puts() */
/* SK_putc() */
/*++++++++++++++++++++++++++++++++++++++
int SK_putc This function writes a single character out to a socket.
int sockfd socket
char ch character
return number of chars written
++++++++++++++++++++++++++++++++++++++*/
int SK_putc(int sockfd, char ch) {
/* [<][>][^][v][top][bottom][index][help] */
return SK_write(sockfd, &ch, 1);
}/* SK_putc() */
/*++++++++++++++++++++++++++++++++++++++
This function reads a single character from a socket.
returns EOF when no character can be read.
++++++++++++++++++++++++++++++++++++++*/
int SK_getc(int sockfd) {
/* [<][>][^][v][top][bottom][index][help] */
char ch;
if( read(sockfd, &ch, 1) <= 0 ) {
return EOF;
}
else {
return ch;
}
}/* SK_getc() */
/* SK_getpeername() */
/*++++++++++++++++++++++++++++++++++++++
This function will tell you who is at the other end of a connected stream socket.
XXX It's not working.
XXX ? MB it is...
int sockfd The socket file descriptor.
More:
+html+ <PRE>
Authors:
ottrey
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
char *SK_getpeername(int sockfd)
/* [<][>][^][v][top][bottom][index][help] */
{
char *hostaddress=NULL;
struct sockaddr_in addr_in;
int namelen=sizeof(addr_in);
if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK);
strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */
}
return hostaddress;
} /* SK_getpeername() */
/* SK_getpeerip */
int SK_getpeerip(int sockfd, ip_addr_t *ip) {
/* [<][>][^][v][top][bottom][index][help] */
struct sockaddr_in addr_in;
int namelen=sizeof(addr_in);
int ret=-1;
memset(& addr_in, 0, sizeof(struct sockaddr_in));
if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
ret=0;
IP_addr_s2b(ip, &addr_in, namelen);
}
return ret;
}
/*-------------------------------------------------------------------
* CD varieties of the functions: broken connections get registered
* in the connection structure within the query environment
* as side effects.
* -----------------------------------------------------------------*/
/* SK_cd_puts() */
/*++++++++++++++++++++++++++++++++++++++
This function writes a character string out to a socket.
int SK_qe_puts The total_count of bytes written,
or errors (represented as negative numbers)
sk_conn_st *condat connection data
char *str The buffer to be written from the socket.
More:
if the connection structure has bad status for this connection
from previous calls, no write will be attempted.
+html+ <PRE>
Authors:
marek
Side Effects:
broken connections get registered
in the connection structure within the query environment
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_cd_puts(sk_conn_st *condat, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
int res=SK_puts(condat->sock, str);
if( res < 0 ){
switch( - res ) {
/* dont know what to do and how to log */
case SK_DISCONNECT:
case SK_INTERRUPT:
/*("Thread received a control-c\n");*/
case SK_TIMEOUT:
/*("Reading timed out\n");*/
break;
default:
/* unexpected error code. bail out */
die;
}
}
} /* SK_cd_puts() */
/* SK_cd_gets() */
/*++++++++++++++++++++++++++++++++++++++
Wrapper around SK_gets.
int SK_qe_gets The total_count of bytes read,
or errors (represented as negative numbers)
sk_conn_st *condat connection data
char *str The buffer to be written from the socket.
More:
if the connection structure has bad status for this connection
from previous calls, no write will be attempted.
+html+ <PRE>
Authors:
marek
Side Effects:
broken connections get registered
in the connection structure within the query environment
+html+ </PRE>
++++++++++++++++++++++++++++++++++++++*/
int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
int res=SK_gets(condat->sock, str, count);
if( res < 0 ){
switch( res ) {
/* dont know what to do and how to log */
case SK_DISCONNECT:
case SK_INTERRUPT:
/*("Thread received a control-c\n");*/
case SK_TIMEOUT:
/*("Reading timed out\n");*/
break;
default:
/* unexpected error code. bail out */
die;
}
}
} /* SK_cd_gets() */
int SK_cd_close(sk_conn_st *condat) {
/* [<][>][^][v][top][bottom][index][help] */
SK_close(condat->sock);
} /* SK_cd_close() */