IPC socket error - c

I m developing program usin IPC socket communication between socket under linux (kernel version is 2.6.25.20)
here after the source code of the client.c and the server.c
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3 /* no. of strings */
#define ADDRESS "mysocket" /* addr to connect */
/*
* Strings we send to the server.
*/
char *strs[NSTRS] = {
"This is the first string from the client.\n",
"This is the second string from the client.\n",
"This is the third string from the client.\n"
};
main()
{
char c;
FILE *fp;
register int i, s, len;
struct sockaddr_un saun;
/*
* Get a socket to work with. This socket will
* be in the UNIX domain, and will be a
* stream socket.
*/
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("client: socket");
exit(1);
}
/*
* Create the address we will be connecting to.
*/
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ADDRESS);
/*
* Try to connect to the address. For this to
* succeed, the server must already have bound
* this address, and must have issued a listen()
* request.
*
* The third argument indicates the "length" of
* the structure, not just the length of the
* socket name.
*/
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (connect(s, &saun, len) < 0) {
perror("client: connect");
exit(1);
}
/*
* We'll use stdio for reading
* the socket.
*/
fp = fdopen(s, "r");
/*
* First we read some strings from the server
* and print them out.
*/
for (i = 0; i < NSTRS; i++) {
while ((c = fgetc(fp)) != EOF) {
putchar(c);
if (c == '\n')
break;
}
}
/*
* Now we send some strings to the server.
*/
for (i = 0; i < NSTRS; i++)
send(s, strs[i], strlen(strs[i]), 0);
/*
* We can simply use close() to terminate the
* connection, since we're done with both sides.
*/
close(s);
exit(0);
}
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3 /* no. of strings */
#define ADDRESS "mysocket" /* addr to connect */
/*
* Strings we send to the client.
*/
char *strs[NSTRS] = {
"This is the first string from the server.\n",
"This is the second string from the server.\n",
"This is the third string from the server.\n"
};
main()
{
char c;
FILE *fp;
int fromlen;
register int i, s, ns, len;
struct sockaddr_un saun, fsaun;
/*
* Get a socket to work with. This socket will
* be in the UNIX domain, and will be a
* stream socket.
*/
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("server: socket");
exit(1);
}
/*
* Create the address we will be binding to.
*/
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ADDRESS);
/*
* Try to bind the address to the socket. We
* unlink the name first so that the bind won't
* fail.
*
* The third argument indicates the "length" of
* the structure, not just the length of the
* socket name.
*/
unlink(ADDRESS);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (bind(s, &saun, len) < 0) {
perror("server: bind");
exit(1);
}
/*
* Listen on the socket.
*/
if (listen(s, 5) < 0) {
perror("server: listen");
exit(1);
}
/*
* Accept connections. When we accept one, ns
* will be connected to the client. fsaun will
* contain the address of the client.
*/
if ((ns = accept(s, &fsaun, &fromlen)) < 0) {
perror("server: accept");
exit(1);
}
/*
* We'll use stdio for reading the socket.
*/
fp = fdopen(ns, "r");
/*
* First we send some strings to the client.
*/
for (i = 0; i < NSTRS; i++)
send(ns, strs[i], strlen(strs[i]), 0);
/*
* Then we read some strings from the client and
* print them out.
*/
for (i = 0; i < NSTRS; i++) {
while ((c = fgetc(fp)) != EOF) {
putchar(c);
if (c == '\n')
break;
}
}
/*
* We can simply use close() to terminate the
* connection, since we're done with both sides.
*/
close(s);
exit(0);
}
After building and running the client and the server I get an error from server in the accept phase and it print the following error server: accept: Invalid argument
the same application run without problem in an other linux system (kernel version 2.6.30)
How to fix the source code to make it run in the first platform?

