9c6e1c9230
git-svn-id: file:///home/ps/projects/distributor/trunk@3 4c72226d-0938-4c61-bee9-4ad40ed711b9
205 lines
5.2 KiB
C
205 lines
5.2 KiB
C
/**
|
|
* Copyright (C) 2007 Juan José Gutiérrez de Quevedo <juanjo@iteisa.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* @author Juan José Gutiérrez de Quevedo <juanjo@gutierrezdequevedo.com>
|
|
*/
|
|
#include "utils.h"
|
|
|
|
extern unsigned long connid;
|
|
char m_buffer[4096]={0};
|
|
|
|
/**
|
|
* reads a string as safely as possible.
|
|
*
|
|
* it will read one byte at a time until a '\\n' is read.
|
|
* we store one char at a time in a static buffer, and when
|
|
* we find a '\\n', we do an strndup of the buffer.
|
|
* it might be possible in this special case to just use
|
|
* a static buffer, return a pointer to it and never assign
|
|
* any memory with strndup or in any other way.
|
|
*
|
|
* @param fd fd to read from
|
|
*
|
|
* @return a pointer to the read string
|
|
*/
|
|
char *read_string(int fd)
|
|
{
|
|
char chr;
|
|
char *buffer=NULL,*tmpbuf=NULL;
|
|
unsigned long strsize=0;
|
|
unsigned long allocsize=0;
|
|
|
|
assert(fd>=0);
|
|
/* read one byte at a time */
|
|
while(1)
|
|
{
|
|
if(1!=recv(fd,&chr,1,MSG_NOSIGNAL))
|
|
break;
|
|
|
|
if(0==allocsize||allocsize<strsize+2)
|
|
{
|
|
allocsize=MAX(allocsize+512,strsize+2);
|
|
if(NULL==(tmpbuf=realloc(buffer,allocsize)))
|
|
{
|
|
debug("Error reserving memory");
|
|
condfree(buffer);
|
|
break;
|
|
}
|
|
else
|
|
buffer=tmpbuf;
|
|
}
|
|
if(10==chr) break;
|
|
if(13!=chr)
|
|
buffer[strsize++]=chr;
|
|
}
|
|
|
|
if(NULL==buffer) return NULL;
|
|
|
|
/* finalize string */
|
|
buffer[strsize]='\0';
|
|
|
|
snprintf(m_buffer,sizeof(m_buffer),"r>%s",buffer);
|
|
debug(m_buffer);
|
|
|
|
/* return a new string with new mem */
|
|
return buffer;
|
|
}
|
|
|
|
/**
|
|
* create a new listening socket.
|
|
*
|
|
* with following options:
|
|
* - SO_REUSEADDR
|
|
* - INADDR_ANY
|
|
*
|
|
* @param port the port to listen on
|
|
*
|
|
* @return the new socket fd
|
|
*/
|
|
int create_listening_socket(unsigned int port)
|
|
{
|
|
int fd_server;
|
|
struct sockaddr_in address;
|
|
int i;
|
|
|
|
/* create socket */
|
|
if(-1==(fd_server=socket(PF_INET,SOCK_STREAM,0))) { perror("Error creating socket"); return -1; }
|
|
|
|
/* set option for the socket: SO_REUSEADDR (will reuse address between invocations of the same program) */
|
|
i=1;
|
|
if(-1==setsockopt(fd_server,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(i))) { perror("Error configuring socket reuse"); closeskt(fd_server); return -1; }
|
|
|
|
/* bind to address :ANY */
|
|
address.sin_family=AF_INET;
|
|
address.sin_addr.s_addr=INADDR_ANY;
|
|
address.sin_port=htons(port);
|
|
|
|
if(-1==bind(fd_server,(struct sockaddr *)&address,sizeof(address))) { perror("Error binding to address"); closeskt(fd_server); return -1; }
|
|
|
|
/* listen on socket */
|
|
if(-1==listen(fd_server,10)) { perror("Error listening on socket"); closeskt(fd_server); return -1; }
|
|
snprintf(m_buffer,sizeof(m_buffer),"Listening on 0.0.0.0:%d",port);
|
|
debug(m_buffer);
|
|
|
|
return fd_server;
|
|
}
|
|
|
|
/**
|
|
* create a socket that is connected to an address.
|
|
*
|
|
* @param address address to connect to
|
|
* @param port port to connect to
|
|
*
|
|
* @return fd of the opened connection
|
|
*/
|
|
int create_connected_socket(char *address,unsigned int port)
|
|
{
|
|
int fd;
|
|
struct sockaddr_in addr;
|
|
|
|
/* create socket */
|
|
if(-1==(fd=socket(PF_INET,SOCK_STREAM,0))) { perror("Error creating socket"); return -1; }
|
|
|
|
/* fill address structure */
|
|
addr.sin_family=AF_INET;
|
|
addr.sin_addr.s_addr=resolve(address);
|
|
addr.sin_port=htons(port);
|
|
|
|
if(0==addr.sin_addr.s_addr) return -1; /* error resolving name */
|
|
/* connect to remote host */
|
|
snprintf(m_buffer,sizeof(m_buffer),"Connecting to %s:%d",address,port);
|
|
debug(m_buffer);
|
|
if(-1==connect(fd,(struct sockaddr *)&addr,sizeof(addr))) { perror("Error connecting to host"); return -1; }
|
|
|
|
return fd;
|
|
}
|
|
|
|
unsigned long resolve(char *address)
|
|
{
|
|
struct hostent *resolved;
|
|
struct in_addr addr;
|
|
|
|
if(NULL==(resolved=gethostbyname(address))) { perror("Error resolving"); return 0; }
|
|
|
|
memcpy(&addr,resolved->h_addr,sizeof(addr));
|
|
|
|
return addr.s_addr;
|
|
}
|
|
|
|
/**
|
|
* whether a fd does have data waiting or not.
|
|
*
|
|
* @param fd array of fd to ask
|
|
* @param nfd number of fds
|
|
* @param time time to wait for data
|
|
*
|
|
* @return 1 on data waiting to be read, else return 0
|
|
*/
|
|
unsigned char can_read(int *fd,int nfd,float time)
|
|
{
|
|
fd_set rfd;
|
|
struct timeval timeout;
|
|
int maxfd=0,i;
|
|
|
|
assert(fd>=0);
|
|
|
|
/* configure timeout */
|
|
timeout.tv_sec=(int)time;
|
|
timeout.tv_usec=(time-(int)time)*1000000;
|
|
|
|
/* configure rfd */
|
|
FD_ZERO(&rfd);
|
|
for(i=0;i<nfd;i++)
|
|
{
|
|
FD_SET(fd[i],&rfd);
|
|
maxfd=MAX(maxfd,fd[i]);
|
|
}
|
|
|
|
return (select(maxfd+1,&rfd,NULL,NULL,time<0?NULL:&timeout)>0)?1:0;
|
|
}
|
|
|
|
/**
|
|
* check whether fd is at eof
|
|
* @param fd socket to check
|
|
*
|
|
* @return true on eof, false otherwise
|
|
*/
|
|
unsigned char socketeof(int fd)
|
|
{
|
|
unsigned char buffer;
|
|
return 0==recv(fd,&buffer,1,MSG_PEEK|MSG_DONTWAIT);
|
|
}
|