Links Powered by MicMac
Cocoa-C-Porting
Fink's translation team
Mac OSX, Fink and Unix
Client/Server Architecture
PowerPC Architecture - UML
System programming
Merise
Pierre-Loïc and Pascaline's wedding

Functions Source Code

Last modified: 22/04/2004 05:21:41 CEST
Author: Michèle Garoche contact

Contents - Overview - Diagrams - Client documentation - Server documentation - Functions documentation - Headers documentation - Client source code - Server source code - Functions source code - Headers source code -

wrapsock.c

Go to the documentation of this file.


00001 /* wrapsock.c */
00002 /* Functions wrapper module */
00003 /* To be used with tcpcli.c and tcpserv.c
00004 /* Author: Michèle Garoche */
00005 /* Date: February 26th 2003
00006 /* Feel free to do what you want with it */
00007 
00012 /* Includes */
00013 #include "wrapsock.h"
00014 
00018 /* Global variables */
00019 int daemon_proc;                /* set to nonzero by daemon_init() */
00020 
00021 /* Static functions */
00022 
00030 /* Main function to handle error */
00031 static void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
00032 {
00033         int errno_save; /* for storing the errno before printing it */
00034         int n; /* length of the message to print */
00035         char buf[MAXLINE + 1]; /* buffer for printing */
00036 
00037         /* Save the error number */
00038         errno_save = errno;
00039         /* write the message into buf */
00040         vsnprintf(buf, MAXLINE, fmt, ap);
00041         /* Retrieve the length of buf */
00042         n = strlen(buf);
00043 
00044         /* There was an error
00045                 Write the message + the error number to buf */
00046         if (errnoflag)
00047         {
00048                 snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
00049         }
00050 
00051         /* Append a new line character to buf */
00052         strcat(buf, "\n");
00053 
00054         /* If the process was launched as a daemon, write the message
00055                 to the console with level LOG_ERR */
00056         if (daemon_proc)
00057         {
00058                 syslog(level, "%s", buf);
00059         }
00060         /* The process was launched as normal process */
00061         else
00062         {
00063                 /* Empty the std out */
00064                 fflush(stdout);
00065                 /* Write the message to stderr */
00066                 fputs(buf, stderr);
00067                 /* Empty stderr */
00068                 fflush(stderr);
00069         }
00070 
00071         return;
00072 }
00073 
00080 /* Handle the errors when reading a stream */
00081 static ssize_t mg_read(int fd, char *ptr)
00082 {
00083         static int read_cnt = 0;
00084         static char *read_ptr;
00085         static char read_buf[MAXLINE];
00086 
00087         if (read_cnt <= 0)
00088         {
00089 again:
00090                 if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)
00091                 {
00092                         if (errno == EINTR)
00093                         {
00094                                 goto again;
00095                         }
00096                         return -1;
00097                 }
00098                 else if (read_cnt == 0)
00099                 {
00100                         return 0;
00101                 }
00102                 
00103                 read_ptr = read_buf;
00104         }
00105 
00106         read_cnt--;
00107         *ptr = *read_ptr++;
00108         return 1;
00109 }
00110 
00111 /* Other functions */
00112 
00117 /* Display an help message and quit */
00118 void cliusage(char *progname)
00119 {
00120         err_quit("\nusage: %s\n"
00121                   "   -a        manage all type of requests\n"
00122                   "   -b        compute numbers requests\n"
00123                   "   -c        convert word from uppercase to lowercase requests\n"
00124                   "   -h        this help\n\n"
00125                   "       address\n\n"
00126                   "You can launch as many clients as your system supports with\n"
00127                   "with different types of request.\n\n"
00128                   "To terminate a client, just issue:\n"
00129                   "   ctrl-D\n"
00130                   "in the corresponding terminal.\n\n"
00131                   "To erase an entry before sending it, type:\n"
00132                   "   ctrl-U\n"
00133                   "in the terminal (useful when the buffer is full).\n\n", progname);
00134 }
00135 
00142 /* Check the validity of address */
00143 void Inet_pton(int family, const char *strptr, void *addrptr)
00144 {
00145         int n; /* value returned by inet_pton */
00146 
00147         /* Some system error occurs */
00148         if ( (n = inet_pton(family, strptr, addrptr)) < 0)
00149         {
00150                 err_sys("inet_pton error for %s", strptr);
00151         }
00152         /* The address is not parseable in the specified address family */
00153         else if (n == 0)
00154         {
00155                 err_quit("inet_pton error for %s", strptr);
00156         }
00157 }
00158 
00165 /* Connect the client to the listening socket */
00166 void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
00167 {
00168         if (connect(fd, sa, salen) < 0)
00169         {
00170                 err_sys("connect error");
00171         }
00172 }
00173 
00179 void str_cli(FILE *fp, int sockfd)
00180 {
00181         int maxfdp1; /* maximum of file descriptors */
00182         int stdineof; /* flag for EOF on stdin */
00183         fd_set rset; /* the set of descriptors */
00184         char sendline[MAXLINE]; /* buffer for sending */
00185         char recvline[MAXLINE]; /* buffer for receiving */
00186 
00187         /* NO EOF */
00188         stdineof = 0;
00189         /* Clear all bits on the set of fd */
00190         FD_ZERO(&rset);
00191 
00192         for ( ; ; )
00193         {
00194                 if (stdineof == 0)
00195                 {
00196                         /*Turn on the bit for stdio */
00197                         FD_SET(fileno(fp), &rset);
00198                 }
00199                 /* Turn on the bit for sockfd */
00200                 FD_SET(sockfd, &rset);
00201                 /* Compute the max of the two descriptors
00202                 + 1 as the descriptor begins with 0 */
00203                 maxfdp1 = MGMAX(fileno(fp), sockfd) + 1;
00204                 /* Call select with the set and no timeout
00205                         so that it blocks until a descriptor
00206                         in the set is ready */
00207                 Select(maxfdp1, &rset, NULL, NULL, NULL);
00208 
00209                 /* The socket is ready */
00210                 if (FD_ISSET(sockfd, &rset))
00211                 {
00212                         /* Read the line */
00213                         if (Readline(sockfd, recvline, MAXLINE) == 0)
00214                         {
00215                                 /* No data to read */
00216                                 if (stdineof == 1)
00217                                 {
00218                                         return;
00219                                 }
00220                                 /* The server has terminated */
00221                                 else
00222                                 {
00223                                         /* Attention: this leaves the server refused to bind */
00224                                         /* when relaunching it till it receives ETIMEOUT */
00225                                         /* < 1 mn on Mac OS 10.2.4 */
00228                                         err_quit("str_cli: server terminated prematurely");
00229                                 }
00230                         }
00231 
00232                         /* Write it to stdout */
00233                         Fputs(recvline, stdout);
00234                 }
00235 
00236                 /* Stdin is ready */
00237                 if (FD_ISSET(fileno(fp), &rset))
00238                 {
00239                         /* Read the line */
00240                         if (Fgets(sendline, MAXLINE, fp) == NULL)
00241                         {
00242                                 /* No more date to read */
00243                                 stdineof = 1;
00244                                 /* Half close the socket */
00245                                 Shutdown(sockfd, SHUT_WR);
00246                                 /* Clear the set */
00247                                 FD_CLR(fileno(fp), &rset);
00248                                 continue;
00249                         }
00250 
00251                         /* Write it to the socket */
00252                         Writen(sockfd, sendline, strlen(sendline));
00253                 }
00254         }
00255 }
00256 
00257 
00262 /* Display an help message and quit */
00263 void servusage(char *progname)
00264 {
00265         err_quit("\nusage: %s\n"
00266                   "   -a        manage all type of requests\n"
00267                   "   -b        compute numbers requests\n"
00268                   "   -c        convert word from uppercase to lowercase requests\n"
00269                   "   -h        this help\n\n"
00270                   "You can launch the server in the background like this:\n"
00271                   "   %s -a &\n"
00272                   "Then you have to type return before launching any client.\n"
00273                   "When finishing with the server, you will have to kill the server like this:\n"
00274                   "   kill - 9 %d\n\n"
00275                   "Or launch the server in the foreground like this:\n"
00276                   "   %s -a\n"
00277                   "Then open a new terminal to launch client.\n", progname, progname, (int)getpid(), progname);
00278 }
00279 
00286 /* Bind the socket */
00287 void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
00288 {
00289         if (bind(fd, sa, salen) < 0)
00290         {
00291                 err_sys("bind error");
00292         }
00293 }
00294 
00300 /* Listen for connection on the listening socket */
00301 void Listen(int fd, int backlog)
00302 {
00303         if (listen(fd, backlog) < 0)
00304         {
00305                 err_sys("listen error");
00306         }
00307 }
00308 
00314 /* Function to call to catch a SIGCHLD */
00315 Sigfunc *Signal(int signo, Sigfunc *func)
00316 {
00317         Sigfunc *sigfunc; /* function to call when the signal raises */
00318 
00319         if ( (sigfunc = mg_signal(signo, func)) == SIG_ERR)
00320         {
00321                 err_sys("signal error");
00322         }
00323 
00324         return sigfunc;
00325 }
00326 
00331 /* Fork a child process */
00332 pid_t Fork(void)
00333 {
00334         pid_t   pid;
00335 
00336         if ( (pid = fork()) == -1)
00337         {
00338                 err_sys("fork error");
00339         }
00340 
00341         return pid;
00342 }
00343 
00348 /* Close the socket */
00349 void Close(int fd)
00350 {
00351         if (close(fd) == -1)
00352         {
00353                 err_sys("close error");
00354         }
00355 }
00356 
00361 /* Handle all requests */
00362 void str_serv1(int sockfd)
00363 {
00364         int arg1; /* first numeric argument */
00365         int arg2; /* second numeric argument */
00366         int i; /* counter for reading a word */
00367         char result2[MAXLINE]; /* intermediate buffer */
00368         int result; /* numeric result */
00369         ssize_t n; /* length of the line */
00370         char line[MAXLINE]; /* buffer for the line */
00371 
00372         for ( ; ; )
00373         {
00374                 /* Discard any data if the client has terminated */
00375                 if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
00376                 {
00377                         return;         /* connection closed by other end */
00378                 }
00379 
00380                 /* There are two numeric arguments */
00381                 if (sscanf(line, "%d%d", &arg1, &arg2) == 2)
00382                 {
00383                         /* Compute x pow 2 + y pow 2 */
00384                         result = (int)(pow((float)arg1, 2.) + pow((float)arg2, 2.));
00385 
00386                         /* Send an overflow message if the result is greater than an int */
00387                         if ((result == INT_MAX) || (result == INT_MIN))
00388                         {
00389                                 strcpy(result2, "Overflow");
00390                                 snprintf(line, sizeof(line), "%s\n", result2);
00391                         }
00392                         /* write the result into line */
00393                         else
00394                         {
00395                                 snprintf(line, sizeof(line), "%d\n", result);
00396                         }
00397                 }
00398                 /* There is one numeric argument */
00399                 else if (sscanf(line, "%d", &arg1) == 1)
00400                 {
00401                         /* Compute x pow 3 */
00402                         result = (int)pow((float)arg1, 3.);
00403 
00404                         /* Send an overflow message if the result is greater than an int */
00405                         if ((result == INT_MAX) || (result == INT_MIN))
00406                         {
00407                                 strcpy(result2, "Overflow");
00408                                 snprintf(line, sizeof(line), "%s\n", result2);
00409                         }
00410                         /* write the result into line */
00411                         else
00412                         {
00413                                 snprintf(line, sizeof(line), "%d\n", result);
00414                         }
00415                 }
00416                 /* There is a word */
00417                 else if (sscanf(line, "%s", result2) == 1)
00418                 {
00419                         for (i = 0; i < MAXLINE; i++)
00420                         {
00421                                 /* Attempt to convert the accentuated characters in uppercase */
00422                                 if ( ((unsigned char)result2[i] >= 192) && ((unsigned char)result2[i] <= 223) )
00423                                 {
00424                                         result2[i] = (unsigned char)result2[i] + 32;
00425                                 }
00426                                 /* Convert the word to uppercase */
00427                                 else
00428                                 {
00429                                         result2[i] = (isupper ((unsigned char)result2[i])? tolower ((unsigned char)result2[i]) : result2[i]);
00430                                 }
00431                         }
00432 
00433                         /* Write the converted word to line */
00434                         snprintf(line, sizeof(line), "%s\n", result2);
00435                 }
00436 
00437                 /* Get the length of line */
00438                 n = strlen(line);
00439                 /* Write line to socket */
00440                 Writen(sockfd, line, n);
00441         }
00442 }
00443 
00448 /* Handle numeric requests */
00449 void str_serv2(int sockfd)
00450 {
00451         /* Idem str_serv1 */
00452         int arg1, arg2, i;
00453         int result;
00454         char result2[MAXLINE];
00455         int digitflag = 0; /* flag for digits */
00456         ssize_t n;
00457         char line[MAXLINE];
00458 
00459         for ( ; ; )
00460         {
00461                 if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
00462                 {
00463                         return;         /* connection closed by other end */
00464                 }
00465 
00466                 if (sscanf(line, "%d%d", &arg1, &arg2) == 2)
00467                 {
00468                         result = (int)(pow((float)arg1, 2.) + pow((float)arg2, 2.));
00469 
00470                         if ((result == INT_MAX) || (result == INT_MIN))
00471                         {
00472                                 strcpy(result2, "Overflow");
00473                                 snprintf(line, sizeof(line), "%s\n", result2);
00474                         }
00475                         else
00476                         {
00477                                 snprintf(line, sizeof(line), "%d\n", result);
00478                         }
00479                 }
00480                 else if (sscanf(line, "%d", &arg1) == 1)
00481                 {
00482                         result = (int)pow((float)arg1, 3.);
00483 
00484                         if ((result == INT_MAX) || (result == INT_MIN))
00485                         {
00486                                 strcpy(result2, "Overflow");
00487                                 snprintf(line, sizeof(line), "%s\n", result2);
00488                         }
00489                         else
00490                         {
00491                                 snprintf(line, sizeof(line), "%d\n", result);
00492                         }
00493                 }
00494                 else if (sscanf(line, "%s", result2) == 1)
00495                 {
00496                         /* Set the flag for digits */
00497                         digitflag = 0;
00498 
00499                         for (i = 0; i < MAXLINE; i++)
00500                         {
00501                                 /* There is a non digit character */
00502                                 if ( isdigit((unsigned char)result2[i]) == 0)
00503                                 {
00504                                         digitflag +=1;
00505                                 }
00506                         }
00507 
00508                         /* Write a message to line */
00509                         if (digitflag > 0)
00510                         {
00511                                 strcpy(result2, "This server only deals with numbers.");
00512                                 snprintf(line, sizeof(line), "%s\n", result2);
00513                         }
00514                 }
00515 
00516                 n = strlen(line);
00517                 Writen(sockfd, line, n);
00518         }
00519 }
00520 
00525 /* Handle word requests */
00526 void str_serv3(int sockfd)
00527 {
00528         /* Idem str_serv1 */
00529         int arg1, i;
00530         char result2[MAXLINE];
00531         ssize_t n;
00532         char line[MAXLINE];
00533 
00534         for ( ; ; )
00535         {
00536                 if ( (n = Readline(sockfd, line, MAXLINE)) == 0)
00537                 {
00538                         return;         /* connection closed by other end */
00539                 }
00540 
00541                 /* There is one digit */
00542                 if (sscanf(line, "%d", &arg1) == 1)
00543                 {
00544                         /* Write a message to result 2 */
00545                         strcpy(result2, "This server only deals with words.");
00546                 }
00547                 else if (sscanf(line, "%s", result2) == 1)
00548                 {
00549                         for (i = 0; i < MAXLINE; i++)
00550                         {
00551                                 if ( ((unsigned char)result2[i] >= 192) && ((unsigned char)result2[i] <= 223) )
00552                                 {
00553                                         result2[i] = (unsigned char)result2[i] + 32;
00554                                 }
00555                                 else
00556                                 {
00557                                         result2[i] = (isupper ((unsigned char)result2[i])? tolower ((unsigned char)result2[i]) : result2[i]);
00558                                 }
00559                         }
00560 
00561                         snprintf(line, sizeof(line), "%s\n", result2);
00562                 }
00563 
00564                 n = strlen(line);
00565                 Writen(sockfd, line, n);
00566         }
00567 }
00568 
00576 /* Create a socket */
00577 int Socket(int family, int type, int protocol)
00578 {
00579         int n; /* the socket to return */
00580 
00581         if ( (n = socket(family, type, protocol)) < 0)
00582         {
00583                 err_sys("socket error");
00584         }
00585 
00586         return n;
00587 }
00588 
00596 /* Wrapper for fgets */
00597 char * Fgets(char *ptr, int n, FILE *stream)
00598 {
00599         char *rptr;
00600 
00601         if ( (rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
00602         {
00603                 err_sys("fgets error");
00604         }
00605 
00606         return rptr;
00607 }
00608 
00616 /* Read a string character after character from a stream */
00617 ssize_t mg_readline(int fd, void *vptr, size_t maxlen)
00618 {
00619         int n, rc;
00620         char c, *ptr;
00621 
00622         ptr = vptr;
00623         for (n = 1; n < maxlen; n++)
00624         {
00625                 if ( (rc = mg_read(fd, &c)) == 1)
00626                 {
00627                         *ptr++ = c;
00628 
00629                         if (c == '\n')
00630                         {
00631                                 break;  /* newline is stored, like fgets() */
00632                         }
00633                 }
00634                 else if (rc == 0)
00635                 {
00636                         if (n == 1)
00637                         {
00638                                 return 0;      /* EOF, no data read */
00639                         }
00640                         else
00641                         {
00642                                 break;          /* EOF, some data was read */
00643                         }
00644                 }
00645                 else
00646                 {
00647                         return -1;             /* error, errno set by read() */
00648                 }
00649         }
00650 
00651         *ptr = 0;       /* null terminate like fgets() */
00652         return n; /* return the number of bytes read */
00653 }
00654 
00662 /* Wrapper for mg_readline */
00663 ssize_t Readline(int fd, void *ptr, size_t maxlen)
00664 {
00665         ssize_t n;
00666 
00667         if ( (n = mg_readline(fd, ptr, maxlen)) < 0)
00668         {
00669                 err_sys("mg_readline error");
00670         }
00671 
00672         return n;
00673 }
00674 
00680 /* Wrapper for fputs */
00681 void Fputs(const char *ptr, FILE *stream)
00682 {
00683         if (fputs(ptr, stream) == EOF)
00684         {
00685                 err_sys("fputs error");
00686         }
00687 }
00688 
00696 /* Write a string character after character to a stream */
00697 ssize_t writen(int fd, const void *vptr, size_t n)
00698 {
00699         size_t nleft;
00700         ssize_t nwritten;
00701         const char *ptr;
00702 
00703         ptr = vptr;
00704         nleft = n;
00705         while (nleft > 0)
00706         {
00707                 if ( (nwritten = write(fd, ptr, nleft)) <= 0)
00708                 {
00709                         if (errno == EINTR)
00710                         {
00711                                 nwritten = 0; /* and call write() again */
00712                         }
00713                         else
00714                         {
00715                                 return -1; /* error */
00716                         }
00717                 }
00718                 
00719                 nleft -= nwritten;
00720                 ptr   += nwritten;
00721         }
00722         
00723         return n; /* the number of bytes written */
00724 }
00725 
00732 /* Wrapper for writen */
00733 void Writen(int fd, void *ptr, size_t nbytes)
00734 {
00735         if (writen(fd, ptr, nbytes) != nbytes)
00736         {
00737                 err_sys("writen error");
00738         }
00739 }
00740 
00750 /* Wait for read and write descriptors ready */
00751 int Select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
00752 {
00753         int n;
00754 
00755         if ( (n = select(nfds, readfds, writefds, exceptfds, timeout)) < 0)
00756         {
00757                 err_sys("select error");
00758         }
00759 
00760         return n;              /* can return 0 on timeout */
00761 }
00762 
00768 /* Initiate a normal termination sequence */
00769 void Shutdown(int fd, int how)
00770 {
00771         /* Make a half-close on write end */
00772         if (shutdown(fd, how) < 0)
00773         {
00774                 err_sys("shutdown error");
00775         }
00776 }
00777 
00782 /* Action to take when child terminates */
00783 void sig_chld(int signo)
00784 {
00785   pid_t pid;
00786   int stat;
00787 
00788   /* Wait for the child to terminate */
00789   while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
00790         {
00791           printf("child %d terminated\n", pid);
00792         }
00793         
00794   return;
00795 }
00796 
00803 /* Handle signals */
00804 Sigfunc * mg_signal(int signo, Sigfunc *func)
00805 {
00806         struct sigaction act, oact;
00807 
00808         /* Set handler to func */
00809         act.sa_handler = func;
00810         /* No other signal is blocked */
00811         sigemptyset(&act.sa_mask);
00812         /* Clean up options */
00813         act.sa_flags = 0;
00814         
00815         /* If signal if SIGALARM, allow the kernel to restart it */
00816         if (signo == SIGALRM)
00817         {
00818                 act.sa_flags |= SA_RESTART;
00819         }
00820         
00821         /* Call sigaction */
00822         if (sigaction(signo, &act, &oact) < 0)
00823         {
00824                 return SIG_ERR;
00825         }
00826 
00827         return oact.sa_handler;
00828 }
00829 
00834 /* Handle errors generated by the system */
00835 void err_sys(const char *fmt, ...)
00836 {
00837         /* Use the variable-length argument list facility */
00838         va_list         ap;
00839 
00840         va_start(ap, fmt);
00841         /* Write an error message to stderr or to console and quit */
00842         err_doit(1, LOG_ERR, fmt, ap);
00843         va_end(ap);
00844         
00845         exit(EXIT_FAILURE);
00846 }
00847 
00852 /* Handle errors not generated by the system,
00853 i.e. there was no errno generated by the caller */
00854 void err_quit(const char *fmt, ...)
00855 {
00856         /* Use the variable-length argument list facility */
00857         va_list         ap;
00858 
00859         va_start(ap, fmt);
00860         /* Write an error message to stderr or to console and quit */
00861         err_doit(0, LOG_ERR, fmt, ap);
00862         va_end(ap);
00863 
00864         exit(EXIT_FAILURE);
00865 }

Generated on Sat Mar 1 04:09:03 2003 for tcpcliserv by doxygen


Contents - Overview - Diagrams - Client documentation - Server documentation - Functions documentation - Headers documentation - Client source code - Server source code - Functions source code - Headers source code -

Powered by Apache/1.3.41 (Darwin) PHP/4.4.8 on Mac OS X bluefish distributed.net Cssed icon Conglomerate icon Valid HTML 4.0.1 Valid CSS
Local date (dd/mm/yyyy): 29/08/2008 06:01:18 CEST