Browse Source

Initial import

Georgi Chorbadzhiyski 13 years ago
commit
1ce770eae5
17 changed files with 1424 additions and 0 deletions
  1. 2
    0
      .gitignore
  2. 25
    0
      Makefile
  3. 141
    0
      asyncdns.c
  4. 19
    0
      asyncdns.h
  5. 106
    0
      http_response.c
  6. 37
    0
      http_response.h
  7. 262
    0
      io.c
  8. 40
    0
      io.h
  9. 42
    0
      libfuncs.h
  10. 171
    0
      list.c
  11. 62
    0
      list.h
  12. 214
    0
      log.c
  13. 43
    0
      log.h
  14. 112
    0
      queue.c
  15. 43
    0
      queue.h
  16. 83
    0
      server.c
  17. 22
    0
      server.h

+ 2
- 0
.gitignore View File

@@ -0,0 +1,2 @@
1
+*.o
2
+*.a

+ 25
- 0
Makefile View File

@@ -0,0 +1,25 @@
1
+CC = $(CROSS)$(TARGET)gcc
2
+LINK = $(CROSS)$(TARGET)ld -o
3
+LIBRARY_LINK_OPTS =  -L. -r
4
+CFLAGS = -ggdb -Wall -Wextra -Wshadow -Wformat-security -O2
5
+RM = /bin/rm -f
6
+Q=@
7
+
8
+OBJS = queue.o list.o io.o log.o http_response.o asyncdns.o server.o
9
+PROG = libfuncs.a
10
+
11
+all: $(PROG)
12
+
13
+$(PROG): $(OBJS) 
14
+	$(Q)echo "  LINK	$(PROG)"
15
+	$(Q)$(LINK) $@ $(LIBRARY_LINK_OPTS) $(OBJS)
16
+
17
+%.o: %.c libfuncs.h
18
+	$(Q)echo "  CC	libfuncs	$<"
19
+	$(Q)$(CC) $(CFLAGS) -c $<
20
+
21
+clean:
22
+	$(Q)echo "  RM	$(PROG) $(OBJS)"
23
+	$(Q)$(RM) $(PROG) *.o core *.core *~
24
+
25
+distclean: clean

+ 141
- 0
asyncdns.c View File

@@ -0,0 +1,141 @@
1
+/*
2
+ * Async DNS resolver
3
+ * Copyright (C) 2009-2010 Unix Solutions Ltd.
4
+ */
5
+
6
+#include <stdio.h>
7
+#include <stdlib.h>
8
+#include <string.h>
9
+#include <netdb.h>
10
+#include <unistd.h>
11
+#include <pthread.h>
12
+#include <errno.h>
13
+#include <arpa/inet.h>
14
+#include <sys/socket.h>
15
+#include <netinet/in.h>
16
+
17
+#include "log.h"
18
+
19
+/* FreeBSD have problems with pathread_cancel so do not use async resolver */
20
+#ifdef __FreeBSD__
21
+
22
+int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
23
+	msec_timeout = msec_timeout;
24
+	active = active;
25
+	struct hostent *hostinfo = gethostbyname(host);
26
+	if (hostinfo == NULL) {
27
+		int local_h_errno = h_errno;
28
+		LOGf("gethostbyname(%s) returned %s", host, hstrerror(local_h_errno));
29
+		return 1; // error
30
+	}
31
+	sockaddr->sin_family = AF_INET;
32
+	sockaddr->sin_port = htons(port);
33
+	sockaddr->sin_addr = *(struct in_addr *)hostinfo->h_addr;
34
+	// LOGf("Not using async resolver! Resolved %s to %s\n", host, inet_ntoa(sockaddr->sin_addr));
35
+	return 0;
36
+}
37
+
38
+#else
39
+
40
+struct url_resolver {
41
+	char *host;
42
+	int port;
43
+	struct sockaddr_in *sockaddr;
44
+	int *status;
45
+};
46
+
47
+static void resolver_cleanup(void *p) {
48
+	if (p)
49
+		freeaddrinfo(p);
50
+}
51
+
52
+static void *resolver_thread(void *indata) {
53
+	struct url_resolver *uri = indata;
54
+	*(uri->status) = 0;
55
+	char *host = uri->host;
56
+	int port = uri->port;
57
+	struct sockaddr_in *sockaddr = uri->sockaddr;
58
+
59
+	int h_err;
60
+	struct addrinfo hints, *addrinfo = NULL;
61
+	memset(&hints, 0, sizeof hints);
62
+
63
+	int state;
64
+	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
65
+	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &state);
66
+	pthread_cleanup_push(resolver_cleanup, NULL);
67
+
68
+	hints.ai_family = AF_INET;
69
+	hints.ai_socktype = SOCK_STREAM;
70
+	h_err = getaddrinfo(host, NULL, &hints, &addrinfo);
71
+
72
+	pthread_cleanup_pop(0);
73
+
74
+	if (h_err == 0) {
75
+		int num_addrs = 0;
76
+		struct addrinfo *p;
77
+		for (p=addrinfo; p!=NULL; p=p->ai_next) {
78
+			struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
79
+			sockaddr->sin_family = AF_INET;
80
+			sockaddr->sin_port = htons(port);
81
+			sockaddr->sin_addr = ipv4->sin_addr;
82
+			char IP[INET_ADDRSTRLEN];
83
+			inet_ntop(p->ai_family, &(sockaddr->sin_addr), IP, sizeof IP);
84
+			num_addrs++;
85
+			// LOGf("Resolved[%d] %s to %s", num_addrs, host, IP);
86
+		}
87
+		freeaddrinfo(addrinfo);
88
+		*(uri->status) = 1;
89
+	} else {
90
+		*(uri->status) = 2;
91
+	}
92
+
93
+	return NULL;
94
+}
95
+
96
+// Returns
97
+//   0 on success
98
+//   1 on error
99
+//   2 on timeout
100
+int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
101
+	pthread_t dns_thread;
102
+	struct url_resolver uri;
103
+	int status = 0;
104
+	uri.host = host;
105
+	uri.port = port;
106
+	uri.sockaddr = sockaddr;
107
+	uri.status = &status;
108
+
109
+	int lactive = 1;
110
+	if (!active)
111
+		active = &lactive;
112
+
113
+	if (pthread_create(&dns_thread, NULL, resolver_thread, &uri)) {
114
+		log_perror("Failed to create resolver thread", errno);
115
+		return 1;
116
+	}
117
+	pthread_detach(dns_thread);
118
+
119
+	#define DNS_SLEEP 20000
120
+	long int waitcount = msec_timeout * 1000;
121
+	while (!status) {
122
+		if (!active) {
123
+			// LOG("Client !active, cancel resolver");
124
+			pthread_cancel(dns_thread);
125
+			return 2;
126
+		}
127
+		usleep(DNS_SLEEP);
128
+		waitcount = waitcount - DNS_SLEEP;
129
+		if (waitcount <= 0) {
130
+			// LOGf("Timed out resolving: %s", host);
131
+			pthread_cancel(dns_thread);
132
+			return 2; // Timed out
133
+		}
134
+	}
135
+
136
+	if (status == 1)
137
+		return 0; // Ok, resolved
138
+
139
+	return 1; // Error resolving
140
+}
141
+#endif

