~josejuan-sanchez/esajpip/continue

« back to all changes in this revision

Viewing changes to src/esa_jpip_server.cc

  • Committer: José Juan Sánchez Hernández
  • Date: 2013-10-01 10:01:21 UTC
  • Revision ID: josejuan.sanchez@gmail.com-20131001100121-xfobvkenqie7y0te
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#define SHOW_TRACES
 
2
 
 
3
#include <wait.h>
 
4
#include <signal.h>
 
5
#include "trace.h"
 
6
#include "version.h"
 
7
#include "app_info.h"
 
8
#include "app_config.h"
 
9
#include "args_parser.h"
 
10
#include "client_info.h"
 
11
#include "client_manager.h"
 
12
#include "net/poll_table.h"
 
13
#include "net/socket_stream.h"
 
14
#include "jpeg2000/file_manager.h"
 
15
#include "jpeg2000/index_manager.h"
 
16
 
 
17
 
 
18
using namespace std;
 
19
using namespace net;
 
20
using namespace jpeg2000;
 
21
 
 
22
 
 
23
#define SERVER_NAME       "ESA JPIP Server"
 
24
#define SERVER_APP_NAME   "esa_jpip_server"
 
25
#define CONFIG_FILE       "server.cfg"
 
26
 
 
27
 
 
28
AppConfig cfg;
 
29
int base_id = 0;
 
30
AppInfo app_info;
 
31
Socket child_socket;
 
32
PollTable poll_table;
 
33
bool child_lost = false;
 
34
IndexManager index_manager;
 
35
UnixAddress child_address("/tmp/child_unix_address");
 
36
UnixAddress father_address("/tmp/father_unix_address");
 
37
 
 
38
 
 
39
int ChildProcess();
 
40
void *ClientThread(void *arg);
 
41
bool ParseArguments(int argc, char **argv);
 
42
 
 
43
 
 
44
void SIGCHLD_handler(int signal)
 
45
{
 
46
  wait(NULL);
 
47
  child_lost = true;
 
48
}
 
49
 
 
50
 
 
51
int main(int argc, char **argv)
 
52
{
 
53
  int res, fd;
 
54
  Socket father_socket;
 
55
  InetAddress from_addr;
 
56
  InetAddress listen_addr;
 
57
  Socket listen_socket, new_conn;
 
58
 
 
59
  if(!app_info.Init())
 
60
    return CERR("The shared information can not be set");
 
61
 
 
62
  if (!cfg.Load(CONFIG_FILE))
 
63
    return CERR("The configuration file can not be read");
 
64
 
 
65
  if(!ArgsParser(cfg, app_info).Parse(argc, argv))
 
66
    return -1;
 
67
 
 
68
  if(app_info.is_running())
 
69
    return CERR("The server is already running");
 
70
 
 
71
  if(!index_manager.Init(cfg.images_folder(), cfg.caching_folder()))
 
72
    return CERR("The index manager can not be initialized");
 
73
 
 
74
  app_info->father_pid = getpid();
 
75
 
 
76
  cout << endl << SERVER_NAME << " " << VERSION << endl;
 
77
  cout << endl << cfg << endl;
 
78
 
 
79
  if (cfg.logging()) TraceSystem::AppendToFile(cfg.logging_folder() + SERVER_APP_NAME);
 
80
 
 
81
  if (!File::Exists(cfg.caching_folder().c_str()))
 
82
    ERROR("The cache folder does not exist");
 
83
 
 
84
  if(cfg.address().size() <= 0) listen_addr = InetAddress(cfg.port());
 
85
  else listen_addr = InetAddress(cfg.address().c_str(), cfg.port());
 
86
 
 
87
  if (!listen_socket.OpenInet())
 
88
    ERROR("The server listen socket can not be created");
 
89
  else if (!listen_socket.ListenAt(listen_addr))
 
90
    ERROR("The server listen socket can not be initialized");
 
91
  else
 
92
  {
 
93
    LOG(SERVER_NAME << " started");
 
94
 
 
95
    signal(SIGCHLD, SIG_IGN);
 
96
 
 
97
    poll_table.Add(listen_socket, POLLIN);
 
98
 
 
99
    if(!father_socket.OpenUnix(SOCK_DGRAM)) {
 
100
      ERROR("The father unix socket can not be created");
 
101
      return -1;
 
102
    }
 
103
 
 
104
    if(!father_socket.BindTo(father_address.Reset())) {
 
105
      ERROR("The father unix socket can not be bound");
 
106
      return -1;
 
107
    }
 
108
 
 
109
    poll_table.Add(father_socket, POLLIN);
 
110
 
 
111
    father_begin:
 
112
 
 
113
    if (!fork()) return ChildProcess();
 
114
    else
 
115
    {
 
116
      signal(SIGCHLD, SIGCHLD_handler);
 
117
 
 
118
      for (;;)
 
119
      {
 
120
        res = poll_table.Poll();
 
121
 
 
122
        if (child_lost)
 
123
        {
 
124
          child_lost = false;
 
125
          goto father_begin;
 
126
        }
 
127
 
 
128
        if(res > 0)
 
129
        {
 
130
          if (poll_table[0].revents & POLLIN)
 
131
          {
 
132
            new_conn = listen_socket.Accept(&from_addr);
 
133
 
 
134
            if (!new_conn.IsValid()) ERROR("Problems accepting a new connection");
 
135
            else
 
136
            {
 
137
              if(app_info->num_connections >= cfg.max_connections()) {
 
138
                LOG("Refusing a connection because the limit has been reached");
 
139
                new_conn.Close();
 
140
 
 
141
              } else {
 
142
                LOG("New connection from " << from_addr.GetPath() << ":" << from_addr.GetPort() << " [" << (int)new_conn << "]");
 
143
 
 
144
                if(!father_socket.SendDescriptor(child_address, new_conn, new_conn)) {
 
145
                  ERROR("The new socket can not be sent to the child process");
 
146
                  new_conn.Close();
 
147
 
 
148
                } else {
 
149
                  poll_table.Add(new_conn, POLLRDHUP | POLLERR | POLLHUP | POLLNVAL);
 
150
                  app_info->num_connections++;
 
151
                }
 
152
              }
 
153
            }
 
154
          }
 
155
 
 
156
          if(poll_table[1].revents & POLLIN)
 
157
          {
 
158
            father_socket.Receive(&fd, sizeof(int));
 
159
            LOG("Closing the connection [" << fd << "] from child");
 
160
            app_info->num_connections--;
 
161
            poll_table.Remove(fd);
 
162
            close(fd);
 
163
          }
 
164
 
 
165
          for(int i = 2; i < poll_table.GetSize(); i++)
 
166
          {
 
167
            if (poll_table[i].revents)
 
168
            {
 
169
              LOG("Closing the connection [" << poll_table[i].fd << "]");
 
170
              app_info->num_connections--;
 
171
              close(poll_table[i].fd);
 
172
              poll_table.RemoveAt(i);
 
173
            }
 
174
          }
 
175
 
 
176
          if(app_info->num_connections < 0)
 
177
            app_info->num_connections = 0;
 
178
        }
 
179
      }
 
180
    }
 
181
  }
 
182
 
 
183
  listen_socket.Close();
 
184
 
 
185
  return 0;
 
186
}
 
