~ubuntu-branches/ubuntu/utopic/sblim-sfcc/utopic-proposed

« back to all changes in this revision

Viewing changes to backend/cimxml/indicationlistener.c

  • Committer: Bazaar Package Importer
  • Author(s): Thierry Carrez
  • Date: 2009-08-19 14:41:55 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20090819144155-jb46y5kmluacii70
Tags: 2.2.0-0ubuntu1
* New upstream version.
* debian/libcimcclient0.install: Ship missing libcmpisfcc library
* debian/control:
  - Switch to libcurl4-openssl-dev to match the rest of the SBLIM stack
  - Bump debhelper depend to >=5 to match debian/compat
  - Fix section names, add missing ${misc:Depends}
* debian/copyright: Add missing copyright notice
* debian/rules: Removed spurious DH_MAKESHLIBS argument

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/*
 
3
 * $\Id$
 
4
 *
 
5
 * © Copyright IBM Corp. 2007
 
6
 *
 
7
 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
 
8
 * ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
 
9
 * CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
 
10
 *
 
11
 * You can obtain a current copy of the Eclipse Public License from
 
12
 * http://www.opensource.org/licenses/eclipse-1.0.php
 
13
 *
 
14
 * Author:        Sven Schuetz <sven@de.ibm.com>
 
15
 *
 
16
 * Description:   indication listener implementation
 
17
 *                Most of the network and http code is taken from sfcb
 
18
 *                and written by Adrian Schuur / Viktor Mihajlovski
 
19
 */
 
20
 
 
21
 
 
22
#include "nativeCimXml.h"
 
23
#include "utilft.h"
 
24
#include "cimXmlParser.h"
 
25
 
 
26
#include <pthread.h>
 
27
#include <sys/socket.h>
 
28
#include <netinet/in.h>
 
29
#include <fcntl.h>
 
30
#include <errno.h>
 
31
#include <unistd.h>
 
32
 
 
33
static int do_listen=1;
 
34
 
 
35
#define SOCKBUFSZ 32768
 
36
#define hdrBufsize 5000
 
37
#define hdrLimmit 5000
 
38
 
 
39
typedef struct _buffer {
 
40
   char *data, *content;
 
41
   int length, size, ptr, content_length,trailers;
 
42
   char *httpHdr, *authorization, *content_type, *host, *useragent;
 
43
   char *principal;
 
44
   char *protocol;
 
45
} Buffer;
 
46
 
 
47
typedef struct commHndl {
 
48
  int   socket;
 
49
  FILE *file;
 
50
  void *buf;
 
51
} CommHndl;
 
52
 
 
53
 
 
54
static void freeBuffer(Buffer * b)
 
55
{
 
56
   Buffer emptyBuf = { NULL, NULL, 0, 0, 0, 0, 0 ,0};
 
57
   if (b->data)
 
58
      free(b->data);
 
59
   if (b->content)
 
60
      free(b->content);
 
61
   *b=emptyBuf;   
 
62
}
 
63
 
 
64
 
 
65
int commWrite(CommHndl to, void *data, size_t count)
 
66
{
 
67
   int rc=0;
 
68
  
 
69
    if (to.file == NULL) { 
 
70
        rc = write(to.socket,data,count);
 
71
    } else {
 
72
        rc = fwrite(data,count,1,to.file);
 
73
        if (rc == 1) {
 
74
        /* return number of bytes written */
 
75
        rc = count;
 
76
        }
 
77
    }
 
78
    
 
79
    return rc;
 
80
}
 
81
 
 
82
int commRead(CommHndl from, void *data, size_t count)
 
83
{
 
84
    int rc=0;
 
85
    
 
86
    rc = read(from.socket,data,count);
 
87
    
 
88
    return rc;
 
89
}
 
90
 
 
91
void commClose(CommHndl hndl)
 
92
{
 
93
    if (hndl.file == NULL) {
 
94
        close(hndl.socket);
 
95
    } else {
 
96
        fclose(hndl.file);
 
97
        if (hndl.buf) {
 
98
            free(hndl.buf);
 
99
        }
 
100
    }
 
101
}
 
102
 
 
103
void commFlush(CommHndl hndl)
 
104
{
 
105
    if (hndl.file) {
 
106
        fflush(hndl.file);
 
107
    }
 
108
}
 
109
 
 
110
static void add2buffer(Buffer * b, char *str, size_t len)
 
