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