Solved

C Programming: Returning array of char pointers

Posted on 2013-10-27
2
442 Views
Last Modified: 2013-10-28
I'm having trouble with my code (deflect.c), and can't figure it out for the past 12 hours.

On line 407, I call the readConfig() method, but it returns nothing, and my log file has almost nothing written to it.

Inside the readConfig() method, on line 285, I call the fetchHTML() method, and it seems to return the string I need because when I do fprintf(), I can see it in the log file for the readConfig() method. But when I try to return the that string, nothing gets returned.

Question:
Am I calling and returning my array of chars correctly in fetchHTML() and readConfig() methods? If so, then what else can be causing the issue?

Below is the C file, called "deflect.c". It's the "server" side of things.

For testing purposes, I am also including the "client" C file called "twist.c", as well as the config.txt file.

Example situation:
./deflect 1 config.txt 1 9000

./twist http://www.facebook.com 9000

deflect.c
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <errno.h>
#include <malloc.h>

#define DAEMON_NAME "vdaemon"

char ** fetchHTML(char *uri, char *host) {

	FILE *fpHTML=NULL;
	// Open a log file in write mode.
	fpHTML = fopen ("/home/users1/pz951772/html_log.txt", "w+");
	fprintf(fpHTML, "Logging info...\n");
	
	struct hostent *h;
	struct in_addr **addr_list;
	
	if((h = gethostbyname(host)) == NULL) {
		fprintf(fpHTML, "Couldn't get host by name.\n");
		fflush(fpHTML);
		return NULL;
	}
	else {
		fprintf(fpHTML, "gethostbyname() success.\n");
	}
	addr_list = (struct in_addr **)h->h_addr_list;
	
	const char *ipAddr = inet_ntoa(*addr_list[0]); //gethostbyname
	fprintf(fpHTML, "IP addr: %s\n", ipAddr);
	
	socklen_t peer_addr_size;

	int conStatus;
	const char *protocolName = "tcp";
	
	int sockfd;
	struct protoent *myProtocol = getprotobyname(protocolName);
	struct sockaddr_in sockIP4addr;
	struct sockaddr *peerSockAddr;

	int max_input = 4000;
	char **buffer;
	buffer = malloc( max_input * sizeof(char*));
	if(!buffer) {
		fprintf(fpHTML, "Couldn't malloc buffer.\n");
		fflush(fpHTML);
		return NULL;
	}
	else {
		fprintf(fpHTML, "malloc buffer success.\n");
	}
		
		
	size_t count = 4000;
	ssize_t bytes_read;
	size_t requestLen;

	sockIP4addr.sin_family = AF_INET;
	sockIP4addr.sin_port = htons(80);
	// store IP addr in sockIP4addr structure
	inet_pton(AF_INET, ipAddr, &sockIP4addr.sin_addr);

	sockfd = socket(AF_INET,SOCK_STREAM,myProtocol->p_proto);

	if(sockfd == -1)
		fprintf(fpHTML, "socket() error: %s\n", strerror(errno));
	else {
		fprintf(fpHTML, "socket() success.\n");
	}
	
	peer_addr_size = sizeof(struct sockaddr_in);
	peerSockAddr = (struct sockaddr*)&sockIP4addr;

	// Connect
	conStatus = connect(sockfd, peerSockAddr, peer_addr_size);

	if(conStatus == -1)
	  fprintf(fpHTML, "connect() error: %s\n", strerror(errno));
	else {
		fprintf(fpHTML, "connect() success.\n");
	}
	  
	char *strRequest;
	int myB;
	if((myB = sprintf(strRequest, "GET %s HTTP/1.1\r\nHOST: %s\r\n\r\n",uri,host)) < 0)
		fprintf(fpHTML, "sprintf() error: %s\n", strerror(errno));
	else {
		fprintf(fpHTML, "sprintf() success.\n");
	}
	fflush(fpHTML);
	
	requestLen = strlen(strRequest);
	
	fprintf(fpHTML, "%s\n", strRequest);
	
	if((write(sockfd, strRequest, requestLen)) < 0)
		fprintf(fpHTML, "write() error: %s\n", strerror(errno));
	else {
		fprintf(fpHTML, "write() success.\n");
	}
	
	if(( bytes_read = read(sockfd, buffer, count)) == -1) {
		fprintf(fpHTML, "read() error: %s\n", strerror(errno));
	}
	else {
	  buffer[bytes_read]='\0';
	  fprintf(fpHTML, "read() success.\n");
	  fprintf(fpHTML, "%s\n", buffer);
	}
	
	fflush(fpHTML);
	return buffer;

}

