Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief This implements server part of network library.
0003  *
0004  * @file server.c
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 
0035 /*---------------------------Includes-----------------------------------*/
0036 #include <ndrx_config.h>
0037 #include <sys/socket.h>
0038 #include <sys/time.h>
0039 #include <sys/types.h>
0040 #include <arpa/inet.h>
0041 #include <netinet/in.h>
0042 #include <errno.h>
0043 #include <fcntl.h>
0044 #include <netdb.h>
0045 #include <string.h>
0046 #include <unistd.h>
0047 #include <atmi.h>
0048 
0049 #include <stdio.h>
0050 #include <stdlib.h>
0051 
0052 #include <exnet.h>
0053 #include <ndrstandard.h>
0054 #include <ndebug.h>
0055 #include <userlog.h>
0056 
0057 #if defined(EX_USE_EPOLL)
0058 
0059 #include <sys/epoll.h>
0060 
0061 #elif defined(EX_USE_KQUEUE)
0062 
0063 #include <sys/event.h>
0064 
0065 #else
0066 
0067 #include <poll.h>
0068 
0069 #endif
0070 /*---------------------------Externs------------------------------------*/
0071 /*---------------------------Macros-------------------------------------*/
0072 
0073 #if defined(EX_USE_EPOLL)
0074 
0075 /* EPOLLET Support #506 causes two packets to go on socket in the same time
0076  * after that the first packet is processed, but second is not, because
0077  * level is not changed
0078  */
0079 #define POLL_FLAGS (EPOLLIN | EPOLLHUP)
0080 
0081 #elif defined (EX_USE_KQUEUE)
0082 
0083 #define POLL_FLAGS EVFILT_READ
0084 
0085 #else
0086 
0087 #define POLL_FLAGS POLLIN
0088 
0089 #endif
0090 
0091 
0092 /*---------------------------Enums--------------------------------------*/
0093 /*---------------------------Typedefs-----------------------------------*/
0094 /*---------------------------Globals------------------------------------*/
0095 /*---------------------------Statics------------------------------------*/
0096 /*---------------------------Prototypes---------------------------------*/
0097 
0098 /**
0099  * About to remove incoming connection.
0100  */
0101 expublic void exnet_remove_incoming(exnetcon_t *net)
0102 {
0103     /* close(net->sock); Bug #233 - socket was already closed, core dumps on freebsd next */
0104     net->my_server->incomming_cons--;
0105     NDRX_LOG(log_debug, "Open connections decreased to: %d", 
0106             net->my_server->incomming_cons);
0107     /*
0108     NDRX_FREE(net->d);  remove network buffer 
0109     NDRX_FREE(net); */
0110 }
0111 
0112 /**
0113  * Server got something on the line! Executed by main thread
0114  * @param net
0115  * @return 
0116  */
0117 expublic int exnetsvpollevent(int fd, uint32_t events, void *ptr1)
0118 {
0119     int ret=EXSUCCEED;
0120     exnetcon_t *srv = (exnetcon_t *)ptr1;
0121     struct sockaddr_in clt_address;
0122     int client_fd;
0123     const char * ip_ptr;
0124     exnetcon_t *client = NULL;
0125     char *fn = "exnetsvpollevent";
0126     socklen_t addr_len = sizeof(clt_address);
0127     int is_new_con;
0128     int port;
0129     char ip[(INET6_ADDRSTRLEN)*2];
0130     struct sockaddr *sa = (struct sockaddr *)&clt_address;
0131     /* COMMON SETUP between new connection and existing... */
0132 #define CLT_COMMON_SETUP client->sock = client_fd;\
0133     EXNET_CONNECTED(client);\
0134     \
0135     /* We could get IP address & port of the call save in client struct \
0136      * & dump do log. \
0137      */\
0138     \
0139     if((ip_ptr = inet_ntop(sa->sa_family, &clt_address.sin_addr, ip, sizeof(ip))) < 0 )\
0140     {\
0141         NDRX_LOG(log_error, "Failed to get client IP address! %s", \
0142                 strerror(errno));\
0143         ret=EXFAIL;\
0144     }\
0145     \
0146     NDRX_STRCPY_SAFE(client->addr, ip_ptr);\
0147     /*Get port number*/\
0148     port = ntohs(clt_address.sin_port);\
0149     NDRX_LOG(log_warn, "Got call from: %s:%u", client->addr, port);\
0150     \
0151     if (EXSUCCEED!=exnet_configure_setopts(client))\
0152     {\
0153         NDRX_LOG(log_error, "Failed to configure client socket");\
0154         ret=EXFAIL;\
0155     }
0156     /* COMMON SETUP between new connection and existing..., END */
0157     
0158     NDRX_LOG(log_debug, "%s - enter", fn);
0159     
0160     
0161     if ( (client_fd = accept(srv->sock, (struct sockaddr *)&clt_address, &addr_len) ) < 0 )
0162     {
0163         NDRX_LOG(log_error, "Error calling accept(): %s", strerror(errno));
0164         EXFAIL_OUT(ret);
0165     }
0166 
0167     NDRX_LOG(log_error, "New incoming connection: fd=%d", client_fd);
0168 
0169     if (srv->incomming_cons+1 > srv->max_cons)
0170     {
0171         NDRX_LOG(log_error, "Too many open connections: %d/%d - closing down fd %d", 
0172                 srv->incomming_cons+1, srv->max_cons, client_fd);
0173         close(client_fd);
0174         /*Nothing to do than go out...*/
0175         goto out;
0176     }
0177     srv->incomming_cons++;
0178     NDRX_LOG(log_debug, "Open connections increased to: %d", 
0179             srv->incomming_cons);
0180     
0181     /* Allocate client connection structure! 
0182      * We could take a copy of server structure + do some modifications to it */
0183     
0184     /* Search for connection existence... - basically needs to find free connection */
0185     if (NULL!=(client=exnet_find_free_conn()))
0186     {
0187         NDRX_LOG(log_info, "Reusing connection object");
0188         is_new_con = EXFALSE;
0189     }
0190     else
0191     {
0192         NDRX_LOG(log_info, "Creating new connection object");
0193         is_new_con = EXTRUE;
0194     }
0195     
0196     if (is_new_con)
0197     {
0198         if (NULL==(client = NDRX_MALLOC(sizeof(exnetcon_t))))
0199         {
0200             int err = errno;
0201 
0202             userlog("Failed to allocate client structure! %s", 
0203                     strerror(err));
0204 
0205             NDRX_LOG(log_error, "Failed to allocate client structure! %s", 
0206                     strerror(err));
0207             EXFAIL_OUT(ret);
0208         }
0209 
0210         memcpy(client, srv, sizeof(exnetcon_t));
0211 
0212         /* Update the structure */
0213         client->is_server=EXFALSE;
0214         client->is_incoming = EXTRUE;
0215         client->my_server = srv;
0216         
0217         memcpy(&client->address, &clt_address, sizeof(clt_address));
0218         
0219         
0220         CLT_COMMON_SETUP;
0221         
0222         /* trap an error */
0223         if (EXSUCCEED!=ret)
0224         {
0225             goto out;
0226         }
0227 
0228         if (EXSUCCEED!=exnet_net_init(client))
0229         {
0230             NDRX_LOG(log_error, "Failed to init client!");
0231             EXFAIL_OUT(ret);
0232         }
0233     }
0234     else
0235     {
0236         exnet_rwlock_mainth_write(client);
0237         
0238         CLT_COMMON_SETUP;
0239         
0240         exnet_rwlock_mainth_read(client);
0241         
0242         /* trap an error */
0243         if (EXSUCCEED!=ret)
0244         {
0245             goto out;
0246         }
0247     }
0248     
0249     
0250     /* Call custom callback, if there is such */
0251     if (NULL!=client->p_connected && EXSUCCEED!=client->p_connected(client))
0252     {
0253         NDRX_LOG(log_error, "Connected notification "
0254                 "callback failed!");
0255         EXFAIL_OUT(ret);
0256     }
0257     
0258     /* Install poller extension? */
0259     if (EXSUCCEED!=tpext_addpollerfd(client->sock, POLL_FLAGS,
0260         client, exnet_poll_cb))
0261     {
0262         NDRX_LOG(log_error, "tpext_addpollerfd failed!");
0263         ret=EXFAIL;
0264         goto out;
0265     }
0266     
0267     if (is_new_con)
0268     {
0269         NDRX_LOG(log_info, "Adding connection to hashlist");
0270         /* Add incoming connection to list of connections. */
0271         exnet_add_con(client);
0272     }
0273     
0274 out:
0275 
0276     if (EXSUCCEED!=ret && client)
0277     {
0278         NDRX_FREE(client);
0279     }
0280 
0281     NDRX_LOG(log_debug, "%s - return %d", fn, ret);
0282     
0283     return ret;
0284 }
0285 
0286 /**
0287  * Server enters int listening state
0288  * If hostname has several IPs, then it will attempt to bind on first one
0289  * which is not busy.
0290  * @param net
0291  * @return 
0292  */
0293 expublic int exnet_bind(exnetcon_t *net)
0294 {
0295     int ret=EXSUCCEED;
0296     char *fn = "exnet_bind";
0297     char ip[(INET6_ADDRSTRLEN)*2];
0298     
0299     NDRX_LOG(log_debug, "%s - enter", fn);
0300     
0301     if ( (net->sock = socket(net->addr_cur->ai_family, SOCK_STREAM, 0)) < 0 )
0302     {
0303         NDRX_LOG(log_error, "Failed to create socket: %s",
0304                                 strerror(errno));
0305         EXFAIL_OUT(ret);
0306     }
0307     
0308     if (EXSUCCEED!=exnet_configure_setopts(net))
0309     {
0310         NDRX_LOG(log_error, "Failed to set socket opts!");
0311         EXFAIL_OUT(ret);
0312     }
0313     
0314     if (NULL!=inet_ntop (net->addr_cur->ai_family, 
0315             &((struct sockaddr_in *)net->addr_cur->ai_addr)->sin_addr, ip, sizeof(ip)))
0316     {
0317         NDRX_LOG(log_info,"About to listen on IPv%d address: %s port: %d", 
0318                 net->addr_cur->ai_family == PF_INET6 ? 6 : 4, ip, 
0319                 (int)exnet_get_port(net->addr_cur->ai_addr));
0320     }
0321     else
0322     {
0323         NDRX_LOG(log_error, "Failed to listen address info: %s", strerror(errno));
0324     }
0325     
0326     /* Bind our socket address to the 
0327      * listening socket, and call listen()  
0328      */
0329     if ( bind(net->sock, net->addr_cur->ai_addr, (int)net->addr_cur->ai_addrlen) < 0 )
0330     {
0331         if (errno==EADDRINUSE || errno==EADDRNOTAVAIL)
0332         {
0333             NDRX_LOG(log_error, "Error calling bind(): %s - ignore error, try later", 
0334                     strerror(errno));
0335             close(net->sock);
0336             net->sock=EXFAIL;
0337             goto out;
0338         }
0339         else
0340         {
0341             NDRX_LOG(log_error, "Error calling bind(): %s", strerror(errno));
0342             EXFAIL_OUT(ret);
0343         }
0344         
0345     }
0346     
0347     if ( listen(net->sock, net->backlog) < 0 ) 
0348     {
0349         if (errno==EADDRINUSE)
0350         {
0351             NDRX_LOG(log_error, "Error calling listen(): %s - ignore error, try later", 
0352                     strerror(errno));
0353 
0354             close(net->sock);
0355             net->sock=EXFAIL;
0356             goto out;
0357         }
0358         else
0359         {
0360             NDRX_LOG(log_error, "Error calling listen(): %s", 
0361                     strerror(errno));
0362             EXFAIL_OUT(ret);
0363         }
0364     }
0365     
0366     /* Install poller extension? */
0367     if (EXSUCCEED!=tpext_addpollerfd(net->sock, POLL_FLAGS, net, exnetsvpollevent))
0368     {
0369         NDRX_LOG(log_error, "tpext_addpollerfd failed!");
0370         ret=EXFAIL;
0371         goto out;
0372     }
0373     
0374 out:
0375 
0376     NDRX_LOG(log_debug, "%s - return %d", fn, ret);
0377 
0378     return ret;
0379 }
0380 /* vim: set ts=4 sw=4 et smartindent: */