-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhttp_server.c
More file actions
167 lines (127 loc) · 4.4 KB
/
Copy pathhttp_server.c
File metadata and controls
167 lines (127 loc) · 4.4 KB
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
#include "http_server.h"
#include "metrics.h"
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#define BUFFER_SIZE 16384
typedef struct {
int client_socket;
int verbose;
} http_thread_args_t;
void send_full_response(int socket, const char *response, size_t response_length) {
size_t total_sent = 0;
while (total_sent < response_length) {
ssize_t sent = send(socket, response + total_sent, response_length - total_sent, 0);
if (sent < 0) {
perror("Failed to send response");
break;
}
total_sent += sent;
}
}
void *handle_client(void *arg) {
http_thread_args_t *client_args = (http_thread_args_t *)arg;
int client_socket = client_args->client_socket;
int verbose = client_args->verbose;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
free(client_args);
getpeername(client_socket, (struct sockaddr *)&client_addr, &addr_len);
char client_ip[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, INET_ADDRSTRLEN);
int client_port = ntohs(client_addr.sin_port);
char *body = malloc(BUFFER_SIZE);
if (!body) {
perror("Failed to allocate memory for metrics body");
close(client_socket);
return NULL;
}
format_metrics(body, BUFFER_SIZE);
int content_length = strlen(body);
size_t response_size = content_length + 128; // Estimate headers size
char *response = malloc(response_size);
if (!response) {
perror("Failed to allocate memory for HTTP response");
free(body);
close(client_socket);
return NULL;
}
snprintf(response, response_size,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %d\r\n"
"Connection: close\r\n"
"\r\n"
"%s",
content_length, body);
if (verbose) {
printf("Client connected: %s:%d\n", client_ip, client_port);
printf("Response headers and body:\n%s\n", response);
}
send_full_response(client_socket, response, strlen(response));
shutdown(client_socket, SHUT_WR);
if (verbose) {
printf("Shutdown write connection for client: %s:%d\n", client_ip, client_port);
}
close(client_socket);
if (verbose) {
printf("Client disconnected: %s:%d\n", client_ip, client_port);
}
free(body);
free(response);
return NULL;
}
void *http_server(void *arg) {
server_args_t *args = (server_args_t *)arg;
int http_port = args->port;
int verbose = args->verbose;
int server_socket, client_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("HTTP socket creation failed");
pthread_exit(NULL);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(http_port);
if (bind(server_socket, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("HTTP socket bind failed");
close(server_socket);
pthread_exit(NULL);
}
if (listen(server_socket, 10) < 0) {
perror("HTTP listen failed");
close(server_socket);
pthread_exit(NULL);
}
printf("HTTP Server running on 0.0.0.0:%d\n", http_port);
while (1) {
client_socket = accept(server_socket, (struct sockaddr *)&address, (socklen_t *)&addrlen);
if (client_socket < 0) {
perror("HTTP accept failed");
continue;
}
http_thread_args_t *client_args = malloc(sizeof(http_thread_args_t));
if (client_args == NULL) {
perror("Failed to allocate memory for client thread arguments");
close(client_socket);
continue;
}
client_args->client_socket = client_socket;
client_args->verbose = verbose;
pthread_t client_thread;
if (pthread_create(&client_thread, NULL, handle_client, client_args) != 0) {
perror("Failed to create client thread");
free(client_args);
close(client_socket);
continue;
}
pthread_detach(client_thread); // Detach thread to avoid blocking
}
close(server_socket);
pthread_exit(NULL);
}