82a40dcbe4e2cb3ac54012d7de9287e3e7337641
[libfirm] / ir / net / firmnet.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   TCP/IP handling (Windows and Unix like systems)
23  * @author  Christian Wuerdig, implementation copied from liblpp created by Sebastian Hack
24  * @date    17.11.2006
25  * @version $Id$
26  */
27
28 #include "config.h" /* HAVE_CONFIG_H */
29
30 #include "firmnet_t.h"
31
32 #ifdef _WIN32
33 static int winsock_init(void) {
34         WORD wVersionRequested;
35         WSADATA wsaData;
36         int err;
37
38         wVersionRequested = MAKEWORD( 2, 2 );
39
40         err = WSAStartup( wVersionRequested, &wsaData );
41         if ( err != 0 ) {
42                 /* Tell the user that we could not find a usable */
43                 /* WinSock DLL.                                  */
44                 return 0;
45         }
46
47         /* Confirm that the WinSock DLL supports 2.2.*/
48         /* Note that if the DLL supports versions greater    */
49         /* than 2.2 in addition to 2.2, it will still return */
50         /* 2.2 in wVersion since that is the version we      */
51         /* requested.                                        */
52
53         if ( LOBYTE( wsaData.wVersion ) != 2 ||
54                 HIBYTE( wsaData.wVersion ) != 2 ) {
55                         /* Tell the user that we could not find a usable */
56                         /* WinSock DLL.                                  */
57                         WSACleanup( );
58                         return 0;
59         }
60         return 1;
61 }
62 #endif /* _WIN32 */
63
64 int firmnet_connect_tcp(const char *host, uint16_t port)
65 {
66         struct hostent     *phe;
67         struct protoent    *ppe;
68         struct sockaddr_in sin;
69         int s;
70
71 #ifdef _WIN32
72         winsock_init();
73 #endif
74
75         memset(&sin, 0, sizeof(sin));
76         sin.sin_family = AF_INET;
77         sin.sin_port   = htons(port);
78
79         if ((phe = gethostbyname(host)))
80                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
81         else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
82                 fprintf(stderr, "cannot get host entry for %s", host);
83                 return -1;
84         }
85
86         ppe = getprotobyname("tcp");
87         ERRNO_CHECK_RETURN(s = socket(PF_INET, SOCK_STREAM, ppe->p_proto), <, 0, -1);
88         ERRNO_CHECK_RETURN(connect(s, (struct sockaddr *) &sin, sizeof(sin)), <, 0, -1);
89
90         return s;
91 }
92
93 void firmnet_close_socket(int fd) {
94 #ifdef _WIN32
95         closesocket(fd);
96 #else /* _WIN32 */
97         close(fd);
98 #endif /* _WIN32 */
99 }
100
101 /**
102  * Send message of size @p n from buffer @p buf to file descriptor @p fd.
103  * @param fd   The file descriptor, the message should be send to.
104  * @param buf  The buffer containing the message
105  * @param n    The length of the message.
106  * @return Number of bytes written or -1 on failure.
107  */
108 ssize_t firmnet_send(int fd, const void *buf, size_t n)
109 {
110         ssize_t    res;
111         size_t     bytes_written = 0;
112         const char *data = buf;
113
114         do {
115                 res = send(fd, &data[bytes_written], n - bytes_written, 0);
116                 if (res < 0) {
117                         if (errno != EAGAIN)
118                                 return -1;
119                         continue;
120                 }
121
122                 bytes_written += res;
123
124         } while (bytes_written < n);
125
126         return n;
127 }
128
129 /**
130  * Try to read some bytes but block until a certain amount is read.
131  * @param fd The file descriptor.
132  * @param buf The buffer to read into.
133  * @param try The amount of bytes to try to read.
134  * @param at_least block until this many bytes are read.
135  * @return The number of bytes read or -1 on error.
136  */
137 ssize_t firmnet_recv(int fd, void *buf, size_t try, size_t at_least)
138 {
139         ssize_t res;
140         size_t  bytes_read = 0;
141         char   *data       = buf;
142
143         do {
144                 res = recv(fd, &data[bytes_read], try - bytes_read, 0);
145                 if (res <= 0) {
146                         if (res == 0 || errno != EAGAIN)
147                                 return -1;
148                         continue;
149                 }
150
151                 bytes_read += res;
152
153         } while (bytes_read < at_least);
154
155         return bytes_read;
156 }