+ 19
- 0
asyncdns.h View File

@@ -0,0 +1,19 @@
1
+/*
2
+ * Async DNS resolver
3
+ * Copyright (C) 2009-2010 Unix Solutions Ltd.
4
+ */
5
+
6
+#ifndef ASYNCDNS_H
7
+# define ASYNCDNS_H
8
+
9
+#include <arpa/inet.h>
10
+#include <netinet/in.h>
11
+#include <sys/socket.h>
12
+
13
+// Returns
14
+//   0 on success
15
+//   1 on error
16
+//   2 on timeout
17
+int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active);
18
+
19
+#endif

+ 106
- 0
http_response.c View File

@@ -0,0 +1,106 @@
1
+/*
2
+ * HTTP responses
3
+ * Copyright (C) 2006-2009 Unix Solutions Ltd.
4
+ */
5
+
6
+#include <stdio.h>
7
+#include <stdarg.h>
8
+#include <netdb.h>
9
+#include <time.h>
10
+
11
+#include "io.h"
12
+
13
+static char *server_signature = NULL;
14
+static char *server_version   = NULL;
15
+
16
+void set_http_response_server_ident(char *server, char *version) {
17
+	server_signature = server;
18
+	server_version   = version;
19
+}
20
+
21
+void send_http_response(int clientsock, const char *response) {
22
+	char buf[128];
23
+	time_t now = time(NULL);
24
+	fdputsf(clientsock, "HTTP/1.0 %s\n", response);
25
+	if (server_signature && server_version)
26
+		fdputsf(clientsock, "Server: %s %s\n", server_signature, server_version);
27
+	strftime(buf,sizeof(buf),"Date: %a, %d %b %Y %H:%M:%S %Z\n",gmtime(&now));
28
+	fdputs(clientsock,buf);
29
+	fdputs(clientsock, "Cache-Control: no-cache\n");
30
+	fdputs(clientsock, "Connection: close\n");
31
+	fdputs(clientsock, "Pragma: no-cache\n");
32
+}
33
+
34
+void send_header_textplain(int clientsock) {
35
+	fdputs(clientsock,"Content-Type: text/plain\n");
36
+}
37
+
38
+void send_http_error(int clientsock, const char *code, const char *message) {
39
+	send_http_response(clientsock, code);
40
+	send_header_textplain(clientsock);
41
+	if (message) {
42
+		fdputsf(clientsock,"X-Error: %s\n", message);
43
+	}
44
+	fdputs(clientsock,"\n");
45
+	fdputsf(clientsock,"%s\n", message ? message : code);
46
+}
47
+
48
+void send_200_ok(int clientsock) {
49
+	send_http_response(clientsock,"200 OK");
50
+}
51
+
52
+void send_http_ok(int clientsock, char *message) {
53
+	send_200_ok(clientsock);
54
+	send_header_textplain(clientsock);
55
+	fdputs(clientsock, "\n");
56
+	fdputs(clientsock, message);
57
+	fdputs(clientsock, "\n");
58
+}
59
+
60
+
61
+void send_http_ok_msg(int clientsock, const char *fmt, ...) {
62
+	char msg[512];
63
+	va_list args;
64
+	va_start(args, fmt);
65
+	vsnprintf(msg, 512, fmt, args);
66
+	va_end(args);
67
+	send_http_ok(clientsock, msg);
68
+}
69
+
70
+void send_302_redirect(int clientsock, char * url) {
71
+	send_http_response(clientsock,"302 Found");
72
+	fdputsf(clientsock,"Location: %s\n", url);
73
+	fdputs(clientsock,"\n");
74
+}
75
+
76
+void send_400_bad_request(int clientsock, const char * msg) {
77
+	send_http_error(clientsock,"400 Bad Request", msg);
78
+}
79
+
80
+void send_403_forbidden_msg(int clientsock, const char *msg) {
81
+	send_http_error(clientsock, "403 Forbidden", msg);
82
+}
83
+
84
+void send_403_forbidden(int clientsock) {
85
+	send_403_forbidden_msg(clientsock, "access-denied");
86
+}
87
+
88
+void send_404_not_found(int clientsock) {
89
+	send_http_error(clientsock, "404 Not Found", NULL);
90
+}
91
+
92
+void send_409_conflict(int clientsock, const char * msg) {
93
+	send_http_error(clientsock, "409 Conflict", msg);
94
+}
95
+
96
+void send_500_internal_server_error(int clientsock, const char * msg) {
97
+	send_http_error(clientsock, "500 Internal Server Error", msg);
98
+}
99
+
100
+void send_501_not_implemented(int clientsock) {
101
+	send_http_error(clientsock, "501 Method Not Implemented", NULL);
102
+}
103
+
104
+void send_504_gateway_timeout(int clientsock) {
105
+	send_http_error(clientsock, "504 Gateway Timeout", "no-signal");
106
+}

+ 37
- 0
http_response.h View File

@@ -0,0 +1,37 @@
1
+/*
2
+ * HTTP responses header file
3
+ * Copyright (C) 2006-2009 Unix Solutions Ltd.
4
+ */
5
+
6
+#ifndef HTTP_RESPONSE_H
7
+# define HTTP_RESPONSE_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+void set_http_response_server_ident(char *server, char *version);
14
+
15
+void send_http_response(int clientsock, const char * response);
16
+void send_header_textplain(int clientsock);
17
+
18
+void send_http_error(int clientsock, const char *code, const char *message);
19
+void send_http_ok(int clientsock, const char *message);
20
+void send_http_ok_msg(int clientsock, const char *fmt, ...);
21
+
22
+void send_200_ok(int clientsock);
23
+void send_302_redirect(int clientsock, const char * url);
24
+void send_400_bad_request(int clientsock, const char *msg);
25
+void send_403_forbidden_msg(int clientsock, const char *msg);
26
+void send_403_forbidden(int clientsock);
27
+void send_404_not_found(int clientsock);
28
+void send_409_conflict(int clientsock, const char * msg);
29
+void send_500_internal_server_error(int clientsock, const char * msg);
30
+void send_501_not_implemented(int clientsock);
31
+void send_504_gateway_timeout(int clientsock);
32
+
33
+#ifdef __cplusplus
34
+}
35
+#endif
36
+
37
+#endif

