OSDN Git Service

Experimental: support ipv6.
[ntch/develop.git] / src / net / nt_socket.c
1 /* Copyright 2013 Akira Ohta (akohta001@gmail.com)
2     This file is part of ntch.
3
4     The ntch is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8
9     The ntch is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with ntch.  If not, see <http://www.gnu.org/licenses/>.
16     
17 */
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <iconv.h>
24 #include <arpa/inet.h>
25 #include <netdb.h>
26 #include <unistd.h>
27 #include <assert.h>
28
29 #include "utils/nt_std_t.h"
30 #include "net/nt_socket.h"
31
32 void nt_socket_free(nt_socket_tp socketp)
33 {
34         free(socketp);
35 }
36
37 nt_socket_tp nt_socket_init(int port, char *addr)
38 {
39 #ifdef NT_NET_IPV6
40         struct addrinfo addr_limit;
41         struct addrinfo *addr_out, *addr_list;
42         struct sockaddr_in  *s_addr;
43         struct sockaddr_in6 *s_addr6;
44         
45 #else
46         struct hostent *hostinfo;
47 #endif
48
49         nt_socket_tp ptr = malloc(sizeof(nt_socket_t));
50         if(ptr == NULL)
51                 return NULL;
52                 
53         ptr->h_mutex = nt_mutex_get_one_time_handle(NT_MUTEX_ROOT_NAME_NET);
54         if(!ptr->h_mutex){
55                 free(ptr);
56                 return NULL;
57         }
58         if(!nt_mutex_add_mbs_moniker(ptr->h_mutex, addr)){
59                 free(ptr);
60                 return NULL;
61         }
62         
63         ptr->_sockaddr_in.sin_port = htons(port);
64         
65 #ifdef NT_NET_IPV6
66         memset(&addr_limit, 0, sizeof(addr_limit));
67         addr_limit.ai_family = AF_UNSPEC;
68         addr_limit.ai_socktype = SOCK_STREAM;
69         addr_limit.ai_protocol = IPPROTO_TCP;
70         if(0 != getaddrinfo(addr, NULL, &addr_limit, &addr_out)){
71                 free(ptr);
72                 return NULL;
73         }
74         
75         for(addr_list = addr_out; addr_list != NULL; 
76                                 addr_list = addr_list->ai_next){
77                 if(!addr_list->ai_addr)
78                         continue;
79                 switch(addr_list->ai_family){
80                 case AF_INET:
81                         assert(addr_list->ai_addrlen == sizeof(struct sockaddr_in));
82                         ptr->addr_family = AF_INET;
83                         s_addr = (struct sockaddr_in*)addr_list->ai_addr;
84                         ptr->_sockaddr_in.sin_family = AF_INET;
85                         memcpy(&ptr->_sockaddr_in.sin_addr.s_addr, 
86                                         &s_addr->sin_addr.s_addr, sizeof(struct in_addr));
87                         return ptr;
88                 case AF_INET6:
89                         assert(addr_list->ai_addrlen == sizeof(struct sockaddr_in6));
90                         ptr->addr_family = AF_INET6;
91                         s_addr6 = (struct sockaddr_in6*)addr_list->ai_addr;
92                         ptr->_sockaddr_in6.sin6_family = AF_INET6;
93                         memcpy(&ptr->_sockaddr_in6.sin6_addr.s6_addr, 
94                                         s_addr6->sin6_addr.s6_addr, sizeof(struct in6_addr));
95                         return ptr;
96                 }
97         }
98         freeaddrinfo(addr_out);
99 #else
100         ptr->_sockaddr_in.sin_family = AF_INET;
101         ptr->_sockaddr_in.sin_addr.s_addr = inet_addr(addr);
102         if(ptr->_sockaddr_in.sin_addr.s_addr == 0xffffffff){
103                 hostinfo = gethostbyname(addr);
104                 if(NULL == hostinfo)
105                         return NULL;
106                 if(hostinfo->h_addrtype != AF_INET)
107                         return NULL;
108                 if(hostinfo->h_addr_list[0] == NULL)
109                         return NULL;
110                 memcpy(&ptr->_sockaddr_in.sin_addr.s_addr, 
111                                 hostinfo->h_addr_list[0], 4);
112         }
113 #endif
114         return ptr;
115 }
116
117 int nt_socket_connect(nt_socket_tp socketp, char* data, int data_len)
118 {
119         int sockfd;
120         int len;
121         int result;
122
123 #ifdef NT_NET_IPV6
124         switch(socketp->addr_family){
125         case AF_INET:
126                 len = sizeof(socketp->_sockaddr_in);
127                 break;
128         case AF_INET6:
129                 len = sizeof(socketp->_sockaddr_in6);
130                 break;
131         default:
132                 assert(0);
133         }
134         sockfd = socket(socketp->addr_family, SOCK_STREAM, 0);
135         if(sockfd == -1)
136                 return -1;
137         
138 #else   
139         sockfd = socket(AF_INET, SOCK_STREAM, 0);
140         if(sockfd == -1)
141                 return -1;
142         
143         len = sizeof(socketp->_sockaddr_in);
144 #endif
145         nt_mutex_lock(socketp->h_mutex);
146         result = connect(sockfd, 
147                         (struct sockaddr *)&(socketp->_sockaddr_in), len);
148         nt_mutex_unlock(socketp->h_mutex);
149         if(result == -1){
150                 close(sockfd);
151                 return -1;
152         }
153
154         result = write(sockfd, data, data_len);
155         if(result == -1){
156                 close(sockfd);
157                 return -1;
158         }
159         return sockfd;
160 }