TCP server and process client request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
New to the forum, 
I run it with this code executable, localhost and a port number on one terminal. On the other terminal i run a given TCP client program, localhost, same port number, and the "GET /" string. On the first terminal says recieve: success. It does with other GET commands as well. Is it going to the error after the read? If so how do i make it so it processes the GET correctly?
Thanks

my code is:
/*
TCP server program 
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sstream>

[code]using namespace std;

// function to run the child process
void processRequest(int connSock)
{
	char buffer[1024],
		 path[1024];
	int file;
		 
// read a message from the client			 
	if ((read(connSock, path, sizeof(path))) < 0);
	{
		perror("recieve");
		exit(EXIT_FAILURE);
	}
	 
	string Spath(path);
	
	string v1, v2;

// separate the path after the GET
	std::istringstream iss(Spath);
	iss >> v1;
	iss >>v2;

// decisions for determining if correctly typed by client
	if (v1 == "GET")
	{		  								 	
		if (v2.at(0) == '/' && v2.find("..") != string::npos)				
		{	
			if (v2 == "/")
			v2.append(".");
		}
		
		else
		{
			perror("invalid path");
			exit(EXIT_FAILURE);
		}
	}
	 
	else
	{
		perror("no GET");
		exit(EXIT_FAILURE);
	}

// create stat to determine if the path entered
// by the client is a file or directory
	struct stat newPath;
	
	if(S_ISREG(newPath.st_mode)) {}	
	if(S_ISDIR(newPath.st_mode)) {}
				  
// open directory	
	DIR *dirp = opendir(path);
		
	if (dirp == 0) 
	{
// tell client that an error occurred
// duplicate socket descriptor into error output
		close(2);
		dup(connSock);
		perror(path);
		exit(EXIT_SUCCESS);
	}
		 
// read directory entries
	struct dirent *dirEntry;
		
	while ((dirEntry = readdir(dirp)) != NULL) 
	{
		strcpy(buffer, dirEntry->d_name);
				
		if (write(connSock, buffer, strlen(buffer)) < 0) 
		{
			perror("write");
			exit(EXIT_FAILURE);
		}

// if the directory has index.html send it to client
		if (strcmp(buffer, "index.html"))
		{
			if (write(connSock, path, strlen(path)) < 0) 
			{
				perror("write");
				exit(EXIT_FAILURE);
			}
		}
				 
		else
		{
			strcat(buffer, " ");
		
			if (write(connSock, buffer, strlen(buffer)) < 0) 
			{
				perror("write");
				exit(EXIT_FAILURE);
			}
		}
	}
			 		  
	closedir(dirp);
	
//open the file and display if not a directory
	file = open(path, O_RDONLY);
			 
	if (file == -1)
	{
		cerr << path;
		exit(EXIT_FAILURE);
	}

// print contents of file if the path is a file	  	  
	if (file != -1)
	{
		strcpy(buffer, "... content of ");
		strcat(buffer, path);
		strcat(buffer, "\n");
		strcat(buffer, ".... ");
	}		  	
	
	close(file);
	 
	close(connSock);
	exit(EXIT_SUCCESS);
 }
 
int main(int argc, char* argv[]) 
{
	if (argc != 3) 
	{
		cerr << "USAGE: echoTCPClient server_ip port message\n";
		exit(EXIT_FAILURE);
	}
	int sock = socket(AF_INET, SOCK_STREAM, 0);
	
	if (sock < 0) 
	{
		perror("socket");
		exit(EXIT_FAILURE);
	}
	 	
// create address structures
	struct sockaddr_in server_address;  // structure for address of server
	struct sockaddr_in client_address;  // structure for address of client
	unsigned int addrlen = sizeof(client_address);	

// Construct the server sockaddr_in structure 
	memset(&server_address, 0, sizeof(server_address));   
	server_address.sin_family = AF_INET;                 
	server_address.sin_addr.s_addr = INADDR_ANY;         
	server_address.sin_port = htons(atoi(argv[1]));       

// Bind the socket
	if (bind(sock, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) 
	{
		perror("bind");
		exit(EXIT_FAILURE);
	}	
	 
	if (listen(sock, 64) < 0) 
	{
		perror("listen");
		exit(EXIT_FAILURE);
	}
	 
	while (true) 
	{
		int connSock = accept(sock, (struct sockaddr *) &client_address, &addrlen);
		
		if (connSock < 0) 
		{
			perror("accept");
			exit(EXIT_FAILURE);
		}
		 
		if (fork())
		  close(connSock);
		else
		  processRequest(connSock);
	}
	 
	close(sock);	
	return 0;
}
   
Last edited on
Can you please use the code format tags to format your code.

There's a bit going on that doesn't make sense, it looks like a lot of pasting from different examples.

Take your treatment of fork(), or dup(connSock) or the processing of the input string as examples.

Any chance of reviewing your code and fixing the basics before moving on to processing the input?
I am mainly just looking for help on the proccessRequest(). The rest was given by the teacher.
That code will generate a new zombie process for every client connection.
should I call the wait() process for the parent somewhere to get rid of the zombie process?
you should think about what you want it to DO.
when a user disconnects, you need to destroy or recycle the connection.
when a user connects, you create or assign one.

It looks like you are starting with too much stuff. Do your programs work now? If not:
Get a small program working that uses a subset of the code and build up. Can you make a client and server program, run them on 2 machines or VMs or whatever, and tell each other one string of test data that you write to the screen?

I want the program to open given directories and files.
The program compiles, and it sends the receive perror back to the server when I try anything from an already given client program.
If I just use the open directory code of the processRequest() it works, but I don't know how to fix what I have now.
Your mis-placed ; means you have this
1
2
3
4
5
6
7
8
9
// read a message from the client			 
	if ((read(connSock, path, sizeof(path))) < 0)
	{
		// Do nothing.
	}
	{
		perror("recieve");
		exit(EXIT_FAILURE);
	}


Also, read() does NOT append a \0 to make it a proper C-style string.
So you would need something like
1
2
3
ssize_t len = read(connSock, path, sizeof(path));
// error check
string Spath(path,len);


You also need to be aware that socket streams only preserve byte order. The client might send "GET foo" in a single call, but you might end up reading only "GE" on the first read call. You would have to call read again (and again) to eventually fetch all of "GET foo".
On a localhost connection, you're probably OK.
But when you're talking to a remote with random bandwidth issues at any point along the way, you will end up with message fragmentation, and correct reassembly is something you need to cater for.

Topic archived. No new replies allowed.