~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/pbms/src/cslib/CSSocket.cc

  • Committer: Lee Bieber
  • Date: 2010-10-22 16:47:38 UTC
  • mfrom: (1841.1.7 drizzle_pbms)
  • Revision ID: kalebral@gmail.com-20101022164738-vv8w22b8towpb307
Merge Barry - fix bug 657830: PBMS build failure in GCC 4.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
 
31
31
#include <stdio.h>
32
32
#include <sys/types.h>
 
33
 
 
34
#ifdef OS_WINDOWS
 
35
#include <winsock.h>
 
36
typedef int socklen_t;
 
37
#define SHUT_RDWR 2
 
38
#define CLOSE_SOCKET(s) closesocket(s)
 
39
#define IOCTL_SOCKET    ioctlsocket
 
40
#define SOCKET_ERRORNO  WSAGetLastError()
 
41
#define EWOULDBLOCK             WSAEWOULDBLOCK
 
42
 
 
43
#else
 
44
#include <sys/ioctl.h>
33
45
#include <sys/socket.h>
34
46
#include <netdb.h>
35
47
#include <netinet/in.h>
36
48
#include <arpa/inet.h>
37
49
#include <netinet/in.h>
38
50
#include <netinet/tcp.h>
 
51
#include <sys/select.h>
 
52
#include <fcntl.h>
 
53
 
 
54
extern void unix_close(int h);
 
55
#define CLOSE_SOCKET(s) unix_close(s)
 
56
#define IOCTL_SOCKET    ioctl
 
57
#define SOCKET_ERRORNO  errno
 
58
 
 
59
#endif
 
60
 
39
61
#include <ctype.h>
40
62
#include <string.h>
41
63
#include <stdlib.h>
46
68
#include "CSStrUtil.h"
47
69
#include "CSFile.h"
48
70
 
 
71
void CSSocket::initSockets()
 
72
{
 
73
#ifdef OS_WINDOWS
 
74
        int             err;
 
75
        WSADATA data;
 
76
        WORD    version = MAKEWORD (1,1);
 
77
        static int inited = 0;
 
78
 
 
79
        if (!inited) {
 
80
                err = WSAStartup(version, &data);
 
81
 
 
82
                if (err != 0) {
 
83
                        CSException::throwException(CS_CONTEXT, err, "WSAStartup error");
 
84
                }
 
85
                
 
86
                inited = 1;
 
87
        }
 
88
        
 
89
#endif
 
90
}
 
91
 
49
92
/*
50
93
 * ---------------------------------------------------------------
51
94
 * CORE SYSTEM SOCKET FACTORY
53
96
 
54
97
CSSocket *CSSocket::newSocket()
55
98
{
56
 
        SCSocket *s;
 
99
        CSSocket *s;
57
100
        
58
 
        new_(s, SCSocket());
59
 
        return (CSSocket *) s;
 
101
        new_(s, CSSocket());
 
102
        return s;
60
103
}
61
104
 
62
105
/*
64
107
 * INTERNAL UTILITIES
65
108
 */
66
109
 
67
 
void SCSocket::formatAddress(size_t size, char *buffer)
 