if ((ns = accept(s, &fsaun, &fromlen)) < 0) {
You have to initialize fromlen before passing it to the function.
The addrlen argument is a value-result argument: the caller must
initialize it to contain the size (in bytes) of the structure
pointed to by addr; on return it will contain the actual size of the
peer address.
Something like:
fromlen = sizeof(fsaun);
/* And then accept. */
And the correct type for fromlen is socklen_t, not int.

Related

Why does my C program fail randomly at write?

I have written a proxy that accepts connections from host1 and forwards the connection toward server2.
I accept a connection and then I start two threads to handle the connections... One thread to receive from host 1 and send to server2, and another thread to receive form server2 and send to host1.
My program compiles with no errors, and when I run it and connect host 1 my program fails at the function WRITE after some short time with no error.
The connection is OK, it just fails after short period of time, before write.
Also you can find the written function that I am using.
The code is failing at the CONTROLLER thread, when the controller is writing to the socket.
Why does the program fail with no error message at all?
/*
* File Server0.c
* ECHO TCP SERVER with the following features:
* - Gets port from keyboard
* - SEQUENTIAL: serves one client at a time
*/
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "mysocket.h"
#include <arpa/inet.h>
#include <fcntl.h> // for open
#include <unistd.h> // for close
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <pthread.h> /* POSIX threads */
#define RBUFLEN 16384
/* FUNCTION PROTOTYPES */
int mygetline(char * line, size_t maxline, char *prompt);
int writen(SOCKET, char *, size_t);
void *mininet(void *);
void *controller(void *);
SOCKET s,s1[100],d[100];
int y=0,z=0;
int main()
{
uint16_t lport_n, lport_h;
int result;
socklen_t addrlen;
struct sockaddr_in saddr, caddr;
//fd_set readfds;
SOCKET conn_request_skt;
int bklog = 2,t=0;
pthread_t tid1[100];
pthread_t tid[100];
/* Initialize socket API if needed */
SockStartup();
/* input server port number */
lport_h=8888;
lport_n = htons(lport_h);
/* create the MININET socket */
printf("Creating first socketn");
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %un",s);
/* bind the MININET socket to any local IP address */
saddr.sin_family = AF_INET;
saddr.sin_port = lport_n;
saddr.sin_addr.s_addr = INADDR_ANY;
showAddr("Binding to address first socket", &saddr);
result = bind(s, (struct sockaddr *) &saddr, sizeof(saddr));
if (result == -1)
err_fatal("bind() failed");
printf("done.n");
/* listen on MININET socket */
printf ("Listening at socket %d with backlog = %d n",s,bklog);
result = listen(s, bklog);
if (result == -1)
err_fatal("listen() failed");
printf("done.n");
conn_request_skt=s;
/* accept next connection from mininet */
for(;;)
{
addrlen = sizeof(struct sockaddr_in);
z++;
y++;
t++;
d[t] = accept(conn_request_skt, (struct sockaddr *) &caddr, &addrlen);
if (d[t] == INVALID_SOCKET)
err_fatal("accept() failed");
showAddr("Accepted connection from", &caddr);
printf("new accepted connection socket: %un",d[t]);
/* serve the client on socket s */
pthread_create(&tid[t], NULL, mininet, &t);
pthread_create(&tid1[t], NULL, controller, &t);
sleep(1);
}
exit(0);
}
void *mininet (void *arg)
{
char buf[RBUFLEN]; /* reception buffer */
int n,t,k;
t=y;
k=z;
printf("MININET: m is: %d, c is: %d n ", t,k);
/* main server loop */
for (;;)
{
printf("MININET receiving on socket: %un",d[t]);
n=recv(d[t], buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("MININET Read errorn");
closesocket(d[t]);
printf("MININET Socket %d closedn", d[t]);
return NULL;
}
else if (n==0)
{
printf("Connection closed by MININET on socket %dn",d[t]);
closesocket(d[t]);
break;
}
else
{
printf("Received line from MININET socket %03d :n", d[t]);
buf[n]=0;
printf("[%s]n",buf);
printf("MINET WRITING TO: %un",s1[k]);
if(writen(s1[k], buf, n) != n)
printf("Write error while replying TO CONTROLERn");
else
printf("Reply sent towards CONTROLERn");
}
}
return NULL;
}
void *controller (void *arg)
{
char buf[RBUFLEN]; /* reception buffer */
uint16_t lport_n1, lport_h1; /* port where the server listens (net/host byte ord resp.) */
int result, n,t,k;
struct sockaddr_in saddr1; /* server and client address structures */
t=y;
k=z;
printf("CONTROLLER: m is: %d, c is: %d n ", t,k);
/* Initialize socket API if needed */
SockStartup();
lport_h1=6633;
lport_n1 = htons(lport_h1);
printf("Creating CONTROLLER socketn");
s1[k] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s1[k] == INVALID_SOCKET)
err_fatal("socket() failed");
printf("done, socket number %un",s1[k]);
/* bind the socket to any local IP address */
saddr1.sin_family = AF_INET;
saddr1.sin_port = lport_n1;
saddr1.sin_addr.s_addr = INADDR_ANY;
/* connect */
showAddr("Connecting to target CONTROLER address", &saddr1);
result = connect(s1[k], (struct sockaddr *) &saddr1, sizeof(saddr1));
if (result == -1)
err_fatal("connect() failed");
printf("done.n");
/* main server loop */
for (;;)
{
printf("CONTROLER receiving on socket: %un",s1[k]);
n=recv(s1[k], buf, RBUFLEN-1, 0);
if (n < 0)
{
printf("CONTROLER Read errorn");
closesocket(s1[k]);
printf("Socket %d closedn", s1[k]);
return NULL;
}
else if (n==0)
{
printf("Connection closed by CONTROLER on socket %dn",s1[k]);
closesocket(s1[k]);
return NULL;
}
else
{
printf("Received line from CONTROLER socket %03d :n", s1[k]);
buf[n]=0;
printf("[%s]n",buf);
printf("CONTROLER writing on socket: %un",d[t]);
if(writen(d[t], buf, n) != n)
printf("Write error while replying TO MININETn");
else
printf("Reply sent towards MININETn");
}
}
return NULL;
}
/* Gets a line of text from standard input after having printed a prompt string Substitutes end of line with ''
Empties standard input buffer but stores at most maxline-1 characters in the passed buffer
*/
int mygetline(char *line, size_t maxline, char *prompt)
{
char ch;
size_t i;
printf("%s", prompt);
for (i=0; i< maxline-1 && (ch = getchar()) != 'n' && ch != EOF; i++)
*line++ = ch;
*line = '';
while (ch != 'n' && ch != EOF)
ch = getchar();
if (ch == EOF)
return(EOF);
else
return(1);
}
/* Writes nbytes from buffer ptr to stream socket s */
int writen(SOCKET s, char *ptr, size_t nbytes)
{
size_t nleft;
ssize_t nwritten;
for (nleft=nbytes; nleft > 0; )
{
nwritten = send(s, ptr, nleft, 0);
if (nwritten <=0)
return (nwritten);
else
{
nleft -= nwritten;
ptr += nwritten;
}
}
return (nbytes - nleft);
}

