modules/sk/sk_socket.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- SK_atoport
- SK_close
- SK_getsock
- SK_accept_connection
- SK_connect
- SK_read
- SK_write
- SK_gets
- SK_puts
- SK_putc
- SK_getc
- SK_getpeername
- SK_getpeerip
1 /***************************************
2 $Revision: 1.15 $
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) {
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
181 int connected_socket = -1;
182 int num_errors = 0;
183
184 #define MAX_ACCEPT_ERRORS 3
185
186 for (;;) {
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 "too many accept() errors (maximum is %d)", MAX_ACCEPT_ERRORS);
214 die;
215 }
216 }
217 }
218 }
219 else { /* success */
220 ER_dbg_va(FAC_SK, ASP_SK_GEN, "client connected on socket %d",
221 connected_socket
222 );
223
224 return connected_socket;
225 }
226
227 }
228 }
229
230
231 /*++++++++++++++++++++++++++++++++++++++
232
233 er_ret_t SK_connect wrapper around connect(), doing non-blocking
234 connection with timeout
235
236 int *sock pointer to the storage for socket descriptor
237
238 char *hostname host to connect to
239
240 int port port to connect to
241
242 int timeout in seconds
243
244 Author: marek
245
246 ++++++++++++++++++++++++++++++++++++++*/
247 er_ret_t SK_connect(int *sock, char *hostname, unsigned int port, unsigned int timeout)
/* [<][>][^][v][top][bottom][index][help] */
248 {
249 struct sockaddr_in sin;
250 struct hostent *hp;
251 int s;
252 int flags;
253 struct timeval ptm;
254 fd_set rset, wset;
255 int gs, sel, er, erlen=sizeof(er);
256 int error;
257 struct hostent result;
258 char aliasbuf[8192]; /* Stevens, UNIX net. prog., p.304 */
259
260 /* look up the host name */
261 #ifdef __linux__
262 er = (gethostbyname_r(hostname, &result, aliasbuf,
263 sizeof(aliasbuf), &hp, &error) < 0 );
264 #else /* default is Solaris implementation */
265 hp = gethostbyname_r(hostname, &result, aliasbuf,
266 sizeof(aliasbuf), &error);
267 er = ( hp == NULL );
268 #endif
269
270 if( er ) {
271 return SK_BADHOST;
272 }
273
274 /* create a socket */
275 s = socket(AF_INET, SOCK_STREAM, 0);
276 if (s < 0) {
277 return SK_SOCKET;
278 }
279
280 /* bind to it */
281 bzero((caddr_t)&sin, sizeof (sin));
282 sin.sin_family = hp->h_addrtype;
283 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
284 close(s);
285 return SK_BIND;
286 }
287 bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
288 sin.sin_port=htons(port);
289
290 /* connect in non-blocking mode */
291 flags = fcntl(s, F_GETFL, 0);
292 fcntl(s, F_SETFL, flags | O_NONBLOCK );
293
294 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0
295 && errno != EINPROGRESS ) {
296 close(s);
297 return SK_CONNECT;
298 }
299
300 /* now wait for success */
301 FD_ZERO( &rset );
302 FD_SET( s, &rset );
303 wset = rset;
304 ptm.tv_usec = 0;
305 ptm.tv_sec = timeout;
306
307 if( (sel=select(s+1, &rset, &wset, NULL, &ptm)) == 0 ) {
308 /* timeout */
309 close(s);
310 return SK_TIMEOUT;
311 }
312 dieif( sel < 0 ); /* we don't expect problems with select */
313
314 gs = getsockopt(s, SOL_SOCKET, SO_ERROR, &er, &erlen);
315
316 if( gs < 0 || er ) { /* Stevens code, p.411 is exceptionally crappy */
317 close(s);
318 return SK_CONNECT;
319 } /* if error */
320
321 fcntl(s, F_SETFL, flags);
322 *sock = s;
323
324 return SK_OK;
325 }
326
327
328 /* SK_read() */
329 /*++++++++++++++++++++++++++++++++++++++
330
331 This is just like the read() system call, except that it will make
332 sure that all your data goes through the socket.
333
334 int SK_read Returns the number of bytes read.
335
336 int sockfd The socket file descriptor.
337
338 char *buf The buffer to be read from the socket.
339
340 size_t count The number of bytes in the buffer.
341
342 Author:
343 ottrey
344
345 ++++++++++++++++++++++++++++++++++++++*/
346 int SK_read(int sockfd, char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
347 size_t bytes_read = 0;
348 int this_read;
349
350 while (bytes_read < count) {
351 do
352 this_read = read(sockfd, buf, count - bytes_read);
353 while ( (this_read < 0) && (errno == EINTR) );
354 if (this_read < 0)
355 return this_read;
356 else if (this_read == 0)
357 return bytes_read;
358 bytes_read += this_read;
359 buf += this_read;
360 }
361
362 return count;
363
364 } /* SK_read() */
365
366
367 /* SK_write() */
368 /*++++++++++++++++++++++++++++++++++++++
369
370 This is just like the write() system call, except that it will
371 make sure that all data is transmitted.
372
373 int SK_write Returns the number of bytes written.
374
375 int sockfd The socket file descriptor.
376
377 char *buf The buffer to be written to the socket.
378
379 size_t count The number of bytes in the buffer.
380
381 Author:
382 ottrey
383
384 ++++++++++++++++++++++++++++++++++++++*/
385 int SK_write(int sockfd, const char *buf, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
386 size_t bytes_sent = 0;
387 int this_write;
388
389
390 ER_dbg_va(FAC_SK, ASP_SK_WRIT,
391 "SK_write = { sockfd=[%d], buf=[%s], count=[%d]",
392 sockfd, buf, count);
393
394 while (bytes_sent < count) {
395 do
396 this_write = write(sockfd, buf, count - bytes_sent);
397 while ( (this_write < 0) && (errno == EINTR) );
398 if (this_write <= 0)
399 return this_write;
400 bytes_sent += this_write;
401 buf += this_write;
402 }
403 return count;
404 } /* SK_write() */
405
406
407 /* SK_gets() */
408 /*++++++++++++++++++++++++++++++++++++++
409
410 This function reads from a socket, until it recieves a linefeed
411 character. It fills the buffer "str" up to the maximum size "count".
412
413 int SK_gets Returns the total_count of bytes read.
414
415 int sockfd The socket file descriptor.
416
417 char *str The buffer to be written from the socket.
418
419 size_t count The number of bytes in the buffer.
420
421
422 Authors:
423 ottrey,
424 marek (modified for meaningful error codes).
425
426 Side Effects:
427 This function will return -1 if the socket is closed during the read operation.
428
429 Note that if a single line exceeds the length of count, the extra data
430 will be read and discarded! You have been warned.
431
432 ++++++++++++++++++++++++++++++++++++++*/
433 int SK_gets(int sockfd, char *str, size_t count) {
/* [<][>][^][v][top][bottom][index][help] */
434 int bytes_read;
435 int total_count = 0;
436 char *current_position;
437 char last_read = 0;
438
439 int control_c = 0;
440
441 current_position = str;
442 while (last_read != 10) {
443
444 bytes_read = read(sockfd, &last_read, 1);
445 if (bytes_read <= 0) {
446 /* The other side may have closed unexpectedly */
447 return SK_DISCONNECT;
448 /* Is this effective on other platforms than linux? */
449 }
450 if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) {
451 *current_position = last_read;
452 current_position++;
453 total_count++;
454 }
455
456 if (last_read == -1) {
457 bytes_read = read(sockfd, &last_read, 1);
458 if (last_read == -12) {
459 ER_dbg_va(FAC_SK, ASP_SK_GEN,"Client pressed Control-c");
460 control_c = 1;
461 ER_dbg_va(FAC_SK, ASP_SK_GEN,"returning SK_INTERRUPT");
462 return SK_INTERRUPT;
463 }
464 }
465 }
466 if (count > 0) {
467 *current_position = 0;
468 }
469
470 return total_count;
471
472 } /* SK_gets() */
473
474
475 /* SK_puts() */
476 /*++++++++++++++++++++++++++++++++++++++
477
478 This function writes a character string out to a socket.
479
480 int SK_puts The total_count of bytes written,
481 or errors (represented as negative numbers)
482
483 int sockfd The socket file descriptor.
484
485 char *str The buffer to be written from the socket.
486
487 More:
488 +html+ <PRE>
489 Authors:
490 ottrey
491
492 Side Effects:
493 This function will return -1 if the socket is closed during the write operation.
494 +html+ </PRE>
495
496 ++++++++++++++++++++++++++++++++++++++*/
497 int SK_puts(int sockfd, const char *str) {
/* [<][>][^][v][top][bottom][index][help] */
498
499 return SK_write(sockfd, str, strlen(str));
500
501 } /* SK_puts() */
502
503 /* SK_putc() */
504 /*++++++++++++++++++++++++++++++++++++++
505
506 This function writes a single character out to a socket.
507
508 int SK_putc Returns the number of characters written.
509
510 int sockfd socket
511
512 char ch character
513
514 ++++++++++++++++++++++++++++++++++++++*/
515 int SK_putc(int sockfd, char ch) {
/* [<][>][^][v][top][bottom][index][help] */
516 return SK_write(sockfd, &ch, 1);
517 }/* SK_putc() */
518
519 /*++++++++++++++++++++++++++++++++++++++
520
521 This function reads a single character from a socket.
522
523 returns EOF when no character can be read.
524
525 ++++++++++++++++++++++++++++++++++++++*/
526 int SK_getc(int sockfd) {
/* [<][>][^][v][top][bottom][index][help] */
527 char ch;
528
529 if( read(sockfd, &ch, 1) <= 0 ) {
530 return EOF;
531 }
532 else {
533 return ch;
534 }
535 }/* SK_getc() */
536
537 /* SK_getpeername() */
538 /*++++++++++++++++++++++++++++++++++++++
539
540 This function will tell you who is at the other end of a connected stream socket.
541
542 char *SK_getpeername Returns allocated string with the IP in it,
543 or "--" if the descriptor is not a socket,
544 or NULL on error.
545
546 int sockfd The socket or file descriptor.
547
548 +html+ <PRE>
549 Authors:
550 ottrey,
551 marek (modified error handling, made MT-Safe).
552 +html+ </PRE>
553
554 ++++++++++++++++++++++++++++++++++++++*/
555 char *SK_getpeername(int sockfd)
/* [<][>][^][v][top][bottom][index][help] */
556 {
557 char *hostaddress=NULL;
558 struct sockaddr_in addr_in;
559 int namelen=sizeof(addr_in);
560
561 if (getpeername(sockfd, (struct sockaddr *)&addr_in, &namelen) == 0) {
562
563 dieif( wr_malloc((void **)&hostaddress, INET_ADDRSTRLEN) != UT_OK);
564 inet_ntop(AF_INET, &(addr_in.sin_addr), hostaddress, INET_ADDRSTRLEN);
565 }
566 else {
567 int er = errno;
568
569 if( er == ENOTSOCK ) {
570 hostaddress = wr_string("--");
571 }
572 else {
573 return NULL;
574 }
575 }
576
577 return hostaddress;
578
579 } /* SK_getpeername() */
580
581
582 /* SK_getpeerip */
583 /*++++++++++++++++++++++++++++++++++++++
584
585 This function will check the ip of the connected peer and store it in the
586 ip_addr_t structure defined in the IP module.
587
588 int SK_getpeerip returns 0 on success, -1 on failure.
589
590 int sockfd The socket descriptor (file will result in -1)
591
592 ip_addr_t *ip Pointer to where the address should be stored.
593
594 +html+ <PRE>
595 Author:
596 marek
597 +html+ </PRE>
598 ++++++++++++++++++++++++++++++++++++++*/
599
600 int SK_getpeerip(int sockfd, ip_addr_t *ip) {
/* [<][>][^][v][top][bottom][index][help] */
601 struct sockaddr_in addr_in;
602 int namelen=sizeof(addr_in);
603 int ret=-1;
604
605 memset(& addr_in, 0, sizeof(struct sockaddr_in));
606
607 if (getpeername(sockfd, (struct sockaddr *)(& addr_in), &namelen) != -1) {
608 ret=0;
609 IP_addr_s2b(ip, &addr_in, namelen);
610 }
611
612 return ret;
613 }
614