1 karl 1.1 /*
2 **==============================================================================
3 **
4 ** Copyright (c) 2003, 2004, 2005 Michael E. Brasher
5 **
6 ** Permission is hereby granted, free of charge, to any person obtaining a
7 ** copy of this software and associated documentation files (the "Software"),
8 ** to deal in the Software without restriction, including without limitation
9 ** the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 ** and/or sell copies of the Software, and to permit persons to whom the
11 ** Software is furnished to do so, subject to the following conditions:
12 **
13 ** The above copyright notice and this permission notice shall be included in
14 ** all copies or substantial portions of the Software.
15 **
16 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 ** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 karl 1.1 ** SOFTWARE.
23 **
24 **==============================================================================
25 */
26
27 #include <cstdio>
28 #include <cstdlib>
29 #include <cstring>
30 #include <cctype>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <netinet/in.h>
34 #include <pthread.h>
35 #include <cassert>
36 #include "memo.h"
37
38 unsigned short SERVER_PORT = 8888;
39
40 static int _close_on_exec(int sock)
41 {
42 return ::fcntl(sock, F_SETFD, ::fcntl(sock, F_GETFD) | FD_CLOEXEC);
43 karl 1.1 }
44
45 static void _handle_client_request(int sock)
46 {
47 unsigned char request;
48
49 int n = read(sock, &request, sizeof(request));
50
51 if (n == -1)
52 {
53 fprintf(stderr, "MEMO: error reading socket: %d\n", sock);
54 return;
55 }
56
57 switch (tolower(request))
58 {
59 case 't':
60 {
61 size_t size = memo_total_bytes();
62 char buffer[64];
63 sprintf(buffer, "%d bytes\n", (int)size);
64 karl 1.1 write(sock, buffer, strlen(buffer) + 1);
65 break;
66 }
67
68 case 'c':
69 {
70 memo_check();
71 break;
72 }
73
74 default:
75 {
76 const char buffer[] = "Illegal request\n";
77 write(sock, buffer, strlen(buffer) + 1);
78 }
79 }
80
81 close(sock);
82 }
83
84 void _create_port_file(unsigned port)
85 karl 1.1 {
86 char path[64];
87 sprintf(path, "/tmp/memo.port");
88
89 FILE* os = fopen(path, "wb");
90
91 if (!os)
92 {
93 fprintf(stderr, "MEMO: failed to create port file: %s\n", path);
94 assert(0);
95 }
96
97 fprintf(os, "%u\n", port);
98 fflush(os);
99 fclose(os);
100 }
101
102 void run_server()
103 {
104 // printf("MEMO: server started\n");
105
106 karl 1.1 //// Initialize server address:
107
108 sockaddr_in server_addr;
109 bzero(&server_addr, sizeof(sockaddr_in));
110 server_addr.sin_family = AF_INET;
111 server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
112 server_addr.sin_port = 0;
113
114 //// Figure out which port was used:
115
116 // htons(SERVER_PORT);
117
118 //// Create socket:
119
120 int listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
121
122 _close_on_exec(listen_sock);
123 int opt = 1;
124 setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof opt);
125
126 bind(listen_sock, (sockaddr*)(&server_addr), sizeof server_addr);
127 karl 1.1
128 sockaddr_in tmp_addr;
129 socklen_t tmp_len = sizeof(tmp_addr);
130 getsockname(listen_sock, (sockaddr*)&tmp_addr, &tmp_len);
131 _create_port_file(ntohs(tmp_addr.sin_port));
132
133 listen(listen_sock, 5);
134
135 //// Accept and handle connections:
136
137 for (;;)
138 {
139 sockaddr_in addr;
140 socklen_t length = sizeof addr;
141 int sock = accept(listen_sock, (sockaddr*)&addr, &length);
142
143 if (sock == -1)
144 continue;
145
146 _close_on_exec(sock);
147 _handle_client_request(sock);
148 karl 1.1 close(sock);
149 }
150 }
|