1 | /***************************************
2 | $Revision: 1.10 $
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 <arpa/inet.h>
26 | #include "socket.h"
27 | #include "constants.h"
28 | #include "stubs.h"
29 |
30 | #include "iproutines.h"
31 | #include "memwrap.h"
32 |
33 | extern int h_errno;
34 |
35 |
36 | /*+ String sizes +*/
37 | #define STR_S 63
38 | #define STR_M 255
39 | #define STR_L 1023
40 | #define STR_XL 4095
41 | #define STR_XXL 16383
42 |
43 | static void log_print(const char *arg) {
44 | FILE *logf;
45 |
46 | if (CO_get_socket_logging() == 1) {
47 | if (strcmp(CO_get_socket_logfile(), "stdout") == 0) {
48 | printf(arg);
49 | }
50 | else {
51 | logf = fopen(CO_get_socket_logfile(), "a");
52 | fprintf(logf, arg);
53 | fclose(logf);
54 | }
55 | }
56 |
57 | } /* log_print() */
58 |
59 | /* SK_atoport() */
60 | /*++++++++++++++++++++++++++++++++++++++
61 | Take a service name, and a service type, and return a port number. If the
62 | service name is not found, it tries it as a decimal number. The number
63 | returned is byte ordered for the network.
64 |
65 | char *service Service name (or port number).
66 |
67 | char *proto Protocol (eg "tcp").
68 |
69 | More:
70 | +html+ <PRE>
71 | Authors:
72 | ottrey
73 |
74 | +html+ </PRE><DL COMPACT>
75 | +html+ <DT>Online References:
76 | +html+ <DD><UL>
77 | +html+ </UL></DL>
78 |
79 | ++++++++++++++++++++++++++++++++++++++*/
80 | int SK_atoport(const char *service, const char *proto) {
81 | int port;
82 | long int lport;
83 | struct servent *serv;
84 | char *errpos;
85 |
86 | /* First try to read it from /etc/services */
87 | serv = getservbyname(service, proto);
88 | if (serv != NULL)
89 | port = serv->s_port;
90 | else { /* Not in services, maybe a number? */
91 | lport = strtol(service,&errpos,0);
92 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
93 | return -1; /* Invalid port address */
94 | port = htons(lport);
95 | }
96 | return port;
97 | } /* SK_atoport() */
98 |
99 |
100 | /* SK_close_listening_socket() */
101 | /*++++++++++++++++++++++++++++++++++++++
102 | XXX Note: Not sure how long this function will last. Shouldn't _really_ need it.
103 |
104 | More:
105 | +html+ <PRE>
106 | Authors:
107 | ottrey
108 |
109 | +html+ </PRE><DL COMPACT>
110 | +html+ <DT>Online References:
111 | +html+ <DD><UL>
112 | +html+ </UL></DL>
113 |
114 | ++++++++++++++++++++++++++++++++++++++*/
115 | /*void SK_close_listening_socket() {
116 | close(listening_socket);
117 | } */ /* SK_close_listening_socket */
118 |
119 | static void func_atexit(void) {
120 | printf("SK: func_atexit() called\n");
121 | }
122 |
123 | static void func_sighup(int n) {
124 | printf("SK: func_sighup(%d) called\n", n);
125 | }
126 |
127 | static void func_sigint(int n) {
128 | printf("SK: func_sigint(%d) called\n", n);
129 | }
130 |
131 |
132 | void SK_close(int socket) {
133 | char print_buf[STR_M];
134 |
135 | sprintf(print_buf, "Closing socket... %d\n", socket); log_print(print_buf); strcpy(print_buf, "");
136 |
137 | close(socket);
138 | }
139 |
140 | /* SK_getsock() */
141 | /*++++++++++++++++++++++++++++++++++++++
142 |
143 | This function creates a socket and binds to it
144 |
145 | int SK_getsock The new socket
146 |
147 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
148 |
149 | u_short port The port to listen on. Remember that ports < 1024 are
150 | reserved for the root user. Must be passed in network byte
151 | order (see "man htons").
152 |
153 | uint32_t bind_address Address to bind to, in network order.
154 | More:
155 | +html+ <PRE>
156 | Authors:
157 | ottrey
158 | joao
159 |
160 | +html+ </PRE><DL COMPACT>
161 | +html+ <DT>Online References:
162 | +html+ <DD><UL>
163 | +html+ </UL></DL>
164 |
165 | ++++++++++++++++++++++++++++++++++++++*/
166 | int SK_getsock(int socket_type, u_short port, uint32_t bind_address) {
167 | struct sockaddr_in address;
168 | int listening_socket;
169 | int reuse_addr = 1;
170 |
171 | /* Setup internet address information.
172 | This is used with the bind() call */
173 | memset((char *) &address, 0, sizeof(address));
174 | address.sin_family = AF_INET;
175 | address.sin_port = port;
176 | address.sin_addr.s_addr = bind_address;
177 |
178 | /* Map all of the signals and exit routine */
179 | atexit(func_atexit);
180 | /* signal.h has a full list of signal names */
181 | //signal(SIGHUP, func_sighup); This should be handled in a different way (thread)
182 | //signal(SIGINT, func_sigint);
183 |
184 | listening_socket = socket(AF_INET, socket_type, 0);
185 | if (listening_socket < 0) {
186 | perror("socket");
187 | exit(EXIT_FAILURE);
188 | }
189 |
190 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
191 |
192 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
193 | perror("bind");
194 | close(listening_socket);
195 | exit(EXIT_FAILURE);
196 | }
197 |
198 |
199 | if (socket_type == SOCK_STREAM) {
200 | listen(listening_socket, 5); /* Queue up to five connections before
201 | having them automatically rejected. */
202 | }
203 |
204 | return listening_socket;
205 | } /* SK_getsock() */
206 |
207 | /*++++++++++++++++++++++++++++++++++++++
208 |
209 | Wait for an incoming connection on the specified socket
210 |
211 | int SK_accept_connection The socket for communicating to the client
212 |
213 | int listening_socket The socket that the server is bound to
214 |
215 | More:
216 | +html+ <PRE>
217 | Authors:
218 | joao
219 | +html+ </PRE>
220 | ++++++++++++++++++++++++++++++++++++++*/
221 | int SK_accept_connection(int listening_socket) {
222 | int connected_socket = -1;
223 | char print_buf[STR_L];
224 |
225 | while(connected_socket < 0) {
226 | sprintf(print_buf, "Going to accept connections on socket : %d\n",listening_socket); log_print(print_buf); strcpy(print_buf, "");
227 | /* XXX joao - ? - why is this here?
228 | fflush(NULL);
229 | */
230 |
231 | connected_socket = accept(listening_socket, NULL, NULL);
232 | if (connected_socket < 0) {
233 | /* Either a real error occured, or blocking was interrupted for
234 | some reason. Only abort execution if a real error occured. */
235 | if (errno != EINTR) {
236 | perror("accept");
237 | close(listening_socket);
238 | exit(EXIT_FAILURE);
239 | } else {
240 | continue; /* don't return - do the accept again */
241 | }
242 | }
243 | }
244 | sprintf(print_buf, "client connected.\n"); log_print(print_buf); strcpy(print_buf, "");
245 |
246 | return connected_socket;
247 | }
248 |
249 | /* sock_read() */
250 | /*++++++++++++++++++++++++++++++++++++++
251 |
252 | This is just like the read() system call, except that it will make
253 | sure that all your data goes through the socket.
254 |
255 | int sock_read The number of bytes read.
256 |
257 | int sockfd The socket file descriptor.
258 |
259 | char *buf The buffer to be read from the socket.
260 |
261 | size_t count The number of bytes in the buffer.
262 |
263 | More:
264 | +html+ <PRE>
265 | Authors:
266 | ottrey
267 | +html+ </PRE>
268 | ++++++++++++++++++++++++++++++++++++++*/
269 | static int sock_read(int sockfd, char *buf, size_t count, unsigned timeout) {
270 | size_t bytes_read = 0;
271 | int this_read;
272 |
273 | while (bytes_read < count) {
274 | do
275 | this_read = read(sockfd, buf, count - bytes_read);
276 | while ( (this_read < 0) && (errno == EINTR) );
277 | if (this_read < 0)
278 | return this_read;
279 | else if (this_read == 0)
280 | return bytes_read;
281 | bytes_read += this_read;
282 | buf += this_read;
283 | }
284 |
285 | return count;
286 |
287 | } /* sock_read() */
288 |
289 |
290 | /* sock_write() */
291 | /*++++++++++++++++++++++++++++++++++++++
292 |
293 | This is just like the write() system call, accept that it will
294 | make sure that all data is transmitted.
295 |
296 | int sockfd The socket file descriptor.
297 |
298 | char *buf The buffer to be written to the socket.
299 |
300 | size_t count The number of bytes in the buffer.
301 |
302 | More:
303 | +html+ <PRE>
304 | Authors:
305 | ottrey
306 |
307 | +html+ </PRE><DL COMPACT>
308 | +html+ <DT>Online References:
309 | +html+ <DD><UL>
310 | +html+ </UL></DL>
311 |
312 | ++++++++++++++++++++++++++++++++++++++*/
313 | static int sock_write(int sockfd, const char *buf, size_t count, unsigned timeout) {
314 | size_t bytes_sent = 0;
315 | int this_write;
316 |
317 | /*
318 | printf("sock_write = { sockfd=[%d], buf=[%s], count=[%d]\n", sockfd, buf, count);
319 | */
320 | while (bytes_sent < count) {
321 | do
322 | this_write = write(sockfd, buf, count - bytes_sent);
323 | while ( (this_write < 0) && (errno == EINTR) );
324 | if (this_write <= 0)
325 | return this_write;
326 | bytes_sent += this_write;
327 | buf += this_write;
328 | }
329 | return count;
330 | } /* sock_write() */
331 |
332 |
333 | /* SK_gets() */
334 | /*++++++++++++++++++++++++++++++++++++++
335 |
336 | This function reads from a socket, until it recieves a linefeed
337 | character. It fills the buffer "str" up to the maximum size "count".
338 |
339 | int SK_gets The total_count of bytes read.
340 |
341 | int sockfd The socket file descriptor.
342 |
343 | char *str The buffer to be written from the socket.
344 |
345 | size_t count The number of bytes in the buffer.
346 |
347 | More:
348 | +html+ <PRE>
349 | Authors:
350 | ottrey
351 |
352 | Side Effects:
353 | This function will return -1 if the socket is closed during the read operation.
354 |
355 | Note that if a single line exceeds the length of count, the extra data
356 | will be read and discarded! You have been warned.
357 |
358 | To Do:
359 | Capture the control-c properly!
360 |
361 | +html+ </PRE>
362 |
363 | ++++++++++++++++++++++++++++++++++++++*/
364 | int SK_gets(int sockfd, char *str, size_t count, unsigned timeout) {
365 | int bytes_read;
366 | int total_count = 0;
367 | char *current_position;
368 | char last_read = 0;
369 |
370 | int control_c = 0;
371 |
372 | current_position = str;
373 | while (last_read != 10) {
374 | bytes_read = read(sockfd, &last_read, 1);
375 | if (bytes_read <= 0) {
376 | /* The other side may have closed unexpectedly */
377 | return SK_DISCONNECT;
378 | /* Is this effective on other platforms than linux? */
379 | }
380 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
381 | *current_position = last_read;
382 | current_position++;
383 | total_count++;
384 | }
385 |
386 | if (last_read == -1) {
387 | bytes_read = read(sockfd, &last_read, 1);
388 | if (last_read == -12) {
389 | printf("Client pressed Control-c.\n");
390 | control_c = 1;
391 | printf("returning SK_INTERRUPT\n");
392 | return SK_INTERRUPT;
393 | }
394 | }
395 | }
396 | if (count > 0) {
397 | *current_position = 0;
398 | }
399 |
400 | return total_count;
401 |
402 | } /* SK_gets() */
403 |
404 |
405 | /* SK_puts() */
406 | /*++++++++++++++++++++++++++++++++++++++
407 |
408 | This function writes a character string out to a socket.
409 |
410 | int SK_puts The total_count of bytes written,
411 | or errors (represented as negative numbers)
412 |
413 | int sockfd The socket file descriptor.
414 |
415 | char *str The buffer to be written from the socket.
416 |
417 | unsigned timeout timeout in seconds
418 |
419 | More:
420 | +html+ <PRE>
421 | Authors:
422 | ottrey
423 |
424 | Side Effects:
425 | This function will return -1 if the socket is closed during the write operation.
426 |
427 | Note that if a single line exceeds the length of count, the extra data
428 | will be read and discarded! You have been warned.
429 |
430 | +html+ </PRE>
431 |
432 | ++++++++++++++++++++++++++++++++++++++*/
433 | int SK_puts(int sockfd, const char *str, unsigned timeout) {
434 |
435 | return sock_write(sockfd, str, strlen(str), timeout);
436 |
437 | } /* SK_puts() */
438 |
439 | /* SK_putc() */
440 | /*++++++++++++++++++++++++++++++++++++++
441 |
442 | int SK_putc This function writes a single character out to a socket.
443 |
444 | int sockfd socket
445 | char ch character
446 | unsigned timeout timeout in seconds
447 |
448 | return number of chars written
449 |
450 | ++++++++++++++++++++++++++++++++++++++*/
451 | int SK_putc(int sockfd, char ch, unsigned timeout) {
452 | return sock_write(sockfd, &ch, 1, timeout);
453 | }/* SK_putc() */
454 |
455 | /*++++++++++++++++++++++++++++++++++++++
456 |
457 | This function reads a single character from a socket.
458 |
459 | returns EOF when no character can be read.
460 |
461 | ++++++++++++++++++++++++++++++++++++++*/
462 | int SK_getc(int sockfd, unsigned timeout) {
463 | char ch;
464 |
465 | if( read(sockfd, &ch, 1) <= 0 ) {
466 | return EOF;
467 | }
468 | else {
469 | return ch;
470 | }
471 | }/* SK_getc() */
472 |
473 | /* SK_getpeername() */
474 | /*++++++++++++++++++++++++++++++++++++++
475 |
476 | This function will tell you who is at the other end of a connected stream socket.
477 | XXX It's not working.
478 | XXX ? MB it is...
479 |
480 | int sockfd The socket file descriptor.
481 |
482 | More:
483 | +html+ <PRE>
484 | Authors:
485 | ottrey
486 | +html+ </PRE>
487 |
488 | ++++++++++++++++++++++++++++++++++++++*/
489 | char *SK_getpeername(int sockfd)
490 | {
491 | char *hostaddress=NULL;
492 | struct sockaddr_in addr_in;
493 | int namelen=sizeof(addr_in);
494 |
495 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) != -1) {
496 | //hostaddress = (char *)malloc(16); /* max length of a valid IPv4 + \0 */
497 | dieif( wr_malloc((void **)&hostaddress, 16) != UT_OK);
498 |
499 | strcpy(hostaddress, inet_ntoa(addr_in.sin_addr)); /* XXX MT-UNSAFE */
500 | }
501 |
502 | return hostaddress;
503 |
504 | } /* SK_getpeername() */
505 |
506 | /* SK_getpeerip */
507 | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
508 | struct sockaddr_in addr_in;
509 | int namelen=sizeof(addr_in);
510 | int ret=-1;
511 |
512 | memset(& addr_in, 0, sizeof(struct sockaddr_in));
513 |
514 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
515 | ret=0;
516 | IP_addr_s2b(ip, &addr_in, namelen);
517 | }
518 |
519 | return ret;
520 | }
521 |
522 | /*-------------------------------------------------------------------
523 | * CD varieties of the functions: broken connections get registered
524 | * in the connection structure within the query environment
525 | * as side effects.
526 | * -----------------------------------------------------------------*/
527 |
528 | /* SK_cd_puts() */
529 | /*++++++++++++++++++++++++++++++++++++++
530 |
531 | This function writes a character string out to a socket.
532 |
533 | int SK_qe_puts The total_count of bytes written,
534 | or errors (represented as negative numbers)
535 |
536 | sk_conn_st *condat connection data
537 |
538 | char *str The buffer to be written from the socket.
539 |
540 | unsigned timeout timeout in seconds
541 |
542 | More:
543 | if the connection structure has bad status for this connection
544 | from previous calls, no write will be attempted.
545 |
546 | +html+ <PRE>
547 | Authors:
548 | marek
549 |
550 | Side Effects:
551 | broken connections get registered
552 | in the connection structure within the query environment
553 |
554 | +html+ </PRE>
555 |
556 | ++++++++++++++++++++++++++++++++++++++*/
557 | int SK_cd_puts(sk_conn_st *condat, const char *str) {
558 | int res=SK_puts(condat->sock, str, condat->wr_timeout );
559 |
560 | if( res < 0 ){
561 | switch( - res ) {
562 | /* dont know what to do and how to log */
563 | case SK_DISCONNECT:
564 | case SK_INTERRUPT:
565 | /*("Thread received a control-c\n");*/
566 | case SK_TIMEOUT:
567 | /*("Reading timed out\n");*/
568 | break;
569 | default:
570 | /* unexpected error code. bail out */
571 | die;
572 | }
573 | }
574 | } /* SK_cd_puts() */
575 |
576 | /* SK_cd_gets() */
577 | /*++++++++++++++++++++++++++++++++++++++
578 |
579 | Wrapper around SK_gets.
580 |
581 | int SK_qe_gets The total_count of bytes read,
582 | or errors (represented as negative numbers)
583 |
584 | sk_conn_st *condat connection data
585 |
586 | char *str The buffer to be written from the socket.
587 |
588 | More:
589 | if the connection structure has bad status for this connection
590 | from previous calls, no write will be attempted.
591 |
592 | +html+ <PRE>
593 | Authors:
594 | marek
595 |
596 | Side Effects:
597 | broken connections get registered
598 | in the connection structure within the query environment
599 |
600 | +html+ </PRE>
601 |
602 | ++++++++++++++++++++++++++++++++++++++*/
603 | int SK_cd_gets(sk_conn_st *condat, char *str, size_t count) {
604 | int res=SK_gets(condat->sock, str, count, condat->wr_timeout);
605 |
606 | if( res < 0 ){
607 | switch( res ) {
608 | /* dont know what to do and how to log */
609 | case SK_DISCONNECT:
610 | case SK_INTERRUPT:
611 | /*("Thread received a control-c\n");*/
612 | case SK_TIMEOUT:
613 | /*("Reading timed out\n");*/
614 | break;
615 | default:
616 | /* unexpected error code. bail out */
617 | die;
618 | }
619 | }
620 | } /* SK_cd_gets() */
621 |
622 |
623 | int SK_cd_close(sk_conn_st *condat) {
624 | SK_close(condat->sock);
625 | } /* SK_cd_close() */