~ubuntu-branches/ubuntu/karmic/rsyslog/karmic-200908151517

« back to all changes in this revision

Viewing changes to tcpclt.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2008-04-23 16:46:39 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20080423164639-5acmt8a4vpxjgnxw
Tags: 3.14.2-3
* debian/rsyslog-doc.install
  - Fix a typo in the install path of the dia files. Closes: #477489
    Thanks to Justin B Rye for the patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* tcpclt.c
 
2
 *
 
3
 * This is the implementation of TCP-based syslog clients (the counterpart
 
4
 * of the tcpsrv class).
 
5
 *
 
6
 * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH.
 
7
 *
 
8
 * This file is part of rsyslog.
 
9
 *
 
10
 * Rsyslog is free software: you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation, either version 3 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * Rsyslog is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with Rsyslog.  If not, see <http://www.gnu.org/licenses/>.
 
22
 *
 
23
 * A copy of the GPL can be found in the file "COPYING" in this distribution.
 
24
 */
 
25
#include "config.h"
 
26
#include "rsyslog.h"
 
27
#include <stdio.h>
 
28
#include <stdarg.h>
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <unistd.h>
 
32
#include <errno.h>
 
33
#include <assert.h>
 
34
#include <netinet/in.h>
 
35
#include <netdb.h>
 
36
#include <sys/types.h>
 
37
#include <sys/socket.h>
 
38
#if HAVE_FCNTL_H
 
39
#include <fcntl.h>
 
40
#endif
 
41
#include "syslogd.h"
 
42
#include "syslogd-types.h"
 
43
#include "net.h"
 
44
#include "tcpsyslog.h"
 
45
#include "tcpclt.h"
 
46
#include "module-template.h"
 
47
#include "srUtils.h"
 
48
 
 
49
MODULE_TYPE_LIB
 
50
 
 
51
/* static data */
 
52
DEFobjStaticHelpers
 
53
 
 
54
/* Initialize TCP sockets (for sender)
 
55
 * This is done once per selector line, if not yet initialized.
 
56
 */
 
57
static int
 
58
CreateSocket(struct addrinfo *addrDest)
 
59
{
 
60
        int fd;
 
61
        struct addrinfo *r; 
 
62
        
 
63
        r = addrDest;
 
64
 
 
65
        while(r != NULL) {
 
66
                fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
 
67
                if (fd != -1) {
 
68
                        /* We can not allow the TCP sender to block syslogd, at least
 
69
                         * not in a single-threaded design. That would cause rsyslogd to
 
70
                         * loose input messages - which obviously also would affect
 
71
                         * other selector lines, too. So we do set it to non-blocking and 
 
72
                         * handle the situation ourselfs (by discarding messages). IF we run
 
73
                         * dual-threaded, however, the situation is different: in this case,
 
74
                         * the receivers and the selector line processing are only loosely
 
75
                         * coupled via a memory buffer. Now, I think, we can afford the extra
 
76
                         * wait time. Thus, we enable blocking mode for TCP if we compile with
 
77
                         * pthreads. -- rgerhards, 2005-10-25
 
78
                         * And now, we always run on multiple threads... -- rgerhards, 2007-12-20
 
79
                         */
 
80
                        if (connect (fd, r->ai_addr, r->ai_addrlen) != 0) {
 
81
                                if(errno == EINPROGRESS) {
 
82
                                        /* this is normal - will complete later select */
 
83
                                        return fd;
 
84
                                } else {
 
85
                                        char errStr[1024];
 
86
                                        dbgprintf("create tcp connection failed, reason %s",
 
87
                                                rs_strerror_r(errno, errStr, sizeof(errStr)));
 
88
                                }
 
89
 
 
90
                        }
 
91
                        else {
 
92
                                return fd;
 
93
                        }
 
94
                        close(fd);
 
95
                }
 
96
                else {
 
97
                        char errStr[1024];
 
98
                        dbgprintf("couldn't create send socket, reason %s", rs_strerror_r(errno, errStr, sizeof(errStr)));
 
99
                }               
 
100
                r = r->ai_next;
 
101
        }
 
102
 
 
103
        dbgprintf("no working socket could be obtained");
 
104
 
 
105
        return -1;
 
106
}
 