int readConfig(const char *config, char *host) {
   
   FILE *configfp=NULL;
   
   struct stat st;
   ssize_t bytes_read;
   size_t count = 400;
   char *buffer;
   char *ch;
   char *Lines[100];
   char LastChar;
   int fd;
   int LineCount;
   off_t size;
   
   stat(config, &st);
   size = st.st_size;
   
   buffer = (char *) malloc(size + 1);
   
   // Open a log config file in write mode.
   configfp = fopen ("/home/users1/pz951772/config_log.txt", "w+");
   fprintf(configfp, "Config Log...\n");

   // open config file
   if( (fd = open(config, O_RDWR)) == -1 ) {
		fprintf(configfp,"open() error: %s: %s\n",strerror(errno),config);
		fflush(configfp);
   }
   
   // read config file line by line
   if(( bytes_read = read(fd, buffer, size)) == -1) {
		fprintf(configfp, "read() error: %s\n", strerror(errno));
		fflush(configfp);
   }
   else if( bytes_read == 0) {   /* EOF */
		fprintf(configfp, "zero bytes read.\n");
		fflush(configfp);
   }
   else {
		
		// with \r\n in each end of line in buffer, file is one long string
		// make all lines end with 0, and make them behave as strings
		buffer[size] = '\0';
		
		for(ch = buffer; *ch; ++ch) {
			if(*ch == '\r' || *ch == '\n')
				*ch = '\0';
		}
		
		// build array of pointers, pointing to each line in config
		for(LineCount=0,LastChar='\0',ch=buffer;ch-buffer < size; ++ch){
			if(LastChar == '\0') {
				if(*ch) // ignore consecutive zero characters
					Lines[LineCount++] = ch;
			}
			LastChar = *ch;
		}		
		close(fd);
		
		// parse host to strip http:// and any dirs
		// *************************************
		char src[50];
		char dest[100];
		char *httpProto = "http://";
		
		if((strstr(host, httpProto)) != NULL) { //does host contain http://
			memset(dest, '\0', sizeof(dest));
			strcpy(dest, host+strlen(httpProto));
			fprintf(configfp,"Stripped HTTP:\n%s\n",dest);
			// http:// stripped -- use dest
		}
		// *************************************
		
		// copy chars off to the hostName until you find "/" or '\0'
		// *************************************
		char request[50];
		char hostName[100];
		int a = 0, b = 0, forwardSlash = 0;
		
		// **********USE DEST************
		
		if((strstr(host, httpProto)) != NULL) { // host contains http://
			for(a=0; dest[a] != '\0'; a++) { //copy domain name into hostName
				if(dest[a] != '/') {
					hostName[a] = dest[a];
				}
				else { // forward slash found
					forwardSlash = 1;
					break;
				}
			}
			if(dest[a] == '\0')
				hostName[a] = '\0'; 
			
			while( (forwardSlash == 1) && (dest[a] != '\0')) { 
				request[b] = dest[a];
				a++;
				b++;
			}
			if( (forwardSlash == 1) && (dest[a] == '\0'))
				request[b] = '\0';
		}
		// **********USE HOST***************
		
		else { // host didn't contain http:// to begin with
			for(a=0; host[a] != '\0'; a++) { //copy domain name into hostName
				if(host[a] != '/') {
					hostName[a] = host[a];
				}
				else { // forward slash found
					forwardSlash = 1;
					break;
				}
			}
			if(host[a] == '\0')
				hostName[a] = '\0';
				
			while( (forwardSlash == 1) && (host[a] != '\0')) { 
				request[b] = host[a];
				a++;
				b++;
			}
			if( (forwardSlash == 1) && (host[a] == '\0'))
				request[b] = '\0';
		}
		
		if(forwardSlash == 0) {
			request[0] = '/';
			request[1] = '\0';
		}
		
		fprintf(configfp,"Host:\n%s\n",host);
		fprintf(configfp,"Domain:\n%s\n",hostName);
		fprintf(configfp,"Request: \n%s\n",request);
		// *************************************
		int i,j,k,m=0;
		char *t1;
		char **html;
		for(i=0; i < LineCount; i++) { // for each line, 
									   // check if hostName in config file
									   // and fetch HTML
									   
			if(*Lines[i] != '#') { // ignore comment lines

				fprintf(configfp,"%s\n",Lines[i]);
				fprintf(configfp,"%s\n",host);
				char *p;
				//if( p[19] != '~' )
				if((p = strstr(Lines[i], host)) != NULL) {
					// found host in config file
					fprintf(configfp, "R:%c %d\n",p[19],p[19]);
					
					if(strstr(Lines[i], "redirected") != NULL) {
					// ***************************************
						if((html=fetchHTML(request, hostName)) != NULL)
							fprintf(configfp,"Redirected:\n%s\n\n",html);
						else
							fprintf(configfp,"fetchHTML() error.\n");
						
						fprintf(configfp, "\nReidrected: Return 1\n");
						fflush(configfp);
						return 1;
					}
					
					else if(strstr(Lines[i], "filtered") != NULL) {
					// ***************************************
						fflush(configfp);
						return 2;
					}
					
					else if(strstr(Lines[i], "cached") != NULL) {
					// ***************************************
						if((html=fetchHTML(request, hostName)) != NULL)
							fprintf(configfp,"Cached:\n%s\n\n",html);
						else
							fprintf(configfp,"fetchHTML() error.\n");
						fflush(configfp);
						return 3;
					}
				}
				else { // couldn't find host in config file
					m = -1;
				}
			}
		}
		// ***************************************
		if((html=fetchHTML(request, hostName)) != NULL)
			fprintf(configfp,"Not in config:\n%s\n\n",html);
		else
			fprintf(configfp,"fetchHTML() error.\n");
			
		fflush(configfp);
		fclose(configfp);
		
		return m;
   }
}

