You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

channelmanager.go 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. // Copyright (c) 2017 Shivaram Lingamneni <slingamn@cs.stanford.edu>
  2. // released under the MIT license
  3. package irc
  4. import (
  5. "sync"
  6. "github.com/oragono/oragono/irc/utils"
  7. )
  8. type channelManagerEntry struct {
  9. channel *Channel
  10. // this is a refcount for joins, so we can avoid a race where we incorrectly
  11. // think the channel is empty (without holding a lock across the entire Channel.Join()
  12. // call)
  13. pendingJoins int
  14. skeleton string
  15. }
  16. // ChannelManager keeps track of all the channels on the server,
  17. // providing synchronization for creation of new channels on first join,
  18. // cleanup of empty channels on last part, and renames.
  19. type ChannelManager struct {
  20. sync.RWMutex // tier 2
  21. // chans is the main data structure, mapping casefolded name -> *Channel
  22. chans map[string]*channelManagerEntry
  23. chansSkeletons utils.StringSet // skeletons of *unregistered* chans
  24. registeredChannels utils.StringSet // casefolds of registered chans
  25. registeredSkeletons utils.StringSet // skeletons of registered chans
  26. purgedChannels utils.StringSet // casefolds of purged chans
  27. server *Server
  28. }
  29. // NewChannelManager returns a new ChannelManager.
  30. func (cm *ChannelManager) Initialize(server *Server) {
  31. cm.chans = make(map[string]*channelManagerEntry)
  32. cm.chansSkeletons = make(utils.StringSet)
  33. cm.server = server
  34. cm.loadRegisteredChannels(server.Config())
  35. // purging should work even if registration is disabled
  36. cm.purgedChannels = cm.server.channelRegistry.PurgedChannels()
  37. }
  38. func (cm *ChannelManager) loadRegisteredChannels(config *Config) {
  39. if !config.Channels.Registration.Enabled {
  40. return
  41. }
  42. rawNames := cm.server.channelRegistry.AllChannels()
  43. registeredChannels := make(utils.StringSet, len(rawNames))
  44. registeredSkeletons := make(utils.StringSet, len(rawNames))
  45. for _, name := range rawNames {
  46. cfname, err := CasefoldChannel(name)
  47. if err == nil {
  48. registeredChannels.Add(cfname)
  49. }
  50. skeleton, err := Skeleton(name)
  51. if err == nil {
  52. registeredSkeletons.Add(skeleton)
  53. }
  54. }
  55. cm.Lock()
  56. defer cm.Unlock()
  57. cm.registeredChannels = registeredChannels
  58. cm.registeredSkeletons = registeredSkeletons
  59. }
  60. // Get returns an existing channel with name equivalent to `name`, or nil
  61. func (cm *ChannelManager) Get(name string) (channel *Channel) {
  62. name, err := CasefoldChannel(name)
  63. if err == nil {
  64. cm.RLock()
  65. defer cm.RUnlock()
  66. entry := cm.chans[name]
  67. // if the channel is still loading, pretend we don't have it
  68. if entry != nil && entry.channel.IsLoaded() {
  69. return entry.channel
  70. }
  71. }
  72. return nil
  73. }
  74. // Join causes `client` to join the channel named `name`, creating it if necessary.
  75. func (cm *ChannelManager) Join(client *Client, name string, key string, isSajoin bool, rb *ResponseBuffer) error {
  76. server := client.server
  77. casefoldedName, err := CasefoldChannel(name)
  78. skeleton, skerr := Skeleton(name)
  79. if err != nil || skerr != nil || len(casefoldedName) > server.Config().Limits.ChannelLen {
  80. return errNoSuchChannel
  81. }
  82. channel, err := func() (*Channel, error) {
  83. cm.Lock()
  84. defer cm.Unlock()
  85. if cm.purgedChannels.Has(casefoldedName) {
  86. return nil, errChannelPurged
  87. }
  88. entry := cm.chans[casefoldedName]
  89. if entry == nil {
  90. registered := cm.registeredChannels.Has(casefoldedName)
  91. // enforce OpOnlyCreation
  92. if !registered && server.Config().Channels.OpOnlyCreation && !client.HasRoleCapabs("chanreg") {
  93. return nil, errInsufficientPrivs
  94. }
  95. // enforce confusables
  96. if cm.chansSkeletons.Has(skeleton) || (!registered && cm.registeredSkeletons.Has(skeleton)) {
  97. return nil, errConfusableIdentifier
  98. }
  99. entry = &channelManagerEntry{
  100. channel: NewChannel(server, name, casefoldedName, registered),
  101. pendingJoins: 0,
  102. }
  103. if !registered {
  104. // for an unregistered channel, we already have the correct unfolded name
  105. // and therefore the final skeleton. for a registered channel, we don't have
  106. // the unfolded name yet (it needs to be loaded from the db), but we already
  107. // have the final skeleton in `registeredSkeletons` so we don't need to track it
  108. cm.chansSkeletons.Add(skeleton)
  109. entry.skeleton = skeleton
  110. }
  111. cm.chans[casefoldedName] = entry
  112. }
  113. entry.pendingJoins += 1
  114. return entry.channel, nil
  115. }()
  116. if err != nil {
  117. return err
  118. }
  119. channel.EnsureLoaded()
  120. err = channel.Join(client, key, isSajoin, rb)
  121. cm.maybeCleanup(channel, true)
  122. return err
  123. }
  124. func (cm *ChannelManager) maybeCleanup(channel *Channel, afterJoin bool) {
  125. cm.Lock()
  126. defer cm.Unlock()
  127. cfname := channel.NameCasefolded()
  128. entry := cm.chans[cfname]
  129. if entry == nil || entry.channel != channel {
  130. return
  131. }
  132. if afterJoin {
  133. entry.pendingJoins -= 1
  134. }
  135. if entry.pendingJoins == 0 && entry.channel.IsClean() {
  136. delete(cm.chans, cfname)
  137. if entry.skeleton != "" {
  138. delete(cm.chansSkeletons, entry.skeleton)
  139. }
  140. }
  141. }
  142. // Part parts `client` from the channel named `name`, deleting it if it's empty.
  143. func (cm *ChannelManager) Part(client *Client, name string, message string, rb *ResponseBuffer) error {
  144. var channel *Channel
  145. casefoldedName, err := CasefoldChannel(name)
  146. if err != nil {
  147. return errNoSuchChannel
  148. }
  149. cm.RLock()
  150. entry := cm.chans[casefoldedName]
  151. if entry != nil {
  152. channel = entry.channel
  153. }
  154. cm.RUnlock()
  155. if channel == nil {
  156. return errNoSuchChannel
  157. }
  158. channel.Part(client, message, rb)
  159. return nil
  160. }
  161. func (cm *ChannelManager) Cleanup(channel *Channel) {
  162. cm.maybeCleanup(channel, false)
  163. }
  164. func (cm *ChannelManager) SetRegistered(channelName string, account string) (err error) {
  165. if cm.server.Defcon() <= 4 {
  166. return errFeatureDisabled
  167. }
  168. var channel *Channel
  169. cfname, err := CasefoldChannel(channelName)
  170. if err != nil {
  171. return err
  172. }
  173. var entry *channelManagerEntry
  174. defer func() {
  175. if err == nil && channel != nil {
  176. // registration was successful: make the database reflect it
  177. err = channel.Store(IncludeAllAttrs)
  178. }
  179. }()
  180. cm.Lock()
  181. defer cm.Unlock()
  182. entry = cm.chans[cfname]
  183. if entry == nil {
  184. return errNoSuchChannel
  185. }
  186. channel = entry.channel
  187. err = channel.SetRegistered(account)
  188. if err != nil {
  189. return err
  190. }
  191. cm.registeredChannels.Add(cfname)
  192. if skel, err := Skeleton(channel.Name()); err == nil {
  193. cm.registeredSkeletons.Add(skel)
  194. }
  195. return nil
  196. }
  197. func (cm *ChannelManager) SetUnregistered(channelName string, account string) (err error) {
  198. cfname, err := CasefoldChannel(channelName)
  199. if err != nil {
  200. return err
  201. }
  202. info, err := cm.server.channelRegistry.LoadChannel(cfname)
  203. if err != nil {
  204. return err
  205. }
  206. if info.Founder != account {
  207. return errChannelNotOwnedByAccount
  208. }
  209. defer func() {
  210. if err == nil {
  211. err = cm.server.channelRegistry.Delete(info)
  212. }
  213. }()
  214. cm.Lock()
  215. defer cm.Unlock()
  216. entry := cm.chans[cfname]
  217. if entry != nil {
  218. entry.channel.SetUnregistered(account)
  219. delete(cm.registeredChannels, cfname)
  220. if skel, err := Skeleton(entry.channel.Name()); err == nil {
  221. delete(cm.registeredSkeletons, skel)
  222. }
  223. }
  224. return nil
  225. }
  226. // Rename renames a channel (but does not notify the members)
  227. func (cm *ChannelManager) Rename(name string, newName string) (err error) {
  228. cfname, err := CasefoldChannel(name)
  229. if err != nil {
  230. return errNoSuchChannel
  231. }
  232. newCfname, err := CasefoldChannel(newName)
  233. if err != nil {
  234. return errInvalidChannelName
  235. }
  236. newSkeleton, err := Skeleton(newName)
  237. if err != nil {
  238. return errInvalidChannelName
  239. }
  240. var channel *Channel
  241. var info RegisteredChannel
  242. defer func() {
  243. if channel != nil && info.Founder != "" {
  244. channel.Store(IncludeAllAttrs)
  245. // we just flushed the channel under its new name, therefore this delete
  246. // cannot be overwritten by a write to the old name:
  247. cm.server.channelRegistry.Delete(info)
  248. }
  249. }()
  250. cm.Lock()
  251. defer cm.Unlock()
  252. if newCfname == cfname {
  253. entry := cm.chans[cfname]
  254. if entry == nil || !entry.channel.IsLoaded() {
  255. return errNoSuchChannel
  256. }
  257. entry.channel.Rename(newName, cfname)
  258. return nil
  259. }
  260. if cm.chans[newCfname] != nil || cm.registeredChannels.Has(newCfname) {
  261. return errChannelNameInUse
  262. }
  263. if cm.chansSkeletons.Has(newSkeleton) || cm.registeredSkeletons.Has(newSkeleton) {
  264. return errChannelNameInUse
  265. }
  266. entry := cm.chans[cfname]
  267. if entry == nil || !entry.channel.IsLoaded() {
  268. return errNoSuchChannel
  269. }
  270. channel = entry.channel
  271. info = channel.ExportRegistration(IncludeInitial)
  272. registered := info.Founder != ""
  273. delete(cm.chans, cfname)
  274. cm.chans[newCfname] = entry
  275. if registered {
  276. delete(cm.registeredChannels, cfname)
  277. if oldSkeleton, err := Skeleton(info.Name); err == nil {
  278. delete(cm.registeredSkeletons, oldSkeleton)
  279. }
  280. cm.registeredChannels.Add(newCfname)
  281. cm.registeredSkeletons.Add(newSkeleton)
  282. } else {
  283. delete(cm.chansSkeletons, entry.skeleton)
  284. cm.chansSkeletons.Add(newSkeleton)
  285. entry.skeleton = newSkeleton
  286. cm.chans[cfname] = entry
  287. }
  288. entry.channel.Rename(newName, newCfname)
  289. return nil
  290. }
  291. // Len returns the number of channels
  292. func (cm *ChannelManager) Len() int {
  293. cm.RLock()
  294. defer cm.RUnlock()
  295. return len(cm.chans)
  296. }
  297. // Channels returns a slice containing all current channels
  298. func (cm *ChannelManager) Channels() (result []*Channel) {
  299. cm.RLock()
  300. defer cm.RUnlock()
  301. result = make([]*Channel, 0, len(cm.chans))
  302. for _, entry := range cm.chans {
  303. if entry.channel.IsLoaded() {
  304. result = append(result, entry.channel)
  305. }
  306. }
  307. return
  308. }
  309. // Purge marks a channel as purged.
  310. func (cm *ChannelManager) Purge(chname string, record ChannelPurgeRecord) (err error) {
  311. chname, err = CasefoldChannel(chname)
  312. if err != nil {
  313. return errInvalidChannelName
  314. }
  315. cm.Lock()
  316. cm.purgedChannels.Add(chname)
  317. cm.Unlock()
  318. cm.server.channelRegistry.PurgeChannel(chname, record)
  319. return nil
  320. }
  321. // IsPurged queries whether a channel is purged.
  322. func (cm *ChannelManager) IsPurged(chname string) (result bool) {
  323. chname, err := CasefoldChannel(chname)
  324. if err != nil {
  325. return false
  326. }
  327. cm.RLock()
  328. result = cm.purgedChannels.Has(chname)
  329. cm.RUnlock()
  330. return
  331. }
  332. // Unpurge deletes a channel's purged status.
  333. func (cm *ChannelManager) Unpurge(chname string) (err error) {
  334. chname, err = CasefoldChannel(chname)
  335. if err != nil {
  336. return errNoSuchChannel
  337. }
  338. cm.Lock()
  339. found := cm.purgedChannels.Has(chname)
  340. delete(cm.purgedChannels, chname)
  341. cm.Unlock()
  342. cm.server.channelRegistry.UnpurgeChannel(chname)
  343. if !found {
  344. return errNoSuchChannel
  345. }
  346. return nil
  347. }