107
 
 
108
 
 
109
 
 
110
/* Build frame based on selected framing 
 
111
 * This function was created by pulling code from TCPSend()
 
112
 * on 2007-12-27 by rgerhards. Older comments are still relevant.
 
113
 *
 
114
 * In order to support compressed messages via TCP, we must support an
 
115
 * octet-counting based framing (LF may be part of the compressed message).
 
116
 * We are now supporting the same mode that is available in IETF I-D
 
117
 * syslog-transport-tls-05 (current at the time of this writing). This also
 
118
 * eases things when we go ahead and implement that framing. I have now made
 
119
 * available two cases where this framing is used: either by explitely
 
120
 * specifying it in the config file or implicitely when sending a compressed
 
121
 * message. In the later case, compressed and uncompressed messages within
 
122
 * the same session have different framings. If it is explicitely set to
 
123
 * octet-counting, only this framing mode is used within the session.
 
124
 * rgerhards, 2006-12-07
 
125
 */
 
126
static rsRetVal
 
127
TCPSendBldFrame(tcpclt_t *pThis, char **pmsg, size_t *plen, int *pbMustBeFreed)
 
128
{
 
129
        DEFiRet;
 
130
        TCPFRAMINGMODE framingToUse;
 
131
        int bIsCompressed;
 
132
        size_t len;
 
133
        char *msg;
 
134
        char *buf = NULL;       /* if this is non-NULL, it MUST be freed before return! */
 
135
 
 
136
        assert(plen != NULL);
 
137
        assert(pbMustBeFreed != NULL);
 
138
        assert(pmsg != NULL);
 
139
 
 
140
        msg = *pmsg;
 
141
        len = *plen;
 
142
        bIsCompressed = *msg == 'z';    /* cache this, so that we can modify the message buffer */
 
143
        /* select framing for this record. If we have a compressed record, we always need to
 
144
         * use octet counting because the data potentially contains all control characters
 
145
         * including LF.
 
146
         */
 
147
        framingToUse = bIsCompressed ? TCP_FRAMING_OCTET_COUNTING : pThis->tcp_framing;
 
148
 
 
149
        /* now check if we need to add a line terminator. We need to
 
150
         * copy the string in memory in this case, this is probably
 
151
         * quicker than using writev and definitely quicker than doing
 
152
         * two socket calls.
 
153
         * rgerhards 2005-07-22
 
154
         *
 
155
         * Some messages already contain a \n character at the end
 
156
         * of the message. We append one only if we there is not
 
157
         * already one. This seems the best fit, though this also
 
158
         * means the message does not arrive unaltered at the final
 
159
         * destination. But in the spirit of legacy syslog, this is
 
160
         * probably the best to do...
 
161
         * rgerhards 2005-07-20
 
162
         */
 
163
 
 
164
        /* Build frame based on selected framing */
 
165
        if(framingToUse == TCP_FRAMING_OCTET_STUFFING) {
 
166
                if((*(msg+len-1) != '\n')) {
 
167
                        /* in the malloc below, we need to add 2 to the length. The
 
168
                         * reason is that we a) add one character and b) len does
 
169
                         * not take care of the '\0' byte. Up until today, it was just
 
170
                         * +1 , which caused rsyslogd to sometimes dump core.
 
171
                         * I have added this comment so that the logic is not accidently
 
172
                         * changed again. rgerhards, 2005-10-25
 
173
                         */
 
174
                        if((buf = malloc((len + 2) * sizeof(char))) == NULL) {
 
175
                                /* extreme mem shortage, try to solve
 
176
                                 * as good as we can. No point in calling
 
177
                                 * any alarms, they might as well run out
 
178
                                 * of memory (the risk is very high, so we
 
179
                                 * do NOT risk that). If we have a message of
 
180
                                 * more than 1 byte (what I guess), we simply
 
181
                                 * overwrite the last character.
 
182
                                 * rgerhards 2005-07-22
 
183
                                 */
 
184
                                if(len > 1) {
 
185
                                        *(msg+len-1) = '\n';
 
186
                                } else {
 
187
                                        /* we simply can not do anything in
 
188
                                         * this case (its an error anyhow...).
 
189
                                         */
 
190
                                }
 
191
                        } else {
 
192
                                /* we got memory, so we can copy the message */
 
193
                                memcpy(buf, msg, len); /* do not copy '\0' */
 
194
                                *(buf+len) = '\n';
 
195
                                *(buf+len+1) = '\0';
 
196
                                msg = buf; /* use new one */
 
197
                                ++len; /* care for the \n */
 
198
                        }
 
199
                }
 
200
        } else {
 
201
                /* Octect-Counting
 
202
                 * In this case, we need to always allocate a buffer. This is because
 
203
                 * we need to put a header in front of the message text
 
204
                 */
 
205
                char szLenBuf[16];
 
206
                int iLenBuf;
 
207
 
 
208
                /* important: the printf-mask is "%d<sp>" because there must be a
 
209
                 * space after the len!
 
210
                 *//* The chairs of the IETF syslog-sec WG have announced that it is
 
211
                 * consensus to do the octet count on the SYSLOG-MSG part only. I am
 
212
                 * now changing the code to reflect this. Hopefully, it will not change
 
213
                 * once again (there can no compatibility layer programmed for this).
 
214
                 * To be on the save side, I just comment the code out. I mark these
 
215
                 * comments with "IETF20061218".
 
216
                 * rgerhards, 2006-12-19
 
217
                 */
 
218
                iLenBuf = snprintf(szLenBuf, sizeof(szLenBuf)/sizeof(char), "%d ", (int) len);
 
219
                /* IETF20061218 iLenBuf =
 
220
                  snprintf(szLenBuf, sizeof(szLenBuf)/sizeof(char), "%d ", len + iLenBuf);*/
 
221
 
 
222
                if((buf = malloc((len + iLenBuf) * sizeof(char))) == NULL) {
 
223
                        /* we are out of memory. This is an extreme situation. We do not
 
224
                         * call any alarm handlers because they most likely run out of mem,
 
225
                         * too. We are brave enough to call debug output, though. Other than
 
226
                         * that, there is nothing left to do. We can not sent the message (as
 
227
                         * in case of the other framing, because the message is incomplete.
 
228
                         * We could, however, send two chunks (header and text separate), but
 
229
                         * that would cause a lot of complexity in the code. So we think it
 
230
                         * is appropriate enough to just make sure we do not crash in this
 
231
                         * very unlikely case. For this, it is justified just to loose
 
232
                         * the message. Rgerhards, 2006-12-07
 
233
                         */
 
234
                         dbgprintf("Error: out of memory when building TCP octet-counted "
 
235
                                 "frame. Message is lost, trying to continue.\n");
 
236
                        ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
 
237
                }
 
238
 
 
239
                 memcpy(buf, szLenBuf, iLenBuf); /* header */
 
240
                 memcpy(buf + iLenBuf, msg, len); /* message */
 
241
                 len += iLenBuf;        /* new message size */
 
242
                 msg = buf;     /* set message buffer */
 
243
        }
 
244
 
 
245
        /* frame building complete, on to actual sending */
 
246
 
 
247
        *plen = len;
 
248
        if(buf == NULL) {
 
249
                /* msg not modified */
 
250
                *pbMustBeFreed = 0;
 
251
        } else {
 
252
                *pmsg = msg;
 
253
                *pbMustBeFreed = 1;
 
254
        }
 
255
 
 
256
finalize_it:
 
257
        RETiRet;
 
258
}
 