+ 262
- 0
io.c View File

@@ -0,0 +1,262 @@
1
+/*
2
+ * UX IO functions
3
+ * Copyright (C) 2006-2009 Unix Solutions Ltd.
4
+ */
5
+
6
+/* Needed for POLLRDHUP */
7
+#define _GNU_SOURCE 1;
8
+
9
+#include <stdio.h>
10
+#include <stdlib.h>
11
+#include <stdarg.h>
12
+#include <unistd.h>
13
+#include <string.h>
14
+#include <netdb.h>
15
+#include <arpa/inet.h>
16
+#include <netinet/in.h>
17
+#include <netinet/tcp.h>
18
+#include <sys/utsname.h>
19
+#include <sys/socket.h>
20
+#include <sys/time.h>
21
+#include <sys/types.h>
22
+#include <sys/stat.h>
23
+#include <poll.h>
24
+#include <fcntl.h>
25
+#include <errno.h>
26
+#include <time.h>
27
+
28
+#include "libfuncs.h"
29
+#include "log.h"
30
+
31
+char * chomp(char *x) {
32
+	int i=strlen(x)-1;
33
+	while ((i>=0)&&((x[i]=='\n')||(x[i]=='\r')||(x[i]==' ')||(x[i]=='\t'))){
34
+		x[i--]=0;
35
+	}
36
+	return x;
37
+}
38
+
39
+ssize_t safe_read(int fd, void *buf, size_t len) {
40
+	ssize_t readen;
41
+	do {
42
+		readen = read(fd, buf, len);
43
+		if ((readen < 0) && (errno == EAGAIN || errno == EINTR))
44
+			continue;
45
+		return readen;
46
+	} while (1);
47
+}
48
+
49
+ssize_t safe_write(int fd, const void *buf, size_t len) {
50
+	ssize_t written;
51
+	do {
52
+		written = write(fd, buf, len);
53
+		if ((written < 0) && (errno == EAGAIN || errno == EINTR))
54
+			continue;
55
+		return written;
56
+	} while (1);
57
+}
58
+
59
+void shutdown_fd(int *in_fd) {
60
+	if (*in_fd > -1) {
61
+		shutdown(*in_fd, SHUT_RDWR);
62
+		close(*in_fd);
63
+		*in_fd = -1;
64
+	}
65
+}
66
+
67
+ssize_t fdgetline(int fd, char *buf, size_t buf_size) {
68
+	size_t i=0;
69
+	int intrs = 0;
70
+	int num_timeouts = 0;
71
+	struct pollfd fdset[1];
72
+	fdset[0].fd = fd;
73
+	fdset[0].events = POLLIN;
74
+	if (buf_size <= 0 || fd == -1)
75
+		return 0;
76
+	while (1) {
77
+		int fdready = poll(fdset, 1, FDGETLINE_TIMEOUT);
78
+		if (fdready == -1) {
79
+			if (errno == EINTR) {
80
+				if (++intrs < FDGETLINE_RETRIES)
81
+					continue;
82
+				else
83
+					return i;
84
+			}
85
+			if (num_timeouts++ <= FDGETLINE_RETRIES) {
86
+				continue;
87
+			} else {
88
+				log_perror("fdgetline() timeout", errno);
89
+			}
90
+		}
91
+		if (fdready == 0 || fdready == -1) { /* Timeout || error */
92
+			if (num_timeouts++ <= FDGETLINE_RETRIES)
93
+				continue;
94
+			return 0;
95
+		}
96
+		if (safe_read(fd,buf+i,1)!=1) /* Try to read 1 char */
97
+			break;
98
+		i++;
99
+		if (buf[i-1]=='\n')
100
+			break;
101
+		if (i==buf_size) /* End of buffer reached, get out a here */
102
+			return 0;
103
+	}
104
+	buf[i]='\0';
105
+	return i;
106
+}
107
+
108
+ssize_t fdread_ex(int fd, char *buf, size_t buf_size, int timeout, int retries, int waitfull) {
109
+	ssize_t rbytes = 0;
110
+	int intrs = 0;
111
+	int num_timeouts = 0;
112
+	struct pollfd fdset[1];
113
+	fdset[0].fd = fd;
114
+	fdset[0].events = POLLIN;
115
+	if (buf_size <= 0 || fd == -1)
116
+		return 0;
117
+	while (1) {
118
+		int fdready = poll(fdset, 1, timeout);
119
+		if (fdready == -1 || fdready == 0) { /* Timeout || error */
120
+			if (errno == EINTR) {
121
+				if (++intrs < retries)
122
+					continue;
123
+				else
124
+					return rbytes;
125
+			}
126
+			if (num_timeouts++ <= retries) {
127
+				continue;
128
+			} else {
129
+				if (timeout) {
130
+					log_perror("fdread() timeout", errno);
131
+				}
132
+				return rbytes > 0 ? rbytes : -1;
133
+			}
134
+		}
135
+		ssize_t j = safe_read(fd, buf + rbytes, buf_size - rbytes);
136
+		if (j < 0) // Error reading
137
+			return j;
138
+		if (j == 0) { // No data, retry?
139
+			if (num_timeouts++ > retries) {
140
+				return rbytes;
141
+			}
142
+			continue;
143
+		}
144
+		rbytes += j;
145
+		if (!waitfull)
146
+			return rbytes;
147
+		if (rbytes == (ssize_t)buf_size)
148
+			return rbytes;
149
+	}
150
+	return 0;
151
+}
152
+
153
+ssize_t fdread(int fd, char *buf, size_t buf_size) {
154
+	return fdread_ex(fd, buf, buf_size, FDREAD_TIMEOUT, FDREAD_RETRIES, 1);
155
+}
156
+
157
+ssize_t fdread_nowaitfull(int fd, char *buf, size_t buf_size) {
158
+	return fdread_ex(fd, buf, buf_size, FDREAD_TIMEOUT, FDREAD_RETRIES, 0);
159
+}
160
+
161
+ssize_t fdwrite(int fd, char *buf, size_t buf_size) {
162
+	ssize_t wbytes=0;
163
+	int intrs = 0;
164
+	int num_timeouts = 0;
165
+	struct pollfd fdset[1];
166
+	fdset[0].fd = fd;
167
+	fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
168
+
169
+	if (buf_size <= 0 || fd == -1)
170
+		return 0;
171
+	while (1) {
172
+		int fdready = poll(fdset, 1, FDWRITE_TIMEOUT);
173
+		if (fdready == -1 || fdready == 0) { /* Timeout || error */
174
+			if (errno == EINTR) {
175
+				if (++intrs < FDWRITE_RETRIES)
176
+					continue;
177
+				else
178
+					return wbytes;
179
+			}
180
+			if (num_timeouts++ <= FDWRITE_RETRIES) {
181
+				continue;
182
+			} else {
183
+				log_perror("fdwrite() timeout", errno);
184
+				return wbytes > 0 ? wbytes : -1;
185
+			}
186
+		}
187
+		if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) /* Timeout || error */
188
+			return -1;
189
+		ssize_t j = safe_write(fd, buf+wbytes, buf_size-wbytes);
190
+		if (j < 0) // Error writing
191
+			return j;
192
+		if (j == 0) { // No data, retry?
193
+			if (num_timeouts++ > FDREAD_RETRIES) {
194
+				return wbytes;
195
+			}
196
+			continue;
197
+		}
198
+		wbytes += j;
199
+		if (wbytes == (ssize_t)buf_size)
200
+			return wbytes;
201
+	}
202
+	return 0;
203
+}
204
+
205
+int fdputs(int fd, char *msg) {
206
+	return fdwrite(fd, msg, strlen(msg));
207
+}
208
+
209
+int fdputsf(int fd, char *fmt, ...) {
210
+	char msg[2048];
211
+	va_list args;
212
+	va_start(args, fmt);
213
+	vsnprintf(msg, sizeof(msg)-1, fmt, args);
214
+	va_end(args);
215
+	return fdwrite(fd, msg, strlen(msg));
216
+}
217
+
218
+
219
+void set_sock_nonblock(int sockfd) {
220
+	int arg = fcntl(sockfd, F_GETFL, NULL);
221
+	arg |= O_NONBLOCK; 
222
+	fcntl(sockfd, F_SETFL, arg);
223
+}
224
+
225
+void set_sock_block(int sockfd) {
226
+	int arg = fcntl(sockfd, F_GETFL, NULL);
227
+	arg &= (~O_NONBLOCK);
228
+	fcntl(sockfd, F_SETFL, arg);
229
+}
230
+
231
+
232
+int do_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen, int timeout) {
233
+	set_sock_nonblock(sockfd);
234
+	// Trying to connect with timeout
235
+	int result = connect(sockfd, serv_addr, addrlen);
236
+	if (result < 0) { // Not connected
237
+		if (errno != EINPROGRESS) { // Not in progress
238
+			return -1;
239
+		} else { // Wait a timeout ms for socket to become ready to write into
240
+			struct pollfd fdset[1];
241
+			fdset[0].fd = sockfd;
242
+			fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
243
+			do {
244
+				int fdready = poll(fdset, 1, timeout);
245
+				if (fdready == -1 && errno == EINTR)
246
+					continue;
247
+				if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) { // Timeout || error
248
+					// Get socket error
249
+					unsigned int err_val=0, sz = sizeof(int); 
250
+					getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void*)(&err_val), &sz);
251
+					errno = err_val;
252
+					if (!errno) // It can't be success, so simulate timeout
253
+						errno = ENETDOWN;
254
+					return -1;
255
+				}
256
+				break;
257
+			} while (1);
258
+		}
259
+	}
260
+	set_sock_block(sockfd);
261
+	return 0;
262
+}

