using select to waiting for data on a client socket - c

Any ideas why when the server writes a socket while the client is waiting on select, select never finishes?
I am using c to communicate between sockets. My client connects to my server fine.
socket_desc=socket(AF_INET,SOCK_STREAM,0);//create the socket descriptor
client->address.sin_addr.s_addr = inet_addr(ipAddress);
client->address.sin_family = AF_INET;
client->address.sin_port = htons(port);
bind(socket_desc,&address,sizeof(address));
connect(socket_desc, &address, sizeof(address));
When I use recv to block and listen for data, everything works fine:
int bytesRead = 1;
while(bytesRead){
int bufsize=1024;
char *buffer=malloc(bufsize);
bytesRead = recv(socket_desc, buffer, bufsize, 0);
printf("CLIENT RECV: %s", buffer);
}
If I try to use select, it doesn't seem to read any data. If I add STDIN to the fd_set, I can force it to read from the socket, but select doesn't seem to get triggered from the socket_desc reading in data...?
int running = 1;
while(running){
/* wait for something to happen on the socket */
struct timeval selTimeout;
selTimeout.tv_sec = 2; /* timeout (secs.) */
selTimeout.tv_usec = 0; /* 0 microseconds */
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(STDIN_FILENO, &readSet);//stdin manually trigger reading
FD_SET(socket_desc, &readSet);//tcp socket
int numReady = select(3, &readSet, NULL, NULL, &selTimeout);
//IT ONLY GETS PAST SELECT ON RETURN FROM THE KEYBOARD
if(numReady > 0){
char buffer[100] = {'\0'};
int bytesRead = read(socket_desc, &buffer, sizeof(buffer));
printf("bytesRead %i : %s", bytesRead, buffer);
if(bytesRead == 0){
running = FALSE;
printf("Shutdowning client.\n");
}
}

The first parameter to select should be the maximum socket id plus 1. So in your case, it should be
socket_desc+1
Can you try with that and see if it works?
The reason it only gets when you press a key on the keyboard is because stdin is 0, which would be within 0 - (3 - 1) range, which is what is checked. If you set the first parameter to socket_desc+1, then 0 - (socket_desc) range should be checked for ready sockets

Related

Use poll to distinguish connection from message

I'm trying to write a program which either reads from a socket or from stdin. If socket then print to stdout (to user), otherwise print to socket. So far I'm using poll to awake program when there's activity on either, my problem is that after the initial connection, poll always reports activity on the socket, even though client hasn't written anything else.
Is there any way to distinguish between "someone has connected to the socket" and "someone put a message on the channel"? Looking through man pages for poll, select and others I don't really see an appropriate flag.
If there is no appropriate flag, what would be a way to accomplish what I'm trying to do ?
What I currently have is something like below. When I enter something in stdin, poll returns and the loop determines the activity was on the socket (wrong).
edit: There's other issues at well but this is what I'm struggling with right now.
/* blocking accept for first and only connection */
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
/* poll stdin and newsockfd */
struct pollfd fds[2];
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[1].fd = newsockfd;
fds[1].events = POLLIN;
ioctl(newsockfd, FIONBIO, (char *)&on); /* int on = 1 */
while (1) {
int rc = poll(fds, 2, -1);
if (rc <= 0)
exit(1);
for (int i = 0; i < 2; i++) {
if (fds[i].revents == 0)
continue;
if (fds[i].revents != POLLIN)
exit(1);
if (fds[i].fd = newsockfd) {
n = read(newsockfd, buffer, 255);
printf("read %d chars from newsockfd: %s\n", n, buffer);
} else if (fds[i].fd = STDIN_FILENO) {
read(STDIN_FILENO, buffer, 255);
n = dprintf(newsockfd, "%s", buffer);
printf("wrote %d chars to newsockfd: %s\n", n, buffer);
}
}
}

Weird order after select() (with FD_SET())

I am developing a multi-client Unix Domain Socket to transfer data through multiple processes. I found some code that implements chat between every client and stuff but I want that once a client send something to the server, the server reply back and the client disconnect.
Having that said, I don't want while(fgets()) but I want (on client side):
int main() {
int sockfd;
struct sockaddr_un remote;
fd_set readfds;
char buf[1024];
char buf2[1024];
int len;
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
remote.sun_family = AF_UNIX;
strcpy(remote.sun_path, SOCK_PATH);
len = strlen(remote.sun_path) + sizeof(remote.sun_family);
if(connect(sockfd, (struct sockaddr*)&remote, len) == -1)
/* handle error */
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(sockfd, &readfds);
if(select(sockfd+1, &readfds, NULL, NULL, NULL) == -1)
/* handle error */
if(FD_ISSET(0, &readfds)) {
fgets(buf, 1024, stdin);
if(write(sockfd, buf, 1024) <= 0)
/* handle error */
}
if(FD_ISSET(sockfd, &readfds)) {
if(read(sockfd, &buf2, 1024) <= 0)
/* handle error */
}
printf("%s\n", buf2);
close(sockfd);
}
In this order, it works if I do everything after connect() twice (with a loop) but I want to do it only once. Without this loop, my server (which is a daemon) crash and I don't know why.
Furthermore, I added printf() from the code above to understand how it works:
(...)
printf("before select\n");
fflush(stdout);
if(select(sockfd+1, &readfds, NULL, NULL, NULL) == -1)
/* handle error */
printf("before select\n");
fflush(stdout);
if(FD_ISSET(0, &readfds)) {
fgets(buf, 1024, stdin);
if(write(sockfd, buf, 1024) <= 0)
/* handle error */
}
(...)
And I have this output:
before select
"input to fgets"
after select
And I don't understand why I have the input BEFORE "after select". It doesn't make any sense to me since I call fgets() after printf().
I hope this is understandable enough.
What's wrong with my code ? Did I miss something ?
The first time through, you call select() before the server has responded. The result is that sockfd won't be ready for reading.
In your case, the client might not need select() on the sockfd. You know that if you wrote something to the server you want to wait for the reply, right?

In C: Proxy HTTP requests to another server

I'm trying to proxy HTTP requests to another HTTP server. The hostname and port number of the upstream HTTP server, respectively, are server_proxy_hostname and server_proxy_port.
The first step is to do a DNS lookup of the server_proxy_hostname.
Secondly, I create a network socket and connet it to the IP address I got from DNS.
Last step: Wait for new data on both sockets. When data arrives, I immediately read it to a buffer and then write it to the other
socket. This maintains a 2-way communication between the HTTP client and
the upstream HTTP server.
If any of the socket is closed, I close the other one.
The problem right now is that it is not working. (It times out)
I believe that the way I'm getting my IP addresses is correct, so the problem has to be in either my while loop (it never terminates?) or the part where I called connect(). I tried adding error termination for read() and select() but that didn't work either.
void handle_proxy_request(int fd) {
char * targetHostName = server_proxy_hostname;
int targetPort = server_proxy_port;
struct hostent *info;
info = gethostbyname(targetHostName);
struct in_addr ** ipAddresslist;
ipAddresslist = (struct in_addr **) (info -> h_addr_list);
struct in_addr * ipAddress = ipAddresslist[0];
printf("ip address is %s\n", inet_ntoa(*ipAddress));
/*ip for in_addr struct*/
unsigned long ip = inet_addr(inet_ntoa(*ipAddress));
struct in_addr addressIp = {ip};
struct sockaddr_in address = {PF_INET, htons(targetPort), addressIp};
int socket_num = socket(PF_INET, SOCK_STREAM, 0);
connect(socket_num, (struct sockaddr *)&address, sizeof(address));
/*portion for select()*/
char buf[10000];
int nfds = (fd > socket_num)?fd:socket_num;
fd_set readSet;
fd_set writeSet;
while (1) {
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_SET(fd, &readSet);
FD_SET(socket_num, &readSet);
FD_SET(fd, &writeSet);
FD_SET(socket_num, &writeSet);
int selectReturn = select(nfds, &readSet, &writeSet, NULL, NULL);
if (selectReturn == -1){
break;
}
if(FD_ISSET(fd, &readSet)){
int readStat = read(fd, buf, sizeof(buf));
int status = write(socket_num, buf, sizeof(buf));
if (status == -1 || readStat == -1){
close(socket_num);
close(fd);
break;
}
/*memset(buf, 0, sizeof(buf));*/
}
if(FD_ISSET(socket_num, &readSet)){
int readStat2 = read(socket_num, buf, sizeof(buf));
int status2 = write(fd, buf, sizeof(buf));
if (status2 == -1 || readStat2 == -1){
close(socket_num);
close(fd);
break;
}
}
}
}
int socket_num = socket(PF_INET, SOCK_STREAM, 0);
Unchecked. Check this for errors.
connect(socket_num, (struct sockaddr *)&address, sizeof(address));
Ditto.
FD_SET(fd, &writeSet);
FD_SET(socket_num, &writeSet);
Remove. This is poor practice. Sockets are almost always ready to write, so you shouldn't use the writeSet unless you have previously encountered a case where a socket wasn't ready to write, i.e. write() returned -1 with errno == EAGAIN/EWOULDBLOCK.
int readStat = read(fd, buf, sizeof(buf));
int status = write(socket_num, buf, sizeof(buf));
That should be
int status = write(socket_num, buf, readStat);
in both socket cases.
and it should be preceded by tests for readStat == 0, indicating end of stream, and readStat == -1, indicating an error, which you should trace.
You can't get a timeout in this code, as you haven't set any.
There's a wrinkle. If you get end of stream reading a socket you should shutdown the other socket for output. If you get end of stream on a socket you've already shutdown for output, close them both. This correctly propagates FINs in both directions at the correct times.
When you get any error from any system call, you must immediately call perror() or log it with the result strerror(), before you call any other system calls.

C TCP Server doesn't send data before closing

I'm trying to set up a TCP connection between two Ubuntu computers.
The server is supposed to send single char-values to the client. The client is supposed to print these chars.
Establishing the connection between server and client seems to work just as expected but when I call send(), there is no output on the clientside.
The only way to achieve an output is by either sending the same char-value in an infinite loop, which leads to an infinite number of chars printed in the client's console, or by changing the if statement in the client's code (see code below) from if(len > 0) to if(len >= 0). In this case the sent chars will be printed correctly as soon as I close the server via CTRL + C, but it will also print the last transmitted char multiple times. So I'm not able to receive the values on clientside while the server is still running.
This is the server's code:
int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in adresse;
adresse.sin_family = AF_INET;
adresse.sin_addr.s_addr = INADDR_ANY;
adresse.sin_port = htons (2457);
bind ( serverSocket, (struct sockaddr *) &adresse, sizeof (adresse))
listen (serverSocket, 1);
while(1)
{
socklen_t adrlen = sizeof(struct sockaddr_in);
int conSocket= accept ( serverSocket, (struct sockaddr *) &adresse, &adrlen );
if(conSocket => 0)
{
char charToSend;
while(1)
{
charToSend = returnChar();
if(send(conSocket= , &charToSend, 1, 0) == -1)
{
printf("Error\n");
}
}
close(conSocket);
}
close(serverSocket);
}
This is the client's code:
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in adresse;
adresse.sin_family = AF_INET;
adresse.sin_port = htons (2457);
inet_aton ("192.168.2.101", &adresse.sin_addr);
if (connect ( clientSocket, (struct sockaddr *) &adresse, sizeof (adresse)) == 0)
{
while(1)
{
char recvd[2];
int len = recv(clientSocket, recvd, 1, 0);
recvd[1] = '\0';
if(len > 0)
{
printf("%s", recvd);
}
}
}
The function returnChar() in the server's code is used to process information from a sensor and returns a char value. It won't terminate before a complete signal has been processed and is running a loop in the meantime.
My only idea is that send() "doesn't have the time" to send out the values before the programm continues in another loop. Could this be the problem? Or did I do something wrong in the client's code?
In my opinion the problem is on the client side. You print the char with no line termination. Therefore everything is buffered in the client stdout stream. Please add '\n' to the printf as: printf("%s\n", recvd);
Actually, the problem is probably on the client side.
Make your client's output unbuffered:
setvbuf(stdout, NULL, _IONBF, (size_t)0);
or simply use unbuffered, rather than standard (buffered) I/O:
write(fileno(stdout), recvd, (size_t)1);
Although, since your traffic is 1-way, the suggestion to use TCP_NODELAY will help speed the sending a bit.

Select() blocking on stdin, will not time out

I am writing a program which receives UDP messages as well as takes input from users however my STDIN is still blocking with select. When I FD_CLR the stdin fd before select the program runs fine, indicating that the stdin socket is always ready to have data read from it. I tried introducing a timeval tv to time it out but this doesnt appear to be working either. Should I be closing the socket somewhere or calling FD_CLR where I am not?
The end result should be a non blocking STDIN but currently it blocks.
Thank You
int
wait_for_input(){
fd_set fds;
int maxfd, sd, err, n;
struct sockaddr_in addr;
char stdbuf[BUFLEN];
unsigned char udpbuf[BUFLEN];
//memset(stdbuf,0x0,sizeof(stdbuf));
memset(stdbuf,0x0,sizeof(udpbuf));
sd = socket(AF_INET, SOCK_DGRAM, 0);
if(sd<0) {
printf("Failed to Open UDP socket");
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(host_list[0]->port);
err = bind(sd,(struct sockaddr *) &addr,sizeof(addr));
if(err < 0){
printf("ERROR: Cant bind port");
}
struct timeval tv;
while(1){
FD_ZERO(&fds);
FD_SET(STDIN_FILENO,&fds);
FD_SET(sd,&fds);
tv.tv_sec = 1;
tv.tv_usec = 0;
fflush(stdout);
select(sd+1,&fds,NULL,NULL,&tv);
// If a UDP message arrives
if(FD_ISSET(sd,&fds)){
n = recv(sd,udpbuf,sizeof(udpbuf),0);
unpack(udpbuf);
recompute_my_dv();
fflush(stdout);
}
//If console data is entered.
if(FD_ISSET(STDIN_FILENO, &fds)){
fgets(stdbuf,sizeof(stdbuf),stdin);
parse(stdbuf);
printf("server> ");
fflush(stdout);
FD_CLR(STDIN_FILENO,&fds);
}
}
return 0;
}
FD_ISSET doesn't return 1 (or true) if you have a message on that socket's buffer, it returns true if the given file descriptor is part of the file descriptor set. That's one problem.
The next is that your loop should start (the while loop that is) should begin before the select statment and loop back to that. You should capture the value returned by the select. This is because select returns how many bits are in the buffer you specified in argument 2 of select (read, write, or error). So if you specified read as the buffer, you will want to read how ever many bits was returned by select.
I think those are the 2 main problems. Hope this helps.

Resources