1 /*
2 * socket.c - socket utilities for the gofish gopher daemon
3 * Copyright (C) 2000,2002 Sean MacLennan <seanm@seanm.ca>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this project; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
19 */
20 /*
21 * All knowledge of sockets should be isolated to this file.
22 */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33
34 #include "gofish.h"
35
36 /* We cannot define this anywhere else */
37 static in_addr_t listen_addr = INADDR_ANY;
38
39
set_listen_address(char * addr)40 void set_listen_address(char *addr)
41 {
42 listen_addr = inet_addr(addr);
43 }
44
45
listen_socket(int port)46 int listen_socket(int port)
47 {
48 struct sockaddr_in sock_name;
49 int s, optval;
50
51 sock_name.sin_family = AF_INET;
52 sock_name.sin_addr.s_addr = listen_addr; /* already network addr */
53 sock_name.sin_port = htons(port);
54 optval = 1;
55
56 if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
57 return -1;
58
59 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
60 (char *)&optval, sizeof (optval)) == -1 ||
61 bind (s, (struct sockaddr *)&sock_name, sizeof(sock_name)) == -1 ||
62 listen(s, GOPHER_BACKLOG) == -1) {
63 close(s);
64 return -1;
65 }
66
67 if((optval = fcntl(s, F_GETFL, 0)) == -1 ||
68 fcntl(s, F_SETFL, optval | O_NONBLOCK)) {
69 close(s);
70 return -1;
71 }
72
73 return s;
74 }
75
accept_socket(int sock,unsigned * addr)76 int accept_socket(int sock, unsigned *addr)
77 {
78 struct sockaddr_in sock_name;
79 int addrlen = sizeof(sock_name);
80 int new, flags;
81
82 if((new = accept(sock, (struct sockaddr *)&sock_name, &addrlen)) < 0)
83 return -1;
84
85 if(addr) *addr = htonl(sock_name.sin_addr.s_addr);
86
87 flags = fcntl(new, F_GETFL, 0);
88 if(flags == -1 || fcntl(new, F_SETFL, flags | O_NONBLOCK) == -1) {
89 printf("fcntl failed\n");
90 close(new);
91 return -1;
92 }
93
94 flags = 1;
95 if(setsockopt(new, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags)))
96 perror("setsockopt(TCP_NODELAY)"); // not fatal
97
98 return new;
99 }
100
101
102 // network byte order
ntoa(unsigned n)103 char *ntoa(unsigned n)
104 {
105 static char a[16];
106
107 sprintf(a, "%d.%d.%d.%d",
108 (n >> 24) & 0xff,
109 (n >> 16) & 0xff,
110 (n >> 8) & 0xff,
111 n & 0xff);
112
113 return a;
114 }
115