+ 40
- 0
io.h View File

@@ -0,0 +1,40 @@
1
+/*
2
+ * UX IO functions header file
3
+ * Copyright (C) 2006-2009 Unix Solutions Ltd.
4
+ */
5
+
6
+#ifndef IO_H
7
+# define IO_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+#include <sys/socket.h>
14
+#include <sys/types.h>
15
+
16
+char * chomp(char *x);
17
+
18
+ssize_t safe_read(int fd, void *buf, size_t len);
19
+ssize_t safe_write(int fd, const void *buf, size_t len);
20
+void shutdown_fd(int *in_fd);
21
+
22
+ssize_t fdgetline(int fd, char *buf, size_t buf_size);
23
+ssize_t fdread_ex(int fd, char *buf, size_t buf_size, int timeout, int retries, int waitfull);
24
+ssize_t fdread(int fd, char *buf, size_t buf_size);
25
+ssize_t fdread_nowaitfull(int fd, char *buf, size_t buf_size);
26
+ssize_t fdwrite(int fd, char *buf, size_t buf_size);
27
+
28
+int fdputs(int fd, char *msg);
29
+int fdputsf(int fd, char *fmt, ...);
30
+
31
+void set_sock_nonblock(int sockfd);
32
+void set_sock_block(int sockfd);
33
+
34
+int do_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen, int timeout);
35
+
36
+#ifdef __cplusplus
37
+}
38
+#endif
39
+
40
+#endif

+ 42
- 0
libfuncs.h View File

@@ -0,0 +1,42 @@
1
+/*
2
+ * UX libfuncs main header
3
+ * Copyright (C) 2006-2010 Unix Solutions Ltd.
4
+ */
5
+
6
+#ifndef LIBFUNCS_H
7
+# define LIBFUNCS_H
8
+
9
+#undef DEBUG
10
+//#define DEBUG 1
11
+
12
+#define DNS_RESOLVER_TIMEOUT 5000
13
+
14
+#define FDGETLINE_TIMEOUT 500
15
+#define FDGETLINE_RETRIES 30
16
+
17
+#define FDREAD_TIMEOUT 1500
18
+#define FDREAD_RETRIES 7
19
+
20
+#define FDWRITE_TIMEOUT 1500
21
+#define FDWRITE_RETRIES 7
22
+
23
+#ifndef FREE
24
+	#define FREE(x) if(x) { free(x); x=NULL; }
25
+#endif
26
+
27
+#ifndef POLLRDHUP
28
+	#define POLLRDHUP 0
29
+#endif
30
+
31
+#define min(a,b) ((a < b) ? a : b)
32
+#define max(a,b) ((a > b) ? a : b)
33
+
34
+#include "asyncdns.h"
35
+#include "http_response.h"
36
+#include "io.h"
37
+#include "list.h"
38
+#include "log.h"
39
+#include "queue.h"
40
+#include "server.h"
41
+
42
+#endif

+ 171
- 0
list.c View File

