OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [or1ksim/] [peripheral/] [channels/] [tcp.c] - Blame information for rev 1767

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1118 sfurman
/* tcp.c -- Definition of functions for peripheral to
2
 * communicate with host via a tcp socket.
3
 
4
   Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
5 1748 jeremybenn
   Copyright (C) 2008 Embecosm Limited
6 1118 sfurman
 
7 1748 jeremybenn
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
8 1118 sfurman
 
9 1748 jeremybenn
   This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
10 1118 sfurman
 
11 1748 jeremybenn
   This program is free software; you can redistribute it and/or modify it
12
   under the terms of the GNU General Public License as published by the Free
13
   Software Foundation; either version 3 of the License, or (at your option)
14
   any later version.
15 1118 sfurman
 
16 1748 jeremybenn
   This program is distributed in the hope that it will be useful, but WITHOUT
17
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19
   more details.
20 1118 sfurman
 
21 1748 jeremybenn
   You should have received a copy of the GNU General Public License along
22
   with this program.  If not, see <http://www.gnu.org/licenses/>.  */
23 1118 sfurman
 
24 1748 jeremybenn
/* This program is commented throughout in a fashion suitable for processing
25
   with Doxygen. */
26
 
27
 
28
/* Autoconf and/or portability configuration */
29
#include "config.h"
30
#include "port.h"
31
 
32
/* System includes */
33
#include <stdlib.h>
34
#include <unistd.h>
35 1118 sfurman
#include <stdio.h>
36
#include <sys/types.h>
37
#include <sys/socket.h>
38
#include <netinet/in.h>
39
#include <fcntl.h>
40
#include <errno.h>
41
 
42 1748 jeremybenn
/* Package includes */
43 1118 sfurman
#include "channel.h"
44
#include "generic.h"
45
#include "fd.h"
46
 
47 1748 jeremybenn
/*! Structure to represent a TCP/IP channel */
48 1118 sfurman
struct tcp_channel
49
{
50 1748 jeremybenn
  struct fd_channel fds;
51
  int               socket_fd;    /* Socket to listen to */
52
  int               port_number;  /* TCP port number */
53
  int               connected;    /* If 0, no remote endpoint yet */
54
  int               nonblocking;  /* If 0, read/write will block until
55
                                     remote client connects */
56 1118 sfurman
};
57
 
58 1748 jeremybenn
/* Forward declarations of static functions */
59
static void *tcp_init (const char *input);
60
static int   tcp_open (void *data);
61
static int   tcp_read (void *data,
62
                       char *buffer,
63
                       int   size);
64
static int   tcp_write (void       *data,
65
                        const char *buffer,
66
                        int         size);
67
 
68
/*! Data structure holding all the operations for a TCP/IP channel */
69
struct channel_ops  tcp_channel_ops = {
70
        .init  = tcp_init,
71
        .open  = tcp_open,
72
        .close = generic_close,
73
        .read  = tcp_read,
74
        .write = tcp_write,
75
        .free  = generic_free,
76
};
77
 
