'Write a datagram.
@type datagram: L{bytes}
@param datagram: The datagram to be sent.
@type addr: L{tuple} containing L{str} as first element and L{int} as
second element, or L{None}
@param addr: A tuple of (I{stringified IPv4 or IPv6 address},
I{integer port number}); can be L{None} in connected mode.'

def write(self, datagram, addr=None):

    if self._connectedAddr:
        assert (addr in (None, self._connectedAddr))
        try:
            return self.socket.send(datagram)
        except socket.error as se:
            no = se.args[0]
            if (no == EINTR):
                return self.write(datagram)
            elif (no == EMSGSIZE):
                raise error.MessageLengthError('message    too    long')
            elif (no == ECONNREFUSED):
                self.protocol.connectionRefused()
            else:
                raise
    else:
        assert (addr != None)
        if ((not abstract.isIPAddress(addr[0])) and (not abstract.isIPv6Address(addr[0])) and (addr[0] != '<broadcast>')):
            raise error.InvalidAddressError(addr[0], 'write()    only    accepts    IP    addresses,    not    hostnames')
        if ((abstract.isIPAddress(addr[0]) or (addr[0] == '<broadcast>')) and (self.addressFamily == socket.AF_INET6)):
            raise error.InvalidAddressError(addr[0], 'IPv6    port    write()    called    with    IPv4    or    broadcast    address')
        if (abstract.isIPv6Address(addr[0]) and (self.addressFamily == socket.AF_INET)):
            raise error.InvalidAddressError(addr[0], 'IPv4    port    write()    called    with    IPv6    address')
        try:
            return self.socket.sendto(datagram, addr)
        except socket.error as se:
            no = se.args[0]
            if (no == EINTR):
                return self.write(datagram, addr)
            elif (no == EMSGSIZE):
                raise error.MessageLengthError('message    too    long')
            elif (no == ECONNREFUSED):
                return
            else:
                raise
