webroar 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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;