socket.cc revision 2
12SN/A/*
21762SN/A * Copyright (c) 2003 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292SN/A#include <sys/types.h>
302SN/A#include <sys/socket.h>
312SN/A
322SN/A#include <netinet/in.h>
332SN/A#include <netinet/tcp.h>
342SN/A
3556SN/A#include <errno.h>
361919SN/A#include <unistd.h>
371919SN/A
3856SN/A#include "host.hh"
392SN/A#include "misc.hh"
401919SN/A#include "socket.hh"
412SN/A
422SN/Ausing namespace std;
431919SN/A
441919SN/A////////////////////////////////////////////////////////////////////////
452SN/A//
462SN/A//
472SN/A
481919SN/AListenSocket::ListenSocket()
491919SN/A    : listening(false), fd(-1)
502SN/A{}
511919SN/A
521919SN/AListenSocket::~ListenSocket()
531919SN/A{
542SN/A    if (fd != -1)
552SN/A        close(fd);
561919SN/A}
571919SN/A
582SN/A// Create a socket and configure it for listening
591919SN/Abool
601919SN/AListenSocket::listen(int port, bool reuse)
611919SN/A{
621919SN/A    if (listening)
631919SN/A        panic("Socket already listening!");
641919SN/A
651919SN/A    fd = ::socket(PF_INET, SOCK_STREAM, 0);
661919SN/A    if (fd < 0)
671919SN/A        panic("Can't create socket!");
681919SN/A
692SN/A    if (reuse) {
701919SN/A        int i = 1;
711919SN/A        if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&i,
721919SN/A                         sizeof(i)) < 0)
731919SN/A            panic("ListenSocket(listen): setsockopt() SO_REUSEADDR failed!");
741919SN/A    }
751919SN/A
761919SN/A    struct sockaddr_in sockaddr;
771919SN/A    sockaddr.sin_family = PF_INET;
781919SN/A    sockaddr.sin_addr.s_addr = INADDR_ANY;
791919SN/A
801919SN/A    sockaddr.sin_port = htons(port);
811919SN/A    int ret = ::bind(fd, (struct sockaddr *)&sockaddr, sizeof (sockaddr));
822SN/A    if (ret != 0) {
832SN/A        if (ret == -1 && errno != EADDRINUSE)
842SN/A            panic("ListenSocket(listen): bind() failed!");
852SN/A        return false;
86    }
87
88    if (::listen(fd, 1) == -1)
89        panic("ListenSocket(listen): listen() failed!");
90
91    listening = true;
92
93    return true;
94}
95
96#if !defined(__OpenBSD__) && !defined(linux)
97typedef int socklen_t;
98#endif
99
100// Open a connection.  Accept will block, so if you don't want it to,
101// make sure a connection is ready before you call accept.
102int
103ListenSocket::accept(bool nodelay)
104{
105    struct sockaddr_in sockaddr;
106    socklen_t slen = sizeof (sockaddr);
107    int sfd = ::accept(fd, (struct sockaddr *)&sockaddr, &slen);
108    if (sfd != -1 && nodelay) {
109        int i = 1;
110        ::setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i));
111    }
112
113    return sfd;
114}
115