Register Storage Class used in Socket Programming using C

What is the use of declaring file descriptor as register storage class in socket programming using c ?
If I am declared only int instead of register, then perror() returns "broken pipe". What is the meaning ?
example : register int i, s, len;
code copied from:
http://www.cs.cf.ac.uk/Dave/C/node28.html#SECTION002800000000000000000
socket_server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3 /* no. of strings */
#define ADDRESS "mysocket" /* addr to connect */
/*
* Strings we send to the client.
*/
char *strs[NSTRS] = {
"This is the first string from the server.\n",
"This is the second string from the server.\n",
"This is the third string from the server.\n"
};
main()
{
char c;
FILE *fp;
int fromlen;
register int i, s, ns, len;
struct sockaddr_un saun, fsaun;
/*
* Get a socket to work with. This socket will
* be in the UNIX domain, and will be a
* stream socket.
*/
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("server: socket");
exit(1);
}
/*
* Create the address we will be binding to.
*/
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ADDRESS);
/*
* Try to bind the address to the socket. We
* unlink the name first so that the bind won't
* fail.
*
* The third argument indicates the "length" of
* the structure, not just the length of the
* socket name.
*/
unlink(ADDRESS);
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (bind(s, &saun, len) < 0) {
perror("server: bind");
exit(1);
}
/*
* Listen on the socket.
*/
if (listen(s, 5) < 0) {
perror("server: listen");
exit(1);
}
/*
* Accept connections. When we accept one, ns
* will be connected to the client. fsaun will
* contain the address of the client.
*/
if ((ns = accept(s, &fsaun, &fromlen)) < 0) {
perror("server: accept");
exit(1);
}
/*
* We'll use stdio for reading the socket.
*/
fp = fdopen(ns, "r");
/*
* First we send some strings to the client.
*/
for (i = 0; i < NSTRS; i++)
send(ns, strs[i], strlen(strs[i]), 0);
/*
* Then we read some strings from the client and
* print them out.
*/
for (i = 0; i < NSTRS; i++) {
while ((c = fgetc(fp)) != EOF) {
putchar(c);
if (c == '\n')
break;
}
}
/*
* We can simply use close() to terminate the
* connection, since we're done with both sides.
*/
close(s);
exit(0);
}
socket_client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#define NSTRS 3 /* no. of strings */
#define ADDRESS "mysocket" /* addr to connect */
/*
* Strings we send to the server.
*/
char *strs[NSTRS] = {
"This is the first string from the client.\n",
"This is the second string from the client.\n",
"This is the third string from the client.\n"
};
main()
{
char c;
FILE *fp;
register int i, s, len;
struct sockaddr_un saun;
/*
* Get a socket to work with. This socket will
* be in the UNIX domain, and will be a
* stream socket.
*/
if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
perror("client: socket");
exit(1);
}
/*
* Create the address we will be connecting to.
*/
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, ADDRESS);
/*
* Try to connect to the address. For this to
* succeed, the server must already have bound
* this address, and must have issued a listen()
* request.
*
* The third argument indicates the "length" of
* the structure, not just the length of the
* socket name.
*/
len = sizeof(saun.sun_family) + strlen(saun.sun_path);
if (connect(s, &saun, len) < 0) {
perror("client: connect");
exit(1);
}
/*
* We'll use stdio for reading
* the socket.
*/
fp = fdopen(s, "r");
/*
* First we read some strings from the server
* and print them out.
*/
for (i = 0; i < NSTRS; i++) {
while ((c = fgetc(fp)) != EOF) {
putchar(c);
if (c == '\n')
break;
}
}
/*
* Now we send some strings to the server.
*/
for (i = 0; i < NSTRS; i++)
send(s, strs[i], strlen(strs[i]), 0);
/*
* We can simply use close() to terminate the
* connection, since we're done with both sides.
*/
close(s);
exit(0);
}

Whois service using UDP