void communicate(const char *port, const char *conf) {
   FILE *fp=NULL;
   socklen_t peer_addr_size;

   const char *protocolName = "tcp";
   const char *ipAddr = "127.0.0.1";
   int portNo = atoi(port); //argc = 5
   int sockfd, csockfd, bindStatus, listenStatus, conStatus;
   int mybacklog = 50;
   int my_inet_addr_len = 16;
   struct protoent *myProtocol = getprotobyname(protocolName);
   struct sockaddr_in sockIP4addr, peerIP4addr;
   struct sockaddr *mySockAddr, *peerSockAddr;
   
   int max_input = 200;
   char buffer[max_input];
   size_t count = 200;
   ssize_t bytes_read;
   size_t blen;
   char peerIPstr[INET_ADDRSTRLEN];
   
   // Open a log file in write mode.
   fp = fopen ("/home/users1/pz951772/log.txt", "w+");
   fprintf(fp, "Logging info...\n");
   fflush(fp);
   
   sockIP4addr.sin_family = AF_INET;
   sockIP4addr.sin_port = htons(portNo);
   inet_pton(AF_INET, ipAddr, &sockIP4addr.sin_addr);

   // Create Socket
   sockfd = socket(AF_INET,SOCK_STREAM,myProtocol->p_proto);
   
   if(sockfd == -1)
      perror("socket() error");
   else
      fprintf(fp, "socket() success\n");
   
   mySockAddr = (struct sockaddr*)&sockIP4addr;
   
   // Bind Socket
   bindStatus = bind(sockfd, mySockAddr, sizeof(struct sockaddr_in));
   
   if(bindStatus == -1)
      fprintf(fp, "bind() error %s\n", strerror(errno));
   else
      fprintf(fp, "bind() success\n");
    
	// Listen
   if (listen(sockfd, mybacklog) == -1)
      fprintf(fp, "listen() error: %s\n", strerror(errno));
   else
      fprintf(fp, "listen() success\n");

   peer_addr_size = sizeof(struct sockaddr_in);
   peerSockAddr = (struct sockaddr*)&peerIP4addr;
   
   // Accept connections - peerSockAddr is filled in with RemoteAddr
   csockfd = accept(sockfd, peerSockAddr, &peer_addr_size);
   
   if(csockfd == -1)
      fprintf(fp, "accept() error %s\n", strerror(errno));
   else {
      fprintf(fp, "Accepted()\nPeer port: %d\nMy port: %d\n", ntohs(peerIP4addr.sin_port),ntohs(sockIP4addr.sin_port));
	  fprintf(fp, "Peer IP: %s\n", inet_ntop(AF_INET, &peerIP4addr.sin_addr, peerIPstr, INET_ADDRSTRLEN));
   }

   char *reply="";
   do
   {
      fprintf(fp, "Logging info while...\n");

      if(( bytes_read = read(csockfd, buffer, count)) == -1)
			fprintf(fp, "read() error %s\n", strerror(errno));
	   else {
			buffer[bytes_read]='\0';
			int hostExist = 0;
			
			if((hostExist = readConfig(conf, buffer)) == -1) {
				reply = "host does not exist\n";
			}
			else if( hostExist == 1) {
				reply = "host redirected\n";
			}
			else if( hostExist == 2) {
				reply = "host filtered\n";
			}
			else if( hostExist == 3) {
				reply = "host cached\n";
			}
			else {
				reply = "error on readConfig()\n";
			}			
			fprintf(fp, "%s\n", reply);
			fflush(fp);
       }
	  sleep(1);
	  blen = strlen(reply);
      if((write(csockfd, reply, blen)) < 0)
	     fprintf(fp, "write() error %s\n", strerror(errno));
	  else
	     fprintf(fp, "write() success: %s\n", reply);
		 
	  fflush(fp);
		 
   } while (0);
   
   fclose(fp);
   
}

