Using C socket from Solaris on Ubuntu - c

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 :)

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);
}

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

IPC socket error

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.

UDP in c: Extra characters getting added to file when saving received data in chunks

I'm trying to get a simple send and receive UDP program working, but I'm having a bit of trouble with saving the received data. As far as I can tell the data is being sent and received properly, as I've printed it out on both ends. Before I write the data to the file (if I just print out the received chunk) it doesn't have any extra characters, so I'm a bit lost as to where they are coming from.
When I append each chunk of received data to the file it adds a "^P^B^GÐ^?" after every chunk written. for example one of the chunks ended with "We, therefore^P^B^GÐ^?," instead of "We, therefore,".
Any help is appreciated, thanks in advance.
UPDATE:
I've seemed to have gotten things working semi-better, I'm now having an issue with it replacing the first character of every chunk with a null character, for example:
"^#N CONGRESS, July 4, 1776." instead of "IN CONGRESS, July 4, 1776."
It's doing this for the first char of every chunk received, I've tried multiple debug print statements but can't seem to figure out what the issue is.
Here is my Receive and Send functions:
void receiveFile() {
int addr_len, bytesRead;
char recvData[BUFSIZE]; // Buffer to store received data
struct sockaddr_in server_addr, client_addr;
// Set up struct to receive data from our port and address
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero), 8);
addr_len = sizeof (struct sockaddr);
printf("\nWaiting for data on port %d\n", port);
//Keep reading data from the socket
while (1) {
FILE *fp;
fp=fopen("dummyfile.txt", "ab");
memset(recvData, 0, BUFSIZE);
bytesRead = recvfrom(sock, recvData, BUFSIZE, 0,
(struct sockaddr *) &client_addr, &addr_len);
int x;
for(x = 0; x < bytesRead; x++) {
fputc(recvData[x], fp);
}
// Print out who we're receiving from and what we're recieving
printf("Receiving data from %s : %d\n", inet_ntoa(client_addr.sin_addr),
ntohs(client_addr.sin_port));
fclose(fp);
}}
Here is the Send Function:
void sendFile() {
// Announce who we're sending data to
if(DEBUG) { printf("\nSending %s to %s:%d\n", filename, address, port); }
// Open file
FILE * file = fopen(filename, "rb");
if (file == NULL) {
perror("Invalid File\n");
exit(1);
}
// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);
int curPos = 0;
int dataSize = 0;
while(curPos < filesize) {
struct sockaddr_in server_addr;
struct hostent *recvr;
char sendData[BUFSIZE]; // stores message to be sent
memset(sendData, 0, BUFSIZE);
int byte, i;
for(i = 0; i < BUFSIZE; i++){
if((filesize - curPos) > 0) {
byte = fgetc(file);
sendData[i] = byte;
curPos++;
dataSize++;
}
else { break; }
}
recvr = gethostbyname(address);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *) recvr->h_addr);
bzero(&(server_addr.sin_zero), 8);
if(DEBUG) {
char tempData[1201];
strncpy(tempData, sendData, 1200);
tempData[1201] ='\0';
printf("%s\n\n\n\n\n", tempData);
}
sendto(sock, sendData, dataSize, 0,
(struct sockaddr *) &server_addr, sizeof (struct sockaddr));
dataSize = 0;
}
fclose(file);}
What happens when you change the printing to:
fprintf(fp, "%.*s", bytesRead, recvData);
There is a guarantee that recvfrom() will not null terminate your messages; you would have to transmit the null terminator yourself.
I can't tell what your residual problem is. I have the following to complete programs working back to back. I've scrutinized the saved file for NULs with no problem.
I ran them as:
./recv & sleep 1; ./send; kill %1
recv.c
#include "posixver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h> /* sockaddr_in */
#include <arpa/inet.h> /* inet_ntoa() */
#include "stderr.h"
static void receiveFile(int sock, int port, char *filename)
{
//Keep reading data from the socket
FILE *fp = fopen(filename, "ab");
if (fp == 0)
err_syserr("failed to open file %s", filename);
printf("\nWaiting for data on port %d\n", port);
while (1)
{
char recvData[BUFSIZ]; // Buffer to store received data
struct sockaddr_storage addr;
struct sockaddr_in *client_addr = (struct sockaddr_in *)&addr;
memset(recvData, 0, sizeof(recvData));
socklen_t addr_len = sizeof (struct sockaddr_storage);
int bytesRead = recvfrom(sock, recvData, sizeof(recvData), 0,
(struct sockaddr *) &client_addr, &addr_len);
if (bytesRead < 0)
err_syserr("Failed to read from socket");
err_remark("Read %d bytes\n", bytesRead);
for (int x = 0; x < bytesRead; x++)
{
fputc(recvData[x], fp);
}
fflush(fp);
// Print out who we're receiving from and what we're receiving
//char *rem_host = inet_ntoa(client_addr->sin_addr);
//int rem_port = ntohs(client_addr->sin_port);
//printf("Receiving %d bytes from %s:%d\n", bytesRead, rem_host ? rem_host : "<unknown>", rem_port);
}
fclose(fp);
}
int main(int argc, char **argv)
{
int fd;
struct sockaddr_storage addr;
struct sockaddr_in *server_addr = (struct sockaddr_in *)&addr;
memset(&addr, 0, sizeof(addr));
server_addr->sin_family = AF_INET;
server_addr->sin_addr.s_addr = htonl(INADDR_ANY);
server_addr->sin_port = htons(5190);
err_setarg0(argv[0]);
if (argc > 1)
err_usage("");
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_syserr("Failed to open DGRAM socket");
if (bind(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
err_syserr("Failed to bind DGRAM socket");
receiveFile(fd, 5190, "dummy.text");
return(0);
}
send.c
#include "posixver.h"
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include "stderr.h"
#define bzero(b,len) (memset((b), '\0', (len)), (void)0)
enum { DEBUG = 1 };
static void sendFile(int sock, const char *filename, char *address, int port)
{
// Announce who we're sending data to
if (DEBUG)
printf("\nSending %s to %s:%d\n", filename, address, port);
// Open file
FILE * file = fopen(filename, "rb");
if (file == 0)
err_syserr("Failed to open file %s", filename);
// Get size of the file
fseek(file, 0, SEEK_END);
int filesize = ftell(file);
rewind(file);
int curPos = 0;
int dataSize = 0;
while (curPos < filesize)
{
struct sockaddr_in server_addr;
struct hostent *recvr;
char sendData[BUFSIZ]; // stores message to be sent
memset(sendData, 0, BUFSIZ);
int byte, i;
for (i = 0; i < BUFSIZ; i++){
if ((filesize - curPos) > 0) {
byte = fgetc(file);
sendData[i] = byte;
curPos++;
dataSize++;
}
else
break;
}
recvr = gethostbyname(address);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr = *((struct in_addr *) recvr->h_addr_list[0]);
bzero(&(server_addr.sin_zero), 8);
if(DEBUG) {
char tempData[1201];
strncpy(tempData, sendData, 1200);
tempData[1201] ='\0';
printf("SEND:\n%s\n\n\n", tempData);
}
if (sendto(sock, sendData, dataSize, 0,
(struct sockaddr *) &server_addr, sizeof (struct sockaddr)) < 0)
err_syserr("Failed to send %d bytes\n", dataSize);
dataSize = 0;
}
fclose(file);
}
int main(int argc, char **argv)
{
int fd;
err_setarg0(argv[0]);
if (argc > 1)
err_usage("");
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
err_syserr("Failed to open DGRAM socket");
sendFile(fd, "/etc/passwd", "localhost", 5190);
return(0);
}
posixver.h
#ifndef JLSS_ID_POSIXVER_H
#define JLSS_ID_POSIXVER_H
/*
** Include this file before including system headers. By default, with
** C99 support from the compiler, it requests POSIX 2001 support. With
** C89 support only, it requests POSIX 1997 support. Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/
/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */
#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600 /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500 /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */
#endif /* JLSS_ID_POSIXVER_H */
stderr.c and stderr.h
Actually, not standard at all, except in my code. The functions used have the declarations:
extern void err_setarg0(const char *argv0);
extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_usage(const char *usestr) NORETURN();
The first records the program name. The second reports an error message and exits; the third reports a message and returns; the fourth reports an error message and adds error information from 'errno' and 'strerror()' if there is any to use; the last reports on how to use the program - in this case, the programs accept no arguments. The full source code (quite large) is available from the IIUG Software site as part of the SQLCMD package available there, and various other programs that I've also submitted there.

Resources