@@ -0,0 +1,171 @@
1
+/*
2
+ * List manipulations
3
+ * Copyright (C) 2006-2010 Unix Solutions Ltd.
4
+ *
5
+ */
6
+#include <string.h>
7
+#include <stdlib.h>
8
+#include <stdio.h>
9
+#include <pthread.h>
10
+
11
+#include "libfuncs.h"
12
+#include "list.h"
13
+
14
+//#define LIST_DEBUG
15
+
16
+#ifdef LIST_DEBUG
17
+	#define Ldbg fprintf
18
+#else
19
+	#define Ldbg(...) do { /* ... */ } while(0)
20
+#endif
21
+
22
+LIST *list_new(char *name) {
23
+	pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
24
+	if (pthread_mutex_init(mutex,NULL) != 0) {
25
+		perror("list_new: mutex_init");
26
+		return NULL;
27
+	}
28
+	LIST *list = calloc(1, sizeof(LIST));
29
+	if (!list)
30
+		return NULL;
31
+	list->mutex = mutex;
32
+	list->name = strdup(name);
33
+
34
+	LNODE *node = malloc(sizeof(LNODE));
35
+	if (!node)
36
+		return NULL;
37
+
38
+	node->data = NULL;
39
+	node->next = node;
40
+	node->prev = node;
41
+
42
+	list->head = node;	// Point to first
43
+	list->tail = node;	// Set prev element
44
+
45
+	Ldbg(stderr, "list_new(%s) l=%p l->head=%p l->tail=%p\n", list->name, list, list->head, list->tail);
46
+	return list;
47
+}
48
+
49
+void list_free(LIST **plist, void (*free_func)(), void (*freep_func)()) {
50
+	LIST *list = *plist;
51
+	if (!list)
52
+		return;
53
+	Ldbg(stderr, "list_free(%s)\n", list->name);
54
+	LNODE *node, *tmp;
55
+	list_lock(list);
56
+	list_for_each(list, node, tmp) {
57
+		if (free_func && node->data)
58
+			free_func(node->data);
59
+		if (freep_func && node->data)
60
+			freep_func(&node->data);
61
+		list_del_unlocked(list, &node);
62
+	}
63
+	FREE(list->head);
64
+	list_unlock(list);
65
+	pthread_mutex_destroy(list->mutex);
66
+	FREE(list->mutex);
67
+	FREE(list->name);
68
+	FREE(*plist);
69
+}
70
+
71
+void list_lock(LIST *list) {
72
+	pthread_mutex_lock(list->mutex);
73
+}
74
+
75
+void list_unlock(LIST *list) {
76
+	pthread_mutex_unlock(list->mutex);
77
+}
78
+
79
+void list_add(LIST *list, void *data) {
80
+	if (!list) {
81
+		Ldbg(stderr, "list_add(), list == NULL\n");
82
+		return;
83
+	}
84
+
85
+	if (!data) {
86
+		Ldbg(stderr, "list_add(%s), data == NULL\n", list->name);
87
+		return;
88
+	}
89
+
90
+	LNODE *node = malloc(sizeof(LNODE));
91
+	if (!node) {
92
+		Ldbg(stderr, "list_add(%s), can't alloc node\n", list->name);
93
+		return;
94
+	}
95
+
96
+	node->data = data;
97
+
98
+//	if (strcmp(list->name, "clients") == 0 || strcmp(list->name, "r->clients") == 0)
99
+	Ldbg(stderr, "list_add(%s), node=%p data=%p\n", list->name, node, node->data);
100
+
101
+	list_lock(list);
102
+
103
+	node->prev = list->tail;
104
+	node->next = list->head;
105
+
106
+	list->tail->next = node;
107
+	list->tail = node;
108
+	list->head->prev = node;
109
+
110
+	list->items++;
111
+	list_unlock(list);
112
+}
113
+
114
+void list_dump(LIST *list) {
115
+	if (list == NULL) {
116
+		fprintf(stderr, "list_dump(), list is null\n");
117
+		return;
118
+	}
119
+	fprintf(stderr, "list_dump(%s), nodes:%d\n", list->name, list->items);
120
+	LNODE *node, *tmp;
121
+	int i = 0;
122
+	list_for_each(list, node, tmp) {
123
+		fprintf(stderr, "   Node:%d Head:%p Tail:%p Node:%p NodeNext:%p NodePrev:%p Data:%p -> %s\n",
124
+			i++, list->head, list->tail, node, node->next, node->prev, node->data, (char *)node->data);
125
+	}
126
+}
127
+
128
+int list_del_unlocked(LIST *list, LNODE **node) {
129
+	if (!list || !*node)
130
+		return 0;
131
+
132
+	LNODE *prev = (*node)->prev;
133
+	LNODE *next = (*node)->next;
134
+
135
+	next->prev = prev;
136
+	prev->next = next;
137
+	if (*node == list->tail)
138
+		list->tail = prev;
139
+
140
+	list->items--;
141
+
142
+	FREE(*node);
143
+	return 1;
144
+}
145
+
146
+
147
+int list_del(LIST *list, LNODE **node) {
148
+	if (!list || !*node)
149
+		return 0;
150
+	list_lock(list);
151
+	int ret = list_del_unlocked(list, node);
152
+	list_unlock(list);
153
+	return ret;
154
+}
155
+
156
+int list_del_entry(LIST *list, void *data) {
157
+	int ret = 0;
158
+	if (!list || !data)
159
+		return 0;
160
+	Ldbg(stderr, "list_del_entry(%s, %p)\n", list->name, data);
161
+	list_lock(list);
162
+	LNODE *node, *tmp;
163
+	list_for_each(list, node, tmp) {
164
+		if (node->data == data) {
165
+			ret = list_del_unlocked(list, &node);
166
+			break;
167
+		}
168
+	}
169
+	list_unlock(list);
170
+	return ret;
171
+}

+ 62
- 0
list.h View File