259
 
 
260
 
 
261
/* Sends a TCP message. It is first checked if the
 
262
 * session is open and, if not, it is opened. Then the send
 
263
 * is tried. If it fails, one silent re-try is made. If the send
 
264
 * fails again, an error status (-1) is returned. If all goes well,
 
265
 * 0 is returned. The TCP session is NOT torn down.
 
266
 * For now, EAGAIN is ignored (causing message loss) - but it is
 
267
 * hard to do something intelligent in this case. With this
 
268
 * implementation here, we can not block and/or defer. Things are
 
269
 * probably a bit better when we move to liblogging. The alternative
 
270
 * would be to enhance the current select server with buffering and
 
271
 * write descriptors. This seems not justified, given the expected
 
272
 * short life span of this code (and the unlikeliness of this event).
 
273
 * rgerhards 2005-07-06
 
274
 * This function is now expected to stay. Libloging won't be used for
 
275
 * that purpose. I have added the param "len", because it is known by the
 
276
 * caller and so saves us some time. Also, it MUST be given because there
 
277
 * may be NULs inside msg so that we can not rely on strlen(). Please note
 
278
 * that the restrictions outlined above do not existin in multi-threaded
 
279
 * mode, which we assume will now be most often used. So there is no
 
280
 * real issue with the potential message loss in single-threaded builds.
 
281
 * rgerhards, 2006-11-30
 
282
 * I greatly restructured the function to be more generic and work
 
283
 * with function pointers. So it now can be used with any type of transport,
 
284
 * as long as it follows stream semantics. This was initially done to 
 
285
 * support plain TCP and GSS via common code.
 
286
 */
 
