1    | /***************************************
2    |   $Revision: 1.3 $
3    | 
4    |   Example code: A socket module.
5    | 
6    |   Status: NOT REVUED, NOT TESTED
7    | 
8    |   +html+ <DL COMPACT>
9    |   +html+ <DT>Online References:
10   |   +html+ <DD><UL>
11   |   +html+   <LI>Adapted from <A HREF="http://www.ibrado.com/sock-faq/sfaq.html#faq65">sample source code</A>.
12   |   +html+ </UL>
13   |   +html+ </DL>
14   |   +html+ <PRE>
15   |   +html+ </PRE>
16   |  
17   |   ******************/ /******************
18   |   Modification History:
19   |         ottrey (08/03/1999) Created from sockhelp.c.
20   |         ottrey (08/03/1998) Heavily butchered.
21   |         joao   (22/06/1999) Modified socket creation and accepts.
22   |   ******************/ /******************
23   |  REMINDER: PUT THE PROPER COPYRIGHT NOTICE HERE
24   |   ***************************************/
25   | #include "socket.h"
26   | #include "constants.h"
27   | 
28   | 
29   | /*+ String sizes +*/
30   | #define STR_S   63
31   | #define STR_M   255
32   | #define STR_L   1023
33   | #define STR_XL  4095
34   | #define STR_XXL 16383
35   | 
36   | static void log_print(const char *arg) {
37   |   FILE *logf;
38   |   char *str;
39   | 
40   |   if (CO_get_socket_logging() == 1) {
41   |     if (strcmp(CO_get_socket_logfile(), "stdout") == 0) {
42   |       printf(arg);
43   |     }
44   |     else {
45   |       logf = fopen(CO_get_socket_logfile(), "a");
46   |       fprintf(logf, arg);
47   |       fclose(logf);
48   |     }
49   |   }
50   | 
51   | } /* log_print() */
52   |  
53   | /* SK_atoport() */
54   | /*++++++++++++++++++++++++++++++++++++++
55   |    Take a service name, and a service type, and return a port number.  If the
56   |    service name is not found, it tries it as a decimal number.  The number
57   |    returned is byte ordered for the network.
58   | 
59   |   char *service   Service name (or port number).
60   | 
61   |   char *proto     Protocol (eg "tcp").
62   | 
63   |   More:
64   |   +html+ <PRE>
65   |   Authors:
66   |         ottrey
67   | 
68   |   +html+ </PRE><DL COMPACT>
69   |   +html+ <DT>Online References:
70   |   +html+ <DD><UL>
71   |   +html+ </UL></DL>
72   | 
73   |   ++++++++++++++++++++++++++++++++++++++*/
74   | int SK_atoport(const char *service, const char *proto) {
75   |   int port;
76   |   long int lport;
77   |   struct servent *serv;
78   |   char *errpos;
79   | 
80   |   /* First try to read it from /etc/services */
81   |   serv = getservbyname(service, proto);
82   |   if (serv != NULL)
83   |     port = serv->s_port;
84   |   else { /* Not in services, maybe a number? */
85   |     lport = strtol(service,&errpos,0);
86   |     if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
87   |       return -1; /* Invalid port address */
88   |     port = htons(lport);
89   |   }
90   |   return port;
91   | } /* SK_atoport() */
92   | 
93   | 
94   | /* SK_close_listening_socket() */
95   | /*++++++++++++++++++++++++++++++++++++++
96   |   XXX Note: Not sure how long this function will last.  Shouldn't _really_ need it.
97   | 
98   |   More:
99   |   +html+ <PRE>
100  |   Authors:
101  |         ottrey
102  | 
103  |   +html+ </PRE><DL COMPACT>
104  |   +html+ <DT>Online References:
105  |   +html+ <DD><UL>
106  |   +html+ </UL></DL>
107  | 
108  |   ++++++++++++++++++++++++++++++++++++++*/
109  | /*void SK_close_listening_socket() {
110  |   close(listening_socket);         
111  | } */ /* SK_close_listening_socket */
112  | 
113  | static void func_atexit(void) {
114  |   printf("SK: func_atexit() called\n");
115  | }
116  | 
117  | static void func_sighup(int n) {
118  |   printf("SK: func_sighup(%d) called\n", n);
119  | }
120  | 
121  | static void func_sigint(int n) {
122  |   printf("SK: func_sigint(%d) called\n", n);
123  | }
124  | 
125  | 
126  | void SK_close(int socket) {
127  |   char print_buf[STR_M];
128  | 
129  |   sprintf(print_buf, "Closing socket... %d\n", socket); log_print(print_buf); strcpy(print_buf, "");
130  | 
131  |   close(socket);
132  | }
133  | 
134  | /* SK_getsock() */
135  | /*++++++++++++++++++++++++++++++++++++++
136  | 
137  |    This function creates a socket and binds to it
138  | 
139  |    int      SK_getsock       The new socket
140  | 
141  |    int      socket_type      SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
142  | 
143  |    u_short  port             The port to listen on.  Remember that ports < 1024 are
144  |                              reserved for the root user.  Must be passed in network byte
145  |                              order (see "man htons").
146  | 
147  |    uint32_t bind_address     Address to bind to, in network order.
148  |   More:
149  |   +html+ <PRE>
150  |   Authors:
151  |         ottrey
152  | 	joao
153  | 
154  |   +html+ </PRE><DL COMPACT>
155  |   +html+ <DT>Online References:
156  |   +html+ <DD><UL>
157  |   +html+ </UL></DL>
158  | 
159  |   ++++++++++++++++++++++++++++++++++++++*/
160  | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
161  |   struct sockaddr_in address;
162  |   int listening_socket;
163  |   int new_process;
164  |   int reuse_addr = 1;
165  | 
166  |   /* Setup internet address information.  
167  |      This is used with the bind() call */
168  |   memset((char *) &address, 0, sizeof(address));
169  |   address.sin_family = AF_INET;
170  |   address.sin_port = port;
171  |   address.sin_addr.s_addr = bind_address;
172  | 
173  |   /* Map all of the signals and exit routine */
174  |   atexit(func_atexit);
175  |   /* signal.h has a full list of signal names */
176  |   signal(SIGHUP, func_sighup);
177  |   signal(SIGINT, func_sigint);
178  | 
179  |   listening_socket = socket(AF_INET, socket_type, 0);
180  |   if (listening_socket < 0) {
181  |     perror("socket");
182  |     exit(EXIT_FAILURE);
183  |   }
184  | 
185  |   setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
186  | 
187  |   if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
188  |     perror("bind");
189  |     close(listening_socket);
190  |     exit(EXIT_FAILURE);
191  |   }
192  | 
193  | 
194  |   if (socket_type == SOCK_STREAM) {
195  |     listen(listening_socket, 5); /* Queue up to five connections before
196  |                                   having them automatically rejected. */
197  |   }
198  | 
199  |   return listening_socket;
200  | } /* SK_getsock() */
201  | 
202  | /*++++++++++++++++++++++++++++++++++++++
203  | 
204  |    Wait for an incoming connection on the specified socket
205  | 
206  |    int	SK_accept_connection The socket for communicating to the client
207  | 
208  |    int  listening_socket     The socket that the server is bound to
209  | 
210  |   More:
211  |   +html+ <PRE>
212  |   Authors:
213  | 	joao
214  |   +html+ </PRE>
215  |   ++++++++++++++++++++++++++++++++++++++*/
216  | int SK_accept_connection(int listening_socket) {
217  |   int connected_socket = -1;
218  |   char print_buf[STR_L];
219  | 
220  |     while(connected_socket < 0) {
221  |       sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, "");
222  | /* XXX joao - ? - why is this here?
223  | fflush(NULL);
224  | */
225  |       connected_socket = accept(listening_socket, NULL, NULL);
226  |       if (connected_socket < 0) {
227  |         /* Either a real error occured, or blocking was interrupted for
228  |            some reason.  Only abort execution if a real error occured. */
229  |         if (errno != EINTR) {
230  |           perror("accept");
231  |           close(listening_socket);
232  |           exit(EXIT_FAILURE);
233  |         } else {
234  |           continue;    /* don't return - do the accept again */
235  |         }
236  |       }
237  |     }
238  |     sprintf(print_buf, "connected_socket=%d\n", connected_socket); log_print(print_buf); strcpy(print_buf, "");
239  | 
240  |     return connected_socket;
241  | }
242  | 
243  | /* sock_read() */
244  | /*++++++++++++++++++++++++++++++++++++++
245  | 
246  |    This is just like the read() system call, except that it will make
247  |    sure that all your data goes through the socket.
248  | 
249  |    int    sock_read  The number of bytes read.
250  | 
251  |    int    sockfd    The socket file descriptor.
252  | 
253  |    char   *buf      The buffer to be read from the socket.
254  | 
255  |    size_t count     The number of bytes in the buffer.
256  | 
257  |   More:
258  |   +html+ <PRE>
259  |   Authors:
260  |         ottrey
261  |   +html+ </PRE>
262  |   ++++++++++++++++++++++++++++++++++++++*/
263  | static int sock_read(int sockfd, char *buf, size_t count) {
264  |   size_t bytes_read = 0;
265  |   int this_read;
266  | 
267  |   while (bytes_read < count) {
268  |     do
269  |       this_read = read(sockfd, buf, count - bytes_read);
270  |     while ( (this_read < 0) && (errno == EINTR) );
271  |     if (this_read < 0)
272  |       return this_read;
273  |     else if (this_read == 0)
274  |       return bytes_read;
275  |     bytes_read += this_read;
276  |     buf += this_read;
277  |   }
278  | 
279  |   return count;
280  | 
281  | } /* sock_read() */
282  | 
283  | 
284  | /* sock_write() */
285  | /*++++++++++++++++++++++++++++++++++++++
286  | 
287  |    This is just like the write() system call, accept that it will
288  |    make sure that all data is transmitted.
289  | 
290  |    int    sockfd  The socket file descriptor.
291  | 
292  |    char   *buf    The buffer to be written to the socket.
293  | 
294  |    size_t count   The number of bytes in the buffer.
295  | 
296  |   More:
297  |   +html+ <PRE>
298  |   Authors:
299  |         ottrey
300  | 
301  |   +html+ </PRE><DL COMPACT>
302  |   +html+ <DT>Online References:
303  |   +html+ <DD><UL>
304  |   +html+ </UL></DL>
305  | 
306  |   ++++++++++++++++++++++++++++++++++++++*/
307  | static int sock_write(int sockfd, const char *buf, size_t count) {
308  |   size_t  bytes_sent = 0;
309  |   int     this_write;
310  | 
311  | /*
312  |   printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count);
313  | */
314  |   while (bytes_sent < count) {
315  |     do
316  |       this_write = write(sockfd, buf, count - bytes_sent);
317  |     while ( (this_write < 0) && (errno == EINTR) );
318  |     if (this_write <= 0)
319  |       return this_write;
320  |     bytes_sent += this_write;
321  |     buf += this_write;
322  |   }
323  |   return count;
324  | } /* sock_write() */
325  | 
326  | 
327  | /* SK_gets() */
328  | /*++++++++++++++++++++++++++++++++++++++
329  | 
330  |    This function reads from a socket, until it recieves a linefeed
331  |    character.  It fills the buffer "str" up to the maximum size "count".
332  | 
333  |    int SK_gets  The total_count of bytes read.
334  | 
335  |    int    sockfd    The socket file descriptor.
336  | 
337  |    char   *str      The buffer to be written from the socket.
338  | 
339  |    size_t count     The number of bytes in the buffer.
340  | 
341  |   More:
342  |   +html+ <PRE>
343  |   Authors:
344  |         ottrey
345  | 
346  |   Side Effects:
347  |         This function will return -1 if the socket is closed during the read operation.
348  | 
349  |         Note that if a single line exceeds the length of count, the extra data
350  |         will be read and discarded!  You have been warned.
351  | 
352  |   To Do:
353  |         Capture the control-c properly!
354  | 
355  |   +html+ </PRE>
356  | 
357  |   ++++++++++++++++++++++++++++++++++++++*/
358  | int SK_gets(int sockfd, char *str, size_t count) {
359  |   int bytes_read;
360  |   int total_count = 0;
361  |   char *current_position;
362  |   char last_read = 0;
363  | 
364  |   int control_c = 0;
365  | 
366  |   current_position = str;
367  |   while (last_read != 10) {
368  |     bytes_read = read(sockfd, &last_read, 1);
369  |     if (bytes_read <= 0) {
370  |       /* The other side may have closed unexpectedly */
371  |       return -1; /* Is this effective on other platforms than linux? */
372  |     }
373  |     if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
374  |       *current_position = last_read;
375  |       current_position++;
376  |       total_count++;
377  |     }
378  | 
379  |     if (last_read == -1) {
380  |       bytes_read = read(sockfd, &last_read, 1);
381  |       if (last_read == -12) {
382  | printf("Client pressed Control-c.\n");
383  |         control_c = 1;
384  | printf("returning a -2\n");
385  |         return -2;
386  |       }
387  |     }
388  |   }
389  |   if (count > 0) {
390  |     *current_position = 0;
391  |   }
392  | 
393  |   return total_count;
394  | 
395  | } /* SK_gets() */
396  | 
397  | 
398  | /* SK_puts() */
399  | /*++++++++++++++++++++++++++++++++++++++
400  | 
401  |    This function writes a character string out to a socket.
402  | 
403  |    int SK_puts  The total_count of bytes read.
404  | 
405  |    int    sockfd    The socket file descriptor.
406  | 
407  |    char   *str      The buffer to be written from the socket.
408  | 
409  |   More:
410  |   +html+ <PRE>
411  |   Authors:
412  |         ottrey
413  | 
414  |   Side Effects:
415  |         This function will return -1 if the socket is closed during the write operation.
416  | 
417  |         Note that if a single line exceeds the length of count, the extra data
418  |         will be read and discarded!  You have been warned.
419  | 
420  |   +html+ </PRE>
421  | 
422  |   ++++++++++++++++++++++++++++++++++++++*/
423  | int SK_puts(int sockfd, const char *str) {
424  | 
425  |   return sock_write(sockfd, str, strlen(str));
426  | 
427  | } /* SK_puts() */
428  |