int main( int argc, char *argv[] ) {

   //Set our Logging Mask and open the Log
   /*setlogmask(LOG_UPTO(LOG_NOTICE));
   openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
   
   syslog(LOG_INFO, "Entering Daemon");
   */
   pid_t process_id = 0, sid = 0;
	  
   // Get Current Working Directory
   long sizeCWD;
   char *bufCWD;
   char *ptrCWD;
   
   sizeCWD = pathconf(".", _PC_PATH_MAX);
   
   if(( bufCWD = (char *)malloc((size_t)sizeCWD)) != NULL)
		ptrCWD = getcwd(bufCWD, (size_t)sizeCWD);

   // Specify absolute path for config file
   strcat(ptrCWD, "/");
   strcat(ptrCWD, argv[2]);

   // Create child process
   process_id = fork();
   
   // fork() failure
   if (process_id < 0)
   {
      printf("fork failed!\n");
	  // return exit status
	  exit(1);
   }
   
   // PARENT PROCESS -- KILL IT
   if (process_id > 0)
   {
      printf("process_id of child process %d \n", process_id);
	  // return success in exit status
	  exit(0);
   }
   
   //unmask the file mode
   umask(0);
   
   // set new session
   sid = setsid();
   if(sid < 0)
   {
      // Return failure
	  exit(1);
   }
   
   // Change the current working directory to root
   chdir("/");
   
   // Close stdin. stdout and stderr
   close(STDIN_FILENO);
   close(STDOUT_FILENO);
   close(STDERR_FILENO);
   

   
   //-------------------
   //Main Process
   //-------------------
   
   communicate(argv[4], ptrCWD);
   
   //Close the log
   //closelog();
   
}

Open in new window


twist.c
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

