1 | /***************************************
2 | $Revision: 1.14 $
3 |
4 | Socket module - routines facilitating calls to socket library.
5 |
6 | Status: NOT REVUED, TESTED
7 |
8 | Basic code adapted by Chris Ottrey from
9 | http://www.ibrado.com/sock-faq/sfaq.html#faq65 - sample source code.
10 | ******************/ /******************
11 | Modification History:
12 | ottrey (08/03/1999) Created from sockhelp.c.
13 | ottrey (08/03/1998) Heavily butchered.
14 | joao (22/06/1999) Modified socket creation and accepts.
15 | marek (December 2000) Added connection function w/timeout.
16 | ******************/ /******************
17 | Copyright (c) 1999, 2000 RIPE NCC
18 |
19 | All Rights Reserved
20 |
21 | Permission to use, copy, modify, and distribute this software and its
22 | documentation for any purpose and without fee is hereby granted,
23 | provided that the above copyright notice appear in all copies and that
24 | both that copyright notice and this permission notice appear in
25 | supporting documentation, and that the name of the author not be
26 | used in advertising or publicity pertaining to distribution of the
27 | software without specific, written prior permission.
28 |
29 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
30 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
31 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
32 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
33 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
34 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 | ***************************************/
36 |
37 | #include "sk.h"
38 | #include "constants.h"
39 | #include "stubs.h"
40 |
41 | #include "memwrap.h"
42 |
43 | /*+ String sizes +*/
44 | #define STR_S 63
45 | #define STR_XXL 16383
46 |
47 | /* SK_atoport() */
48 | /*++++++++++++++++++++++++++++++++++++++
49 | Take a service name, and a service type, and return a port number. If the
50 | service name is not found, it tries it as a decimal number. The number
51 | returned is byte ordered for the network.
52 |
53 | char *service Service name (or port number).
54 |
55 | char *proto Protocol (eg "tcp").
56 |
57 | Author:
58 | ottrey.
59 |
60 | ++++++++++++++++++++++++++++++++++++++*/
61 | int SK_atoport(const char *service, const char *proto) {
62 | unsigned port;
63 | long int lport;
64 | struct servent *serv;
65 | char *errpos;
66 | struct servent result;
67 | char buffer[STR_XXL];
68 |
69 | /* First try to read it from /etc/services */
70 |
71 | #ifdef __linux__
72 | if(getservbyname_r(service, proto, &result, buffer, sizeof(buffer), &serv) < 0) serv = NULL;
73 | #else
74 | serv = getservbyname_r(service, proto, &result, buffer, sizeof(buffer));
75 | #endif
76 |
77 | if (serv != NULL)
78 | port = serv->s_port;
79 | else { /* Not in services, maybe a number? */
80 | lport = strtol(service,&errpos,0);
81 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) )
82 | return -1; /* Invalid port address */
83 | port = htons(lport);
84 | }
85 | return port;
86 | } /* SK_atoport() */
87 |
88 |
89 | /* SK_close() */
90 | /*++++++++++++++++++++++++++++++++++++++
91 |
92 | int SK_close wrapper around closing the socket. Returns the value
93 | returned by close(2)
94 |
95 | int socket socket to be closed
96 |
97 | Author:
98 | ottrey
99 | ++++++++++++++++++++++++++++++++++++++*/
100 | int SK_close(int socket) {
101 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "Closing socket... %d", socket);
102 |
103 | return close(socket);
104 | }
105 |
106 | /* SK_getsock() */
107 | /*++++++++++++++++++++++++++++++++++++++
108 |
109 | int SK_getsock This function creates a socket and binds to it.
110 | Returns the number of the created
111 | descriptor/listening socket.
112 |
113 | int socket_type SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets)
114 |
115 | unsigned port The port to listen on. Ports < 1024 are
116 | reserved for the root user. Host byte order.
117 |
118 | int backlog Size of the backlog queue to be set on that
119 | socket.
120 |
121 | uint32_t bind_address Address to bind to, in network order.
122 |
123 | Authors:
124 | ottrey,
125 | joao,
126 | marek (added htons conversion for port).
127 |
128 | ++++++++++++++++++++++++++++++++++++++*/
129 | int SK_getsock(int socket_type, unsigned h_port, int backlog,
130 | uint32_t bind_address) {
131 | struct sockaddr_in address;
132 | int listening_socket;
133 | int reuse_addr = 1;
134 | u_short port = htons(h_port);
135 |
136 | /* Setup internet address information.
137 | This is used with the bind() call */
138 | memset((char *) &address, 0, sizeof(address));
139 | address.sin_family = AF_INET;
140 | address.sin_port = port;
141 | address.sin_addr.s_addr = bind_address;
142 |
143 | /* Map all of the signals and exit routine */
144 |
145 | listening_socket = socket(AF_INET, socket_type, 0);
146 | if (listening_socket < 0) {
147 | perror("socket");
148 | exit(EXIT_FAILURE);
149 | }
150 |
151 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse_addr, sizeof(reuse_addr));
152 |
153 | if (bind(listening_socket, (struct sockaddr *) &address, sizeof(address)) < 0) {
154 | perror("bind");
155 | close(listening_socket);
156 | exit(EXIT_FAILURE);
157 | }
158 |
159 |
160 | if (socket_type == SOCK_STREAM) {
161 | listen(listening_socket, backlog); /* Queue up to five connections before
162 | having them automatically rejected. */
163 | }
164 |
165 | return listening_socket;
166 | } /* SK_getsock() */
167 |
168 | /*++++++++++++++++++++++++++++++++++++++
169 |
170 | Wait for an incoming connection on the specified socket
171 |
172 | int SK_accept_connection The socket for communicating to the client
173 |
174 | int listening_socket The socket that the server is bound to
175 |
176 | Authors:
177 | joao,
178 | marek.
179 | ++++++++++++++++++++++++++++++++++++++*/
180 | int SK_accept_connection(int listening_socket) {
181 | int connected_socket = -1;
182 | int num_errors = 0;
183 |
184 | #define MAX_ACCEPT_ERRORS 3
185 |
186 | while(connected_socket < 0) {
187 |
188 | ER_dbg_va(FAC_SK, ASP_SK_GEN,
189 | "Going to accept connections on socket : %d",listening_socket);
190 |
191 | connected_socket = accept(listening_socket, NULL, NULL);
192 | if (connected_socket < 0) {
193 | /* Either a real error occured, or blocking was interrupted for
194 | some reason. Only abort execution if a real error occured. */
195 | switch(errno) {
196 | case EINTR: /* Interrupted system call */
197 | case ECONNABORTED: /* Software caused connection abort */
198 | /* no warning */
199 | continue; /* don't return - do the accept again */
200 | default:
201 | /* special case: shutdown of the server - just return */
202 | if( CO_get_do_server() == 0 ) {
203 | return -1;
204 | }
205 | else { /* real error */
206 | if( ++num_errors < MAX_ACCEPT_ERRORS ) {
207 | /* warn */
208 | ER_perror(FAC_SK, SK_ACERW, "(%d) %s", errno, strerror(errno));
209 | }
210 | else {
211 | /* crash */
212 | ER_perror(FAC_SK, SK_ACERF, "");
213 | die;
214 | }
215 | }
216 | }
217 | }
218 | else { /* success */
219 | ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
220 | connected_socket
221 | );
222 |
223 | return connected_socket;
224 | }
225 | } /* while */
226 | }
227 |
228 |
229 | /*++++++++++++++++++++++++++++++++++++++
230 |
231 | er_ret_t SK_connect wrapper around connect(), doing non-blocking
232 | connection with timeout
233 |
234 | int *sock pointer to the storage for socket descriptor
235 |
236 | char *hostname host to connect to
237 |
238 | int port port to connect to
239 |
240 | int timeout in seconds
241 |
242 | Author: marek
243 |
244 | ++++++++++++++++++++++++++++++++++++++*/
245 | er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
246 | {
247 | struct sockaddr_in sin;
248 | struct hostent *hp;
249 | int s;
250 | int flags;
251 | struct timeval ptm;
252 | fd_set rset, wset;
253 | int gs, sel, er, erlen=sizeof(er);
254 | int error;
255 | struct hostent result;
256 | char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
257 |
258 | /* look up the host name */
259 | #ifdef __linux__
260 | er = (gethostbyname_r(hostname, &result, aliasbuf,
261 | sizeof(aliasbuf), &hp, &error) < 0 );
262 | #else /* default is Solaris implementation */
263 | hp = gethostbyname_r(hostname, &result, aliasbuf,
264 | sizeof(aliasbuf), &error);
265 | er = ( hp == NULL );
266 | #endif
267 |
268 | if( er ) {
269 | return SK_BADHOST;
270 | }
271 |
272 | /* create a socket */
273 | s = socket(AF_INET, SOCK_STREAM, 0);
274 | if (s < 0) {
275 | return SK_SOCKET;
276 | }
277 |
278 | /* bind to it */
279 | bzero((caddr_t)&sin, sizeof (sin));
280 | sin.sin_family = hp->h_addrtype;
281 | if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
282 | close(s);
283 | return SK_BIND;
284 | }
285 | bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
286 | sin.sin_port=htons(port);
287 |
288 | /* connect in non-blocking mode */
289 | flags = fcntl(s, F_GETFL, 0);
290 | fcntl(s, F_SETFL, flags | O_NONBLOCK );
291 |
292 | if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
293 | && errno != EINPROGRESS ) {
294 | close(s);
295 | return SK_CONNECT;
296 | }
297 |
298 | /* now wait for success */
299 | FD_ZERO( &rset );
300 | FD_SET( s, &rset );
301 | wset = rset;
302 | ptm.tv_usec = 0;
303 | ptm.tv_sec = timeout;
304 |
305 | if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
306 | /* timeout */
307 | close(s);
308 | return SK_TIMEOUT;
309 | }
310 | dieif( sel < 0 ); /* we don't expect problems with select */
311 |
312 | gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
313 |
314 | if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
315 | close(s);
316 | return SK_CONNECT;
317 | } /* if error */
318 |
319 | fcntl(s, F_SETFL, flags);
320 | *sock = s;
321 |
322 | return SK_OK;
323 | }
324 |
325 |
326 | /* SK_read() */
327 | /*++++++++++++++++++++++++++++++++++++++
328 |
329 | This is just like the read() system call, except that it will make
330 | sure that all your data goes through the socket.
331 |
332 | int SK_read Returns the number of bytes read.
333 |
334 | int sockfd The socket file descriptor.
335 |
336 | char *buf The buffer to be read from the socket.
337 |
338 | size_t count The number of bytes in the buffer.
339 |
340 | Author:
341 | ottrey
342 |
343 | ++++++++++++++++++++++++++++++++++++++*/
344 | int SK_read(int sockfd, char *buf, size_t count) {
345 | size_t bytes_read = 0;
346 | int this_read;
347 |
348 | while (bytes_read < count) {
349 | do
350 | this_read = read(sockfd, buf, count - bytes_read);
351 | while ( (this_read < 0) && (errno == EINTR) );
352 | if (this_read < 0)
353 | return this_read;
354 | else if (this_read == 0)
355 | return bytes_read;
356 | bytes_read += this_read;
357 | buf += this_read;
358 | }
359 |
360 | return count;
361 |
362 | } /* SK_read() */
363 |
364 |
365 | /* SK_write() */
366 | /*++++++++++++++++++++++++++++++++++++++
367 |
368 | This is just like the write() system call, except that it will
369 | make sure that all data is transmitted.
370 |
371 | int SK_write Returns the number of bytes written.
372 |
373 | int sockfd The socket file descriptor.
374 |
375 | char *buf The buffer to be written to the socket.
376 |
377 | size_t count The number of bytes in the buffer.
378 |
379 | Author:
380 | ottrey
381 |
382 | ++++++++++++++++++++++++++++++++++++++*/
383 | int SK_write(int sockfd, const char *buf, size_t count) {
384 | size_t bytes_sent = 0;
385 | int this_write;
386 |
387 |
388 | ER_dbg_va(FAC_SK, ASP_SK_WRIT,
389 | "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
390 | sockfd, buf, count);
391 |
392 | while (bytes_sent < count) {
393 | do
394 | this_write = write(sockfd, buf, count - bytes_sent);
395 | while ( (this_write < 0) && (errno == EINTR) );
396 | if (this_write <= 0)
397 | return this_write;
398 | bytes_sent += this_write;
399 | buf += this_write;
400 | }
401 | return count;
402 | } /* SK_write() */
403 |
404 |
405 | /* SK_gets() */
406 | /*++++++++++++++++++++++++++++++++++++++
407 |
408 | This function reads from a socket, until it recieves a linefeed
409 | character. It fills the buffer "str" up to the maximum size "count".
410 |
411 | int SK_gets Returns the total_count of bytes read.
412 |
413 | int sockfd The socket file descriptor.
414 |
415 | char *str The buffer to be written from the socket.
416 |
417 | size_t count The number of bytes in the buffer.
418 |
419 |
420 | Authors:
421 | ottrey,
422 | marek (modified for meaningful error codes).
423 |
424 | Side Effects:
425 | This function will return -1 if the socket is closed during the read 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 | ++++++++++++++++++++++++++++++++++++++*/
431 | int SK_gets(int sockfd, char *str, size_t count) {
432 | int bytes_read;
433 | int total_count = 0;
434 | char *current_position;
435 | char last_read = 0;
436 |
437 | int control_c = 0;
438 |
439 | current_position = str;
440 | while (last_read != 10) {
441 |
442 | bytes_read = read(sockfd, &last_read, 1);
443 | if (bytes_read <= 0) {
444 | /* The other side may have closed unexpectedly */
445 | return SK_DISCONNECT;
446 | /* Is this effective on other platforms than linux? */
447 | }
448 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
449 | *current_position = last_read;
450 | current_position++;
451 | total_count++;
452 | }
453 |
454 | if (last_read == -1) {
455 | bytes_read = read(sockfd, &last_read, 1);
456 | if (last_read == -12) {
457 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
458 | control_c = 1;
459 | ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
460 | return SK_INTERRUPT;
461 | }
462 | }
463 | }
464 | if (count > 0) {
465 | *current_position = 0;
466 | }
467 |
468 | return total_count;
469 |
470 | } /* SK_gets() */
471 |
472 |
473 | /* SK_puts() */
474 | /*++++++++++++++++++++++++++++++++++++++
475 |
476 | This function writes a character string out to a socket.
477 |
478 | int SK_puts The total_count of bytes written,
479 | or errors (represented as negative numbers)
480 |
481 | int sockfd The socket file descriptor.
482 |
483 | char *str The buffer to be written from the socket.
484 |
485 | More:
486 | +html+ <PRE>
487 | Authors:
488 | ottrey
489 |
490 | Side Effects:
491 | This function will return -1 if the socket is closed during the write operation.
492 | +html+ </PRE>
493 |
494 | ++++++++++++++++++++++++++++++++++++++*/
495 | int SK_puts(int sockfd, const char *str) {
496 |
497 | return SK_write(sockfd, str, strlen(str));
498 |
499 | } /* SK_puts() */
500 |
501 | /* SK_putc() */
502 | /*++++++++++++++++++++++++++++++++++++++
503 |
504 | This function writes a single character out to a socket.
505 |
506 | int SK_putc Returns the number of characters written.
507 |
508 | int sockfd socket
509 |
510 | char ch character
511 |
512 | ++++++++++++++++++++++++++++++++++++++*/
513 | int SK_putc(int sockfd, char ch) {
514 | return SK_write(sockfd, &ch, 1);
515 | }/* SK_putc() */
516 |
517 | /*++++++++++++++++++++++++++++++++++++++
518 |
519 | This function reads a single character from a socket.
520 |
521 | returns EOF when no character can be read.
522 |
523 | ++++++++++++++++++++++++++++++++++++++*/
524 | int SK_getc(int sockfd) {
525 | char ch;
526 |
527 | if( read(sockfd, &ch, 1) <= 0 ) {
528 | return EOF;
529 | }
530 | else {
531 | return ch;
532 | }
533 | }/* SK_getc() */
534 |
535 | /* SK_getpeername() */
536 | /*++++++++++++++++++++++++++++++++++++++
537 |
538 | This function will tell you who is at the other end of a connected stream socket.
539 |
540 | char *SK_getpeername Returns allocated string with the IP in it,
541 | or "--" if the descriptor is not a socket,
542 | or NULL on error.
543 |
544 | int sockfd The socket or file descriptor.
545 |
546 | +html+ <PRE>
547 | Authors:
548 | ottrey,
549 | marek (modified error handling, made MT-Safe).
550 | +html+ </PRE>
551 |
552 | ++++++++++++++++++++++++++++++++++++++*/
553 | char *SK_getpeername(int sockfd)
554 | {
555 | char *hostaddress=NULL;
556 | struct sockaddr_in addr_in;
557 | int namelen=sizeof(addr_in);
558 |
559 | if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
560 |
561 | dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK);
562 | inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
563 | }
564 | else {
565 | int er = errno;
566 |
567 | if( er == ENOTSOCK ) {
568 | hostaddress = wr_string("--");
569 | }
570 | else {
571 | return NULL;
572 | }
573 | }
574 |
575 | return hostaddress;
576 |
577 | } /* SK_getpeername() */
578 |
579 |
580 | /* SK_getpeerip */
581 | /*++++++++++++++++++++++++++++++++++++++
582 |
583 | This function will check the ip of the connected peer and store it in the
584 | ip_addr_t structure defined in the IP module.
585 |
586 | int SK_getpeerip returns 0 on success, -1 on failure.
587 |
588 | int sockfd The socket descriptor (file will result in -1)
589 |
590 | ip_addr_t *ip Pointer to where the address should be stored.
591 |
592 | +html+ <PRE>
593 | Author:
594 | marek
595 | +html+ </PRE>
596 | ++++++++++++++++++++++++++++++++++++++*/
597 |
598 | int SK_getpeerip(int sockfd, ip_addr_t *ip) {
599 | struct sockaddr_in addr_in;
600 | int namelen=sizeof(addr_in);
601 | int ret=-1;
602 |
603 | memset(& addr_in, 0, sizeof(struct sockaddr_in));
604 |
605 | if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
606 | ret=0;
607 | IP_addr_s2b(ip, &addr_in, namelen);
608 | }
609 |
610 | return ret;
611 | }
612 |