111
{
 
112
   if (b->size == 0) {
 
113
      b->size = len + 500;
 
114
      b->length = 0;
 
115
      b->data = (char *) malloc(b->size);
 
116
   }
 
117
   else if (b->length + len >= b->size) {
 
118
      b->size = b->length + len + 500;
 
119
      b->data = (char *) realloc((void *) b->data, b->size);
 
120
   }
 
121
   memmove(&((b->data)[b->length]), str, len);
 
122
   b->length += len;
 
123
   (b->data)[b->length] = 0;
 
124
}
 
125
 
 
126
static void genError(CommHndl conn_fd, Buffer * b, int status, char *title,
 
127
                     char *more)
 
128
{
 
129
    char head[1000];
 
130
    char server[] = "Server: sfcc indListener\r\n";
 
131
    char clength[] = "Content-Length: 0\r\n";
 
132
    char cclose[] = "Connection: close\r\n";
 
133
    char end[] = "\r\n";
 
134
 
 
135
    snprintf(head, sizeof(head), "%s %d %s\r\n", b->protocol, status, title);
 
136
    commWrite(conn_fd, head, strlen(head));
 
137
    if (more) {
 
138
        commWrite(conn_fd, more, strlen(more));
 
139
    }
 
140
    commWrite(conn_fd, server, strlen(server));
 
141
    commWrite(conn_fd, clength, strlen(clength));
 
142
    commWrite(conn_fd, cclose, strlen(cclose));
 
143
 
 
144
    commWrite(conn_fd, end, strlen(end));
 
145
    commFlush(conn_fd);
 
146
}
 
147
 
 
148
static char *getNextHdr(Buffer * b)
 
149
{
 
150
    int i;
 
151
    char c;
 
152
 
 
153
    for (i = b->ptr; b->ptr < b->length; ++b->ptr) {
 
154
        c = b->data[b->ptr];
 
155
        if (c == '\n' || c == '\r') {
 
156
            b->data[b->ptr] = 0;
 
157
            ++b->ptr;
 
158
            if (c == '\r' && b->ptr < b->length && b->data[b->ptr] == '\n') {
 
159
                b->data[b->ptr] = 0;
 
160
                ++b->ptr;
 
161
            }
 
162
            return &(b->data[i]);
 
163
        }
 
164
    }
 
165
    return NULL;
 
166
}
 
167
 
 
168
static int readData(CommHndl conn_fd, char *into, int length)
 
169
{
 
170
    int c = 0, r;
 
171
 
 
172
    while (c < length) {
 
173
        r = commRead(conn_fd, into + c, length - c);
 
174
        if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
 
175
            continue;
 
176
        }
 
177
        c += r;
 
178
    }
 
179
    return c;
 
180
}
 
181
 
 
182
static void getPayload(CommHndl conn_fd, Buffer * b)
 
183
{
 
184
    int c = b->length - b->ptr;
 
185
    b->content = (char *) malloc(b->content_length + 8);
 
186
    if (c) memcpy(b->content, (b->data) + b->ptr, c);
 
187
 
 
188
    readData(conn_fd, (b->content) + c, b->content_length - c);
 
189
    *((b->content) + b->content_length) = 0;
 
190
}
 
191
 
 
192
static int  getHdrs(CommHndl conn_fd, Buffer * b, char *cmd)
 
193
{
 
194
   int first=1,total=0,isReady;
 
195
   struct timeval httpTimeout;
 
196
   fd_set httpfds;
 
197
   int state=0;
 
198
   
 
199
   FD_ZERO(&httpfds);
 
200
   FD_SET(conn_fd.socket,&httpfds);
 
201
   httpTimeout.tv_sec=5;
 
202
   httpTimeout.tv_usec=0;
 
203
   isReady = select(conn_fd.socket+1,&httpfds,NULL,NULL,&httpTimeout);
 
204
   if (isReady == 0) return 3;
 
205
    
 
206
   for (;;) {
 
207
      char buf[hdrBufsize];
 
208
      int r = commRead(conn_fd, buf, sizeof(buf));
 
209
      
 
210
      if (r < 0 && (errno == EINTR || errno == EAGAIN)) continue;
 
211
      if (r <= 0) break;
 
212
      
 
213
      add2buffer(b, buf, r);
 
214
      total+=r;
 
215
      if (r && first) {
 
216
         if (strncasecmp(buf,cmd,strlen(cmd)) != 0) { 
 
217
       /* not what we expected - still continue to read to
 
218
          not confuse the client */
 
219
       state = 1;
 
220
     }
 
221
         first=0;
 
222
      }
 
223
      
 
224
      if (strstr(b->data, "\r\n\r\n") != NULL ||
 
225
          strstr(b->data, "\n\n") != NULL) {
 
226
         break;
 
227
      }
 
228
      
 
229
      if (total>=hdrLimmit) {
 
230
        fprintf(stderr, "-#- Possible DOS attempt detected\n");
 
231
        state = 2;
 
232
        break;
 
233
      }
 
234
   }
 
235
   return state;
 
236
}
 