int main( int argc, char *argv[] ) {

   socklen_t peer_addr_size;
   
   int conStatus;
   const char *protocolName = "tcp";
   const char *ipAddr = "127.0.0.1";
   int sockfd;
   struct protoent *myProtocol = getprotobyname(protocolName);
   struct sockaddr_in sockIP4addr;
   struct sockaddr *peerSockAddr;
   
   int max_input = 200;
   char buffer[max_input];
   size_t count = 200;
   ssize_t bytes_read;
   size_t hostlen;
   
   sockIP4addr.sin_family = AF_INET;
   sockIP4addr.sin_port = htons(atoi(argv[2]));
   inet_pton(AF_INET, ipAddr, &sockIP4addr.sin_addr);

   sockfd = socket(AF_INET,SOCK_STREAM,myProtocol->p_proto);
   
   if(sockfd == -1)
      perror("socket() error");
   
   peer_addr_size = sizeof(struct sockaddr_in);
   peerSockAddr = (struct sockaddr*)&sockIP4addr;
   
   // Connect
   conStatus = connect(sockfd, peerSockAddr, peer_addr_size);
   
   if(conStatus == -1)
      perror("connect() error");
	  
   const char *host = argv[1];
   hostlen = strlen(host);

   if((write(sockfd, host, hostlen)) < 0)
      perror("write() error");

   if(( bytes_read = read(sockfd, buffer, count)) == -1)
      perror("read() error");
   else if( bytes_read == 0) {
      exit(1);
   }
   else {
      buffer[bytes_read]='\0';
   }

   printf("%s\n", buffer);
	  


}

Open in new window


config.txt
# Example Configuration File for deflect:  
# deflect:  Daemon for HTTP Egress, Filtering, Load balancing, and Caching Trivially
#
# URL-prefix			Disposition	Host list

http://www.csun.edu/		redirected	130.166.238.195, redwing.csun.edu
http://www.facebook.com/	filtered
http://www.csun.edu/~steve/	cached		www.csun.edu

# Note that any URL that is not covered by any rule is transferred through the system 
# without any additional processing.

Open in new window

0
Comment
Question by:pzozulka
2 Comments
 
LVL 24

Accepted Solution

by:
chaau earned 250 total points
ID: 39604851
It is not a good idea to return a buffer that has been allocated in a function you are calling. It will be better if you change the function fetchHTML the way function read (that you are using in line 116) is written, i.e.:
int fetchHTML(const char *uri, const char *host, char* buffer, int maxSize) 
{
    // do your stuff and fill the buffer. If the size of the read information is greater 
    // than maxSize return 0 or -1 (even better, return the number of bytes required). 
    // Otherwise return the number of read bytes
    // Do not allocate the buffer inside this function
}

Open in new window

Then in your main code you would call this function with some small buffer (or even with buffer = NULL) and check for the return code to see if how many bytes required. Then allocate memory for the buffer and call it again.

BTW, if you really want to use your code, you can still use it. You need to change the function signature to:
char * fetchHTML(char *uri, char *host)

Open in new window

and change lines 55,56 to these:
	char *buffer;
	buffer = malloc( max_input * sizeof(char));

Open in new window

.
And of course html must be declared as char* in your readConfig().

BTW, have you noticed the in your readConfig you never free() the memory at html address. These lines should have something like this:
		if((html=fetchHTML(request, hostName)) != NULL) 
{
			fprintf(configfp,"Not in config:\n%s\n\n",html);
                        free(html);
}
		else
			fprintf(configfp,"fetchHTML() error.\n");

Open in new window

0
 
LVL 51

Assisted Solution

by:Julian Hansen
Julian Hansen earned 250 total points
ID: 39604880
I am not sure I agree 100% with chaau on the malloc issue on the basis that calling the function twice means making the HTML request twice - seems a bit inefficient to me - unless I misunderstood something.

The point about keeping the malloc out of the function is to avoid memory leaks - multiple calls to the function (forggeting to free the previous buffer) - could result in a memory leak.

However this is easily solved using a static buffer in the function.

If the buffer can be variable - start with a reasonable size and check on each call if it is big enough and realloc if it is not.

If required you can have a specific parameter call to delete the buffer to clean up on application termination.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now