webroar 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/CHANGELOG +48 -1
  2. data/README +11 -14
  3. data/Rakefile +1 -1
  4. data/conf/mime_type.yml +172 -166
  5. data/conf/server_internal_config.yml +30 -8
  6. data/doc/user-guide.html +294 -153
  7. data/doc/user-guide.txt +9 -13
  8. data/lib/command_runner.rb +1 -0
  9. data/lib/dependencies.rb +18 -15
  10. data/lib/installer.rb +115 -50
  11. data/src/admin_panel/app/controllers/admin_controller.rb +1 -15
  12. data/src/admin_panel/app/controllers/application_controller.rb +2 -2
  13. data/src/admin_panel/app/controllers/application_specification_controller.rb +2 -1
  14. data/src/admin_panel/app/controllers/headers_controller.rb +73 -0
  15. data/src/admin_panel/app/controllers/mail_specification_controller.rb +10 -0
  16. data/src/admin_panel/app/controllers/server_specification_controller.rb +14 -0
  17. data/src/admin_panel/app/helpers/admin_helper.rb +0 -85
  18. data/src/admin_panel/app/models/app.rb +1 -1
  19. data/src/admin_panel/app/models/application_specification.rb +33 -25
  20. data/src/admin_panel/app/models/headers.rb +116 -0
  21. data/src/admin_panel/app/models/mail_specification.rb +20 -5
  22. data/src/admin_panel/app/models/server_specification.rb +2 -7
  23. data/src/admin_panel/app/views/admin/configuration.html.erb +10 -5
  24. data/src/admin_panel/app/views/exceptions/_exception_list_partial.html.erb +4 -4
  25. data/src/admin_panel/app/views/graph/_graph_page.html.erb +3 -0
  26. data/src/admin_panel/app/views/headers/_add_expires_text_box.html.erb +35 -0
  27. data/src/admin_panel/app/views/headers/_expires_by_type_form.html.erb +65 -0
  28. data/src/admin_panel/app/views/headers/_headers_table.html.erb +113 -0
  29. data/src/admin_panel/app/views/mail_specification/_current_spec.html.erb +168 -0
  30. data/src/admin_panel/app/views/{admin → server_specification}/_add_div.html.erb +1 -1
  31. data/src/admin_panel/config/initializers/application_constants.rb +6 -0
  32. data/src/admin_panel/lib/control.rb +6 -3
  33. data/src/admin_panel/lib/scgi.rb +74 -21
  34. data/src/admin_panel/lib/yaml_writer.rb +51 -17
  35. data/src/admin_panel/public/javascripts/application.js +20 -1
  36. data/src/head/wr_access_log.c +2 -2
  37. data/src/head/wr_application.c +294 -236
  38. data/src/head/wr_application.h +8 -8
  39. data/src/head/wr_configurator.c +451 -517
  40. data/src/head/wr_configurator.h +10 -115
  41. data/src/head/wr_connection.c +26 -25
  42. data/src/head/wr_connection.h +2 -3
  43. data/src/head/wr_controller.c +110 -93
  44. data/src/head/wr_controller.h +6 -6
  45. data/src/head/wr_main.c +31 -24
  46. data/src/head/wr_request.c +70 -93
  47. data/src/head/wr_request.h +0 -4
  48. data/src/head/wr_resolver.c +21 -15
  49. data/src/head/wr_resolver.h +2 -2
  50. data/src/head/wr_server.c +36 -26
  51. data/src/head/wr_server.h +5 -5
  52. data/src/head/wr_worker.c +551 -512
  53. data/src/head/wr_worker.h +33 -20
  54. data/src/helper/wr_config.c +316 -0
  55. data/src/helper/wr_config.h +235 -0
  56. data/src/helper/wr_helper.h +1 -5
  57. data/src/helper/wr_logger.c +4 -4
  58. data/src/helper/wr_scgi.c +3 -4
  59. data/src/helper/wr_scgi.h +2 -0
  60. data/src/helper/wr_string.h +2 -2
  61. data/src/helper/wr_util.c +3 -1
  62. data/src/helper/wr_util.h +0 -0
  63. data/src/helper/wr_yaml_parser.c +30 -0
  64. data/src/helper/wr_yaml_parser.h +1 -0
  65. data/src/ruby_lib/exception_tracker/instrumentation/action_controller.rb +2 -1
  66. data/src/ruby_lib/mailer/smtpmail.rb +7 -4
  67. data/src/ruby_lib/profiler/instrumentation/action_controller.rb +2 -1
  68. data/src/ruby_lib/profiler/instrumentation/active_record.rb +3 -0
  69. data/src/ruby_lib/rack/adapter/rails.rb +14 -7
  70. data/src/ruby_lib/ruby_interface/client.rb +1 -1
  71. data/src/ruby_lib/ruby_interface/version.rb +2 -2
  72. data/src/ruby_lib/webroar_app_loader.rb +4 -2
  73. data/src/worker/wkr_controller.c +200 -140
  74. data/src/worker/wkr_http.c +14 -28
  75. data/src/worker/wkr_http.h +4 -4
  76. data/src/worker/wkr_http_request.c +12 -11
  77. data/src/worker/wkr_http_request.h +7 -8
  78. data/src/worker/wkr_http_response.c +10 -14
  79. data/src/worker/wkr_http_response.h +0 -1
  80. data/src/worker/wkr_main.c +74 -140
  81. data/src/worker/wkr_static.c +295 -108
  82. data/src/worker/wkr_static.h +20 -7
  83. data/src/worker/worker.c +245 -70
  84. data/src/worker/worker.h +46 -34
  85. data/tasks/compile.rake +128 -175
  86. data/tasks/test.rake +345 -469
  87. data/test/spec/webroar_command_spec.rb +23 -0
  88. metadata +173 -43
  89. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/README +0 -34
  90. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/Rakefile +0 -13
  91. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/init.rb +0 -5
  92. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/lib/action_mailer_tls.rb +0 -16
  93. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/lib/smtp_tls.rb +0 -123
  94. data/src/admin_panel/vendor/plugins/action_mailer_optional_tls/test/tls_test.rb +0 -42
  95. data/src/head/wr_config.h +0 -165
  96. data/src/ruby_lib/mailer/action_mailer_tls.rb +0 -16
  97. data/src/ruby_lib/mailer/smtp_tls.rb +0 -123
data/src/head/wr_worker.c CHANGED
@@ -1,3 +1,6 @@
1
+
2
+ #include "wr_worker.h"
3
+
1
4
  /* WebROaR - Ruby Application Server - http://webroar.in/
2
5
  * Copyright (C) 2009 Goonj LLC
3
6
  *
@@ -17,31 +20,177 @@
17
20
  * along with WebROaR. If not, see <http://www.gnu.org/licenses/>.
18
21
  */
19
22
  #include <wr_request.h>
20
- #include <wr_access_log.h>
21
23
  #include <unistd.h>
22
24
  #include <errno.h>
23
25
  #include <fcntl.h>
24
26
  #include <sys/un.h>
25
27
 
28
+ extern config_t *Config;
29
+
26
30
  /** Private functions */
