1a1b8620cde1164918076ac6831ee55bc6718c31
[matches/MCTX3420.git] / rpi / network.c
1 #include "network.h"
2 #include <assert.h>
3 #include <errno.h>
4 #include <sys/select.h>
5 #include "log.h"
6
7 #define h_addr h_addr_list[0]
8
9
10
11
12
13 int Network_get_port(int sfd)
14 {
15         static struct sockaddr_in sin;
16         static socklen_t len = sizeof(struct sockaddr_in);
17
18         if (getsockname(sfd, (struct sockaddr *)&sin, &len) != 0)
19                  error("Network_port", "getsockname : %s", strerror(errno));
20         return ntohs(sin.sin_port);
21 }
22
23 int Network_server_bind(int port, int * bound)
24 {
25         int sfd = socket(PF_INET, SOCK_STREAM, 0);
26         if (sfd < 0)
27         {
28                 error("Network_server", "Creating socket on port %d : %s", port, strerror(errno));
29         }
30
31         struct   sockaddr_in name;
32
33         name.sin_family = AF_INET;
34         name.sin_addr.s_addr = htonl(INADDR_ANY);
35         name.sin_port = htons(port);
36
37         if (bind( sfd, (struct sockaddr *) &name, sizeof(name) ) < 0)
38         {
39                 error("Network_server", "Binding socket on port %d : %s", port, strerror(errno));
40         }
41
42         if (bound != NULL)
43                 *bound = Network_get_port(sfd);
44         return sfd;     
45 }
46
47 int Network_server_listen(int sfd, char * addr)
48 {
49         int port = Network_get_port(sfd);
50         if (listen(sfd, 1) < 0)
51         {
52                 error("Network_server", "Listening on port %d : %s", port, strerror(errno));
53         }
54         
55         int psd;
56         if (addr == NULL)
57                 psd = accept(sfd, 0, 0);
58         else
59         {
60                 struct  sockaddr_in client;
61                 struct  hostent *hp;
62
63                 client.sin_family = AF_INET;
64                 hp = gethostbyname(addr);
65                 bcopy ( hp->h_addr, &(client.sin_addr.s_addr), hp->h_length);
66                 client.sin_port = htons(port);
67                 socklen_t len = sizeof(client);
68
69                 psd = accept(sfd, (struct sockaddr*)&client, &len);
70         }
71         //close(sfd); // don't close the bind socket here; we might want to reuse the port
72         assert(psd >= 0);
73         return psd;
74 }
75
76 int Network_server(char * addr, int port)
77 {
78         int bind = Network_server_bind(port, &port);
79         int sfd = Network_server_listen(bind, addr);
80         close(bind); // won't be able to reuse the port (it goes into TIME_WAIT)
81         return sfd;
82 }
83
84 int Network_client(const char * addr, int port, int timeout)
85 {
86         int sfd = socket(PF_INET, SOCK_STREAM, 0);
87
88         //log_print(2, "Network_client", "Created socket");
89         long arg = fcntl(sfd, F_GETFL, NULL);
90         arg |= O_NONBLOCK;
91         fcntl(sfd, F_SETFL, arg);
92
93         if (sfd < 0)
94         {
95                 error("Network_client", "Creating socket for address %s:%d : %s", addr, port, strerror(errno));
96         }
97         struct  sockaddr_in server;
98         struct  hostent *hp;
99
100
101         server.sin_family = AF_INET;
102         hp = gethostbyname(addr);
103         if (hp == NULL)
104         {
105                 error("Network_client", "Can't get host by name %s", addr);
106         }
107         bcopy ( hp->h_addr, &(server.sin_addr.s_addr), hp->h_length);
108         server.sin_port = htons(port);
109
110
111         int res = connect(sfd, (struct sockaddr *) &server, sizeof(server));
112         
113
114         if (res < 0 && errno == EINPROGRESS)
115         {
116                 
117                 fd_set writeSet;
118                 FD_ZERO(&writeSet);
119                 FD_SET(sfd, &writeSet);
120
121                 struct timeval tv;
122                 tv.tv_sec = timeout;
123                 tv.tv_usec = 0;
124
125                 struct timeval * tp;
126                 tp = (timeout < 0) ? NULL : &tv;
127                 
128                 int err = select(sfd+1, NULL, &writeSet, NULL, tp);
129                 
130                 if (err == 0)
131                 {
132                         error("Network_client", "Timed out trying to connect to %s:%d after %d seconds", addr, port, timeout);
133                 }
134                 else if (err < 0)
135                 {
136                         error("Network_client", "Connecting to %s:%d - Error in select(2) call : %s", addr, port, strerror(errno));
137                 }
138                 else if (FD_ISSET(sfd, &writeSet))
139                 {
140                         int so_error;
141                         socklen_t len = sizeof so_error;
142                         getsockopt(sfd, SOL_SOCKET, SO_ERROR, &so_error, &len);
143                         if (so_error != 0)
144                         {
145                                 error("Network_client", "Connecting to %s:%d : %s", addr, port, strerror(so_error));
146                         }
147                 }
148                 else
149                 {
150                         error("Network_client", "select(2) returned %d but the socket is not writable!?", err);
151                 }
152         }
153         else
154         {
155                 error("Network_client", "Connecting to %s:%d : %s", addr, port, strerror(errno));
156         }
157
158         arg = fcntl(sfd, F_GETFL, NULL);
159         arg &= (~O_NONBLOCK);
160         fcntl(sfd, F_SETFL, arg);
161         
162         
163         
164         return sfd;
165 }
166
167 void Network_close(int sfd)
168 {
169         if (shutdown(sfd, 2) != 0)
170         {
171                 error("Network_close", "Closing socket : %s", strerror(errno));
172         }
173         close(sfd);
174 }

UCC git Repository :: git.ucc.asn.au