237
 
 
238
static void processIndication(struct native_indicationlistener *i, char *xml)
 
239
{
 
240
    ResponseHdr rh;
 
241
    
 
242
    CIMCInstance *inst;
 
243
    
 
244
    rh = scanCimXmlResponse(xml, NULL);
 
245
    
 
246
    if (rh.errCode != 0) {
 
247
        free(rh.description);
 
248
        rh.rvArray->ft->release(rh.rvArray);
 
249
        return;
 
250
    }
 
251
   
 
252
    inst = (CIMCInstance*)rh.rvArray->ft->getElementAt(rh.rvArray, 0, NULL).value.inst;
 
253
    
 
254
    if(inst) {
 
255
        i->sendIndicationInstance(inst->ft->clone(inst, NULL));
 
256
    }
 
257
    
 
258
    rh.rvArray->ft->release(rh.rvArray);
 
259
}
 
260
 
 
261
static void handleConnection(int connFd, struct native_indicationlistener *i)
 
262
{
 
263
    Buffer inBuf = { NULL, NULL, 0, 0, 0, 0, 0 ,0};
 
264
    int badReq = 0;
 
265
    int discardInput=0;
 
266
    char *path, *hdr;
 
267
    char *cp;
 
268
    CommHndl conn_fd;
 
269
    int rc;
 
270
    
 
271
    inBuf.authorization = "";
 
272
    inBuf.protocol="HTTP/1.1";
 
273
    inBuf.content_type = NULL;
 
274
    inBuf.content_length = -1;
 
275
    inBuf.host = NULL;
 
276
    inBuf.useragent = "";
 
277
    
 
278
    conn_fd.socket=connFd;
 
279
    conn_fd.file=fdopen(connFd,"a");
 
280
    conn_fd.buf = NULL;
 
281
    if (conn_fd.file == NULL) {
 
282
        /* failed to create socket stream - continue with raw socket */
 
283
    } else {
 
284
        conn_fd.buf = malloc(SOCKBUFSZ);
 
285
    if (conn_fd.buf) {
 
286
        setbuffer(conn_fd.file,conn_fd.buf,SOCKBUFSZ);
 
287
    } else {
 
288
           /* failed to create socket buffer - continue unbuffered */
 
289
        }
 
290
    }
 
291
 
 
292
    rc=getHdrs(conn_fd, &inBuf,"POST ");
 
293
    
 
294
    if (rc==1) { 
 
295
        genError(conn_fd, &inBuf, 501, "Not Implemented", NULL);
 
296
        /* we continue to parse headers and empty the socket
 
297
        to be graceful with the client */
 
298
        discardInput=1;
 
299
    }
 
300
    else if (rc==2) {
 
301
        genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
 
302
        discardInput=2;
 
303
        /* potential DOS attempt discovered */      
 
304
    }
 
305
    else if (rc==3) {
 
306
        genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
 
307
        /* exiting after request timeout */
 
308
        commClose(conn_fd);
 
309
        exit(1);
 
310
    }
 
311
            
 
312
    if (inBuf.size == 0) {
 
313
        /* no buffer data - end of file - quit */   
 
314
        commClose(conn_fd);
 
315
        exit(1);
 
316
    }
 
317
    
 
318
    inBuf.httpHdr = getNextHdr(&inBuf);
 
319
    for (badReq = 1;;) {
 
320
        if (inBuf.httpHdr == NULL) {
 
321
            break;
 
322
        }
 
323
        path = strpbrk(inBuf.httpHdr, " \t\r\n");
 
324
        if (path == NULL) {
 
325
            break;
 
326
        }
 
327
        *path++ = 0;
 
328
        path += strspn(path, " \t\r\n");
 
329
        inBuf.protocol = strpbrk(path, " \t\r\n");
 
330
        *inBuf.protocol++ = 0;
 
331
        if (inBuf.protocol == NULL) {
 
332
            break;
 
333
        }
 
334
        badReq = 0;
 
335
    }
 
336
    
 
337
    while ((hdr = getNextHdr(&inBuf)) != NULL) {
 
338
        if (hdr[0] == 0) {
 
339
            break;
 
340
        }
 
341
        else if (strncasecmp(hdr, "Authorization:", 14) == 0) {
 
342
            cp = &hdr[14];
 
343
            cp += strspn(cp, " \t");
 
344
            inBuf.authorization = cp;
 
345
        }
 
346
        else if (strncasecmp(hdr, "Content-Length:", 15) == 0) {
 
347
            cp = &hdr[15];
 
348
            cp += strspn(cp, " \t");
 
349
            inBuf.content_length = atol(cp);
 
350
        }
 
351
        else if (strncasecmp(hdr, "Content-Type:", 13) == 0) {
 
352
            cp = &hdr[13];
 
353
            cp += strspn(cp, " \t");
 
354
            inBuf.content_type = cp;
 
355
        }
 
356
        else if (strncasecmp(hdr, "Host:", 5) == 0) {
 
357
            cp = &hdr[5];
 
358
            cp += strspn(cp, " \t");
 
359
            inBuf.host = cp;
 
360
            if (strchr(inBuf.host, '/') != NULL || inBuf.host[0] == '.') {
 
361
                if (!discardInput) {
 
362
                    genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
 
363
                    discardInput=2;
 
364
                }
 
365
            }
 
366
        }
 
367
        else if (strncasecmp(hdr, "User-Agent:", 11) == 0) {
 
368
            cp = &hdr[11];
 
369
            cp += strspn(cp, " \t");
 
370
            inBuf.useragent = cp;
 
371
        }
 
372
        else if (strncasecmp(hdr, "TE:", 3) == 0) {
 
373
            char *cp = &hdr[3];
 
374
            cp += strspn(cp, " \t");
 
375
            if (strncasecmp(cp,"trailers",8)==0)
 
376
            inBuf.trailers=1;
 
377
        }
 
378
        else if (strncasecmp(hdr, "Expect:", 7) == 0) {
 
379
            if (!discardInput) {
 
380
                genError(conn_fd, &inBuf, 417, "Expectation Failed", NULL);
 
381
                discardInput=2;
 
382
            }
 
383
        }
 
384
    }
 
385
    
 
386
    if (inBuf.content_length < 0) {
 
387
        if (!discardInput) {
 
388
            genError(conn_fd, &inBuf, 411, "Length Required", NULL);
 
389
        }      
 
390
        commClose(conn_fd);
 
391
        exit(1);
 
392
    }
 
393
 
 
394
    getPayload(conn_fd, &inBuf);
 
395
    if (discardInput) {
 
396
        freeBuffer(&inBuf);
 
397
        return;
 
398
    }
 
399
    
 
400
    /* well, not really an error ... op successful */
 
401
    genError(conn_fd, &inBuf, 200, "OK", NULL);
 
402
    
 
403
    processIndication(i, inBuf.content);
 
404
    
 
405
    freeBuffer(&inBuf);
 
406
    free(conn_fd.buf);
 
407
}
 
