main.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>
  6. #include <fcntl.h>
  7. #include <netdb.h>
  8. #include <time.h>
  9. #include <ctype.h>
  10. #include <sys/socket.h>
  11. #include <sys/types.h>
  12. #include <netinet/in.h>
  13. #include <arpa/inet.h>
  14. #include <pthread.h>
  15. #include <signal.h>
  16. #define SERVER_PORT 12345
  17. #define MAX_CONNECTIONS 1000
  18. #define LOCK_FILE_PATH "/tmp/pid.lock"
  19. #define m_string char*
  20. /*
  21. Client
  22. socket()
  23. ? bind() ?
  24. connect()
  25. ----------------
  26. write() | read()
  27. send() | recv()
  28. sendto() | recvfrom()
  29. writev() | readv()
  30. sendmsg() | recvmsg()
  31. ----------------
  32. close()
  33. Server
  34. socket()
  35. bind()
  36. listen()
  37. accept()
  38. ----------------
  39. write() | read()
  40. send() | recv()
  41. sendto() | recvfrom()
  42. writev() | readv()
  43. sendmsg() | recvmsg()
  44. ----------------
  45. close()
  46. */
  47. typedef enum {
  48. eHTTP_UNKNOWN = 0,
  49. eHTTP_CONNECT,
  50. eHTTP_DELETE,
  51. eHTTP_GET,
  52. eHTTP_HEAD,
  53. eHTTP_OPTIONS,
  54. eHTTP_PATCH,
  55. eHTTP_POST,
  56. eHTTP_PUT,
  57. eHTTP_TRACE
  58. } eHTTPMethod;
  59. typedef struct {
  60. eHTTPMethod type;
  61. char path[255];
  62. } sHTTPHeader;
  63. typedef struct {
  64. struct strList *next;
  65. char *cont;
  66. } strList;
  67. typedef struct {
  68. void *access_semaphore;
  69. char login[256];
  70. char password[256];
  71. char bound_ip[64];
  72. char message[4096];
  73. } dbElem;
  74. typedef struct {
  75. int sockd;
  76. struct sockaddr_in client_sockaddr;
  77. int client_sockaddr_size;
  78. } clientData;
  79. // DAEMON BASE FUNCTIONS
  80. // Starts server daemon, returns 1 on success, otherwise 0
  81. void start_server();
  82. // Stops server daemon, returns 1 on success, otherwise 0
  83. void stop_server();
  84. // Shows help and returns (is used if no parameter specified)
  85. void show_help();
  86. // Runs server event loop (called inside daemon)
  87. void process_server();
  88. // SERVER BASE FUNCTIONS
  89. // Creates socket, binds it to defined port and makes ready to listen for connections.
  90. int create_socket();
  91. // Opens (and creates, if necessary) file for user data and maps it to pointer in shared mode via memory-mapping.
  92. void *open_database();
  93. // Creates worker subprocess for connection, which lives while connection is established and communicates with client.
  94. // Returns worker pid to parent soon after creation (non-blocking communication).
  95. int process_request(int client_d, struct sockaddr *addr, void *database);
  96. // WORKER BASE FUNCTIONS
  97. // Waits until user request, then returns path, client_ip and header information
  98. void receive_request(m_string*path, m_string*client_ip, m_string*http_header);
  99. // Checks if user ip is bound to any login in database. Returns username, if bound and nullptr - if not.
  100. m_string check_user_authorisation(m_string client_ip);
  101. // Tries to update user message. Returns 1, if successfull, or 0 - if not;
  102. int update_user_message(m_string username, m_string msg);
  103. void send_404_not_found(int sockd);
  104. void send_401_not_authorised(int sockd);
  105. void send_403_forbidden(int sockd);
  106. void send_200_user_message(int sockd);
  107. void send_error_invalid_message(int sockd);
  108. // WORKER ADDITIONAL FUNCTIONS
  109. // Sends message
  110. void send_message(int sockd, const m_string msg);
  111. // Returns client address depending on ipv4/ipv6 protocol
  112. void *get_client_addr(struct sockaddr *);
  113. // Parses http request
  114. void* handle_request(void* data);
  115. void parse_http_request(const char *, sHTTPHeader *);
  116. // ============================================================================================= //
  117. int main(int argc, char** argv) {
  118. if (argc < 2) {
  119. show_help();
  120. return 0;
  121. }
  122. if (strcmp(argv[1], "start") == 0) {
  123. start_server();
  124. return 0;
  125. } else if (strcmp(argv[1], "stop") == 0) {
  126. stop_server();
  127. return 0;
  128. } else if (strcmp(argv[1], "help") == 0) {
  129. show_help();
  130. return 0;
  131. } else {
  132. show_help();
  133. return 0;
  134. }
  135. }
  136. void start_server() {
  137. FILE *lock_file = fopen(LOCK_FILE_PATH, "r");
  138. if (lock_file) {
  139. fprintf(stderr, "Error: seems like server is already running!\nStop it before starting the new one!\n");
  140. return;
  141. }
  142. pid_t pid = fork();
  143. if (pid == -1) {
  144. fprintf(stderr, "Error: cannot create server! (fork exited with error: %s)\n", strerror(errno));
  145. return;
  146. } else if (pid == 0) {
  147. process_server();
  148. return;
  149. } else {
  150. printf("Server started with pid = %d\n", pid);
  151. lock_file = fopen(LOCK_FILE_PATH, "w");
  152. fprintf(lock_file, "%d", pid);
  153. fclose(lock_file);
  154. return;
  155. }
  156. }
  157. void stop_server() {
  158. FILE *lock_file = fopen(LOCK_FILE_PATH, "r");
  159. if (!lock_file) {
  160. fprintf(stderr, "Error: cannot stop server (no running server found)!\n");
  161. return;
  162. }
  163. int pid;
  164. if (fscanf(lock_file, "%d", &pid) != 1) {
  165. fprintf(stderr, "Error: cannot stop server (pid read error)!\n");
  166. fclose(lock_file);
  167. return;
  168. }
  169. if (kill(pid, SIGTERM) != 0) {
  170. fprintf(stderr, "Warning: server pid is incorrect, server might be already stopped (exited), but lock file still exists.\n");
  171. }
  172. fclose(lock_file);
  173. if (remove(LOCK_FILE_PATH) != 0) {
  174. fprintf(stderr, "Error: cannot remove server lock file (%s), but server was stopped...\n", LOCK_FILE_PATH);
  175. } else {
  176. printf("Server stopped successfully.\n");
  177. }
  178. }
  179. void show_help() {
  180. printf("Using: server <COMMAND>\n"
  181. "\n"
  182. "<COMMAND> values:\n"
  183. "start - starts server daemon, if there's no one already started.\n"
  184. "\n"
  185. "stop - stops running server daemon if there's one.\n"
  186. "\n"
  187. "help - shows this help.\n"
  188. "");
  189. }
  190. void * get_client_addr(struct sockaddr * sa) {
  191. if (sa -> sa_family == AF_INET) {
  192. return &(((struct sockaddr_in * ) sa) -> sin_addr);
  193. }
  194. return &(((struct sockaddr_in6 * ) sa) -> sin6_addr);
  195. }
  196. void process_server() {
  197. int sock = create_socket();
  198. if (sock < 0) {
  199. fprintf(stderr, "Server: Error, cannot create socket!\n");
  200. return;
  201. }
  202. printf("Server: server created and listening on port %d.\n", SERVER_PORT);
  203. while (1) {
  204. clientData *data = malloc(sizeof(clientData)); // would be freed in thread after its finishing
  205. data->sockd = accept(sock, (struct sockaddr *) &data->client_sockaddr, &data->client_sockaddr_size);
  206. pthread_t thread_id;
  207. pthread_attr_t attr;
  208. pthread_attr_init(&attr);
  209. printf("Server: got new connection, creating worker thread.\n");
  210. pthread_create(&thread_id, &attr, handle_request, data);
  211. printf("Server: created worker thread %d.\n", thread_id);
  212. }
  213. }
  214. int create_socket() {
  215. printf("Creating socket\n");
  216. int sock = socket(PF_INET, SOCK_STREAM, 0);
  217. int on = 1;
  218. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  219. /* initialize the server's sockaddr */
  220. struct sockaddr_in server_sockaddr;
  221. memset(&server_sockaddr, 0, sizeof(server_sockaddr));
  222. server_sockaddr.sin_family = AF_INET;
  223. server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  224. server_sockaddr.sin_port = htons(SERVER_PORT);
  225. printf("Binding socket %d to sockaddr %p with size %d\n", sock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));
  226. int bind_result = bind(sock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));
  227. if (bind_result < 0) {
  228. fprintf(stderr, "Server: Error: bind failed!");
  229. return -1;
  230. }
  231. listen(sock, MAX_CONNECTIONS);
  232. return sock;
  233. }
  234. void* handle_request(void* data) {
  235. clientData* client_data = data;
  236. char ip[INET_ADDRSTRLEN];
  237. inet_ntop(AF_INET, get_client_addr((struct sockaddr *) &client_data->client_sockaddr), ip, sizeof(ip));
  238. printf("Worker %d: Established connection with %s beginning work.\n", pthread_self(), ip);
  239. const int request_buffer_size = 65536;
  240. char request[request_buffer_size];
  241. int bytes_recvd = recv(client_data->sockd, request, request_buffer_size - 1, 0);
  242. if (bytes_recvd < 0) {
  243. fprintf(stderr, "error recv: %s\n", strerror(errno));
  244. return NULL;
  245. }
  246. request[bytes_recvd] = '\0';
  247. printf("request:\n%s\n", request);
  248. sHTTPHeader req;
  249. parse_http_request(request, &req);
  250. if (req.type == eHTTP_GET) {
  251. send_message(client_data->sockd, "Hello! GET received...");
  252. } else if (req.type == eHTTP_POST) {
  253. send_message(client_data->sockd, "Hello! POST received...");
  254. } else {
  255. send_404_not_found(client_data->sockd);
  256. }
  257. close(client_data->sockd);
  258. printf("Worker %d: Finished.\n", pthread_self());
  259. return NULL;
  260. }
  261. void parse_http_request(const char *apstrRequest, sHTTPHeader *apHeader) {
  262. int type_length = 0;
  263. char type[255] = {0};
  264. int index = 0;
  265. apHeader->type = eHTTP_UNKNOWN;
  266. sscanf(&apstrRequest[index], "%s", type);
  267. type_length = strlen(type);
  268. if (!strcmp(type, "GET")) {
  269. apHeader->type = eHTTP_GET;
  270. index += type_length + 1;
  271. sscanf(&apstrRequest[index], "%s", apHeader->path);
  272. } else {
  273. if (!strcmp(type, "POST")) {
  274. apHeader->type = eHTTP_POST;
  275. char *pch = strstr(apstrRequest, "\r\n\r\n");
  276. pch += 4;
  277. strcpy(apHeader->path, pch);
  278. }
  279. }
  280. }
  281. void send_message(int aSock, const char *apstrMessage) {
  282. char buffer[65536] = {0};
  283. strcat(buffer, "HTTP/1.1 200 OK\n\n");
  284. strcat(buffer, "<h1>");
  285. strcat(buffer, apstrMessage);
  286. strcat(buffer, "</h1>");
  287. int len = strlen(buffer);
  288. send(aSock, buffer, len, 0);
  289. }
  290. void send_404_not_found(int sockd) {
  291. const char *buffer = "HTTP/1.1 404 \n\n";
  292. int len = strlen(buffer);
  293. send(sockd, buffer, len, 0);
  294. }
  295. // server: got connection from 127.0.0.1
  296. // request:
  297. // GET /index.html HTTP/1.1
  298. // Host: localhost:3490
  299. // Connection: keep-alive
  300. // Upgrade-Insecure-Requests: 1
  301. // User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/68.0.3440.75 Chrome/68.0.3440.75 Safari/537.36
  302. // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  303. // Accept-Encoding: gzip, deflate, br
  304. // Accept-Language: en-US,en;q=0.9,ru;q=0.8