1
/* Copyright (c) 2008 PrimeBase Technologies GmbH, Germany
3
* PrimeBase Media Stream for MySQL
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
* Original author: Paul McCullagh (H&G2JCtL)
20
* Continued development: Barry Leslie
32
#include <sys/types.h>
33
#include <sys/socket.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
37
#include <netinet/in.h>
38
#include <netinet/tcp.h>
46
#include "CSStrUtil.h"
50
* ---------------------------------------------------------------
51
* CORE SYSTEM SOCKET FACTORY
54
CSSocket *CSSocket::newSocket()
59
return (CSSocket *) s;
63
* ---------------------------------------------------------------
67
void SCSocket::formatAddress(size_t size, char *buffer)
70
cs_strcpy(size, buffer, iHost);
72
cs_strcat(size, buffer, ":");
77
cs_strcat(size, buffer, iService);
80
void SCSocket::throwError(const char *func, const char *file, int line, char *address, int err)
83
CSException::throwFileError(func, file, line, address, err);
85
CSException::throwEOFError(func, file, line, address);
88
void SCSocket::throwError(const char *func, const char *file, int line, int err)
90
char address[CS_SOCKET_ADDRESS_SIZE];
92
formatAddress(CS_SOCKET_ADDRESS_SIZE, address);
93
throwError(func, file, line, address, err);
96
void SCSocket::setInternalOptions()
100
if (setsockopt(iHandle, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) == -1)
101
CSException::throwOSError(CS_CONTEXT, errno);
104
void SCSocket::openInternal()
106
iHandle = socket(AF_INET, SOCK_STREAM, 0);
108
CSException::throwOSError(CS_CONTEXT, errno);
109
setInternalOptions();
113
* ---------------------------------------------------------------
114
* SOCKET BASED ON THE STANDARD C SOCKET
117
CSOutputStream *CSSocket::getOutputStream()
119
return CSSocketOutputStream::newStream(RETAIN(this));
122
CSInputStream *CSSocket::getInputStream()
124
return CSSocketInputStream::newStream(RETAIN(this));
127
void SCSocket::publish(char *service, int default_port)
132
struct servent *servp;
133
struct sockaddr_in server;
139
if (isdigit(service[0])) {
140
int i = atoi(service);
143
CSException::throwCoreError(CS_CONTEXT, CS_ERR_BAD_ADDRESS, service);
145
s.s_port = htons((uint16_t) i);
146
iService = cs_strdup(service);
148
else if ((servp = getservbyname(service, "tcp")) == NULL) {
150
CSException::throwCoreError(CS_CONTEXT, CS_ERR_UNKNOWN_SERVICE, service);
152
s.s_port = htons((uint16_t) default_port);
153
iService = cs_strdup(default_port);
156
iService = cs_strdup(service);
160
CSException::throwCoreError(CS_CONTEXT, CS_ERR_UNKNOWN_SERVICE, "");
162
s.s_port = htons((uint16_t) default_port);
163
iService = cs_strdup(default_port);
166
iPort = ntohs(servp->s_port);
168
memset(&server, 0, sizeof(server));
169
server.sin_family = AF_INET;
170
server.sin_addr.s_addr = INADDR_ANY;
171
server.sin_port = (uint16_t) servp->s_port;
173
if (setsockopt(iHandle, SOL_SOCKET, SO_REUSEADDR, (char *) &flag, sizeof(int)) == -1)
174
CSException::throwOSError(CS_CONTEXT, errno);
176
if (bind(iHandle, (struct sockaddr *) &server, sizeof(server)) == -1)
177
CSException::throwOSError(CS_CONTEXT, errno);
179
if (listen(iHandle, SOMAXCONN) == -1)
180
CSException::throwOSError(CS_CONTEXT, errno);
190
void SCSocket::open(CSSocket *listener)
197
char address[CS_SOCKET_ADDRESS_SIZE];
198
struct sockaddr_in remote;
199
socklen_t addrlen = sizeof(remote);
201
/* First get all the information we need from the listener: */
202
listener_handle = ((SCSocket *) listener)->iHandle;
203
listener->formatAddress(CS_SOCKET_ADDRESS_SIZE, address);
205
/* I want to make sure no error occurs after the connect!
206
* So I allocate a buffer for the host name up front.
207
* This means it may be to small, but this is not a problem
208
* because the host name stored here is is only used for display
209
* of error message etc.
211
iHost = (char *) cs_malloc(100);
212
iHandle = accept(listener_handle, (struct sockaddr *) &remote, &addrlen);
214
throwError(CS_CONTEXT, address, errno);
216
cs_strcpy(100, iHost, inet_ntoa(remote.sin_addr));
217
iPort = ntohs(remote.sin_port);
219
setInternalOptions();
229
void SCSocket::open(char *address, int default_port)
234
char *portp = strchr(address, ':');
236
struct servent *servp;
237
struct hostent *hostp;
238
struct sockaddr_in server;
242
iHost = cs_strdup(address);
244
CSException::throwCoreError(CS_CONTEXT, CS_ERR_BAD_ADDRESS, address);
245
iService = cs_strdup(default_port);
248
iHost = cs_strdup(address, (size_t) (portp - address));
249
iService = cs_strdup(portp+1);
252
if (isdigit(iService[0])) {
253
int i = atoi(iService);
256
CSException::throwCoreError(CS_CONTEXT, CS_ERR_BAD_ADDRESS, address);
258
s.s_port = htons((uint16_t) i);
260
else if ((servp = getservbyname(iService, "tcp")) == NULL)
261
CSException::throwCoreError(CS_CONTEXT, CS_ERR_UNKNOWN_SERVICE, iService);
262
iPort = (int) ntohs(servp->s_port);
264
if ((hostp = gethostbyname(iHost)) == 0)
265
CSException::throwCoreError(CS_CONTEXT, CS_ERR_UNKNOWN_HOST, iHost);
267
memset(&server, 0, sizeof(server));
268
server.sin_family = AF_INET;
269
memcpy(&server.sin_addr, hostp->h_addr, (size_t) hostp->h_length);
270
server.sin_port = (uint16_t) servp->s_port;
271
if (connect(iHandle, (struct sockaddr *) &server, sizeof(server)) == -1)
272
throwError(CS_CONTEXT, errno);
282
void SCSocket::close()
285
shutdown(iHandle, SHUT_RDWR);
286
/* shutdown does not close the socket!!? */
287
unix_file_close(iHandle);
301
size_t SCSocket::read(void *data, size_t len)
306
/* recv, by default will block until at lease one byte is
308
* So a return of zero means EOF!
311
in = recv(iHandle, data, len, 0);
314
/* Note, we actually ignore all errors on the socket.
315
* If no data was returned by the read so far, then
316
* the error will be considered EOF.
318
if (errno == EAGAIN || errno == EINTR)
322
return_((size_t) in);
331
if (read(buffer, 1) == 1)
343
void SCSocket::write(const void *data, size_t len)
349
out = send(iHandle, data, len, 0);
354
if (err == EAGAIN || errno == EINTR)
356
throwError(CS_CONTEXT, err);
358
if ((size_t) out > len)
361
data = ((char *) data) + (size_t) out;
366
void SCSocket::write(char ch)
373
void SCSocket::flush()