©2004 by Marc J. Rochkind. All rights reserved. Portions marked "Open Source" may be copied under license.

 

Main Page   Modules   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

c8/ssi.c

Go to the documentation of this file.
00001 /*
00002     Simple Socket Interface
00003     AUP2, Sec. 8.04.5
00004 
00005     Copyright 2003 by Marc J. Rochkind. All rights reserved.
00006     May be copied only for purposes and under conditions described
00007     on the Web page www.basepath.com/aup/copyright.htm.
00008 
00009     The Example Files are provided "as is," without any warranty;
00010     without even the implied warranty of merchantability or fitness
00011     for a particular purpose. The author and his publisher are not
00012     responsible for any damages, direct or incidental, resulting
00013     from the use or non-use of these Example Files.
00014 
00015     The Example Files may contain defects, and some contain deliberate
00016     coding mistakes that were included for educational reasons.
00017     You are responsible for determining if and how the Example Files
00018     are to be used.
00019 
00020 */
00021 #ifdef DARWIN
00022 /* Following needed to get socklen_t defined. */
00023 #define _BSD_SOCKLEN_T_ int
00024 #endif /* DARWIN */
00025 #include "defs.h"
00026 #include "ssi.h"
00027 #ifdef SOLARIS
00028 #define __EXTENSIONS__
00029 #endif
00030 #include <netdb.h>
00031 #undef __EXTENSIONS__
00032 #include <sys/un.h>
00033 #include <netinet/in.h>
00034 #include <arpa/inet.h>
00035 /*[set_fd_hwm]*/
00036 static void set_fd_hwm(SSI *ssip, int fd)
00037 {
00038     if (fd > ssip->ssi_fd_hwm)
00039         ssip->ssi_fd_hwm = fd;
00040 }
00041 
00042 static void reset_fd_hwm(SSI *ssip, int fd)
00043 {
00044     if (fd == ssip->ssi_fd_hwm)
00045         ssip->ssi_fd_hwm--;
00046 }
00047 /*[make_sockaddr]*/
00048 bool make_sockaddr(struct sockaddr *sa, socklen_t *len, const char *name,
00049   int domain, bool will_bind)
00050 {
00051     struct addrinfo *infop = NULL;
00052 
00053     if (domain == AF_UNIX) {
00054         struct sockaddr_un *sunp = (struct sockaddr_un *)sa;
00055 
00056         if (strlen(name) >= sizeof(sunp->sun_path)) {
00057             errno = ENAMETOOLONG;
00058             EC_FAIL
00059         }
00060         strcpy(sunp->sun_path, name);
00061         sunp->sun_family = AF_UNIX;
00062         *len = sizeof(*sunp);
00063     }
00064     else {
00065         struct addrinfo hint;
00066         char nodename[SSI_NAME_SIZE], *servicename;
00067 
00068         memset(&hint, 0, sizeof(hint));
00069         hint.ai_family = domain;
00070         hint.ai_socktype = SOCK_STREAM;
00071         if (will_bind)
00072             hint.ai_flags = AI_PASSIVE;
00073         strcpy(nodename, name);
00074         servicename = strchr(nodename, ':');
00075         if (servicename == NULL) {
00076             errno = EINVAL;
00077             EC_FAIL
00078         }
00079         *servicename = '\0';
00080         servicename++;
00081         ec_ai( getaddrinfo(nodename, servicename, &hint, &infop) )
00082         memcpy(sa, infop->ai_addr, infop->ai_addrlen);
00083         *len = infop->ai_addrlen;
00084         freeaddrinfo(infop);
00085     }
00086     return true;
00087 
00088 EC_CLEANUP_BGN
00089     if (infop != NULL)
00090         freeaddrinfo(infop);
00091     return false;
00092 EC_CLEANUP_END
00093 }
00094 /*[]*/
00095 /*
00096     Name of the form "//host:port" uses AF_INET to access that host and port. Otherwise, AF_UNIX is used, and the name has no slashes, colon, or port. (E.g., "someservice".) Because numeric port numbers are used, there need be no entry in /etc/services. host can be a name with an entry in /etc/hosts (or via DNS), or it can be a numeric IP address (e.g., 192.168,0,1).
00097 */
00098 /*[ssi_open]*/
00099 SSI *ssi_open(const char *name_server, bool server)
00100 {
00101     SSI *ssip = NULL;
00102     struct sockaddr_storage sa;
00103     socklen_t sa_len;
00104 
00105     ec_null(  ssip = (SSI *)calloc(1, sizeof(SSI)) )
00106     ssip->ssi_server = server;
00107     if (strncmp(name_server, "//", 2) == 0) {
00108         ssip->ssi_domain = AF_INET;
00109         name_server += 2;
00110     }
00111     else {
00112         ssip->ssi_domain = AF_UNIX;
00113         if (ssip->ssi_server)
00114             (void)unlink(name_server);
00115     }
00116     if (strlen(name_server) >= sizeof(ssip->ssi_name_server)) {
00117         errno = ENAMETOOLONG;
00118         EC_FAIL
00119     }
00120     strcpy(ssip->ssi_name_server, name_server);
00121     ec_false( make_sockaddr((struct sockaddr *)&sa, &sa_len,
00122       ssip->ssi_name_server, ssip->ssi_domain, ssip->ssi_server) )
00123     ec_neg1(  ssip->ssi_fd = socket(ssip->ssi_domain, SOCK_STREAM, 0) )
00124     set_fd_hwm(ssip, ssip->ssi_fd);
00125     if (ssip->ssi_domain == AF_INET) {
00126         /*
00127             SO_REUSEADDR supposedly makes the connection less reliable,
00128             but it's too inconvenient to do development without it set.
00129         */
00130         int socket_option_value = 1;
00131 
00132         ec_neg1(  setsockopt(ssip->ssi_fd, SOL_SOCKET, SO_REUSEADDR,
00133           &socket_option_value, sizeof(socket_option_value)) )
00134     }
00135     if (ssip->ssi_server) {
00136         FD_ZERO(&ssip->ssi_fd_set);
00137         ec_neg1( bind(ssip->ssi_fd, (struct sockaddr *)&sa, sa_len) )
00138         ec_neg1( listen(ssip->ssi_fd, SOMAXCONN) )
00139         FD_SET(ssip->ssi_fd, &ssip->ssi_fd_set);
00140     }
00141     else
00142         ec_neg1( connect(ssip->ssi_fd, (struct sockaddr *)&sa, sa_len) )
00143     return ssip;
00144 
00145 EC_CLEANUP_BGN
00146     free(ssip);
00147     return NULL;
00148 EC_CLEANUP_END
00149 }
00150 /*[ssi_close]*/
00151 bool ssi_close(SSI *ssip)
00152 {
00153     if (ssip->ssi_server) {
00154         int fd;
00155 
00156         for (fd = 0; fd <= ssip->ssi_fd_hwm; fd++)
00157             if (FD_ISSET(fd, &ssip->ssi_fd_set))
00158                 (void)close(fd);
00159         if (ssip->ssi_domain == AF_UNIX)
00160             (void)unlink(ssip->ssi_name_server);
00161     }
00162     else
00163         (void)close(ssip->ssi_fd);
00164     free(ssip);
00165     return true;
00166 }
00167 /*[ssi_close_fd]*/
00168 bool ssi_close_fd(SSI *ssip, int fd)
00169 {
00170     ec_neg1( close(fd) );
00171     FD_CLR(fd, &ssip->ssi_fd_set);
00172     reset_fd_hwm(ssip, fd);
00173     return true;
00174 
00175 EC_CLEANUP_BGN
00176     return false;
00177 EC_CLEANUP_END
00178 }
00179 /*[ssi_wait_server]*/
00180 int ssi_wait_server(SSI *ssip)
00181 {
00182     if (ssip->ssi_server) {
00183         fd_set fd_set_read;
00184         int fd, clientfd;
00185         struct sockaddr_un from;
00186         socklen_t from_len = sizeof(from);
00187 
00188         while (true) {
00189             fd_set_read = ssip->ssi_fd_set;
00190             ec_neg1( select(ssip->ssi_fd_hwm + 1, &fd_set_read, NULL, NULL,
00191               NULL) )
00192             for (fd = 0; fd <= ssip->ssi_fd_hwm; fd++)
00193                 if (FD_ISSET(fd, &fd_set_read)) {
00194                     if (fd == ssip->ssi_fd) {
00195                         ec_neg1( clientfd = accept(ssip->ssi_fd,
00196                           (struct sockaddr *)&from, &from_len) );
00197                         FD_SET(clientfd, &ssip->ssi_fd_set);
00198                         set_fd_hwm(ssip, clientfd);
00199                         continue;
00200                     }
00201                     else
00202                         return fd;
00203                 }
00204         }
00205     }
00206     else {
00207         errno = ENOTSUP;
00208         EC_FAIL
00209     }
00210 
00211 EC_CLEANUP_BGN
00212     return -1;
00213 EC_CLEANUP_END
00214 }
00215 /*[ssi_get_server_fd]*/
00216 int ssi_get_server_fd(SSI *ssip)
00217 {
00218     return ssip->ssi_fd;
00219 }
00220 /*[]*/
00221 #if 0
00222 bool ssi_send(SSI *ssip, void *buf, size_t bufsize)
00223 {
00224     if (ssip->ssi_server) {
00225         ec_neg1( sendto(ssip->ssi_fd_client, buf, bufsize, 0,
00226           (struct sockaddr *)&ssip->ssi_sa, ssip->ssi_sa_len) )
00227     }
00228     else
00229         ec_neg1( send(ssip->ssi_fd, buf, bufsize, 0) )
00230     return true;
00231 
00232 EC_CLEANUP_BGN
00233     return false;
00234 EC_CLEANUP_END
00235 }
00236 
00237 bool ssi_receive(SSI *ssip, void *buf, size_t bufsize)
00238 {
00239     if (ssip->ssi_server) {
00240         ec_neg1( ssip->ssi_fd_client = ssi_wait_server(ssip) )
00241         ssip->ssi_sa_len = sizeof(ssip->ssi_sa);
00242 // check on short count... go back for more?
00243         ec_neg1( recvfrom(ssip->ssi_fd_client, buf, bufsize,
00244           0, (struct sockaddr *)&ssip->ssi_sa, &ssip->ssi_sa_len) )
00245     }
00246     else
00247         ec_neg1( recv(ssip->ssi_fd, buf, bufsize, 0) )
00248     return true;
00249 
00250 EC_CLEANUP_BGN
00251     return false;
00252 EC_CLEANUP_END
00253 }
00254 #endif

Generated on Fri Apr 23 10:57:02 2004 for AUP2 Example Source by doxygen 1.3.1