408
 
 
409
static void* establish_listener(int sslMode, int port, struct native_indicationlistener *i)
 
410
{
 
411
    struct sockaddr_in sin;
 
412
    socklen_t sz,sin_len;
 
413
    int listenFd, connFd;
 
414
    int ru;
 
415
    struct timeval timeout;
 
416
    fd_set socksset;
 
417
    int dataRead;
 
418
    char *xml;
 
419
 
 
420
    listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 
421
    sin_len = sizeof(sin);
 
422
 
 
423
    memset(&sin, 0, sin_len);
 
424
    sin.sin_family = AF_INET;
 
425
    sin.sin_addr.s_addr = INADDR_ANY;
 
426
    sin.sin_port = htons(port);
 
427
    
 
428
    ru = 1;
 
429
    setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (char *) &ru, sizeof(ru));
 
430
    
 
431
    if (bind(listenFd, (struct sockaddr *) &sin, sin_len) ||
 
432
        listen(listenFd, 0)) {
 
433
      exit(0);
 
434
    }
 
435
    
 
436
    sz = sizeof(sin);
 
437
    listen(listenFd, 1);
 
438
    
 
439
    while(do_listen) {
 
440
    
 
441
        timeout.tv_sec = 3;
 
442
        timeout.tv_usec = 0;
 
443
        FD_ZERO(&socksset);
 
444
        FD_SET(listenFd,&socksset);
 
445
        
 
446
        dataRead = select(listenFd+1, &socksset, NULL, NULL, &timeout);
 
447
        
 
448
        if(dataRead < 0) {
 
449
            fprintf(stderr, "Error during select(), return value was: %d\n", dataRead);
 
450
        }
 
451
        else if(dataRead == 0) {
 
452
            /* timed out, trying again */
 
453
        } else {
 
454
            if ((connFd = accept(listenFd, (__SOCKADDR_ARG) & sin, &sz))<0) {
 
455
                fprintf(stderr, "Error during accept(), return value was: %d\n", connFd);
 
456
                exit(0);
 
457
            }
 
458
            handleConnection(connFd, i);
 
459
            close(connFd);
 
460
        }
 
461
    }
 