287
static int
 
288
Send(tcpclt_t *pThis, void *pData, char *msg, size_t len)
 
289
{
 
290
        DEFiRet;
 
291
        int bDone = 0;
 
292
        int retry = 0;
 
293
        int bMsgMustBeFreed = 0;/* must msg be freed at end of function? 0 - no, 1 - yes */
 
294
 
 
295
        ISOBJ_TYPE_assert(pThis, tcpclt);
 
296
        assert(pData != NULL);
 
297
        assert(msg != NULL);
 
298
        assert(len > 0);
 
299
 
 
300
        CHKiRet(TCPSendBldFrame(pThis, &msg, &len, &bMsgMustBeFreed));
 
301
 
 
302
        while(!bDone) { /* loop is broken when send succeeds or error occurs */
 
303
                CHKiRet(pThis->initFunc(pData));
 
304
                iRet = pThis->sendFunc(pData, msg, len);
 
305
 
 
306
                if(iRet == RS_RET_OK) {
 
307
                        /* we are done, we also use this as indication that the previous
 
308
                         * message was succesfully received (it's not always the case, but its at 
 
309
                         * least our best shot at it -- rgerhards, 2008-03-12
 
310
                         */
 
311
                        if(pThis->prevMsg != NULL)
 
312
                                free(pThis->prevMsg);
 
313
                        /* if we can not alloc a new buffer, we silently ignore it. The worst that
 
314
                         * happens is that we lose our message recovery buffer - anything else would
 
315
                         * be worse, so don't try anything ;) -- rgerhards, 2008-03-12
 
316
                         */
 
317
                        if((pThis->prevMsg = malloc(len)) != NULL) {
 
318
                                memcpy(pThis->prevMsg, msg, len);
 
319
                                pThis->lenPrevMsg = len;
 
320
                        }
 
321
 
 
322
                        /* we are done with this record */
 
323
                        bDone = 1;
 
324
                } else {
 
325
                        if(retry == 0) { /* OK, one retry */
 
326
                                ++retry;
 
327
                                CHKiRet(pThis->prepRetryFunc(pData)); /* try to recover */
 
328
                                /* now try to send our stored previous message (which most probably
 
329
                                 * didn't make it
 
330
                                 */
 
331
                                if(pThis->prevMsg != NULL) {
 
332
                                        CHKiRet(pThis->initFunc(pData));
 
333
                                        CHKiRet(pThis->sendFunc(pData, pThis->prevMsg, pThis->lenPrevMsg));
 
334
                                }
 
335
                        } else {
 
336
                                /* OK, max number of retries reached, nothing we can do */
 
337
                                bDone = 1;
 
338
                        }
 
339
                }
 
340
        }
 
341
 
 
342
finalize_it:
 
343
        if(bMsgMustBeFreed)
 
344
                free(msg);
 
345
        RETiRet;
 
346
}
 
347
 
 
348
 
 
349
/* set functions */
 
350
static rsRetVal
 
351
SetSendInit(tcpclt_t *pThis, rsRetVal (*pCB)(void*))
 
352
{
 
353
        DEFiRet;
 
354
        pThis->initFunc = pCB;
 
355
        RETiRet;
 
356
}
 
357
static rsRetVal
 
358
SetSendPrepRetry(tcpclt_t *pThis, rsRetVal (*pCB)(void*))
 
359
{
 
360
        DEFiRet;
 
361
        pThis->prepRetryFunc = pCB;
 
362
        RETiRet;
 
363
}
 
364
static rsRetVal
 
365
SetSendFrame(tcpclt_t *pThis, rsRetVal (*pCB)(void*, char*, size_t))
 
366
{
 
367
        DEFiRet;
 
368
        pThis->sendFunc = pCB;
 
369
        RETiRet;
 
370
}
 
371
static rsRetVal
 
372
SetFraming(tcpclt_t *pThis, TCPFRAMINGMODE framing)
 
373
{
 
374
        DEFiRet;
 
375
        pThis->tcp_framing = framing;
 
376
        RETiRet;
 
377
}
 
