/[rdesktop]/sourceforge.net/trunk/rdesktop/tcp.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /sourceforge.net/trunk/rdesktop/tcp.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4 by matty, Wed May 10 07:36:34 2000 UTC revision 1365 by jsorg71, Thu Jan 4 05:39:39 2007 UTC
# Line 1  Line 1 
1  /*  /* -*- c-basic-offset: 8 -*-
2     rdesktop: A Remote Desktop Protocol client.     rdesktop: A Remote Desktop Protocol client.
3     Protocol services - TCP layer     Protocol services - TCP layer
4     Copyright (C) Matthew Chapman 1999-2000     Copyright (C) Matthew Chapman 1999-2007
5      
6     This program is free software; you can redistribute it and/or modify     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.     (at your option) any later version.
10      
11     This program is distributed in the hope that it will be useful,     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.     GNU General Public License for more details.
15      
16     You should have received a copy of the GNU General Public License     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */  */
20    
21  #include "includes.h"  #ifndef _WIN32
22    #include <unistd.h>             /* select read write close */
23  /* Establish a connection on the TCP layer */  #include <sys/socket.h>         /* socket connect setsockopt */
24  HCONN tcp_connect(char *server)  #include <sys/time.h>           /* timeval */
25    #include <netdb.h>              /* gethostbyname */
26    #include <netinet/in.h>         /* sockaddr_in */
27    #include <netinet/tcp.h>        /* TCP_NODELAY */
28    #include <arpa/inet.h>          /* inet_addr */
29    #include <errno.h>              /* errno */
30    #endif
31    
32    #include "rdesktop.h"
33    
34    #ifdef _WIN32
35    #define socklen_t int
36    #define TCP_CLOSE(_sck) closesocket(_sck)
37    #define TCP_STRERROR "tcp error"
38    #define TCP_BLOCKS (WSAGetLastError() == WSAEWOULDBLOCK)
39    #else
40    #define TCP_CLOSE(_sck) close(_sck)
41    #define TCP_STRERROR strerror(errno)
42    #define TCP_BLOCKS (errno == EWOULDBLOCK)
43    #endif
44    
45    #ifndef INADDR_NONE
46    #define INADDR_NONE ((unsigned long) -1)
47    #endif
48    
49    static int g_sock;
50    static struct stream g_in;
51    #ifndef WITH_SCARD
52    static struct stream g_out;
53    #endif
54    int g_tcp_port_rdp = TCP_PORT_RDP;
55    
56    /* wait till socket is ready to write or timeout */
57    static BOOL
58    tcp_can_send(int sck, int millis)
59  {  {
60          struct hostent *nslookup;          fd_set wfds;
61          struct sockaddr_in servaddr;          struct timeval time;
62          struct connection *conn;          int sel_count;
63          int sock;  
64          int true = 1;          time.tv_sec = millis / 1000;
65            time.tv_usec = (millis * 1000) % 1000000;
66          if ((nslookup = gethostbyname(server)) != NULL)          FD_ZERO(&wfds);
67          {          FD_SET(sck, &wfds);
68                  memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));          sel_count = select(sck + 1, 0, &wfds, 0, &time);
69          }          if (sel_count > 0)
         else if (!inet_aton(server, &servaddr.sin_addr))  
