Browse code

Implement the ipv4 part of socklib. Still lacking the sselect functions implementations.

Dario Rodriguez authored on 28/05/2014 12:11:17
Showing 2 changed files
... ...
@@ -6,36 +6,216 @@
6 6
  * History:
7 7
  *      28/01/2014 Creation
8 8
  *      27/05/2014 New API.
9
+ *      28/05/2014 Implement the ipv4_* functions.
9 10
  *
10 11
  * Author: Dario Rodriguez dario@softhome.net
11 12
  * This file is licensed under the terms of the GNU LGPL v2+
12 13
  */
13 14
 
14 15
 #include <stdlib.h>
16
+#include <unistd.h>
15 17
 #include <string.h>
16 18
 #include <netdb.h>
19
+#include <errno.h>
20
+#include <fcntl.h>
17 21
 #include <netinet/in.h>
22
+#include <netinet/tcp.h>
18 23
 #include <sys/types.h>
19 24
 #include <sys/socket.h>
20 25
 #include <sys/select.h>
26
+#include <sys/ioctl.h>
21 27
 
22 28
 #include "socklib.h"
23 29
 
24 30
 typedef struct _sselect {
25
-        int dummy
31
+        int dummy;
26 32
 } _sselect;
27 33
 
28
-char *ipv4_genip(char *hostname, long *resulthostsize);
29
-int ipv4_genport(char *portname, int fallback);
30
-int ipv4_preconnect(char *host, long hostsize, int port); /* setup socket, set non-blocking, connect(2) call */
31
-int ipv4_connect(int fd); /* tests writeability */
32
-int ipv4_postconnect(int fd); /* hopefully connect(2) suceeded, set blocking */
33
-int ipv4_server(int port);
34
-int ipv4_serverbinded(char *host, long hostsize, int port);
35
-int sock_accept(int fd);
36
-int sock_getinfo(int socket, int *iplen, char *ip, int *port); /* ip must be at least 16 bytes to have room for an ipv6 address */
37
-int sock_queued(int socket);
38
-int sock_setblocking(int socket, int block);
34
+
35
+#ifndef FILLTV
36
+#define FILLTV(tv,sec,usec) tv.tv_sec=sec,tv.tv_usec=usec
37
+#endif
38
+
39
+#ifndef FILLIPV4ADDR
40
+#define FILLIPV4ADDR(a,family,addr,port) \
41
+                memset(&(a),0,sizeof(struct sockaddr_in)),\
42
+                s.sin_family=family,\
43
+                s.sin_addr.s_addr=addr,\
44
+                s.sin_port=htons(port)
45
+#endif
46
+
47
+char *
48
+ipv4_genip(char *hostname, long *resulthostsize)
49
+{
50
+        struct addrinfo hints,*ai;
51
+        struct sockaddr_in *in;
52
+        char *host;
53
+        memset(&hints,0,sizeof(hints));
54
+        hints.ai_family=AF_INET;
55
+        if(getaddrinfo(hostname,NULL,&hints,&ai)!=0)
56
+                return(NULL);
57
+        in=(struct sockaddr_in *)ai->ai_addr;
58
+        if(in==NULL || (host=malloc(ai->ai_addrlen))==NULL) {
59
+                freeaddrinfo(ai),ai=NULL;
60
+                return(NULL);
61
+        }
62
+        memcpy(host,ai->ai_addr,ai->ai_addrlen);
63
+        *resulthostsize=ai->ai_addrlen;
64
+        freeaddrinfo(ai),ai=NULL;
65
+        return(host);
66
+}
67
+
68
+int
69
+ipv4_genport(char *portname, int fallback)
70
+{
71
+        struct addrinfo hints,*ai;
72
+        struct sockaddr_in *in;
73
+        char port;
74
+        if(*portname>='0' && *portname<='9')
75
+                return(atoi(portname));
76
+        memset(&hints,0,sizeof(hints));
77
+        hints.ai_family=AF_INET;
78
+        if(getaddrinfo(NULL,portname,&hints,&ai)!=0)
79
+                return(fallback);
80
+        if((in=((struct sockaddr_in *)ai->ai_addr))==NULL) {
81
+                freeaddrinfo(ai),ai=NULL;
82
+                return(fallback);
83
+        }
84
+        port=ntohs(in->sin_port);
85
+        freeaddrinfo(ai),ai=NULL;
86
+        return(port);
87
+}
88
+
89
+int
90
+ipv4_preconnect(char *host, long hostsize, int port) /* setup socket, set non-blocking, connect(2) call */
91
+{
92
+        struct sockaddr_in c,s;
93
+        int fd;
94
+        int res,err;
95
+        FILLIPV4ADDR(c,AF_INET,htonl(INADDR_ANY),0);
96
+        FILLIPV4ADDR(c,AF_INET,htonl(INADDR_ANY),port);
97
+        memcpy(&(s.sin_addr.s_addr),host,hostsize);
98
+        if((fd=socket(AF_INET,SOCK_STREAM,0 /* any protocol */))==-1)
99
+                return(-1);
100
+        if(bind(fd,(struct sockaddr *)&c,sizeof(c))!=0) {
101
+                close(fd),fd=-1;
102
+                return(-1);
103
+        }
104
+        sock_setblocking(fd,0);
105
+        res=connect(fd,(struct sockaddr *)&s,sizeof(s));
106
+        err=errno;
107
+        if(res==-1 && err!=EINPROGRESS) {
108
+                close(fd),fd=-1;
109
+                return(-1);
110
+        }
111
+        return(fd);
112
+}
113
+
114
+int
115
+ipv4_connect(int fd, long timeoutmsec) /* tests writeability */
116
+{
117
+        struct timeval tv;
118
+        fd_set wset;
119
+        FILLTV(tv,timeoutmsec/1000L,(timeoutmsec%(1000L))*1000L);
120
+        FD_ZERO(&wset);
121
+        FD_SET(fd,&wset);
122
+        if(select(fd+1,NULL,&wset,NULL,&tv)>0)
123
+                return(0);
124
+        return(-1);
125
+}
126
+
127
+int
128
+ipv4_postconnect(int fd) /* hopefully connect(2) suceeded, set blocking */
129
+{
130
+        sock_setblocking(fd,1);
131
+        return(0);
132
+}
133
+
134
+int
135
+ipv4_server(int port)
136
+{
137
+        return(ipv4_serverbinded(NULL,0,port));
138
+}
139
+
140
+int
141
+ipv4_serverbinded(char *host, long hostsize, int port)
142
+{
143
+        struct sockaddr_in s;
144
+        int fd;
145
+        if((fd=socket(AF_INET,SOCK_STREAM,0 /* any protocol */))==-1)
146
+                return(-1);
147
+        FILLIPV4ADDR(s,AF_INET,htonl(INADDR_ANY),port);
148
+        if(host!=NULL)
149
+                memcpy(&(s.sin_addr.s_addr),host,hostsize);
150
+        if(bind(fd,(struct sockaddr *)&s,sizeof(s))!=0) {
151
+                close(fd),fd=-1;
152
+                return(-1);
153
+        }
154
+        if(listen(fd,4)==-1) {
155
+                close(fd),fd=-1;
156
+                return(-1);
157
+        }
158
+        return(fd);
159
+}
160
+
161
+int
162
+sock_accept(int fd)
163
+{
164
+        int newfd;
165
+        struct sockaddr_in s;
166
+        socklen_t slen;
167
+        slen=sizeof(s);
168
+        if(fd==-1 || (newfd=accept(fd,(struct sockaddr *)&s,&slen))==-1)
169
+                return(-1);
170
+        return(newfd);
171
+}
172
+
173
+int
174
+sock_getinfo(int fd, int *iplen, char *ip, int *port) /* ip must be at least 16 bytes to have room for an ipv6 address */
175
+{
176
+        struct sockaddr c;
177
+        struct sockaddr_in *c4;
178
+        struct sockaddr_in6 *c6;
179
+        socklen_t clen;
180
+        if(fd==-1)
181
+                return(-1);
182
+        clen=sizeof(c);
183
+        if(getsockname(fd,(struct sockaddr *)&c,&clen)==-1)
184
+                return(-1);
185
+        if(c.sa_family!=AF_INET && c.sa_family!=AF_INET6)
186
+                return(-1);
187
+        if(c.sa_family==AF_INET) {
188
+                c4=(struct sockaddr_in *) &c;
189
+                *iplen=sizeof(c4->sin_addr.s_addr);
190
+                memcpy(ip,&(c4->sin_addr.s_addr),*iplen);
191
+                *port=ntohs(c4->sin_port);
192
+        } else {
193
+                c6=(struct sockaddr_in6 *) &c;
194
+                *iplen=sizeof(c6->sin6_addr);
195
+                memcpy(ip,&(c6->sin6_addr),*iplen);
196
+                *port=ntohs(c6->sin6_port);
197
+        }
198
+        return(0);
199
+}
200
+
201
+int
202
+sock_queued(int fd)
203
+{
204
+        int n;
205
+        if(ioctl(fd,FIONREAD,&n)!=0)
206
+                return(-1);
207
+        return(n);
208
+}
209
+
210
+int
211
+sock_setblocking(int fd, int block)
212
+{
213
+        int fl;
214
+        if((fl=fcntl(fd,F_GETFL,0))==-1)
215
+                return(-1);
216
+        fl=(block)?(fl&(~O_NONBLOCK)):(fl|O_NONBLOCK);
217
+        return(fcntl(fd,F_SETFL,fl));
218
+}
39 219
 