110
void CSSocket::formatAddress(size_t size, char *buffer)
68
111
{
69
112
        if (iHost) {
70
113
                cs_strcpy(size, buffer, iHost);
77
120
                cs_strcat(size, buffer, iService);
78
121
}
79
122
 
80
 
void SCSocket::throwError(const char *func, const char *file, int line, char *address, int err)
 
123
void CSSocket::throwError(const char *func, const char *file, int line, char *address, int err)
81
124
{
82
125
        if (err)
83
126
                CSException::throwFileError(func, file, line, address, err);
85
128
                CSException::throwEOFError(func, file, line, address);
86
129
}
87
130
 
88
 
void SCSocket::throwError(const char *func, const char *file, int line, int err)
 
131
void CSSocket::throwError(const char *func, const char *file, int line, int err)
89
132
{
90
133
        char address[CS_SOCKET_ADDRESS_SIZE];
91
134
 
93
136
        throwError(func, file, line, address, err);
94
137
}
95
138
 
96
 
void SCSocket::setInternalOptions()
 
139
void CSSocket::setNoDelay()
97
140
{
98
141
        int flag = 1;
99
142
 
100
143
        if (setsockopt(iHandle, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) == -1)
101
 
                CSException::throwOSError(CS_CONTEXT, errno);
102
 
}
103
 
 
104
 
void SCSocket::openInternal()
105
 
{
106
 
        iHandle = socket(AF_INET, SOCK_STREAM, 0);
 
144
                CSException::throwOSError(CS_CONTEXT, SOCKET_ERRORNO);
 
145
}
 
146
 
 
147
void CSSocket::setNonBlocking()
 
148
{
 
149
        if (iTimeout) {
 
150
                unsigned long block = 1;
 
151
 
 
152
                if (IOCTL_SOCKET(iHandle, FIONBIO, &block) != 0)
 
153
                        throwError(CS_CONTEXT, SOCKET_ERRORNO);
 
154
        }
 
155
}
 
156
 
 
157
void CSSocket::setBlocking()
 
158
{
 
159
        /* No timeout, set blocking: */
 
160
        if (!iTimeout) {
 
161
                unsigned long block = 0;
 
162
 
 
163
                if (IOCTL_SOCKET(iHandle, FIONBIO, &block) != 0)
 
164
                        throwError(CS_CONTEXT, SOCKET_ERRORNO);
 
165
        }
 
166
}
 
167
 
 
168
void CSSocket::openInternal()
 
169
{
 
170
        iHandle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
107
171
        if (iHandle == -1)
108
 
                CSException::throwOSError(CS_CONTEXT, errno);
109
 
        setInternalOptions();
 
172
                CSException::throwOSError(CS_CONTEXT, SOCKET_ERRORNO);
 
173
        setNoDelay();
 
174
        setNonBlocking();
 
175
}
 
176
 
 
177
void CSSocket::writeBlock(const void *data, size_t len)
 
178
{
 
179
        ssize_t out;
 
180
 
 
181
        enter_();
 
182
        while (len > 0) {
 
183
                out = send(iHandle, (const char *) data, len, 0);
 
184
                self->interrupted();
 
185
                if (out == -1) {
 
186
                        int err = SOCKET_ERRORNO;
 
187
 
 
188
                        if (err == EWOULDBLOCK || err == EINTR)
 
189
                                continue;
 
190
                        throwError(CS_CONTEXT, err);
 
191
                }
 
192
                if ((size_t) out > len)
 
193
                        break;
 
194
                len -= (size_t) out;
 
195
                data = ((char *) data) + (size_t) out;
 
196
        }
 
197
        exit_();
 
198
}
 
199
 
 
200
int CSSocket::timeoutRead(CSThread *self, void *buffer, size_t length)
 
201
{      
 
202
        int                     in;
 
203
        uint64_t        start_time;
 
204
        uint64_t        timeout = iTimeout * 1000;
 
205
        
 
206
        start_time = CSTime::getTimeCurrentTicks();
 
207
 
 
208
        retry:
 
209
        in = recv(iHandle, (char *) buffer, length, 0);
 
210
        if (in == -1) {
 
211
                if (SOCKET_ERRORNO == EWOULDBLOCK) {
 
212
                        fd_set                  readfds;
 
213
                        uint64_t                time_diff;
 
214
                        struct timeval  tv_timeout;
 
215
 
 
216
                        FD_ZERO(&readfds);
 
217
                        self->interrupted();
 
218
 
 
219
                        time_diff = CSTime::getTimeCurrentTicks() - start_time;
 
220
                        if (time_diff >= timeout) {
 
221
                                char address[CS_SOCKET_ADDRESS_SIZE];
 
222
 
 
223
                                formatAddress(CS_SOCKET_ADDRESS_SIZE, address);
 
224
                                CSException::throwExceptionf(CS_CONTEXT, CS_ERR_RECEIVE_TIMEOUT, "Receive timeout: %lu ms, on: %s", iTimeout, address);
 
225
                        }
 
226
 
 
227
                        /* Calculate how much time we can wait: */
 
228
                        time_diff = timeout - time_diff;
 
229
                        tv_timeout.tv_sec = (long)time_diff / 1000000;
 
230
                        tv_timeout.tv_usec = (long)time_diff % 1000000;
 
231
 
 
232
                        FD_SET(iHandle, &readfds);
 
233
                        in = select(iHandle+1, &readfds, NULL, NULL, &tv_timeout);
 
234
                        if (in != -1)
 
235
                                goto retry;
 
236
                }
 
237
        }
 
238
        return in;
110
239
}
111
240
 
112
241
/*
114
243
 * SOCKET BASED ON THE STANDARD C SOCKET
115
244
 */
116
245
 
 
246
void CSSocket::setTimeout(uint32_t milli_sec)
 
247
{
 
248
        if (iTimeout != milli_sec) {
 
249
                if ((iTimeout = milli_sec))
 
250
                        setNonBlocking();
 
251
                else
 
252
                        setBlocking();
 
253
        }
 
254
}
 
255
 
117
256
CSOutputStream *CSSocket::getOutputStream()
118
257
{
119
258
        return CSSocketOutputStream::newStream(RETAIN(this));
124
263
        return CSSocketInputStream::newStream(RETAIN(this));
125
264
}
126
265
 
127
 
void SCSocket::publish(char *service, int default_port)
 
266
void CSSocket::publish(char *service, int default_port)
128
267
{
129
268
        enter_();
130
269
        close();
171
310
                server.sin_port = (uint16_t) servp->s_port;
172
311
 
173
312
                if (setsockopt(iHandle, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(int)) == -1)
174
 
                        CSException::throwOSError(CS_CONTEXT, errno);
 
313
                        CSException::throwOSError(CS_CONTEXT, SOCKET_ERRORNO);
175
314
 
176
315
                if (bind(iHandle, (struct sockaddr *) &server, sizeof(server)) == -1)
177
 
                        CSException::throwOSError(CS_CONTEXT, errno);
 
316
                        CSException::throwOSError(CS_CONTEXT, SOCKET_ERRORNO);
178
317
 
179
318
                if (listen(iHandle, SOMAXCONN) == -1)
180
 
                        CSException::throwOSError(CS_CONTEXT, errno);
 
319
                        CSException::throwOSError(CS_CONTEXT, SOCKET_ERRORNO);
181
320
        }
182
321
        catch_(a) {
183
322
                close();
187
326
        exit_();
188
327
}
189
328
 
190
 
void SCSocket::open(CSSocket *listener)
 
329
void CSSocket::open(CSSocket *listener)
191
330
{
192
331
        enter_();
193
332
 
199
338
                socklen_t                       addrlen = sizeof(remote);
200
339
 
201
340
                /* First get all the information we need from the listener: */
202
 
                listener_handle = ((SCSocket *) listener)->iHandle;
 
341
                listener_handle = ((CSSocket *) listener)->iHandle;
203
342
                listener->formatAddress(CS_SOCKET_ADDRESS_SIZE, address);
204
343
 
205
344
                /* I want to make sure no error occurs after the connect!
211
350
                iHost = (char *) cs_malloc(100);
212
351
                iHandle = accept(listener_handle, (struct sockaddr *) &remote, &addrlen);
213
352
                if (iHandle == -1)
214
 
                        throwError(CS_CONTEXT, address, errno);
 
353
                        throwError(CS_CONTEXT, address, SOCKET_ERRORNO);
215
354
 
216
355
                cs_strcpy(100, iHost, inet_ntoa(remote.sin_addr));
217
356
                iPort = ntohs(remote.sin_port);
218
357
 
219
 
                setInternalOptions();
 
358
                setNoDelay();
 
359
                setNonBlocking();
220
360
        }
221
361
        catch_(a) {
222
362
                close();
226
366
        exit_();
227
367
}
228
368
 
229
 
void SCSocket::open(char *address, int default_port)
 
369
void CSSocket::open(char *address, int default_port)
230
370
{
231
371
        enter_();
232
372
        close();
269
409
                memcpy(&server.sin_addr, hostp->h_addr, (size_t) hostp->h_length);
270
410
                server.sin_port = (uint16_t) servp->s_port;
271
411
                if (connect(iHandle, (struct sockaddr *) &server, sizeof(server)) == -1)
272
 
                        throwError(CS_CONTEXT, errno);
 
412
                        throwError(CS_CONTEXT, SOCKET_ERRORNO);
273
413
        }
274
414
        catch_(a) {
275
415
                close();
279
419
        exit_();
280
420
}
281
421
 
282
 
void SCSocket::close()
 
422
void CSSocket::close()
283
423
{
 
424
        flush();
284
425
        if (iHandle != -1) {
285
426
                shutdown(iHandle, SHUT_RDWR);
286
427
                /* shutdown does not close the socket!!? */
287
 
                unix_file_close(iHandle);
 
428
                CLOSE_SOCKET(iHandle);
288
429
                iHandle = -1;
289
430
        }
290
431
        if (iHost) {
295
436
                cs_free(iService);
296
437
                iService = NULL;
297
438
        }
 
439
        if (iIdentity) {
 
440
                cs_free(iIdentity);
 
441
                iIdentity = NULL;
 
442
        }
298
443
        iPort = 0;
299
444
}
300
445
 
