I am running into some problem with my server. I am trying to reading inputs from multiple clients but I can only do it one at a time. I think my server's code does not have an issue. So I assume that my local clients are the ones that are actually at fault here. Are each clients exactly the same as the other if I want to handle multiple clients with different sockets. or are they different in some ways?
What do you guys think?
Server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <stdlib.h>
//char *socket_path = "./socket";
char *socket_path = "\0hidden";
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
//max client sockets
int max_sd, sd, i, client_socket[3], activity;
char buf[100];
int fd,cl,rc;
fd_set readfds;
if (argc > 3) socket_path=argv[3];
//establish socket
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
//establish socket name
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
unlink(socket_path);
//bind socket
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(-1);
}
//listen to the socket
if (listen(fd, 5) == -1) {
perror("listen error");
exit(-1);
}
while (1) {
//clear the scoket set
FD_ZERO(&readfds);
//add fd socket to set
FD_SET(fd, &readfds);
max_sd = fd;
//add child sockets to the set
for(i = 0; i < 3; i++) {
sd = client_socket[i];
if(sd > 0) {
FD_SET( sd, &readfds);
}
if(sd > max_sd) {
max_sd = sd;
}
}
//wait for an activity from a socket
activity = select(max_sd + 1, &readfds,NULL, NULL,NULL);
if((activity < 0) && (errno!=EINTR)) {
printf("select");
}
if(FD_ISSET(fd, &readfds)) {
if ( (cl = accept(fd, NULL, NULL)) == -1) {
perror("accept error");
continue;
}
while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
}
if (rc == -1) {
perror("read");
exit(-1);
}
else if (rc == 0) {
printf("EOF\n");
close(cl);
}
}
}
return 0;
}
What?
//wait for an activity from a socket
activity = select(max_sd + 1, &readfds,NULL, NULL,NULL);
if((activity < 0) && (errno!=EINTR)) {
printf("select");
}
if(FD_ISSET(fd, &readfds)) {
if ( (cl = accept(fd, NULL, NULL)) == -1) {
Accepting a connection...
perror("accept error");
continue;
}
while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
}
Blocking read until there is no error... (with incorrect printf)
if (rc == -1) {
perror("read");
exit(-1);
}
else if (rc == 0) {
printf("EOF\n");
close(cl);
}
Incorrect, but assuming no real errors means reading till the other party closes their side.
With this in mind, how was this supposed to support several clients at once?
Read this: http://www.kegel.com/c10k.html
I don't know how sockets work in C, but I've been working on some Java programs, and the solution to your problem, in java, is to provide a separate thread on the server for each client. Each time a client connects to the server, you start a thread that will serve that client. A fork will help maybe.
Related
I am using raw sockets for the first time, so excuse me if my question exhibits serious lack of knowledge in this field.
My goal is to make a client-server program using raw sockets where client can send a string to server and server can send a reply. My codes are as follows:
/* server.c */
#include "../cn.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char const *argv[]) {
int sfd = socket(AF_INET, SOCK_RAW, 253);
if (sfd < 0) {
perror("Could not create socket");
exit(0);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Could not bind");
}
int nsfd = accept(sfd, NULL, NULL);
if (nsfd < 0) {
perror("Could not accept");
exit(0);
}
char buffer[20];
int sz;
while (1) {
if ((sz = read(nsfd, buffer, 20)) < 0) {
perror("Could not read");
} else {
buffer[sz] = '\0';
strcat(buffer, " form server");
if (write(nsfd, buffer, strlen(buffer)) < 0) {
perror("Could not send");
}
}
}
return 0;
}
Client code:
#include "../cn.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main(int argc, char const *argv[]) {
int sfd = socket(AF_INET, SOCK_RAW, 253);
if (sfd < 0) {
perror("Could not create socket");
exit(0);
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Could not connect");
exit(0);
}
char buffer[20];
int sz;
while (1) {
scanf("%[^\n]s", buffer);
while (getchar() != '\n')
;
if (write(sfd, buffer, strlen(buffer)) < 0) {
perror("Could not write");
} else
if ((sz = read(sfd,buffer, 20)) < 0) {
perror("Could not read");
} else {
buffer[sz] = '\0';
printf("Reading: %s\n", buffer);
}
}
return 0;
}
Whenever I am trying to run the programs , it is showing error at the very time of socket creation itself:
Could not create socket: Operation not permitted
My questions are:
What am I missing in this case? Why does is this operation not permitted?
Though it is a broad question but, how to use raw sockets with custom protocol ID?
Is there any good material available for use of raw sockets with custom protocol?
I'm playing around with epoll on Linux for the first time and see some strange behavior. Specificall, when I connect with a client to a socket, I see two events emitted by epoll_wait on the server side. When I call accept on the second attempt I get a "temporary unavailable" error.
Here's the simple client code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const char* msg = "friendly ping";
int main(int argc, char** argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <socket>\n", argv[0]);
exit(-1);
}
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket");
exit(-1);
}
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("Error connecting");
exit(-1);
}
write(sock, msg, strlen(msg));
close(sock);
return 0;
}
The server code is the following:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
const int kMaxEvents = 100;
const char *kSocketFile = "dummy_socket";
void MakeNonBlocking(int fd) {
int flags, s;
flags = fcntl (fd, F_GETFL, 0);
if (flags == -1) {
perror ("fcntl");
exit(-1);
}
flags |= O_NONBLOCK;
s = fcntl (fd, F_SETFL, flags);
if (s == -1) {
perror ("fcntl");
exit(-1);
}
}
void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.data.fd = sock;
event.events = EPOLLIN;
int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}
MakeNonBlocking(insock);
int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}
int main(void) {
int sock, efd, n;
struct sockaddr_un addr;
struct epoll_event event;
struct epoll_event *events;
char buf[1024];
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("Error creating socket.");
exit(-1);
}
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, kSocketFile, sizeof(addr.sun_path) - 1);
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("Error binding name to socket");
exit(-1);
}
if (listen(sock, SOMAXCONN) < 0) {
perror("Error listening on socket");
exit(-1);
}
MakeNonBlocking(sock);
if ((efd = epoll_create1(0)) < 0) {
perror("Epoll initialization error");
exit(-1);
}
event.data.fd = sock;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &event) < 0) {
perror("Epoll error adding socket");
exit(-1);
}
events = (struct epoll_event*) calloc(kMaxEvents, sizeof(event));
if (!events) {
perror("Error allocating event buffers");
exit(-1);
}
while(1) {
printf("Calling epoll_wait\n");
if ((n = epoll_wait(efd, events, kMaxEvents, -1)) == -1) {
perror("epoll_wait failure");
exit(-1);
}
for (int i = 0; i < n; ++i) {
printf("Checking event for fd = %d\n", events[i].data.fd);
if (sock == events[i].data.fd) {
AcceptConnections(sock, efd);
continue;
}
int count = read(events[i].data.fd, buf, 100);
if (count == 0) {
close(events[i].data.fd);
}
write(1, buf, count);
}
}
free(events);
close(efd);
close(sock);
unlink(kSocketFile);
return 0;
}
When I run the server and connect to the client I get:
Calling epoll_wait
Checking event for fd = 3
Connection processed.
Calling epoll_wait
Checking event for fd = 3
Error accepting connection: Resource temporarily unavailable
In other words, I see two events on the listening socket. Any ideas?
To fix, change AcceptConnections to:
void AcceptConnections(int sock, int epoll_fd) {
struct epoll_event event;
event.events = EPOLLIN;
int insock = accept(sock, NULL, NULL);
if (insock < 0) {
perror("Error accepting connection");
exit(-1);
}
// This is the important change.
event.data.fd = insock;
MakeNonBlocking(insock);
int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event);
if (s < 0) {
perror("Epoll error adding accepted connection");
exit(-1);
}
printf("Connection processed.\n");
}
epoll is sometimes funny...
The issue is with the way you register the event in AcceptConnections.
epoll accepts two different fd values, one in event.data.fd (user opaque data value) and the other in the beginning of the epoll_ctl function call (the fd controlling the event).
The event.data.fd can be anything, and it's the actual data you read in your event loop...
... in your original code, you set it to the listening socket instead of the client socket.
So, when the client socket has data ready to be read, an event is raised with event.data.fd pointing at the listening socket instead of the client socket.
Since you don't clear the event (for the client socket), it's repeatedly raised with the data you set (the listening socket fd).
Good Luck!
I am trying to make a server.c file that supports 3 sockets, which are represented by 3 respective client classes: client1, client2, client3.
In my server.c file, I currently have this code which I found on the internet.
If I wanted to make it have 3 sockets. I want to use the select() command to see the write activities of the 3 clients. My question is how can I use this to support 3 sockets.
Can I bind the 3 clients to 3 sockets that the server can listen to? If so, how can the server listen to these 3 sockets respectively? With an array possibly?
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#define socket1 "sock1"
#define socket2 "sock2"
#define socket3 "sock3"
int main(int argc, char *argv[]) {
//struct sockaddr_un addr;
struct sockaddr_un addr1;
struct sockaddr_un addr2;
struct sockaddr_un addr3;
char buf[100];
int socket1;
int socket2;
int socket3;
//int fd;
int cl,rc;
if (argc > 1) socket_path=argv[1];
if ( (socket1 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr1, 0, sizeof(addr1));
addr1.sun_family = AF_UNIX;
strncpy(addr1.sun_path, socket_path, sizeof(addr1.sun_path)-1);
unlink(socket_path1);
if ( (socket2 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr2, 0, sizeof(addr2));
addr1.sun_family = AF_UNIX;
strncpy(addr2.sun_path, socket_path, sizeof(addr2.sun_path)-1);
unlink(socket_path2);
if ( (socket3 = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr3, 0, sizeof(addr3));
addr3.sun_family = AF_UNIX;
strncpy(addr3.sun_path, socket_path, sizeof(addr3.sun_path)-1);
unlink(socket_path3);
if (bind(socket1, (struct sockaddr*)&addr1, sizeof(addr1)) == -1) {
perror("bind error");
exit(-1);
}
if (bind(socket2, (struct sockaddr*)&addr2, sizeof(addr2)) == -1) {
perror("bind error");
exit(-1);
}
if (bind(socket3, (struct sockaddr*)&addr3, sizeof(addr3)) == -1) {
perror("bind error");
exit(-1);
}
if (listen(socket1, 5) == -1) {
perror("listen error");
exit(-1);
}
if (listen(socket2, 5) == -1) {
perror("listen error");
exit(-1);
}
if (listen(socket3, 5) == -1) {
perror("listen error");
exit(-1);
}
while (1) {
if ( (cl = accept(fd, NULL, NULL)) == -1) {
perror("accept error");
continue;
}
while ( (rc=read(cl,buf,sizeof(buf))) > 0) {
printf("read %u bytes: %.*s\n", rc, rc, buf);
}
if (rc == -1) {
perror("read");
exit(-1);
}
else if (rc == 0) {
printf("EOF\n");
close(cl);
}
}
return 0;
}
If you want three listening sockets in the same process, you have to make them unique. In the AF_INET family you do that by bind(2)-ing different ports, in the AF_UNIX family you do that with different paths.
Also your line:
char *socket_path = "\0hidden";
has at least two problems:
Type of the string literal on the right side of the assignment is const char[8], which decays to const char* pointer type, but not char* type. Make the left hand side const char*. Plus, compile with higher warning level, like -Wall -pedantic to get help from your compiler.
Zero byte at the beginning of the string makes strncpy(3) not copy anything, since it copies at most n characters from the string pointed to by src, including the terminating null byte ('\0').
Create a function that take UNIX path as an argument and creates, binds, and marks socket as listening, and returns created socket descriptor. Call it three times - you have three listening UNIX sockets. Setup select(2) on them for reading - that'll tell you when client connections arrive. At that point call accept(2) on the active socket to get connected client socket, which is separate from the listening socket itself.
Ok, since select, is and has always been my favorite Unix syscall, I decided to do a little something, which is, in my humble opinion, what you were looking for.
I shamelessly took server's and client's code from here:
https://troydhanson.github.io/misc/Unix_domain_sockets.html
I did of course some little modifications, to make it fit your needs, lets see:
server.c:
#include <stdio.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
char *socket_path = "/tmp/socket";
int main() {
int fd, i;
int clients[10], num_clients;
fd_set read_set;
char buf[100];
struct sockaddr_un addr;
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
unlink(socket_path);
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(-1);
}
if (listen(fd, 5) == -1) {
perror("listen error");
exit(-1);
}
num_clients = 0;
while (1) {
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
for (i = 0; i < num_clients; i++) {
FD_SET(clients[i], &read_set);
}
select(fd + num_clients + 1, &read_set, NULL, NULL, NULL);
if (FD_ISSET(fd, &read_set)) {
if ( (clients[num_clients++] = accept(fd, NULL, NULL)) == -1) {
perror("accept error");
continue;
}
printf("we got a connection!\n");
}
for (i = 0; i < num_clients; i++) {
if (FD_ISSET(clients[i], &read_set)) {
read(clients[i], buf, sizeof(buf));
printf("client %d says: %s\n", i, buf);
}
}
}
}
client.c:
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
char *socket_path = "/tmp/socket";
int main(int argc, char *argv[]) {
struct sockaddr_un addr;
char buf[100];
int fd,rc;
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("connect error");
exit(-1);
}
while( (rc=read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
printf("writing\n");
*index(buf, '\n') = 0;
if (write(fd, buf, rc) != rc) {
if (rc > 0) fprintf(stderr,"partial write");
else {
perror("write error");
exit(-1);
}
}
}
return 0;
}
Ok, this works very easily, you just fire the server in one terminal, and then you open a couple other terminals and fire a couple clients.
Running it on my pc I get:
exe#atreides:~/tmp$ ./server
we got a connection!
client 0 says: Hello!
we got a connection!
client 1 says: Hey man!
Another terminal at the same time:
exe#atreides:~/tmp$ ./client
Hey man!
writing
And in another:
exe#atreides:~/tmp$ ./client
Hello!
writing
The magic behind all this is to properly use socket and select.
First you need a server socket, the one that will accept connections.
Once you bind to a server socket, let it be a Unix socket or a network socket, you can get sockets to your clients by accepting connections on that socket. Each client gets a new socket number.
Then, you add these sockets, the server socket and the clients socket to an fd_set and pass it to select. Select will listen on all sockets at the same time and will leave in the set those who have received data.
Now you iterate the set to see what sockets are hot and, you're there!
One more thing, which I guess was confusing you, all clients connect to the same server socket address (file). Yes it is like if many processes opened the same file, at the same time... But this isn't an ordinary file, it is a Unix socket. :)
Have fun and good luck!!!
Hello i made this code to open a socket and make a thread to send data so the socket
int is_valid_fd(int fd)
{
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}
int main(int Count, char *Strings[])
{
pfd.events = POLLIN;
pfd.revents = 0;
/*---Create streaming socket---*/
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
perror("Socket");
exit(errno);
}
/*---Initialize address/port structure---*/
bzero(&self, sizeof(self));
self.sin_family = AF_INET;
self.sin_port = htons(MY_PORT);
self.sin_addr.s_addr = INADDR_ANY;
/*---Assign a port number to the socket---*/
if ( bind(sockfd, (struct sockaddr*)&self, sizeof(self)) != 0 )
{
perror("socket--bind");
exit(errno);
}
/*---Make it a "listening socket"---*/
if ( listen(sockfd, 20) != 0 )
{
perror("socket--listen");
exit(errno);
}
err = pthread_create(&(tid), NULL, &thread_accept, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
/*---Forever... ---*/
while(1){
if(0<poll(&pfd,1,100)){
if(pfd.revents & POLLIN){
run = read(pfd.fd, &t,1);
}
}
if(run){
if(is_valid_fd(clientfd))send(clientfd, "12 ",3,0);
/*---Close data connection---*/
}
printf("hejsa\n");
fflush(stdout);
sleep(1);
}
/*---Clean up (should never get here!)---*/
close(sockfd);
return 0;
}
void* thread_accept(){
while (1){
/*---accept a connection (creating a data pipe)---*/
clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen);
pfd.fd=clientfd;
printf("%s:%d, connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
run=1;
/*---Echo back anything sent---*/
send(clientfd, buffer, recv(clientfd, buffer, MAXBUF, 0), 0);
//close(clientfd);
}
}
My problem is then, that when i close the socket connection, the program shuts down instead of just closing the socket and keep printf("hejsa\n)
I don't see where you break the while loop?
you should also protect your shared data with mutex or something.
I have a short example that do something similar(but in different way) here
I am learning how to program a Server TCP socket wherein clients can connect to and wait for commands...
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
do {
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
I just get the part of the code where I'm having problem. I'm reading from a pipe. I'm using that to send messages to the client.. but my problem is with recv. it waits for data sent by client before it sends the data read from my pipe to the client. What i want to happen is everytime i send a data to my pipe it goes directly to the client without waiting for recv.. How can this be done?
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#define TRUE 1
#define FALSE 0
typedef struct SERVER_FD{
int sPort;
int serverFD;
int smaxFD;
int newFD;
}sSD;
int cFD,
dSize,
err,
start = 1,
state,
DescRead,
DCSERVER = FALSE;
struct sockaddr_in addr, cli_addr;
unsigned long ip;
char strbuf[256];
socklen_t clilen;
fd_set fdin, fduse;
pid_t pid, sid;
int fd=-1;
int nbytes;
char buffer[256];
void process(int ServerFD, int Port, int sMax, int NewSFD);
void cleanUP(int i, int max);
void dlogs(unsigned long ip);
void daemonize();
main (int argc, char *argv[])
{
sSD link;
sSD *sCon;
sCon = &link;
sCon->sPort = 53234;
fd = open("/tmp/myFIFO", O_RDWR);
if(fd<0){
perror("open() error");
exit(1);
}
printf("Starting Server-G\n");
fcntl(fd, F_SETFL,
fcntl(fd, F_GETFL) | O_NONBLOCK);
sCon->serverFD = socket(AF_INET, SOCK_STREAM, 0);
if (sCon->serverFD != -1) {
err = setsockopt(sCon->serverFD, SOL_SOCKET, SO_REUSEADDR,(char *)&start, sizeof(start));
if (err != -1) {
err = ioctl(sCon->serverFD, FIONBIO, (char *)&start);
if (err != -1){
process(sCon->serverFD,sCon->sPort,sCon->smaxFD,sCon->newFD);
}
else{
perror("ioctl() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("setsockopt() failed");
close(sCon->serverFD);
exit(EXIT_FAILURE);
}
}
else{
perror("FAILED CONNECTING TO SOCKET");
exit(EXIT_FAILURE);
}
}
void process(int ServerFD, int Port, int sMax, int NewSFD){
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = 0;
addr.sin_port = htons(Port);
err = bind(ServerFD,(struct sockaddr *)&addr, sizeof(addr));
if (err < 0) {
perror("bind() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
daemonize();
err = listen(ServerFD, 32);
if (err < 0) {
perror("listen() failed");
close(ServerFD);
exit(EXIT_FAILURE);
}
clilen = sizeof(cli_addr);
FD_ZERO(&fdin);
sMax = ServerFD;
FD_SET(ServerFD, &fdin);
do {
fduse = fdin;
err = select(sMax + 1, &fduse, NULL, NULL, NULL);
if (err < 0) {
perror(" select() failed");
break;
}
DescRead = err;
for (cFD=0; cFD <= sMax && DescRead > 0; ++cFD) {
if (FD_ISSET(cFD, &fduse)) {
DescRead -= 1;
if (cFD == ServerFD) {
do {
NewSFD = accept(ServerFD,(struct sockaddr *) &cli_addr, &clilen);
if (NewSFD < 0) {
if (errno != EWOULDBLOCK) {
perror(" accept() failed");
DCSERVER = TRUE;
}
break;
}
ip = ntohl(cli_addr.sin_addr.s_addr);
printf(" Connection from %d.%d.%d.%d\n",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
dlogs(ip);
FD_SET(NewSFD, &fdin);
if (NewSFD > sMax)
sMax = NewSFD;
} while (NewSFD != -1);
}
else {
state = FALSE;
do {
//PART WHERE I'm Having problems.
err = recv(cFD, strbuf, sizeof(strbuf), 0);
if (err < 0) {
if (errno != EWOULDBLOCK) {
perror(" recv() failed");
state = TRUE;
}
break;
}
if (err == 0) {
printf(" Connection closed\n");
state = TRUE;
break;
}
dSize = err;
printf(" %d bytes received\n", dSize);
while ((nbytes = read(fd, buffer, sizeof(buffer)-1)) > 0) {
buffer[nbytes] = '\0';
printf("%s\n", buffer);
}
err = send(cFD, buffer, strlen(buffer), 0);
if (err < 0) {
perror(" send() failed");
state = TRUE;
break;
}
} while (TRUE);
if (state) {
close(fd);
close(cFD);
FD_CLR(cFD, &fdin);
if (cFD == sMax) {
while (FD_ISSET(sMax, &fdin) == FALSE)
sMax -= 1;
}
}
}
}
}
} while (DCSERVER == FALSE);
cleanUP(cFD, sMax);
}
void cleanUP(int i, int max){
for (i=0; i <= max; ++i) {
if (FD_ISSET(i, &fdin))
close(i);
}
}
void dlogs(unsigned long ip){
FILE* pFile = fopen("/sockF.txt", "a+");
fprintf(pFile,"Connection from: %d.%d.%d.%d",
(int)(ip>>24)&0xff,
(int)(ip>>16)&0xff,
(int)(ip>>8)&0xff,
(int)(ip>>0)&0xff);
fclose(pFile);
}
void daemonize(){
pid = fork();
if(pid<0){
perror("fork() failed");
exit(EXIT_FAILURE);
}
if(pid>0){
exit(EXIT_SUCCESS);
}
umask(0);
sid = setsid();
if(sid<0){
perror("setsid() failed");
exit(EXIT_FAILURE);
}
if((chdir("/")) < 0){
perror("failed changing directory");
exit(EXIT_FAILURE);
}
}
Sample Output: I am using telnet and putty to test Server
From Telnet: IP: 192.168.5.53
Telnet 192.168.5.55 53234
./socks
Starting Server-G
Connection from: 192.168.5.53
Now When telnet is connected i use putty to send data to the pipe so the server will read it.
From Putty:
echo "TEST" > /tmp/myFIFO
the problem here is that whenever i send the data from putty writing to the pipe the server waits for telnet to send data before it outputs and send the data i've written to the pipe. How can i make both recv and read work at the same tym so when i write to my pipe it will output without waiting for recv?
Thanks
EDIT: I've also used thread to read the pipe but it still waits recv() before the server output what have been read to the pipe.
Use select or poll to wait for events on both of your file handles, eg. (using poll)
#include <poll.h>
//...
struct pollfd pfds[2];
int rc;
/* Wait for input on either one of the fds */
pfds[0].fd = fd;
pfds[0].events = POLLIN;
pfds[1].fd = cFD;
pfds[1].events = POLLIN;
do {
/* Wait forever for something to happen */
rc = poll(&pfds, 2, -1);
/* Error handling elided */
if (pfds[0].revents & POLLIN)
{
/* Read from fd, change pfds[1].events to (POLLIN | POLLOUT) so you know when you
can write without blocking. also clear pfds[0].events so we don't read until we
write */
pfds[0].events = 0;
pfds[1].events = POLLIN | POLLOUT;
}
if (pfds[1].revents & POLLIN)
{
/* Read from socket */
}
if (pfds[1].revents & POLLOUT)
{
/* write to socket, reset events flags */
pfds[0].events = POLLIN;
pfds[1].events = POLLIN;
}
} while (1)