1 //-< UNISOCK.CPP >---------------------------------------------------*--------*
2 // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 // (Post Relational Database Management System) * /\| *
4 // * / \ *
5 // Created: 8-Feb-97 K.A. Knizhnik * / [] \ *
6 // Last update: 18-May-97 K.A. Knizhnik * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // Unix sockets
9 //-------------------------------------------------------------------*--------*
10
11 #ifndef _WIN32
12 #define _INCLUDE_HPUX_SOURCE
13 #define __EXTENSIONS__
14 #define _EXTENSIONS
15
16 #include "unisock.h"
17 #undef BYTE_ORDER
18
19 //#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__bsdi__) || defined(__APPLE__)
20 //#include <sys/ioctl.h>
21 //#else
22 //#include <stropts.h>
23 //#endif
24 #include <sys/ioctl.h>
25 #include <fcntl.h>
26 #include <sys/time.h>
27 #include <sys/errno.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/utsname.h>
31 #ifndef HPUX11
32 #include <sys/select.h>
33 #endif
34 #include <netinet/in.h>
35 #include <netinet/tcp.h>
36 #include <arpa/inet.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #if defined(_AIX)
42 #include <strings.h>
43 #endif /* _AIX */
44 #include <stddef.h>
45 #include <assert.h>
46 #include <errno.h>
47
48 extern "C" {
49 #include <netdb.h>
50 }
51
52
53 #include <signal.h>
54
55 BEGIN_GIGABASE_NAMESPACE
56
57 const int MAX_HOST_NAME = 256;
58 const int GETHOSTBYNAME_BUF_SIZE = 1024;
59
60 char* unix_socket::unix_socket_dir = (char*)"/tmp/";
61
62 class unix_socket_library {
63 public:
unix_socket_library()64 unix_socket_library() {
65 static struct sigaction sigpipe_ignore;
66 sigpipe_ignore.sa_handler = SIG_IGN;
67 sigaction(SIGPIPE, &sigpipe_ignore, NULL);
68 }
69 };
70
71 static unix_socket_library unisock_lib;
72
open(int listen_queue_size)73 bool unix_socket::open(int listen_queue_size)
74 {
75 char hostname[MAX_HOST_NAME];
76 unsigned short port;
77 char* p;
78
79 assert(address != NULL);
80
81 if ((p = strchr(address, ':')) == NULL
82 || unsigned(p - address) >= sizeof(hostname)
83 || sscanf(p+1, "%hu", &port) != 1)
84 {
85 errcode = bad_address;
86 return false;
87 }
88 memcpy(hostname, address, p - address);
89 hostname[p - address] = '\0';
90
91 create_file = false;
92 union {
93 sockaddr sock;
94 sockaddr_in sock_inet;
95 char name[MAX_HOST_NAME];
96 } u;
97 int len;
98
99 if (domain == sock_local_domain) {
100 u.sock.sa_family = AF_UNIX;
101
102 assert(strlen(unix_socket_dir) + strlen(address)
103 < MAX_HOST_NAME - offsetof(sockaddr,sa_data));
104
105 len = offsetof(sockaddr,sa_data) +
106 sprintf(u.sock.sa_data, "%s%s.%u", unix_socket_dir, hostname, port);
107
108 unlink(u.sock.sa_data); // remove file if existed
109 create_file = true;
110 } else {
111 u.sock_inet.sin_family = AF_INET;
112 if (*hostname && strcmp(hostname, "localhost") != 0) {
113 struct hostent* hp;
114 #if defined(HAVE_GETHOSTBYNAME_R) && !defined(NO_PTHREADS)
115 struct hostent ent; // entry in hosts table
116 char buf[GETHOSTBYNAME_BUF_SIZE];
117 int h_err;
118 #if defined(__sun)
119 if ((hp = gethostbyname_r(hostname, &ent, buf, sizeof buf, &h_err)) == NULL
120 #else
121 if (gethostbyname_r(hostname, &ent, buf, sizeof buf, &hp, &h_err) != 0
122 || hp == NULL
123 #endif
124 || hp->h_addrtype != AF_INET)
125 #else
126 if ((hp = gethostbyname(hostname)) == NULL || hp->h_addrtype != AF_INET)
127 #endif
128 {
129 TRACE_MSG(("Failed to get host by name: %s\n", errno));
130 errcode = bad_address;
131 return false;
132 }
133 memcpy(&u.sock_inet.sin_addr, hp->h_addr,
134 sizeof u.sock_inet.sin_addr);
135 } else {
136 u.sock_inet.sin_addr.s_addr = htonl(INADDR_ANY);
137 }
138 u.sock_inet.sin_port = htons(port);
139 len = sizeof(sockaddr_in);
140 }
141 if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
142 errcode = errno;
143 return false;
144 }
145 int on = 1;
146 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof on);
147
148 if (bind(fd, &u.sock, len) < 0) {
149 errcode = errno;
150 ::close(fd);
151 return false;
152 }
153 if (listen(fd, listen_queue_size) < 0) {
154 errcode = errno;
155 ::close(fd);
156 return false;
157 }
158 errcode = ok;
159 state = ss_open;
160 return true;
161 }
162
get_peer_name()163 char* unix_socket::get_peer_name()
164 {
165 if (state != ss_open) {
166 errcode = not_opened;
167 return NULL;
168 }
169 struct sockaddr_in insock;
170 #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ > 3) || defined(_AIX43) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(HPUX11) || defined (__DragonFly__) || defined(_SOCKLEN_T)
171 socklen_t len = sizeof(insock);
172 #elif defined(_AIX41)
173 size_t len = sizeof(insock);
174 #else
175 int len = sizeof(insock);
176 #endif
177 if (getpeername(fd, (struct sockaddr*)&insock, &len) != 0) {
178 errcode = errno;
179 return NULL;
180 }
181 char* addr = inet_ntoa(insock.sin_addr);
182 if (addr == NULL) {
183 errcode = errno;
184 return NULL;
185 }
186 char* addr_copy = new char[strlen(addr)+1];
187 strcpy(addr_copy, addr);
188 errcode = ok;
189 return addr_copy;
190 }
191
is_ok()192 bool unix_socket::is_ok()
193 {
194 return errcode == ok;
195 }
196
get_error_text(char_t * buf,size_t buf_size)197 void unix_socket::get_error_text(char_t* buf, size_t buf_size)
198 {
199 char_t* msg;
200 switch(errcode) {
201 case ok:
202 msg = STRLITERAL("ok");
203 break;
204 case not_opened:
205 msg = STRLITERAL("socket not opened");
206 break;
207 case bad_address:
208 msg = STRLITERAL("bad address");
209 break;
210 case connection_failed:
211 msg = STRLITERAL("exceed limit of attempts of connection to server");
212 break;
213 case broken_pipe:
214 msg = STRLITERAL("connection is broken");
215 break;
216 case invalid_access_mode:
217 msg = STRLITERAL("invalid access mode");
218 break;
219 default:
220 #ifdef UNICODE
221 mbstowcs(buf, strerror(errcode), buf_size);
222 return;
223 #else
224 msg = strerror(errcode);
225 #endif
226 }
227 strncpy(buf, msg, buf_size-1);
228 buf[buf_size-1] = '\0';
229 }
230
accept()231 socket_t* unix_socket::accept()
232 {
233 int s;
234
235 if (state != ss_open) {
236 errcode = not_opened;
237 return NULL;
238 }
239
240 while((s = ::accept(fd, NULL, NULL )) < 0 && errno == EINTR);
241
242 if (s < 0) {
243 errcode = errno;
244 return NULL;
245 } else if (state != ss_open) {
246 errcode = not_opened;
247 return NULL;
248 } else {
249 if (domain == sock_global_domain) {
250 int enabled = 1;
251 if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&enabled,
252 sizeof enabled) != 0)
253 {
254 errcode = errno;
255 ::close(s);
256 return NULL;
257 }
258 }
259 #ifdef USE_SO_LINGER
260 static struct linger l = {1, LINGER_TIME};
261 if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof l) != 0) {
262 errcode = invalid_access_mode;
263 ::close(s);
264 return NULL;
265 }
266 #endif
267 errcode = ok;
268 return new unix_socket(s);
269 }
270 }
271
cancel_accept()272 bool unix_socket::cancel_accept()
273 {
274 bool result = close();
275 // Wakeup listener
276 delete socket_t::connect(address, domain, 1, 0);
277 return result;
278 }
279
280
connect(int max_attempts,time_t timeout)281 bool unix_socket::connect(int max_attempts, time_t timeout)
282 {
283 int rc;
284 char* p;
285 struct utsname local_host;
286 char hostname[MAX_HOST_NAME];
287 unsigned short port;
288
289 assert(address != NULL);
290
291 if ((p = strchr(address, ':')) == NULL
292 || unsigned(p - address) >= sizeof(hostname)
293 || sscanf(p+1, "%hu", &port) != 1)
294 {
295 errcode = bad_address;
296 return false;
297 }
298 memcpy(hostname, address, p - address);
299 hostname[p - address] = '\0';
300
301 create_file = false;
302 uname(&local_host);
303
304 if (domain == sock_local_domain || (domain == sock_any_domain &&
305 (strcmp(hostname, local_host.nodename) == 0
306 || strcmp(hostname, "localhost") == 0)))
307 {
308 // connect UNIX socket
309 union {
310 sockaddr sock;
311 char name[MAX_HOST_NAME];
312 } u;
313 u.sock.sa_family = AF_UNIX;
314
315 assert(strlen(unix_socket_dir) + strlen(address)
316 < MAX_HOST_NAME - offsetof(sockaddr,sa_data));
317
318 int len = offsetof(sockaddr,sa_data) +
319 sprintf(u.sock.sa_data, "%s%s.%u", unix_socket_dir, hostname, port);
320
321 while (true) {
322 if ((fd = socket(u.sock.sa_family, SOCK_STREAM, 0)) < 0) {
323 errcode = errno;
324 return false;
325 }
326 do {
327 rc = ::connect(fd, &u.sock, len);
328 } while (rc < 0 && errno == EINTR);
329
330 if (rc < 0) {
331 errcode = errno;
332 ::close(fd);
333 if (errcode == ENOENT || errcode == ECONNREFUSED) {
334 if (--max_attempts > 0) {
335 sleep(timeout);
336 } else {
337 break;
338 }
339 } else {
340 return false;
341 }
342 } else {
343 errcode = ok;
344 state = ss_open;
345 return true;
346 }
347 }
348 } else {
349 sockaddr_in sock_inet;
350 struct hostent* hp;
351 #if defined(HAVE_GETHOSTBYNAME_R) && !defined(NO_PTHREADS)
352 struct hostent ent; // entry in hosts table
353 char buf[GETHOSTBYNAME_BUF_SIZE];
354 int h_err;
355 #if defined(__sun)
356 if ((hp = gethostbyname_r(hostname, &ent, buf, sizeof buf, &h_err)) == NULL
357 #else
358 if (gethostbyname_r(hostname, &ent, buf, sizeof buf, &hp, &h_err) != 0
359 || hp == NULL
360 #endif
361 || hp->h_addrtype != AF_INET)
362 #else
363 if ((hp = gethostbyname(hostname)) == NULL || hp->h_addrtype != AF_INET)
364 #endif
365 {
366 TRACE_MSG(("Host name can not be resolved: %d\n", errno));
367 errcode = bad_address;
368 return false;
369 }
370 sock_inet.sin_family = AF_INET;
371 sock_inet.sin_port = htons(port);
372
373 while (true) {
374 for (int i = 0; hp->h_addr_list[i] != NULL; i++) {
375 memcpy(&sock_inet.sin_addr, hp->h_addr_list[i],
376 sizeof sock_inet.sin_addr);
377 if ((fd = socket(sock_inet.sin_family, SOCK_STREAM, 0)) < 0) {
378 errcode = errno;
379 return false;
380 }
381 do {
382 rc = ::connect(fd,(sockaddr*)&sock_inet,sizeof(sock_inet));
383 } while (rc < 0 && errno == EINTR);
384
385 if (rc < 0) {
386 errcode = errno;
387 ::close(fd);
388 if (errcode != ENOENT && errcode != ECONNREFUSED) {
389 return false;
390 }
391 } else {
392 int enabled = 1;
393 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
394 (char*)&enabled, sizeof enabled) != 0)
395 {
396 errcode = errno;
397 ::close(fd);
398 return false;
399 }
400 #ifdef USE_SO_LINGER
401 static struct linger l = {1, LINGER_TIME};
402 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&l, sizeof l) != 0) {
403 errcode = invalid_access_mode;
404 ::close(fd);
405 return NULL;
406 }
407 #endif
408 errcode = ok;
409 state = ss_open;
410 return true;
411 }
412 }
413 if (--max_attempts > 0) {
414 sleep(timeout);
415 } else {
416 break;
417 }
418 }
419 }
420 errcode = connection_failed;
421 return false;
422 }
423
read(void * buf,size_t min_size,size_t max_size,time_t timeout)424 int unix_socket::read(void* buf, size_t min_size, size_t max_size,
425 time_t timeout)
426 {
427 size_t size = 0;
428 time_t start = 0;
429 if (state != ss_open) {
430 errcode = not_opened;
431 return -1;
432 }
433 if (timeout != WAIT_FOREVER) {
434 start = time(NULL);
435 }
436 do {
437 ssize_t rc;
438 if (timeout != WAIT_FOREVER) {
439 fd_set events;
440 struct timeval tm;
441 FD_ZERO(&events);
442 FD_SET(fd, &events);
443 tm.tv_sec = timeout;
444 tm.tv_usec = 0;
445 while ((rc = select(fd+1, &events, NULL, NULL, &tm)) < 0
446 && errno == EINTR);
447 if (rc < 0) {
448 errcode = errno;
449 return -1;
450 }
451 if (rc == 0) {
452 return size;
453 }
454 time_t now = time(NULL);
455 timeout = start + timeout >= now ? timeout + start - now : 0;
456 }
457 while ((rc = ::read(fd, (char*)buf + size, max_size - size)) < 0
458 && errno == EINTR);
459 if (rc < 0) {
460 errcode = errno;
461 return -1;
462 } else if (rc == 0) {
463 errcode = broken_pipe;
464 return -1;
465 } else {
466 size += rc;
467 }
468 } while (size < min_size);
469
470 return (int)size;
471 }
472
473
write(void const * buf,size_t size)474 bool unix_socket::write(void const* buf, size_t size)
475 {
476 if (state != ss_open) {
477 errcode = not_opened;
478 return false;
479 }
480
481 do {
482 ssize_t rc;
483 while ((rc = ::write(fd, buf, size)) < 0 && errno == EINTR);
484 if (rc < 0) {
485 errcode = errno;
486 return false;
487 } else if (rc == 0) {
488 errcode = broken_pipe;
489 return false;
490 } else {
491 buf = (char*)buf + rc;
492 size -= rc;
493 }
494 } while (size != 0);
495
496 //
497 // errcode is not assigned 'ok' value beacuse write function
498 // can be called in parallel with other socket operations, so
499 // we want to preserve old error code here.
500 //
501 return true;
502 }
503
close()504 bool unix_socket::close()
505 {
506 if (state != ss_close) {
507 state = ss_close;
508 if (::close(fd) == 0) {
509 errcode = ok;
510 return true;
511 } else {
512 errcode = errno;
513 return false;
514 }
515 }
516 errcode = ok;
517 return true;
518 }
519
shutdown()520 bool unix_socket::shutdown()
521 {
522 if (state == ss_open) {
523 state = ss_shutdown;
524 int rc = ::shutdown(fd, 2);
525 if (rc != 0) {
526 errcode = errno;
527 return false;
528 }
529 }
530 return true;
531 }
532
~unix_socket()533 unix_socket::~unix_socket()
534 {
535 close();
536 if (create_file) {
537 char name[MAX_HOST_NAME];
538 char* p = strrchr(address, ':');
539 sprintf(name, "%s%.*s.%s", unix_socket_dir, (int)(p - address), address, p+1);
540 unlink(name);
541 }
542 delete[] address;
543 }
544
unix_socket(const char * addr,socket_domain domain)545 unix_socket::unix_socket(const char* addr, socket_domain domain)
546 {
547 address = new char[strlen(addr)+1];
548 strcpy(address, addr);
549 this->domain = domain;
550 create_file = false;
551 errcode = ok;
552 }
553
unix_socket(int new_fd)554 unix_socket::unix_socket(int new_fd)
555 {
556 fd = new_fd;
557 address = NULL;
558 create_file = false;
559 state = ss_open;
560 errcode = ok;
561 }
562
create_local(char const * address,int listen_queue_size)563 socket_t* socket_t::create_local(char const* address, int listen_queue_size)
564 {
565 unix_socket* sock = new unix_socket(address, sock_local_domain);
566 sock->open(listen_queue_size);
567 return sock;
568 }
569
create_global(char const * address,int listen_queue_size)570 socket_t* socket_t::create_global(char const* address, int listen_queue_size)
571 {
572 unix_socket* sock = new unix_socket(address, sock_global_domain);
573 sock->open(listen_queue_size);
574 return sock;
575 }
576
connect(char const * address,socket_domain domain,int max_attempts,time_t timeout)577 socket_t* socket_t::connect(char const* address,
578 socket_domain domain,
579 int max_attempts,
580 time_t timeout)
581 {
582 unix_socket* sock = new unix_socket(address, domain);
583 sock->connect(max_attempts, timeout);
584 return sock;
585 }
586
587 END_GIGABASE_NAMESPACE
588
589
590 #endif
591