5 #include <sys/types.h> |
5 #include <sys/types.h> |
6 #include <sys/socket.h> |
6 #include <sys/socket.h> |
7 #include <netdb.h> |
7 #include <netdb.h> |
8 #include <unistd.h> |
8 #include <unistd.h> |
9 #include <string.h> |
9 #include <string.h> |
10 #include <err.h> |
10 #include <assert.h> |
11 |
11 |
12 /* |
12 /* |
13 * Our sock_stream_type.methods.read implementation |
13 * Our sock_stream_methods.read method |
14 */ |
14 */ |
15 static int sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len) |
15 static err_t sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len) |
16 { |
16 { |
17 struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); |
17 struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); |
|
18 int ret; |
|
19 |
|
20 // map directly to read(2) |
|
21 if ((ret = read(sock->fd, buf, len)) < 0) |
|
22 // errno |
|
23 RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_READ); |
18 |
24 |
19 return read(sock->fd, buf, len); |
25 else |
|
26 // bytes read |
|
27 return ret; |
20 } |
28 } |
21 |
29 |
22 /* |
30 /* |
23 * Our sock_stream_type.methods.write implementation |
31 * Our sock_stream_methods.write method |
24 */ |
32 */ |
25 static int sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len) |
33 static err_t sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len) |
26 { |
34 { |
27 struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); |
35 struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp); |
|
36 int ret; |
|
37 |
|
38 // map directly to write(2) |
|
39 if ((ret = write(sock->fd, buf, len)) < 0) |
|
40 // errno |
|
41 RETURN_SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_WRITE); |
28 |
42 |
29 return write(sock->fd, buf, len); |
43 else |
|
44 // bytes read |
|
45 return ret; |
30 } |
46 } |
31 |
47 |
32 /* |
48 /* |
33 * Our sock_stream_type |
49 * Our sock_stream_type |
34 * |
|
35 * XXX: move to sock_tcp.h |
|
36 */ |
50 */ |
37 struct sock_stream_type sock_tcp_type = { |
51 struct sock_stream_type sock_tcp_type = { |
38 .methods.read = &sock_tcp_read, |
52 .methods.read = &sock_tcp_read, |
39 .methods.write = &sock_tcp_write, |
53 .methods.write = &sock_tcp_write, |
40 }; |
54 }; |
41 |
55 |
42 struct sock_tcp* sock_tcp_alloc (void) |
56 err_t sock_tcp_alloc (struct sock_tcp **sock_ptr) |
43 { |
57 { |
44 struct sock_tcp *sock; |
|
45 |
|
46 // alloc |
58 // alloc |
47 if ((sock = calloc(1, sizeof(*sock))) == NULL) |
59 if ((*sock_ptr = calloc(1, sizeof(**sock_ptr))) == NULL) |
48 errx(1, "calloc"); |
60 return ERR_CALLOC; |
49 |
61 |
50 // initialize base |
62 // initialize base with sock_tcp_type |
51 sock->base.type = &sock_tcp_type; |
63 sock_stream_init(SOCK_TCP_BASE(*sock_ptr), &sock_tcp_type); |
52 |
64 |
53 // done |
65 // done |
54 return sock; |
66 return SUCCESS; |
55 } |
67 } |
56 |
68 |
57 int sock_tcp_init_fd (struct sock_tcp *sock, int fd) |
69 err_t sock_tcp_init_fd (struct sock_tcp *sock, int fd) |
58 { |
70 { |
|
71 // valid fd -XXX: err instead? |
|
72 assert(fd >= 0); |
|
73 |
59 // initialize |
74 // initialize |
60 sock->fd = fd; |
75 sock->fd = fd; |
61 |
76 |
62 // done |
77 // done |
63 return 0; |
78 return SUCCESS; |
64 } |
79 } |
65 |
80 |
66 int sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service) |
81 err_t sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service) |
67 { |
82 { |
68 struct addrinfo hints, *res, *r; |
83 struct addrinfo hints, *res, *r; |
69 int _err; |
84 int err; |
|
85 RESET_ERROR(SOCK_TCP_ERR(sock)); |
70 |
86 |
71 // hints |
87 // hints |
72 memset(&hints, 0, sizeof(hints)); |
88 memset(&hints, 0, sizeof(hints)); |
73 hints.ai_family = AF_UNSPEC; |
89 hints.ai_family = AF_UNSPEC; |
74 hints.ai_socktype = SOCK_STREAM; |
90 hints.ai_socktype = SOCK_STREAM; |
75 |
91 |
76 // resolve |
92 // resolve |
77 if ((_err = getaddrinfo(hostname, service, &hints, &res))) |
93 if ((err = getaddrinfo(hostname, service, &hints, &res))) |
78 errx(1, "getaddrinfo: %s", gai_strerror(_err)); |
94 RETURN_SET_ERROR_EXTRA(SOCK_TCP_ERR(sock), ERR_GETADDRINFO, err); |
79 |
95 |
80 // use |
96 // try each result in turn |
81 for (r = res; r; r = r->ai_next) { |
97 for (r = res; r; r = r->ai_next) { |
82 // XXX: wrong |
98 // create the socket |
83 if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) |
99 if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0) { |
84 err(1, "socket"); |
100 // remember error |
|
101 SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_SOCKET); |
85 |
102 |
86 if (connect(sock->fd, r->ai_addr, r->ai_addrlen)) |
103 // skip to next one |
87 err(1, "connect"); |
104 continue; |
|
105 } |
|
106 |
|
107 // connect to remote address |
|
108 if (connect(sock->fd, r->ai_addr, r->ai_addrlen)) { |
|
109 // remember error |
|
110 SET_ERROR_ERRNO(SOCK_TCP_ERR(sock), ERR_CONNECT); |
|
111 |
|
112 // close/invalidate socket |
|
113 close(sock->fd); |
|
114 sock->fd = -1; |
88 |
115 |
|
116 // skip to next one |
|
117 continue; |
|
118 } |
|
119 |
|
120 // valid socket, use this |
89 break; |
121 break; |
90 } |
122 } |
91 |
123 |
92 // ensure we got some valid socket |
124 // ensure we got some valid socket, else return last error code |
93 if (sock->fd < 0) |
125 if (sock->fd < 0) { |
94 errx(1, "no valid socket"); |
126 // did we hit some error? |
|
127 if (IS_ERROR(SOCK_TCP_ERR(sock))) |
|
128 // return last error |
|
129 return ERROR_CODE(SOCK_TCP_ERR(sock)); |
|
130 |
|
131 else |
|
132 // no results |
|
133 return SET_ERROR(SOCK_TCP_ERR(sock), ERR_GETADDRINFO_EMPTY); |
|
134 } |
95 |
135 |
96 // ok, done |
136 // ok, done |
97 return 0; |
137 return 0; |
98 } |
138 } |
99 |
139 |
100 // XXX: error handling |
140 err_t sock_tcp_connect (struct sock_stream **sock_ptr, const char *host, const char *service, struct error_info *err_info) |
101 struct sock_stream* sock_tcp_connect (const char *host, const char *service) |
|
102 { |
141 { |
103 struct sock_tcp *sock; |
142 struct sock_tcp *sock; |
|
143 err_t err; |
104 |
144 |
105 // allocate |
145 // allocate |
106 sock = sock_tcp_alloc(); |
146 if ((err = sock_tcp_alloc(&sock))) |
|
147 return err; |
107 |
148 |
108 // connect |
149 // connect |
109 sock_tcp_init_connect(sock, host, service); |
150 if ((err = sock_tcp_init_connect(sock, host, service))) { |
|
151 // set *err_info |
|
152 *err_info = SOCK_TCP_ERR(sock); |
110 |
153 |
111 // done |
154 // cleanup |
112 return SOCK_TCP_BASE(sock); |
155 sock_tcp_release(sock); |
|
156 |
|
157 // return error code |
|
158 return err; |
|
159 } |
|
160 |
|
161 // good |
|
162 *sock_ptr = SOCK_TCP_BASE(sock); |
|
163 |
|
164 return 0; |
113 } |
165 } |
|
166 |
|
167 void sock_tcp_release (struct sock_tcp *sock) |
|
168 { |
|
169 // must not be connected |
|
170 assert(sock->fd < 0); |
|
171 |
|
172 // free |
|
173 free(sock); |
|
174 } |