301
 
size_t SCSocket::read(void *data, size_t len)
 
446
size_t CSSocket::read(void *data, size_t len)
302
447
{
303
448
        ssize_t in;
304
449
 
308
453
         * So a return of zero means EOF!
309
454
         */
310
455
        retry:
311
 
        in = recv(iHandle, data, len, 0);
 
456
        if (iTimeout)
 
457
                in = timeoutRead(self, data, len);
 
458
        else
 
459
                in = recv(iHandle, (char *) data, len, 0);
312
460
        self->interrupted();
313
461
        if (in == -1) {
314
462
                /* Note, we actually ignore all errors on the socket.
315
463
                 * If no data was returned by the read so far, then
316
464
                 * the error will be considered EOF.
317
465
                 */
318
 
                if (errno == EAGAIN || errno == EINTR)
 
466
                int err = SOCKET_ERRORNO;
 
467
 
 
468
                if (err == EWOULDBLOCK || err == EINTR)
319
469
                        goto retry;
 
470
                throwError(CS_CONTEXT, err);
320
471
                in = 0;
321
472
        }
322
473
        return_((size_t) in);
323
474
}
324
475
 
325
 
int SCSocket::read()
 
476
int CSSocket::read()
326
477
{
327
478
        int             ch;
328
479
        u_char  buffer[1];
335
486
        return_(ch);
336
487
}
337
488
 
