]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * This file is provided for use with the unix-socket-faq. It is public | |
3 | * domain, and may be copied freely. There is no copyright on it. The | |
4 | * original work was by Vic Metcalfe (vic@brutus.tlug.org), and any | |
5 | * modifications made to that work were made with the understanding that | |
6 | * the finished work would be in the public domain. | |
7 | * | |
8 | * If you have found a bug, please pass it on to me at the above address | |
9 | * acknowledging that there will be no copyright on your work. | |
10 | * | |
11 | * The most recent version of this file, and the unix-socket-faq can be | |
12 | * found at http://www.interlog.com/~vic/sock-faq/. | |
13 | */ | |
14 | ||
15 | #include "sockhelp.h" | |
16 | ||
17 | /* Take a service name, and a service type, and return a port number. If | |
18 | the | |
19 | service name is not found, it tries it as a decimal number. The number | |
20 | returned is byte ordered for the network. */ | |
21 | int atoport(char *service, char *proto) | |
22 | { | |
23 | int port; | |
24 | long int lport; | |
25 | struct servent *serv; | |
26 | char *errpos; | |
27 | ||
28 | /* First try to read it from /etc/services */ | |
29 | serv = getservbyname(service, proto); | |
30 | if (serv != NULL) | |
31 | port = serv->s_port; | |
32 | else { /* Not in services, maybe a number? */ | |
33 | lport = strtol(service,&errpos,0); | |
34 | if ( (errpos[0] != 0) || (lport < 1) || (lport > 65535) ) | |
35 | return -1; /* Invalid port address */ | |
36 | port = htons(lport); | |
37 | } | |
38 | return port; | |
39 | } | |
40 | ||
41 | /* Converts ascii text to in_addr struct. NULL is returned if the address | |
42 | can not be found. */ | |
43 | struct in_addr *atoaddr(char *address) | |
44 | { | |
45 | struct hostent *host; | |
46 | static struct in_addr saddr; | |
47 | ||
48 | /* First try it as aaa.bbb.ccc.ddd. */ | |
49 | saddr.s_addr = inet_addr(address); | |
50 | if (saddr.s_addr != -1) { | |
51 | return &saddr; | |
52 | } | |
53 | host = gethostbyname(address); | |
54 | if (host != NULL) { | |
55 | return (struct in_addr *) *host->h_addr_list; | |
56 | } | |
57 | return NULL; | |
58 | } | |
59 | ||
60 | /* This function listens on a port, and returns connections. It forks | |
61 | returns off internally, so your main function doesn't have to worry | |
62 | about that. This can be confusing if you don't know what is going on. | |
63 | The function will create a new process for every incoming connection, | |
64 | so in the listening process, it will never return. Only when a | |
65 | connection | |
66 | comes in, and we create a new process for it will the function return. | |
67 | This means that your code that calls it should _not_ loop. | |
68 | ||
69 | The parameters are as follows: | |
70 | socket_type: SOCK_STREAM or SOCK_DGRAM (TCP or UDP sockets) | |
71 | port: The port to listen on. Remember that ports < 1024 are | |
72 | reserved for the root user. Must be passed in network byte | |
73 | order (see "man htons"). | |
74 | listener: This is a pointer to a variable for holding the file | |
75 | descriptor of the socket which is being used to listen. It | |
76 | is provided so that you can write a signal handler to close | |
77 | it in the event of program termination. If you aren't interested, | |
78 | just pass NULL. Note that all modern unixes will close file | |
79 | descriptors for you on exit, so this is not required. */ | |
80 | int get_connection(int socket_type, u_short port, int *listener) | |
81 | { | |
82 | struct sockaddr_in address; | |
83 | int listening_socket; | |
84 | int connected_socket = -1; | |
85 | int new_process; | |
86 | int reuse_addr = 1; | |
87 | ||
88 | /* Setup internet address information. | |
89 | This is used with the bind() call */ | |
90 | memset((char *) &address, 0, sizeof(address)); | |
91 | address.sin_family = AF_INET; | |
92 | address.sin_port = port; | |
93 | address.sin_addr.s_addr = htonl(INADDR_ANY); | |
94 | ||
95 | listening_socket = socket(AF_INET, socket_type, 0); | |
96 | if (listening_socket < 0) { | |
97 | perror("socket"); | |
98 | exit(EXIT_FAILURE); | |
99 | } | |
100 | ||
101 | if (listener != NULL) | |
102 | *listener = listening_socket; | |
103 | ||
104 | setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, | |
105 | sizeof(reuse_addr)); | |
106 | ||
107 | if (bind(listening_socket, (struct sockaddr *) &address, | |
108 | sizeof(address)) < 0) { | |
109 | perror("bind"); | |
110 | close(listening_socket); | |
111 | exit(EXIT_FAILURE); | |
112 | } | |
113 | ||
114 | if (socket_type == SOCK_STREAM) { | |
115 | listen(listening_socket, 5); /* Queue up to five connections before | |
116 | having them automatically rejected. */ | |
117 | ||
118 | while(connected_socket < 0) { | |
119 | connected_socket = accept(listening_socket, NULL, NULL); | |
120 | if (connected_socket < 0) { | |
121 | /* Either a real error occured, or blocking was interrupted for | |
122 | some reason. Only abort execution if a real error occured. */ | |
123 | if (errno != EINTR) { | |
124 | perror("accept"); | |
125 | close(listening_socket); | |
126 | exit(EXIT_FAILURE); | |
127 | } else { | |
128 | continue; /* don't fork - do the accept again */ | |
129 | } | |
130 | } | |
131 | ||
132 | new_process = fork(); | |
133 | if (new_process < 0) { | |
134 | perror("fork"); | |
135 | close(connected_socket); | |
136 | connected_socket = -1; | |
137 | } | |
138 | else { /* We have a new process... */ | |
139 | if (new_process == 0) { | |
140 | /* This is the new process. */ | |
141 | close(listening_socket); /* Close our copy of this socket */ | |
142 | if (listener != NULL) | |
143 | *listener = -1; /* Closed in this process. We are not | |
144 | responsible for it. */ | |
145 | } | |
146 | else { | |
147 | /* This is the main loop. Close copy of connected socket, and | |
148 | continue loop. */ | |
149 | close(connected_socket); | |
150 | connected_socket = -1; | |
151 | } | |
152 | } | |
153 | } | |
154 | return connected_socket; | |
155 | } | |
156 | else | |
157 | return listening_socket; | |
158 | } | |
159 | ||
160 | /* This is a generic function to make a connection to a given server/port. | |
161 | service is the port name/number, | |
162 | type is either SOCK_STREAM or SOCK_DGRAM, and | |
163 | netaddress is the host name to connect to. | |
164 | The function returns the socket, ready for action.*/ | |
165 | int make_connection(char *service, int type, char *netaddress) | |
166 | { | |
167 | /* First convert service from a string, to a number... */ | |
168 | int port = -1; | |
169 | struct in_addr *addr; | |
170 | int sock, connected; | |
171 | struct sockaddr_in address; | |
172 | ||
173 | if (type == SOCK_STREAM) | |
174 | port = atoport(service, "tcp"); | |
175 | if (type == SOCK_DGRAM) | |
176 | port = atoport(service, "udp"); | |
177 | if (port == -1) { | |
178 | fprintf(stderr,"make_connection: Invalid socket type.\n"); | |
179 | return -1; | |
180 | } | |
181 | addr = atoaddr(netaddress); | |
182 | if (addr == NULL) { | |
183 | fprintf(stderr,"make_connection: Invalid network address.\n"); | |
184 | return -1; | |
185 | } | |
186 | ||
187 | memset((char *) &address, 0, sizeof(address)); | |
188 | address.sin_family = AF_INET; | |
189 | address.sin_port = (port); | |
190 | address.sin_addr.s_addr = addr->s_addr; | |
191 | ||
192 | sock = socket(AF_INET, type, 0); | |
193 | ||
194 | printf("Connecting to %s on port %d.\n",inet_ntoa(*addr),htons(port)); | |
195 | ||
196 | if (type == SOCK_STREAM) { | |
197 | connected = connect(sock, (struct sockaddr *) &address, | |
198 | sizeof(address)); | |
199 | if (connected < 0) { | |
200 | perror("connect"); | |
201 | return -1; | |
202 | } | |
203 | return sock; | |
204 | } | |
205 | /* Otherwise, must be for udp, so bind to address. */ | |
206 | if (bind(sock, (struct sockaddr *) &address, sizeof(address)) < 0) { | |
207 | perror("bind"); | |
208 | return -1; | |
209 | } | |
210 | return sock; | |
211 | } | |
212 | ||
213 | /* This is just like the read() system call, accept that it will make | |
214 | sure that all your data goes through the socket. */ | |
215 | int sock_read(int sockfd, char *buf, size_t count) | |
216 | { | |
217 | size_t bytes_read = 0; | |
218 | int this_read; | |
219 | ||
220 | while (bytes_read < count) { | |
221 | do | |
222 | this_read = read(sockfd, buf, count - bytes_read); | |
223 | while ( (this_read < 0) && (errno == EINTR) ); | |
224 | if (this_read < 0) | |
225 | return this_read; | |
226 | else if (this_read == 0) | |
227 | return bytes_read; | |
228 | bytes_read += this_read; | |
229 | buf += this_read; | |
230 | } | |
231 | return count; | |
232 | } | |
233 | ||
234 | /* This function reads from a socket, until it recieves a linefeed | |
235 | character. It fills the buffer "str" up to the maximum size "count". | |
236 | ||
237 | This function will return -1 if the socket is closed during the read | |
238 | operation. | |
239 | ||
240 | Note that if a single line exceeds the length of count, the extra data | |
241 | will be read and discarded! You have been warned. */ | |
242 | int sock_gets(int sockfd, char *str, size_t count) | |
243 | { | |
244 | int bytes_read; | |
245 | int total_count = 0; | |
246 | char *current_position; | |
247 | char last_read = 0; | |
248 | ||
249 | current_position = str; | |
250 | while (last_read != 10) { | |
251 | bytes_read = read(sockfd, &last_read, 1); | |
252 | if (bytes_read <= 0) { | |
253 | /* The other side may have closed unexpectedly */ | |
254 | return -1; /* Is this effective on other platforms than linux? */ | |
255 | } | |
256 | if ( (total_count < count) && (last_read != 10) && (last_read !=13) ) | |
257 | { | |
258 | current_position[0] = last_read; | |
259 | current_position++; | |
260 | total_count++; | |
261 | } | |
262 | } | |
263 | if (count > 0) | |
264 | current_position[0] = 0; | |
265 | return total_count; | |
266 | } | |
267 | ||
268 | /* This is just like the write() system call, accept that it will | |
269 | make sure that all data is transmitted. */ | |
270 | int sock_write(int sockfd, const char *buf, size_t count) | |
271 | { | |
272 | size_t bytes_sent = 0; | |
273 | int this_write; | |
274 | ||
275 | while (bytes_sent < count) { | |
276 | do | |
277 | this_write = write(sockfd, buf, count - bytes_sent); | |
278 | while ( (this_write < 0) && (errno == EINTR) ); | |
279 | if (this_write <= 0) | |
280 | return this_write; | |
281 | bytes_sent += this_write; | |
282 | buf += this_write; | |
283 | } | |
284 | return count; | |
285 | } | |
286 | ||
287 | /* This function writes a character string out to a socket. It will | |
288 | return -1 if the connection is closed while it is trying to write. */ | |
289 | int sock_puts(int sockfd, const char *str) | |
290 | { | |
291 | return sock_write(sockfd, str, strlen(str)); | |
292 | } | |
293 | ||
294 | /* This ignores the SIGPIPE signal. This is usually a good idea, since | |
295 | the default behaviour is to terminate the application. SIGPIPE is | |
296 | sent when you try to write to an unconnected socket. You should | |
297 | check your return codes to make sure you catch this error! */ | |
298 | void ignore_pipe(void) | |
299 | { | |
300 | struct sigaction sig; | |
301 | ||
302 | sig.sa_handler = SIG_IGN; | |
303 | sig.sa_flags = 0; | |
304 | sigemptyset(&sig.sa_mask); | |
305 | sigaction(SIGPIPE,&sig,NULL); | |
306 | } | |
307 |