"Fossies" - the Fresh Open Source Software Archive

Member "citadel/clientsocket.c" (5 Jun 2021, 6854 Bytes) of package /linux/www/citadel.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "clientsocket.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 8.24_vs_9.01.

    1 // This module handles client-side sockets opened by the Citadel server (for
    2 // the client side of Internet protocols, etc.)   It does _not_ handle client
    3 // sockets for the Citadel client; for that you must look in ipc_c_tcp.c
    4 // (which, uncoincidentally, bears a striking similarity to this file).
    5 //
    6 // Copyright (c) 1987-2017 by the citadel.org team
    7 //
    8 // This program is open source software.  Use, duplication, or disclosure
    9 // is subject to the terms of the GNU General Public License, version 3.
   10 // The program is distributed without any warranty, expressed or implied.
   11 
   12 #include <stdlib.h>
   13 #include <unistd.h>
   14 #include <netdb.h>
   15 #include <stdio.h>
   16 #include <libcitadel.h>
   17 #include "ctdl_module.h"
   18 #include "clientsocket.h"
   19 
   20 int sock_connect(char *host, char *service)
   21 {
   22     struct in6_addr serveraddr;
   23     struct addrinfo hints;
   24     struct addrinfo *res = NULL;
   25     struct addrinfo *ai = NULL;
   26     int rc = (-1);
   27     int sock = (-1);
   28 
   29     if ((host == NULL) || IsEmptyStr(host))
   30         return (-1);
   31     if ((service == NULL) || IsEmptyStr(service))
   32         return (-1);
   33 
   34     memset(&hints, 0x00, sizeof(hints));
   35     hints.ai_flags = AI_NUMERICSERV;
   36     hints.ai_family = AF_UNSPEC;
   37     hints.ai_socktype = SOCK_STREAM;
   38 
   39     /*
   40      * Handle numeric IPv4 and IPv6 addresses
   41      */
   42     rc = inet_pton(AF_INET, host, &serveraddr);
   43     if (rc == 1) {                      /* dotted quad */
   44         hints.ai_family = AF_INET;
   45         hints.ai_flags |= AI_NUMERICHOST;
   46     } else {
   47         rc = inet_pton(AF_INET6, host, &serveraddr);
   48         if (rc == 1) {                  /* IPv6 address */
   49             hints.ai_family = AF_INET6;
   50             hints.ai_flags |= AI_NUMERICHOST;
   51         }
   52     }
   53 
   54     /* Begin the connection process */
   55 
   56     rc = getaddrinfo(host, service, &hints, &res);
   57     if (rc != 0) {
   58         syslog(LOG_ERR, "%s: %s", host, gai_strerror(rc));
   59         return(-1);
   60     }
   61 
   62     /*
   63      * Try all available addresses until we connect to one or until we run out.
   64      */
   65     for (ai = res; ai != NULL; ai = ai->ai_next) {
   66         sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
   67         if (sock < 0) {
   68             syslog(LOG_ERR, "%s: %m", host);
   69             freeaddrinfo(res);
   70             return(-1);
   71         }
   72         rc = connect(sock, ai->ai_addr, ai->ai_addrlen);
   73         if (rc >= 0) {
   74                         freeaddrinfo(res);
   75             return(sock);
   76         }
   77         else {
   78             syslog(LOG_ERR, "%s: %m", host);
   79             close(sock);
   80         }
   81     }
   82     freeaddrinfo(res);
   83     return(-1);
   84 }
   85 
   86 
   87 
   88 /*
   89  * Read data from the client socket.
   90  *
   91  * sock     socket fd to read from
   92  * buf      buffer to read into 
   93  * bytes    number of bytes to read
   94  * timeout  Number of seconds to wait before timing out
   95  *
   96  * Possible return values:
   97  *      1       Requested number of bytes has been read.
   98  *      0       Request timed out.
   99  *  -1      Connection is broken, or other error.
  100  */
  101 int socket_read_blob(int *Socket, StrBuf *Target, int bytes, int timeout)
  102 {
  103     const char *Error;
  104     int retval = 0;
  105 
  106     retval = StrBufReadBLOBBuffered(Target, CC->SBuf.Buf, &CC->SBuf.ReadWritePointer, Socket, 1, bytes, O_TERM, &Error); 
  107     if (retval < 0) {
  108         syslog(LOG_ERR, "clientsocket: socket_read_blob() failed: %s", Error);
  109     }
  110     return retval;
  111 }
  112 
  113 
  114 int CtdlSockGetLine(int *sock, StrBuf *Target, int nSec)
  115 {
  116     CitContext *CCC = MyContext();
  117     const char *Error;
  118     int rc;
  119 
  120     FlushStrBuf(Target);
  121     rc = StrBufTCP_read_buffered_line_fast(Target,
  122                            CCC->SBuf.Buf,
  123                            &CCC->SBuf.ReadWritePointer,
  124                            sock, nSec, 1, &Error);
  125     if ((rc < 0) && (Error != NULL)) {
  126         syslog(LOG_ERR, "clientsocket: CtdlSockGetLine() failed: %s", Error);
  127     }
  128     return rc;
  129 }
  130 
  131 
  132 /*
  133  * client_getln()   ...   Get a LF-terminated line of text from the client.
  134  */
  135 int sock_getln(int *sock, char *buf, int bufsize)
  136 {
  137     int i, retval;
  138     CitContext *CCC = MyContext();
  139     const char *pCh;
  140 
  141     FlushStrBuf(CCC->sMigrateBuf);
  142     retval = CtdlSockGetLine(sock, CCC->sMigrateBuf, 5);
  143 
  144     i = StrLength(CCC->sMigrateBuf);
  145     pCh = ChrPtr(CCC->sMigrateBuf);
  146 
  147     memcpy(buf, pCh, i + 1);
  148 
  149     FlushStrBuf(CCC->sMigrateBuf);
  150     if (retval < 0) {
  151         safestrncpy(&buf[i], "000", bufsize - i);
  152         i += 3;
  153     }
  154     return i;
  155 }
  156 
  157 
  158 /*
  159  * sock_write() - send binary to server.
  160  * Returns the number of bytes written, or -1 for error.
  161  */
  162 int sock_write(int *sock, const char *buf, int nbytes) 
  163 { return sock_write_timeout(sock, buf, nbytes, 50); }
  164 int sock_write_timeout(int *sock, const char *buf, int nbytes, int timeout)
  165 {
  166     int nSuccessLess = 0;
  167     int bytes_written = 0;
  168     int retval;
  169     fd_set rfds;
  170         int fdflags;
  171     int IsNonBlock;
  172     struct timeval tv;
  173     int selectresolution = 100;
  174 
  175     fdflags = fcntl(*sock, F_GETFL);
  176     IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
  177 
  178     while ((nSuccessLess < timeout) && 
  179            (*sock != -1) && 
  180            (bytes_written < nbytes)) 
  181     {
  182         if (IsNonBlock){
  183             tv.tv_sec = selectresolution;
  184             tv.tv_usec = 0;
  185             
  186             FD_ZERO(&rfds);
  187             FD_SET(*sock, &rfds);
  188             if (select(*sock + 1, NULL, &rfds, NULL, &tv) == -1) {
  189                 close (*sock);
  190                 *sock = -1;
  191                 return -1;
  192             }
  193         }
  194         if (IsNonBlock && !  FD_ISSET(*sock, &rfds)) {
  195             nSuccessLess ++;
  196             continue;
  197         }
  198         retval = write(*sock, &buf[bytes_written],
  199                    nbytes - bytes_written);
  200         if (retval < 1) {
  201             sock_close(*sock);
  202             *sock = -1;
  203             return (-1);
  204         }
  205         bytes_written = bytes_written + retval;
  206         if (IsNonBlock && (bytes_written == nbytes)){
  207             tv.tv_sec = selectresolution;
  208             tv.tv_usec = 0;
  209             
  210             FD_ZERO(&rfds);
  211             FD_SET(*sock, &rfds);
  212             if (select(*sock + 1, NULL, &rfds, NULL, &tv) == -1) {
  213                 close (*sock);
  214                 *sock = -1;
  215                 return -1;
  216             }
  217         }
  218     }
  219     return (bytes_written);
  220 }
  221 
  222 
  223 /*
  224  * client_getln()   ...   Get a LF-terminated line of text from the client.
  225  */
  226 int sock_getln_err(int *sock, char *buf, int bufsize, int *rc, int nSec)
  227 {
  228     int i, retval;
  229     CitContext *CCC = MyContext();
  230     const char *pCh;
  231 
  232     FlushStrBuf(CCC->sMigrateBuf);
  233     *rc = retval = CtdlSockGetLine(sock, CCC->sMigrateBuf, nSec);
  234 
  235     i = StrLength(CCC->sMigrateBuf);
  236     pCh = ChrPtr(CCC->sMigrateBuf);
  237 
  238     memcpy(buf, pCh, i + 1);
  239 
  240     FlushStrBuf(CCC->sMigrateBuf);
  241     if (retval < 0) {
  242         safestrncpy(&buf[i], "000", bufsize - i);
  243         i += 3;
  244     }
  245     return i;
  246 }
  247 
  248 
  249 /*
  250  * Multiline version of sock_gets() ... this is a convenience function for
  251  * client side protocol implementations.  It only returns the first line of
  252  * a multiline response, discarding the rest.
  253  */
  254 int ml_sock_gets(int *sock, char *buf, int nSec)
  255 {
  256     int rc = 0;
  257     char bigbuf[1024];
  258     int g;
  259 
  260     g = sock_getln_err(sock, buf, SIZ, &rc, nSec);
  261     if (rc < 0)
  262         return rc;
  263     if (g < 4)
  264         return (g);
  265     if (buf[3] != '-')
  266         return (g);
  267 
  268     do {
  269         g = sock_getln_err(sock, bigbuf, SIZ, &rc, nSec);
  270         if (rc < 0)
  271             return rc;
  272         if (g < 0)
  273             return (g);
  274     } while ((g >= 4) && (bigbuf[3] == '-'));
  275 
  276     return (strlen(buf));
  277 }
  278 
  279 
  280 /*
  281  * sock_puts() - send line to server - implemented in terms of serv_write()
  282  * Returns the number of bytes written, or -1 for error.
  283  */
  284 int sock_puts(int *sock, char *buf)
  285 {
  286     int i, j;
  287 
  288     i = sock_write(sock, buf, strlen(buf));
  289     if (i < 0)
  290         return (i);
  291     j = sock_write(sock, "\n", 1);
  292     if (j < 0)
  293         return (j);
  294     return (i + j);
  295 }