Handle query strings using socket programming

Hi, I need to make a daemon which listens to port 81 for messages like http://localhost/message?command=move&dir=left
So far I made a daemon which serves as a simple stream server: I set up a socket to listen to a non-reserved port (like 9999), but I don't know how to read the query strings.

Linux distro: Kubuntu 9.04
Language: C
Last edited on
closed account (S6k9GNh0)
Any code?
Why not use Apache and create a CGI program in C?
If you type the address of your demon program into a browser with the query string, then your demon should receive something like this through the socket:


GET /message?key1=value1&key2=value2 HTTP/1.1
Host: localhost
Connection: keep-alive
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.253.0 Safari/532.5
Accept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-GB,en-US;q=0.8,en;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3



That is because the browser takes the URL that includes the query string and writes it to the socket it connects to using the HTTP protocol.

So your demon needs to read in each line from the socket and the first line (that begins with "GET" and ends with "HTTP/..." will contain the raw query string.
Last edited on
PanGalactic wrote:
Why not use Apache and create a CGI program in C?

I can't use Apache, because I have to use this program on an embedded system running OpenWRT. The resources are limited.


Thanks Galic, I'll try that.


computerquip wrote:
Any code?
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
#include <stdlib.h>
#include <syslog.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

#define PORT		81
#define MAXBUF		64
#define SLEEP_TIME 	3
#define COUNT_MAX	3


int main(void)
{
	pid_t pid, sid;
	int status;

	/* Fork off the parent process */
	pid = fork();
	if (pid < 0)
	{
		syslog(LOG_ERR, "fork(): %m");
		exit(EXIT_FAILURE);
	}
	
    /* If we got a good PID, then
	we can exit the parent process. */
	if (pid > 0)
	{
		exit(EXIT_SUCCESS);
	}

	/* Change the file mode mask */
	umask(0);

	/* Create a new SID for the child process */
	sid = setsid();
	if (sid < 0)
	{
		syslog(LOG_ERR, "setsid(): %m");
		exit(EXIT_FAILURE);
	}

	/* Change the current working directory */
	if ((chdir("/")) < 0)
	{
		syslog(LOG_ERR, "chdir(): %m");
		exit(EXIT_FAILURE);
	}

	/* Close out the standard file descriptors */
	status = close(STDIN_FILENO);
	if (status < 0)
	{
		syslog(LOG_ERR, "close(STDIN_FILENO): %m");
		exit(EXIT_FAILURE);
	}
	
	status = close(STDOUT_FILENO);
	if (status < 0)
	{
		syslog(LOG_ERR, "close(STDOUT_FILENO): %m");
		exit(EXIT_FAILURE);
	}
	
	status = close(STDERR_FILENO);
	if (status < 0)
	{
		syslog(LOG_ERR, "close(STDERR_FILENO): %m");
		exit(EXIT_FAILURE);
	}

	//---------------------------------------------------------------------------
	
	int sockfd, clientfd;
	struct sockaddr_in self, client_addr;
	int addrlen = sizeof(client_addr);
	char buffer[MAXBUF], command[8], param[8];
	int count;

	/* Create streaming socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
	{
		syslog(LOG_ERR, "socket(): %m");
		exit(EXIT_FAILURE);
	}

	/* Initialize address/port structure */
	bzero(&self, sizeof(self));
	self.sin_family = AF_INET;
	self.sin_port = htons(PORT);
	self.sin_addr.s_addr = INADDR_ANY;

	/* Assign a port number to the socket */
	status = bind(sockfd, (struct sockaddr*) &self, sizeof(self));
	if (status < 0)
	{
		syslog(LOG_ERR, "bind(): %m");
		exit(EXIT_FAILURE);
	}
	
	/* Make it a "listening socket" */
	status = listen(sockfd, 20);
	if (status < 0)
	{
		syslog(LOG_ERR, "listen(): %m");
		exit(EXIT_FAILURE);
	}
	
	/* The Big Loop */
	while (1)
	{
		/* Accept a connection (creating a data pipe) */
		count = COUNT_MAX;
		do {
			clientfd = accept(sockfd, (struct sockaddr*) &client_addr, &addrlen);
			if (clientfd < 0)
			{
				syslog(LOG_ERR, "accept(): %m");
				count--;
				sleep(SLEEP_TIME); // Wait
			}
		} while (status < 0 && count > 0);
		if (count <= 0)
			exit(EXIT_FAILURE);

		/* Receive message */
		status = recv(clientfd, buffer, MAXBUF, 0);
		if (status < 0)
			syslog(LOG_ERR, "recv(): %m");
		else if (status > 0)
		{

		}

		/* Close data connection */
		count = COUNT_MAX;
		do {
			status = close(clientfd);
			if (status < 0)
			{
				syslog(LOG_ERR, "close(clientfd): %m");
				count--;
				sleep(SLEEP_TIME); // Wait
			}
		} while (status < 0 && count > 0);
		if (count <= 0)
			exit(EXIT_FAILURE);
	}

	/* Clean up */
	count = COUNT_MAX;
	do {
		status = close(sockfd);
		if (status < 0)
		{
			syslog(LOG_ERR, "close(sockfd): %m");
			count--;
			sleep(SLEEP_TIME); // Wait
		}
	} while (status < 0 && count > 0);
	if (count <= 0)
		exit(EXIT_FAILURE);

	/* Everything went well */
	exit(EXIT_SUCCESS);
}
Cool. I have an OpenWRT router. So, let me ask it this way: "Why not use BusyBox's httpd and create a CGI program in C?"
PanGalactic wrote:
Why not use BusyBox's httpd and create a CGI program in C?

Because I didn't know of its existence. I'm new to programming, not only in Linux, but also in network related stuff, so there are many things I don't know.

Thanks for your help, now it's time to get my hands dirty.
I finally managed to get the query string. I wasn't reading/parsing the buffer correctly because I didn't know the format. Thank you for your help.
Topic archived. No new replies allowed.