Solved

C Programming: Returning array of char pointers

Posted on 2013-10-27
2
463 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
2 Comments
 
LVL 25

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 57

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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
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 how to create, access, and change arrays in the C programming language.

752 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