enum recstate {
initial
};
int num_clients = 0;
static void addclient(int fd, struct in_addr addr){
struct client *p = (struct client *) malloc (sizeof(struct client));
if (!p) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
printf("Adding client %s\n", inet_ntoa(addr));
p->fd = fd;
p->next = top;
p->state = initial;
top = p;
num_clients++;
}
struct client {
int fd; // socket descriptor for this client
enum recstate state; // current state of data transfer for this client
struct client *next; // a pointer to the next client in the list
struct in_addr ipaddr;
} *top = NULL;
int main(int argc, char* argv[]){
int listenfd, clientfd, maxfd, nready;
struct client *p;
struct sockaddr_in self, client;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&self, '\0', sizeof(self));
self.sin_family = AF_INET;
self.sin_addr.s_addr = INADDR_ANY;
self.sin_port = htons(PORT);
if (bind(listenfd, (struct sockaddr *) &self, sizeof(self))){
perror("bind");
exit(1);
}
if (listen(listenfd, 5) < 0){
perror("listen");
exit(1);
}
while (1){
fd_set allset, rset;
FD_ZERO(&allset);
FD_SET(listenfd, &allset);
maxfd = listenfd;
rset = allset;
for (p = top; p; p = p->next){
FD_SET(p->fd, &allset);
if (p->fd > maxfd){
maxfd = p->fd;
}
}
if(FD_ISSET(listenfd, &rset)){
printf("Listenfd is ready\n");
len = sizeof(client);
if ((clientfd = accept(listenfd, (struct sockaddr *) &client, &len)) < 0){
perror("accept");
return(1);
}
else {
printf("Connection from %s\n", inet_ntoa(client.sin_addr));
addclient(clientfd, client.sin_addr);
FD_SET(clientfd, &rset);
printf("clientfd has been added to fdset\n");
if(p->state == initial){ //cannot get into this if statement
printf("now in initial state\n");
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(nready == 0){
printf("timeout happened\n");
continue;
}
else if(nready == -1){
perror("select");
continue;
}
else if (nready > 0){
printf("Data is now available.\n");
continue;
}
if (FD_ISSET(listenfd, &rset)){ //returns a value for fd in rset
//read data into file
}
}
}
}
}
}
This is part of my server code.
I'm trying to send files from the client to the server, but when I send the files from the client, the server will execute until just above the if(p->state == initial) statement, and hangs there. When I terminate the server, it'll give me a segmentation fault: 11 error.
Also, I'm using select() inside the initial state to allow multiple clients to connect simultaneously.
Don't know where I went wrong, any help would be greatly appreciated.
Thanks.
for (p = top; p; p = p->next){
Unless I'm mistaken, you loop until p is NULL
if(p->state == initial){
and then you dereference p.
KABOOM.
Related
I have read some example and manual about select and accept but I still can't figure out where I did wrong.
I tried to let server communicate with multiple clients. But when I execute server first, then execute client, server will immediately cause segmentation fault( when i == sockfd in server.c). And I tried to print some strings to check which statement cause wrong, it even no print anything after if (i == sockfd). So I really have no idea how to move on, are there any suggestion?
Server.c
char inputBuffer[140] = {};
char message[] = {"Hi,this is server.\n"};
int sockfd = 0,forClientSockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket creation
struct sockaddr_in serverInfo,clientInfo;
socklen_t addrlen = sizeof(clientInfo);
serverInfo.sin_family = PF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY;
serverInfo.sin_port = htons(PORT);
bind(sockfd,(struct sockaddr *)&serverInfo,sizeof(serverInfo));
listen(sockfd,5);
fd_set active_fd_set, read_fd_set;
int i;
struct sockaddr_in clientname;
size_t size;
/* Initialize the set of active sockets. */
FD_ZERO (&active_fd_set);
FD_SET (sockfd, &active_fd_set);
int fd_max = sockfd;
while (1)
{
/* Block until input arrives on one or more active sockets. */
//FD_ZERO (&active_fd_set);
//FD_SET (sockfd, &active_fd_set);
read_fd_set = active_fd_set;
if (select (fd_max+1, &read_fd_set, NULL, NULL, NULL) < 0)
{
printf("select fail\n");
}
/* Service all the sockets with input pending. */
for (i = 0; i <= fd_max; ++i)
{
//printf("%d\n",i);
if (FD_ISSET (i, &read_fd_set))
{
//printf("inner :%d %d\n",i,sockfd);
if (i == sockfd)
{
/* Connection request on original socket. */
//printf("A");
int new;
size = sizeof (clientname);
new = accept (sockfd,(struct sockaddr *) &clientname,&size);
if (new < 0)
{
printf("accept fail\n");
}
else
{
printf (
"Server: connect from host %s, port %hd.\n",
inet_ntoa (clientname.sin_addr),
ntohs (clientname.sin_port));
FD_SET (new, &active_fd_set);
if(new > fd_max)
{
fd_max = new;
}
}
}
else
{
/* Data arriving on an already-connected socket. */
if (read_from_client (i) < 0)
{
close (i);
FD_CLR (i, &active_fd_set);
}
}
}
}
}
return 0;
}
int read_from_client (int filedes)
{
char buffer[140];
int nbytes;
nbytes = recv (filedes, buffer, sizeof(buffer),0);
if (nbytes < 0)
{
/* Read error. */
perror ("read");
exit (EXIT_FAILURE);
}
else if (nbytes == 0)
/* End-of-file. */
return -1;
else
{
/* Data read. */
printf ("Server: got message: `%s'\n", buffer);
return 0;
}
}
client.c
int sockfd = 0;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
printf("Fail to create a socket.");
}
//socket connnection
struct sockaddr_in info;
bzero(&info,sizeof(info));
info.sin_family = PF_INET;
//localhost test
info.sin_addr.s_addr = inet_addr(LOCALHOST);
info.sin_port = htons(PORT);
int err;
char *p;
//Send a message to server
err = connect(sockfd,(struct sockaddr *)&info,sizeof(info));
if(err==-1)
printf("Connection error");
while(1)
{
char message[140];
char receiveMessage[140] = {};
fgets(message,140,stdin);
//scanf("%*[^\n]",message);
//printf("%s",message);
/*if(p=strchr(message,'\n')){
*p = 0;
}else{
scanf("%*[^\n]");
scanf("%c");
}
fgets(message,140,stdin);*/
//scanf("%s",message);
send(sockfd,message,sizeof(message),0);
//printf("RCV");
//recv(sockfd,receiveMessage,sizeof(receiveMessage),0);
//printf("%s\n",receiveMessage);
}
thanks !!
I am trying to connect to my local UNIX server i made from another remote device. the Server is up and listening to the port i specified. i also added a new firewall rule to open that port but still my client cannot connect. it shows ERROR CONNECTION REFUSED
here is my server code
int main() {
int fd, i,svclient,rval,msg;
int clients[10], num_clients;
fd_set read_set,write_set;
char buf[100];
struct sockaddr_in addr;
if ( (fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket error");
exit(-1);
}
bzero((char *) &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(4001);
//strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)-1);
//strcpy(addr.sun_path, NAME);
if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
perror("bind error");
exit(-1);
}
printf("Bind complet...\n");
if (listen(fd, 20) == -1) {
perror("listen error");
exit(-1);
}
num_clients = 0;
int size = sizeof(fd);
while (1) {
int clientfd;
struct sockaddr_in client_addr;
int addrlen=sizeof(client_addr);
FD_ZERO(&read_set);
FD_SET(fd, &read_set);
for (i = 0; i < num_clients; i++) { //at first this part will not excute
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,(struct sockaddr*)&client_addr,&addrlen)) == -1) {
perror("accept error");
continue;
}
/*printf("incoming message..................... !\n \n");*/
printf("%s:%d connected\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
}
for (i = 0; i < num_clients; i++) {
if (FD_ISSET(clients[i], &read_set)) {
msg = read(clients[i], buf, sizeof(buf));
if(msg > 0){
buf[msg] = 0;
int savedclnt = clients[i];
printf("%s \n \n", buf);
/*for(int p=0;p<num_clients;p++)
{
if( clients[p]!= savedclnt){
write(clients[p],buf,msg);
}
}*/
}
}
}
}
}
and my client
int main( )
{
struct uci_context *uci;
uci = uci_init();
int sockfd;
int ret;
struct sockaddr_in dest;
struct addrinfo hint, *res = NULL;
struct hostent *host;
char *hostip;
char *string;
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
{
puts("Unble to create socket");
exit(1);
}
hostip = ucix_get_option(uci, "pack_mon", "pack_monitoring", "address");
string = ucix_get_option(uci, "pack_mon", "pack_monitoring", "port");
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(atoi(string));
memset(&hint, '\0', sizeof hint);
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
printf(" %s- %s\n", hostip, string );
if(isdigit(hostip[0])){
ret = getaddrinfo(hostip, NULL, &hint, &res);// this is more efficient than inet_addr
if (ret) {
exit(1);
}
}else if( (host = gethostbyname(hostip)) != 0){
memcpy((char*)&dest.sin_addr , (char*)host->h_addr , (sizeof dest.sin_addr)+1);
}else{
exit(1);
printf("cannot resolve ip address");
}
if ( connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) < 0 )
{
perror("ERROR Connecting" );
exit(1);
}else{
printf("Port number %s is open.....\n",string);
}
char *message;
message = "help";
write(sockfd,message,strlen(message));
close(sockfd);
freeaddrinfo(res);
return 0;
}
FIREWALL RULE
sudo iptables -I INPUT -p tcp --dport 4001 -j ACCEPT
Error is :
192.168.10.155- 4001
ERROR Connecting: Connection refused
and this logs are coming from this codes :
printf(" %s- %s\n", hostip, string );
perror("ERROR Connecting");
exit(1);
Your client has no code to specify the IP address it wants to connect to. All the code that could do that has been commented out.
Update: Now your bug is here:
strncpy((char*)&dest.sin_addr , (char*)host->h_addr , sizeof dest.sin_addr);
The strncpy function is only suitable for C-style strings. You need to use memcpy or something similar. This will only copy part of the IP address if any octet other than its last one (in network byte order) is zero.
Update: Now your bug is here:
printf("%d\n", connect(sockfd, (struct sockaddr *)&dest, sizeof(dest)) < 0);
perror("hmmmm" );
exit(1);
This calls connect, then calls printf and then calls perror. The problem is, the call to printf can modify errno even if it succeeds. Thus your call to perror can print a totally irrelevant error message.
Using thread, I wanted to launch UDP server on background.
But the server start and loop forever checking if any packet is received.
The same thread work fine if I use TCP server instead.
the test code is the following:
int udp_server_listen () {
printf("udp_server_listen \n");
int res;
unsigned char rsp_buf[1024];
struct sockaddr_in src;
socklen_t srclen;
memset(&src, 0, sizeof(src));
srclen = sizeof(src);
listen(s , 3);
//Accept and incoming connection
int c = sizeof(struct sockaddr_in);
int client_sock;
while( (client_sock = accept(s, (struct sockaddr *)&src, (socklen_t*)&c)) )
{
sleep(1);
printf("OK \n");
}
}
void *thread_udp_cr_listen (void *v)
{
udp_server_listen();
return NULL;
}
int s;
int main()
{
printf("start test \n");
struct sockaddr_in *local = malloc(sizeof (struct sockaddr_in *));
s = socket(AF_INET, SOCK_DGRAM, 0); // UDP
printf("create socket end\n");
int reusaddr = 1;
int reusport = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reusaddr, sizeof(int)) < 0)
{
printf("setsockopt(SO_REUSEADDR) failed \n");
}
if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &reusport, sizeof(int)) < 0)
{
printf("setsockopt(SO_REUSEPORT) failed \n");
}
struct timeval tv;
tv.tv_sec = 2; /* 30 Secs Timeout */
tv.tv_usec = 0; // Not init'ing this can cause strange errors
setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
fcntl(s, F_SETFL, O_NONBLOCK);
printf(" Bind to a specific network interface and a specific local port\n");
int i = 0;
for(;i<6;i++)
{
if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0)
{
printf("bind Faild %d\n", i);
sleep(1);
continue;
}
break;
}
error = pthread_create(&udp_cr_server_thread, NULL, &thread_udp_cr_listen, NULL);
if (error<0)
{
printf("thread error \n");
}
pthread_join(udp_cr_server_thread, NULL);
}
You have one serious problem here:
struct sockaddr_in *local = malloc(sizeof (struct sockaddr_in *));
because you're just allocating the size of a pointer instead of the size of the struct itself.
This should of course be:
struct sockaddr_in *local = malloc(sizeof (struct sockaddr_in));
Two more problems with the same variable in this line:
if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0)
This should be:
if (bind(s, (struct sockaddr *)local, sizeof(*local)) < 0)
Basically i'm trying to do a server-client program that communicates with sockets.
I find it strange that the server, once started it doesn't even print the first line. Why is this?
There must be something that's sliping from me and I really need to know what.
Server.c
int rvsock;
void stop(int sig){
close(rvsock);
}
void* worker(void* p){
struct mymsg m;
int err;
int sock = (int)p;
err = recv(sock,&m,sizeof(m),0);
if(err < 0){
printf("Failed to receive");
exit(1);
}
m.a = ntohl(m.a);
m.b = ntohl(m.b);
m.c = ntohl(m.c);
m.ip = ntohl(m.ip);
printf("Received numbers: %d %d %d from IP:%d", m.a,m.b,m.c,m.ip);
if(m.a < m.b && m.b <= m.c)
m.a = m.c;
else if(m.a < m.b && m.b >= m.c)
m.a = m.b;
else if(m.a > m.b && m.b <= m.c)
m.a = m.a;
m.a = htonl(m.a);
m.b = htonl(m.b);
m.c = htonl(m.c);
err = send(sock, &m,sizeof(m),0);
if(err < 0){
printf("Failed to send!");
close(sock);
return NULL;
}
close(sock);
return NULL;
}
int main(int argc, char** argv) {
printf("DAFUQ"); //It doesn't even print this. Why?
int port;
int sock;
int err;
unsigned int len;
struct sockaddr_in saddr;
struct sockaddr_in caddr;
pthread_t w[100];
int wn = 0;
int i;
sscanf(argv[1], "%d", &port);
signal(SIGINT, stop);
rvsock = socket(AF_INET, SOCK_STREAM, 0);
if(rvsock < 0) {
perror("Failed to create socket");
exit(1);
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = INADDR_ANY;
saddr.sin_port = htons(port);
err = bind(rvsock, (struct sockaddr*)&saddr,
sizeof(struct sockaddr_in));
if(err < 0) {
perror("Failed to bind");
exit(1);
}
err = listen(rvsock, 5);
if(err < 0) {
perror("Failed to listen");
close(rvsock);
exit(1);
}
while(1) {
len = sizeof(struct sockaddr_in);
sock = accept(rvsock, (struct sockaddr*)&caddr, &len);
if(sock < 0) {
perror("Failed to accept");
break;
}
pthread_create(&w[wn], 0, worker, (int*)sock);
wn++;
}
for(i=0; i<wn; i++) {
pthread_join(w[i], 0);
}
return 0;
}
client.c
int main(int argc, char** argv){
int sock;
int err;
int port;
struct sockaddr_in saddr;
struct mymsg m;
sscanf(argv[1], "%d", &port);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0){
printf("failed to create");
exit(1);
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
saddr.sin_port = htons(port);
err = connect(sock, (struct sockaddr*)&saddr, sizeof(struct sockaddr_in));
if(err < 0){
perror("Failed to connect!");
exit(1);
}
printf("give a:");scanf("%d",&m.a);
printf("give b:");scanf("%d",&m.b);
printf("give c:");scanf("%d",&m.c);
m.a = htonl(m.a);
m.b = htonl(m.b);
m.c = htonl(m.c);
send(sock,&m,sizeof(m),0);
return 0;
}
message.h
struct mymsg{
int a;
int b;
int c;
int ip;
};
In your server you have this line. printf prints to the stdout FILE which is opened for you when you start your program.
printf("DAFUQ"); //It doesn't even print this. Why?
man stdout provides the following information about stdout:
The stream stdout is line-buffered
when it points to a terminal. Partial lines will not appear until
fflush(3) or exit(3) is called, or a newline is printed.
You don't print a newline, you don't flush stdout and your program doesn't exit, therefore none of the conditions required to print your output to the terminal are met.
Therefore in order to print the line you have 3 options:
1
printf("DAFUQ"); //It doesn't even print this. Why?
fflush(stdout);
2
printf("DAFUQ\n"); /*notice added '\n'*/
3
call exit() after you print ( not very helpful probably).
I wrote a web server using C language. I can visit the server at http://myhostname:protnum/index.html
But when I use my friend's computer to visit the same address, it said cannot visit the web page.
The file is webserv.c, server is launched with ./webserv 12345 (in a terminal)
Why can't my friend computer access the server?
The following is the webserv.c file:
int main(int argc, char const *argv[])
{
int sock, fd;
FILE *fpin;
char request[BUFSIZ];
if (argc == 1) {
fprintf(stderr, "usage: ws portnum\n");
exit(1);
}
sock = make_server_socket( atoi(argv[1]) );
if (sock == -1)
exit(2);
/*main loop here*/
while (1) {
/*take a call and buffer it*/
fd = accept(sock, NULL, NULL);
fpin = fdopen(fd, "r");
/*read request*/
fgets(request, BUFSIZ, fpin);
printf("Got a call: request = %s", request);
read_til_crnl(fpin);
/*do what client asks*/
process_rq(request, fd);
fclose(fpin);
}
return 0;
}
int make_server_socket_q(int portnum, int backlog)
{
struct sockaddr_in saddr;
struct hostent *hp;
char hostname[HOSTLEN];
int sock_id;
sock_id = socket(PF_INET, SOCK_STREAM, 0);
if (sock_id == -1)
return -1;
/*build address abd bind it to socket*/
bzero((void *)&saddr, sizeof(saddr));
gethostname(hostname, HOSTLEN);
hp = gethostbyname(hostname);
bcopy((void *)hp->h_addr, (void *)&saddr.sin_addr, hp->h_length);
saddr.sin_port = htons(portnum);
saddr.sin_family = AF_INET;
if (bind(sock_id, (struct sockaddr *)&saddr, sizeof(saddr)) != 0)
return -1;
if (listen(sock_id, backlog) != 0)
return -1;
return sock_id;
}
void process_rq(char *request, int fd)
{
char cmd[BUFSIZ], arg[BUFSIZ];
/*create a new process and return if not the child*/
if (fork() != 0)
return;
strcpy(arg, "./");
if (sscanf(request, "%s%s", cmd, arg+2) !=2)
return;
if (strcmp(cmd, "GET") != 0)
cannot_do(fd);
else if (not_exist(arg))
do_404(arg, fd);
else if (isadir(arg))
do_ls(arg, fd);
else if (ends_in_cgi(arg))
do_exec(arg, fd);
else
do_cat(arg, fd);
}
One common error is to use the wrong address when creating the listening socket. If your listen from 127.0.0.1 only local connections will be accepted. You should listen on 0.0.0.0 to allow connection from any IP address.
To do this in my windows code I've used in the past
addr.sin_family = AF_INET;
addr.sin_port = ...;
addr.sin_addr.s_addr = 0;
but seems that INADDR_ANY is a better way to say 0.