@@ -0,0 +1,62 @@
1
+/*
2
+ * List manipulations header file
3
+ * Copyright (C) 2006-2010 Unix Solutions Ltd.
4
+ *
5
+ */
6
+#ifndef LIST_H
7
+# define LIST_H
8
+
9
+#ifdef __cplusplus
10
+extern "C" {
11
+#endif
12
+
13
+#include <pthread.h>
14
+
15
+typedef struct LNODE {
16
+	struct LNODE *prev;
17
+	struct LNODE *next;
18
+	void *data;
19
+} LNODE;
20
+
21
+typedef struct LIST {
22
+	pthread_mutex_t *mutex;		// List's lock
23
+	struct LNODE *head;			// Points to first element of the list
24
+	struct LNODE *tail;			// Points to last element of the list
25
+	unsigned int items;			// How many items are in the list
26
+	char *name;
27
+} LIST;
28
+
29
+// Safe against calling list_del inside
30
+#define list_for_each(list, elem, tmp_el) \
31
+	for (elem = (list)->head->next, tmp_el = elem->next; elem != (list)->head && elem->data; elem = tmp_el, tmp_el = elem->next)
32
+
33
+#define list_for_each_reverse(list, elem, tmp_el) \
34
+	for (elem = (list)->head->prev, tmp_el = elem->prev; elem != (list)->head && elem->data; elem = tmp_el, tmp_el = elem->prev)
35
+
36
+// list_del can not be called inside this for
37
+#define list_for_each_unsafe(list, elem) \
38
+	for (elem = (list)->head->next; elem != (list)->head && elem->data; elem = elem->next)
39
+
40
+#define list_for_each_reverse_unsafe(list, elem) \
41
+	for (elem = (list)->head->prev; elem != (list)->head && elem->data; elem = elem->prev)
42
+
43
+LIST *list_new			(char *listname);
44
+void list_free			(LIST **l, void (*l_free)(), void (*l_freep)());
45
+
46
+void list_lock			(LIST *l);
47
+void list_unlock		(LIST *l);
48
+
49
+void list_add			(LIST *l, void *data);
50
+
51
+int  list_del			(LIST *l, LNODE **node);
52
+int  list_del_unlocked	(LIST *l, LNODE **node);
53
+
54
+int  list_del_entry		(LIST *l, void *data);
55
+
56
+void list_dump(LIST *l);
57
+
58
+#ifdef __cplusplus
59
+}
60
+#endif
61
+
62
+#endif

+ 214
- 0
log.c View File

@@ -0,0 +1,214 @@
1
+/*
2
+ * IPTV.bg Media Proxy
3
+ * LOG functions
4
+ * 
5
+ * Copyright (C) 2006-2008 Unix Solutions Ltd.
6
+ * Written by Luben Karavelov (luben@unixsol.org)
7
+ * 
8
+ */
9
+
10
+/* Needed for POLLRDHUP */
11
+#define _GNU_SOURCE 1
12
+
13
+#include <stdio.h>
14
+#include <stdlib.h>
15
+#include <stdarg.h>
16
+#include <unistd.h>
17
+#include <string.h>
18
+#include <netdb.h>
19
+#include <arpa/inet.h>
20
+#include <netinet/in.h>
21
+#include <netinet/tcp.h>
22
+#include <sys/socket.h>
23
+#include <sys/time.h>
24
+#include <sys/types.h>
25
+#include <sys/stat.h>
26
+#include <poll.h>
27
+#include <errno.h>
28
+#include <time.h>
29
+#include <pthread.h>
30
+
31
+#include "libfuncs.h"
32
+#include "io.h"
33
+#include "queue.h"
34
+#include "asyncdns.h"
35
+#include "log.h"
36
+
37
+static FILE *OUT_FD = NULL;
38
+
39
+struct logger {
40
+	int			use_stderr;
41
+	int			use_syslog;
42
+
43
+	char		*host_ident;
44
+
45
+	char		*log_host;
46
+	int			log_port;
47
+	int			log_sock;
48
+
49
+	int			dienow : 1,
50
+				dying  : 1;
51
+
52
+	QUEUE		*queue;
53
+	pthread_t	thread;
54
+};
55
+
56
+static void log_connect(struct logger *l) {
57
+	struct sockaddr_in sockname;
58
+
59
+	if (!l->use_syslog)
60
+		return;
61
+
62
+	while (1) {
63
+		if (l->dying || l->dienow)
64
+			break;
65
+		int active = 1;
66
+		int dret = async_resolve_host(l->log_host, l->log_port, &sockname, 500, &active);
67
+		if (dret != 0) {
68
+			log_perror("Could not resolve log host.", errno);
69
+			sleep(2);
70
+			continue;
71
+		}
72
+		l->log_sock = socket(PF_INET, SOCK_STREAM, 0);
73
+		if (l->log_sock < 0) {
74
+			log_perror("Could not create syslog socket", errno);
75
+			sleep(2);
76
+			continue;
77
+		}
78
+		if (connect(l->log_sock, (struct sockaddr *) &sockname, sizeof (sockname)) < 0) {
79
+			log_perror("Could not connect to log host.", errno);
80
+			shutdown_fd(&l->log_sock);
81
+			sleep(2);
82
+			continue;
83
+		}
84
+		int on = 1;
85
+		setsockopt(l->log_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&on, sizeof(int));
86
+		break;
87
+	}
88
+}
89
+
90
+static void * log_thread(void *param) {
91
+	char date[64], logline[1024], *msg=NULL;
92
+	struct logger *l = (struct logger *)param;
93
+
94
+	if (l->log_sock < 0)
95
+		log_connect(l);
96
+
97
+	while (l && !l->dienow) {
98
+		msg = queue_get(l->queue); // Waits...
99
+		if (!msg)
100
+			break;
101
+
102
+		time_t now = time(NULL);
103
+		memset(date, 0, sizeof(date));
104
+		struct tm ltime;
105
+		localtime_r(&now, &ltime);
106
+		strftime(date, sizeof(date)-1, "%b %d %H:%M:%S", &ltime);
107
+
108
+		memset(logline, 0, sizeof(logline));
109
+		snprintf(logline, sizeof(logline)-1, "<30>%s host %s: %s", date, l->host_ident, msg);
110
+		logline[sizeof(logline)-2] = '\n';
111
+		logline[sizeof(logline)-1] = '\0';
112
+
113
+		if (l->use_stderr)
114
+			fprintf(OUT_FD, "%s", logline+4);
115
+
116
+		while (l->use_syslog) {
117
+			struct pollfd fdset[1];
118
+			int fdready;
119
+			do {
120
+				fdset[0].fd = l->log_sock;
121
+				fdset[0].events = POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDHUP;
122
+				fdready = poll(fdset, 1, 5 * 1000);
123
+			} while (fdready == -1 && errno == EINTR);
124
+			if (fdready < 1 || (fdready == 1 && fdset[0].revents != POLLOUT)) { /* Timeout || error */
125
+				do { /* Try to reconnect to log host */
126
+					if (l->dienow)
127
+						goto OUT;
128
+					LOGf("ERROR: Lost connection to log server (%s), fd: %i\n", fdready == 1 ? "poll error" : "timeout", l->log_sock);
129
+					shutdown_fd(&l->log_sock);
130
+					log_connect(l);
131
+					sleep(2);
132
+				} while (l->log_sock < 0);
133
+			} else {
134
+				if (fdwrite(l->log_sock, logline, strlen(logline)) > 0)
135
+					break;
136
+				else
137
+					if (l->dienow)
138
+						goto OUT;
139
+			}
140
+		}
141
+
142
+		FREE(msg);
143
+	}
144
+OUT:
145
+	FREE(msg);
146
+	pthread_exit(0);
147
+}
148
+
149
+static struct logger *logger = NULL;
150
+
151
+void log_init(char *host_ident, int use_syslog, int use_stderr, char *log_host, int log_port) {
152
+	logger = calloc(1, sizeof(struct logger));
153
+
154
+	logger->queue = queue_new();
155
+	logger->host_ident = strdup(host_ident);
156
+
157
+	if (log_host)
158
+		logger->log_host = strdup(log_host);
159
+	logger->log_port = log_port;
160
+	logger->log_sock = -1;
161
+
162
+	logger->use_syslog = use_syslog;
163
+	logger->use_stderr = use_stderr;
164
+
165
+	pthread_create(&logger->thread, NULL , &log_thread, logger);
166
+}
167
+
168
+void log_set_out_fd(FILE *new_out_fd) {
169
+	OUT_FD = new_out_fd;
170
+}
171
+
172
+void log_close() {
173
+	logger->dying = 1;
174
+	int count = 0;
175
+	while (logger->queue->items && count++ < 250)
176
+		usleep(1000);
177
+	logger->dienow = 1;
178
+	queue_wakeup(logger->queue);
179
+	pthread_join(logger->thread, NULL);
180
+	shutdown_fd(&logger->log_sock);
181
+	queue_free(&logger->queue);
182
+	FREE(logger->host_ident);
183
+	FREE(logger->log_host);
184
+	FREE(logger);
185
+}
186
+
187
+void LOG(const char *msg) {
188
+	if (OUT_FD == NULL)
189
+		OUT_FD = stderr;
190
+	if (!logger || logger->dying) {
191
+		fprintf(OUT_FD, "%s", msg);
192
+	} else {
193
+		queue_add(logger->queue, strdup(msg));
194
+	}
195
+}
196
+
197
+void LOGf(const char *fmt, ...) {
198
+	char msg[1024];
199
+	va_list args;
200
+	va_start(args, fmt);
201
+	vsnprintf(msg, sizeof(msg)-1, fmt, args);
202
+	va_end(args);
203
+	msg[sizeof(msg)-2] = '\n';
204
+	msg[sizeof(msg)-1] = '\0';
205
+	LOG(msg);
206
+}
207
+
208
+void log_perror(const char *message, int _errno) {
209
+	char msg[1024];
210
+	snprintf(msg, sizeof(msg)-1, "PERROR: %s | %s\n", message, strerror(_errno));
211
+	msg[sizeof(msg)-2] = '\n';
212
+	msg[sizeof(msg)-1] = '\0';
213
+	LOG(msg);
214
+}

