5
* © Copyright IBM Corp. 2007
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.
11
* You can obtain a current copy of the Eclipse Public License from
12
* http://www.opensource.org/licenses/eclipse-1.0.php
14
* Author: Sven Schuetz <sven@de.ibm.com>
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
22
#include "nativeCimXml.h"
24
#include "cimXmlParser.h"
27
#include <sys/socket.h>
28
#include <netinet/in.h>
33
static int do_listen=1;
35
#define SOCKBUFSZ 32768
36
#define hdrBufsize 5000
37
#define hdrLimmit 5000
39
typedef struct _buffer {
41
int length, size, ptr, content_length,trailers;
42
char *httpHdr, *authorization, *content_type, *host, *useragent;
47
typedef struct commHndl {
54
static void freeBuffer(Buffer * b)
56
Buffer emptyBuf = { NULL, NULL, 0, 0, 0, 0, 0 ,0};
65
int commWrite(CommHndl to, void *data, size_t count)
69
if (to.file == NULL) {
70
rc = write(to.socket,data,count);
72
rc = fwrite(data,count,1,to.file);
74
/* return number of bytes written */
82
int commRead(CommHndl from, void *data, size_t count)
86
rc = read(from.socket,data,count);
91
void commClose(CommHndl hndl)
93
if (hndl.file == NULL) {
103
void commFlush(CommHndl hndl)
110
static void add2buffer(Buffer * b, char *str, size_t len)
115
b->data = (char *) malloc(b->size);
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);
121
memmove(&((b->data)[b->length]), str, len);
123
(b->data)[b->length] = 0;
126
static void genError(CommHndl conn_fd, Buffer * b, int status, char *title,
130
char server[] = "Server: sfcc indListener\r\n";
131
char clength[] = "Content-Length: 0\r\n";
132
char cclose[] = "Connection: close\r\n";
135
snprintf(head, sizeof(head), "%s %d %s\r\n", b->protocol, status, title);
136
commWrite(conn_fd, head, strlen(head));
138
commWrite(conn_fd, more, strlen(more));
140
commWrite(conn_fd, server, strlen(server));
141
commWrite(conn_fd, clength, strlen(clength));
142
commWrite(conn_fd, cclose, strlen(cclose));
144
commWrite(conn_fd, end, strlen(end));
148
static char *getNextHdr(Buffer * b)
153
for (i = b->ptr; b->ptr < b->length; ++b->ptr) {
155
if (c == '\n' || c == '\r') {
158
if (c == '\r' && b->ptr < b->length && b->data[b->ptr] == '\n') {
162
return &(b->data[i]);
168
static int readData(CommHndl conn_fd, char *into, int length)
173
r = commRead(conn_fd, into + c, length - c);
174
if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
182
static void getPayload(CommHndl conn_fd, Buffer * b)
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);
188
readData(conn_fd, (b->content) + c, b->content_length - c);
189
*((b->content) + b->content_length) = 0;
192
static int getHdrs(CommHndl conn_fd, Buffer * b, char *cmd)
194
int first=1,total=0,isReady;
195
struct timeval httpTimeout;
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;
207
char buf[hdrBufsize];
208
int r = commRead(conn_fd, buf, sizeof(buf));
210
if (r < 0 && (errno == EINTR || errno == EAGAIN)) continue;
213
add2buffer(b, buf, r);
216
if (strncasecmp(buf,cmd,strlen(cmd)) != 0) {
217
/* not what we expected - still continue to read to
218
not confuse the client */
224
if (strstr(b->data, "\r\n\r\n") != NULL ||
225
strstr(b->data, "\n\n") != NULL) {
229
if (total>=hdrLimmit) {
230
fprintf(stderr, "-#- Possible DOS attempt detected\n");
238
static void processIndication(struct native_indicationlistener *i, char *xml)
244
rh = scanCimXmlResponse(xml, NULL);
246
if (rh.errCode != 0) {
247
free(rh.description);
248
rh.rvArray->ft->release(rh.rvArray);
252
inst = (CIMCInstance*)rh.rvArray->ft->getElementAt(rh.rvArray, 0, NULL).value.inst;
255
i->sendIndicationInstance(inst->ft->clone(inst, NULL));
258
rh.rvArray->ft->release(rh.rvArray);
261
static void handleConnection(int connFd, struct native_indicationlistener *i)
263
Buffer inBuf = { NULL, NULL, 0, 0, 0, 0, 0 ,0};
271
inBuf.authorization = "";
272
inBuf.protocol="HTTP/1.1";
273
inBuf.content_type = NULL;
274
inBuf.content_length = -1;
276
inBuf.useragent = "";
278
conn_fd.socket=connFd;
279
conn_fd.file=fdopen(connFd,"a");
281
if (conn_fd.file == NULL) {
282
/* failed to create socket stream - continue with raw socket */
284
conn_fd.buf = malloc(SOCKBUFSZ);
286
setbuffer(conn_fd.file,conn_fd.buf,SOCKBUFSZ);
288
/* failed to create socket buffer - continue unbuffered */
292
rc=getHdrs(conn_fd, &inBuf,"POST ");
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 */
301
genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
303
/* potential DOS attempt discovered */
306
genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
307
/* exiting after request timeout */
312
if (inBuf.size == 0) {
313
/* no buffer data - end of file - quit */
318
inBuf.httpHdr = getNextHdr(&inBuf);
320
if (inBuf.httpHdr == NULL) {
323
path = strpbrk(inBuf.httpHdr, " \t\r\n");
328
path += strspn(path, " \t\r\n");
329
inBuf.protocol = strpbrk(path, " \t\r\n");
330
*inBuf.protocol++ = 0;
331
if (inBuf.protocol == NULL) {
337
while ((hdr = getNextHdr(&inBuf)) != NULL) {
341
else if (strncasecmp(hdr, "Authorization:", 14) == 0) {
343
cp += strspn(cp, " \t");
344
inBuf.authorization = cp;
346
else if (strncasecmp(hdr, "Content-Length:", 15) == 0) {
348
cp += strspn(cp, " \t");
349
inBuf.content_length = atol(cp);
351
else if (strncasecmp(hdr, "Content-Type:", 13) == 0) {
353
cp += strspn(cp, " \t");
354
inBuf.content_type = cp;
356
else if (strncasecmp(hdr, "Host:", 5) == 0) {
358
cp += strspn(cp, " \t");
360
if (strchr(inBuf.host, '/') != NULL || inBuf.host[0] == '.') {
362
genError(conn_fd, &inBuf, 400, "Bad Request", NULL);
367
else if (strncasecmp(hdr, "User-Agent:", 11) == 0) {
369
cp += strspn(cp, " \t");
370
inBuf.useragent = cp;
372
else if (strncasecmp(hdr, "TE:", 3) == 0) {
374
cp += strspn(cp, " \t");
375
if (strncasecmp(cp,"trailers",8)==0)
378
else if (strncasecmp(hdr, "Expect:", 7) == 0) {
380
genError(conn_fd, &inBuf, 417, "Expectation Failed", NULL);
386
if (inBuf.content_length < 0) {
388
genError(conn_fd, &inBuf, 411, "Length Required", NULL);
394
getPayload(conn_fd, &inBuf);
400
/* well, not really an error ... op successful */
401
genError(conn_fd, &inBuf, 200, "OK", NULL);
403
processIndication(i, inBuf.content);
409
static void* establish_listener(int sslMode, int port, struct native_indicationlistener *i)
411
struct sockaddr_in sin;
412
socklen_t sz,sin_len;
413
int listenFd, connFd;
415
struct timeval timeout;
420
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
421
sin_len = sizeof(sin);
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);
429
setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (char *) &ru, sizeof(ru));
431
if (bind(listenFd, (struct sockaddr *) &sin, sin_len) ||
432
listen(listenFd, 0)) {
444
FD_SET(listenFd,&socksset);
446
dataRead = select(listenFd+1, &socksset, NULL, NULL, &timeout);
449
fprintf(stderr, "Error during select(), return value was: %d\n", dataRead);
451
else if(dataRead == 0) {
452
/* timed out, trying again */
454
if ((connFd = accept(listenFd, (__SOCKADDR_ARG) & sin, &sz))<0) {
455
fprintf(stderr, "Error during accept(), return value was: %d\n", connFd);
458
handleConnection(connFd, i);
466
static void* start_listen_thread(void *parms)
468
struct native_indicationlistener* i;
469
i = (struct native_indicationlistener*) parms;
470
establish_listener(i->sslMode, i->port, i);
474
static CIMCStatus _ilft_release(CIMCIndicationListener* il)
476
struct native_indicationlistener* i = (struct native_indicationlistener*)
488
static CIMCIndicationListener* _ilft_clone(CIMCIndicationListener* il,
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 */
497
static CIMCStatus _ilft_start(CIMCIndicationListener* il)
500
struct native_indicationlistener* i;
502
i = (struct native_indicationlistener*) il;
506
pthread_create(&id, NULL, &start_listen_thread, i);
514
static CIMCStatus _ilft_stop(CIMCIndicationListener* il)
524
CIMCIndicationListener *newCIMCIndicationListener(int sslMode,
526
void (*fp) (CIMCInstance *indInstance),
529
static CIMCIndicationListenerFT ilft = {
530
NATIVECIMXML_FT_VERSION,
537
static CIMCIndicationListener il = {
538
"CIMCIndicationListener",
542
struct native_indicationlistener * indicationlistener =
543
(struct native_indicationlistener*) calloc(1,
544
sizeof(struct native_indicationlistener));
546
indicationlistener->il = il;
547
indicationlistener->port = *portNumber;
548
indicationlistener->sslMode = sslMode;
549
indicationlistener->sendIndicationInstance = fp;
551
return (CIMCIndicationListener*) indicationlistener;