187
 
 
188
 
 
189
int ChildProcess()
 
190
{
 
191
  int sock, father_sock;
 
192
  pthread_t service_tid;
 
193
  ClientInfo *client_info;
 
194
 
 
195
  app_info->child_iterations++;
 
196
  app_info->child_pid = getpid();
 
197
 
 
198
  signal(SIGPIPE, SIG_IGN);
 
199
 
 
200
  LOG("Child process created (PID = " << getpid() << ")");
 
201
 
 
202
  if(!child_socket.OpenUnix(SOCK_DGRAM)) {
 
203
    ERROR("The child unix socket can not be created");
 
204
    return -1;
 
205
  }
 
206
 
 
207
  if(!child_socket.BindTo(child_address.Reset())) {
 
208
    ERROR("The child unix socket can not be bound");
 
209
    return -1;
 
210
  }
 
211
 
 
212
  for (int i = 2; i < poll_table.GetSize(); i++)
 
213
  {
 
214
    sock = poll_table[i].fd;
 
215
    client_info = new ClientInfo(0, sock, sock);
 
216
 
 
217
    LOG("Creating a client thread for the old connection [" << sock << "]");
 
218
 
 
219
    if (pthread_create(&service_tid, NULL, ClientThread, client_info) == -1)
 
220
    {
 
221
      ERROR("A new client thread for the old connection [" << sock << "] can not be created");
 
222
      delete client_info;
 
223
      return -1;
 
224
    }
 
225
 
 
226
    pthread_detach(service_tid);
 
227
  }
 
228
 
 
229
  for (;;)
 
230
  {
 
231
    child_socket.ReceiveDescriptor(&sock, &father_sock);
 
232
    client_info = new ClientInfo(base_id++, sock, father_sock);
 
233
 
 
234
    LOG("Creating a client thread for the new connection [" << sock << "|" << father_sock << "]");
 
235
 
 
236
    if (pthread_create(&service_tid, NULL, ClientThread, client_info) == -1)
 
237
    {
 
238
      LOG("A new client thread for the new connection [" << sock << "|" << father_sock << "] can not be created");
 
239
      delete client_info;
 
240
      return -1;
 
241
    }
 
242
 
 
243
    pthread_detach(service_tid);
 
244
  }
 
245
 
 
246
  return 0;
 
247
}
 
248
 
 
249
 
 
250
void *ClientThread(void *arg)
 
251
{
 
252
  int sock, res;
 
253
  ClientInfo *client_info = (ClientInfo *)arg;
 
254
 
 
255
#ifndef BASIC_SERVER
 
256
  ClientManager(cfg, app_info, index_manager).Run(client_info);
 
257
#else
 
258
  ClientManager(cfg, app_info, index_manager).RunBasic(client_info);
 
259
#endif
 
260
 
 
261
  sock = client_info->father_sock();
 
262
  res = child_socket.SendTo(father_address, &sock, sizeof(int));
 
263
 
 
264
  if(res < (int)sizeof(int))
 
265
    ERROR("The connection [" << sock << "] could not be closed");
 
266
 
 
267
  delete client_info;
 
268
  pthread_exit(0);
 
269
}