27
- static void wr_req_hearer_write_cb(struct ev_loop*, struct ev_io*, int);
31
+ void wr_req_hearer_write_cb(struct ev_loop*, struct ev_io*, int);
32
+ void wr_wrk_allocate(wr_wkr_t* worker);
33
+ void wr_wkr_ping_send(wr_wkr_t *worker);
34
+
35
+ void wr_wkr_state_machine(wr_wkr_t *worker, wr_wkr_action_t action){
36
+
37
+ switch(action){
38
+ case WKR_ACTION_ERROR:
39
+ case WKR_ACTION_REMOVE:
40
+ worker->state = WKR_STATE_ERROR;
41
+ wr_wkr_free(worker);
42
+ return;
43
+ }
28
44
 
29
- static inline void wr_wait_watcher_start(wr_wkr_t *w) {
30
- w->trials_done = 0;
45
+ switch(worker->state){
46
+ // Connecting
47
+ case WKR_STATE_CONNECTING:
48
+ switch(action){
49
+ case WKR_ACTION_ADD:
50
+ worker->state = WKR_STATE_INACTIVE;
51
+ return;
52
+ }
53
+ break;
54
+
55
+ // Active
56
+ case WKR_STATE_ACTIVE:
57
+ switch(action){
58
+ case WKR_ACTION_REQ_PROCESSED:
59
+ worker->state = WKR_STATE_INACTIVE;
60
+ wr_wrk_allocate(worker);
61
+ return;
62
+ case WKR_ACTION_PING_TIMEOUT:
63
+ if(worker->trials_done < Config->Server.Worker.ping_trials) {
64
+ worker->state = WKR_STATE_PINGING;
65
+ wr_wkr_ping_send(worker);
66
+ } else {
67
+ worker->state = WKR_STATE_HANGUP;
68
+ wr_app_t *app = worker->app;
69
+ wr_wkr_free(worker);
70
+ wr_app_wkr_balance(app);
71
+ }
72
+ return;
73
+ }
74
+ break;
75
+
76
+ // Inactive
77
+ case WKR_STATE_INACTIVE:
78
+ switch(action){
79
+ case WKR_ACTION_REQ_PROCESSING:
80
+ worker->state = WKR_STATE_ACTIVE;
81
+ return;
82
+ }
83
+ break;
84
+
85
+ // Pinging
86
+ case WKR_STATE_PINGING:
87
+ switch(action){
88
+ case WKR_ACTION_REQ_PROCESSED:
89
+ worker->state = WKR_STATE_INACTIVE;
90
+ wr_wrk_allocate(worker);
91
+ return;
92
+ case WKR_ACTION_REQ_PROCESSING:
93
+ worker->state = WKR_STATE_ACTIVE;
94
+ return;
95
+ case WKR_ACTION_PING_REPLAY:
96
+ worker->state = WKR_STATE_ACTIVE;
97
+ ev_timer_stop(worker->loop, &worker->t_wait);
98
+ worker->t_wait.repeat = Config->Server.Worker.idle_time;
99
+ ev_timer_again(worker->loop, &worker->t_wait);
100
+ return;
101
+ case WKR_ACTION_PING_TIMEOUT:
102
+ if(worker->trials_done < Config->Server.Worker.ping_trials) {
103
+ worker->state = WKR_STATE_PINGING;
104
+ wr_wkr_ping_send(worker);
105
+ } else {
106
+ worker->state = WKR_STATE_HANGUP;
107
+ wr_app_t *app = worker->app;
108
+ wr_wkr_free(worker);
109
+ wr_app_wkr_balance(app);
110
+ }
111
+ return;
112
+ }
113
+ break;
114
+
115
+ // Expired
116
+ case WKR_STATE_EXPIRED:
117
+ switch(action){
118
+ case WKR_ACTION_REQ_PROCESSED:
119
+ case WKR_ACTION_PING_TIMEOUT:
120
+ worker->state = WKR_STATE_DISCONNECTING;
121
+ wr_wkr_free(worker);
122
+ return;
123
+ }
124
+ break;
125
+
126
+ // Acknowledge Error message
127
+ case WKR_STATE_ERROR_ACK:
128
+ break;
129
+
130
+ case WKR_STATE_ERROR: // Error
131
+ case WKR_STATE_TIMEDOUT: // Timedout
132
+ case WKR_STATE_HANGUP: // Hangup
133
+ case WKR_STATE_DISCONNECTING: // Disconnecting
134
+ wr_wkr_free(worker);
135
+ break;
136
+ }
137
+ }
138
+
139
+ void wr_wkr_ping_send(wr_wkr_t *worker){
140
+ worker->trials_done++;
141
+ LOG_INFO("Worker %d with pid %u ping for trial no %d",
142
+ worker->id, worker->pid, worker->trials_done);
143
+ worker->t_wait.repeat = Config->Server.Worker.ping_timeout;
144
+
145
+ scgi_t *scgi = scgi_new();
146
+ scgi_header_add(scgi, "COMPONENT", strlen("COMPONENT"), "WORKER", strlen("WORKER"));
147
+ scgi_header_add(scgi, "METHOD", strlen("METHOD"), "PING", strlen("PING"));
148
+ if(scgi_build(scgi)!=0) {
149
+ LOG_ERROR(WARN,"SCGI request build failed.");
150
+ }
151
+ worker->ctl->scgi = scgi;
152
+ ev_io_start(worker->loop, &worker->ctl->w_write);
153
+ //ev_timer_again(loop, &worker->t_ping_wait);
154
+ ev_timer_again(worker->loop, &worker->t_wait);
155
+ }
156
+
157
+ void wr_wait_watcher_start(wr_wkr_t *worker) {
158
+ wr_wkr_state_machine(worker, WKR_ACTION_REQ_PROCESSING);
159
+ worker->trials_done = 0;
31
160
  // Clear WR_WKR_PING_SENT, WR_WKR_PING_REPLIED and WR_WKR_HANG state.
32
- w->state &= (~224);
33
- w->t_wait.repeat = WR_WKR_IDLE_TIME;
34
- ev_timer_again(w->loop, &w->t_wait);
161
+ if(Config->Server.Worker.idle_time > 0){
162
+ worker->t_wait.repeat = Config->Server.Worker.idle_time;
163
+ ev_timer_again(worker->loop, &worker->t_wait);
164
+ }
165
+ }
166
+
167
+ void wr_wkr_req_processing(wr_wkr_t* worker, wr_req_t* req){
168
+ LOG_DEBUG(4,"Allocate worker %d to req id %d", worker->id , req->id);
169
+ req->wkr = worker;
170
+ req->using_wkr = TRUE;
171
+
172
+ worker->req = req;
173
+ worker->watcher.data = req;
174
+
175
+ wr_wkr_state_machine(worker, WKR_ACTION_REQ_PROCESSING);
176
+
177
+ ev_io_init(&worker->watcher, wr_req_hearer_write_cb, worker->fd, EV_WRITE);
178
+ ev_io_start(worker->loop,&worker->watcher);
35
179
  }
36
180
 
37
181
  /** Check for pending request to process */
38
- static inline void wr_wrk_allocate(wr_wkr_t* worker) {
182
+ void wr_wrk_allocate(wr_wkr_t* worker) {
39
183
  LOG_FUNCTION
40
184
  wr_req_t* req;
41
185
  wr_app_t* app = worker->app;
42
186
  wr_svr_t* server = app->svr;
43
187
  int retval;
188
+
44
189
  //do we need high load ratio check here?
190
+ if(worker->app){
191
+ wr_app_chk_load_to_remove_wkr(worker->app);
192
+ }
193
+
45
194
  if(app && app->q_messages->q_count > 0) {
46
195
  //There is pending request
47
196
  WR_QUEUE_FETCH(app->q_messages, req) ;
@@ -49,47 +198,30 @@ static inline void wr_wrk_allocate(wr_wkr_t* worker) {
49
198
  if(req == NULL) {
50
199
  WR_QUEUE_INSERT(app->q_free_workers, worker, retval) ;
51
200
  } else {
52
- LOG_DEBUG(4,"Allocate worker %d to req id %d", worker->id , req->id);
53
- req->wkr = worker;
54
- worker->req = req;
55
- worker->watcher.data = req;
56
- ev_io_init(&worker->watcher, wr_req_hearer_write_cb, worker->fd, EV_WRITE);
57
- ev_io_start(server->ebb_svr.loop,&worker->watcher);
201
+ wr_wkr_req_processing(worker, req);
58
202
  }
59
203
  } else if(app) {
60
204
  //No any pending request. Add Worker to free worker list
61
205
  LOG_DEBUG(4,"Message queue is empty");
62
206
  WR_QUEUE_INSERT(app->q_free_workers, worker, retval) ;
63
207
  } else {
64
- //Remove worker
65
- LOG_ERROR(SEVERE,"wr_wrk_allocate: Remove worker with pid %d.", worker->pid);
66
- wr_wkr_free(worker);
208
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
67
209
  }
68
210
  }
69
211
 
70
- static inline void wr_wkr_release(wr_req_t* req) {
71
- LOG_FUNCTION
72
- wr_wkr_t* worker = req->wkr;
73
-
74
- LOG_DEBUG(DEBUG,"req %d", req->id);
75
- wr_req_free(req);
212
+ void wr_wkr_req_processed(wr_wkr_t *worker){
213
+ wr_req_free(worker->req);
76
214
  worker->req = NULL;
77
- //Check applicatio load
78
- if(worker->app)
79
- wr_app_chk_load_to_remove_wkr(worker->app);
80
-
81
- // Check worker status before allication
82
- if(worker->state & WR_WKR_ACTIVE) {
83
- wr_wrk_allocate(worker);
84
- } else {
85
- // Remove worker if it is not active
86
- LOG_ERROR(SEVERE,"wr_wkr_release: Remove worker with pid %d", worker->pid);
87
- wr_wkr_remove(worker, 0);
215
+ LOG_DEBUG(DEBUG,"Idle watcher stopped for worker %d", worker->id);
216
+ // worker is done with current Request
217
+ if(Config->Server.Worker.idle_time > 0){
218
+ ev_timer_stop(worker->loop,&worker->t_wait);
88
219
  }
220
+ wr_wkr_state_machine(worker, WKR_ACTION_REQ_PROCESSED);
89
221
  }
90
222
 
91
223
  /** Reads streamed response from Worker */
92
- static void wr_resp_read_cb(struct ev_loop *loop,struct ev_io *w, int revents) {
224
+ void wr_resp_read_cb(struct ev_loop *loop,struct ev_io *w, int revents) {
93
225
  LOG_FUNCTION
94
226
  wr_req_t *req = (wr_req_t*) w->data;
95
227
  wr_wkr_t *worker = req->wkr;
@@ -108,10 +240,8 @@ static void wr_resp_read_cb(struct ev_loop *loop,struct ev_io *w, int revents) {
108
240
  wr_min(WR_RESP_BUF_SIZE,req->resp_buf_len - req->bytes_received),
109
241
  0);
110
242
  if(read <= 0) {
111
- ev_io_stop(loop,w);
112
243
  LOG_ERROR(WARN,"Error reading response:%s",strerror(errno));
113
- worker->state += (WR_WKR_ERROR + WR_WKR_HANG);
114
- wr_ctl_free(worker->ctl);
244
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
115
245
  return;
116
246
  }
117
247
 
@@ -128,22 +258,57 @@ static void wr_resp_read_cb(struct ev_loop *loop,struct ev_io *w, int revents) {
128
258
  //if(req->bytes_received == req->resp_buf_len) {
129
259
  if(req->bytes_received >= req->resp_buf_len) {
130
260
  ev_io_stop(loop, w);
131
- LOG_DEBUG(DEBUG,"Idle watcher stopped for worker %d", worker->id);
132
- // worker is done with current Request
133
- worker->req = NULL;
134
- req->using_wkr = FALSE;
135
-
136
- worker->state &= (~224);
137
- ev_timer_stop(worker->loop,&worker->t_wait);
138
- // Close Request once response read
139
- wr_wkr_release(req);
261
+ wr_wkr_req_processed(worker);
140
262
  } else {
141
263
  wr_wait_watcher_start(worker);
142
264
  }
143
265
  }
144
266
 
267
+ int wr_wkr_set_req(wr_wkr_t *worker, wr_req_t* req, scgi_t* scgi){
268
+ const char *value = scgi_header_value_get(scgi, SCGI_CONTENT_LENGTH);
269
+
270
+ // Set response length
271
+ req->resp_buf_len = (value ? atoi(value) : 0);
272
+
273
+ // Set rsponse code
274
+ value = scgi_header_value_get(scgi, Config->Request.Header.resp_code.str);
275
+ req->resp_code = (value ? atoi(value) : 0);
276
+
277
+ // Set content length
278
+ value = scgi_header_value_get(scgi, Config->Request.Header.resp_content_len.str);
279
+ req->resp_body_len = (value ? atoi(value) : 0);
280
+
281
+ LOG_DEBUG(DEBUG,"resp_code = %d, content len = %d, resp len = %d",
282
+ req->resp_code,
283
+ req->resp_body_len,
284
+ req->resp_buf_len);
285
+ // Response length should be greater than 0
286
+ if(req->resp_buf_len == 0) {
287
+ //TODO: Render 500 Internal Error, close Request, allocate worker to next Request
288
+ LOG_ERROR(WARN,"Got response len 0");
289
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
290
+ return FALSE;
291
+ }
292
+
293
+ if(!req->conn_err && req->app && Config->Server.flag & SERVER_ACCESS_LOG) {
294
+ wr_access_log(req);
295
+ }
296
+
297
+ scgi_free(req->scgi);
298
+ req->scgi = NULL;
299
+
300
+ req->bytes_received = scgi->body_length;
301
+ LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() bytes read = %d", req->bytes_received);
302
+ if(req->bytes_received > 0 && !req->conn_err) {
303
+ wr_conn_resp_body_add(req->conn, scgi->body, scgi->body_length);
304
+ }
305
+
306
+ scgi_free(scgi);
307
+ return TRUE;
308
+ }
309
+
145
310
  /** Reads the response from worker, deserialize it, render it to the Request. */
146
- static void wr_resp_len_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
311
+ void wr_resp_len_read_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
147
312
  LOG_FUNCTION
148
313
  wr_req_t* req = (wr_req_t*) w->data;
149
314
  wr_wkr_t *worker = req->wkr;
@@ -162,8 +327,7 @@ static void wr_resp_len_read_cb(struct ev_loop *loop, struct ev_io *w, int reven
162
327
  if(read <= 0) {
163
328
  ev_io_stop(loop,w);
164
329
  LOG_ERROR(WARN,"Error reading response:%s",strerror(errno));
165
- worker->state += (WR_WKR_ERROR + WR_WKR_HANG);
166
- wr_ctl_free(worker->ctl);
330
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
167
331
  return;
168
332
  }
169
333
 
@@ -174,82 +338,46 @@ static void wr_resp_len_read_cb(struct ev_loop *loop, struct ev_io *w, int reven
174
338
 
175
339
  scgi_t* scgi = scgi_parse(req->resp_buf, req->bytes_received);
176
340
 
177
- if(scgi) {
178
- ev_io_stop(loop,w);
179
- const char *value = scgi_header_value_get(scgi, SCGI_CONTENT_LENGTH);
180
- // Set response length
181
- if(value)
182
- req->resp_buf_len = atoi(value);
183
- else
184
- req->resp_buf_len = 0;
185
-
186
- // Set rsponse code
187
- value = scgi_header_value_get(scgi, RESP_CODE);
188
- if(value)
189
- req->resp_code = atoi(value);
190
- else
191
- req->resp_code = 0;
192
-
193
- // Set content length
194
- value = scgi_header_value_get(scgi, RESP_CONTENT_LENGTH);
195
- if(value)
196
- req->resp_body_len = atoi(value);
197
- else
198
- req->resp_body_len = 0;
199
-
200
- LOG_DEBUG(DEBUG,"resp_code = %d, content len = %d, resp len = %d",
201
- req->resp_code,
202
- req->resp_body_len,
203
- req->resp_buf_len);
204
- // Response length should be greater than 0
205
- if(req->resp_buf_len == 0) {
206
- //TODO: Render 500 Internal Error, close Request, allocate worker to next Request
207
- LOG_ERROR(WARN,"Got response len 0");
208
- ev_io_stop(loop,w);
209
- worker->state += (WR_WKR_ERROR + WR_WKR_HANG);
210
- wr_ctl_free(worker->ctl);
211
- return;
212
- }
213
-
214
- if(!req->conn_err && req->app && req->app->svr->conf->server->flag & WR_SVR_ACCESS_LOG) {
215
- wr_access_log(req);
216
- }
341
+ if(scgi == NULL) return;
342
+ ev_io_stop(loop,w);
217
343
 
218
- scgi_free(req->scgi);
219
- req->scgi = NULL;
344
+ if(wr_wkr_set_req(worker, req, scgi) == FALSE) return;
345
+
346
+ // Check for response length
347
+ if(req->resp_buf_len == req->bytes_received) {
348
+ wr_wkr_req_processed(worker);
349
+ } else {
350
+ LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() Request %d, read %d/%d",
351
+ req->id,
352
+ req->bytes_received,
353
+ req->resp_buf_len);
354
+ ev_io_init(w,wr_resp_read_cb, w->fd,EV_READ);
355
+ ev_io_start(loop,w);
356
+ wr_wait_watcher_start(worker);
357
+ }
358
+ }
220
359
 
221
- req->bytes_received = scgi->body_length;
222
- LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() bytes read = %d", req->bytes_received);
223
- if(req->bytes_received > 0 && !req->conn_err) {
224
- wr_conn_resp_body_add(req->conn, scgi->body, scgi->body_length);
225
- }
360
+ void wr_wkr_req_sent(wr_wkr_t *worker){
361
+ ev_io_stop(worker->loop, &worker->watcher);
362
+ wr_req_t * req = worker->req;
226
363
 
227
- scgi_free(scgi);
228
-
229
- // Check for response length
230
- if(req->resp_buf_len == req->bytes_received) {
231
- LOG_DEBUG(DEBUG,"Idle watcher stopped for worker %d", worker->id);
232
- // worker is done with current Request
233
- worker->req = NULL;
234
- req->using_wkr = FALSE;
235
- worker->state &= (~224);
236
- ev_timer_stop(worker->loop,&worker->t_wait);
237
- // Close Request once complete response read
238
- wr_wkr_release(req);
239
- } else {
240
- LOG_DEBUG(DEBUG,"wr_resp_len_read_cb() Request %d, read %d/%d",
241
- req->id,
242
- req->bytes_received,
243
- req->resp_buf_len);
244
- ev_io_init(w,wr_resp_read_cb, w->fd,EV_READ);
245
- ev_io_start(loop,w);
246
- wr_wait_watcher_start(worker);
247
- }
364
+ if(req->upload_file) {
365
+ fclose(req->upload_file);
366
+ remove(req->upload_file_name->str);
367
+ wr_buffer_free(req->upload_file_name);
368
+ req->upload_file = NULL;
248
369
  }
370
+
371
+ ev_io_init(&worker->watcher, wr_resp_len_read_cb, worker->fd, EV_READ);
372
+ ev_io_start(worker->loop,&worker->watcher);
373
+ //We are waiting for response from worker, start idle watcher for it
374
+ LOG_DEBUG(DEBUG,"Idle watcher started for worker %d", worker->id);
375
+ wr_wait_watcher_start(worker);
249
376
  }
250
377
 
251
378
  /** Send SCGI formatted request stream to Worker*/
252
- static void wr_req_body_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
379
+ /* Send request body to worker */
380
+ void wr_req_body_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
253
381
  LOG_FUNCTION
254
382
  wr_req_t *req = (wr_req_t*) w->data;
255
383
  wr_wkr_t *worker = req->wkr;
@@ -259,22 +387,20 @@ static void wr_req_body_write_cb(struct ev_loop *loop, struct ev_io *w, int reve
259
387
  return;
260
388
 
261
389
  if(req->upload_file) {
262
- char buffer[WR_REQ_BODY_MAX_SIZE];
390
+ char buffer[Config->Request.max_body_size];
263
391
  ssize_t read;
264
392
  int rv=fseek(req->upload_file,req->bytes_sent,SEEK_SET);
265
393
  if(rv<0) {
266
394
  LOG_ERROR(WARN,"Error reading file:%s",strerror(errno));
267
395
  return;
268
396
  }
269
- read = fread(buffer,1,WR_REQ_BODY_MAX_SIZE,req->upload_file);
397
+ read = fread(buffer,1,Config->Request.max_body_size,req->upload_file);
270
398
  sent = send(w->fd, buffer, read, 0);
271
399
  }
272
400
 
273
401
  if(sent <= 0) {
274
- ev_io_stop(loop,w);
275
402
  LOG_ERROR(WARN,"Error sending request:%s",strerror(errno));
276
- worker->state += (WR_WKR_ERROR + WR_WKR_HANG);
277
- wr_ctl_free(worker->ctl);
403
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
278
404
  return;
279
405
  }
280
406
 
@@ -282,31 +408,14 @@ static void wr_req_body_write_cb(struct ev_loop *loop, struct ev_io *w, int reve
282
408
  LOG_DEBUG(DEBUG,"Request %d sent %d/%d", req->id, req->bytes_sent, req->ebb_req->content_length);
283
409
 
284
410
  if(req->ebb_req->content_length == req->bytes_sent) {
285
- ev_io_stop(loop,w);
286
-
287
- LOG_DEBUG(DEBUG,"Sent request body for Request %d to worker %d", req->id, worker->id);
288
- if(req->upload_file) {
289
- fclose(req->upload_file);
290
- remove(req->upload_file_name->str);
291
- wr_buffer_free(req->upload_file_name);
292
- req->upload_file = NULL;
293
- }
294
-
295
- scgi_free(req->scgi);
296
- req->scgi = NULL;
297
-
298
- ev_io_init(w,wr_resp_len_read_cb,w->fd,EV_READ);
299
- ev_io_start(loop,w);
300
- //We are waiting for response from worker, start idle watcher for it
301
- LOG_DEBUG(DEBUG,"Idle watcher started for worker %d", worker->id);
302
- wr_wait_watcher_start(worker);
303
- //wr_wkr_idle_watch_reset(worker);
411
+ wr_wkr_req_sent(worker);
304
412
  }
305
413
  }
306
414
 
307
415
  /** Start writing SCGI formatted request to Worker */
416
+ /* Send request headers to worker */
308
417
  //whenever there is a pending request for processing and worker's fd is ready for write, it will dump serialized data to worker by this function
309
- static void wr_req_hearer_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
418
+ void wr_req_hearer_write_cb(struct ev_loop *loop, struct ev_io *w, int revents) {
310
419
  LOG_FUNCTION
311
420
  wr_req_t* req = (wr_req_t*) w->data;
312
421
  wr_wkr_t *worker = req->wkr;
@@ -318,92 +427,64 @@ static void wr_req_hearer_write_cb(struct ev_loop *loop, struct ev_io *w, int re
318
427
  if(scgi_send(req->scgi, w->fd) <= 0){
319
428
  ev_io_stop(loop,w);
320
429
  LOG_ERROR(WARN,"Error sending request:%s",strerror(errno));
321
- worker->state += (WR_WKR_ERROR + WR_WKR_HANG);
322
- wr_ctl_free(worker->ctl);
323
- return;
430
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
324
431
  }
325
432
  LOG_DEBUG(DEBUG,"Request %d write %d/%d", req->id, req->scgi->bytes_sent,
326
433
  req->scgi->length);
327
434
  if(req->scgi->bytes_sent == req->scgi->length) {
328
- ev_io_stop(loop,w);
435
+
329
436
  LOG_DEBUG(DEBUG,"Sent request header for Request %d to worker %d", req->id, worker->id);
330
437
  req->bytes_sent = 0;
331
438
 
332
439
  if(req->upload_file) {
440
+ ev_io_stop(loop,w);
333
441
  ev_io_init(w,wr_req_body_write_cb,w->fd,EV_WRITE);
442
+ ev_io_start(loop,w);
334
443
  } else {
335
- ev_io_init(w, wr_resp_len_read_cb, w->fd,EV_READ);
336
- //We are waiting for response from worker, start idle watcher for it
337
- LOG_DEBUG(DEBUG,"Idle watcher started for worker %d", worker->id);
338
- //wr_wkr_idle_watch_reset(worker);
339
- wr_wait_watcher_start(worker);
444
+ wr_wkr_req_sent(worker);
340
445
  }
341
- ev_io_start(loop,w);
342
446
  }
343
447
  }
344
448
 
345
- /*******************************************
346
- * Worker Function Definition *
347
- *******************************************/
348
-
349
- static inline void wr_wkr_recreate(wr_wkr_t *worker) {
350
- LOG_FUNCTION
351
- wr_req_t *req = worker->req;
449
+ typedef struct {
450
+ char log_level[STR_SIZE32], controller_path[STR_SIZE32];
451
+ wr_str_t baseuri;
452
+ }wr_wkr_create_t;
352
453
 
353
- // Need to stop ev_io so that all the pending call related to worker turns out to void
354
- ev_io_stop(worker->loop, &worker->watcher);
355
- worker->state &= (~224);
356
- worker->state |= WR_WKR_HANG;
357
- ev_timer_stop(worker->loop,&worker->t_wait);
358
-
359
- if(req) {
360
- LOG_ERROR(SEVERE,"Worker %d Hangup. Killing it. Request id = %d, Connection id = %d, Request Path is %s",
361
- worker->id, req->id, req->conn->id, req->req_uri.str);
362
- wr_conn_err_resp(req->conn, WR_HTTP_STATUS_500);
363
- }
364
- wr_app_t *app = worker->app;
365
- worker->state |= WR_WKR_ERROR;
366
- wr_wkr_remove(worker, 0);
367
- //create new worker if required
368
- if(TOTAL_WORKER_COUNT(app) < app->conf->min_worker ||
369
- app->q_messages->q_count > app->high_ratio) {
370
- wr_app_wkr_add(app);
454
+ wr_wkr_create_t* wr_wkr_create_init(wr_svr_t *server, config_application_list_t *app_conf){
455
+ wr_wkr_create_t *worker = wr_malloc(wr_wkr_create_t);
456
+
457
+ wr_string_null(worker->baseuri);
458
+ if(app_conf->baseuri.str) {
459
+ wr_string_dump(worker->baseuri, app_conf->baseuri);
460
+ } else {
461
+ wr_string_new(worker->baseuri, "/", 1);
371
462
  }
463
+
464
+ sprintf(worker->log_level, "%d", app_conf->log_level);
465
+
466
+ if(Config->Server.flag & SERVER_UDS_SUPPORT) {
467
+ strcpy(worker->controller_path, server->ctl->sock_path.str);
468
+ } else {
469
+ sprintf(worker->controller_path, "%d", server->ctl->port);
470
+ }
471
+
472
+ return worker;
372
473
  }
373
474
 
374
475
  /** This would get called when idel time watcher goes timeout */
375
- static void wr_wkr_wait_cb(struct ev_loop *loop, ev_timer *w, int revents) {
476
+ void wr_wkr_wait_cb(struct ev_loop *loop, ev_timer *w, int revents) {
376
477
  LOG_FUNCTION
377
478
  wr_wkr_t *worker = (wr_wkr_t*)w->data;
378
-
479
+
379
480
  //ev_timer_stop(loop, &worker->t_idle);
380
481
  ev_timer_stop(loop, &worker->t_wait);
381
-
482
+
382
483
  if(worker->app == NULL) {
383
484
  LOG_INFO("wr_wkr_wait_cb: Worker removed with pid %d", worker->pid);
384
- wr_wkr_free(worker);
385
- } else if(worker->trials_done < WR_PING_TRIALS) {
386
- worker->trials_done++;
387
- LOG_INFO("Worker %d with pid %u ping for trial no %d",
388
- worker->id, worker->pid, worker->trials_done);
389
- worker->t_wait.repeat = WR_PING_WAIT_TIME;
390
- worker->state |= (WR_WKR_HANG | WR_WKR_PING_SENT);
391
- if(worker->state & WR_WKR_PING_REPLIED) {
392
- worker->state ^= WR_WKR_PING_REPLIED;
393
- }
394
- scgi_t *scgi = scgi_new();
395
- scgi_header_add(scgi, "COMPONENT", strlen("COMPONENT"), "WORKER", strlen("WORKER"));
396
- scgi_header_add(scgi, "METHOD", strlen("METHOD"), "PING", strlen("PING"));
397
- if(scgi_build(scgi)!=0) {
398
- LOG_ERROR(WARN,"SCGI request build failed.");
399
- }
400
- worker->ctl->scgi = scgi;
401
- ev_io_start(loop, &worker->ctl->w_write);
402
- //ev_timer_again(loop, &worker->t_ping_wait);
403
- ev_timer_again(loop, &worker->t_wait);
404
- } else {
405
- //render 500 response to Request, kill the worker
406
- wr_wkr_recreate(worker);
485
+ wr_wkr_state_machine(worker, WKR_ACTION_ERROR);
486
+ }else{
487
+ wr_wkr_state_machine(worker, WKR_ACTION_PING_TIMEOUT);
407
488
  }
408
489
  }
409
490
 
@@ -413,7 +494,7 @@ wr_wkr_t* wr_wkr_new(wr_ctl_t *ctl) {
413
494
  wr_wkr_t* worker = wr_malloc(wr_wkr_t);
414
495
  if(worker == NULL)
415
496
  return NULL;
416
-
497
+
417
498
  // Set default value
418
499
  worker->ctl = ctl;
419
500
  worker->req = NULL;
@@ -422,146 +503,199 @@ wr_wkr_t* wr_wkr_new(wr_ctl_t *ctl) {
422
503
  worker->pid = 0;
423
504
  worker->app = NULL;
424
505
  worker->watcher.active = 0;
425
- worker->state = WR_WKR_CLEAR;
506
+ worker->state = WKR_STATE_CONNECTING;
426
507
  worker->trials_done = 0;
427
508
  worker->t_wait.data = worker;
428
509
  worker->loop = ctl->svr->ebb_svr.loop;
429
- ev_timer_init(&worker->t_wait, wr_wkr_wait_cb, 0., WR_WKR_IDLE_TIME);
510
+ if(Config->Server.Worker.idle_time > 0){
511
+ ev_timer_init(&worker->t_wait, wr_wkr_wait_cb, 0., Config->Server.Worker.idle_time);
512
+ }
430
513
  return worker;
431
514
  }
432
515
 
433
- /** Destroy worker */
434
- void wr_wkr_free(wr_wkr_t *worker) {
435
- LOG_FUNCTION
436
- if(worker->state & WR_WKR_ACTIVE) {
437
- worker->state -= WR_WKR_ACTIVE ;
438
- }
439
-
440
- if(ev_is_active(&worker->t_wait))
441
- ev_timer_stop(worker->loop,&worker->t_wait);
442
-
443
- //Kill the process
444
- if(!(worker->state & WR_WKR_ERROR) &&
445
- !(worker->state & WR_WKR_DISCONNECT) &&
446
- worker->req == NULL &&
447
- worker->pid > 0) {
448
- LOG_DEBUG(DEBUG,"Stopping worker %d with pid %d...",worker->id, worker->pid);
449
- LOG_INFO("Stopping worker %d with pid %d...",worker->id, worker->pid);
450
- scgi_t* remove_req = scgi_new();
451
- if(remove_req) {
452
- scgi_header_add(remove_req, "METHOD", strlen("METHOD"), "REMOVE", strlen("REMOVE"));
453
- scgi_build(remove_req);
454
- //TODO: made it asynchronous
455
- send(worker->ctl->fd, remove_req->header + remove_req->start_offset, remove_req->length, 0);
456
- scgi_free(remove_req);
457
- } else {
458
- kill(worker->pid,SIGHUP);
516
+ int wr_wkr_check_uds(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg){
517
+ if(Config->Server.flag & SERVER_UDS_SUPPORT) {
518
+ if(strcmp(ctl_msg->msg.wkr.uds.str,"YES")!=0 ||
519
+ ctl_msg->msg.wkr.sock_path.str == NULL) {
520
+ scgi_body_add(ctl->scgi, "Invalid UDS, sock path and configuration.", strlen("Invalid UDS, sock path and configuration."));
521
+ LOG_ERROR(SEVERE,"connect_with_worker()Invalid UDS, sock path and configuration.");
522
+ return FALSE;
459
523
  }
460
- worker->pid = 0;
461
- } else if(worker->state & WR_WKR_HANG) {
462
- kill(worker->pid,SIGKILL);
463
- LOG_DEBUG(DEBUG,"Worker %d with pid %d killed...",worker->id, worker->pid);
464
- LOG_INFO("Worker %d with pid %d killed...",worker->id, worker->pid);
465
- } else if(worker->req && worker->app) {
466
- LOG_DEBUG(DEBUG,"Worker %d with pid %d. Waiting for worker...",worker->id, worker->pid);
467
- LOG_INFO("Worker %d with pid %d. Waiting for worker...",worker->id, worker->pid);
468
- worker->app = NULL;
469
- worker->t_wait.repeat = WR_WKR_KILL_TIMEOUT;
470
- ev_timer_again(worker->loop, &worker->t_wait);
471
- return;
472
- } else if(worker->req) {
473
- LOG_DEBUG(DEBUG,"Worker %d with pid %d. Worker cannot served the request.",worker->id, worker->pid);
474
- LOG_INFO("Worker %d with pid %d. Worker cannot served the request.",worker->id, worker->pid);
475
- if(ev_is_active(&worker->watcher))
476
- ev_io_stop(worker->loop,&worker->watcher);
477
- worker->req->using_wkr = FALSE;
478
- wr_conn_err_resp(worker->req->conn, WR_HTTP_STATUS_500);
479
- kill(worker->pid,SIGKILL);
480
- LOG_DEBUG(DEBUG,"Worker %d with pid %d killed...",worker->id, worker->pid);
481
524
  } else {
482
- kill(worker->pid,SIGKILL);
483
- LOG_DEBUG(DEBUG,"Worker %d with pid %d killed...",worker->id, worker->pid);
484
- LOG_INFO("Worker %d with pid %d killed...",worker->id, worker->pid);
525
+ if(strcmp(ctl_msg->msg.wkr.uds.str,"NO")!=0 ||
526
+ ctl_msg->msg.wkr.port.str == NULL) {
527
+ scgi_body_add(ctl->scgi, "Invalid UDS, sock path and configuration.", strlen("Invalid UDS, sock path and configuration."));
528
+ LOG_ERROR(SEVERE,"connect_with_worker()Invalid UDS, sock path and configuration.");
529
+ return FALSE;
530
+ }
485
531
  }
532
+ return TRUE;
533
+ }
486
534
 
487
- if(worker->ctl) {
488
- worker->ctl->wkr = NULL;
489
- wr_ctl_free(worker->ctl);
535
+ /** Connect to worker using UDS */
536
+ int wr_wkr_connect_uds(wr_wkr_t* worker, const wr_ctl_msg_t *ctl_msg){
537
+ struct sockaddr_un addr;
538
+ int len;
539
+
540
+ if((worker->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
541
+ perror("socket()");
542
+ LOG_ERROR(4,"socket() failed");
543
+ // Worker is not added, Reset the high load ratio
544
+ return FALSE;
545
+ }
546
+
547
+ LOG_DEBUG(3,"Socket successfully open for worker. File Descriptor is %d",worker->fd);
548
+
549
+ setsocketoption(worker->fd);
550
+ memset(&addr, 0, sizeof(addr));
551
+
552
+ addr.sun_family = AF_UNIX;
553
+ strcpy(addr.sun_path,ctl_msg->msg.wkr.sock_path.str);
554
+ len = sizeof(addr.sun_family) + strlen(addr.sun_path);
555
+
556
+ #ifdef __APPLE__
557
+ len++;
558
+ #endif
559
+
560
+ if(connect(worker->fd, (struct sockaddr *)&addr,len) == -1) {
561
+ perror("connect");
562
+ LOG_ERROR(4,"Unable to connect with worker at socket path %s. %s Closing it.",addr.sun_path, strerror(errno));
563
+ close_fd(worker->fd);
564
+ worker->fd=0;
565
+ // Worker is not added, Reset the high load ratio
566
+ return FALSE;
490
567
  }
491
- //Close socket
492
- if(worker->fd > 0)
493
- close(worker->fd);
494
-
495
- free(worker);
568
+
569
+ return TRUE;
496
570
  }
497
571
 
498
- /** Remove worker */
499
- int wr_wkr_remove(wr_wkr_t *worker, int flag) {
500
- LOG_FUNCTION
501
- wr_app_t* app = worker->app;
502
-
503
- if(worker->state & WR_WKR_ACTIVE)
504
- worker->state -= WR_WKR_ACTIVE;
505
-
506
- if(app) {
507
- LOG_INFO("Removing worker %d with pid %d...app->q_workers->q_count=%d, q_front=%d, q_rear=%d app=%s",
508
- worker->id, worker->pid,app->q_workers->q_count,app->q_workers->q_front,app->q_workers->q_rear,
509
- app->conf->name.str);
510
- } else {
511
- LOG_INFO("Removing worker %d with pid %d", worker->id, worker->pid);
572
+ /** Connect to worker using internet socket */
573
+ int wr_wkr_connect_inet(wr_wkr_t* worker, const wr_ctl_msg_t *ctl_msg){
574
+ struct sockaddr_in addr;
575
+ if ((worker->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
576
+ perror("socket()");
577
+ LOG_ERROR(4,"socket() failed for worker");
578
+ // Worker is not added, Reset the high load ratio
579
+ // return if not able to connect to the first worker
580
+ return FALSE;
581
+ }
582
+ LOG_DEBUG(3,"Socket successfully open for worker. File Descriptor is %d",worker->fd);
583
+
584
+ setsocketoption(worker->fd);
585
+ memset(&addr, 0, sizeof(addr));
586
+
587
+ addr.sin_family = AF_INET;
588
+ addr.sin_port = htons(atoi(ctl_msg->msg.wkr.port.str));
589
+ addr.sin_addr.s_addr =inet_addr("127.0.0.1");
590
+
591
+ if(connect(worker->fd, (struct sockaddr *)&addr,sizeof addr) == -1) {
592
+ perror("connect");
593
+ LOG_ERROR(4,"Unable to connect with worker at port %s. %s Closing it.",ctl_msg->msg.wkr.port.str, strerror(errno));
594
+ close_fd(worker->fd);
595
+ worker->fd=0;
596
+ return FALSE;
512
597
  }
598
+
599
+ return TRUE;
600
+ }
513
601
 
514
- if(app && wr_queue_remove(app->q_workers, worker) == 0) {
515
- app->high_ratio = TOTAL_WORKER_COUNT(app) * WR_MAX_REQ_RATIO;
516
- app->low_ratio = WR_QUEUE_SIZE(app->q_workers) * WR_MIN_REQ_RATIO;
517
-
518
- if(flag) {
519
- wr_queue_remove(app->q_free_workers, worker);
520
- }
521
- wr_wkr_free(worker);
522
- return 0;
523
- } else if(app == NULL) {
524
- wr_wkr_free(worker);
525
- return 0;
602
+ int wr_wkr_set_ratio(wr_ctl_t *ctl, wr_wkr_t* worker){
603
+ if(setnonblock(worker->fd) < 0) {
604
+ LOG_ERROR(SEVERE,"Setting worker_fd non-block failed:%s",strerror(errno));
605
+ close_fd(worker->fd);
606
+ return FALSE;
526
607
  }
527
-
528
- return -1;
608
+
609
+ if(wr_queue_insert(worker->app->q_workers, worker) < 0){
610
+ LOG_ERROR(WARN,"Worker queue is full.");
611
+ return FALSE;
612
+ }
613
+
614
+ //Setting low load ratio for application, refer "wr_worker_remove_cb" in wr_server.c for details.
615
+ worker->app->low_ratio = worker->app->q_workers->q_count * Config->Application.min_req_ratio;
616
+ ctl->wkr = worker;
617
+ LOG_DEBUG(DEBUG,"Added Worker %d",worker->id);
618
+
619
+ wr_wkr_state_machine(worker, WKR_ACTION_ADD);
620
+
621
+ ev_io_set(&worker->watcher,worker->fd,EV_READ);
622
+ return TRUE;
529
623
  }
530
624
 
531
- /** Create the Worker */
532
- int wr_wkr_create(wr_svr_t *server, wr_app_conf_t *app_conf) {
625
+ /** Handle connect request from Worker */
626
+ int wr_wkr_connect(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
533
627
  LOG_FUNCTION
534
- pid_t pid;
535
- char cuid_s[WR_SHORT_STR_LEN],
536
- cgid_s[WR_SHORT_STR_LEN],
537
- controller_path[WR_LONG_STR_LEN],
538
- log_level[WR_SHORT_STR_LEN];
539
-
540
- wr_str_t baseuri;
541
- wr_string_null(baseuri);
542
-
543
- if(app_conf->baseuri.str) {
544
- wr_string_dump(baseuri, app_conf->baseuri);
628
+ wr_svr_t* server = ctl->svr;
629
+ wr_wkr_t* worker = NULL;
630
+ wr_u_short retval = TRUE;
631
+
632
+ if(wr_wkr_check_uds(ctl, ctl_msg) == FALSE) return -1;
633
+
634
+ LOG_DEBUG(4,"Sock_path = %s, port=%s, app_name=%s, pid=%s", ctl_msg->msg.wkr.sock_path.str,
635
+ ctl_msg->msg.wkr.port.str,
636
+ ctl_msg->msg.wkr.app_name.str,
637
+ ctl_msg->msg.wkr.pid.str);
638
+
639
+ worker = wr_wkr_new(ctl);
640
+ if(worker == NULL) {
641
+ LOG_ERROR(WARN,"worker object alloaction failde. Returning ...");
642
+ return -1;
643
+ }
644
+
645
+ worker->pid = atoi(ctl_msg->msg.wkr.pid.str);
646
+
647
+ // Insert newly added Worker to application list*/
648
+ if(wr_app_wkr_insert(server, worker, ctl_msg)!=0) {
649
+ LOG_INFO("No more workers required.");
650
+ free(worker);
651
+ return -1;
652
+ }
653
+
654
+ LOG_INFO("Worker %d with PID %d for Application %s inserted successfully. control fd = %d",
655
+ worker->id, worker->pid, worker->app->conf->name.str,worker->ctl->fd);
656
+ if(Config->Server.flag & SERVER_UDS_SUPPORT) {
657
+ retval = wr_wkr_connect_uds(worker, ctl_msg);
545
658
  } else {
546
- wr_string_new(baseuri, "/", 1);
659
+ retval = wr_wkr_connect_inet(worker, ctl_msg);
547
660
  }
661
+
662
+ if(retval == TRUE) retval = wr_wkr_set_ratio(ctl, worker);
663
+
664
+ if(retval == FALSE){
665
+ worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * Config->Application.max_req_ratio;
666
+ free(worker);
667
+ return -1;
668
+ }
669
+
670
+ LOG_DEBUG(DEBUG,"Allocating task to newly added worker %d",worker->id);
671
+ //Check for pending requests
672
+ wr_wrk_allocate(worker);
673
+ LOG_DEBUG(5,"Successfully connected to worker");
674
+ LOG_DEBUG(DEBUG,"Allocated task to newly added worker %d",worker->id);
675
+ wr_app_wkr_balance(worker->app);
676
+
677
+ return 0;
678
+ }
548
679
 
549
- sprintf(cuid_s, "%d", app_conf->cuid);
550
- sprintf(cgid_s, "%d", app_conf->cgid);
551
- sprintf(log_level, "%d", app_conf->log_level);
552
680
 
553
- if(server->conf->uds) {
554
- strcpy(controller_path, server->ctl->sock_path.str);
555
- } else {
556
- sprintf(controller_path, "%d", server->ctl->port);
557
- }
681
+ /*******************************************
682
+ * Worker Function Definition *
683
+ *******************************************/
684
+
685
+ /** Create the Worker */
686
+ /* Fork a new process and start worker in it. */
687
+ int wr_wkr_create(wr_svr_t *server, config_application_list_t *app_conf) {
688
+ LOG_FUNCTION
689
+ pid_t pid;
690
+ wr_wkr_create_t *worker = wr_wkr_create_init(server, app_conf);
691
+
558
692
  pid = fork();
559
- LOG_DEBUG(DEBUG,"Forked PID is %i, uid = %s, gid =%s, app = %s",pid, cuid_s, cgid_s, app_conf->name.str) ;
693
+ LOG_DEBUG(DEBUG,"Forked PID is %i, app = %s",pid, app_conf->name.str) ;
560
694
  if (pid == 0) {
561
695
  LOG_DEBUG(3,"Child is continuing %i",pid);
562
696
  setsid();
563
697
  int i = 0;
564
- for (i=getdtablesize();i>=0;--i) {
698
+ for (i = getdtablesize();i>=0;--i) {
565
699
  //LOG_DEBUG(DEBUG,"closing fd=%d",i);
566
700
  close(i); //why??
567
701
  }
@@ -575,43 +709,100 @@ int wr_wkr_create(wr_svr_t *server, wr_app_conf_t *app_conf) {
575
709
  int j = dup(i); // stdout
576
710
  j = dup(i); // stderr
577
711
 
578
- LOG_DEBUG(DEBUG,"Before execl():Rails application=%s, uid=%s, gid = %s",app_conf->path.str, cuid_s, cgid_s);
579
- LOG_DEBUG(DEBUG,"exe file = %s",server->conf->wkr_exe_path.str);
712
+ LOG_DEBUG(DEBUG,"Before execl():Rails application=%s", app_conf->path.str);
713
+ LOG_DEBUG(DEBUG,"exe file = %s",Config->Server.File.worker_bin.str);
580
714
  int rv;
581
- rv=execl(server->conf->wkr_exe_path.str, server->conf->wkr_exe_path.str,
582
- "-a", app_conf->path.str,
583
- "-e", app_conf->env.str,
584
- "-u", cuid_s,
585
- "-g", cgid_s,
586
- "-c", controller_path,
587
- "-i", (server->conf->uds? "y" : "n"),
588
- "-t", app_conf->type.str,
715
+ rv=execl(Config->Server.File.worker_bin.str, Config->Server.File.worker_bin.str,
716
+ "-c", worker->controller_path,
717
+ "-i", (Config->Server.flag & SERVER_UDS_SUPPORT ? "y" : "n"),
589
718
  "-n", app_conf->name.str,
590
- "-p", (app_conf->analytics? "y" : "n"),
591
- "-r", baseuri.str,
592
- "-b", server->conf->ruby_lib_path.str,
593
- "-o", server->conf->wr_root_path.str,
594
- "-k", (WR_SVR_KEEP_ALIVE? "y" : "n"),
595
- "-l", log_level,
719
+ "-o", Config->Server.Dir.root.str,
720
+ "-k", (Config->Server.flag & SERVER_KEEP_ALIVE ? "y" : "n"),
721
+ "-l", worker->log_level,
596
722
  NULL);
597
- wr_string_free(baseuri);
723
+ wr_string_free(worker->baseuri);
724
+ free(worker);
598
725
  if(rv<0) {
599
- LOG_ERROR(5,"Unable to run %s: %s\n", server->conf->wkr_exe_path.str, strerror(errno));
600
- fprintf(stderr, "Unable to run %s: %s\n", server->conf->wkr_exe_path.str, strerror(errno));
726
+ LOG_ERROR(5,"Unable to run %s: %s\n", Config->Server.File.worker_bin.str, strerror(errno));
727
+ fprintf(stderr, "Unable to run %s: %s\n", Config->Server.File.worker_bin.str, strerror(errno));
601
728
  fflush(stderr);
602
729
  _exit(1);
603
730
  }
604
731
  } else if (pid == -1) {
605
- wr_string_free(baseuri);
732
+ wr_string_free(worker->baseuri);
733
+ free(worker);
606
734
  LOG_ERROR(5,"Cannot fork a new process %i", errno);
607
735
  } else {
608
- wr_string_free(baseuri);
736
+ wr_string_free(worker->baseuri);
737
+ free(worker);
609
738
  //Temporary Hack
610
739
  return pid;
611
740
  }
612
741
  return -1;
613
742
  }
614
743
 
744
+ /** Destroy worker */
745
+ void wr_wkr_free(wr_wkr_t *worker) {
746
+ LOG_FUNCTION
747
+
748
+ if(Config->Server.Worker.idle_time > 0 && ev_is_active(&worker->t_wait))
749
+ ev_timer_stop(worker->loop,&worker->t_wait);
750
+
751
+ if(ev_is_active(&worker->watcher))
752
+ ev_io_stop(worker->loop,&worker->watcher);
753
+
754
+ if(worker->req) {
755
+ LOG_DEBUG(DEBUG,"Worker %d with pid %d. Worker cannot served the request.",worker->id, worker->pid);
756
+ LOG_INFO("Worker %d with pid %d. Worker cannot served the request.",worker->id, worker->pid);
757
+ worker->req->using_wkr = FALSE;
758
+ wr_conn_err_resp(worker->req->conn, WR_HTTP_STATUS_500);
759
+ }
760
+
761
+ if(worker->app){
762
+ LOG_INFO("Removing worker %d with pid %d...app->q_workers->q_count=%d, q_front=%d, q_rear=%d app=%s",
763
+ worker->id, worker->pid,worker->app->q_workers->q_count,
764
+ worker->app->q_workers->q_front,worker->app->q_workers->q_rear,
765
+ worker->app->conf->name.str);
766
+ if(wr_queue_remove(worker->app->q_workers, worker) == 0) {
767
+ worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * Config->Application.max_req_ratio;
768
+ worker->app->low_ratio = WR_QUEUE_SIZE(worker->app->q_workers) * Config->Application.min_req_ratio;
769
+ }
770
+ wr_queue_remove(worker->app->q_free_workers, worker);
771
+ }else{
772
+ LOG_INFO("Removing worker %d with pid %d", worker->id, worker->pid);
773
+ }
774
+
775
+ if(worker->state == WKR_STATE_DISCONNECTING){
776
+ LOG_DEBUG(DEBUG,"Stopping worker %d with pid %d...",worker->id, worker->pid);
777
+ LOG_INFO("Stopping worker %d with pid %d...",worker->id, worker->pid);
778
+ scgi_t* scgi = scgi_new();
779
+ if(scgi) {
780
+ scgi_header_add(scgi, "METHOD", strlen("METHOD"), "REMOVE", strlen("REMOVE"));
781
+ scgi_build(scgi);
782
+ //TODO: made it asynchronous
783
+ scgi_send(scgi, worker->ctl->fd);
784
+ scgi_free(scgi);
785
+ } else {
786
+ kill(worker->pid, SIGHUP);
787
+ }
788
+ worker->pid = 0;
789
+ }else if(worker->state == WKR_STATE_HANGUP){
790
+ kill(worker->pid, SIGKILL);
791
+ }else{
792
+ kill(worker->pid, SIGHUP);
793
+ }
794
+
795
+ if(worker->ctl) {
796
+ worker->ctl->wkr = NULL;
797
+ wr_ctl_free(worker->ctl);
798
+ }
799
+ //Close socket
800
+ if(worker->fd > 0)
801
+ close(worker->fd);
802
+
803
+ free(worker);
804
+ }
805
+
615
806
  /** Request callback called by ebb Request*/
616
807
  /* It will be called after request is parsed and environment hash is ready.
617
808
  * Request is inserted into application queue, and one of free worker allocated to a Request. */
@@ -628,167 +819,12 @@ void wr_wkr_dispatch_req(wr_req_t* req) {
628
819
  WR_APP_MSG_DISPATCH(req->app, new_req, worker) ;
629
820
 
630
821
  if(new_req && worker) {
631
- LOG_DEBUG(DEBUG,"Allocate worker %d to Request id %d", worker->id, new_req->id);
632
- new_req->wkr = worker;
633
- new_req->using_wkr = TRUE;
634
-
635
- worker->watcher.data = new_req;
636
- //set Request on wich worker is working
637
- worker->req = new_req;
638
- ev_io_init(&worker->watcher, wr_req_hearer_write_cb, worker->fd, EV_WRITE);
639
- ev_io_start(worker->loop, &worker->watcher);
822
+ wr_wkr_req_processing(worker, new_req);
640
823
  }else{
641
824
  LOG_DEBUG(DEBUG, "Could not dispatch the request");
642
825
  }
643
826
  }
644
827
 
645
- /** Handle connect request from Worker */
646
- int wr_wkr_connect(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
647
- LOG_FUNCTION
648
- wr_svr_t* server = ctl->svr;
649
- wr_wkr_t* worker = NULL;
650
-
651
- if(server->conf->uds) {
652
- if(strcmp(ctl_msg->msg.wkr.uds.str,"YES")!=0 ||
653
- ctl_msg->msg.wkr.sock_path.str == NULL) {
654
- scgi_body_add(ctl->scgi, "Invalid UDS, sock path and configuration.", strlen("Invalid UDS, sock path and configuration."));
655
- LOG_ERROR(SEVERE,"connect_with_worker()Invalid UDS, sock path and configuration.");
656
- return -1;
657
- }
658
- } else {
659
- if(strcmp(ctl_msg->msg.wkr.uds.str,"NO")!=0 ||
660
- ctl_msg->msg.wkr.port.str == NULL) {
661
- scgi_body_add(ctl->scgi, "Invalid UDS, sock path and configuration.", strlen("Invalid UDS, sock path and configuration."));
662
- LOG_ERROR(SEVERE,"connect_with_worker()Invalid UDS, sock path and configuration.");
663
- return -1;
664
- }
665
- }
666
-
667
- LOG_DEBUG(4,"Sock_path = %s, port=%s, app_name=%s, pid=%s", ctl_msg->msg.wkr.sock_path.str,
668
- ctl_msg->msg.wkr.port.str,
669
- ctl_msg->msg.wkr.app_name.str,
670
- ctl_msg->msg.wkr.pid.str);
671
-
672
- worker = wr_wkr_new(ctl);
673
- if(worker == NULL) {
674
- LOG_ERROR(WARN,"worker object alloaction failde. Returning ...");
675
- return -1;
676
- }
677
-
678
- worker->pid = atoi(ctl_msg->msg.wkr.pid.str);
679
- worker->state += WR_WKR_CONNECTING;
680
-
681
- // Insert newly added Worker to application list*/
682
- if(wr_app_wkr_insert(server, worker, ctl_msg)!=0) {
683
- LOG_INFO("No more workers required.");
684
- free(worker);
685
- return -1;
686
- }
687
-
688
- LOG_INFO("Worker %d with PID %d for Application %s inserted successfully. control fd = %d",
689
- worker->id, worker->pid, worker->app->conf->name.str,worker->ctl->fd);
690
- if(server->conf->uds) {
691
- //Connect to Worker using UNIX domain socket
692
- struct sockaddr_un addr;
693
- int len;
694
-
695
- if ((worker->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
696
- perror("socket()");
697
- LOG_ERROR(4,"socket() failed");
698
- // Worker is not added, Reset the high load ratio
699
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
700
- free(worker);
701
- return -1;
702
- }
703
- LOG_DEBUG(3,"Socket successfully open for worker. File Descriptor is %d",worker->fd);
704
-
705
- setsocketoption(worker->fd);
706
- memset(&addr, 0, sizeof(addr));
707
-
708
- addr.sun_family = AF_UNIX;
709
- strcpy(addr.sun_path,ctl_msg->msg.wkr.sock_path.str);
710
- len = sizeof(addr.sun_family) + strlen(addr.sun_path);
711
-
712
- #ifdef __APPLE__
713
- len++;
714
- #endif
715
-
716
- if(connect(worker->fd, (struct sockaddr *)&addr,len) == -1) {
717
- perror("connect");
718
- LOG_ERROR(4,"Unable to connect with worker at socket path %s. %s Closing it.",addr.sun_path, strerror(errno));
719
- close_fd(worker->fd);
720
- worker->fd=0;
721
- // Worker is not added, Reset the high load ratio
722
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
723
- free(worker);
724
- return -1;
725
- }
726
- } else {
727
- //Connect to Worker using internet socket
728
- struct sockaddr_in addr;
729
- if ((worker->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
730
- perror("socket()");
731
- LOG_ERROR(4,"socket() failed for worker");
732
- // Worker is not added, Reset the high load ratio
733
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
734
- free(worker);
735
- // return if not able to connect to the first worker
736
- return -1;
737
- }
738
- LOG_DEBUG(3,"Socket successfully open for worker. File Descriptor is %d",worker->fd);
739
-
740
- setsocketoption(worker->fd);
741
- memset(&addr, 0, sizeof(addr));
742
-
743
- addr.sin_family = AF_INET;
744
- addr.sin_port = htons(atoi(ctl_msg->msg.wkr.port.str));
745
- addr.sin_addr.s_addr =inet_addr("127.0.0.1");
746
-
747
- if(connect(worker->fd, (struct sockaddr *)&addr,sizeof addr) == -1) {
748
- perror("connect");
749
- LOG_ERROR(4,"Unable to connect with worker at port %s. %s Closing it.",ctl_msg->msg.wkr.port.str, strerror(errno));
750
- close_fd(worker->fd);
751
- worker->fd=0;
752
- free(worker);
753
- // Worker is not added, Reset the high load ratio
754
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
755
- return -1;
756
- }
757
- }
758
-
759
- if(setnonblock(worker->fd) < 0) {
760
- LOG_ERROR(SEVERE,"Setting worker_fd non-block failed:%s",strerror(errno));
761
- close_fd(worker->fd);
762
- free(worker);
763
- // Worker is not added, Reset the high load ratio
764
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
765
- return -1;
766
- }
767
-
768
- if(wr_queue_insert(worker->app->q_workers, worker) < 0){
769
- LOG_ERROR(WARN,"Worker queue is full.");
770
- worker->app->high_ratio = TOTAL_WORKER_COUNT(worker->app) * WR_MAX_REQ_RATIO;
771
- return -1;
772
- }
773
-
774
- //Setting low load ratio for application, refer "wr_worker_remove_cb" in wr_server.c for details.
775
- worker->app->low_ratio = worker->app->q_workers->q_count * WR_MIN_REQ_RATIO;
776
- ctl->wkr = worker;
777
- LOG_DEBUG(DEBUG,"Added Worker %d",worker->id);
778
-
779
- ev_io_set(&worker->watcher,worker->fd,EV_READ);
780
-
781
- LOG_DEBUG(DEBUG,"Allocating task to newly added worker %d",worker->id);
782
- //Check for pending requests
783
- wr_wrk_allocate(worker);
784
- LOG_DEBUG(5,"Successfully connected to worker");
785
- LOG_DEBUG(DEBUG,"Allocated task to newly added worker %d",worker->id);
786
- wr_app_wkr_balance(worker->app);
787
- //wr_app_wkr_added_cb(worker->app);
788
-
789
- return 0;
790
- }
791
-
792
828
  ///** This would get called when worker reply to PING */
793
829
  //void wr_wkr_ping_reply(wr_wkr_t *worker)
794
830
  //{
@@ -798,13 +834,15 @@ int wr_wkr_connect(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
798
834
  // if(worker->state & WR_WKR_PING_SENT)
799
835
  // {
800
836
  // ev_timer_stop(worker->ctl->svr->ebb_svr.loop, &worker->t_wait);
801
- // worker->t_wait.repeat = WR_WKR_IDLE_TIME;
837
+ // worker->t_wait.repeat = Config->Server.Worker.idle_time;
802
838
  // worker->state &= (~224);
803
839
  // ev_timer_again(worker->ctl->svr->ebb_svr.loop, &worker->t_wait);
804
840
  // }
805
841
  //}
806
842
 
807
843
  /** Worker add callback */
844
+ /* This callback function called from controller on receiving WORKER ADD control
845
+ * signal */
808
846
  void wr_wkr_add_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
809
847
  LOG_FUNCTION
810
848
  int retval;
@@ -819,22 +857,28 @@ void wr_wkr_add_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
819
857
  wr_ctl_resp_write(ctl);
820
858
  }
821
859
 
860
+ /** Worker Add error callback */
861
+ void wr_wkr_add_error_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg){
862
+ LOG_FUNCTION
863
+ wr_app_wkr_error(ctl->svr, ctl_msg);
864
+ scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "OK", strlen("OK"));
865
+ wr_ctl_resp_write(ctl);
866
+ }
867
+
822
868
  /** Worker remove callback */
823
869
  void wr_wkr_remove_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
824
870
  LOG_FUNCTION
825
871
  wr_app_t *app = NULL;
872
+
826
873
  if(ctl->wkr ) {
827
874
  app = ctl->wkr->app;
828
- ctl->wkr->state += WR_WKR_DISCONNECT;
829
- if(ctl->wkr->state & WR_WKR_ACTIVE)
830
- wr_wkr_remove(ctl->wkr,1);
831
- else
832
- wr_wkr_free(ctl->wkr);
875
+ wr_wkr_state_machine(ctl->wkr, WKR_ACTION_REMOVE);
876
+ scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "OK", strlen("OK"));
877
+ }else{
878
+ LOG_ERROR(SEVERE,"failed to connect with worker");
879
+ scgi_header_add(ctl->scgi, "STATUS", strlen("STATUS"), "ERROR", strlen("ERROR"));
833
880
  }
834
- scgi_build(ctl->scgi);
835
- scgi_free(ctl->scgi);
836
- ctl->scgi = NULL;
837
- //TODO :Send acknowledgement signal.
881
+
838
882
  wr_ctl_resp_write(ctl);
839
883
 
840
884
  // Create new worker if required
@@ -842,17 +886,12 @@ void wr_wkr_remove_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msg) {
842
886
  }
843
887
 
844
888
  /** Worker ping callback */
889
+ /* Get reply for the ping control request */
845
890
  void wr_wkr_ping_cb(wr_ctl_t *ctl, const wr_ctl_msg_t *ctl_msgs) {
846
891
  LOG_FUNCTION
847
892
  wr_wkr_t *worker = ctl->wkr;
848
893
  LOG_INFO("Worker %d with pid %d replied for trial no %d", worker->id, worker->pid, worker->trials_done);
849
- //worker has replied so setting WR_WORKER_REPLIED flag, and clearing WR_WORKER_PING_SENT
850
- if(worker->state & WR_WKR_PING_SENT) {
851
- ev_timer_stop(ctl->svr->ebb_svr.loop, &worker->t_wait);
852
- worker->t_wait.repeat = WR_WKR_IDLE_TIME;
853
- worker->state &= (~224);
854
- ev_timer_again(ctl->svr->ebb_svr.loop, &worker->t_wait);
855
- }
894
+ wr_wkr_state_machine(worker, WKR_ACTION_PING_REPLAY);
856
895
  scgi_build(ctl->scgi);
857
896
  scgi_free(ctl->scgi);
858
897
  ctl->scgi = NULL;