378
 
 
379
 
 
380
/* Standard-Constructor
 
381
 */
 
382
BEGINobjConstruct(tcpclt) /* be sure to specify the object type also in END macro! */
 
383
ENDobjConstruct(tcpclt)
 
384
 
 
385
 
 
386
/* ConstructionFinalizer
 
387
 */
 
388
static rsRetVal
 
389
tcpcltConstructFinalize(tcpclt_t __attribute__((unused)) *pThis)
 
390
{
 
391
        DEFiRet;
 
392
        ISOBJ_TYPE_assert(pThis, tcpclt);
 
393
 
 
394
        RETiRet;
 
395
}
 
396
 
 
397
 
 
398
/* destructor for the tcpclt object */
 
399
BEGINobjDestruct(tcpclt) /* be sure to specify the object type also in END and CODESTART macros! */
 
400
CODESTARTobjDestruct(tcpclt)
 
401
        if(pThis->prevMsg != NULL)
 
402
                free(pThis->prevMsg);
 
403
ENDobjDestruct(tcpclt)
 
404
 
 
405
 
 
406
/* ------------------------------ handling the interface plumbing ------------------------------ */
 
407
 
 
408
/* queryInterface function
 
409
 * rgerhards, 2008-03-12
 
410
 */
 
411
BEGINobjQueryInterface(tcpclt)
 
412
CODESTARTobjQueryInterface(tcpclt)
 
413
        if(pIf->ifVersion != tcpcltCURR_IF_VERSION) { /* check for current version, increment on each change */
 
414
                ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
 
415
        }
 
416
 
 
417
        /* ok, we have the right interface, so let's fill it
 
418
         * Please note that we may also do some backwards-compatibility
 
419
         * work here (if we can support an older interface version - that,
 
420
         * of course, also affects the "if" above).
 
421
         */
 
422
        pIf->Construct = tcpcltConstruct;
 
423
        pIf->ConstructFinalize = tcpcltConstructFinalize;
 
424
        pIf->Destruct = tcpcltDestruct;
 
425
 
 
426
        pIf->CreateSocket = CreateSocket;
 
427
        pIf->Send = Send;
 
428
 
 
429
        /* set functions */
 
430
        pIf->SetSendInit = SetSendInit;
 
431
        pIf->SetSendFrame = SetSendFrame;
 
432
        pIf->SetSendPrepRetry = SetSendPrepRetry;
 
433
        pIf->SetFraming = SetFraming;
 
434
 
 
435
finalize_it:
 
436
ENDobjQueryInterface(tcpclt)
 
437
 
 
438
 
 
439
/* exit our class
 
440
 * rgerhards, 2008-03-10
 
441
 */
 
442
BEGINObjClassExit(tcpclt, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */
 
443
CODESTARTObjClassExit(tcpclt)
 
444
        /* release objects we no longer need */
 
445
ENDObjClassExit(tcpclt)
 
446
 
 
447
 
 
448
/* Initialize our class. Must be called as the very first method
 
449
 * before anything else is called inside this class.
 
450
 * rgerhards, 2008-02-29
 
451
 */
 
452
BEGINObjClassInit(tcpclt, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE class also in END MACRO! */
 
453
        /* request objects we use */
 
454
 
 
455
        /* set our own handlers */
 
456
        OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, tcpcltConstructFinalize);
 
457
ENDObjClassInit(tcpclt)
 
458
 
 
459
 
 
460
/* --------------- here now comes the plumbing that makes as a library module --------------- */
 
461
 
 
462
 
 
463
BEGINmodExit
 
464
CODESTARTmodExit
 
465
        /* de-init in reverse order! */
 
466
        tcpcltClassExit();
 
467
ENDmodExit
 
468
 
 
469
 
 
470
BEGINqueryEtryPt
 
471
CODESTARTqueryEtryPt
 
472
CODEqueryEtryPt_STD_LIB_QUERIES
 
473
ENDqueryEtryPt
 
474
 
 
475
 
 
476
BEGINmodInit()
 
477
CODESTARTmodInit
 
478
        *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
 
479
 
 
480
        /* Initialize all classes that are in our module - this includes ourselfs */
 
481
        CHKiRet(tcpcltClassInit(pModInfo)); /* must be done after tcps_sess, as we use it */
 
482
ENDmodInit
 
483
 
 
484
 
 
485
/*
 
486
 * vi:set ai:
 
487
 */