source: subversion/applications/utils/tirex/backend-mapnik/networklistener.cc @ 29342

Last change on this file since 29342 was 28533, checked in by Dirk Stoecker, 7 years ago

add missing include

File size: 5.9 KB
Line 
1/*
2 * Tirex Tile Rendering System
3 *
4 * Mapnik rendering backend
5 *
6 * Originally written by Jochen Topf & Frederik Ramm.
7 *
8 */
9
10#include <sys/types.h>
11#include <sys/socket.h>
12#include <netinet/in.h>
13#include <arpa/inet.h>
14#include <netdb.h>
15#include <stdio.h>
16#include <errno.h>
17#include <iostream>
18#include <signal.h>
19#include <strings.h>
20#include <unistd.h>
21
22#include "networklistener.h"
23#include "networkrequest.h"
24#include "networkresponse.h"
25
26// stuff for handling the hangup signal properly
27extern "C" 
28{
29    static volatile sig_atomic_t gHangupOccurred;
30    static void hangup_signal_handler(int param) { param = param; gHangupOccurred = 1; }
31    static void install_sighup_handler(bool with_restart) 
32    {
33        struct sigaction action;
34        sigemptyset(&action.sa_mask);
35        action.sa_handler = hangup_signal_handler;
36        action.sa_flags = with_restart ? SA_RESTART : 0;
37        sigaction(SIGHUP, &action, NULL);
38    }
39    static void ignore_sigpipe()
40    {
41        struct sigaction action;
42        sigemptyset(&action.sa_mask);
43        action.sa_handler = SIG_IGN;
44        action.sa_flags = 0;
45        sigaction(SIGPIPE, &action, NULL);
46    }
47}
48
49NetworkListener::NetworkListener(int port, int sockfd, int parentfd, std::map<std::string, RequestHandler *> *handlers)
50{
51    mpRequestHandlers = handlers;
52
53    socklen_t length;
54    struct sockaddr_in server;
55
56    if (sockfd >= 0)
57    {
58        mSocket = sockfd;
59        debug("using existing socket %d", sockfd);
60    }
61    else
62    {
63        mSocket = socket(AF_INET, SOCK_DGRAM, 0);
64        if (mSocket < 0) die ("cannot open socket: %s", strerror(errno));
65        int one = 1;
66        setsockopt(mSocket, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
67        length = sizeof(server);
68        bzero(&server, length);
69        server.sin_family = AF_INET;
70        server.sin_addr.s_addr = inet_addr("127.0.0.1");
71        server.sin_port = htons(port);
72        if (bind(mSocket,(struct sockaddr *) &server, length) < 0) die("cannot bind to port %d: %s", port, strerror(errno));
73        debug("bound to port %d", port);
74    }
75    mParent = parentfd;
76}
77
78NetworkListener::~NetworkListener()
79{
80}
81
82void NetworkListener::run()
83{
84    struct sockaddr_in client;
85    socklen_t fromlen = sizeof(struct sockaddr_in);
86    char buf[MAX_DGRAM];
87
88    // install SIGHUP signal handler. use sigaction to avoid restarting after signal.
89    gHangupOccurred = 0;
90    int errcnt = 0;
91    fd_set rfds;
92    FD_ZERO(&rfds);
93    time_t last_alive_sent = 0;
94    install_sighup_handler(false);
95    ignore_sigpipe();
96    while (!gHangupOccurred) 
97    {
98        struct timeval to = { 5, 0 };
99        FD_SET(mSocket, &rfds);
100        // do not select for writability of mParent, since it is
101        // always writable.
102        int n = select(mSocket + 1, &rfds, NULL, NULL, &to);
103
104        // send alive message to parent.
105        if (mParent > -1) 
106        {
107            time_t now = time(NULL);
108            if (now >= last_alive_sent + 5)
109            {
110                // we really are not interested in the write() result since
111                // the parent is going to kill us anyway if it does not recieve
112                // an alive message. The following construction gets rid of
113                // the compiler warning about not using the return value.
114                if (write(mParent, (const void *) "alive", 5)) {};
115                last_alive_sent = now;
116            }
117        }
118
119        if (n <= 0) 
120        {
121            if (n < 0 && errno != EINTR)
122            {
123                error("error while reading data: %s", strerror(errno));
124                if (errcnt++ > 10)
125                {
126                    error("too many errors - exiting");
127                    break;
128                }
129            }
130            continue;
131        }
132
133        n = recvfrom(mSocket, buf, MAX_DGRAM, 0, (struct sockaddr *) &client, &fromlen);
134        if (n < 0) 
135        {
136            if (errno != EINTR)
137            {
138                error("error while reading data: %s", strerror(errno));
139                if (errcnt++ > 10)
140                {
141                    error("too many errors - exiting");
142                    break;
143                }
144            }
145        }
146        else
147        {
148            errcnt = 0;
149            NetworkRequest *req = new NetworkRequest();
150            std::string strbuf(buf, n);
151            debug("read: %s", strbuf.c_str());
152            const NetworkResponse *resp;
153            if (!req->parse(strbuf))
154            {
155                error("error parsing request");
156                resp = NetworkResponse::makeErrorResponse(NULL, "cannot parse request");
157            }
158            else
159            {
160                std::map<std::string, RequestHandler *>::const_iterator h = mpRequestHandlers->find(req->getParam("map", ""));
161                install_sighup_handler(true);
162
163                if (h != mpRequestHandlers->end())
164                {
165                    if (!(resp = h->second->handleRequest(req)))
166                    {
167                        error("handler returned null");
168                        resp = NetworkResponse::makeErrorResponse(req, 
169                            "Handler for map '%s' encountered an error", req->getParam("map", "").c_str());
170                    }
171                }
172                else
173                {
174                    error("no handler found for map style '%s'", req->getParam("map", "").c_str());
175                    resp = NetworkResponse::makeErrorResponse(req,
176                        "map style '%s' is not known", req->getParam("map", "").c_str());
177                }
178                install_sighup_handler(false);
179            }
180
181            std::string responseString;
182            resp->build(responseString);
183            debug("sending: %s", responseString.c_str());
184            n = sendto(mSocket, responseString.data(), responseString.length(), 0, (struct sockaddr *)&client, fromlen);
185            if (n < 0)
186            {
187                error("error in sendto");
188            }
189            delete resp;
190            delete req;
191        }
192    }
193}
194
195
Note: See TracBrowser for help on using the repository browser.