78
static void *
79
tcp_init (const char *input)
80 1118 sfurman
{
81 1748 jeremybenn
  int port_number, fd, flags;
82
  struct sockaddr_in local_ip;
83
  struct tcp_channel *channel =
84
    (struct tcp_channel *) malloc (sizeof (struct tcp_channel));
85
  if (!channel)
86
    return NULL;
87 1118 sfurman
 
88 1748 jeremybenn
  fd = 0;
89
  channel->nonblocking = 1;
90
  channel->fds.fdin = -1;
91
  channel->fds.fdout = -1;
92
  channel->socket_fd = -1;
93
  channel->port_number = -1;
94 1118 sfurman
 
95 1748 jeremybenn
  port_number = atoi (input);
96
  if (port_number == 0)
97
    goto error;
98 1118 sfurman
 
99 1748 jeremybenn
  fd = socket (AF_INET, SOCK_STREAM, 0);
100
  if (fd < 0)
101
    goto error;
102
 
103
  flags = 1;
104
  if (setsockopt
105
      (fd, SOL_SOCKET, SO_REUSEADDR, (const char *) &flags, sizeof (int)) < 0)
106 1118 sfurman
    {
107 1748 jeremybenn
      perror ("Can not set SO_REUSEADDR option on channel socket");
108
      goto error;
109
    }
110 1118 sfurman
 
111 1748 jeremybenn
  memset (&local_ip, 0, sizeof (local_ip));
112
  local_ip.sin_family = AF_INET;
113
  local_ip.sin_addr.s_addr = htonl (INADDR_ANY);
114
  local_ip.sin_port = htons (port_number);
115
  if (bind (fd, (struct sockaddr *) &local_ip, sizeof (local_ip)) < 0)
116
    {
117
      perror ("Can't bind local address");
118
      goto error;
119
    }
120 1118 sfurman
 
121 1748 jeremybenn
  if (channel->nonblocking)
122
    {
123
      if (fcntl (fd, F_SETFL, O_NONBLOCK) < 0)
124
        {
125
          perror ("Can not make channel socket non-blocking");
126
          goto error;
127 1118 sfurman
        }
128 1748 jeremybenn
    }
129 1118 sfurman
 
130 1748 jeremybenn
  if (listen (fd, 1) < 0)
131
    goto error;
132 1118 sfurman
 
133 1748 jeremybenn
  channel->socket_fd = fd;
134
  channel->port_number = port_number;
135
  channel->connected = 0;
136
  return (void *) channel;
137
 
138 1118 sfurman
error:
139 1748 jeremybenn
  if (fd)
140
    close (fd);
141
  free (channel);
142
  return NULL;
143 1118 sfurman
}
144
 
145 1748 jeremybenn
static int
146
tcp_open (void *data)
147 1118 sfurman
{
148 1748 jeremybenn
  /* Socket is opened lazily, upon first read or write, so do nothing here */
149
  return 0;
150 1118 sfurman
}
151
 
152
 
153 1748 jeremybenn
static int
154
wait_for_tcp_connect (struct tcp_channel *channel)
155
{
156
  int fd;
157
  socklen_t sizeof_remote_ip;
158
  struct sockaddr_in remote_ip;
159 1118 sfurman
 
160 1748 jeremybenn
  sizeof_remote_ip = sizeof (remote_ip);
161
  fd =
162
    accept (channel->socket_fd, (struct sockaddr *) &remote_ip,
163
            &sizeof_remote_ip);
164
  if (fd < 0)
165
    {
166
      if (channel->nonblocking)
167
        {
168
          /* Not an error if there is not yet a remote connection - try again later */
169
          if (errno == EAGAIN)
170
            return 0;
171 1118 sfurman
        }
172 1748 jeremybenn
      perror ("Couldn't accept connection");
173
      return -1;
174
    }
175 1118 sfurman
 
176 1748 jeremybenn
  channel->fds.fdin = channel->fds.fdout = fd;
177
  close (channel->socket_fd);
178
  channel->socket_fd = -1;
179
  channel->connected = 1;
180
  return 1;
181 1118 sfurman
}
182
 
183 1748 jeremybenn
static int
184
tcp_read (void *data, char *buffer, int size)
185 1118 sfurman
{
186 1748 jeremybenn
  struct tcp_channel *channel = data;
187 1118 sfurman
 
188 1748 jeremybenn
  /* Lazily connect to tcp partner on read/write */
189
  if (!channel->connected)
190
    {
191
      int retval = wait_for_tcp_connect (data);
192
      if (retval <= 0)
193
        return retval;
194
    }
195
  return fd_read (data, buffer, size);
196 1118 sfurman
}
197
 
198 1748 jeremybenn
static int
199
tcp_write (void *data, const char *buffer, int size)
200 1118 sfurman
{
201 1748 jeremybenn
  struct tcp_channel *channel = data;
202 1118 sfurman
 
203 1748 jeremybenn
  /* Lazily connect to tcp partner on read/write */
204
  if (!channel->connected)
205
    {
206
      int retval = wait_for_tcp_connect (data);
207
      if (retval < 0)
208
        return retval;
209
    }
210
  return fd_write (data, buffer, size);
211 1118 sfurman
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.