ee8b31847121e29be90779d1e245b2b017563dcb
[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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif /* HAVE_CONFIG_H */
31
32 #include "firmnet_t.h"
33
34 #ifdef _WIN32
35 static int winsock_init(void) {
36         WORD wVersionRequested;
37         WSADATA wsaData;
38         int err;
39
40         wVersionRequested = MAKEWORD( 2, 2 );
41
42         err = WSAStartup( wVersionRequested, &wsaData );
43         if ( err != 0 ) {
44                 /* Tell the user that we could not find a usable */
45                 /* WinSock DLL.                                  */
46                 return 0;
47         }
48
49         /* Confirm that the WinSock DLL supports 2.2.*/
50         /* Note that if the DLL supports versions greater    */
51         /* than 2.2 in addition to 2.2, it will still return */
52         /* 2.2 in wVersion since that is the version we      */
53         /* requested.                                        */
54
55         if ( LOBYTE( wsaData.wVersion ) != 2 ||
56                 HIBYTE( wsaData.wVersion ) != 2 ) {
57                         /* Tell the user that we could not find a usable */
58                         /* WinSock DLL.                                  */
59                         WSACleanup( );
60                         return 0;
61         }
62         return 1;
63 }
64 #endif /* _WIN32 */
65
66 int firmnet_connect_tcp(const char *host, uint16_t port)
67 {
68         struct hostent     *phe;
69         struct protoent    *ppe;
70         struct sockaddr_in sin;
71         int s;
72
73 #ifdef _WIN32
74         winsock_init();
75 #endif
76
77         memset(&sin, 0, sizeof(sin));
78         sin.sin_family = AF_INET;
79         sin.sin_port   = htons(port);
80
81         if ((phe = gethostbyname(host)))
82                 memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
83         else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
84                 fprintf(stderr, "cannot get host entry for %s", host);
85                 return -1;
86         }
87
88         ppe = getprotobyname("tcp");
89         ERRNO_CHECK_RETURN(s = socket(PF_INET, SOCK_STREAM, ppe->p_proto), <, 0, -1);
90         ERRNO_CHECK_RETURN(connect(s, (struct sockaddr *) &sin, sizeof(sin)), <, 0, -1);
91
92         return s;
93 }
94
95 void firmnet_close_socket(int fd) {
96 #ifdef _WIN32
97         closesocket(fd);
98 #else /* _WIN32 */
99         close(fd);
100 #endif /* _WIN32 */
101 }
102
103 /**
104  * Send message of size @p n from buffer @p buf to file descriptor @p fd.
105  * @param fd   The file descriptor, the message should be send to.
106  * @param buf  The buffer containing the message
107  * @param n    The length of the message.
108  * @return Number of bytes written or -1 on failure.
109  */
110 ssize_t firmnet_send(int fd, const void *buf, size_t n)
111 {
112         ssize_t    res;
113         size_t     bytes_written = 0;
114         const char *data = buf;
115
116         do {
117                 res = send(fd, &data[bytes_written], n - bytes_written, 0);
118                 if (res < 0) {
119                         if (errno != EAGAIN)
120                                 return -1;
121                         continue;
122                 }
123
124                 bytes_written += res;
125
126         } while (bytes_written < n);
127
128         return n;
129 }
130
131 /**
132  * Try to read some bytes but block until a certain amount is read.
133  * @param fd The file descriptor.
134  * @param buf The buffer to read into.
135  * @param try The amount of bytes to try to read.
136  * @param at_least block until this many bytes are read.
137  * @return The number of bytes read or -1 on error.
138  */
139 ssize_t firmnet_recv(int fd, void *buf, size_t try, size_t at_least)
140 {
141         ssize_t res;
142         size_t  bytes_read = 0;
143         char   *data       = buf;
144
145         do {
146                 res = recv(fd, &data[bytes_read], try - bytes_read, 0);
147                 if (res <= 0) {
148                         if (res == 0 || errno != EAGAIN)
149                                 return -1;
150                         continue;
151                 }
152
153                 bytes_read += res;
154
155         } while (bytes_read < at_least);
156
157         return bytes_read;
158 }