40 220
 sselect *sselect_init(void);
41 221
 int sselect_reset(sselect *ssel);
... ...
@@ -43,7 +223,29 @@ int sselect_addread(sselect *ssel, int fd);
43 223
 int sselect_addwrite(sselect *ssel, int fd);
44 224
 int sselect_delread(sselect *ssel, int fd);
45 225
 int sselect_delwrite(sselect *ssel, int fd);
46
-int sselect_wait(sslect *ssel, int ms);
226
+int sselect_wait(sselect *ssel, int ms);
47 227
 int sselect_getread(sselect *ssel, int *fds, int sizefds);
48 228
 int sselect_getwrite(sselect *ssel, int *fds, int sizefds);
49 229
 
230
+
231
+/* aux functions */
232
+void
233
+sock_setfast(int fd)
234
+{
235
+        int val;
236
+        val=1;
237
+        setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,(void *)&val,sizeof(val));
238
+}
239
+
240
+void
241
+sock_setunsafe(int fd)
242
+{
243
+        int val;
244
+        struct linger ltime;
245
+        val=1;
246
+        setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(void *)&val,sizeof(val));
247
+        ltime.l_onoff=1;
248
+        ltime.l_linger=0;
249
+        setsockopt(fd,SOL_SOCKET,SO_LINGER,(void *)&ltime,sizeof(ltime));
250
+}
251
+
... ...
@@ -24,19 +24,19 @@
24 24
 #ifndef SOCKLIB_H