Hell all. I was working on a server c project, using UDP for a whois service.
But I got error: "No whois is service on this host." Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pwd.h>
#define BACKLOG 5 /* # of requests we're willing to queue */
#define MAXHOSTNAME 32 /* maximum host name length we tolerate */
main(argc,argv)
int argc; /* standard UNIX argument declarations */
char *argv[];
{
int s,t; /* socket descriptors */
int i; /* general purpose integer */
struct sockaddr_in sa,isa; /* Internet socket address structure */
struct hostent *hp; /* result of host name lookup */
char *myname; /* pointer to name of this program */
struct servent *sp; /* result of service lookup */
char localhost[MAXHOSTNAME+1]; /* local host name as character string */
myname = argv[0];
/*
* Look up the WHOIS service entry
*/
if((sp = getservbyname("whois","udp")) == NULL){
fprintf(stderr, "%s: No whois service on this host\n", myname);
exit(1);
}
/*
* Get our own host information
*/
gethostname(localhost, MAXHOSTNAME);
if((hp = gethostbyname(localhost)) == NULL){
fprintf(stderr, "%s: cannot get local host info?\n", myname);
exit(1);
}
printf("host name is: %s\n",hp->h_name);
printf("my name is: %s\n",myname);
/*
* Put the WHOIS socket number and our address info into the socket structure
*/
u_short portbase = 0;
portbase = 5000;
sa.sin_port = sp->s_port;
sa.sin_port = htons(ntohs((u_short)sp->s_port)+portbase);
bcopy((char *)hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
sa.sin_family = hp->h_addrtype;
/*
* Allocate an open socket for incoming connections
*/
if((s = socket(hp->h_addrtype, SOCK_DGRAM, 0)) < 0){
perror("socket");
exit(1);
}
/*
* Bind the socket to the service port
*/
if(bind(s, (struct sockaddr *)&sa, sizeof sa) < 0){
perror("bind");
exit(1);
}
/*
* Set maximum connections we will fall behind
*/
//listen(s,BACKLOG);
/*
* Go into an infinite loop waiting for new connections
*/
while(1){
i = sizeof isa;
/*
* We hang in accept() while waiting for new customers
*/
/*
if((t = accept(s, (struct sockaddr *)&isa, &i)) < 0){
perror("accept");
exit(1);
}
*/
whois(s); /* perform the actual WHOIS service */
close(s);
}
}
/*
* Get the WHOIS request from remote host and format a reply.
*/
whois(sock)
int sock;
{
struct sockaddr_in clientAddr;
socklen_t len = sizeof(clientAddr);
memset(&clientAddr, 0, sizeof(clientAddr));
struct passwd *p;
char buf[BUFSIZ+1];
int i;
/*
* Get one line request
*/
printf("start to recv data\n");
if((i = recvfrom(sock, buf, BUFSIZ, 0, (struct sockaddr*)&clientAddr, &len)) <= 0)
printf("recv failed\n");
return;
buf[i] = '\0'; /* Null terminate */
printf("After the read, the buf is: %s \n",buf);
/*
* Look up the requested user and format reply
*/
if((p = getpwnam(buf)) == NULL)
strcpy(buf, "User not found\n");
else
sprintf(buf, "%s: %s (from me)\n", p->pw_name, p->pw_gecos);
/*
* Return reply
*/
//write(sock, buf, strlen(buf));
sendto(sock, buf, strlen(buf), 0, (struct sockaddr*)&clientAddr, len);
return;
}
I couldn't figure out where's error. I have a similar code using TCP for whois which runs no problem.
WHOIS is a TCP service. It is not available over UDP.
Additionally, what you are writing is not a WHOIS server at all. WHOIS is a protocol implemented by domain and IP registrars to communicate ownership information (e.g, to look up the owner of a domain name). What you are writing here appears to be a NIS service of some sort - this is not WHOIS, and should not use the same port.

Socket Programming in C

I'm trying to write a web server but with the code I have I'm getting 'open failed'. The html document (ht.html) which is supposed to be opened in the browser.
The code I have is:
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define SERVER_PORT 12345
#define BUF_SIZE 4096
#define QUEUE_SIZE 10
int main(int argc, char *argv[])
{
int s, b, l, fd, sa, bytes, on = 1;
char buf[BUF_SIZE]; //buffer for outgoing file
struct hostent *h; //info about server
struct sockaddr_in channel; //holds IP address
//Build address structure to bind to socket
memset(&channel, 0, sizeof(channel)); //zero channel
channel.sin_family = AF_INET;
channel.sin_addr.s_addr = htonl(INADDR_ANY);
channel.sin_port = htons(SERVER_PORT);
//Passive open. Wait for connection
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* create socket */
if (s < 0) fatal("socket failed");
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
if (b < 0) fatal("bind failed");
l = listen(s, QUEUE_SIZE); /* specify queue size */
if (l < 0) fatal("listen failed");
/* Socket is now set up and bound. Wait for connection and process it. */
while(1) {
sa = accept(s, 0, 0); /* block for connection request */
if (sa < 0) fatal("accept failed");
read(sa, buf, BUF_SIZE); /* read file name from socket */
/* Get and return the file. */
fd = open(buf, O_RDONLY); /* open the file to be sent back */
if (fd < 0) fatal("open failed");
while(1){
bytes = read(fd, buf, BUF_SIZE); /* read from file */
if (bytes <= 0) break; /* check for end of file */
write(sa, buf, bytes); /*write bytes to socket*/
}
close(fd); //close file
close(sa); //close connection
}
}
fatal(char*string)
{
printf("%s", string);
exit(1);
}
Where's my error? Or what has to be added?
Maybe you can start with outputting the data received from the socket, or at least run in a debugger, otherwise everything will be run in the dark, without you knowing what is going on. In the code below I have added a printf to print what we get from the web browser.
Also like others have pointed out, it is good to know what errno is trying to tell us. It is a bit awkward/annoying to use perror + exit, so in Linux and BSD you can use err(3) and warn(3). err will print errno message and then exit, while warn will just print errno message and not exit, I replaced your fatal function with these.
The web browser most likely will send GET /ht.html HTTP/1.1\r\n and this is what you are attempting to open. In order to open the file we need to extract the ht.html part. I have updated your code below and now strchr(3) and strstr(3) are used to extract ht.html.
We also need to send a HTTP response code and tell the web browser we want to send HTML, that is why the HTTP/1.1 200 OK is sent. Remember all HTTP headers need to be separated by \r\n (carriage return - newline). You will find more info about the HTTP protocol in RFC 2616.
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#define SERVER_PORT 12345
#define BUF_SIZE 4096
#define QUEUE_SIZE 10
int main(int argc, char *argv[])
{
int s, b, l, fd, sa, bytes, on = 1;
char buf[BUF_SIZE]; /* buffer for outgoing file */
char *p, *endp, *cp;
struct sockaddr_in channel; /* holds IP address */
/* Build address structure to bind to socket */
memset(&channel, 0, sizeof(channel)); /* zero channel */
channel.sin_family = AF_INET; /* ipv4 */
channel.sin_addr.s_addr = htonl(INADDR_ANY); /* 0.0.0.0 */
channel.sin_port = htons(SERVER_PORT);
/* Passive open. Wait for connection */
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* create socket */
if (s < 0) err(1, "socket failed");
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
b = bind(s, (struct sockaddr *) &channel, sizeof(channel));
if (b < 0) err(1, "bind failed");
l = listen(s, QUEUE_SIZE); /* specify queue size */
if (l < 0) err(1, "listen failed");
/* Socket is now set up and bound. Wait for connection and process it. */
while(1) {
sa = accept(s, NULL, NULL); /* block for connection request */
if(sa < 0) {
warn("accept failed");
continue;
}
bytes = 0;
endp = buf + sizeof(buf); /* pointer to end of buf */
cp = NULL;
buf[0] = '\0';
/* read first line from socket */
/* should be "GET /[file] HTTP/1.1" */
for(p = buf; (bytes = read(sa, p, endp - p)) > 0; p += bytes) {
p[bytes] = '\0'; /* read(2) doesn't NUL terminate buf */
if((cp = strchr(p, '\r')) != NULL) /* break at first carriage return */
break;
}
printf("incoming request %lu bytes:\n%s\n", strlen(buf), buf);
/* no carrige return or no "GET /" was found */
if(cp == NULL || strstr(buf, "GET /") != buf) {
warnx("incomplete request");
close(sa);
continue;
}
*cp = '\0'; /* replace '\r' with '\0' */
p = buf + sizeof("GET /") - 1; /* point to after "GET /" */
cp = strchr(p, ' '); /* find " HTTP/1.1" */
if(cp == NULL) {
warnx("HTTP version was not found");
close(sa);
continue;
}
*cp = '\0'; /* replace ' ' with '\0' */
/* Get and return the file. */
fd = open(p, O_RDONLY); /* open the file to be sent back */
if(fd < 0) {
warn("open failed: %s", p);
close(fd);
close(sa);
continue;
}
/* Send HTTP header */
/* Should probably also send Content-Length: <sizeof file>, */
/* this can be checked using fstat(2) */
write(sa, "HTTP/1.1 200 OK\r\n" \
"Content-Type: text/html;charset=UTF-8\r\n\r\n", 58);
while(1) {
bytes = read(fd, buf, sizeof(buf)); /* read from file */
if (bytes <= 0) break; /* check for end of file */
write(sa, buf, bytes); /*write bytes to socket*/
}
close(fd); /* close file */
close(sa); /* close connection */
}
return 0;
}
To connect from your web browser to your HTTP server go to: http://127.0.0.1:12345/ht.html.
Try to add some debug messages or run with a debugger.
I think that the problem relies in the buffer passed to open statement. It looks like buf is not initialized with zeroes and also not NULL terminated by "read".
n = read(sa, buf, BUF_SIZE);
buf[n] = '\0';
In general, when working with read, it should be called in a loop until 0 or -1 returned. It might fill only a fraction of the buffer.
Try to look ERRNO.
if (fd < 0) perror("open failed");
Try to look buf.
if (fd < 0){
printf("%s\n", buf);
perror("open failed");
}
Try to look buf this way:
if (fd < 0){
for(i=0;i<strlen(buf);i++)
printf("%d", buf[i]);
perror("open failed");
}
This will be enough to understand the error because your application simply does not open the file.
The stuff you are reading from the browser is a HTTP request.
You will need to decode this - so read the spec for HTTP.
Example of HTTP requests can be found here

Using C socket from Solaris on Ubuntu

the following c-code was programmed for solaris. now i had to port it to a ubuntu linux:
udp client
/* Modul fuer Echo-Client mittels UDP
Autor K. Felten Letzte Aenderung: 02.04.2008
Anpassung an Solaris 9
Aufruf mit: udpclient IP-Addr UDP-Port
------------------------------------------------------------------------------
* Example of server using UDP protocol.
------------------------------------------------------------------------------
As with the TCP server example, the Internet address for the bind is specified
as INADDR_ANY.
The client program:
------------------------------------------------------------------------------
*/
#include "inet.h"
#include <netdb.h>
#include <ctype.h>
int check_dot( address )
char *address;
{ int dotcount = 0;
for ( ; *address != '\0'; address++ )
if ( *address == '.' )
dotcount++;
else if (!isdigit(*address))
dotcount = 4;
return ( dotcount );
}
int main(int argc, char *argv[])
{
int sockfd;
int i, *iaddr;
unsigned char *addr;
struct sockaddr_in cli_addr, serv_addr;
char *server_ip_addr;
int dotnum; /* Number of Dots in Address (argv[1] */
unsigned short server_port; /* Serverport-Nr. */
struct hostent *server;
if (argc != 3 ){
printf("2 Arguments required:\n");
printf(" - IP-Address, Dot Notation\n");
printf(" - UDP-Port-Nr.\n");
exit(1);
}
else server_ip_addr = argv[1];
dotnum = check_dot(server_ip_addr);
if ( dotnum != 3 )
{ /* Address not in Dot-Notation */
server = gethostbyname( server_ip_addr );
if ( server != NULL )
{ iaddr = (int * ) *(server->h_addr_list); /* get 4 Byte Internet-addr. */
/* Testausgaben */
printf("Server-Name =%s\n", server->h_name );
printf("Server-Addr_length=%d\n", server->h_length );
printf("Addr=%x\n",(unsigned int)server->h_addr_list );
addr = (unsigned char * ) *(server->h_addr_list);
printf("Addr=%x\n", *iaddr );
while ( *addr != 0)
{ printf("Addr=%d\n", *addr );
addr++;
}
}
else printf("Server-Address not found\n");
}
server_port = (short) atoi(argv[2]);
/*
* Fill in the structure "serv_addr" with the address of the
* server that we want to send to.
*/
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
if ( dotnum == 3 )
serv_addr.sin_addr.s_addr = inet_addr( server_ip_addr );
else
serv_addr.sin_addr.s_addr = *iaddr;
serv_addr.sin_port = htons(server_port);
/*
* Open a UDP socket (an Internet datagram socket).
*/
if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_dump("client can't open datagram socket");
/*
* Bind any local address for us.
*/
bzero((char *) &cli_addr, sizeof(cli_addr)); /* zero out */
cli_addr.sin_family = AF_INET;
cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
cli_addr.sin_port = htons(0);
if (bind(sockfd, (struct sockaddr *) &cli_addr, sizeof(cli_addr)) < 0)
err_dump("client: can't bind local address");
/* else printf("bind ist ok\n"); */
dg_cli(stdin, sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
close(sockfd);
exit ( 0 ) ;
}
there's also a makefile:
# this makefile uses your sources
APPN=echoUDP # put your favorite program here
# change these for different maschines and stages of development
CFLAGS = -g -lnsl # build the symbol table for debugger
# build the utilities
utilities.o: utilities.c
$(CC) $(CFLAGS) -c utilities.c
# build the client application
$(APPN)client: inet.h utilities.o $(APPN)client.o
$(CC) $(CFLAGS) -o $(APPN)client utilities.o $(APPN)client.o $(LFLAGS)
# build the server application
$(APPN)serv: inet.h utilities.o $(APPN)serv.c
$(CC) $(CFLAGS) -o $(APPN)serv utilities.o $(APPN)serv.o\
$(APPN)serv.c $(LFLAGS)
and the inet.h header file:
/* Header-File fuer TCP und UDP
* Letzte Aenderung: 02.04.2008 K. Felten
* Definitions for TCP and UDP client/server programs.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <syslog.h>
#define SERV_HOST_ADDR "127.0.0.1" /* host addr for server = localhost */
char *pname;
void err_sys( char *errortext);
void err_dump( char *errortext);
void dg_echo(int sockfd, struct sockaddr *pcli_addr, int maxclilen);
void dg_cli(FILE *fp, int sockfd, struct sockaddr *pserv_addr, int servlen);
and at least the utilities.c
/* Modul mit Hilfsprogrammen fuer Socket-Beispiel
* Letzte Aenderung: 02.04.2008 K. Felten
*/
#include <stdio.h>
#include <string.h>
#include <syslog.h>
char emesgstr[255] ={0};
/* Print the UNIX errno value
* We must append it to the end of the e,mesgstr[] array.
*/
my_perror()
{
register int len;
char *sys_err_str();
len = strlen(emesgstr);
sprintf(emesgstr + len, " %s", sys_err_str());
}
extern int errno; /* UNIX error number */
extern int sys_nerr; /* # of error message strings in sys table */
extern char *sys_errlist[]; /* the system error message table */
/* Return a string containing sme additional operating-system
* dependet information.
*/
char *sys_err_str()
{
static char msgstr[200];
if (errno != 0 ){
if (errno > 0 && errno < sys_nerr)
sprintf(msgstr,"(%s)", sys_errlist[errno]);
else
sprintf(msgstr,"(errno = %d)", errno);
}
else msgstr[0] = '\0';
return(msgstr);
}
#define syslog(a,b) fprintf(stderr,"%s\n", (b))
err_sys( errortext )
char *errortext;
{
fprintf( stderr,"%s\n", errortext );
my_perror();
syslog(LOG_ERR, emesgstr);
return( 1 );
}
err_dump( errortext )
char *errortext;
{
fprintf( stderr,"%s\n", errortext );
my_perror();
syslog(LOG_ERR, emesgstr);
return( 1 );
}
/*
*******************************************************************************
* Read "n" bytes from a descriptor.
* Use in place of read() when fd is a stream socket.
*******************************************************************************
*/
int readn(fd, ptr, nbytes )
register int fd;
register char *ptr;
register int nbytes;
{
int nleft, nread;
nleft = nbytes;
while (nleft > 0){
nread = read(fd, ptr, nleft);
if (nread < 0)
return(nread); /* error, return < 0 */
else if (nread == 0)
break; /* EOF */
nleft -= nread;
ptr += nread;
}
return(nbytes - nleft); /* return >= 0 */
}
/*
*******************************************************************************
* Read a stream socket one line at a time, and write each line back
* to the sender.
*
* Return when the connection is terminated.
*******************************************************************************
*/
#define MAXLINE 512
str_echo(sockfd)
int sockfd;
{
int n;
char line[MAXLINE];
char line2[MAXLINE];
for ( ; ; ) {
n = readline(sockfd, line, MAXLINE);
if (n == 0)
return; /* connection terminated */
else if (n < 0)
err_dump("str_echo: readline error");
strcpy(line2, "TCP-Echo=>" );
strcat( line2, line);
/* puts(line2); Testausgabe */
n = strlen(line2);
if (writen(sockfd, line2, n ) != n)
err_dump("str_echo: writen error");
}
}
/*
------------------------------------------------------------------------------
The following function is used by the three connection-oriented clients:
------------------------------------------------------------------------------
* Read the contents of the FILE *fp, write each line to the
* stream socket (to the server process), then read a line back from
* the socket and write it to the standard output.
*
* Return to caller when an EOF is encountered on the input file.
*/
#include <stdio.h>
#define MAXLINE 512
str_cli ( fp, sockfd)
register FILE *fp;
register int sockfd;
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL) {
n = strlen(sendline);
if (writen(sockfd, sendline, n) != n)
err_sys("str_cli: writen error on socket");
/*
* Now read a line from the socket and write it to
* our standard output.
*/
n = readline(sockfd, recvline, MAXLINE);
if (n < 0)
err_dump("str_cli: readline error");
fputs(recvline, stdout);
}
if (ferror (fp) )
err_sys("str_cli: error reading file");
}
/*
------------------------------------------------------------------------------
The following function is used by the three connectionless servers. By passing
address of the actual socket address structure to this function, it works with
all protocol families. Since the size of the structure can differ between
protocol families also pass its size to this function, as it is needed for the
recvfrom system call.
------------------------------------------------------------------------------
* Read a datagram from a connectionless socket and write it back to
* the sender.
*
* We never return, as we never know when a datagram client is done.
*/
#include <sys/types.h>
#include <sys/socket.h>
#define MAXMESG 2048
dg_echo(sockfd, pcli_addr, maxclilen)
int sockfd;
struct sockaddr *pcli_addr; /* ptr to appropriate sockaddr XX structure */
int maxclilen; /* sizeof(*pcli_addr) */
{
int n, clilen;
char mesg[MAXMESG];
char mesg2[MAXMESG];
for ( ; ; ){
clilen = maxclilen;
n = recvfrom(sockfd, mesg, MAXMESG, 0, pcli_addr, &clilen);
if (n < 0)
err_dump("dg_echo: recvfrom error");
/* Protokollausgabe */
mesg[n] = 0; /* String-Laenge begrenzen */
printf("UDP-Server-recvfrom:%slng=%d\n", mesg, n );
/* Manipulation der Zeilen */
strcpy( mesg2, "UDP-Echo=>" );
strcat( mesg2, mesg);
n = strlen(mesg2);
if (sendto(sockfd, mesg2, n, 0, pcli_addr, clilen) != n)
err_dump("dg_echo: sendto error");
}
}
/*
------------------------------------------------------------------------------
The following function is for the connectionless clients. It is similar to the
one for a connection-oriented client, with the writen calls replaced by sendto
and the readn calls replaced by recvfrom. Also, we need the address of the
actual socket address structure and its size for the datagram system calls.
------------------------------------------------------------------------------
* Read the contents of the FILE *fp, write each line to the
* datagram socket, then read a line back from the datagram
* socket and write it to the standard output.
*
* Return to caller when an EOF is encountered on the input file.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#define MAXLINE 512
dg_cli(fp, sockfd, pserv_addr, servlen)
FILE *fp; int sockfd;
struct sockaddr *pserv_addr; /* ptr to appropriate sockaddr_XX structure */
int servlen; /* actual sizeof(*pserv_addrj */
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (fgets(sendline, MAXLINE, fp) != NULL) {
n = strlen(sendline);
if (sendto(sockfd, sendline, n, 0, pserv_addr, servlen) != n)
err_dump("dg_cli: sendto error on socket");
/*
* Now read a message from the socket and write it to
* our standard output.
*/
n = recvfrom(sockfd, recvline, MAXLINE, 0,
(struct sockaddr *) 0, (int *) 0);
if (n < 0)
err_dump("dg_cli: recvfrom error");
recvline[n] = 0; /* null terminate */
fputs(recvline, stdout);
}
if (ferror(fp))
err_dump("dg_cli: error reading file");
}
/*
------------------------------------------------------------------------------
The following function writes to a stream socket:
------------------------------------------------------------------------------
* Write "n" bytes to a descriptor.
* Use in place of write() when fd is a stream socket. /*
*/
int writen(fd, ptr, nbytes)
register int fd;
register char *ptr;
register int nbytes;
{
int nleft, nwritten;
nleft = nbytes;
while (nleft > 0) {
nwritten = write(fd, ptr, nleft);
if (nwritten <= 0)
return(nwritten); /* error */
nleft -= nwritten;
ptr += nwritten;
}
return(nbytes - nleft);
}
/*
------------------------------------------------------------------------------
We use the following function to read a line from a stream socket. In our
examples we'll be exchanging Unix text lines between the client and server.
------------------------------------------------------------------------------
* Read a line from a descriptor. Read the line one byte at a time,
* looking for the newline. We store the newline in the buffer,
* then follow it with a null (the same as fgets(3)).
* We return the number of characters up to, but not including,
* the null (the same as strlen(3)).
*/
int readline(fd, ptr, maxlen)
register int fd;
register char *ptr;
register int maxlen;
{
int n, rc;
char c;
for (n = 1; n < maxlen; n++) {
if ( (rc = read(fd, &c, 1)) == 1){
*ptr++ = c;
if (c == '\n')
break;
}
else if (rc == 0) {
if (n == 1)
return(0); /* EOF, no data read */
else
break; /* EOF, some data was read */
}
else
return(-1); /* error */
}
*ptr = 0;
return(n);
}
if i try make echoDUPclient i get the following error:
cc -g -lnsl echoUDPclient.c -o echoUDPclient
/tmp/cclsBda6.o: In function `main':
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:81: undefined reference to `err_dump'
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:90: undefined reference to `err_dump'
/home/hannes/Dokumente/0_university/20_netzwerkprogrammierung/echo/echoUDP/echoUDPclient.c:92: undefined reference to `dg_cli'
with make utilities i get:
cc -g -lnsl -c utilities.c
utilities.c:23:14: Fehler: In Konflikt stehende Typen für »sys_errlist«
/usr/include/i386-linux-gnu/bits/sys_errlist.h:28:30: Anmerkung: Vorherige Deklaration von »sys_errlist« war hier
(means confilct of sys_errlist and a previous declaration in sys_errlist.h)
On Solaris this sholud work, but it didn't on my linux. So what are the things i have to modify?
Your first call to cc complains about undefined references since you omitted to tell the linker where to find the utilities.o object file. Tell the linker (by adding utilities.o to the cc call) or simply stick with the Makefile.
According to my Linux manpages, sys_errlist has type char **, while you define char *sys_errlist[] in utilities.c. It's worth noting that sys_errlist is deprecated and you should use strerror() instead.
That gives you at least two options:
either fix your definition of sys_errlist, e.g. by removing it completely and relying on stdio.h to properly declare it
replace the whole sys_errlist stuff with proper strerror() error reporting
On a sidenote, it might be easier to come up with your own UDP echo client/server instead of porting a Solaris implementation. Also, you should properly tag your homework questions as such.
Grüße aus dem Saarland :)

Resources