00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: socket.c,v 1.14 2007-04-14 15:21:12 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025
00026 #include <unistd.h>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <fcntl.h>
00031 #include <errno.h>
00032
00033
00034 #ifndef SHUT_RDWR
00035 # define SHUT_RDWR 2
00036 #endif
00037
00038 #ifdef IPV6
00039 # define DO_IPV6
00040 #endif
00041 #define DO_IPV4
00042
00043 typedef struct {
00044 int len;
00045 int family;
00046 union {
00047 struct sockaddr addr;
00048 #ifdef DO_IPV4
00049 struct sockaddr_in ipv4;
00050 #endif
00051 #ifdef DO_IPV6
00052 struct sockaddr_in6 ipv6;
00053 #endif
00054 } u;
00055 } sockname_t;
00056
00057 static int socket_name(sockname_t *name, const char *ipaddr, int port)
00058 {
00059 memset(name, 0, sizeof(*name));
00060
00061 #ifdef DO_IPV4
00062 if (inet_pton(AF_INET, ipaddr, &name->u.ipv4.sin_addr) > 0) {
00063 name->len = sizeof(name->u.ipv4);
00064 name->family = PF_INET;
00065 name->u.ipv4.sin_port = htons(port);
00066 name->u.ipv4.sin_family = AF_INET;
00067 return(0);
00068 }
00069 #endif
00070
00071 #ifdef DO_IPV6
00072 if (inet_pton(AF_INET6, ipaddr, &name->u.ipv6.sin6_addr) > 0) {
00073 name->len = sizeof(name->u.ipv6);
00074 name->family = PF_INET6;
00075 name->u.ipv6.sin6_port = htons(port);
00076 name->u.ipv6.sin6_family = AF_INET6;
00077 return(0);
00078 }
00079 #endif
00080
00081
00082 name->len = sizeof(name->u.ipv4);
00083 name->family = PF_INET;
00084 name->u.ipv4.sin_port = htons(port);
00085 name->u.ipv4.sin_family = AF_INET;
00086 return(0);
00087 }
00088
00089 int socket_get_name(int sock, char **ip, int *port)
00090 {
00091 sockname_t name;
00092 socklen_t namelen;
00093
00094 if (ip) *ip = NULL;
00095 if (port) *port = 0;
00096
00097 #ifdef DO_IPV4
00098 namelen = sizeof(name.u.ipv4);
00099 if (!getsockname(sock, &name.u.addr, &namelen) && namelen == sizeof(name.u.ipv4)) {
00100 if (ip) {
00101 *ip = malloc(32);
00102 inet_ntop(AF_INET, &name.u.ipv4.sin_addr, *ip, 32);
00103 }
00104 if (port) *port = ntohs(name.u.ipv4.sin_port);
00105 return(0);
00106 }
00107 #endif
00108 #ifdef DO_IPV6
00109 namelen = sizeof(name.u.ipv6);
00110 if (!getsockname(sock, &name.u.addr, &namelen) && namelen == sizeof(name.u.ipv6)) {
00111 if (ip) {
00112 *ip = malloc(128);
00113 if (IN6_IS_ADDR_V4MAPPED((&name.u.ipv6.sin6_addr))) {
00114 unsigned int ipv4part = 0;
00115 memcpy(&ipv4part, &name.u.ipv6.sin6_addr.s6_addr[12], 4);
00116 inet_ntop(AF_INET, &ipv4part, *ip, 128);
00117 }
00118 else {
00119 inet_ntop(AF_INET6, &name.u.ipv6.sin6_addr, *ip, 128);
00120 }
00121 }
00122 if (port) *port = ntohs(name.u.ipv6.sin6_port);
00123 return(0);
00124 }
00125 #endif
00126
00127 return(-1);
00128 }
00129
00130 int socket_get_peer_name(int sock, char **peer_ip, int *peer_port)
00131 {
00132 sockname_t name;
00133 socklen_t namelen;
00134
00135 if (peer_ip) *peer_ip = NULL;
00136 if (peer_port) *peer_port = 0;
00137
00138 #ifdef DO_IPV4
00139 namelen = sizeof(name.u.ipv4);
00140 if (!getpeername(sock, &name.u.addr, &namelen) && namelen == sizeof(name.u.ipv4)) {
00141 if (peer_ip) {
00142 *peer_ip = malloc(32);
00143 inet_ntop(AF_INET, &name.u.ipv4.sin_addr, *peer_ip, 32);
00144 }
00145 if (peer_port) *peer_port = ntohs(name.u.ipv4.sin_port);
00146 return(0);
00147 }
00148 #endif
00149 #ifdef DO_IPV6
00150 namelen = sizeof(name.u.ipv6);
00151 if (!getpeername(sock, &name.u.addr, &namelen) && namelen == sizeof(name.u.ipv6)) {
00152 if (peer_ip) {
00153 *peer_ip = malloc(128);
00154 inet_ntop(AF_INET6, &name.u.ipv6.sin6_addr, *peer_ip, 128);
00155 }
00156 if (peer_port) *peer_port = ntohs(name.u.ipv6.sin6_port);
00157 return(0);
00158 }
00159 #endif
00160
00161 return(-1);
00162 }
00163
00164 int socket_get_error(int sock)
00165 {
00166 int err;
00167 socklen_t size;
00168
00169 if (sock < 0) return(0);
00170
00171 size = sizeof(int);
00172 err = 0;
00173 getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &size);
00174 return(err);
00175 }
00176
00177 int socket_accept(int sock, char **peer_ip, int *peer_port)
00178 {
00179 int newsock;
00180 sockname_t name;
00181 socklen_t len;
00182
00183 *peer_ip = NULL;
00184 *peer_port = 0;
00185 memset(&name, 0, sizeof(name));
00186 len = sizeof(name.u);
00187 newsock = accept(sock, &name.u.addr, &len);
00188 #ifdef DO_IPV4
00189 if (len == sizeof(name.u.ipv4)) {
00190 *peer_ip = malloc(32);
00191 *peer_port = ntohs(name.u.ipv4.sin_port);
00192 inet_ntop(AF_INET, &name.u.ipv4.sin_addr, *peer_ip, 32);
00193 }
00194 #endif
00195 #ifdef DO_IPV6
00196 if (len == sizeof(name.u.ipv6)) {
00197 *peer_ip = malloc(128);
00198 *peer_port = ntohs(name.u.ipv6.sin6_port);
00199 if (IN6_IS_ADDR_V4MAPPED((&name.u.ipv6.sin6_addr))) {
00200 unsigned int ipv4part = 0;
00201 memcpy(&ipv4part, &name.u.ipv6.sin6_addr.s6_addr[12], 4);
00202 inet_ntop(AF_INET, &ipv4part, *peer_ip, 128);
00203 }
00204 else {
00205 inet_ntop(AF_INET6, &name.u.ipv6.sin6_addr, *peer_ip, 128);
00206 }
00207 }
00208 #endif
00209 return(newsock);
00210 }
00211
00212
00213
00214
00215
00216
00217 int socket_create(const char *dest_ip, int dest_port, const char *src_ip, int src_port, int flags)
00218 {
00219 char *passive[] = {"::", "0.0.0.0"};
00220 int sock = -1, pfamily, try;
00221 sockname_t dest_name, src_name;
00222
00223
00224 for (try = 0; try < 2; try++) {
00225
00226 socket_name(&dest_name, dest_ip ? dest_ip : passive[try], dest_port);
00227 socket_name(&src_name, src_ip ? src_ip : passive[try], src_port);
00228
00229 if (src_ip || src_port) flags |= SOCKET_BIND;
00230
00231 if (flags & SOCKET_CLIENT) pfamily = dest_name.family;
00232 else if (flags & SOCKET_SERVER) pfamily = src_name.family;
00233 else {
00234 errno = EADDRNOTAVAIL;
00235 return(-1);
00236 }
00237
00238
00239 if (flags & SOCKET_UDP) sock = socket(pfamily, SOCK_DGRAM, 0);
00240 else sock = socket(pfamily, SOCK_STREAM, 0);
00241
00242 if (sock >= 0) break;
00243 }
00244
00245 if (sock < 0) return(-2);
00246
00247 if (flags & SOCKET_NONBLOCK) socket_set_nonblock(sock, 1);
00248
00249
00250 if (flags & (SOCKET_SERVER|SOCKET_BIND)) {
00251 int yes = 1;
00252
00253 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
00254 if (bind(sock, &src_name.u.addr, src_name.len) != 0) {
00255 close(sock);
00256 return(-3);
00257 }
00258 if (flags & SOCKET_SERVER) listen(sock, 50);
00259 }
00260
00261 if (flags & SOCKET_CLIENT) {
00262 if (connect(sock, &dest_name.u.addr, dest_name.len) != 0) {
00263 if (errno != EINPROGRESS) {
00264 close(sock);
00265 return(-4);
00266 }
00267 }
00268 }
00269
00270 errno = 0;
00271
00272
00273 return(sock);
00274 }
00275
00276 int socket_close(int sock)
00277 {
00278 shutdown(sock, SHUT_RDWR);
00279 close(sock);
00280 return(0);
00281 }
00282
00283 int socket_set_nonblock(int sock, int value)
00284 {
00285 int oldflags = fcntl(sock, F_GETFL, 0);
00286 if (oldflags == -1) return -1;
00287 if (value != 0) oldflags |= O_NONBLOCK;
00288 else oldflags &= ~O_NONBLOCK;
00289
00290 return fcntl(sock, F_SETFL, oldflags);
00291 }
00292
00293 int socket_valid_ip(const char *ip)
00294 {
00295 char buf[512];
00296
00297 #ifdef DO_IPV6
00298 if (inet_pton(AF_INET6, ip, buf) > 0) return(1);
00299 #endif
00300 #ifdef DO_IPV4
00301 if (inet_pton(AF_INET, ip, buf) > 0) return(1);
00302 #endif
00303 return(0);
00304 }
00305
00306 int socket_ip_to_uint(const char *ip, unsigned int *longip)
00307 {
00308 struct in_addr addr;
00309
00310 inet_pton(AF_INET, ip, &addr);
00311 *longip = htonl(addr.s_addr);
00312 return(0);
00313 }
00314
00315
00316
00317 int socket_ipv6_to_dots(const char *ip, char *dots)
00318 {
00319 #ifndef DO_IPV6
00320 dots[0] = 0;
00321 return(-1);
00322 #else
00323 struct in6_addr buf;
00324
00325 dots[0] = 0;
00326 if (inet_pton(AF_INET6, ip, &buf) <= 0) return(-1);
00327 sprintf(dots, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x",
00328 buf.s6_addr[0] >> 4, buf.s6_addr[0] & 0xf,
00329 buf.s6_addr[1] >> 4, buf.s6_addr[1] & 0xf,
00330 buf.s6_addr[2] >> 4, buf.s6_addr[2] & 0xf,
00331 buf.s6_addr[3] >> 4, buf.s6_addr[3] & 0xf,
00332 buf.s6_addr[4] >> 4, buf.s6_addr[4] & 0xf,
00333 buf.s6_addr[5] >> 4, buf.s6_addr[5] & 0xf,
00334 buf.s6_addr[6] >> 4, buf.s6_addr[6] & 0xf,
00335 buf.s6_addr[7] >> 4, buf.s6_addr[7] & 0xf,
00336 buf.s6_addr[8] >> 4, buf.s6_addr[8] & 0xf,
00337 buf.s6_addr[9] >> 4, buf.s6_addr[9] & 0xf,
00338 buf.s6_addr[10] >> 4, buf.s6_addr[10] & 0xf,
00339 buf.s6_addr[11] >> 4, buf.s6_addr[11] & 0xf,
00340 buf.s6_addr[12] >> 4, buf.s6_addr[12] & 0xf,
00341 buf.s6_addr[13] >> 4, buf.s6_addr[13] & 0xf,
00342 buf.s6_addr[14] >> 4, buf.s6_addr[14] & 0xf,
00343 buf.s6_addr[15] >> 4, buf.s6_addr[15] & 0xf
00344 );
00345 return(0);
00346 #endif
00347 }