+ 43
- 0
log.h View File

@@ -0,0 +1,43 @@
1
+/*
2
+ * IPTV.bg Media Proxy
3
+ * LOG functions header file
4
+ * 
5
+ * Copyright (C) 2006 Unix Solutions Ltd.
6
+ * Written by Luben Karavelov (luben@unixsol.org)
7
+ * 
8
+ */
9
+
10
+#ifndef LOG_H
11
+# define LOG_H
12
+
13
+#ifdef __cplusplus
14
+extern "C" {
15
+#endif
16
+
17
+#include <stdio.h>
18
+
19
+void log_init  (char *host_ident, int use_syslog, int use_stderr, char *log_host, int log_port);
20
+void log_close ();
21
+
22
+void LOG (const char *msg);
23
+
24
+__attribute__ ((format(printf, 1, 2)))
25
+void LOGf(const char *fmt, ...);
26
+
27
+void log_perror(const char *message, int _errno);
28
+
29
+void log_set_out_fd(FILE *new_out_fd);
30
+
31
+#ifdef DEBUG
32
+	#define dbg_LOG  LOG
33
+	#define dbg_LOGf LOGf
34
+#else
35
+	#define dbg_LOG(arg)  do { /* arg */ } while(0)
36
+	#define dbg_LOGf(...) do { /* ... */ } while(0)
37
+#endif
38
+
39
+#ifdef __cplusplus
40
+}
41
+#endif
42
+
43
+#endif

+ 112
- 0
queue.c View File

@@ -0,0 +1,112 @@
1
+/*
2
+ * IPTV.bg Media Proxy
3
+ * Request queue handling
4
+ * 
5
+ * Copyright (C) 2006 Unix Solutions Ltd.
6
+ * Written by Luben Karavelov (luben@unixsol.org)
7
+ * 
8
+ */
9
+#include <stdio.h>
10
+#include <stdlib.h>
11
+#include <assert.h>
12
+#include <errno.h>
13
+#include <err.h>
14
+#include <pthread.h>
15
+
16
+#include "libfuncs.h"
17
+#include "queue.h"
18
+
19
+QUEUE *queue_new() {
20
+	pthread_mutex_t *mutex = malloc(sizeof(pthread_mutex_t));
21
+	if (pthread_mutex_init(mutex,NULL) != 0) {
22
+		perror("queue_new: mutex_init");
23
+		return NULL;
24
+	}
25
+	pthread_cond_t *cond = malloc(sizeof(pthread_cond_t));
26
+	if (pthread_cond_init(cond,NULL)!=0){
27
+		perror("queue_new: cond_init");
28
+		return NULL;
29
+	}
30
+    QUEUE *q = calloc(1, sizeof(QUEUE));
31
+	if (!q)
32
+		return NULL;
33
+    // initialize queue 
34
+    q->mutex = mutex;
35
+    q->cond  = cond;
36
+    return q;
37
+}
38
+
39
+void queue_free(QUEUE **pq) {
40
+	QUEUE *q = *pq;
41
+	void *data;
42
+	if (!q)
43
+		return;
44
+	while (q->items > 0) {
45
+		data = queue_get(q);
46
+	}
47
+	pthread_mutex_destroy(q->mutex);
48
+	FREE(q->mutex);
49
+	pthread_cond_destroy(q->cond);
50
+	FREE(q->cond);
51
+	FREE(*pq);
52
+}
53
+
54
+void queue_add(QUEUE *q, void *data) {
55
+	if (!q)
56
+		return;
57
+	QNODE *a_msg = malloc(sizeof(QNODE));
58
+	if (!a_msg) {
59
+		perror("queue_enqueue, malloc:");
60
+		return;
61
+	}
62
+	a_msg->data = data;
63
+	a_msg->next = NULL;
64
+	pthread_mutex_lock(q->mutex);
65
+	if (q->items == 0) { 			// special case - queue is empty 
66
+		q->head = a_msg;
67
+		q->tail = a_msg;
68
+	} else {
69
+		q->tail->next = a_msg;
70
+		q->tail = a_msg;
71
+	}
72
+	q->items++;
73
+	pthread_cond_signal(q->cond);
74
+	pthread_mutex_unlock(q->mutex);
75
+}
76
+
77
+void *queue_get(QUEUE *q) {
78
+	if (!q)
79
+		return NULL;
80
+	pthread_mutex_lock(q->mutex);
81
+	while (q->items==0) {
82
+		pthread_cond_wait(q->cond, q->mutex);
83
+		if (q->items == 0)
84
+			return NULL;
85
+	}
86
+	if (!q || !q->head || q->items == 0) // Can happen in free
87
+		return NULL;
88
+	QNODE *a_msg = q->head;
89
+	q->head = a_msg->next;
90
+	if (q->head == NULL) { 		// this was last msg
91
+	    q->tail = NULL;
92
+	}
93
+	q->items--;
94
+	pthread_cond_signal(q->cond);
95
+	pthread_mutex_unlock(q->mutex);
96
+	void *data = a_msg->data;
97
+	FREE(a_msg);
98
+    return data;
99
+}
100
+
101
+void *queue_get_nowait(QUEUE* q) {
102
+	if (!q || q->items == 0)
103
+		return NULL;
104
+	return queue_get(q);
105
+}
106
+
107
+void queue_wakeup(QUEUE *q) {
108
+	if (q) {
109
+		pthread_cond_signal(q->cond);
110
+	}
111
+}
112
+

