Main Page   Data Structures   File List   Data Fields   Globals  

nsds_util.c

Go to the documentation of this file.
00001 
00010 #include "nsds_util.h"
00011 #include "flog.h"
00012 
00013 #include <sys/types.h>
00014 #include <sys/socket.h>
00015 #include <netinet/in.h>
00016 #include <arpa/inet.h>
00017 #include <netdb.h>
00018 #include <errno.h>
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <math.h>
00022 #include <unistd.h>
00023 #include <stdint.h>
00024 #include <string.h>
00025 #include <signal.h>
00026 #include <time.h>
00027 #include <sys/time.h>
00028 
00029 // Ref to control-c handler
00030 extern bool control_break;
00031 
00032 
00033 // ---------------------------------------------------------------------
00046 char *gen_timestamp(void)
00047 {
00048     char           me[] = "gen_timestamp";
00049     struct tm      l_tm;
00050     struct timeval t_highres;
00051     int            rc;
00052     static char    timebuf[80];
00053     time_t         in_time;
00054     
00055     // get fractional seconds
00056     rc = gettimeofday(&t_highres, NULL);
00057     if(rc != 0)
00058     {
00059     flog_usr(FLOG_ERROR, FL_ERR_SYSTEM, me,
00060          "Error reading current time!");
00061     return(NULL);
00062     }
00063 
00064     // Save elapsed seconds into time_t
00065     in_time = (time_t) t_highres.tv_sec;
00066 
00067     // Convert current into UTC
00068     gmtime_r(&in_time, &l_tm);
00069     
00070     // ISO 8601 format, as per 
00071     // http://www.exit109.com/~ghealton/y2k/yrexamples.html
00072     sprintf(timebuf, "%04d-%02d-%02dT%02d:%02d:%02d.%05.0f",
00073         l_tm.tm_year + 1900,
00074         l_tm.tm_mon + 1,
00075         l_tm.tm_mday,
00076         l_tm.tm_hour,
00077         l_tm.tm_min,
00078         l_tm.tm_sec,
00079         (float) (t_highres.tv_usec / 10.0));
00080     
00081     return(timebuf);
00082 }
00083 
00084 
00100 int tcp_socket_make(const uint16_t SRV_PORT, const int QUEUE_LENGTH)
00101 {
00102     char                me[] = "tcp_socket_make";
00103     struct sockaddr_in  serv_in;
00104     struct protoent     *ppe = NULL;
00105     int             itmp;
00106     int                 new_socket = 0;
00107     const int           no_socket = -1;
00108     int                 so_reuseaddr = 1;
00109     struct linger       so_linger;
00110 
00111     
00112     ppe = getprotobyname("tcp");
00113     if(ppe == NULL)
00114     {
00115     flog_usr(FLOG_ERROR, FL_ERR_SYSTEM, me, 
00116          "Error on getprotobyname");
00117     return(no_socket);
00118     }
00119     
00120     itmp = socket(PF_INET, SOCK_STREAM, ppe->p_proto);
00121     
00122     // Socket returns -1 on an error
00123     if(itmp < 0)
00124     {
00125     flog_usr(FLOG_ERROR, FL_ERR_SOCKET, me,
00126          "Error on socket creation; server running?");
00127     return(no_socket);
00128     }
00129     else
00130     new_socket = itmp;
00131 
00132     // Set socket options - see LSPBE book for details
00133     itmp = setsockopt(new_socket, SOL_SOCKET, SO_REUSEADDR,
00134               &so_reuseaddr, sizeof(so_reuseaddr));
00135     if(itmp != 0)
00136     flog_usr(FLOG_WARNING, 0, me,
00137          "Failure on setsockopt");
00138 
00139     // Set linger to true so that close waits for flush
00140     so_linger.l_onoff = true;
00141     so_linger.l_linger = 5;    // 5 second timeout on close(2)
00142     itmp = setsockopt(new_socket, SOL_SOCKET, SO_LINGER,
00143               &so_linger, sizeof(so_linger));
00144     if(itmp != 0)
00145     flog_usr(FLOG_WARNING, 0, me,
00146          "Failure on setsockopt");
00147     
00148     // Set up servers' address
00149     serv_in.sin_family = AF_INET;
00150     serv_in.sin_addr.s_addr = INADDR_ANY;
00151     serv_in.sin_port = htons(SRV_PORT);
00152     
00153     // Bind the socket to address
00154     itmp = bind(new_socket, (struct sockaddr *) &serv_in, sizeof(serv_in));
00155     
00156     // bind also returns -1 on an error
00157     if(itmp < 0)
00158     {
00159     flog_usr(FLOG_ERROR, FL_ERR_SOCKET, me,
00160          "Unable to bind to local port; server already running?");
00161 
00162         close(new_socket);
00163     return(no_socket);
00164     }
00165     
00166     // enable incoming connections
00167     // No max queue length in linux >= 2.2, not sure about other unixes -
00168     // this is a side benefit of the syn flood fixes
00169     itmp = listen(new_socket, QUEUE_LENGTH);
00170     if(itmp < 0)
00171     {
00172     flog_usr(FLOG_ERROR, FL_ERR_SOCKET, me, "Listen failure");
00173     close(new_socket);
00174          
00175     return(no_socket);
00176     }
00177     
00178     flog_usr(FLOG_NOTICE, 0, me,
00179          "Network setup completed OK on port %d", SRV_PORT);
00180 
00181     return(new_socket);
00182 }
00183 
00194 int tcp_nl_write(const int socket, const char *buf)
00195 {
00196     char   me[] = "tcp_nl_write";
00197     int    rc;
00198     int    len = strlen(buf);
00199     char   newline[] = "\n";
00200     
00201     rc = write(socket, buf, len);
00202     if(rc != len)
00203     {
00204     flog_usr(FLOG_ERROR, FL_ERR_TRANSCEIVE, me,
00205          "Error writing to socket");
00206     return(rc);
00207     }
00208     
00209     // Append newline
00210     rc = write(socket, newline, 1);
00211     if(rc != 1)
00212     {
00213     flog_usr(FLOG_ERROR, FL_ERR_TRANSCEIVE, me,
00214          "Error writing newline to socket");
00215     return(rc);
00216     }
00217 
00218     // Flush
00219     fsync(socket);
00220     
00221     // Made it OK
00222     return(len);
00223 }
00224 
00246 int tcp_nl_read(const uint16_t socket, char *buf, const time_t timeout)
00247 {
00248     char              me[] = "tcp_nl_read";
00249     int               bytes_read = 0;
00250     int               rc;
00251     char              *write_ptr = buf;
00252     bool              done = false;
00253     bool              got_newline = false;
00254     socket_wait_ret   sel_rc;
00255     bool              got_err = false;    
00256 
00257     if(buf == NULL)
00258     return(-1);
00259 
00260     // DDT zero the buffer
00261     memset(buf, 0x00, MAX_CMD_LEN);
00262     
00263     while(!done)
00264     {
00265       sel_rc = SWAIT_SYS_ERR;
00266 
00267     if(bytes_read >= (MAX_CMD_LEN - 1))
00268     {
00269         flog_usr(FLOG_ERROR, FL_ERR_BUF_NOSPACE, me,
00270              "Max cmd length %d exceeded with no delimiter",
00271              MAX_CMD_LEN);
00272         done = true;
00273         got_err = true;
00274         break;
00275     }
00276 
00277     // Wait for data available
00278     sel_rc = tcp_socket_wait(socket, timeout);
00279     if(sel_rc == SWAIT_TIMEOUT)
00280     {
00281         flog_usr(FLOG_L3BUG, 0, me, "No data before timeout");
00282         done = true;
00283         break;
00284     }
00285     if(sel_rc != SWAIT_GOT_DATA)
00286     {
00287         flog_usr(FLOG_ERROR, FL_ERR_SOCKET, me, "Error waiting for data");
00288         done = true;
00289         got_err = true;
00290         break;
00291     }
00292     
00293     // read a byte at a time, Bottlenecks Anonymous
00294     rc = read(socket, write_ptr, 1);
00295     if(rc == 1)
00296     {
00297         // got a byte
00298         if((*write_ptr == '\n') || (*write_ptr == '\r'))
00299         {
00300         // Strip leading newlines, in case get cr/lf combo
00301         if(bytes_read == 0)
00302         {
00303             // Discard the data by leaving write ptr in same place
00304             continue;
00305         }
00306             
00307         got_newline = true;
00308         done = true;
00309         
00310         // Terminate the string, overwrites newline
00311         *write_ptr = 0x00;
00312         
00313         break;
00314         }
00315         else // No newline
00316         {
00317         write_ptr++;
00318         bytes_read++;
00319         }
00320         
00321     }
00322     else if(rc <= 0) // Error on read?
00323     {
00324         done = true;
00325         got_err = true;
00326         break;
00327     }
00328     else // should never occur, but just in case
00329         usleep(10);
00330     }
00331 
00332     // DDT
00333     //    printf("\nnl_read bytes: %d newline: %d", bytes_read, got_newline);
00334     
00335     if(got_newline)
00336     return(bytes_read);
00337     else if(got_err == false)
00338     return(0);
00339     else
00340       return(-1);
00341 }
00342 
00343     
00359 int tcp_connect(const char *server, const uint16_t port)
00360 {
00361     char               me[] = "tcp_connect";
00362     struct hostent     *phe;    /* pointer to host information entry    */
00363     struct protoent    *ppe;    /* pointer to protocol information entry*/
00364     struct sockaddr_in sin;     /* an Internet endpoint address         */
00365     int                s, type; /* socket descriptor and socket type    */
00366     struct linger      so_linger;
00367     int                itmp;
00368     
00369     // Zero struct
00370     memset(&sin, 0x00, sizeof(sin));
00371 
00372     // Address family is INET
00373     sin.sin_family = AF_INET;
00374 
00375     /* Map service name to port number, ensuring network byte order */
00376     sin.sin_port = htons(port);
00377 
00378     /* Map host name to IP address, allowing for dotted decimal */
00379     phe = gethostbyname(server);
00380 
00381     if(phe != NULL)
00382         memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
00383     else
00384     {
00385     flog_usr(FLOG_ERROR, FL_ERR_HOST_NOTFOUND, me,
00386          "Connection error in gethostbyname");
00387         return(-1);
00388     }
00389 
00390     /* Map protocol name to protocol number */
00391     if ( (ppe = getprotobyname("tcp")) == 0)
00392     {
00393     flog_usr(FLOG_ERROR, FL_ERR_SYSTEM, me, 
00394          "Connection error in getprotobyname");
00395         return(-2);
00396     }
00397 
00398     type = SOCK_STREAM;
00399 
00400     /* Allocate a socket */
00401     s = socket(PF_INET, type, ppe->p_proto);
00402     if (s < 0)
00403     {
00404     flog_usr(FLOG_ERROR, FL_ERR_SYSTEM, me, "Error allocating socket");
00405         return(-3);
00406     }
00407 
00408     // Set linger to true so that close waits for flush, new 6/24/01 pfh
00409     so_linger.l_onoff = true;
00410     so_linger.l_linger = 5;    // 5 second timeout on close(2)
00411     itmp = setsockopt(s, SOL_SOCKET, SO_LINGER,
00412               &so_linger, sizeof(so_linger));
00413     if(itmp != 0)
00414     flog_usr(FLOG_WARNING, FL_ERR_SOCKET, me, 
00415          "Error setting socket opts");
00416     
00417     /* Connect the socket */
00418     if(connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
00419         return(-1);
00420    
00421     return s;
00422 }
00423 
00424 // ------------------------------------------------------------------------------
00437 socket_wait_ret tcp_socket_wait(const int socket, const time_t timeout)
00438 {
00439     char            me[] = "tcp_socket_wait";
00440     fd_set          read_fds;
00441     fd_set          err_fds;
00442     struct timeval  *sel_timeout = NULL;
00443     int             num_fds;
00444     int             sel_return;
00445     struct timeval  foo;
00446 
00447 
00448     // Do we have to worry about timeouts?
00449     if(timeout > 0)
00450     {
00451     sel_timeout = (struct timeval *) &foo;
00452 
00453     sel_timeout->tv_sec = timeout;
00454     sel_timeout->tv_usec = 0L;
00455     }
00456     else
00457     sel_timeout = NULL;
00458     
00459     // Clear all bits in read and error bitmaps
00460     FD_ZERO(&read_fds);
00461     FD_ZERO(&err_fds);
00462 
00463     // Flag socket descriptor as active in both
00464     FD_SET(socket, &read_fds);
00465     FD_SET(socket, &err_fds);
00466 
00467     // Ask system how many file descriptors we have to track
00468     num_fds = getdtablesize();
00469 
00470     // Call select, note that this is _only_ for reading!
00471     sel_return = select(num_fds, &read_fds,
00472             NULL, &err_fds, sel_timeout);
00473 
00474     // See if we got a readable socket or an error
00475     if(FD_ISSET(socket, &err_fds))
00476     {
00477     flog_usr(FLOG_INFO, FL_ERR_SOCKET, me, 
00478          "Error bit set in select");
00479     return(SWAIT_SYS_ERR);
00480     }
00481 
00482     // Figure out return code
00483     if((sel_return > 0) && (FD_ISSET(socket, &read_fds)))
00484     return(SWAIT_GOT_DATA);
00485 
00486     if(sel_return == -1)
00487     {
00488     flog_usr(FLOG_INFO, FL_ERR_SOCKET, me, "select returns -1");
00489     return(SWAIT_SYS_ERR);
00490     }
00491 
00492     if(sel_return == 0)
00493     return(SWAIT_TIMEOUT);
00494 
00495     // Catch-all; should be unreachable
00496     flog_usr(FLOG_L3BUG, 0, me,
00497          "Select returned %d, errno=%d", sel_return, errno);
00498     return(SWAIT_SYS_ERR);
00499 }
00500 
00501 // ---------------------------------------------------------------------
00510 char * tcp_peername(const int socket)
00511 {
00512     char               me[] = "tcp_peername";
00513     int                itmp, rc;
00514     struct sockaddr    client_info;
00515     struct sockaddr_in *so = (struct sockaddr_in *) &client_info;
00516     struct hostent     *cl_hostent = NULL;
00517     static char        remote_hostname[128] = "";
00518     
00519 
00520     // Check who connected
00521     itmp = sizeof(struct sockaddr);
00522     rc = getpeername(socket, &client_info, &itmp);
00523     if((rc != 0) || (itmp < 0))
00524     {
00525     flog_usr(FLOG_ERROR, FL_ERR_HOST_NOTFOUND, me,
00526          "Error getting peer information");
00527     return(remote_hostname);
00528     }
00529 
00530     // Do reverse DNS lookup
00531     cl_hostent = gethostbyaddr((char *) &so->sin_addr.s_addr,
00532                    sizeof(so->sin_addr.s_addr), AF_INET);
00533     if(cl_hostent == NULL)
00534     {
00535     flog_usr(FLOG_ERROR, FL_ERR_HOST_NOTFOUND, me,
00536          "Reverse DNS lookup failed");
00537     strcpy(remote_hostname, inet_ntoa(so->sin_addr));
00538     }
00539     else
00540     strcpy(remote_hostname, cl_hostent->h_name);
00541     
00542     return(remote_hostname);
00543 }
00544 
00545     
00546 
00547 // ---------------------------------------------------------------------
00562 int tcp_connect_retry(const char *host, const uint16_t port,
00563               const time_t retry_delay, const time_t end_time,
00564               const char *description)
00565 {
00566     char      me[] = "tcp_connect_retry";
00567     bool      done = false;
00568     int       retry_count = 0;
00569     int       cl_socket = -1;
00570     const char      *desc = NULL;
00571     
00572 
00573     // Use description if provided
00574     if(description != NULL)
00575     desc = description;
00576     else
00577     desc = host;
00578     
00579     while((done == false) && !(control_break))
00580     {
00581     // If end time is valid (>0), check
00582     if((end_time > 0) && (time(NULL) >= end_time))
00583     {
00584         flog_usr(FLOG_L3BUG, 0, me,
00585              "End time reached without connection, exiting");
00586         
00587         done = true;
00588         break;
00589     }
00590 
00591     flog_usr(FLOG_L2BUG, 0, me, 
00592          "Connecting to %s on %s, port %d", desc, host, port);
00593     
00594     cl_socket = tcp_connect(host, port);
00595     if(cl_socket > 0)
00596     {
00597         done = true;
00598         break;
00599     }
00600     
00601     flog_usr(FLOG_CL2BUG, 0, me,
00602          "Unable to connect to %s on %s, sleeping %d seconds",
00603          desc, host, (int) retry_delay);
00604     
00605     retry_count++;
00606     sleep(retry_delay);
00607     }
00608     
00609     return(cl_socket);
00610 }
00611 
00612 // ---------------------------------------------------------------------
00620 void tcp_close(const int socket_fd)
00621 {
00622     if(socket_fd <= 0)
00623     return;
00624     
00625     //Assume valid FD
00626     shutdown(socket_fd, SHUT_RDWR);
00627     close(socket_fd);
00628     
00629     return;
00630 }

Generated on Fri Dec 6 14:33:16 2002 for NSDS Driver by doxygen1.2.18