70          {          {
71                  fprintf(stderr, "%s: unable to resolve host\n", server);                  return True;
                 return NULL;  
72          }          }
73            return False;
74    }
75    
76          if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)  /* Initialise TCP transport data packet */
77          {  STREAM
78                  fprintf(stderr, "socket: %s\n", strerror(errno));  tcp_init(uint32 maxlen)
79                  return NULL;  {
80          }          STREAM result = NULL;
81    
82          servaddr.sin_family = AF_INET;  #ifdef WITH_SCARD
83          servaddr.sin_port = htons(TCP_PORT_RDP);          scard_lock(SCARD_LOCK_TCP);
84            result = scard_tcp_init();
85    #else
86            result = &g_out;
87    #endif
88    
89          if (connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0)          if (maxlen > result->size)
90          {          {
91                  fprintf(stderr, "connect: %s\n", strerror(errno));                  result->data = (uint8 *) xrealloc(result->data, maxlen);
92                  close(sock);                  result->size = maxlen;
                 return NULL;  
93          }          }
94    
95          setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &true, sizeof(true));          result->p = result->data;
96            result->end = result->data + result->size;
97          conn = xmalloc(sizeof(struct connection));  #ifdef WITH_SCARD
98          STREAM_INIT(conn->in,  False);          scard_unlock(SCARD_LOCK_TCP);
99          STREAM_INIT(conn->out, True);  #endif
100            return result;
         conn->tcp_socket = sock;  
         return conn;  
 }  
   
 /* Disconnect on the TCP layer */  
 void tcp_disconnect(HCONN conn)  
 {  
         close(conn->tcp_socket);  
         free(conn);  
101  }  }
102    
103  /* Send TCP transport data packet */  /* Send TCP transport data packet */
104  BOOL tcp_send(HCONN conn)  void
105    tcp_send(STREAM s)
106  {  {
107          int length = conn->out.end;          int length = s->end - s->data;
108          int sent, total = 0;          int sent, total = 0;
109    
110    #ifdef WITH_SCARD
111            scard_lock(SCARD_LOCK_TCP);
112    #endif
113          while (total < length)          while (total < length)
114          {          {
115                  sent = write(conn->tcp_socket, conn->out.data + total,                  sent = send(g_sock, s->data + total, length - total, 0);
                              length - total);  
   
116                  if (sent <= 0)                  if (sent <= 0)
117                  {                  {
118                          fprintf(stderr, "write: %s\n", strerror(errno));                          if (sent == -1 && TCP_BLOCKS)
119                          return False;                          {
120                                    tcp_can_send(g_sock, 100);
121                                    sent = 0;
122                            }
123                            else
124                            {
125                                    error("send: %s\n", TCP_STRERROR);
126                                    return;
127                            }
128                  }                  }
   
129                  total += sent;                  total += sent;
130          }          }
131    #ifdef WITH_SCARD
132          conn->out.offset = 0;          scard_unlock(SCARD_LOCK_TCP);
133          conn->out.end = conn->out.size;  #endif
         return True;  
134  }  }
135    
136  /* Receive a message on the TCP layer */  /* Receive a message on the TCP layer */
137  BOOL tcp_recv(HCONN conn, int length)  STREAM
138    tcp_recv(STREAM s, uint32 length)
139  {  {
140          int rcvd;          uint32 new_length, end_offset, p_offset;
141            int rcvd = 0;
142    
143          STREAM_SIZE(conn->in, length);          if (s == NULL)
144          conn->in.end = conn->in.offset = 0;          {
145                    /* read into "new" stream */
146                    if (length > g_in.size)
147                    {
148                            g_in.data = (uint8 *) xrealloc(g_in.data, length);
149                            g_in.size = length;
150                    }
151                    g_in.end = g_in.p = g_in.data;
152                    s = &g_in;
153            }
154            else
155            {
156                    /* append to existing stream */
157                    new_length = (s->end - s->data) + length;
158                    if (new_length > s->size)
159                    {
160                            p_offset = s->p - s->data;
161                            end_offset = s->end - s->data;
162                            s->data = (uint8 *) xrealloc(s->data, new_length);
163                            s->size = new_length;
164                            s->p = s->data + p_offset;
165                            s->end = s->data + end_offset;
166                    }
167            }
168    
169          while (length > 0)          while (length > 0)
170          {          {
171                  rcvd = read(conn->tcp_socket, conn->in.data + conn->in.end,                  if (!ui_select(g_sock))
172                              length);                          /* User quit */
173                            return NULL;
174    
175                  if (rcvd <= 0)                  rcvd = recv(g_sock, s->end, length, 0);
176                    if (rcvd < 0)
177                    {
178                            if (rcvd == -1 && TCP_BLOCKS)
179                            {
180                                    rcvd = 0;
181                            }
182                            else
183                            {
184                                    error("recv: %s\n", TCP_STRERROR);
185                                    return NULL;
186                            }
187                    }
188                    else if (rcvd == 0)
189                  {                  {
190                          fprintf(stderr, "read: %s\n", strerror(errno));                          error("Connection closed\n");
191                          return False;                          return NULL;
192                  }                  }
193    
194                  conn->in.end += rcvd;                  s->end += rcvd;
195                  length -= rcvd;                  length -= rcvd;
196          }          }
197    
198            return s;
199    }
200    
201    /* Establish a connection on the TCP layer */
202    BOOL
203    tcp_connect(char *server)
204    {
205            socklen_t option_len;
206            uint32 option_value;
207    
208    #ifdef IPv6
209    
210            int n;
211            struct addrinfo hints, *res, *ressave;
212            char tcp_port_rdp_s[10];
213    
214            snprintf(tcp_port_rdp_s, 10, "%d", g_tcp_port_rdp);
215    
216            memset(&hints, 0, sizeof(struct addrinfo));
217            hints.ai_family = AF_UNSPEC;
218            hints.ai_socktype = SOCK_STREAM;
219    
220            if ((n = getaddrinfo(server, tcp_port_rdp_s, &hints, &res)))
221            {
222                    error("getaddrinfo: %s\n", gai_strerror(n));
223                    return False;
224            }
225    
226            ressave = res;
227            g_sock = -1;
228            while (res)
229            {
230                    g_sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
231                    if (!(g_sock < 0))
232                    {
233                            if (connect(g_sock, res->ai_addr, res->ai_addrlen) == 0)
234                                    break;
235                            TCP_CLOSE(g_sock);
236                            g_sock = -1;
237                    }
238                    res = res->ai_next;
239            }
240            freeaddrinfo(ressave);
241    
242            if (g_sock == -1)
243            {
244                    error("%s: unable to connect\n", server);
245                    return False;
246            }
247    
248    #else /* no IPv6 support */
249    
250            struct hostent *nslookup;
251            struct sockaddr_in servaddr;
252    
253            if ((nslookup = gethostbyname(server)) != NULL)
254            {
255                    memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
256            }
257            else if ((servaddr.sin_addr.s_addr = inet_addr(server)) == INADDR_NONE)
258            {
259                    error("%s: unable to resolve host\n", server);
260                    return False;
261            }
262    
263            if ((g_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
264            {
265                    error("socket: %s\n", TCP_STRERROR);
266                    return False;
267            }
268    
269            servaddr.sin_family = AF_INET;
270            servaddr.sin_port = htons((uint16) g_tcp_port_rdp);
271    
272            if (connect(g_sock, (struct sockaddr *) &servaddr, sizeof(struct sockaddr)) < 0)
273            {
274                    error("connect: %s\n", TCP_STRERROR);
275                    TCP_CLOSE(g_sock);
276                    return False;
277            }
278    
279    #endif /* IPv6 */
280    
281            option_value = 1;
282            option_len = sizeof(option_value);
283            setsockopt(g_sock, IPPROTO_TCP, TCP_NODELAY, (void *) &option_value, option_len);
284            /* receive buffer must be a least 16 K */
285            if (getsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value, &option_len) == 0)
286            {
287                    if (option_value < (1024 * 16))
288                    {
289                            option_value = 1024 * 16;
290                            option_len = sizeof(option_value);
291                            setsockopt(g_sock, SOL_SOCKET, SO_RCVBUF, (void *) &option_value,
292                                       option_len);
293                    }
294            }
295    
296            g_in.size = 4096;
297            g_in.data = (uint8 *) xmalloc(g_in.size);
298    
299    #ifdef WITH_SCARD
300            scard_tcp_connect();
301    #else
302            g_out.size = 4096;
303            g_out.data = (uint8 *) xmalloc(g_out.size);
304    #endif
305    
306          return True;          return True;
307  }  }
308    
309    /* Disconnect on the TCP layer */
310    void
311    tcp_disconnect(void)
312    {
313            TCP_CLOSE(g_sock);
314    }
315    
316    char *
317    tcp_get_address()
318    {
319            static char ipaddr[32];
320            struct sockaddr_in sockaddr;
321            socklen_t len = sizeof(sockaddr);
322            if (getsockname(g_sock, (struct sockaddr *) &sockaddr, &len) == 0)
323            {
324                    uint8 *ip = (uint8 *) & sockaddr.sin_addr;
325                    sprintf(ipaddr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
326            }
327            else
328                    strcpy(ipaddr, "127.0.0.1");
329            return ipaddr;
330    }
331    
332    /* reset the state of the tcp layer */
333    /* Support for Session Directory */
334    void
335    tcp_reset_state(void)
336    {
337            g_sock = -1;            /* reset socket */
338    
339            /* Clear the incoming stream */
340            if (g_in.data != NULL)
341                    xfree(g_in.data);
342            g_in.p = NULL;
343            g_in.end = NULL;
344            g_in.data = NULL;
345            g_in.size = 0;
346            g_in.iso_hdr = NULL;
347            g_in.mcs_hdr = NULL;
348            g_in.sec_hdr = NULL;
349            g_in.rdp_hdr = NULL;
350            g_in.channel_hdr = NULL;
351    
352            /* Clear the outgoing stream(s) */
353    #ifdef WITH_SCARD
354            scard_tcp_reset_state();
355    #else
356            if (g_out.data != NULL)
357                    xfree(g_out.data);
358            g_out.p = NULL;
359            g_out.end = NULL;
360            g_out.data = NULL;
361            g_out.size = 0;
362            g_out.iso_hdr = NULL;
363            g_out.mcs_hdr = NULL;
364            g_out.sec_hdr = NULL;
365            g_out.rdp_hdr = NULL;
366            g_out.channel_hdr = NULL;
367    #endif
368    }

Legend:
Removed from v.4  
changed lines
  Added in v.1365

  ViewVC Help
Powered by ViewVC 1.1.26