+ 43
- 0
queue.h View File

@@ -0,0 +1,43 @@
1
+/*
2
+ * IPTV.bg Media Proxy
3
+ * Request queue header file
4
+ * 
5
+ * Copyright (C) 2006 Unix Solutions Ltd.
6
+ * Written by Luben Karavelov (luben@unixsol.org)
7
+ * 
8
+ */
9
+#ifndef QUEUE_H
10
+# define QUEUE_H
11
+
12
+#ifdef __cplusplus
13
+extern "C" {
14
+#endif
15
+
16
+#include <pthread.h>
17
+
18
+typedef struct QNODE {
19
+	struct QNODE *next;
20
+	void *data;
21
+} QNODE;
22
+
23
+typedef struct QUEUE {
24
+	QNODE *head;
25
+	QNODE *tail;
26
+	pthread_mutex_t *mutex;	// queue's mutex.
27
+	pthread_cond_t  *cond;	// queue's condition variable.
28
+	int items;				// number of messages in queue
29
+} QUEUE;
30
+
31
+QUEUE *queue_new		();
32
+void queue_free			(QUEUE **q);
33
+
34
+void queue_add			(QUEUE *q, void *data);
35
+void *queue_get			(QUEUE *q);
36
+void *queue_get_nowait	(QUEUE *q);
37
+void queue_wakeup		(QUEUE *q);
38
+
39
+#ifdef __cplusplus
40
+}
41
+#endif
42
+
43
+#endif

+ 83
- 0
server.c View File

@@ -0,0 +1,83 @@
1
+/*
2
+ * Server functions
3
+ * Copyright (C) 2006-2010 Unix Solutions Ltd.
4
+ */
5
+
6
+#include <stdio.h>
7
+#include <stdlib.h>
8
+#include <unistd.h>
9
+#include <string.h>
10
+#include <errno.h>
11
+#include <netdb.h>
12
+#include <sys/types.h>
13
+#include <sys/socket.h>
14
+#include <netinet/in.h>
15
+#include <arpa/inet.h>
16
+
17
+void daemonize(char *pidfile) {
18
+	if (!pidfile)
19
+		return;
20
+	printf("Daemonizing.\n");
21
+	pid_t pid = fork();
22
+	if (pid > 0) {
23
+		FILE *F = fopen(pidfile,"w");
24
+		if (F) {
25
+			fprintf(F,"%i\n",pid);
26
+			fclose(F);
27
+		}
28
+		exit(0);
29
+	}
30
+	// Child process continues...
31
+	setsid();	// request a new session (job control)
32
+	freopen("/dev/null", "r", stdin);
33
+	freopen("/dev/null", "w", stdout);
34
+	freopen("/dev/null", "w", stderr);
35
+}
36
+
37
+void init_server_socket(char *bind_addr, int bind_port, struct sockaddr_in *server, int *server_socket) {
38
+	char *binded;
39
+
40
+	struct hostent *host_ptr;
41
+	*server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
42
+	if (*server_socket == -1) {
43
+		perror("socket(server_socket)");
44
+		exit(1);
45
+	}
46
+	int j = 1;
47
+	if (setsockopt(*server_socket, SOL_SOCKET, SO_REUSEADDR,(const char *) &j, sizeof(j))<0) {
48
+		perror("setsockopt(SO_REUSEADDR)");
49
+		exit(1);
50
+	}
51
+
52
+	memset(server, 0, sizeof(struct sockaddr_in));
53
+	if (!bind_addr) {
54
+		binded = "*";
55
+		server->sin_addr.s_addr = htonl(INADDR_ANY);
56
+	} else {
57
+		host_ptr = gethostbyname(bind_addr);
58
+		if (!host_ptr) {
59
+			fprintf(stderr,"Error can't resolve bind address: %s\n", bind_addr);
60
+			exit(1);
61
+		}
62
+		memcpy(&server->sin_addr, host_ptr->h_addr, sizeof(server->sin_addr));
63
+		binded = inet_ntoa(server->sin_addr);
64
+	}
65
+
66
+	/* Bind to server socket */
67
+	fprintf(stderr, "Binding to %s:%i\t", binded, bind_port);
68
+	if (strcmp(binded,"*")==0)
69
+		fprintf(stderr,"\t");
70
+
71
+	server->sin_family = AF_INET;
72
+	server->sin_port   = htons(bind_port);
73
+	if (bind(*server_socket, (struct sockaddr *)server, sizeof(struct sockaddr_in)) < 0) {
74
+		perror("bind(server_socket)");
75
+		exit(1);
76
+	}
77
+	if (listen(*server_socket, 256) < 0) {
78
+		perror("listen()");
79
+		exit(1);
80
+	}
81
+
82
+	fputs("[OK]\n",stderr);
83
+}

+ 22
- 0
server.h View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * Server functions
3
+ * Copyright (C) 2006-2010 Unix Solutions Ltd.
4
+ */
5
+#ifndef SERVER_H
6
+# define SERVER_H
7
+
8
+#ifdef __cplusplus
9
+extern "C" {
10
+#endif
11
+
12
+#include <arpa/inet.h>
13
+#include <netinet/in.h>
14
+
15
+void daemonize(char *pidfile);
16
+void init_server_socket(char *bind_addr, int bind_port, struct sockaddr_in *server, int *server_socket);
17
+
18
+#ifdef __cplusplus
19
+}
20
+#endif
21
+
22
+#endif

Loading…
Cancel
Save