462
 
 
463
    return NULL;
 
464
}
 
465
 
 
466
static void* start_listen_thread(void *parms)
 
467
{
 
468
    struct native_indicationlistener* i;
 
469
    i = (struct native_indicationlistener*) parms;
 
470
    establish_listener(i->sslMode, i->port, i);   
 
471
    return NULL;
 
472
}
 
473
 
 
474
static CIMCStatus _ilft_release(CIMCIndicationListener* il)
 
475
{
 
476
    struct native_indicationlistener* i = (struct native_indicationlistener*)
 
477
                                          il;
 
478
                                          
 
479
    if(i) {
 
480
        free(i);
 
481
    }
 
482
    CIMCStatus ret;
 
483
    ret.rc = CIMC_RC_OK;
 
484
    ret.msg = NULL;
 
485
    return ret;
 
486
}
 
487
 
 
488
static CIMCIndicationListener* _ilft_clone(CIMCIndicationListener* il,
 
489
                                           CIMCStatus* rc)
 
490
{
 
491
    /* not yet implemented. function is just here to comply with the default
 
492
     * function tables. it is questionable if a clone is needed for an
 
493
     * indication listener */
 
494
    return NULL;
 
495
}
 
496
 
 
497
static CIMCStatus _ilft_start(CIMCIndicationListener* il)
 
498
{
 
499
    pthread_t id;
 
500
    struct native_indicationlistener* i;
 
501
    
 
502
    i = (struct native_indicationlistener*) il;
 
503
    
 
504
    do_listen = 1;
 
505
    
 
506
    pthread_create(&id, NULL, &start_listen_thread, i);
 
507
 
 
508
    CIMCStatus ret;
 
509
    ret.rc = CIMC_RC_OK;
 
510
    ret.msg = NULL;
 
511
    return ret;
 
512
}
 
513
 
 
514
static CIMCStatus _ilft_stop(CIMCIndicationListener* il)
 
515
{
 
516
    do_listen = 0;
 
517
 
 
518
    CIMCStatus ret;
 
519
    ret.rc = CIMC_RC_OK;
 
520
    ret.msg = NULL;
 
521
    return ret;
 
522
}
 
523
 
 
524
CIMCIndicationListener *newCIMCIndicationListener(int sslMode,
 
525
                                                  int *portNumber,
 
526
                                                  void (*fp) (CIMCInstance *indInstance),
 
527
                                                  CIMCStatus *rc)
 
528
{
 
529
    static CIMCIndicationListenerFT ilft = {
 
530
        NATIVECIMXML_FT_VERSION,
 
531
        _ilft_release,
 
532
        _ilft_clone,
 
533
        _ilft_start,
 
534
        _ilft_stop
 
535
    };
 
536
    
 
537
    static CIMCIndicationListener il = {
 
538
        "CIMCIndicationListener",
 
539
        &ilft
 
540
    };
 
541
    
 
542
    struct native_indicationlistener  * indicationlistener =
 
543
                (struct native_indicationlistener*) calloc(1,
 
544
                   sizeof(struct native_indicationlistener));
 
545
                           
 
546
    indicationlistener->il = il;
 
547
    indicationlistener->port = *portNumber;
 
548
    indicationlistener->sslMode = sslMode;
 
549
    indicationlistener->sendIndicationInstance = fp;
 
550
    
 
551
    return (CIMCIndicationListener*) indicationlistener;
 
552
}