]> err.no Git - sope/blob - sope-appserver/mod_ngobjweb/sns.c
added strict OSX bundle dependencies
[sope] / sope-appserver / mod_ngobjweb / sns.c
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "common.h"
23 #include "NGBufferedDescriptor.h"
24
25 extern int HEAVY_LOG;
26
27 //#define HTTP_DETAIL_LOG 1
28
29 #define SNS_HTTP_METHOD "POST"
30 #define SNS_LOOKUP_URL  "/snsd2/wa/lookupSession"
31 #define SNS_REQLINE     "reqline"
32 #define SNS_APPNAME     "appname"
33 #define SNS_COOKIES     "cookies"
34
35 static inline int _isPlistBreakChar(unsigned char c)
36 {
37     if (!apr_isalnum(c)) return 1;
38     
39     switch (c) {
40         case '_': case '@': case '#': case '$':
41         case '.': case '=': case ';': case ',':
42         case '{': case '}': case '(': case ')':
43         case '<': case '>': case '/': case '\\':
44         case '"':
45             return 1;
46             
47         default:
48             return 0;
49     }
50 }
51
52 static void _getSNSAddressForRequest(request_rec *_rq, struct sockaddr **_sns,
53                                      ngobjweb_dir_config *_cfg)
54 {
55   //extern struct sockaddr *sns;
56   struct sockaddr *result = NULL; //sns;
57   const char *socket;
58   
59   *_sns = NULL;
60   if (_rq == NULL) {
61     fprintf(stderr, "%s: missing request ...\n", __PRETTY_FUNCTION__);
62     return;
63   }
64   if (_cfg == NULL) {
65     ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
66                  "SNS: missing directory config for request ..");
67     return;
68   }
69   
70     if ((socket = _cfg->snsPort)) {
71       long int port;
72       char     *end, *pos;
73       
74       if (_cfg->snsPortDomain == AF_UNIX) {
75         result = apr_palloc(_rq->pool, sizeof(struct sockaddr_un));
76         memset(result, 0, sizeof(struct sockaddr_un));
77         
78         ((struct sockaddr_un *)result)->sun_family = AF_UNIX;
79         strncpy(((struct sockaddr_un *)result)->sun_path,
80                 socket,
81                 sizeof(((struct sockaddr_un *)result)->sun_path) - 1);
82       }
83       else if (_cfg->snsPortDomain == AF_INET) {
84         /* the string contained a number - the port of an IP address */
85         struct sockaddr_in *snsi;
86         unsigned char *host;
87
88         /* try to convert port to number */
89         if ((pos = index(socket, ':'))) {
90           /* contains a ':' */
91           port = strtol((pos + 1), &end, 10);
92           
93           host = apr_palloc(_rq->pool, (pos - socket) + 3);
94           strncpy(host, socket, (pos - socket));
95           host[pos - socket] = '\0';
96         }
97         else {
98           host = "127.0.0.1";
99           port = strtol(socket, &end, 10);
100         }
101         
102         result = apr_palloc(_rq->pool, sizeof(struct sockaddr_in));
103         memset(result, 0, sizeof(struct sockaddr_in));
104         snsi = (struct sockaddr_in *)result;
105         
106         snsi->sin_addr.s_addr = apr_inet_addr(host);
107         
108         snsi->sin_family = AF_INET;
109         snsi->sin_port   = htons((short)(port & 0xFFFF));
110         
111         if (snsi->sin_addr.s_addr == -1) {
112           ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
113                        "SNS: couldn't convert snsd IP address: %s", host);
114         }
115         if (HEAVY_LOG && 0) {
116           ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
117                        "SNS: connect IP address: %s", host);
118         }
119       }
120       else {
121         ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
122                      "SNS: unknown socket domain %i for SNS server "
123                      "(address=%s) !!!",
124                      _cfg->snsPortDomain, _cfg->snsPort);
125       }
126     }
127   
128   *_sns = result;
129 }
130
131 static void _logSNSConnect(request_rec *_rq, struct sockaddr *sns) {
132   if (sns == NULL) {
133     ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
134                  "found no SNS socket address ...");
135     return;
136   }
137   if (sns->sa_family == AF_INET) {
138     struct sockaddr_in *snsi = (struct sockaddr_in *)sns;
139       
140     if (HEAVY_LOG) {
141       ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
142                    "SNS: connecting INET socket (family=%d, ip=%s:%i) ...",
143                    sns->sa_family,
144                    inet_ntoa(snsi->sin_addr),
145                    ntohs(snsi->sin_port));
146     }
147   }
148   else if (sns->sa_family == AF_UNIX) {
149     if (HEAVY_LOG) {
150       ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
151                    "SNS: connect UNIX socket (family=%d) ...",
152                    sns->sa_family);
153     }
154   }
155   else {
156     ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
157                  "SNS: unknown socket address family: %d.",
158                  sns->sa_family);
159   }
160 }
161
162 void *_sendSNSQuery(request_rec *_rq, const char *_line,
163                     const char *_cookie,
164                     int *_domain, size_t *_len,
165                     const char *_appName,
166                     ngobjweb_dir_config *_cfg)
167 {
168   /*
169     Sends a query for the instance socket address to the session
170     name server.
171   */
172   NGBufferedDescriptor *toSNS = NULL;
173   int    fd;
174   struct sockaddr *sns;
175   int    failed = 0;
176   
177   _getSNSAddressForRequest(_rq, &sns, _cfg);
178   if (sns == NULL) {
179     return NULL;
180   }
181   
182   *_domain = 0;
183   *_len    = 0;
184   
185   if (_line   == NULL) _line   = "";
186   if (_cookie == NULL) _cookie = "";
187   
188   /* setup connection */
189   {
190     _logSNSConnect(_rq, sns);
191     
192     fd = socket(sns->sa_family, SOCK_STREAM, 0);
193     if (fd < 0) {
194       ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
195                    "SNS: could not setup socket to SNS: %s.",
196                    strerror(errno));
197       return NULL;
198     }
199     
200     if (connect(fd, sns,
201                 (sns->sa_family == AF_INET)
202                 ? sizeof(struct sockaddr_in)
203                 : sizeof(struct sockaddr_un)) != 0) {
204       if (HEAVY_LOG) {
205         ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
206                      "could not connect sns daemon %s: %s.",
207                      sns->sa_family == AF_UNIX
208                      ? ((struct sockaddr_un *)sns)->sun_path
209                      : "via ip",
210                      strerror(errno));
211       }
212       close(fd);
213       return NULL;
214     }
215     
216     toSNS = NGBufferedDescriptor_newWithOwnedDescriptorAndSize(fd, 1024);
217     if (toSNS == NULL) {
218       ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
219                 "could not allocate buffered descriptor.");
220       close(fd);
221       return NULL;
222     }
223   }
224   
225   /* send request */
226   {
227     char c   = 50; // SNSLookupSession
228     int  len = strlen(_line);
229     
230     if (HEAVY_LOG) {
231       ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
232                    "SNS: line %s cookie '%s'", _line, _cookie);
233     }
234     
235     /* send message code */
236     if (!NGBufferedDescriptor_safeWrite(toSNS, &c, 1)) {
237       failed = 1;
238       goto finish;
239     }
240     
241     /* send request line + space + appname */
242     len = strlen(_line) + 1 + strlen(_appName);
243     if (!NGBufferedDescriptor_safeWrite(toSNS, &len, sizeof(len))) {
244       failed = 2;
245       goto finish;
246     }
247     
248     if ((len = strlen(_line)) > 0) {
249       if (!NGBufferedDescriptor_safeWrite(toSNS, _line, len)) {
250         failed = 3;
251         goto finish;
252       }
253     }
254     if (!NGBufferedDescriptor_safeWrite(toSNS, " ", 1)) {
255       failed = 4;
256       goto finish;
257     }
258     if ((len = strlen(_appName)) > 0) {
259       if (!NGBufferedDescriptor_safeWrite(toSNS, _appName, len)) {
260         failed = 5;
261         goto finish;
262       }
263     }
264     
265     // send cookie
266     len = strlen(_cookie);
267     if (len > 2000) {
268       ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
269                    "WARNING: cookie length > 2000 bytes (%i bytes): %s",
270                    len, _cookie);
271     }
272     if (!NGBufferedDescriptor_safeWrite(toSNS, &len, sizeof(len))) {
273       failed = 6;
274       goto finish;
275     }
276     if (len > 0) {
277       if (!NGBufferedDescriptor_safeWrite(toSNS, _cookie, len)) {
278         failed = 7;
279         goto finish;
280       }
281     }
282
283     if (!NGBufferedDescriptor_flush(toSNS)) {
284       failed = 8;
285       goto finish;
286     }
287     
288     if (HEAVY_LOG) {
289       ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
290                    "SNS: reading response ..");
291     }
292     
293     // recv response
294     {
295       char *buffer;
296       int  domain;
297       int  size;
298
299       buffer = apr_palloc(_rq->pool, 1000);
300       memset(buffer, 0, 1000);
301       
302       if (!NGBufferedDescriptor_safeRead(toSNS, &domain, sizeof(domain))) {
303         failed = 9;
304         goto finish;
305       }
306       if (HEAVY_LOG) {
307         ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
308                      "SNS:   domain: %i ..", domain);
309       }
310       
311       if (!NGBufferedDescriptor_safeRead(toSNS, &size, sizeof(size))) {
312         failed = 10;
313         goto finish;
314       }
315       if (HEAVY_LOG) {
316         ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
317                      "SNS:   size: %i ..", size);
318       }
319       
320       if (size > 1024) {
321         ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
322                      "SNS: size of returned address is too big (%i bytes) !",
323                      size);
324         goto finish;
325       }
326       
327       if (!NGBufferedDescriptor_safeRead(toSNS, buffer, size)) {
328         failed = 11;
329         goto finish;
330       }
331       
332       if (HEAVY_LOG) {
333         ap_log_error(__FILE__, __LINE__, APLOG_INFO, 0, _rq->server,
334                      "SNS: got address in domain %i, size is %i bytes !",
335                      domain, size);
336       }
337
338       *_domain = domain;
339       *_len    = size;
340       
341       if (toSNS) {
342         NGBufferedDescriptor_free(toSNS);
343         toSNS = NULL;
344       }
345       return buffer;
346     }
347   finish:
348     if (failed) {
349       ap_log_error(__FILE__, __LINE__, APLOG_ERR, 0, _rq->server,
350                    "SNS: lookup request failed (code=%i) !", failed);
351     }
352     if (toSNS) {
353       NGBufferedDescriptor_free(toSNS);
354       toSNS = NULL;
355     }
356   }
357   return NULL;
358 }