| ************************ tcpserv.c **********************************
alain.marchi> cat tcpserv.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#define BUFS 128
char buf[BUFS];
main(int argc, char * argv[])
{
int lsock, sock;
struct sockaddr_in lsockaddr, peeraddr;
int peeraddrlen;
int backlog = 1;
int remport;
int l;
if (argc != 2 )
{
fprintf(stderr, "Usage: %s port\n", argv[0]);
exit(1);
}
remport = atoi(argv[1]);
if ( ( lsock = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
abort("Socket");
bzero(&lsockaddr, sizeof(lsockaddr));
lsockaddr.sin_family = AF_INET;
lsockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
lsockaddr.sin_port = htons(remport);
if ( bind(lsock, &lsockaddr, sizeof(lsockaddr)) < 0 )
abort("Bind");
if ( listen(lsock, backlog) < 0 )
abort("Listen");
if ( ( sock = accept(lsock, &peeraddr, &peeraddrlen) ) < 0 )
abort("Accept");
if (close(lsock) < 0)
abort("Close listen socket");
if ( shutdown(sock,1) < 0 )
abort("Shutdown for write");
while ( (l = read(sock,buf,BUFS)) > 0 )
{
#if 0
printf("%d\n", l);
fflush(stdout);
#endif
}
if ( l < 0 )
abort("Read");
if (close(sock) < 0)
abort("Close peer socket");
}
abort(char * txt)
{
perror(txt);
exit(1);
}
*************************** tcpcon.c ******************************
alain.marchi> cat tcpcon.c
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
char * argv0;
#define BUFS 8192
char buf[BUFS];
main(argc, argv)
int argc;
char * argv [];
{
fd_set writefds;
int nfds;
int sockfd;
struct sockaddr_in serv_addr;
struct hostent * hstp;
int openforread;
int openforwrite;
char * remhost;
int s;
argv0 = argv[0];
if ( argc != 3 || ! isdigit(argv[2][0]))
{
fprintf ( stderr, "usage: %s host port\n", argv0);
exit(1);
}
remhost = argv[1];
if ( ( hstp = gethostbyname(remhost)) == NULL )
panic("cannot gethostbyname", remhost);
bzero((char *) & serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *((unsigned long *)*(hstp->h_addr_list));
serv_addr.sin_port = htons(atoi(argv[2]));
if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
abort("Socket");
if ( connect(sockfd, (struct sockaddr *) &serv_addr, sizeof
(serv_addr)) < 0 )
abort("Connect");
if ( shutdown(sockfd,0) < 0 )
abort("Shutdown for read");
nfds = getdtablesize();
if ( nfds > FD_SETSIZE ) nfds = FD_SETSIZE;
while (1)
{
FD_ZERO(&writefds);
FD_SET(sockfd,&writefds);
if ( select(nfds, NULL, &writefds, NULL, NULL) != 1 )
abort("Select");
if ( write(sockfd, buf, BUFS) != BUFS )
abort("Write");
printf("%d\n", BUFS);
fflush(stdout);
}
}
panic(m1, m2)
char * m1, * m2;
{
fprintf(stderr, "%s: %s: %s\n", argv0, m1, m2);
exit(1);
}
abort(char * txt)
{
perror(txt);
exit(1);
}
**************************************************************************
|
| Alain, as nobody answers, my 2 cent
for me it looks too like a bug. the program hangs in do_scan, but
the problem happened in my understanding earlier (soo_select which is
called by selscan). but it's hard to trace, so I would issue a QAR
and let some knowledgable look into the flag settings.
a quick and by no mean comprehensive test showed that the poll
interface works better, so if possible try some more extensive tests
and ask the customer if it's possible to replace select by poll
here's you're client example used with poll on sockfd, server unchanged
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <time.h>
char * argv0;
#define BUFS 8192
char buf[BUFS];
main(argc, argv)
int argc;
char * argv [];
{
int nfds;
struct pollfd pfd[1];
int sockfd;
struct sockaddr_in serv_addr;
struct hostent * hstp;
int openforread;
int openforwrite;
char * remhost;
int s;
argv0 = argv[0];
if ( argc != 3 || ! isdigit(argv[2][0]))
{
fprintf ( stderr, "usage: %s host port\n", argv0);
exit(1);
}
remhost = argv[1];
if ( ( hstp = gethostbyname(remhost)) == NULL )
panic("cannot gethostbyname", remhost);
bzero((char *) & serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = *((unsigned long *)*(hstp->h_addr_list));
serv_addr.sin_port = htons(atoi(argv[2]));
if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
abort("Socket");
if ( connect(sockfd, (struct sockaddr *) &serv_addr, sizeof
(serv_addr)) < 0 ) abort("Connect");
if ( shutdown(sockfd,0) < 0 )
abort("Shutdown for read");
nfds = getdtablesize();
if ( nfds > FD_SETSIZE ) nfds = FD_SETSIZE;
pfd[0].fd = sockfd;
pfd[0].events = POLLHUP;
while (1)
{
/******
FD_ZERO(&writefds);
FD_SET(sockfd,&writefds);
if ( select(nfds, NULL, &writefds, NULL, NULL) != 1 )
abort("Select");
*******/
if (poll(pfd, 1, -1) < 0)
abort("Poll");
if ( write(sockfd, buf, BUFS) != BUFS )
abort("Write");
printf("%d\n", BUFS);
fflush(stdout);
}
}
you will see some delay in the client output due to the fact that the
server reads in the small fragments, but as I understood, thi sis what
you wanted to achieve.
Pit
|
| I wonder if
if ( select(nfds, NULL, &writefds, NULL, NULL) != 1 )
should be
if ( select(nfds+1, NULL, &writefds, NULL, NULL) != 1 )
|
| > I wonder if
> if ( select(nfds, NULL, &writefds, NULL, NULL) != 1 )
> should be
> if ( select(nfds+1, NULL, &writefds, NULL, NULL) != 1 )
nope, not in this case. if they had been using:
select(socketnumber, ....)
then it would need the +1, but nfds is correct, and nfds+1
is incorrect and could result in an EFAULT since the kernel
may try to read more than the size of fd_set.
I'm not sure why they aren't using "socketnumber+1" since
they appear to be trying to optimize in the case where
the actual size of the fd table is smaller than FD_SETSIZE
(vs. just using select(FD_SETSIZE, ....))
note that ideally you should dynamically allocate (ie malloc)
fd_set based on the number of actual file descriptors because
it's possible that FD_SETSIZE may be too *small*, especially
when built on one version of the OS and then run on a latter
version.
|