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