25 25
 #define SOCKLIB_H
26 26
 
27
-typedef sselect void;
27
+typedef void sselect;
28 28
 
29 29
 char *ipv4_genip(char *hostname, long *resulthostsize);
30 30
 int ipv4_genport(char *portname, int fallback);
31 31
 int ipv4_preconnect(char *host, long hostsize, int port); /* setup socket, set non-blocking, connect(2) call */
32
-int ipv4_connect(int fd); /* tests writeability */
32
+int ipv4_connect(int fd, long timeoutmsec); /* tests writeability */
33 33
 int ipv4_postconnect(int fd); /* hopefully connect(2) suceeded, set blocking */
34 34
 int ipv4_server(int port);
35 35
 int ipv4_serverbinded(char *host, long hostsize, int port);
36 36
 int sock_accept(int fd);
37
-int sock_getinfo(int socket, int *iplen, char *ip, int *port); /* ip must be at least 16 bytes to have room for an ipv6 address */
38
-int sock_queued(int socket);
39
-int sock_setblocking(int socket, int block);
37
+int sock_getinfo(int fd, int *iplen, char *ip, int *port); /* ip must be at least 16 bytes to have room for an ipv6 address */
38
+int sock_queued(int fd);
39
+int sock_setblocking(int fd, int block);
40 40
 
41 41
 sselect *sselect_init(void);
42 42
 int sselect_reset(sselect *ssel);
... ...
@@ -44,7 +44,11 @@ int sselect_addread(sselect *ssel, int fd);
44 44
 int sselect_addwrite(sselect *ssel, int fd);
45 45
 int sselect_delread(sselect *ssel, int fd);
46 46
 int sselect_delwrite(sselect *ssel, int fd);
47
-int sselect_wait(sslect *ssel, int ms);
47
+int sselect_wait(sselect *ssel, int ms);
48 48
 int sselect_getread(sselect *ssel, int *fds, int sizefds);
49 49
 int sselect_getwrite(sselect *ssel, int *fds, int sizefds);
50
+
51
+void sock_setfast(int fd); /* mark as low-bandwidth interactive stream */
52
+void sock_setunsafe(int fd); /* for server sockets, configure reuseaddress, linger: only suitable for intranet usage */
53
+
50 54
 #endif