-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.c
210 lines (196 loc) · 6.66 KB
/
main.c
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <libgen.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "main.h"
#include "function.c"
// temp TODO
#include "net/net_logic.c"
server_struct * server;
int main(int argc, char * argv[])
{
// initial server config
server_config_struct * server_config;
server_config = parse_config_file();
if (NULL == server_config) {
printf( "parse config file error.\n" );
return -1;
}
// daemonize the program...like Nginx OR Redis
if (0 == strcmp("yes", server_config->daemonize)) {
daemonize();
}
// event loop flow:begin
ev_loop_struct * ev = init_ev(1024);
// create a single process & thread tcp server
server = init_server(server_config, ev);
// begin event-loop
ev_main(ev);
return 0;
}
/*
* @desc : parse config file to server config structure
* @return : pointer of server_config_struct
*/
server_config_struct * parse_config_file()
{
server_config_struct * server_config = (server_config_struct *)malloc(sizeof(server_config_struct));
/*
config_item_struct config_item_list[] = {
{ "host", "" },
{ "port", "" },
{ "event", "" },
{ "daemonize", "" },
};
*/
int buffer_size = 64;
int config_item_list_size;
char config_item[buffer_size];
char * key;
char * value;
char * _config_item;
char * delimeter = "=";
FILE * config_file;
if ((config_file = fopen( "./conf/tidis.conf", "r" )) < 0) {
return NULL;
}
//config_item_list_size = sizeof( config_item_list ) / sizeof( config_item_struct );
while (fgets(config_item, buffer_size, config_file)) {
_config_item = config_item;
// NOTICE : strtok is deprecated, just use strsep( Thread Satety! )
key = strsep(&_config_item, delimeter);
value = _config_item;
trim(key);
trim(value);
if (key[0] == '#' || key[0] == '\0') {
continue;
} if (0 == strcmp( key, "host")) {
strcpy(server_config->host, value );
} else if ( 0 == strcmp( key, "port")) {
strcpy( server_config->port, value );
} else if ( 0 == strcmp( key, "event" ) ) {
strcpy( server_config->event, value );
} else if ( 0 == strcmp( key, "daemonize" ) ) {
strcpy( server_config->daemonize, value );
}
//free( key );
//free( value );
/*
for ( int i = 0; i < config_item_list_size; i++ ) {
if ( 0 == strcmp( key, config_item_list[ i ].key ) ) {
strcpy( config_item_list[ i ].value, value );
}
}
*/
}
return server_config;
}
/*
* @desc : creata a tcp server( single process & thread )
* @param : server_config_struct point
*/
server_struct * init_server( server_config_struct * server_config, ev_loop_struct * ev )
{
server_struct * server = (server_struct *)malloc(sizeof(server_struct));
server->config = server_config;
server->db_num = 1; // 这个,暂时没用,临时给1吧
struct sockaddr_in listen_socket_struct;
int listen_socket_fd;
int lis_sock_opt_addr_reuse = 1;
struct sockaddr_in client_socket_struct;
int client_socket_fd;
socklen_t client_socket_struct_length;
int common_ret;
// bzero:Not standard ANSI,deprecated! Sugguest memset~
//bzero( &listen_socket_struct, sizeof( listen_socket_struct ) );
memset(&listen_socket_struct, 0, sizeof(listen_socket_struct));
listen_socket_struct.sin_family = AF_INET;
// remember atoi
listen_socket_struct.sin_port = htons(atoi(server_config->port));
inet_pton(AF_INET, server_config->host, &listen_socket_struct.sin_addr);
// create listen socket.NOTE:if you do not know what exactly the last parameter means,just keep it 0
listen_socket_fd = socket(PF_INET, SOCK_STREAM, 0);
net_set_nonblock(listen_socket_fd);
if (listen_socket_fd < 0) {
printf("create socket error.");
exit(-1);
}
// fcntl
setsockopt(listen_socket_fd, SOL_SOCKET, SO_REUSEADDR,
&lis_sock_opt_addr_reuse, sizeof(lis_sock_opt_addr_reuse));
// convert sockaddr_in -> sockaddr_stroage,I think sockaddr_stroage would be better than sockaddr
common_ret = bind(listen_socket_fd, (struct sockaddr *)&listen_socket_struct, sizeof(listen_socket_struct));
if (common_ret < 0) {
printf("bind socket error.");
exit(-1);
}
// make the socket in listening.Second parameter is backlog
common_ret = listen(listen_socket_fd, 10);
if (common_ret < 0) {
printf("listen socket error.");
exit(-1);
}
server->listen_socket_fd = listen_socket_fd;
// init database, the hashmap struct
db_struct * db = (db_struct *)malloc(sizeof(db_struct));
// init the key hashtable
ht_st * key_ht = init_ht();
db->key = key_ht;
server->db = db;
// create an event-struct for listen_socket_fd
ev_create_file_event(ev, listen_socket_fd, net_accept_tcp_connect_processor, EV_READABLE);
return server;
}
/*
* @desc : unix standard daemon function.
* 1.Some guy may like fork twice( a little bird says [fork twice] to avoid SVR4 bugs,in some case,
fork once can not make the program separate from the CLI-terminal ),BUT I do it only once,you
may add the second fork to the code
2.The Linux standard libray supply a API in the unistd.h header file:daemon( int, int )
*/
bool daemonize()
{
pid_t pid;
pid = fork();
// fork error.
if ( pid < 0 ) {
return false;
}
// exit father process
if ( pid > 0 ) {
// notice:NOT return,BUT exit!
exit( 0 );
}
// from here,let rock the child process flow
umask( 0 );
pid_t sid;
sid = setsid();
if ( sid < 0 ) {
return false;
}
// change work directory
/*
chdir();
*/
// close STDIN STDOUT STDERR
close( STDIN_FILENO );
close( STDOUT_FILENO );
close( STDERR_FILENO );
// redirect STDIN STDOUT STDERR to /dev/null OR somewhere else
// /dev/null means : all the data-flow to /dev/null will directly missing
// little tip:open three "/dev/null" right after closing three STD-FILENO means the program will reuse file-no 0 1 2,bcz open sys-call will return the minimum number of the UN-USED file-no
// 0=STDIN_FILENO 1=STDOUT_FILENO 2=STDERR_FILENO
// dup/dup2 function could do the same work also
open( "/dev/null", O_RDONLY );
open( "/dev/null", O_RDWR );
open( "/dev/null", O_RDWR );
return true;
}