338
 
int SCSocket::peek()
 
489
int CSSocket::peek()
339
490
{
340
491
        return -1;
341
492
}
342
493
 
343
 
void SCSocket::write(const void *data, size_t len)
344
 
{
345
 
        ssize_t out;
346
 
 
347
 
        enter_();
348
 
        while (len > 0) {
349
 
                out = send(iHandle, data, len, 0);
350
 
                self->interrupted();
351
 
                if (out == -1) {
352
 
                        int err = errno;
353
 
 
354
 
                        if (err == EAGAIN || errno == EINTR)
355
 
                                continue;
356
 
                        throwError(CS_CONTEXT, err);
357
 
                }
358
 
                if ((size_t) out > len)
359
 
                        break;
360
 
                len -= (size_t) out;
361
 
                data = ((char *) data) + (size_t) out;
362
 
        }
363
 
        exit_();
364
 
}
365
 
 
366
 
void SCSocket::write(char ch)
367
 
{
368
 
        enter_();
369
 
        write(&ch, 1);
370
 
        exit_();
371
 
}
372
 
 
373
 
void SCSocket::flush()
374
 
{
375
 
}
 
494
void CSSocket::write(const void *data, size_t len)
 
495
{
 
496
#ifdef CS_USE_OUTPUT_BUFFER
 
497
        if (len <= CS_MIN_WRITE_SIZE) {
 
498
                if (iDataLen + len > CS_OUTPUT_BUFFER_SIZE) {
 
499
                        /* This is the amount of data that will still fit
 
500
                         * intp the buffer:
 
501
                         */
 
502
                        size_t tfer = CS_OUTPUT_BUFFER_SIZE - iDataLen;
 
503
 
 
504
                        memcpy(iOutputBuffer + iDataLen, data, tfer);
 
505
                        flush();
 
506
                        len -= tfer;
 
507
                        memcpy(iOutputBuffer, ((char *) data) + tfer, len);
 
508
                        iDataLen = len;
 
509
                }
 
510
                else {
 
511
                        memcpy(iOutputBuffer + iDataLen, data, len);
 
512
                        iDataLen += len;
 
513
                }
 
514
        }
 
515
        else {
 
516
                /* If the block give is large enough, the
 
517
                 * writing directly from the block saves copying the
 
518
                 * data to the local output buffer buffer:
 
519
                 */
 
520
                flush();
 
521
                writeBlock(data, len);
 
522
        }
 
523
#else
 
524
        writeBlock(data, len);
 
525
#endif
 
526
}
 
527
 
 
528
void CSSocket::write(char ch)
 
529
{
 
530
        enter_();
 
531
        writeBlock(&ch, 1);
 
532
        exit_();
 
533
}
 
534
 
 
535
void CSSocket::flush()
 
536
{
 
537
#ifdef CS_USE_OUTPUT_BUFFER
 
538
        uint32_t len;
 
539
 
 
540
        if ((len = iDataLen)) {
 
541
                iDataLen = 0;
 
542
                /* Note: we discard the data to be written if an
 
543
                 * exception occurs.
 
544
                 */
 
545
                writeBlock(iOutputBuffer, len);
 
546
        }
 
547
#endif
 
548
}
 
549
 
 
550
const char *CSSocket::identify()
 
551
{
 
552
        enter_();
 
553
        if (!iIdentity) {
 
554
                char buffer[200];
 
555
 
 
556
                formatAddress(200, buffer);
 
557
                iIdentity = cs_strdup(buffer);
 
558
        }
 
559
        return_(iIdentity);
 
560
}
 
561
 
376
562
 
377
563